gsd-pi 2.78.1-dev.b0759e59b → 2.78.1-dev.e9d88a536
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/dist/headless-recover.d.ts +23 -0
- package/dist/headless-recover.js +93 -0
- package/dist/headless.js +9 -0
- package/dist/help-text.js +1 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +8 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +4 -56
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -27
- package/dist/resources/extensions/gsd/auto-start.js +1 -8
- package/dist/resources/extensions/gsd/auto-worktree.js +59 -176
- package/dist/resources/extensions/gsd/auto.js +24 -6
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -77
- package/dist/resources/extensions/gsd/commands-codebase.js +2 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +5 -5
- package/dist/resources/extensions/gsd/commands-logs.js +2 -2
- package/dist/resources/extensions/gsd/commands-scan.js +2 -2
- package/dist/resources/extensions/gsd/commands-ship.js +2 -2
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +5 -5
- package/dist/resources/extensions/gsd/db-writer.js +16 -85
- package/dist/resources/extensions/gsd/dispatch-guard.js +6 -10
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +2 -2
- package/dist/resources/extensions/gsd/gsd-db.js +74 -8
- package/dist/resources/extensions/gsd/guided-flow.js +31 -8
- package/dist/resources/extensions/gsd/markdown-renderer.js +14 -51
- package/dist/resources/extensions/gsd/parallel-merge.js +14 -13
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +5 -2
- package/dist/resources/extensions/gsd/paths.js +35 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
- package/dist/resources/extensions/gsd/queue-order.js +6 -1
- package/dist/resources/extensions/gsd/rethink.js +2 -2
- package/dist/resources/extensions/gsd/state.js +91 -372
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -5
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -12
- package/dist/resources/extensions/gsd/tools/complete-task.js +19 -31
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -5
- package/dist/resources/extensions/gsd/workflow-manifest.js +2 -1
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -21
- package/dist/resources/extensions/gsd/workflow-reconcile.js +3 -3
- package/dist/resources/extensions/gsd/worktree-command.js +4 -3
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/chunks/6336.js +1 -0
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +6 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +56 -2
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/parse-workflow-args.test.ts +80 -0
- package/packages/mcp-server/src/workflow-tools.ts +61 -2
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +13 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +4 -60
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -26
- package/src/resources/extensions/gsd/auto-start.ts +1 -8
- package/src/resources/extensions/gsd/auto-worktree.ts +61 -204
- package/src/resources/extensions/gsd/auto.ts +23 -6
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +9 -84
- package/src/resources/extensions/gsd/commands-codebase.ts +2 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +5 -5
- package/src/resources/extensions/gsd/commands-logs.ts +2 -2
- package/src/resources/extensions/gsd/commands-scan.ts +2 -2
- package/src/resources/extensions/gsd/commands-ship.ts +2 -2
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +5 -5
- package/src/resources/extensions/gsd/db-writer.ts +16 -83
- package/src/resources/extensions/gsd/dispatch-guard.ts +6 -11
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +2 -2
- package/src/resources/extensions/gsd/gsd-db.ts +85 -8
- package/src/resources/extensions/gsd/guided-flow.ts +35 -8
- package/src/resources/extensions/gsd/markdown-renderer.ts +13 -64
- package/src/resources/extensions/gsd/parallel-merge.ts +14 -13
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +5 -2
- package/src/resources/extensions/gsd/paths.ts +55 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
- package/src/resources/extensions/gsd/queue-order.ts +6 -1
- package/src/resources/extensions/gsd/rethink.ts +2 -2
- package/src/resources/extensions/gsd/state.ts +91 -389
- package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +21 -34
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +6 -7
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +12 -27
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +18 -5
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +10 -38
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +136 -56
- package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +119 -61
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +6 -20
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +14 -15
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +11 -16
- package/src/resources/extensions/gsd/tests/escalation.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +15 -36
- package/src/resources/extensions/gsd/tests/handler-worktree-write-isolation.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +15 -15
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +15 -5
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +14 -8
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +25 -16
- package/src/resources/extensions/gsd/tests/projection-regression.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +184 -0
- package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/resolve-ts.mjs +4 -0
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +10 -56
- package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +15 -16
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +23 -27
- package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +13 -14
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +10 -33
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +12 -7
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +65 -71
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +26 -151
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -5
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -14
- package/src/resources/extensions/gsd/tools/complete-task.ts +19 -34
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +7 -5
- package/src/resources/extensions/gsd/workflow-manifest.ts +4 -1
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -18
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/worktree-command.ts +4 -3
- package/dist/web/standalone/.next/server/chunks/8527.js +0 -1
- /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → oZGTPvJBQX_IDKKnuV8Bt}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → oZGTPvJBQX_IDKKnuV8Bt}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -310,7 +310,9 @@ This is what makes GSD different. Run it, walk away, come back to built software
|
|
|
310
310
|
/gsd auto
|
|
311
311
|
```
|
|
312
312
|
|
|
313
|
-
Auto mode is a state machine driven by
|
|
313
|
+
Auto mode is a state machine driven by the GSD database at the project root. It derives the next unit of work from authoritative SQLite state, creates a fresh agent session, injects a focused prompt with all relevant context pre-inlined, and lets the LLM execute. When the LLM finishes, auto mode persists the result to the database, refreshes markdown projections such as `STATE.md`, and dispatches the next unit.
|
|
314
|
+
|
|
315
|
+
The database is authoritative for milestones, slices, tasks, requirements, decisions, summaries, and completion status. Markdown under `.gsd/` is a rendered projection for review, prompts, and git-friendly history; it is not a runtime fallback unless you explicitly run a recovery/import command. In worktree mode, project-root DB state remains authoritative and worktree markdown projections are not synced back as state.
|
|
314
316
|
|
|
315
317
|
**What happens under the hood:**
|
|
316
318
|
|
|
@@ -499,6 +501,7 @@ Every dispatch is carefully constructed. The LLM never wastes tool calls on orie
|
|
|
499
501
|
|
|
500
502
|
| Artifact | Purpose |
|
|
501
503
|
| ------------------ | --------------------------------------------------------------- |
|
|
504
|
+
| `gsd.db` | Authoritative runtime state for hierarchy and completion |
|
|
502
505
|
| `PROJECT.md` | Living doc — what the project is right now |
|
|
503
506
|
| `REQUIREMENTS.md` | Project-level capability contract and out-of-scope list |
|
|
504
507
|
| `DECISIONS.md` | Append-only register of architectural decisions |
|
|
@@ -506,7 +509,7 @@ Every dispatch is carefully constructed. The LLM never wastes tool calls on orie
|
|
|
506
509
|
| `RUNTIME.md` | Runtime context — API endpoints, env vars, services (v2.39) |
|
|
507
510
|
| `runtime/research-decision.json` | Deep-mode marker for project research vs skip |
|
|
508
511
|
| `research/*.md` | Optional deep-mode project research: stack, features, architecture, pitfalls |
|
|
509
|
-
| `STATE.md` | Quick-glance dashboard
|
|
512
|
+
| `STATE.md` | Quick-glance dashboard rendered from the database |
|
|
510
513
|
| `M001-ROADMAP.md` | Milestone plan with slice checkboxes, risk levels, dependencies |
|
|
511
514
|
| `M001-CONTEXT.md` | User decisions from the discuss phase |
|
|
512
515
|
| `M001-RESEARCH.md` | Codebase and ecosystem research |
|
|
@@ -708,7 +711,7 @@ The best practice for working in teams is to ensure unique milestone names acros
|
|
|
708
711
|
.gsd/completed-units*.json
|
|
709
712
|
# State manifest — workflow state for recovery
|
|
710
713
|
.gsd/state-manifest.json
|
|
711
|
-
# Derived state
|
|
714
|
+
# Derived state projection — regenerated from the authoritative database
|
|
712
715
|
.gsd/STATE.md
|
|
713
716
|
# Per-developer token/cost accumulator
|
|
714
717
|
.gsd/metrics.json
|
|
@@ -720,7 +723,7 @@ The best practice for working in teams is to ensure unique milestone names acros
|
|
|
720
723
|
.gsd/worktrees/
|
|
721
724
|
# Parallel orchestration IPC and worker status
|
|
722
725
|
.gsd/parallel/
|
|
723
|
-
# SQLite database and WAL sidecars —
|
|
726
|
+
# SQLite database and WAL sidecars — authoritative runtime state, local only
|
|
724
727
|
.gsd/gsd.db*
|
|
725
728
|
# Daily-rotated event journal — structured event log for forensics
|
|
726
729
|
.gsd/journal/
|
|
@@ -785,7 +788,7 @@ gsd (CLI binary)
|
|
|
785
788
|
- **`pkg/` shim directory** — `PI_PACKAGE_DIR` points here (not project root) to avoid Pi's theme resolution collision with our `src/` directory. Contains only `piConfig` and theme assets.
|
|
786
789
|
- **Two-file loader pattern** — `loader.ts` sets all env vars with zero SDK imports, then dynamic-imports `cli.ts` which does static SDK imports. This ensures `PI_PACKAGE_DIR` is set before any SDK code evaluates.
|
|
787
790
|
- **Always-overwrite sync** — `npm update -g` takes effect immediately. Bundled extensions and agents are synced to `~/.gsd/agent/` on every launch, not just first run.
|
|
788
|
-
- **
|
|
791
|
+
- **DB-authoritative state** — the project-root GSD database is the runtime source of truth. `.gsd/` markdown files are rendered projections for review, prompt context, and git history. No in-memory state survives across sessions.
|
|
789
792
|
|
|
790
793
|
---
|
|
791
794
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless Recover — `gsd headless recover`
|
|
3
|
+
*
|
|
4
|
+
* Non-interactive parallel of the `/gsd recover` slash command. Clears the
|
|
5
|
+
* milestones / slices / tasks tables and re-imports them from the on-disk
|
|
6
|
+
* markdown projections (ROADMAP.md, PLAN.md, SUMMARY.md, …) via
|
|
7
|
+
* migrateHierarchyToDb. Mutating: this is the one headless subcommand that
|
|
8
|
+
* writes to the DB. Required for CI / automation flows that need to
|
|
9
|
+
* reconcile DB state from markdown without launching an LLM session or a
|
|
10
|
+
* TTY-bound interactive runtime.
|
|
11
|
+
*
|
|
12
|
+
* Output: `gsd-recover: recovered <N>M/<N>S/<N>T hierarchy\n` to stderr on
|
|
13
|
+
* success — same marker emitted by handleRecover (commands-maintenance.ts)
|
|
14
|
+
* so callers can distinguish the success path from a silent no-op.
|
|
15
|
+
*
|
|
16
|
+
* Exit codes:
|
|
17
|
+
* 0 — recovery succeeded
|
|
18
|
+
* 1 — `.gsd/` missing, DB could not be opened, or migration threw
|
|
19
|
+
*/
|
|
20
|
+
export interface RecoverResult {
|
|
21
|
+
exitCode: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function handleRecover(basePath: string): Promise<RecoverResult>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// gsd-pi — Headless Recover entrypoint
|
|
2
|
+
/**
|
|
3
|
+
* Headless Recover — `gsd headless recover`
|
|
4
|
+
*
|
|
5
|
+
* Non-interactive parallel of the `/gsd recover` slash command. Clears the
|
|
6
|
+
* milestones / slices / tasks tables and re-imports them from the on-disk
|
|
7
|
+
* markdown projections (ROADMAP.md, PLAN.md, SUMMARY.md, …) via
|
|
8
|
+
* migrateHierarchyToDb. Mutating: this is the one headless subcommand that
|
|
9
|
+
* writes to the DB. Required for CI / automation flows that need to
|
|
10
|
+
* reconcile DB state from markdown without launching an LLM session or a
|
|
11
|
+
* TTY-bound interactive runtime.
|
|
12
|
+
*
|
|
13
|
+
* Output: `gsd-recover: recovered <N>M/<N>S/<N>T hierarchy\n` to stderr on
|
|
14
|
+
* success — same marker emitted by handleRecover (commands-maintenance.ts)
|
|
15
|
+
* so callers can distinguish the success path from a silent no-op.
|
|
16
|
+
*
|
|
17
|
+
* Exit codes:
|
|
18
|
+
* 0 — recovery succeeded
|
|
19
|
+
* 1 — `.gsd/` missing, DB could not be opened, or migration threw
|
|
20
|
+
*/
|
|
21
|
+
import { createJiti } from '@mariozechner/jiti';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import { resolveGsdAgentExtensionsDir, shouldUseAgentExtensionsDir } from './headless-query.js';
|
|
24
|
+
import { resolveBundledGsdExtensionModule } from './bundled-resource-path.js';
|
|
25
|
+
import { join } from 'node:path';
|
|
26
|
+
import { existsSync } from 'node:fs';
|
|
27
|
+
const jiti = createJiti(fileURLToPath(import.meta.url), { interopDefault: true, debug: false });
|
|
28
|
+
const agentExtensionsDir = resolveGsdAgentExtensionsDir();
|
|
29
|
+
const { useAgentDir } = shouldUseAgentExtensionsDir({ env: process.env });
|
|
30
|
+
const gsdExtensionPath = (...segments) => useAgentDir
|
|
31
|
+
? resolveAgentExtensionModule(agentExtensionsDir, segments)
|
|
32
|
+
: resolveBundledGsdExtensionModule(import.meta.url, segments.join('/'));
|
|
33
|
+
function resolveAgentExtensionModule(agentDir, segments) {
|
|
34
|
+
const requested = join(agentDir, ...segments);
|
|
35
|
+
if (existsSync(requested))
|
|
36
|
+
return requested;
|
|
37
|
+
if (segments.length === 1 && segments[0].endsWith('.ts')) {
|
|
38
|
+
const jsPath = join(agentDir, segments[0].replace(/\.ts$/, '.js'));
|
|
39
|
+
if (existsSync(jsPath))
|
|
40
|
+
return jsPath;
|
|
41
|
+
}
|
|
42
|
+
return requested;
|
|
43
|
+
}
|
|
44
|
+
async function loadExtensionModules() {
|
|
45
|
+
const stateModule = await jiti.import(gsdExtensionPath('state.ts'), {});
|
|
46
|
+
const dbModule = await jiti.import(gsdExtensionPath('gsd-db.ts'), {});
|
|
47
|
+
const importerModule = await jiti.import(gsdExtensionPath('md-importer.ts'), {});
|
|
48
|
+
const dynamicToolsModule = await jiti.import(gsdExtensionPath('bootstrap/dynamic-tools.ts'), {});
|
|
49
|
+
return {
|
|
50
|
+
ensureDbOpen: dynamicToolsModule.ensureDbOpen,
|
|
51
|
+
isDbAvailable: dbModule.isDbAvailable,
|
|
52
|
+
clearEngineHierarchy: dbModule.clearEngineHierarchy,
|
|
53
|
+
transaction: dbModule.transaction,
|
|
54
|
+
migrateHierarchyToDb: importerModule.migrateHierarchyToDb,
|
|
55
|
+
invalidateStateCache: stateModule.invalidateStateCache,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export async function handleRecover(basePath) {
|
|
59
|
+
const gsdDir = join(basePath, '.gsd');
|
|
60
|
+
if (!existsSync(gsdDir)) {
|
|
61
|
+
process.stderr.write(`[headless] recover: no .gsd/ directory at ${basePath}\n`);
|
|
62
|
+
return { exitCode: 1 };
|
|
63
|
+
}
|
|
64
|
+
let modules;
|
|
65
|
+
try {
|
|
66
|
+
modules = await loadExtensionModules();
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
70
|
+
process.stderr.write(`[headless] recover: failed to load extension modules: ${msg}\n`);
|
|
71
|
+
return { exitCode: 1 };
|
|
72
|
+
}
|
|
73
|
+
const opened = await modules.ensureDbOpen(basePath);
|
|
74
|
+
if (!opened || !modules.isDbAvailable()) {
|
|
75
|
+
process.stderr.write(`[headless] recover: failed to open or create the GSD database at ${basePath}\n`);
|
|
76
|
+
return { exitCode: 1 };
|
|
77
|
+
}
|
|
78
|
+
let counts;
|
|
79
|
+
try {
|
|
80
|
+
counts = modules.transaction(() => {
|
|
81
|
+
modules.clearEngineHierarchy();
|
|
82
|
+
return modules.migrateHierarchyToDb(basePath);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
87
|
+
process.stderr.write(`[headless] recover failed: ${msg}\n`);
|
|
88
|
+
return { exitCode: 1 };
|
|
89
|
+
}
|
|
90
|
+
modules.invalidateStateCache();
|
|
91
|
+
process.stderr.write(`gsd-recover: recovered ${counts.milestones}M/${counts.slices}S/${counts.tasks}T hierarchy\n`);
|
|
92
|
+
return { exitCode: 0 };
|
|
93
|
+
}
|
package/dist/headless.js
CHANGED
|
@@ -265,6 +265,15 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
265
265
|
const result = await handleQuery(process.cwd());
|
|
266
266
|
return { exitCode: result.exitCode, interrupted: false };
|
|
267
267
|
}
|
|
268
|
+
// Recover: rebuild DB hierarchy from on-disk markdown projections, no RPC
|
|
269
|
+
// child needed. This is the one mutating headless subcommand — required for
|
|
270
|
+
// CI / automation that needs to reconcile DB state from markdown without
|
|
271
|
+
// launching an interactive TTY-bound runtime.
|
|
272
|
+
if (options.command === 'recover') {
|
|
273
|
+
const { handleRecover } = await import('./headless-recover.js');
|
|
274
|
+
const result = await handleRecover(process.cwd());
|
|
275
|
+
process.exit(result.exitCode);
|
|
276
|
+
}
|
|
268
277
|
// Doctor: read-only health check, no RPC child needed (#4904 live-regression).
|
|
269
278
|
// The interactive `/gsd doctor` command lives in the GSD extension; this CLI
|
|
270
279
|
// path lets non-interactive callers (CI, recovery scripts, the live-regression
|
package/dist/help-text.js
CHANGED
|
@@ -156,6 +156,7 @@ const SUBCOMMAND_HELP = {
|
|
|
156
156
|
' gsd headless --answers answers.json auto With pre-supplied answers',
|
|
157
157
|
' gsd headless --events agent_end,extension_ui_request auto Filtered event stream',
|
|
158
158
|
' gsd headless query Instant JSON state snapshot',
|
|
159
|
+
' gsd headless recover Rebuild DB hierarchy from markdown (mutating)',
|
|
159
160
|
'',
|
|
160
161
|
'Exit codes: 0 = success, 1 = error/timeout, 10 = blocked, 11 = cancelled',
|
|
161
162
|
].join('\n'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
d371193140538b9c
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
-
import { StringEnum } from "@gsd/pi-ai";
|
|
3
2
|
import { diffCompactStates } from "../core.js";
|
|
4
3
|
import { setLastActionBeforeState, setLastActionAfterState, } from "../state.js";
|
|
5
4
|
// ---------------------------------------------------------------------------
|
|
@@ -15,6 +14,14 @@ const INTENTS = [
|
|
|
15
14
|
"auth_action",
|
|
16
15
|
"back_navigation",
|
|
17
16
|
];
|
|
17
|
+
function StringEnum(values, options) {
|
|
18
|
+
return Type.Unsafe({
|
|
19
|
+
type: "string",
|
|
20
|
+
enum: values,
|
|
21
|
+
...(options?.description && { description: options.description }),
|
|
22
|
+
...(options?.default && { default: options.default }),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
18
25
|
// ---------------------------------------------------------------------------
|
|
19
26
|
// Scoring evaluate script — runs entirely in-browser via page.evaluate()
|
|
20
27
|
// ---------------------------------------------------------------------------
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* without modifying orchestration code.
|
|
10
10
|
*/
|
|
11
11
|
import { loadFile, extractUatType, loadActiveOverrides } from "./files.js";
|
|
12
|
-
import { isDbAvailable, getMilestoneSlices, getPendingGates, markAllGatesOmitted, getMilestone
|
|
12
|
+
import { isDbAvailable, getMilestoneSlices, getPendingGates, markAllGatesOmitted, getMilestone } from "./gsd-db.js";
|
|
13
13
|
import { isClosedStatus } from "./status-guards.js";
|
|
14
14
|
import { extractVerdict, isAcceptableUatVerdict } from "./verdict-parser.js";
|
|
15
15
|
import { gsdRoot, resolveMilestoneFile, resolveMilestonePath, resolveSliceFile, resolveTaskFile, relSliceFile, buildMilestoneFileName, } from "./paths.js";
|
|
@@ -19,7 +19,6 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "
|
|
|
19
19
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
20
20
|
import { join } from "node:path";
|
|
21
21
|
import { hasImplementationArtifacts } from "./auto-recovery.js";
|
|
22
|
-
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
23
22
|
import { buildDiscussMilestonePrompt, buildDiscussProjectPrompt, buildDiscussRequirementsPrompt, buildResearchDecisionPrompt, buildResearchProjectPrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildRefineSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, buildGateEvaluatePrompt, buildParallelResearchSlicesPrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
|
|
24
23
|
import { resolveModelWithFallbacksForUnit } from "./preferences-models.js";
|
|
25
24
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
@@ -720,13 +719,9 @@ export const DISPATCH_RULES = [
|
|
|
720
719
|
// while a slice is still `is_sketch=1`, fall through to a standard
|
|
721
720
|
// plan-slice so the loop doesn't dead-end.
|
|
722
721
|
//
|
|
723
|
-
// Note on the flag-OFF downgrade:
|
|
724
|
-
//
|
|
725
|
-
//
|
|
726
|
-
// next iteration. That implicit coupling is the sole mechanism that
|
|
727
|
-
// reconciles `is_sketch=1` on the plan-slice path — do not remove the
|
|
728
|
-
// auto-heal without either adding an explicit `setSliceSketchFlag(..., false)`
|
|
729
|
-
// call here or doing so inside the plan-slice tool handler.
|
|
722
|
+
// Note on the flag-OFF downgrade: DB slice metadata is authoritative.
|
|
723
|
+
// PLAN.md is only a projection, so plan-slice/refine-slice handlers must
|
|
724
|
+
// explicitly clear `is_sketch` when a sketch becomes a full plan.
|
|
730
725
|
name: "refining → refine-slice",
|
|
731
726
|
match: async ({ state, mid, midTitle, basePath, prefs, sessionContextWindow, modelRegistry, sessionProvider }) => {
|
|
732
727
|
if (state.phase !== "refining")
|
|
@@ -1037,14 +1032,6 @@ export const DISPATCH_RULES = [
|
|
|
1037
1032
|
return { action: "skip" };
|
|
1038
1033
|
}
|
|
1039
1034
|
}
|
|
1040
|
-
const existingSummary = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
1041
|
-
let summaryOutcome = "unknown";
|
|
1042
|
-
if (existingSummary) {
|
|
1043
|
-
const summaryContent = await loadFile(existingSummary);
|
|
1044
|
-
if (summaryContent) {
|
|
1045
|
-
summaryOutcome = classifyMilestoneSummaryContent(summaryContent);
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
1035
|
// Safety guard (#2675): block completion when VALIDATION verdict is
|
|
1049
1036
|
// needs-remediation. The state machine treats needs-remediation as
|
|
1050
1037
|
// terminal (to prevent validate-milestone loops per #832), but
|
|
@@ -1121,45 +1108,6 @@ export const DISPATCH_RULES = [
|
|
|
1121
1108
|
catch (err) { /* fall through — don't block on DB errors */
|
|
1122
1109
|
logWarning("dispatch", `verification class check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1123
1110
|
}
|
|
1124
|
-
// Disk/DB mismatch handling (#4658): SUMMARY presence alone is not enough.
|
|
1125
|
-
// Apply post-gate policy:
|
|
1126
|
-
// - success summary: reconcile DB and skip re-dispatch
|
|
1127
|
-
// - failure summary: pause/fail-closed
|
|
1128
|
-
// - unknown summary: pause/fail-closed
|
|
1129
|
-
if (existingSummary) {
|
|
1130
|
-
const milestone = isDbAvailable() ? getMilestone(mid) : null;
|
|
1131
|
-
const status = milestone?.status ?? (isDbAvailable() ? "missing" : "unavailable");
|
|
1132
|
-
if (summaryOutcome === "success") {
|
|
1133
|
-
if (!isDbAvailable()) {
|
|
1134
|
-
logWarning("dispatch", `Milestone ${mid} SUMMARY indicates completion while DB is unavailable — skipping duplicate complete-milestone dispatch`);
|
|
1135
|
-
return { action: "skip" };
|
|
1136
|
-
}
|
|
1137
|
-
try {
|
|
1138
|
-
updateMilestoneStatus(mid, "complete", new Date().toISOString());
|
|
1139
|
-
logWarning("dispatch", `Milestone ${mid} SUMMARY indicates completion while DB status was "${status}" — reconciled DB to complete (#4658)`);
|
|
1140
|
-
return { action: "skip" };
|
|
1141
|
-
}
|
|
1142
|
-
catch (err) {
|
|
1143
|
-
return {
|
|
1144
|
-
action: "stop",
|
|
1145
|
-
level: "warning",
|
|
1146
|
-
reason: `Milestone ${mid} SUMMARY indicates completion but DB reconciliation failed (${err instanceof Error ? err.message : String(err)}). Auto-mode paused for manual review.`,
|
|
1147
|
-
};
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
if (summaryOutcome === "failure") {
|
|
1151
|
-
return {
|
|
1152
|
-
action: "stop",
|
|
1153
|
-
level: "warning",
|
|
1154
|
-
reason: `Milestone ${mid} has a failure-path SUMMARY while DB status is "${status}". Auto-mode will not promote completion from failure artifacts. Re-run complete-milestone only after blockers are resolved and verification passes.`,
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
return {
|
|
1158
|
-
action: "stop",
|
|
1159
|
-
level: "warning",
|
|
1160
|
-
reason: `Milestone ${mid} has an ambiguous SUMMARY while DB status is "${status}". Auto-mode paused instead of promoting completion from file presence alone.`,
|
|
1161
|
-
};
|
|
1162
|
-
}
|
|
1163
1111
|
return {
|
|
1164
1112
|
action: "dispatch",
|
|
1165
1113
|
unitType: "complete-milestone",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Post-unit processing for auto-loop — auto-commit, doctor run,
|
|
3
|
-
* state rebuild,
|
|
3
|
+
* state rebuild, projection checks, DB tool closeout, hooks, triage, and
|
|
4
4
|
* quick-task dispatch.
|
|
5
5
|
*
|
|
6
6
|
* Split into two functions called sequentially by auto-loop with
|
|
@@ -24,7 +24,7 @@ import { runTurnGitAction, } from "./git-service.js";
|
|
|
24
24
|
import { verifyExpectedArtifact, resolveExpectedArtifactPath, writeBlockerPlaceholder, diagnoseExpectedArtifact, } from "./auto-recovery.js";
|
|
25
25
|
import { regenerateIfMissing } from "./workflow-projections.js";
|
|
26
26
|
import { syncStateToProjectRoot } from "./auto-worktree.js";
|
|
27
|
-
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus,
|
|
27
|
+
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
|
|
28
28
|
import { renderPlanCheckboxes } from "./markdown-renderer.js";
|
|
29
29
|
import { consumeSignal } from "./session-status-io.js";
|
|
30
30
|
import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookState, resolveHookArtifactPath, } from "./post-unit-hooks.js";
|
|
@@ -109,9 +109,8 @@ import { autoCommitCurrentBranch } from "./worktree.js";
|
|
|
109
109
|
* the completion tool. A "rogue" file is one that exists on disk but has
|
|
110
110
|
* no corresponding DB row with status "complete".
|
|
111
111
|
*
|
|
112
|
-
* This is a safety-net diagnostic (D003).
|
|
113
|
-
*
|
|
114
|
-
* detection provides immediate diagnostics so operators know the prompt failed.
|
|
112
|
+
* This is a safety-net diagnostic (D003). Runtime detection never imports
|
|
113
|
+
* markdown into the DB; explicit migration/import/recovery commands own that.
|
|
115
114
|
*/
|
|
116
115
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
117
116
|
function hasNonEmptyFields(row, fields) {
|
|
@@ -145,15 +144,7 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
|
|
|
145
144
|
return [];
|
|
146
145
|
const dbRow = getSlice(mid, sid);
|
|
147
146
|
if (!dbRow || dbRow.status !== "complete") {
|
|
148
|
-
|
|
149
|
-
// match filesystem instead of reporting as rogue (#3633).
|
|
150
|
-
try {
|
|
151
|
-
updateSliceStatus(mid, sid, "complete", new Date().toISOString());
|
|
152
|
-
}
|
|
153
|
-
catch {
|
|
154
|
-
// If DB update fails, fall back to rogue detection so the issue is visible
|
|
155
|
-
rogues.push({ path: summaryPath, unitType, unitId });
|
|
156
|
-
}
|
|
147
|
+
rogues.push({ path: summaryPath, unitType, unitId });
|
|
157
148
|
}
|
|
158
149
|
}
|
|
159
150
|
else if (unitType === "plan-milestone") {
|
|
@@ -628,7 +619,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
628
619
|
ctx.ui.notify(`slice-cadence merge conflict in ${sid}: ${err.conflictedFiles.join(", ")}. ` +
|
|
629
620
|
`Resolve manually on main and run \`/gsd auto\` to resume.`, "error");
|
|
630
621
|
// Stop auto AND signal the outer postUnit flow to exit early.
|
|
631
|
-
// Without the flag, subsequent hooks (triage,
|
|
622
|
+
// Without the flag, subsequent hooks (triage,
|
|
632
623
|
// DB writes) would keep running against a conflicted main
|
|
633
624
|
// checkout after the loop was already told to stop.
|
|
634
625
|
const { stopAuto } = await import("./auto.js");
|
|
@@ -648,7 +639,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
648
639
|
}
|
|
649
640
|
});
|
|
650
641
|
// Exit early after stopAuto so the rest of post-unit processing
|
|
651
|
-
// (triage,
|
|
642
|
+
// (triage, hook dispatch, DB writes) doesn't run
|
|
652
643
|
// against a conflicted main checkout. Return "dispatched" to match
|
|
653
644
|
// the convention used by other stop/pauseAuto paths in this function
|
|
654
645
|
// (see signal handling earlier: stop/pause also return "dispatched").
|
|
@@ -689,17 +680,6 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
689
680
|
logError("engine", "triage resolution failed", { error: err.message });
|
|
690
681
|
}
|
|
691
682
|
}
|
|
692
|
-
// Rogue file detection — safety net for LLM bypassing completion tools (D003)
|
|
693
|
-
try {
|
|
694
|
-
const rogueFiles = detectRogueFileWrites(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
695
|
-
for (const rogue of rogueFiles) {
|
|
696
|
-
logWarning("engine", "rogue file write detected", { path: rogue.path, unitId: rogue.unitId });
|
|
697
|
-
ctx.ui.notify(`Rogue file write detected: ${rogue.path}`, "warning");
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
catch (e) {
|
|
701
|
-
debugLog("postUnit", { phase: "rogue-detection", error: String(e) });
|
|
702
|
-
}
|
|
703
683
|
// ── Safety harness: post-unit validation ──
|
|
704
684
|
try {
|
|
705
685
|
const { loadEffectiveGSDPreferences } = await import("./preferences.js");
|
|
@@ -649,19 +649,12 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
649
649
|
const gsdDbPath = resolveProjectRootDbPath(s.basePath);
|
|
650
650
|
const gsdDirPath = join(s.basePath, ".gsd");
|
|
651
651
|
if (existsSync(gsdDirPath) && !existsSync(gsdDbPath)) {
|
|
652
|
-
const hasDecisions = existsSync(join(gsdDirPath, "DECISIONS.md"));
|
|
653
|
-
const hasRequirements = existsSync(join(gsdDirPath, "REQUIREMENTS.md"));
|
|
654
|
-
const hasMilestones = existsSync(join(gsdDirPath, "milestones"));
|
|
655
652
|
try {
|
|
656
653
|
const { openDatabase: openDb } = await import("./gsd-db.js");
|
|
657
654
|
openDb(gsdDbPath);
|
|
658
|
-
if (hasDecisions || hasRequirements || hasMilestones) {
|
|
659
|
-
const { migrateFromMarkdown } = await import("./md-importer.js");
|
|
660
|
-
migrateFromMarkdown(s.basePath);
|
|
661
|
-
}
|
|
662
655
|
}
|
|
663
656
|
catch (err) {
|
|
664
|
-
logError("engine", `
|
|
657
|
+
logError("engine", `failed to initialize project database: ${err.message}`);
|
|
665
658
|
}
|
|
666
659
|
}
|
|
667
660
|
if (existsSync(gsdDbPath) && !isDbAvailable()) {
|