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
|
@@ -10,7 +10,7 @@ import type { ExtensionAPI, ExtensionContext, ExtensionCommandContext } from "@g
|
|
|
10
10
|
import type { GSDState } from "./types.js";
|
|
11
11
|
import { showNextAction } from "../shared/tui.js";
|
|
12
12
|
import { loadFile, saveFile } from "./files.js";
|
|
13
|
-
import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
|
|
13
|
+
import { isDbAvailable, getMilestone, getMilestoneSlices } from "./gsd-db.js";
|
|
14
14
|
import { parseRoadmapSlices } from "./roadmap-slices.js";
|
|
15
15
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
16
16
|
import {
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
buildPlanSlicePrompt,
|
|
22
22
|
buildSkillActivationBlock,
|
|
23
23
|
} from "./auto-prompts.js";
|
|
24
|
-
import { deriveState } from "./state.js";
|
|
24
|
+
import { deriveState, isGhostMilestone } from "./state.js";
|
|
25
25
|
import { invalidateAllCaches } from "./cache.js";
|
|
26
26
|
import { startAutoDetached } from "./auto.js";
|
|
27
27
|
import { clearLock } from "./crash-recovery.js";
|
|
@@ -36,7 +36,7 @@ import { gsdHome } from "./gsd-home.js";
|
|
|
36
36
|
import {
|
|
37
37
|
gsdRoot, milestonesDir, resolveMilestoneFile, resolveMilestonePath,
|
|
38
38
|
resolveSliceFile, resolveSlicePath, resolveGsdRootFile, relGsdRootFile,
|
|
39
|
-
relMilestoneFile, relSliceFile,
|
|
39
|
+
relMilestoneFile, relSliceFile, clearPathCache,
|
|
40
40
|
} from "./paths.js";
|
|
41
41
|
import { join } from "node:path";
|
|
42
42
|
import { readFileSync, existsSync, mkdirSync, readdirSync, rmSync, unlinkSync } from "node:fs";
|
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
formatPriorContextBrief,
|
|
70
70
|
} from "./preparation.js";
|
|
71
71
|
import { verifyExpectedArtifact } from "./auto-recovery.js";
|
|
72
|
+
import { createWorkspace, scopeMilestone, type MilestoneScope } from "./workspace.js";
|
|
72
73
|
|
|
73
74
|
// ─── Re-exports (preserve public API for existing importers) ────────────────
|
|
74
75
|
export {
|
|
@@ -83,6 +84,46 @@ export {
|
|
|
83
84
|
} from "./guided-flow-queue.js";
|
|
84
85
|
import { logWarning } from "./workflow-logger.js";
|
|
85
86
|
|
|
87
|
+
// ─── Scope-based validator wrappers ──────────────────────────────────────────
|
|
88
|
+
// These thin wrappers accept a MilestoneScope so callers that already hold a
|
|
89
|
+
// pinned scope never have to re-derive (basePath, milestoneId) separately.
|
|
90
|
+
// The underlying implementations in auto-recovery.ts / auto-artifact-paths.ts /
|
|
91
|
+
// state.ts are unchanged — only the call surface in guided-flow.ts is migrated.
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Scope-based overload of verifyExpectedArtifact.
|
|
95
|
+
* Uses scope.workspace.projectRoot as the authoritative base path, making
|
|
96
|
+
* the check immune to cwd-drift and worktree-path divergence.
|
|
97
|
+
*/
|
|
98
|
+
export function verifyExpectedArtifactForScope(
|
|
99
|
+
scope: MilestoneScope,
|
|
100
|
+
unitType: string,
|
|
101
|
+
unitId: string,
|
|
102
|
+
): boolean {
|
|
103
|
+
return verifyExpectedArtifact(unitType, unitId, scope.workspace.projectRoot);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Scope-based overload of resolveExpectedArtifactPath.
|
|
108
|
+
* Returns the canonical absolute path (or null) using the scope's projectRoot.
|
|
109
|
+
*/
|
|
110
|
+
export function resolveExpectedArtifactPathForScope(
|
|
111
|
+
scope: MilestoneScope,
|
|
112
|
+
unitType: string,
|
|
113
|
+
unitId: string,
|
|
114
|
+
): string | null {
|
|
115
|
+
return resolveExpectedArtifactPath(unitType, unitId, scope.workspace.projectRoot);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Scope-based overload of isGhostMilestone.
|
|
120
|
+
* Binds basePath and milestoneId from the scope, ensuring path resolution
|
|
121
|
+
* uses the canonical project root regardless of the cwd at call time.
|
|
122
|
+
*/
|
|
123
|
+
export function isGhostMilestoneByScope(scope: MilestoneScope): boolean {
|
|
124
|
+
return isGhostMilestone(scope.workspace.projectRoot, scope.milestoneId);
|
|
125
|
+
}
|
|
126
|
+
|
|
86
127
|
function needsPlanV2Gate(state: GSDState): boolean {
|
|
87
128
|
return state.phase === "executing"
|
|
88
129
|
|| state.phase === "summarizing"
|
|
@@ -135,6 +176,13 @@ interface PendingAutoStartEntry {
|
|
|
135
176
|
// #4573: counter for how many times the LLM emitted the ready phrase
|
|
136
177
|
// without writing the required artifacts. Cleared on entry delete/recreate.
|
|
137
178
|
readyRejectCount?: number;
|
|
179
|
+
// C1: scope is pinned at reservation time so path resolution is immune to
|
|
180
|
+
// cwd-drift between discuss and checkAutoStartAfterDiscuss.
|
|
181
|
+
// TODO(C3): basePath becomes redundant once all consumers migrate to scope.
|
|
182
|
+
scope: MilestoneScope;
|
|
183
|
+
// H1: retry counter for Gate 1b plan-blocked recovery. Capped at
|
|
184
|
+
// MAX_PLAN_BLOCKED_RECOVERIES to prevent infinite recovery loops (#5012).
|
|
185
|
+
planBlockedRecoveryCount: number;
|
|
138
186
|
}
|
|
139
187
|
|
|
140
188
|
interface PendingDeepProjectSetupEntry {
|
|
@@ -152,6 +200,11 @@ interface PendingDeepProjectSetupEntry {
|
|
|
152
200
|
// phrase before giving up and asking the user to re-run /gsd.
|
|
153
201
|
const MAX_READY_REJECTS = 2;
|
|
154
202
|
|
|
203
|
+
// H1 (#5012): cap for Gate 1b plan-blocked recovery hints. After this many
|
|
204
|
+
// consecutive recovery attempts the loop is stopped and the user is directed
|
|
205
|
+
// to investigate manually.
|
|
206
|
+
const MAX_PLAN_BLOCKED_RECOVERIES = 3;
|
|
207
|
+
|
|
155
208
|
// #4573: matches the canonical ready phrase the discuss prompt asks the LLM
|
|
156
209
|
// to emit. Accepts any M-prefixed milestone ID (three digits + optional
|
|
157
210
|
// suffix) with optional trailing punctuation.
|
|
@@ -187,9 +240,9 @@ This stage is running inside the foreground \`/gsd new-project --deep\` intervie
|
|
|
187
240
|
/**
|
|
188
241
|
* Backward-compat bridge: returns a mutable reference to the entry matching
|
|
189
242
|
* basePath, or the sole entry when only one session exists.
|
|
190
|
-
*
|
|
243
|
+
* Exported for testing — internal use only in production code.
|
|
191
244
|
*/
|
|
192
|
-
function _getPendingAutoStart(basePath?: string): PendingAutoStartEntry | null {
|
|
245
|
+
export function _getPendingAutoStart(basePath?: string): PendingAutoStartEntry | null {
|
|
193
246
|
if (basePath) return pendingAutoStartMap.get(basePath) ?? null;
|
|
194
247
|
if (pendingAutoStartMap.size === 1) return pendingAutoStartMap.values().next().value!;
|
|
195
248
|
return null;
|
|
@@ -233,7 +286,9 @@ function clearEmptyLegacyDeepSetupPseudoMilestones(basePath: string, entries: st
|
|
|
233
286
|
* Exported for testing (#2985).
|
|
234
287
|
*/
|
|
235
288
|
export function setPendingAutoStart(basePath: string, entry: { basePath: string; milestoneId: string; ctx?: ExtensionCommandContext; pi?: ExtensionAPI; step?: boolean; createdAt?: number }): void {
|
|
236
|
-
|
|
289
|
+
const ws = createWorkspace(entry.basePath);
|
|
290
|
+
const scope = scopeMilestone(ws, entry.milestoneId);
|
|
291
|
+
pendingAutoStartMap.set(basePath, { createdAt: Date.now(), planBlockedRecoveryCount: 0, ...entry, scope } as PendingAutoStartEntry);
|
|
237
292
|
}
|
|
238
293
|
|
|
239
294
|
/**
|
|
@@ -343,6 +398,10 @@ export async function checkDeepProjectSetupAfterTurn(
|
|
|
343
398
|
if (!entry) return false;
|
|
344
399
|
|
|
345
400
|
if (entry.currentUnitType && entry.currentUnitId) {
|
|
401
|
+
// TODO(C-future): PendingDeepProjectSetupEntry does not carry a MilestoneScope
|
|
402
|
+
// because deep-project-setup units span non-milestone unit types (discuss-project,
|
|
403
|
+
// discuss-requirements, etc.). Migrate to verifyExpectedArtifactForScope once
|
|
404
|
+
// PendingDeepProjectSetupEntry is extended with a scope field.
|
|
346
405
|
const artifactReady = verifyExpectedArtifact(entry.currentUnitType, entry.currentUnitId, entry.basePath);
|
|
347
406
|
if (!artifactReady) {
|
|
348
407
|
return false;
|
|
@@ -426,17 +485,77 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|
|
426
485
|
|
|
427
486
|
// Gate 1: Primary milestone must have CONTEXT.md or ROADMAP.md
|
|
428
487
|
// The "discuss" path creates CONTEXT.md; the "plan" path creates ROADMAP.md.
|
|
429
|
-
|
|
430
|
-
const
|
|
488
|
+
// Use pinned scope (immune to cwd-drift) for existence checks.
|
|
489
|
+
const contextFilePath = entry.scope.contextFile();
|
|
490
|
+
const roadmapFilePath = entry.scope.roadmapFile();
|
|
491
|
+
const contextFile = existsSync(contextFilePath) ? contextFilePath : null;
|
|
492
|
+
const roadmapFile = existsSync(roadmapFilePath) ? roadmapFilePath : null;
|
|
431
493
|
if (!contextFile && !roadmapFile) return false; // neither artifact yet — keep waiting
|
|
432
494
|
|
|
495
|
+
// Gate 1b: Discriminate plan-blocked from discuss-incomplete when the DB row is queued.
|
|
496
|
+
// If the DB is available and the row is still "queued" but CONTEXT.md already exists on
|
|
497
|
+
// disk, the discuss phase completed but gsd_plan_milestone was hard-blocked by the
|
|
498
|
+
// depth-verification gate. Emit a recovery hint so the next agent turn can retry
|
|
499
|
+
// gsd_plan_milestone, then return false (keep blocking auto-start).
|
|
500
|
+
// If CONTEXT.md does not exist (discuss-incomplete), Gate 1 already blocked above.
|
|
501
|
+
if (isDbAvailable()) {
|
|
502
|
+
const dbRow = getMilestone(milestoneId);
|
|
503
|
+
if (dbRow?.status === "queued" && contextFile) {
|
|
504
|
+
if (entry.planBlockedRecoveryCount >= MAX_PLAN_BLOCKED_RECOVERIES) {
|
|
505
|
+
// H1: recovery loop cap reached — stop triggering new turns, escalate to user.
|
|
506
|
+
logWarning(
|
|
507
|
+
"guided",
|
|
508
|
+
`Gate 1b: milestone ${milestoneId} plan-blocked recovery limit reached ` +
|
|
509
|
+
`(${entry.planBlockedRecoveryCount}/${MAX_PLAN_BLOCKED_RECOVERIES}); escalating to user`,
|
|
510
|
+
);
|
|
511
|
+
ctx.ui.notify(
|
|
512
|
+
`Milestone ${milestoneId} plan_milestone has been blocked ${entry.planBlockedRecoveryCount} times. ` +
|
|
513
|
+
`Re-run /gsd to reset the recovery counter, or run /gsd-debug to diagnose without resetting.`,
|
|
514
|
+
"error",
|
|
515
|
+
);
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
logWarning(
|
|
519
|
+
"guided",
|
|
520
|
+
`Gate 1b: milestone ${milestoneId} queued with CONTEXT.md present — ` +
|
|
521
|
+
`plan_milestone was blocked; emitting recovery hint ` +
|
|
522
|
+
`(attempt ${entry.planBlockedRecoveryCount + 1}/${MAX_PLAN_BLOCKED_RECOVERIES})`,
|
|
523
|
+
);
|
|
524
|
+
ctx.ui.notify(
|
|
525
|
+
`Milestone ${milestoneId}: context file exists but milestone is still queued. ` +
|
|
526
|
+
`Retrying gsd_plan_milestone to complete the blocked planning step.`,
|
|
527
|
+
"warning",
|
|
528
|
+
);
|
|
529
|
+
try {
|
|
530
|
+
pi.sendMessage(
|
|
531
|
+
{
|
|
532
|
+
customType: "gsd-plan-milestone-blocked-recovery",
|
|
533
|
+
content:
|
|
534
|
+
`Milestone ${milestoneId} has ${contextFile} on disk but its DB row is still ` +
|
|
535
|
+
`"queued". The gsd_plan_milestone tool was previously blocked by the ` +
|
|
536
|
+
`depth-verification gate. Call gsd_plan_milestone now to complete the ` +
|
|
537
|
+
`planning phase.`,
|
|
538
|
+
display: false,
|
|
539
|
+
},
|
|
540
|
+
{ triggerTurn: true },
|
|
541
|
+
);
|
|
542
|
+
// Increment only after a successful dispatch so transient sendMessage
|
|
543
|
+
// failures do not consume recovery budget.
|
|
544
|
+
entry.planBlockedRecoveryCount += 1;
|
|
545
|
+
} catch (e) {
|
|
546
|
+
logWarning("guided", `Gate 1b recovery sendMessage failed: ${(e as Error).message}`);
|
|
547
|
+
}
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
433
552
|
// Gate 2: STATE.md must exist — written as the last step in the discuss
|
|
434
553
|
// output phase. This prevents auto-start from firing during Phase 3
|
|
435
554
|
// (sequential readiness gates for remaining milestones) in multi-milestone
|
|
436
555
|
// discussions, where M001-CONTEXT.md exists but M002/M003 haven't been
|
|
437
556
|
// processed yet.
|
|
438
|
-
const
|
|
439
|
-
if (!
|
|
557
|
+
const stateFilePath = entry.scope.stateFile();
|
|
558
|
+
if (!existsSync(stateFilePath)) return false; // discussion not finalized yet
|
|
440
559
|
|
|
441
560
|
// Gate 3: Multi-milestone completeness warning
|
|
442
561
|
// Parse PROJECT.md for milestone sequence, warn if any are missing context.
|
|
@@ -469,7 +588,7 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|
|
469
588
|
// The LLM writes DISCUSSION-MANIFEST.json after each Phase 3 gate decision.
|
|
470
589
|
// When it exists, validate it before auto-starting. Project history alone is
|
|
471
590
|
// not a reliable signal for the current discussion mode.
|
|
472
|
-
const manifestPath = join(
|
|
591
|
+
const manifestPath = join(entry.scope.workspace.contract.projectGsd, "DISCUSSION-MANIFEST.json");
|
|
473
592
|
if (existsSync(manifestPath)) {
|
|
474
593
|
try {
|
|
475
594
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
@@ -588,12 +707,39 @@ export function maybeHandleReadyPhraseWithoutFiles(event: { messages: any[] }):
|
|
|
588
707
|
const text = extractAssistantText(lastMsg);
|
|
589
708
|
if (!READY_PHRASE_RE.test(text)) return false;
|
|
590
709
|
|
|
710
|
+
// Bust paths.ts cached dir listings before checking for fresh writes. The
|
|
711
|
+
// LLM's Write tool calls do not invalidate paths.ts caches, so a stale
|
|
712
|
+
// listing taken before the milestone dir or its CONTEXT/ROADMAP files
|
|
713
|
+
// existed would falsely report the artifacts as missing and trigger the
|
|
714
|
+
// 3-strike "ready without files" abort even though the writes succeeded.
|
|
715
|
+
clearPathCache();
|
|
716
|
+
|
|
591
717
|
// Gate: artifacts must still be missing — if they exist, the happy path
|
|
592
718
|
// already fired and we have nothing to do.
|
|
593
719
|
const contextFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT");
|
|
594
720
|
const roadmapFile = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
595
721
|
if (contextFile || roadmapFile) return false;
|
|
596
722
|
|
|
723
|
+
// Diagnostic: when the cached resolver reports both files missing, also probe
|
|
724
|
+
// the canonical paths with uncached existsSync so we can tell whether the
|
|
725
|
+
// recovery is firing on real-missing files or a path-resolution miss
|
|
726
|
+
// (basePath/symlink mismatch, stale cache despite agent-end-recovery flush,
|
|
727
|
+
// legacy descriptor dir not matching, etc.).
|
|
728
|
+
try {
|
|
729
|
+
const mDir = resolveMilestonePath(basePath, milestoneId);
|
|
730
|
+
const canonicalCtx = mDir ? join(mDir, `${milestoneId}-CONTEXT.md`) : null;
|
|
731
|
+
const canonicalRoadmap = mDir ? join(mDir, `${milestoneId}-ROADMAP.md`) : null;
|
|
732
|
+
logWarning(
|
|
733
|
+
"guided",
|
|
734
|
+
`ready-phrase-reject diagnostic mid=${milestoneId} basePath=${basePath} ` +
|
|
735
|
+
`mDir=${mDir ?? "null"} ` +
|
|
736
|
+
`canonical-ctx=${canonicalCtx ?? "null"} ctx-exists=${canonicalCtx ? existsSync(canonicalCtx) : "n/a"} ` +
|
|
737
|
+
`canonical-roadmap=${canonicalRoadmap ?? "null"} roadmap-exists=${canonicalRoadmap ? existsSync(canonicalRoadmap) : "n/a"}`,
|
|
738
|
+
);
|
|
739
|
+
} catch (e) {
|
|
740
|
+
logWarning("guided", `ready-phrase-reject diagnostic failed: ${(e as Error).message}`);
|
|
741
|
+
}
|
|
742
|
+
|
|
597
743
|
entry.readyRejectCount = (entry.readyRejectCount ?? 0) + 1;
|
|
598
744
|
|
|
599
745
|
if (entry.readyRejectCount > MAX_READY_REJECTS) {
|
|
@@ -696,14 +842,14 @@ export function maybeHandleEmptyIntentTurn(
|
|
|
696
842
|
// path, handled by maybeHandleReadyPhraseWithoutFiles.
|
|
697
843
|
if (READY_PHRASE_RE.test(text)) return false;
|
|
698
844
|
|
|
699
|
-
// Skip if the LLM is clearly handing back to the user.
|
|
700
|
-
//
|
|
701
|
-
//
|
|
702
|
-
//
|
|
703
|
-
//
|
|
845
|
+
// Skip if the LLM is clearly handing back to the user. Discuss flows
|
|
846
|
+
// often pose a question and follow it with a conditional intent on the
|
|
847
|
+
// same line ("Did I capture that correctly? If so, I'll write the
|
|
848
|
+
// requirements."). A line-trailing `?` check misses these because the
|
|
849
|
+
// line ends in `.`. Match any sentence-terminating `?` (followed by
|
|
850
|
+
// whitespace or end-of-text) — false negatives here auto-reply to the
|
|
704
851
|
// user, which is a much worse failure mode than a missed nudge.
|
|
705
|
-
|
|
706
|
-
if (lines.some((l) => l.endsWith("?"))) return false;
|
|
852
|
+
if (/\?(?:\s|$)/.test(text)) return false;
|
|
707
853
|
|
|
708
854
|
// Must contain a commit-intent phrase — this is the stall we care about.
|
|
709
855
|
if (!COMMIT_INTENT_RE.test(text)) return false;
|
|
@@ -1077,7 +1223,7 @@ export async function showHeadlessMilestoneCreation(
|
|
|
1077
1223
|
const prompt = buildHeadlessDiscussPrompt(nextId, seedContext, basePath);
|
|
1078
1224
|
|
|
1079
1225
|
// Set pending auto start (auto-mode triggers on "Milestone X ready." via checkAutoStartAfterDiscuss)
|
|
1080
|
-
|
|
1226
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId });
|
|
1081
1227
|
|
|
1082
1228
|
// Dispatch as discuss-milestone. The LLM writes PROJECT.md, REQUIREMENTS.md,
|
|
1083
1229
|
// and CONTEXT.md, then calls gsd_plan_milestone — this is semantically the
|
|
@@ -1274,12 +1420,12 @@ export async function showDiscuss(
|
|
|
1274
1420
|
const seed = draftContent
|
|
1275
1421
|
? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
|
|
1276
1422
|
: basePrompt;
|
|
1277
|
-
|
|
1423
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: mid, step: false });
|
|
1278
1424
|
await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "discuss-milestone");
|
|
1279
1425
|
} else if (choice === "discuss_fresh") {
|
|
1280
1426
|
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1281
1427
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1282
|
-
|
|
1428
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: mid, step: false });
|
|
1283
1429
|
await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
|
|
1284
1430
|
milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
1285
1431
|
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
@@ -1291,7 +1437,7 @@ export async function showDiscuss(
|
|
|
1291
1437
|
const milestoneIds = findMilestoneIds(basePath);
|
|
1292
1438
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
1293
1439
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
1294
|
-
|
|
1440
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: false });
|
|
1295
1441
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
|
|
1296
1442
|
}
|
|
1297
1443
|
return;
|
|
@@ -1582,6 +1728,9 @@ function selfHealRuntimeRecords(basePath: string, ctx: ExtensionContext): { clea
|
|
|
1582
1728
|
for (const record of records) {
|
|
1583
1729
|
const { unitType, unitId, phase } = record;
|
|
1584
1730
|
// Clear records whose expected artifact already exists (completed but not cleaned up)
|
|
1731
|
+
// TODO(C-future): selfHealRuntimeRecords iterates across all unit types (not just milestone
|
|
1732
|
+
// units), so it cannot be converted to resolveExpectedArtifactPathForScope without
|
|
1733
|
+
// first establishing a per-record scope. Migrate once unit runtime records carry scope info.
|
|
1585
1734
|
const artifactPath = resolveExpectedArtifactPath(unitType, unitId, basePath);
|
|
1586
1735
|
if (artifactPath && existsSync(artifactPath)) {
|
|
1587
1736
|
clearUnitRuntimeRecord(basePath, unitType, unitId);
|
|
@@ -1696,7 +1845,7 @@ async function handleMilestoneActions(
|
|
|
1696
1845
|
const milestoneIds = findMilestoneIds(basePath);
|
|
1697
1846
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
1698
1847
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
1699
|
-
|
|
1848
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1700
1849
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
|
|
1701
1850
|
`New milestone ${nextId}.`,
|
|
1702
1851
|
basePath
|
|
@@ -1924,7 +2073,7 @@ export async function showSmartEntry(
|
|
|
1924
2073
|
|
|
1925
2074
|
if (isFirst) {
|
|
1926
2075
|
// First ever — skip wizard, just ask directly
|
|
1927
|
-
|
|
2076
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1928
2077
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
|
|
1929
2078
|
`New project, milestone ${nextId}. Do NOT read or explore .gsd/ — it's empty scaffolding.`,
|
|
1930
2079
|
basePath
|
|
@@ -1945,7 +2094,7 @@ export async function showSmartEntry(
|
|
|
1945
2094
|
});
|
|
1946
2095
|
|
|
1947
2096
|
if (choice === "new_milestone") {
|
|
1948
|
-
|
|
2097
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1949
2098
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
|
|
1950
2099
|
`New milestone ${nextId}.`,
|
|
1951
2100
|
basePath
|
|
@@ -1959,7 +2108,7 @@ export async function showSmartEntry(
|
|
|
1959
2108
|
const milestoneTitle = state.activeMilestone.title;
|
|
1960
2109
|
|
|
1961
2110
|
if (planV2GateDecision === "recover-missing-context") {
|
|
1962
|
-
|
|
2111
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
1963
2112
|
await dispatchWorkflow(
|
|
1964
2113
|
pi,
|
|
1965
2114
|
await buildDiscussMilestonePrompt(
|
|
@@ -2001,7 +2150,7 @@ export async function showSmartEntry(
|
|
|
2001
2150
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
2002
2151
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
2003
2152
|
|
|
2004
|
-
|
|
2153
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
2005
2154
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
|
|
2006
2155
|
`New milestone ${nextId}.`,
|
|
2007
2156
|
basePath
|
|
@@ -2053,12 +2202,12 @@ export async function showSmartEntry(
|
|
|
2053
2202
|
const seed = draftContent
|
|
2054
2203
|
? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
|
|
2055
2204
|
: basePrompt;
|
|
2056
|
-
|
|
2205
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
2057
2206
|
await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "discuss-milestone");
|
|
2058
2207
|
} else if (choice === "discuss_fresh") {
|
|
2059
2208
|
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2060
2209
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2061
|
-
|
|
2210
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
2062
2211
|
await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
|
|
2063
2212
|
milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
2064
2213
|
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
@@ -2068,7 +2217,7 @@ export async function showSmartEntry(
|
|
|
2068
2217
|
const milestoneIds = findMilestoneIds(basePath);
|
|
2069
2218
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
2070
2219
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
2071
|
-
|
|
2220
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
2072
2221
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
|
|
2073
2222
|
`New milestone ${nextId}.`,
|
|
2074
2223
|
basePath
|
|
@@ -2133,7 +2282,7 @@ export async function showSmartEntry(
|
|
|
2133
2282
|
});
|
|
2134
2283
|
|
|
2135
2284
|
if (choice === "plan") {
|
|
2136
|
-
|
|
2285
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
2137
2286
|
await dispatchWorkflow(
|
|
2138
2287
|
pi,
|
|
2139
2288
|
await buildPlanMilestonePrompt(milestoneId, milestoneTitle, basePath),
|
|
@@ -2153,7 +2302,7 @@ export async function showSmartEntry(
|
|
|
2153
2302
|
const milestoneIds = findMilestoneIds(basePath);
|
|
2154
2303
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
2155
2304
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
2156
|
-
|
|
2305
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
2157
2306
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
|
|
2158
2307
|
`New milestone ${nextId}.`,
|
|
2159
2308
|
basePath
|
|
@@ -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.
|
|
@@ -85,58 +84,19 @@ function taskSummaryForSlicePlan(description: string): string {
|
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
/**
|
|
88
|
-
* Load artifact content from DB
|
|
89
|
-
*
|
|
90
|
-
*
|
|
87
|
+
* Load artifact content from the DB. Markdown projections are not authoritative
|
|
88
|
+
* during runtime; when the artifact row is missing, callers regenerate from DB
|
|
89
|
+
* rows instead of patching disk fallback content and storing it back.
|
|
91
90
|
*/
|
|
92
91
|
function loadArtifactContent(
|
|
93
92
|
artifactPath: string,
|
|
94
|
-
absPath: string | null,
|
|
95
|
-
opts: {
|
|
96
|
-
artifact_type: string;
|
|
97
|
-
milestone_id: string;
|
|
98
|
-
slice_id?: string;
|
|
99
|
-
task_id?: string;
|
|
100
|
-
},
|
|
101
93
|
): string | null {
|
|
102
|
-
// Try DB first
|
|
103
94
|
const artifact = getArtifact(artifactPath);
|
|
104
95
|
if (artifact && artifact.full_content) {
|
|
105
96
|
return artifact.full_content;
|
|
106
97
|
}
|
|
107
98
|
|
|
108
|
-
|
|
109
|
-
if (!absPath) {
|
|
110
|
-
process.stderr.write(
|
|
111
|
-
`markdown-renderer: artifact not found in DB or on disk: ${artifactPath}\n`,
|
|
112
|
-
);
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
let content: string;
|
|
117
|
-
try {
|
|
118
|
-
content = readFileSync(absPath, "utf-8");
|
|
119
|
-
} catch {
|
|
120
|
-
logWarning("renderer", `cannot read file from disk: ${absPath}`);
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Store in DB for future use (graceful degradation path)
|
|
125
|
-
try {
|
|
126
|
-
insertArtifact({
|
|
127
|
-
path: artifactPath,
|
|
128
|
-
artifact_type: opts.artifact_type,
|
|
129
|
-
milestone_id: opts.milestone_id,
|
|
130
|
-
slice_id: opts.slice_id ?? null,
|
|
131
|
-
task_id: opts.task_id ?? null,
|
|
132
|
-
full_content: content,
|
|
133
|
-
});
|
|
134
|
-
} catch {
|
|
135
|
-
// Non-fatal: we have the content, DB storage is best-effort
|
|
136
|
-
logWarning("renderer", `failed to store disk fallback in DB: ${artifactPath}`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return content;
|
|
99
|
+
return null;
|
|
140
100
|
}
|
|
141
101
|
|
|
142
102
|
/**
|
|
@@ -507,20 +467,15 @@ export async function renderRoadmapCheckboxes(
|
|
|
507
467
|
const absPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
508
468
|
const artifactPath = absPath ? toArtifactPath(absPath, basePath) : null;
|
|
509
469
|
|
|
510
|
-
// Load content from DB
|
|
470
|
+
// Load content from DB; regenerate from DB rows when the artifact is absent.
|
|
511
471
|
let content: string | null = null;
|
|
512
472
|
if (artifactPath) {
|
|
513
|
-
content = loadArtifactContent(artifactPath
|
|
514
|
-
artifact_type: "ROADMAP",
|
|
515
|
-
milestone_id: milestoneId,
|
|
516
|
-
});
|
|
473
|
+
content = loadArtifactContent(artifactPath);
|
|
517
474
|
}
|
|
518
475
|
|
|
519
476
|
if (!content) {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
);
|
|
523
|
-
return false;
|
|
477
|
+
await renderRoadmapFromDb(basePath, milestoneId);
|
|
478
|
+
return true;
|
|
524
479
|
}
|
|
525
480
|
|
|
526
481
|
// Apply checkbox patches for each slice
|
|
@@ -582,18 +537,12 @@ export async function renderPlanCheckboxes(
|
|
|
582
537
|
|
|
583
538
|
let content: string | null = null;
|
|
584
539
|
if (artifactPath) {
|
|
585
|
-
content = loadArtifactContent(artifactPath
|
|
586
|
-
artifact_type: "PLAN",
|
|
587
|
-
milestone_id: milestoneId,
|
|
588
|
-
slice_id: sliceId,
|
|
589
|
-
});
|
|
540
|
+
content = loadArtifactContent(artifactPath);
|
|
590
541
|
}
|
|
591
542
|
|
|
592
543
|
if (!content) {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
);
|
|
596
|
-
return false;
|
|
544
|
+
await renderPlanFromDb(basePath, milestoneId, sliceId);
|
|
545
|
+
return true;
|
|
597
546
|
}
|
|
598
547
|
|
|
599
548
|
// Apply checkbox patches for each task
|