gsd-pi 2.78.1-dev.b0759e59b → 2.78.1-dev.d8826a445
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/phases.js +7 -2
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +7 -58
- package/dist/resources/extensions/gsd/auto-post-unit.js +14 -28
- package/dist/resources/extensions/gsd/auto-start.js +1 -8
- package/dist/resources/extensions/gsd/auto-worktree.js +244 -216
- package/dist/resources/extensions/gsd/auto.js +86 -7
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -77
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -16
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +67 -55
- 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 +106 -95
- package/dist/resources/extensions/gsd/delegation-policy.js +155 -0
- 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 +268 -8
- package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
- package/dist/resources/extensions/gsd/guided-flow.js +141 -32
- package/dist/resources/extensions/gsd/markdown-renderer.js +14 -51
- package/dist/resources/extensions/gsd/metrics.js +287 -1
- 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 +114 -9
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -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/templates/project.md +10 -0
- 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-mcp.js +2 -2
- package/dist/resources/extensions/gsd/workflow-reconcile.js +3 -3
- package/dist/resources/extensions/gsd/workspace.js +59 -0
- package/dist/resources/extensions/gsd/worktree-command.js +4 -3
- package/dist/resources/extensions/gsd/worktree-resolver.js +15 -2
- package/dist/resources/extensions/gsd/write-intercept.js +3 -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/required-server-files.json +1 -1
- 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/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/README.md +2 -11
- package/packages/mcp-server/dist/remote-questions.d.ts +27 -0
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
- package/packages/mcp-server/dist/remote-questions.js +28 -0
- package/packages/mcp-server/dist/remote-questions.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts +28 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +94 -4
- package/packages/mcp-server/dist/server.js.map +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/mcp-server.test.ts +226 -0
- package/packages/mcp-server/src/parse-workflow-args.test.ts +80 -0
- package/packages/mcp-server/src/remote-questions.test.ts +103 -0
- package/packages/mcp-server/src/remote-questions.ts +35 -0
- package/packages/mcp-server/src/server.ts +129 -6
- package/packages/mcp-server/src/workflow-tools.ts +62 -3
- 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/phases.ts +8 -2
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -62
- package/src/resources/extensions/gsd/auto-post-unit.ts +15 -27
- package/src/resources/extensions/gsd/auto-start.ts +1 -8
- package/src/resources/extensions/gsd/auto-worktree.ts +286 -251
- package/src/resources/extensions/gsd/auto.ts +102 -7
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +9 -84
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -17
- package/src/resources/extensions/gsd/bootstrap/tests/write-gate-basepath.test.ts +103 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -55
- 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 +123 -94
- package/src/resources/extensions/gsd/delegation-policy.ts +197 -0
- 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 +269 -8
- package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
- package/src/resources/extensions/gsd/guided-flow.ts +181 -32
- package/src/resources/extensions/gsd/markdown-renderer.ts +13 -64
- package/src/resources/extensions/gsd/metrics.ts +321 -1
- 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 +122 -9
- package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -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/templates/project.md +10 -0
- package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +14 -14
- 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/auto-session-scope.test.ts +331 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +176 -0
- 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-path-containment.test.ts +152 -0
- package/src/resources/extensions/gsd/tests/db-writer-root-artifact.test.ts +221 -0
- package/src/resources/extensions/gsd/tests/db-writer-scope.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/delegation-policy.test.ts +151 -0
- 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-backgroundable-annotation.test.ts +55 -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/draft-promotion.test.ts +3 -23
- 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/gate-1b-orphan-discrimination.test.ts +193 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +246 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +218 -0
- package/src/resources/extensions/gsd/tests/gsd-db-failed-open-restore.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/gsd-db-workspace-scope.test.ts +226 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/gsd-root-canonical.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/gsd-root-home-guard.test.ts +68 -5
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +15 -36
- package/src/resources/extensions/gsd/tests/guided-flow-prompt-consolidation.test.ts +4 -4
- 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/integration/workspace-collapse-integration.test.ts +371 -0
- 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/metrics-atomic-merge.test.ts +222 -0
- package/src/resources/extensions/gsd/tests/metrics-lock-hardening.test.ts +400 -0
- package/src/resources/extensions/gsd/tests/metrics-lock-not-acquired.test.ts +141 -0
- package/src/resources/extensions/gsd/tests/metrics-lock-retry-sleep.test.ts +287 -0
- package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +149 -0
- package/src/resources/extensions/gsd/tests/metrics-scope.test.ts +378 -0
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +329 -0
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/path-cache-decoupled.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/path-normalization-unified.test.ts +175 -0
- package/src/resources/extensions/gsd/tests/paths-cache.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +120 -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/prompt-contracts.test.ts +150 -7
- 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/register-hooks-depth-verification.test.ts +28 -16
- 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/resume-missing-worktree-warning.test.ts +209 -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-layer-scope.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +10 -33
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +162 -0
- package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +1 -1
- 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/validator-scope-parity.test.ts +239 -0
- 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 +26 -3
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/workspace.test.ts +190 -0
- 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/tests/write-gate-predicates.test.ts +35 -35
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -52
- package/src/resources/extensions/gsd/tests/write-intercept.test.ts +1 -1
- 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-mcp.ts +2 -2
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/workspace.ts +95 -0
- package/src/resources/extensions/gsd/worktree-command.ts +4 -3
- package/src/resources/extensions/gsd/worktree-resolver.ts +16 -2
- package/src/resources/extensions/gsd/write-intercept.ts +3 -3
- package/dist/web/standalone/.next/server/chunks/8527.js +0 -1
- /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → AT5qi39nKXkdmQIOIoh0f}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → AT5qi39nKXkdmQIOIoh0f}/_ssgManifest.js +0 -0
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { showNextAction } from "../shared/tui.js";
|
|
9
9
|
import { loadFile, saveFile } from "./files.js";
|
|
10
|
-
import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
|
|
10
|
+
import { isDbAvailable, getMilestone, getMilestoneSlices } from "./gsd-db.js";
|
|
11
11
|
import { parseRoadmapSlices } from "./roadmap-slices.js";
|
|
12
12
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
13
13
|
import { buildCompleteSlicePrompt, buildDiscussMilestonePrompt, buildExecuteTaskPrompt, buildPlanMilestonePrompt, buildPlanSlicePrompt, buildSkillActivationBlock, } from "./auto-prompts.js";
|
|
14
|
-
import { deriveState } from "./state.js";
|
|
14
|
+
import { deriveState, isGhostMilestone } from "./state.js";
|
|
15
15
|
import { invalidateAllCaches } from "./cache.js";
|
|
16
16
|
import { startAutoDetached } from "./auto.js";
|
|
17
17
|
import { clearLock } from "./crash-recovery.js";
|
|
@@ -19,7 +19,7 @@ import { assessInterruptedSession, formatInterruptedSessionRunningMessage, forma
|
|
|
19
19
|
import { listUnitRuntimeRecords, clearUnitRuntimeRecord } from "./unit-runtime.js";
|
|
20
20
|
import { resolveExpectedArtifactPath } from "./auto.js";
|
|
21
21
|
import { gsdHome } from "./gsd-home.js";
|
|
22
|
-
import { gsdRoot, milestonesDir, resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveGsdRootFile, relGsdRootFile, relMilestoneFile, relSliceFile, } from "./paths.js";
|
|
22
|
+
import { gsdRoot, milestonesDir, resolveMilestoneFile, resolveMilestonePath, resolveSliceFile, resolveSlicePath, resolveGsdRootFile, relGsdRootFile, relMilestoneFile, relSliceFile, clearPathCache, } from "./paths.js";
|
|
23
23
|
import { join } from "node:path";
|
|
24
24
|
import { readFileSync, existsSync, mkdirSync, readdirSync, rmSync, unlinkSync } from "node:fs";
|
|
25
25
|
import { readSessionLockData, isSessionLockProcessAlive } from "./session-lock.js";
|
|
@@ -43,10 +43,39 @@ import { DISCUSS_TOOLS_ALLOWLIST } from "./constants.js";
|
|
|
43
43
|
import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForGuidedUnit, supportsStructuredQuestions, } from "./workflow-mcp.js";
|
|
44
44
|
import { runPreparation, formatCodebaseBrief, formatPriorContextBrief, } from "./preparation.js";
|
|
45
45
|
import { verifyExpectedArtifact } from "./auto-recovery.js";
|
|
46
|
+
import { createWorkspace, scopeMilestone } from "./workspace.js";
|
|
46
47
|
// ─── Re-exports (preserve public API for existing importers) ────────────────
|
|
47
48
|
export { MILESTONE_ID_RE, generateMilestoneSuffix, nextMilestoneId, extractMilestoneSeq, parseMilestoneId, milestoneIdSort, maxMilestoneNum, findMilestoneIds, reserveMilestoneId, claimReservedId, getReservedMilestoneIds, clearReservedMilestoneIds, } from "./milestone-ids.js";
|
|
48
49
|
export { showQueue, handleQueueReorder, showQueueAdd, buildExistingMilestonesContext, } from "./guided-flow-queue.js";
|
|
49
50
|
import { logWarning } from "./workflow-logger.js";
|
|
51
|
+
// ─── Scope-based validator wrappers ──────────────────────────────────────────
|
|
52
|
+
// These thin wrappers accept a MilestoneScope so callers that already hold a
|
|
53
|
+
// pinned scope never have to re-derive (basePath, milestoneId) separately.
|
|
54
|
+
// The underlying implementations in auto-recovery.ts / auto-artifact-paths.ts /
|
|
55
|
+
// state.ts are unchanged — only the call surface in guided-flow.ts is migrated.
|
|
56
|
+
/**
|
|
57
|
+
* Scope-based overload of verifyExpectedArtifact.
|
|
58
|
+
* Uses scope.workspace.projectRoot as the authoritative base path, making
|
|
59
|
+
* the check immune to cwd-drift and worktree-path divergence.
|
|
60
|
+
*/
|
|
61
|
+
export function verifyExpectedArtifactForScope(scope, unitType, unitId) {
|
|
62
|
+
return verifyExpectedArtifact(unitType, unitId, scope.workspace.projectRoot);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Scope-based overload of resolveExpectedArtifactPath.
|
|
66
|
+
* Returns the canonical absolute path (or null) using the scope's projectRoot.
|
|
67
|
+
*/
|
|
68
|
+
export function resolveExpectedArtifactPathForScope(scope, unitType, unitId) {
|
|
69
|
+
return resolveExpectedArtifactPath(unitType, unitId, scope.workspace.projectRoot);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Scope-based overload of isGhostMilestone.
|
|
73
|
+
* Binds basePath and milestoneId from the scope, ensuring path resolution
|
|
74
|
+
* uses the canonical project root regardless of the cwd at call time.
|
|
75
|
+
*/
|
|
76
|
+
export function isGhostMilestoneByScope(scope) {
|
|
77
|
+
return isGhostMilestone(scope.workspace.projectRoot, scope.milestoneId);
|
|
78
|
+
}
|
|
50
79
|
function needsPlanV2Gate(state) {
|
|
51
80
|
return state.phase === "executing"
|
|
52
81
|
|| state.phase === "summarizing"
|
|
@@ -77,6 +106,10 @@ function buildDocsCommitInstruction(_message) {
|
|
|
77
106
|
// #4573: cap for how many times we nudge the LLM after a premature ready
|
|
78
107
|
// phrase before giving up and asking the user to re-run /gsd.
|
|
79
108
|
const MAX_READY_REJECTS = 2;
|
|
109
|
+
// H1 (#5012): cap for Gate 1b plan-blocked recovery hints. After this many
|
|
110
|
+
// consecutive recovery attempts the loop is stopped and the user is directed
|
|
111
|
+
// to investigate manually.
|
|
112
|
+
const MAX_PLAN_BLOCKED_RECOVERIES = 3;
|
|
80
113
|
// #4573: matches the canonical ready phrase the discuss prompt asks the LLM
|
|
81
114
|
// to emit. Accepts any M-prefixed milestone ID (three digits + optional
|
|
82
115
|
// suffix) with optional trailing punctuation.
|
|
@@ -110,9 +143,9 @@ This stage is running inside the foreground \`/gsd new-project --deep\` intervie
|
|
|
110
143
|
/**
|
|
111
144
|
* Backward-compat bridge: returns a mutable reference to the entry matching
|
|
112
145
|
* basePath, or the sole entry when only one session exists.
|
|
113
|
-
*
|
|
146
|
+
* Exported for testing — internal use only in production code.
|
|
114
147
|
*/
|
|
115
|
-
function _getPendingAutoStart(basePath) {
|
|
148
|
+
export function _getPendingAutoStart(basePath) {
|
|
116
149
|
if (basePath)
|
|
117
150
|
return pendingAutoStartMap.get(basePath) ?? null;
|
|
118
151
|
if (pendingAutoStartMap.size === 1)
|
|
@@ -157,7 +190,9 @@ function clearEmptyLegacyDeepSetupPseudoMilestones(basePath, entries) {
|
|
|
157
190
|
* Exported for testing (#2985).
|
|
158
191
|
*/
|
|
159
192
|
export function setPendingAutoStart(basePath, entry) {
|
|
160
|
-
|
|
193
|
+
const ws = createWorkspace(entry.basePath);
|
|
194
|
+
const scope = scopeMilestone(ws, entry.milestoneId);
|
|
195
|
+
pendingAutoStartMap.set(basePath, { createdAt: Date.now(), planBlockedRecoveryCount: 0, ...entry, scope });
|
|
161
196
|
}
|
|
162
197
|
/**
|
|
163
198
|
* Clear pending auto-start state.
|
|
@@ -249,6 +284,10 @@ export async function checkDeepProjectSetupAfterTurn(_event, ctx, basePath) {
|
|
|
249
284
|
if (!entry)
|
|
250
285
|
return false;
|
|
251
286
|
if (entry.currentUnitType && entry.currentUnitId) {
|
|
287
|
+
// TODO(C-future): PendingDeepProjectSetupEntry does not carry a MilestoneScope
|
|
288
|
+
// because deep-project-setup units span non-milestone unit types (discuss-project,
|
|
289
|
+
// discuss-requirements, etc.). Migrate to verifyExpectedArtifactForScope once
|
|
290
|
+
// PendingDeepProjectSetupEntry is extended with a scope field.
|
|
252
291
|
const artifactReady = verifyExpectedArtifact(entry.currentUnitType, entry.currentUnitId, entry.basePath);
|
|
253
292
|
if (!artifactReady) {
|
|
254
293
|
return false;
|
|
@@ -320,17 +359,61 @@ export function checkAutoStartAfterDiscuss() {
|
|
|
320
359
|
const { ctx, pi, basePath, milestoneId, step } = entry;
|
|
321
360
|
// Gate 1: Primary milestone must have CONTEXT.md or ROADMAP.md
|
|
322
361
|
// The "discuss" path creates CONTEXT.md; the "plan" path creates ROADMAP.md.
|
|
323
|
-
|
|
324
|
-
const
|
|
362
|
+
// Use pinned scope (immune to cwd-drift) for existence checks.
|
|
363
|
+
const contextFilePath = entry.scope.contextFile();
|
|
364
|
+
const roadmapFilePath = entry.scope.roadmapFile();
|
|
365
|
+
const contextFile = existsSync(contextFilePath) ? contextFilePath : null;
|
|
366
|
+
const roadmapFile = existsSync(roadmapFilePath) ? roadmapFilePath : null;
|
|
325
367
|
if (!contextFile && !roadmapFile)
|
|
326
368
|
return false; // neither artifact yet — keep waiting
|
|
369
|
+
// Gate 1b: Discriminate plan-blocked from discuss-incomplete when the DB row is queued.
|
|
370
|
+
// If the DB is available and the row is still "queued" but CONTEXT.md already exists on
|
|
371
|
+
// disk, the discuss phase completed but gsd_plan_milestone was hard-blocked by the
|
|
372
|
+
// depth-verification gate. Emit a recovery hint so the next agent turn can retry
|
|
373
|
+
// gsd_plan_milestone, then return false (keep blocking auto-start).
|
|
374
|
+
// If CONTEXT.md does not exist (discuss-incomplete), Gate 1 already blocked above.
|
|
375
|
+
if (isDbAvailable()) {
|
|
376
|
+
const dbRow = getMilestone(milestoneId);
|
|
377
|
+
if (dbRow?.status === "queued" && contextFile) {
|
|
378
|
+
if (entry.planBlockedRecoveryCount >= MAX_PLAN_BLOCKED_RECOVERIES) {
|
|
379
|
+
// H1: recovery loop cap reached — stop triggering new turns, escalate to user.
|
|
380
|
+
logWarning("guided", `Gate 1b: milestone ${milestoneId} plan-blocked recovery limit reached ` +
|
|
381
|
+
`(${entry.planBlockedRecoveryCount}/${MAX_PLAN_BLOCKED_RECOVERIES}); escalating to user`);
|
|
382
|
+
ctx.ui.notify(`Milestone ${milestoneId} plan_milestone has been blocked ${entry.planBlockedRecoveryCount} times. ` +
|
|
383
|
+
`Re-run /gsd to reset the recovery counter, or run /gsd-debug to diagnose without resetting.`, "error");
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
logWarning("guided", `Gate 1b: milestone ${milestoneId} queued with CONTEXT.md present — ` +
|
|
387
|
+
`plan_milestone was blocked; emitting recovery hint ` +
|
|
388
|
+
`(attempt ${entry.planBlockedRecoveryCount + 1}/${MAX_PLAN_BLOCKED_RECOVERIES})`);
|
|
389
|
+
ctx.ui.notify(`Milestone ${milestoneId}: context file exists but milestone is still queued. ` +
|
|
390
|
+
`Retrying gsd_plan_milestone to complete the blocked planning step.`, "warning");
|
|
391
|
+
try {
|
|
392
|
+
pi.sendMessage({
|
|
393
|
+
customType: "gsd-plan-milestone-blocked-recovery",
|
|
394
|
+
content: `Milestone ${milestoneId} has ${contextFile} on disk but its DB row is still ` +
|
|
395
|
+
`"queued". The gsd_plan_milestone tool was previously blocked by the ` +
|
|
396
|
+
`depth-verification gate. Call gsd_plan_milestone now to complete the ` +
|
|
397
|
+
`planning phase.`,
|
|
398
|
+
display: false,
|
|
399
|
+
}, { triggerTurn: true });
|
|
400
|
+
// Increment only after a successful dispatch so transient sendMessage
|
|
401
|
+
// failures do not consume recovery budget.
|
|
402
|
+
entry.planBlockedRecoveryCount += 1;
|
|
403
|
+
}
|
|
404
|
+
catch (e) {
|
|
405
|
+
logWarning("guided", `Gate 1b recovery sendMessage failed: ${e.message}`);
|
|
406
|
+
}
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
327
410
|
// Gate 2: STATE.md must exist — written as the last step in the discuss
|
|
328
411
|
// output phase. This prevents auto-start from firing during Phase 3
|
|
329
412
|
// (sequential readiness gates for remaining milestones) in multi-milestone
|
|
330
413
|
// discussions, where M001-CONTEXT.md exists but M002/M003 haven't been
|
|
331
414
|
// processed yet.
|
|
332
|
-
const
|
|
333
|
-
if (!
|
|
415
|
+
const stateFilePath = entry.scope.stateFile();
|
|
416
|
+
if (!existsSync(stateFilePath))
|
|
334
417
|
return false; // discussion not finalized yet
|
|
335
418
|
// Gate 3: Multi-milestone completeness warning
|
|
336
419
|
// Parse PROJECT.md for milestone sequence, warn if any are missing context.
|
|
@@ -362,7 +445,7 @@ export function checkAutoStartAfterDiscuss() {
|
|
|
362
445
|
// The LLM writes DISCUSSION-MANIFEST.json after each Phase 3 gate decision.
|
|
363
446
|
// When it exists, validate it before auto-starting. Project history alone is
|
|
364
447
|
// not a reliable signal for the current discussion mode.
|
|
365
|
-
const manifestPath = join(
|
|
448
|
+
const manifestPath = join(entry.scope.workspace.contract.projectGsd, "DISCUSSION-MANIFEST.json");
|
|
366
449
|
if (existsSync(manifestPath)) {
|
|
367
450
|
try {
|
|
368
451
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
@@ -486,12 +569,35 @@ export function maybeHandleReadyPhraseWithoutFiles(event) {
|
|
|
486
569
|
const text = extractAssistantText(lastMsg);
|
|
487
570
|
if (!READY_PHRASE_RE.test(text))
|
|
488
571
|
return false;
|
|
572
|
+
// Bust paths.ts cached dir listings before checking for fresh writes. The
|
|
573
|
+
// LLM's Write tool calls do not invalidate paths.ts caches, so a stale
|
|
574
|
+
// listing taken before the milestone dir or its CONTEXT/ROADMAP files
|
|
575
|
+
// existed would falsely report the artifacts as missing and trigger the
|
|
576
|
+
// 3-strike "ready without files" abort even though the writes succeeded.
|
|
577
|
+
clearPathCache();
|
|
489
578
|
// Gate: artifacts must still be missing — if they exist, the happy path
|
|
490
579
|
// already fired and we have nothing to do.
|
|
491
580
|
const contextFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT");
|
|
492
581
|
const roadmapFile = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
493
582
|
if (contextFile || roadmapFile)
|
|
494
583
|
return false;
|
|
584
|
+
// Diagnostic: when the cached resolver reports both files missing, also probe
|
|
585
|
+
// the canonical paths with uncached existsSync so we can tell whether the
|
|
586
|
+
// recovery is firing on real-missing files or a path-resolution miss
|
|
587
|
+
// (basePath/symlink mismatch, stale cache despite agent-end-recovery flush,
|
|
588
|
+
// legacy descriptor dir not matching, etc.).
|
|
589
|
+
try {
|
|
590
|
+
const mDir = resolveMilestonePath(basePath, milestoneId);
|
|
591
|
+
const canonicalCtx = mDir ? join(mDir, `${milestoneId}-CONTEXT.md`) : null;
|
|
592
|
+
const canonicalRoadmap = mDir ? join(mDir, `${milestoneId}-ROADMAP.md`) : null;
|
|
593
|
+
logWarning("guided", `ready-phrase-reject diagnostic mid=${milestoneId} basePath=${basePath} ` +
|
|
594
|
+
`mDir=${mDir ?? "null"} ` +
|
|
595
|
+
`canonical-ctx=${canonicalCtx ?? "null"} ctx-exists=${canonicalCtx ? existsSync(canonicalCtx) : "n/a"} ` +
|
|
596
|
+
`canonical-roadmap=${canonicalRoadmap ?? "null"} roadmap-exists=${canonicalRoadmap ? existsSync(canonicalRoadmap) : "n/a"}`);
|
|
597
|
+
}
|
|
598
|
+
catch (e) {
|
|
599
|
+
logWarning("guided", `ready-phrase-reject diagnostic failed: ${e.message}`);
|
|
600
|
+
}
|
|
495
601
|
entry.readyRejectCount = (entry.readyRejectCount ?? 0) + 1;
|
|
496
602
|
if (entry.readyRejectCount > MAX_READY_REJECTS) {
|
|
497
603
|
// Give up: clear state and tell the user to re-run /gsd. Avoids an
|
|
@@ -576,14 +682,14 @@ export function maybeHandleEmptyIntentTurn(event, isAuto) {
|
|
|
576
682
|
// path, handled by maybeHandleReadyPhraseWithoutFiles.
|
|
577
683
|
if (READY_PHRASE_RE.test(text))
|
|
578
684
|
return false;
|
|
579
|
-
// Skip if the LLM is clearly handing back to the user.
|
|
580
|
-
//
|
|
581
|
-
//
|
|
582
|
-
//
|
|
583
|
-
//
|
|
685
|
+
// Skip if the LLM is clearly handing back to the user. Discuss flows
|
|
686
|
+
// often pose a question and follow it with a conditional intent on the
|
|
687
|
+
// same line ("Did I capture that correctly? If so, I'll write the
|
|
688
|
+
// requirements."). A line-trailing `?` check misses these because the
|
|
689
|
+
// line ends in `.`. Match any sentence-terminating `?` (followed by
|
|
690
|
+
// whitespace or end-of-text) — false negatives here auto-reply to the
|
|
584
691
|
// user, which is a much worse failure mode than a missed nudge.
|
|
585
|
-
|
|
586
|
-
if (lines.some((l) => l.endsWith("?")))
|
|
692
|
+
if (/\?(?:\s|$)/.test(text))
|
|
587
693
|
return false;
|
|
588
694
|
// Must contain a commit-intent phrase — this is the stall we care about.
|
|
589
695
|
if (!COMMIT_INTENT_RE.test(text))
|
|
@@ -873,7 +979,7 @@ export async function showHeadlessMilestoneCreation(ctx, pi, basePath, seedConte
|
|
|
873
979
|
// Build and dispatch the headless discuss prompt
|
|
874
980
|
const prompt = buildHeadlessDiscussPrompt(nextId, seedContext, basePath);
|
|
875
981
|
// Set pending auto start (auto-mode triggers on "Milestone X ready." via checkAutoStartAfterDiscuss)
|
|
876
|
-
|
|
982
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId });
|
|
877
983
|
// Dispatch as discuss-milestone. The LLM writes PROJECT.md, REQUIREMENTS.md,
|
|
878
984
|
// and CONTEXT.md, then calls gsd_plan_milestone — this is semantically the
|
|
879
985
|
// discuss path, just non-interactive. Using "plan-milestone" here caused
|
|
@@ -1039,13 +1145,13 @@ export async function showDiscuss(ctx, pi, basePath) {
|
|
|
1039
1145
|
const seed = draftContent
|
|
1040
1146
|
? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
|
|
1041
1147
|
: basePrompt;
|
|
1042
|
-
|
|
1148
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: mid, step: false });
|
|
1043
1149
|
await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "discuss-milestone");
|
|
1044
1150
|
}
|
|
1045
1151
|
else if (choice === "discuss_fresh") {
|
|
1046
1152
|
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1047
1153
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1048
|
-
|
|
1154
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: mid, step: false });
|
|
1049
1155
|
await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
|
|
1050
1156
|
milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
1051
1157
|
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
@@ -1058,7 +1164,7 @@ export async function showDiscuss(ctx, pi, basePath) {
|
|
|
1058
1164
|
const milestoneIds = findMilestoneIds(basePath);
|
|
1059
1165
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
1060
1166
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
1061
|
-
|
|
1167
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: false });
|
|
1062
1168
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
|
|
1063
1169
|
}
|
|
1064
1170
|
return;
|
|
@@ -1312,6 +1418,9 @@ function selfHealRuntimeRecords(basePath, ctx) {
|
|
|
1312
1418
|
for (const record of records) {
|
|
1313
1419
|
const { unitType, unitId, phase } = record;
|
|
1314
1420
|
// Clear records whose expected artifact already exists (completed but not cleaned up)
|
|
1421
|
+
// TODO(C-future): selfHealRuntimeRecords iterates across all unit types (not just milestone
|
|
1422
|
+
// units), so it cannot be converted to resolveExpectedArtifactPathForScope without
|
|
1423
|
+
// first establishing a per-record scope. Migrate once unit runtime records carry scope info.
|
|
1315
1424
|
const artifactPath = resolveExpectedArtifactPath(unitType, unitId, basePath);
|
|
1316
1425
|
if (artifactPath && existsSync(artifactPath)) {
|
|
1317
1426
|
clearUnitRuntimeRecord(basePath, unitType, unitId);
|
|
@@ -1414,7 +1523,7 @@ async function handleMilestoneActions(ctx, pi, basePath, milestoneId, milestoneT
|
|
|
1414
1523
|
const milestoneIds = findMilestoneIds(basePath);
|
|
1415
1524
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
1416
1525
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
1417
|
-
|
|
1526
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1418
1527
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
|
|
1419
1528
|
return true;
|
|
1420
1529
|
}
|
|
@@ -1619,7 +1728,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1619
1728
|
const isFirst = milestoneIds.length === 0;
|
|
1620
1729
|
if (isFirst) {
|
|
1621
1730
|
// First ever — skip wizard, just ask directly
|
|
1622
|
-
|
|
1731
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1623
1732
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New project, milestone ${nextId}. Do NOT read or explore .gsd/ — it's empty scaffolding.`, basePath), "gsd-run", ctx, "discuss-milestone");
|
|
1624
1733
|
}
|
|
1625
1734
|
else {
|
|
@@ -1637,7 +1746,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1637
1746
|
notYetMessage: "Run /gsd when ready.",
|
|
1638
1747
|
});
|
|
1639
1748
|
if (choice === "new_milestone") {
|
|
1640
|
-
|
|
1749
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1641
1750
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
|
|
1642
1751
|
}
|
|
1643
1752
|
}
|
|
@@ -1646,7 +1755,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1646
1755
|
const milestoneId = state.activeMilestone.id;
|
|
1647
1756
|
const milestoneTitle = state.activeMilestone.title;
|
|
1648
1757
|
if (planV2GateDecision === "recover-missing-context") {
|
|
1649
|
-
|
|
1758
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
1650
1759
|
await dispatchWorkflow(pi, await buildDiscussMilestonePrompt(milestoneId, milestoneTitle, basePath, getStructuredQuestionsAvailability(pi, ctx)), "gsd-discuss", ctx, "discuss-milestone");
|
|
1651
1760
|
return;
|
|
1652
1761
|
}
|
|
@@ -1674,7 +1783,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1674
1783
|
const milestoneIds = findMilestoneIds(basePath);
|
|
1675
1784
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
1676
1785
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
1677
|
-
|
|
1786
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1678
1787
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
|
|
1679
1788
|
}
|
|
1680
1789
|
else if (choice === "status") {
|
|
@@ -1721,13 +1830,13 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1721
1830
|
const seed = draftContent
|
|
1722
1831
|
? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
|
|
1723
1832
|
: basePrompt;
|
|
1724
|
-
|
|
1833
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
1725
1834
|
await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "discuss-milestone");
|
|
1726
1835
|
}
|
|
1727
1836
|
else if (choice === "discuss_fresh") {
|
|
1728
1837
|
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1729
1838
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1730
|
-
|
|
1839
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
1731
1840
|
await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
|
|
1732
1841
|
milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
1733
1842
|
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
@@ -1738,7 +1847,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1738
1847
|
const milestoneIds = findMilestoneIds(basePath);
|
|
1739
1848
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
1740
1849
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
1741
|
-
|
|
1850
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1742
1851
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
|
|
1743
1852
|
}
|
|
1744
1853
|
return;
|
|
@@ -1794,7 +1903,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1794
1903
|
notYetMessage: "Run /gsd when ready.",
|
|
1795
1904
|
});
|
|
1796
1905
|
if (choice === "plan") {
|
|
1797
|
-
|
|
1906
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
1798
1907
|
await dispatchWorkflow(pi, await buildPlanMilestonePrompt(milestoneId, milestoneTitle, basePath), "gsd-run", ctx, "plan-milestone");
|
|
1799
1908
|
}
|
|
1800
1909
|
else if (choice === "discuss") {
|
|
@@ -1810,7 +1919,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1810
1919
|
const milestoneIds = findMilestoneIds(basePath);
|
|
1811
1920
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
1812
1921
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
1813
|
-
|
|
1922
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1814
1923
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
|
|
1815
1924
|
}
|
|
1816
1925
|
else if (choice === "discard_milestone") {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// GSD Markdown Renderer — DB → Markdown file generation
|
|
2
2
|
//
|
|
3
3
|
// Transforms DB state into correct markdown files on disk.
|
|
4
|
-
// Each render function reads from DB
|
|
5
|
-
//
|
|
6
|
-
// stores updated content in the artifacts table, and invalidates caches.
|
|
4
|
+
// Each render function reads from DB, writes a markdown projection to disk,
|
|
5
|
+
// stores generated content in the artifacts table, and invalidates caches.
|
|
7
6
|
//
|
|
8
7
|
// Critical invariant: rendered markdown must round-trip through
|
|
9
8
|
// parseRoadmap(), parsePlan(), parseSummary() in files.ts.
|
|
@@ -60,45 +59,16 @@ function taskSummaryForSlicePlan(description) {
|
|
|
60
59
|
return firstBlock || beforeHeading;
|
|
61
60
|
}
|
|
62
61
|
/**
|
|
63
|
-
* Load artifact content from DB
|
|
64
|
-
*
|
|
65
|
-
*
|
|
62
|
+
* Load artifact content from the DB. Markdown projections are not authoritative
|
|
63
|
+
* during runtime; when the artifact row is missing, callers regenerate from DB
|
|
64
|
+
* rows instead of patching disk fallback content and storing it back.
|
|
66
65
|
*/
|
|
67
|
-
function loadArtifactContent(artifactPath
|
|
68
|
-
// Try DB first
|
|
66
|
+
function loadArtifactContent(artifactPath) {
|
|
69
67
|
const artifact = getArtifact(artifactPath);
|
|
70
68
|
if (artifact && artifact.full_content) {
|
|
71
69
|
return artifact.full_content;
|
|
72
70
|
}
|
|
73
|
-
|
|
74
|
-
if (!absPath) {
|
|
75
|
-
process.stderr.write(`markdown-renderer: artifact not found in DB or on disk: ${artifactPath}\n`);
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
let content;
|
|
79
|
-
try {
|
|
80
|
-
content = readFileSync(absPath, "utf-8");
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
logWarning("renderer", `cannot read file from disk: ${absPath}`);
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
// Store in DB for future use (graceful degradation path)
|
|
87
|
-
try {
|
|
88
|
-
insertArtifact({
|
|
89
|
-
path: artifactPath,
|
|
90
|
-
artifact_type: opts.artifact_type,
|
|
91
|
-
milestone_id: opts.milestone_id,
|
|
92
|
-
slice_id: opts.slice_id ?? null,
|
|
93
|
-
task_id: opts.task_id ?? null,
|
|
94
|
-
full_content: content,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
// Non-fatal: we have the content, DB storage is best-effort
|
|
99
|
-
logWarning("renderer", `failed to store disk fallback in DB: ${artifactPath}`);
|
|
100
|
-
}
|
|
101
|
-
return content;
|
|
71
|
+
return null;
|
|
102
72
|
}
|
|
103
73
|
/**
|
|
104
74
|
* Write rendered content to disk and update the artifacts table.
|
|
@@ -401,17 +371,14 @@ export async function renderRoadmapCheckboxes(basePath, milestoneId) {
|
|
|
401
371
|
}
|
|
402
372
|
const absPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
403
373
|
const artifactPath = absPath ? toArtifactPath(absPath, basePath) : null;
|
|
404
|
-
// Load content from DB
|
|
374
|
+
// Load content from DB; regenerate from DB rows when the artifact is absent.
|
|
405
375
|
let content = null;
|
|
406
376
|
if (artifactPath) {
|
|
407
|
-
content = loadArtifactContent(artifactPath
|
|
408
|
-
artifact_type: "ROADMAP",
|
|
409
|
-
milestone_id: milestoneId,
|
|
410
|
-
});
|
|
377
|
+
content = loadArtifactContent(artifactPath);
|
|
411
378
|
}
|
|
412
379
|
if (!content) {
|
|
413
|
-
|
|
414
|
-
return
|
|
380
|
+
await renderRoadmapFromDb(basePath, milestoneId);
|
|
381
|
+
return true;
|
|
415
382
|
}
|
|
416
383
|
// Apply checkbox patches for each slice
|
|
417
384
|
let updated = content;
|
|
@@ -454,15 +421,11 @@ export async function renderPlanCheckboxes(basePath, milestoneId, sliceId) {
|
|
|
454
421
|
const artifactPath = absPath ? toArtifactPath(absPath, basePath) : null;
|
|
455
422
|
let content = null;
|
|
456
423
|
if (artifactPath) {
|
|
457
|
-
content = loadArtifactContent(artifactPath
|
|
458
|
-
artifact_type: "PLAN",
|
|
459
|
-
milestone_id: milestoneId,
|
|
460
|
-
slice_id: sliceId,
|
|
461
|
-
});
|
|
424
|
+
content = loadArtifactContent(artifactPath);
|
|
462
425
|
}
|
|
463
426
|
if (!content) {
|
|
464
|
-
|
|
465
|
-
return
|
|
427
|
+
await renderPlanFromDb(basePath, milestoneId, sliceId);
|
|
428
|
+
return true;
|
|
466
429
|
}
|
|
467
430
|
// Apply checkbox patches for each task
|
|
468
431
|
let updated = content;
|