Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
486c2a3
docs: add phase 6 — polish and harden
pingvinen Mar 27, 2026
5fe19a4
docs(06): capture phase context
pingvinen Mar 27, 2026
d0d4ccd
docs(state): record phase 6 context session
pingvinen Mar 27, 2026
67c16e2
docs(06): expand bootstrap to donna-tools.cjs with broader scope
pingvinen Mar 27, 2026
71c0f53
docs(06): research phase domain
pingvinen Mar 27, 2026
ff511a7
docs(06): add research and validation strategy
pingvinen Mar 27, 2026
337c75c
docs(06): create phase 6 plan — 5 plans in 2 waves
pingvinen Mar 27, 2026
56958d0
feat(06-02): add GitHub Actions UAT merge gate workflow
pingvinen Mar 27, 2026
2eff66b
feat(06-03): group skills list and add automation docs in README
pingvinen Mar 27, 2026
3c30186
test(06-01): add failing tests for donna-tools subcommands
pingvinen Mar 27, 2026
ce46002
feat(06-02): add skip-setup guard, simplify adjust-tool
pingvinen Mar 27, 2026
f380569
docs(06-03): complete docs and README improvements plan
pingvinen Mar 27, 2026
5cbd334
feat(06-01): create donna-tools.cjs with 4 subcommands and version check
pingvinen Mar 27, 2026
62204d2
docs(06-01): complete donna-tools.cjs plan execution
pingvinen Mar 27, 2026
ebcec53
Merge branch 'worktree-agent-a683ec8c' into gsd/phase-06-polish-and-h…
pingvinen Mar 27, 2026
a0d9138
Merge branch 'worktree-agent-a9e3ad0c' into gsd/phase-06-polish-and-h…
pingvinen Mar 27, 2026
8745ff8
docs(06-02): add plan summary for UAT gate, skip-setup guard, adjust-…
pingvinen Mar 27, 2026
cf06623
feat(06-04): enhance add-tool learn-capabilities with cascading sources
pingvinen Mar 27, 2026
8eeac4a
feat(06-04): enhance relearn-tools relearn-changed with cascading sou…
pingvinen Mar 27, 2026
3359346
Merge branch 'worktree-agent-af458df2' into gsd/phase-06-polish-and-h…
pingvinen Mar 27, 2026
b151768
docs(06-04): add plan summary for enhanced tool learning cascade
pingvinen Mar 27, 2026
e8da836
feat(06-05): add donna-tools.cjs copy step to installer
pingvinen Mar 27, 2026
72de170
feat(06-05): replace bootstrap and git-commit blocks in all 9 workflows
pingvinen Mar 27, 2026
30032e6
docs(06-05): complete refactor skill bootstrap plan
pingvinen Mar 27, 2026
e876bfa
docs(06): update roadmap — all 5 plans complete
pingvinen Mar 27, 2026
bb964bd
fix(06): wire donna-tools resolve-secret into 3 workflows
pingvinen Mar 27, 2026
10bb838
docs(phase-06): complete phase execution — all gaps resolved
pingvinen Mar 27, 2026
581a94c
docs(06): ship phase 06 — PR #36
pingvinen Mar 27, 2026
a769e6f
test(06): complete UAT - 10 passed, 0 issues
pingvinen Apr 3, 2026
91c741d
test(06): complete human UAT - 2 passed, 5 issues (2 blocker, 1 major…
pingvinen Apr 3, 2026
78eda1e
fix(06): resolve 5 human UAT issues — installer deps, UAT gate, READM…
pingvinen Apr 3, 2026
42fc7ab
fix(06): block type change in adjust-tool with remove/re-add guidance
pingvinen Apr 3, 2026
b3cd89d
feat(06): add /donna:remove-tool skill for clean tool removal
pingvinen Apr 3, 2026
0436ec0
test(06): complete human UAT retest - 6 passed, 1 issue (major: UAT g…
pingvinen Apr 3, 2026
b7efaf4
fix(06): UAT gate requires issues: 0 and checks all UAT file types
pingvinen Apr 3, 2026
8161654
test(06): complete UAT retest - 7 passed, 0 issues
pingvinen Apr 3, 2026
104d0de
fix(06): scope UAT gate to current phase only
pingvinen Apr 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/workflows/uat-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: UAT Gate
on:
pull_request:
branches: [main]
types: [opened, synchronize, reopened, labeled, unlabeled]

permissions:
contents: read
pull-requests: read

jobs:
uat-gate:
name: UAT
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Extract phase number from branch
id: phase
run: |
BRANCH="${{ github.head_ref }}"
# Extract phase number from branch name (e.g., gsd/phase-06-... → 06)
PHASE_NUM=$(echo "$BRANCH" | sed -n 's|^gsd/phase-\([0-9]\{2,\}\)-.*|\1|p')
if [ -z "$PHASE_NUM" ]; then
echo "Could not extract phase number from branch: $BRANCH"
echo "Expected format: gsd/phase-XX-..."
exit 1
fi
echo "phase_num=$PHASE_NUM" >> "$GITHUB_OUTPUT"
echo "Phase: $PHASE_NUM"

- name: Check UAT completion
run: |
PHASE_NUM="${{ steps.phase.outputs.phase_num }}"

# Find UAT files for this phase only (HUMAN-UAT and RETEST-UAT)
PHASE_DIR=$(find .planning/phases -maxdepth 1 -type d -name "${PHASE_NUM}-*" | head -1)

if [ -z "$PHASE_DIR" ]; then
echo "No phase directory found for phase $PHASE_NUM"
exit 1
fi

UAT_FILES=$(find "$PHASE_DIR" -name "*-HUMAN-UAT.md" -o -name "*-RETEST-UAT.md" 2>/dev/null | sort)

if [ -z "$UAT_FILES" ]; then
echo "No UAT files found in $PHASE_DIR"
echo "Complete human UAT with /gsd:verify-work before merging."
exit 1
fi

# Use the latest UAT file (last in sorted order)
LATEST=$(echo "$UAT_FILES" | tail -1)
STATUS=$(head -10 "$LATEST" | grep '^status:' | awk '{print $2}')
ISSUES=$(grep '^issues:' "$LATEST" | head -1 | awk '{print $2}')
echo "Checking: $LATEST — status: $STATUS, issues: ${ISSUES:-unknown}"

if [ "$STATUS" != "complete" ]; then
echo "FAIL: status is not complete"
echo "Run /gsd:verify-work to complete UAT."
exit 1
fi

if [ "${ISSUES:-1}" != "0" ]; then
echo "FAIL: latest UAT found $ISSUES issue(s) — retest needed after fixes"
echo "Run /gsd:verify-work to retest."
exit 1
fi

echo ""
echo "Phase $PHASE_NUM UAT passed: status complete, 0 issues."
14 changes: 14 additions & 0 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,17 @@ Plans:

Plans:
- [x] 05-01-PLAN.md — Remove timeout binary from workflows + update test assertions

### Phase 6: Polish and harden — version check, skip-setup guard, simplify adjust-tool, UAT merge gate, docs and README improvements, enhance tool learning, refactor skill bootstrap

**Goal:** Harden and polish the existing Donna skill suite: create donna-tools.cjs as a centralized CLI utility to eliminate bootstrap duplication across workflows, add a daily version check, suppress the setup prompt when already configured, simplify adjust-tool, add a UAT merge gate, improve README documentation, and enhance tool learning with cascading sources
**Requirements**: D-01 (daily version check), D-02 (non-blocking update hint), D-03 (version check in init), D-04 (skip-setup guard), D-05 (simplify adjust-tool), D-06 (UAT merge gate), D-07 (README skills grouping), D-08 (automation docs), D-09 (cascading tool learning), D-10 (donna-tools.cjs entry point), D-11 (donna-tools subcommands), D-12 (workflow bootstrap refactor)
**Depends on:** Phase 5
**Plans:** 4/5 plans executed

Plans:
- [x] 06-01-PLAN.md — donna-tools.cjs: centralized CLI utility with init, commit, daily-path, resolve-secret subcommands + version check
- [x] 06-02-PLAN.md — UAT merge gate, skip-setup guard, simplify adjust-tool
- [x] 06-03-PLAN.md — README improvements: grouped skills list + automation docs
- [x] 06-04-PLAN.md — Enhanced tool learning cascade in add-tool and relearn-tools
- [x] 06-05-PLAN.md — Workflow bootstrap refactor: replace inline bootstrap with donna-tools calls in all 9 workflows
27 changes: 16 additions & 11 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
gsd_state_version: 1.0
milestone: v1.0
milestone_name: milestone
status: "Phase 05 shipped — PR #35"
stopped_at: Completed 05-01-PLAN.md
last_updated: "2026-03-27T15:52:38.571Z"
status: "Phase 06 shipped — PR #36"
stopped_at: Completed 06-05-PLAN.md
last_updated: "2026-03-27T20:19:54.511Z"
progress:
total_phases: 5
completed_phases: 5
total_plans: 16
completed_plans: 16
total_phases: 6
completed_phases: 6
total_plans: 21
completed_plans: 21
---

# Project State
Expand All @@ -19,11 +19,11 @@ progress:
See: .planning/PROJECT.md (updated 2026-03-16)

**Core value:** Never forget an important task again -- the assistant knows your role, surfaces what needs attention each day, and captures everything that falls through the cracks outside your ticketing system.
**Current focus:** Phase 05fix-the-constant-timeout-warnings
**Current focus:** Phase 06polish-and-harden-version-check-skip-setup-guard-simplify-adjust-tool-uat-merge-gate-docs-and-readme-improvements-enhance-tool-learning-refactor-skill-bootstrap

## Current Position

Phase: 05
Phase: 06
Plan: Not started

## Accumulated Context
Expand All @@ -49,6 +49,10 @@ Decisions are logged in PROJECT.md Key Decisions table (17 decisions, all ✓ Go
- [Phase 04-ingest-github-issues-into-gsd]: Skill stages TODO files with git add but does not commit — developer commits in main context (CLAUDE.md SSH signing constraint)
- [Phase 05]: Use Bash tool native timeout parameter (ms) instead of external timeout binary — cross-platform, no coreutils required on macOS
- [Phase 05]: Same timeout durations preserved: 10s (10000ms) for tool commands, 15s (15000ms) for GraphQL introspection
- [Phase 06]: donna-tools.cjs exports named handlers (runInit/runCommit/runDailyPath/runResolveSecret) for direct unit testing without subprocess spawning
- [Phase 06]: fetchLatestVersion is injectable in runInit — tests mock the registry call without hitting the real npm registry
- [Phase 06-03]: Skills grouped into 4 categories in README: Setup and configuration, Daily workflow, Tool management, Help and feedback
- [Phase 06]: Tests updated from checking config/donna/config.md presence to checking donna-tools.cjs init — tests verify the refactored bootstrap contract

### Pending Todos

Expand Down Expand Up @@ -76,6 +80,7 @@ Decisions are logged in PROJECT.md Key Decisions table (17 decisions, all ✓ Go
- Phase 3 added: Prioritized now view — distill daily file to focus items
- Phase 4 added: Ingest GitHub issues into GSD (ref: #21)
- Phase 5 added: Fix the constant timeout warnings
- Phase 6 added: Polish and harden — version check, skip-setup guard, simplify adjust-tool, UAT merge gate, docs/README improvements, enhance tool learning, refactor skill bootstrap

### Quick Tasks Completed

Expand All @@ -85,5 +90,5 @@ Decisions are logged in PROJECT.md Key Decisions table (17 decisions, all ✓ Go

## Session Continuity

Last session: 2026-03-27T16:00:00.000Z
Stopped at: Completed 05-01-PLAN.md
Last session: 2026-03-27T20:07:55.189Z
Stopped at: Completed 06-05-PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
---
phase: 06-polish-and-harden
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- src/donna-tools.cjs
- test/donna-tools.test.cjs
autonomous: true
requirements: [D-01, D-02, D-03, D-10, D-11]

must_haves:
truths:
- "donna-tools init returns JSON with storage_repo, daily_folder, auto_push, update_available, migrations_applied, error fields"
- "donna-tools commit runs git add, status, commit, and conditional push, returning JSON result"
- "donna-tools daily-path returns today's daily file path and creates directory if missing"
- "donna-tools resolve-secret reads secrets.md and returns resolved value or error for placeholders"
- "Version check caches result per day in ~/.donna/version-check.md and does not block on network failure"
artifacts:
- path: "src/donna-tools.cjs"
provides: "CLI entry point with subcommand router"
exports: ["main"]
contains: "async function main"
- path: "test/donna-tools.test.cjs"
provides: "Unit tests for all 4 subcommands + version check"
min_lines: 100
key_links:
- from: "src/donna-tools.cjs"
to: "src/version.cjs"
via: "require for readVersion"
pattern: "require.*version\\.cjs"
- from: "src/donna-tools.cjs"
to: "src/migrator.cjs"
via: "require for runMigrations"
pattern: "require.*migrator\\.cjs"
---

<objective>
Create `src/donna-tools.cjs` — a centralized CLI utility following the gsd-tools.cjs pattern — with all 4 initial subcommands (init, commit, daily-path, resolve-secret) plus the once-per-day version check integrated into init.

Purpose: This is the foundation module that all workflow refactoring (Plan 05) depends on. It consolidates ~75 lines of duplicated bootstrap boilerplate into a single reusable CLI entry point per D-10/D-11.

Output: `src/donna-tools.cjs` with working subcommands, `test/donna-tools.test.cjs` with full coverage.
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/06-polish-and-harden-version-check-skip-setup-guard-simplify-adjust-tool-uat-merge-gate-docs-and-readme-improvements-enhance-tool-learning-refactor-skill-bootstrap/06-CONTEXT.md
@.planning/phases/06-polish-and-harden-version-check-skip-setup-guard-simplify-adjust-tool-uat-merge-gate-docs-and-readme-improvements-enhance-tool-learning-refactor-skill-bootstrap/06-RESEARCH.md

<interfaces>
<!-- Existing modules that donna-tools.cjs will reuse -->

From src/version.cjs:
```javascript
function readVersion(donnaDir) // returns { version, lastMigration, installed, updated } or null
function writeVersion(donnaDir, version, lastMigration) // writes ~/.donna/version.md
```

From src/migrator.cjs:
```javascript
function runMigrations(migrationsDir, donnaDir, lastMigration)
// returns Array<{num, description, ok, error?}>
```

From src/output.cjs:
```javascript
// Banner/info/success/fail formatting functions
```

From src/changelog.cjs:
```javascript
function semverGt(a, b) // returns true if a > b (semver comparison)
```
</interfaces>
</context>

<tasks>

<task type="auto" tdd="true">
<name>Task 1: Create donna-tools.cjs with all 4 subcommands and version check</name>
<files>src/donna-tools.cjs, test/donna-tools.test.cjs</files>
<read_first>
- src/version.cjs (readVersion/writeVersion signatures and version.md format)
- src/migrator.cjs (runMigrations signature — migrationsDir, donnaDir, lastMigration)
- src/changelog.cjs (semverGt function for version comparison)
- src/installer.cjs (to see how migrator is called — lines 44, 58)
- workflows/relearn-tools.md (lines 1-83 — the bootstrap pattern being replaced: read-config step lines 8-22, check-pending-migrations step lines 24-83)
- test/installer.test.cjs (makeTempHome and captureOutput helper patterns for test setup)
</read_first>
<behavior>
- Test: `donna-tools init` with valid config.md returns JSON with storage_repo, daily_folder, auto_push fields
- Test: `donna-tools init` without config.md returns JSON with `{"error": "not_configured", "storage_repo": null}`
- Test: `donna-tools init` reads config from `~/.config/donna/config.md` YAML frontmatter
- Test: `donna-tools init` includes `update_available: null` when version-check.md has today's date (cache hit)
- Test: `donna-tools init` runs migrations via migrator.cjs and returns migrations_applied array
- Test: `donna-tools commit "msg" --files f1 f2` stages files, checks porcelain, commits, returns JSON
- Test: `donna-tools commit` skips commit when porcelain is empty, returns `{"committed": false}`
- Test: `donna-tools commit` pushes when auto_push is true
- Test: `donna-tools daily-path` returns `<storage_repo>/<daily_folder>/YYYY-MM-DD.md` and creates directory
- Test: `donna-tools resolve-secret <key>` reads `<storage_repo>/donna/secrets.md`, extracts value for key
- Test: `donna-tools resolve-secret <key>` returns error when value is a placeholder like `your-token-here`
- Test: unknown subcommand prints error to stderr and exits with code 1
</behavior>
<action>
Create `src/donna-tools.cjs` as a CJS module per D-10, following the gsd-tools.cjs pattern exactly:

**Router structure:**
```javascript
"use strict";
async function main() {
const args = process.argv.slice(2);
const cmd = args[0];
if (cmd === 'init') { /* ... */ }
if (cmd === 'commit') { /* ... */ }
if (cmd === 'daily-path') { /* ... */ }
if (cmd === 'resolve-secret') { /* ... */ }
process.stderr.write(`Unknown command: ${cmd}\n`);
process.exit(1);
}
main().catch(err => { process.stderr.write(err.message + '\n'); process.exit(1); });
```

**`init` subcommand (per D-11):**
1. Read `~/.config/donna/config.md` — parse YAML frontmatter for `storage_repo`, `daily_folder` (default: `"daily"`), `auto_push` (default: `false`). If file doesn't exist, return `{"error": "not_configured", "storage_repo": null}`.
2. Run Obsidian daily-notes sync: check `<storage_repo>/.obsidian/daily-notes.json` for `folder` field, sync with `daily_folder` if different, or write it if missing.
3. Run migrations: call `migrator.runMigrations(migrationsDir, donnaDir, lastMigration)` where `migrationsDir` resolves to `__dirname + '/../migrations'` and `donnaDir` is `~/.donna/`. Return names of applied migrations in `migrations_applied` array.
4. Version check (per D-01/D-03): Read `~/.donna/version-check.md`. If `checked_on` matches today's date (YYYY-MM-DD), use cached `latest_version`. Otherwise, fetch `https://registry.npmjs.org/@pingvinen%2Fdonna-assistant` via `node:https` with 3000ms socket timeout. Parse `dist-tags.latest` from JSON response. Write cache file. Compare with current version from `version.cjs readVersion`. Set `update_available` to latest version string if newer (use `semverGt` from changelog.cjs), otherwise `null`. On ANY error (timeout, ENOTFOUND, parse error), set `update_available: null` — never throw.
5. Return JSON: `{ storage_repo, daily_folder, auto_push, update_available, migrations_applied, error: null }`

**Version cache file format** (`~/.donna/version-check.md`):
```
---
checked_on: 2026-03-27
latest_version: 1.0.0
---
```

**`commit` subcommand (per D-11):**
Args: `commit <msg> --files f1 f2 ...`
1. Parse message (first arg after `commit`) and files (args after `--files`).
2. Read storage_repo from `~/.config/donna/config.md` (same config reader as init).
3. For each file in `--files`, run `git -C <storage_repo> add <file>`. If no `--files`, run `git -C <storage_repo> add -A`.
4. Run `git -C <storage_repo> status --porcelain`. If empty, return `{"committed": false, "reason": "nothing_to_commit"}`.
5. Run `git -C <storage_repo> commit -m <msg>`. Return `{"committed": true, "message": <msg>}`.
6. If `auto_push` is true, run `git -C <storage_repo> push`.

Use `require("node:child_process").execSync` for git commands. Wrap in try/catch, return `{"error": <msg>}` on failure.

**`daily-path` subcommand (per D-11):**
1. Read config for `storage_repo` and `daily_folder`.
2. Compute today's date as `YYYY-MM-DD`.
3. Construct path: `<storage_repo>/<daily_folder>/<YYYY-MM-DD>.md`
4. Create directory `<storage_repo>/<daily_folder>/` if it doesn't exist (`fs.mkdirSync` with `recursive: true`).
5. Return `{"path": "<computed_path>"}`.

**`resolve-secret` subcommand (per D-11):**
Args: `resolve-secret <key>`
1. Read config for `storage_repo`.
2. Read `<storage_repo>/donna/secrets.md`.
3. Parse markdown looking for `- <key>: <value>` pattern.
4. If key not found, return `{"error": "key_not_found", "key": "<key>"}`.
5. If value matches placeholder patterns (`your-*-here`, `TODO`, `PLACEHOLDER`, `xxx`, `<...>`), return `{"error": "placeholder_value", "key": "<key>", "value": "<value>"}`.
6. Return `{"key": "<key>", "value": "<resolved_value>"}`.

**Test file** `test/donna-tools.test.cjs`:
Use same patterns as `test/installer.test.cjs`: `makeTempHome` helper for temp dirs, `require("node:test")` with `describe/it/beforeEach/afterEach`, `assert/strict`. For testing subcommands, extract the handler functions and export them (or use `child_process.execSync("node src/donna-tools.cjs ...")` in tests). Prefer extracting functions for unit testability: export `runInit`, `runCommit`, `runDailyPath`, `runResolveSecret` as named exports alongside `main`.

For the version check network call, inject the fetch function so tests can mock it without hitting the real registry.

Run `npm run lint:fix` after creating both files.
</action>
<verify>
<automated>npm test</automated>
</verify>
<acceptance_criteria>
- src/donna-tools.cjs contains `async function main()`
- src/donna-tools.cjs contains `if (cmd === 'init')`
- src/donna-tools.cjs contains `if (cmd === 'commit')`
- src/donna-tools.cjs contains `if (cmd === 'daily-path')`
- src/donna-tools.cjs contains `if (cmd === 'resolve-secret')`
- src/donna-tools.cjs contains `registry.npmjs.org`
- src/donna-tools.cjs contains `version-check.md`
- src/donna-tools.cjs contains `require("./version.cjs")`
- src/donna-tools.cjs contains `require("./migrator.cjs")`
- test/donna-tools.test.cjs exists and has at least 10 test cases
- `npm test` exits 0
- `npm run lint` exits 0
- `node src/donna-tools.cjs init 2>&1` produces JSON output (may have error field if no config)
- `node src/donna-tools.cjs unknown-cmd 2>&1` exits with non-zero code
</acceptance_criteria>
<done>All 4 subcommands implemented and tested. donna-tools.cjs is a working CLI entry point that returns JSON. Version check uses HTTPS with 3s timeout and caches per-day. Tests cover all subcommands including error paths.</done>
</task>

</tasks>

<verification>
- `npm test` passes (all donna-tools.test.cjs tests green)
- `npm run lint` passes
- `node src/donna-tools.cjs init` returns valid JSON
- `node src/donna-tools.cjs daily-path` returns valid JSON with a path field
- `node src/donna-tools.cjs unknown` exits non-zero
</verification>

<success_criteria>
- donna-tools.cjs exists with all 4 subcommands producing JSON output
- Version check integrated into init with cache and 3s timeout
- Full test coverage for all subcommands and error paths
- All tests and linting pass
</success_criteria>

<output>
After completion, create `.planning/phases/06-polish-and-harden-version-check-skip-setup-guard-simplify-adjust-tool-uat-merge-gate-docs-and-readme-improvements-enhance-tool-learning-refactor-skill-bootstrap/06-01-SUMMARY.md`
</output>
Loading
Loading