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
|
@@ -4,11 +4,16 @@ import { readFileSync } from "node:fs";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
const promptsDir = join(process.cwd(), "src/resources/extensions/gsd/prompts");
|
|
7
|
+
const templatesDir = join(process.cwd(), "src/resources/extensions/gsd/templates");
|
|
7
8
|
|
|
8
9
|
function readPrompt(name: string): string {
|
|
9
10
|
return readFileSync(join(promptsDir, `${name}.md`), "utf-8");
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
function readTemplate(name: string): string {
|
|
14
|
+
return readFileSync(join(templatesDir, `${name}.md`), "utf-8");
|
|
15
|
+
}
|
|
16
|
+
|
|
12
17
|
test("reactive-execute prompt keeps task summaries with subagents and avoids batch commits", () => {
|
|
13
18
|
const prompt = readPrompt("reactive-execute");
|
|
14
19
|
assert.match(prompt, /subagent-written summary as authoritative/i);
|
|
@@ -174,15 +179,15 @@ test("guided-resume-task prompt preserves recovery state until work is supersede
|
|
|
174
179
|
|
|
175
180
|
// ─── Prompt migration: execute-task → gsd_complete_task ───────────────
|
|
176
181
|
|
|
177
|
-
test("execute-task prompt references
|
|
182
|
+
test("execute-task prompt references gsd_task_complete tool", () => {
|
|
178
183
|
const prompt = readPrompt("execute-task");
|
|
179
|
-
assert.match(prompt, /
|
|
184
|
+
assert.match(prompt, /gsd_task_complete/);
|
|
180
185
|
});
|
|
181
186
|
|
|
182
|
-
test("execute-task prompt uses
|
|
187
|
+
test("execute-task prompt uses gsd_task_complete as canonical summary write path", () => {
|
|
183
188
|
const prompt = readPrompt("execute-task");
|
|
184
189
|
assert.match(prompt, /\{\{taskSummaryPath\}\}/);
|
|
185
|
-
assert.match(prompt, /
|
|
190
|
+
assert.match(prompt, /gsd_task_complete/);
|
|
186
191
|
assert.match(prompt, /DB-backed tool is the canonical write path/i);
|
|
187
192
|
assert.match(prompt, /Do \*\*not\*\* manually write `?\{\{taskSummaryPath\}\}`?/i);
|
|
188
193
|
assert.doesNotMatch(prompt, /^\d+\.\s+Write `?\{\{taskSummaryPath\}\}`?\s*$/m);
|
|
@@ -202,9 +207,9 @@ test("execute-task prompt still contains template variables for context", () =>
|
|
|
202
207
|
|
|
203
208
|
// ─── Prompt migration: complete-slice → gsd_complete_slice ────────────
|
|
204
209
|
|
|
205
|
-
test("complete-slice prompt references
|
|
210
|
+
test("complete-slice prompt references gsd_slice_complete tool", () => {
|
|
206
211
|
const prompt = readPrompt("complete-slice");
|
|
207
|
-
assert.match(prompt, /
|
|
212
|
+
assert.match(prompt, /gsd_slice_complete/);
|
|
208
213
|
});
|
|
209
214
|
|
|
210
215
|
test("complete-slice prompt does not instruct LLM to toggle checkboxes manually", () => {
|
|
@@ -216,7 +221,7 @@ test("complete-slice prompt instructs writing summary and UAT files before tool
|
|
|
216
221
|
const prompt = readPrompt("complete-slice");
|
|
217
222
|
assert.match(prompt, /\{\{sliceSummaryPath\}\}/);
|
|
218
223
|
assert.match(prompt, /\{\{sliceUatPath\}\}/);
|
|
219
|
-
assert.match(prompt, /
|
|
224
|
+
assert.match(prompt, /gsd_slice_complete/);
|
|
220
225
|
assert.match(prompt, /DB-backed tool is the canonical write path/i);
|
|
221
226
|
assert.match(prompt, /Do \*\*not\*\* manually write `?\{\{sliceSummaryPath\}\}`?/i);
|
|
222
227
|
assert.match(prompt, /Do \*\*not\*\* manually write `?\{\{sliceUatPath\}\}`?/i);
|
|
@@ -398,3 +403,141 @@ test("reactive-execute prompt references tool calls instead of checkbox updates"
|
|
|
398
403
|
assert.doesNotMatch(prompt, /checkbox edits/);
|
|
399
404
|
assert.match(prompt, /completion tool calls/);
|
|
400
405
|
});
|
|
406
|
+
|
|
407
|
+
// ─── Project-shape classifier + 3-or-4-options-with-Other-hatch contract ──
|
|
408
|
+
|
|
409
|
+
test("guided-discuss-project classifies project shape and persists the verdict to PROJECT.md", () => {
|
|
410
|
+
const prompt = readPrompt("guided-discuss-project");
|
|
411
|
+
assert.match(prompt, /Classify project shape/i, "must include the classifier section");
|
|
412
|
+
assert.match(prompt, /`simple`/);
|
|
413
|
+
assert.match(prompt, /`complex`/);
|
|
414
|
+
assert.match(prompt, /Default to `complex` when uncertain/i);
|
|
415
|
+
assert.match(prompt, /## Project Shape/, "must reference the persisted PROJECT.md section");
|
|
416
|
+
assert.match(prompt, /\*\*Complexity:\*\*\s*simple/);
|
|
417
|
+
assert.match(prompt, /\*\*Complexity:\*\*\s*complex/);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
test("guided-discuss prompts require 3-or-4 options plus Other-let-me-discuss in complex mode", () => {
|
|
421
|
+
for (const name of [
|
|
422
|
+
"guided-discuss-project",
|
|
423
|
+
"guided-discuss-milestone",
|
|
424
|
+
"guided-discuss-slice",
|
|
425
|
+
]) {
|
|
426
|
+
const prompt = readPrompt(name);
|
|
427
|
+
assert.match(
|
|
428
|
+
prompt,
|
|
429
|
+
/3 or 4 concrete, researched options/i,
|
|
430
|
+
`${name} must require 3 or 4 grounded options in complex mode`,
|
|
431
|
+
);
|
|
432
|
+
assert.match(
|
|
433
|
+
prompt,
|
|
434
|
+
/"Other — let me discuss"/,
|
|
435
|
+
`${name} must include the "Other — let me discuss" escape hatch`,
|
|
436
|
+
);
|
|
437
|
+
assert.match(
|
|
438
|
+
prompt,
|
|
439
|
+
/grounded in (the |your |)investigation/i,
|
|
440
|
+
`${name} must require options grounded in prior investigation`,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test("guided-discuss-requirements scopes the 3-or-4-options rule to free-form questions only", () => {
|
|
446
|
+
const prompt = readPrompt("guided-discuss-requirements");
|
|
447
|
+
assert.match(prompt, /3 or 4 concrete, researched options/i);
|
|
448
|
+
assert.match(prompt, /"Other — let me discuss"/);
|
|
449
|
+
// Class-assignment and status questions have fixed enumerations, so the rule must exempt them.
|
|
450
|
+
assert.match(prompt, /class-assignment.*status.*exempt/i);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
test("downstream discuss prompts read project shape verdict from PROJECT.md", () => {
|
|
454
|
+
for (const name of [
|
|
455
|
+
"guided-discuss-milestone",
|
|
456
|
+
"guided-discuss-requirements",
|
|
457
|
+
"guided-discuss-slice",
|
|
458
|
+
]) {
|
|
459
|
+
const prompt = readPrompt(name);
|
|
460
|
+
assert.match(
|
|
461
|
+
prompt,
|
|
462
|
+
/Project Shape/,
|
|
463
|
+
`${name} must reference Project Shape from PROJECT.md`,
|
|
464
|
+
);
|
|
465
|
+
assert.match(
|
|
466
|
+
prompt,
|
|
467
|
+
/default to `complex`/i,
|
|
468
|
+
`${name} must default to complex when the verdict is missing`,
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
test("project template includes the Project Shape section so the verdict has a home", () => {
|
|
474
|
+
const template = readTemplate("project");
|
|
475
|
+
assert.match(template, /## Project Shape/);
|
|
476
|
+
assert.match(template, /\*\*Complexity:\*\*/);
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
// ─── Project shape verdict — end-to-end propagation contract (F7 / #5267) ──
|
|
480
|
+
// The verdict is propagated from discuss-project to downstream stages via
|
|
481
|
+
// PROJECT.md text only, with no parser. These tests pin the round-trip:
|
|
482
|
+
// the format the upstream stage is told to write must be discoverable by
|
|
483
|
+
// the regex pattern the downstream stage is told to look for.
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Render the project.md template with a concrete complexity verdict so we
|
|
487
|
+
* can assert on a realistic PROJECT.md (the placeholder is filled the way
|
|
488
|
+
* an LLM following the prompt would fill it).
|
|
489
|
+
*/
|
|
490
|
+
function renderProjectMd(verdict: "simple" | "complex"): string {
|
|
491
|
+
return readTemplate("project")
|
|
492
|
+
.replace("{{simple | complex}}", verdict)
|
|
493
|
+
.replace("{{one-line rationale citing the signals that decided it}}", "Test fixture rationale.");
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
test("project shape verdict survives the discuss-project → discuss-milestone round trip", () => {
|
|
497
|
+
for (const verdict of ["simple", "complex"] as const) {
|
|
498
|
+
const projectMd = renderProjectMd(verdict);
|
|
499
|
+
|
|
500
|
+
// Upstream contract: the PROJECT.md the discuss-project prompt writes
|
|
501
|
+
// must contain the section header and the bolded `**Complexity:** <verdict>`
|
|
502
|
+
// marker that downstream stages are told to grep for.
|
|
503
|
+
assert.match(projectMd, /## Project Shape/, `rendered ${verdict} PROJECT.md must keep the section header`);
|
|
504
|
+
const complexityMarker = new RegExp(`\\*\\*Complexity:\\*\\*\\s*${verdict}\\b`);
|
|
505
|
+
assert.match(
|
|
506
|
+
projectMd,
|
|
507
|
+
complexityMarker,
|
|
508
|
+
`rendered ${verdict} PROJECT.md must expose the bolded Complexity marker the downstream regex looks for`,
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
// Downstream contract: discuss-milestone, discuss-requirements, and
|
|
512
|
+
// discuss-slice must each instruct the LLM to look at the same section
|
|
513
|
+
// header AND the same `**Complexity:**` marker the template writes.
|
|
514
|
+
// Without this, the upstream verdict is silently dropped.
|
|
515
|
+
for (const downstream of ["guided-discuss-milestone", "guided-discuss-requirements", "guided-discuss-slice"]) {
|
|
516
|
+
const prompt = readPrompt(downstream);
|
|
517
|
+
assert.match(
|
|
518
|
+
prompt,
|
|
519
|
+
/## Project Shape/,
|
|
520
|
+
`${downstream} must direct the LLM to the same section header the template writes`,
|
|
521
|
+
);
|
|
522
|
+
assert.match(
|
|
523
|
+
prompt,
|
|
524
|
+
/\*\*Complexity:\*\*/,
|
|
525
|
+
`${downstream} must direct the LLM to the same **Complexity:** marker the template writes`,
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
test("downstream discuss prompts default to complex when PROJECT.md lacks the verdict", () => {
|
|
532
|
+
// Safe-by-default: if upstream omits the section (existing projects, LLM
|
|
533
|
+
// drift, future template change), each downstream stage must explicitly
|
|
534
|
+
// fall back to complex so behavior is conservative rather than stuck.
|
|
535
|
+
for (const downstream of ["guided-discuss-milestone", "guided-discuss-requirements", "guided-discuss-slice"]) {
|
|
536
|
+
const prompt = readPrompt(downstream);
|
|
537
|
+
assert.match(
|
|
538
|
+
prompt,
|
|
539
|
+
/default to `complex`/i,
|
|
540
|
+
`${downstream} must default to complex when the upstream verdict is missing`,
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
});
|
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
maybeHandleEmptyIntentTurn,
|
|
22
22
|
resetEmptyTurnCounter,
|
|
23
23
|
} from "../guided-flow.ts";
|
|
24
|
+
import { drainLogs } from "../workflow-logger.ts";
|
|
25
|
+
import { resolveMilestoneFile, clearPathCache } from "../paths.ts";
|
|
24
26
|
|
|
25
27
|
// ─── Test harness ──────────────────────────────────────────────────────────
|
|
26
28
|
|
|
@@ -177,6 +179,79 @@ describe("#4573 maybeHandleReadyPhraseWithoutFiles", () => {
|
|
|
177
179
|
}
|
|
178
180
|
});
|
|
179
181
|
|
|
182
|
+
test("stale path cache from a prior listing → fresh writes are detected (regression)", () => {
|
|
183
|
+
// Repro the live binary failure where:
|
|
184
|
+
// 1. paths.ts cached dir listings were populated when M001/ was empty
|
|
185
|
+
// (or the milestone dir didn't yet exist).
|
|
186
|
+
// 2. The LLM then wrote M001-CONTEXT.md and M001-ROADMAP.md via the
|
|
187
|
+
// standard Write tool — which has no awareness of paths.ts caches.
|
|
188
|
+
// 3. maybeHandleReadyPhraseWithoutFiles called resolveMilestoneFile,
|
|
189
|
+
// which read the stale cache and reported the artifacts missing,
|
|
190
|
+
// firing a false rejection nudge until MAX_READY_REJECTS aborted
|
|
191
|
+
// the auto-start with `LLM signaled "ready" 3 times without
|
|
192
|
+
// writing files`.
|
|
193
|
+
//
|
|
194
|
+
// The fix busts the path cache at the top of the validator before
|
|
195
|
+
// re-resolving. This test fails pre-fix (handled === true) because the
|
|
196
|
+
// cache returns the empty listing it captured in step (a).
|
|
197
|
+
const base = mkBase();
|
|
198
|
+
try {
|
|
199
|
+
const mDir = join(base, ".gsd", "milestones", "M001");
|
|
200
|
+
|
|
201
|
+
// (a) Prime the cache with a listing that DOES NOT include M001's
|
|
202
|
+
// CONTEXT/ROADMAP files. mkBase() has already created the M001
|
|
203
|
+
// directory but nothing inside it yet — so this readdir caches an
|
|
204
|
+
// empty entry list keyed by the M001 dir path.
|
|
205
|
+
clearPathCache();
|
|
206
|
+
assert.equal(
|
|
207
|
+
resolveMilestoneFile(base, "M001", "CONTEXT"),
|
|
208
|
+
null,
|
|
209
|
+
"precondition: resolver must report missing before files are written",
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// (b) Write the artifacts directly to disk (simulates the LLM Write
|
|
213
|
+
// tool — no clearPathCache() call between the write and the
|
|
214
|
+
// validator).
|
|
215
|
+
writeFileSync(join(mDir, "M001-CONTEXT.md"), "# ctx");
|
|
216
|
+
writeFileSync(join(mDir, "M001-ROADMAP.md"), "# roadmap");
|
|
217
|
+
|
|
218
|
+
// (c) Sanity: the cache is still stale. Without the fix, the
|
|
219
|
+
// validator would still see the empty cached listing.
|
|
220
|
+
assert.equal(
|
|
221
|
+
resolveMilestoneFile(base, "M001", "CONTEXT"),
|
|
222
|
+
null,
|
|
223
|
+
"stale cache still reports missing pre-clearPathCache",
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
// (d) Run the validator. With the fix it busts the cache before
|
|
227
|
+
// resolving and returns false (no nudge). Without the fix it
|
|
228
|
+
// fires the nudge.
|
|
229
|
+
const cap = mkCapture();
|
|
230
|
+
setPendingAutoStart(base, {
|
|
231
|
+
basePath: base,
|
|
232
|
+
milestoneId: "M001",
|
|
233
|
+
ctx: mkCtx(cap),
|
|
234
|
+
pi: mkPi(cap),
|
|
235
|
+
});
|
|
236
|
+
const handled = maybeHandleReadyPhraseWithoutFiles({
|
|
237
|
+
messages: [assistantMsg("Milestone M001 ready.")],
|
|
238
|
+
});
|
|
239
|
+
assert.equal(
|
|
240
|
+
handled,
|
|
241
|
+
false,
|
|
242
|
+
"fresh writes must not trigger the rejection nudge — cache must be busted before resolution",
|
|
243
|
+
);
|
|
244
|
+
assert.equal(cap.messages.length, 0, "no nudge sent");
|
|
245
|
+
assert.equal(
|
|
246
|
+
cap.notifies.length,
|
|
247
|
+
0,
|
|
248
|
+
"no rejection notify when files exist on disk",
|
|
249
|
+
);
|
|
250
|
+
} finally {
|
|
251
|
+
clearPendingAutoStart();
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
180
255
|
test("legacy unprefixed files present → no nudge", () => {
|
|
181
256
|
const base = mkBase();
|
|
182
257
|
try {
|
|
@@ -219,6 +294,81 @@ describe("#4573 maybeHandleReadyPhraseWithoutFiles", () => {
|
|
|
219
294
|
}
|
|
220
295
|
});
|
|
221
296
|
|
|
297
|
+
test("nudge fires → diagnostic warning logged with basePath, mDir, canonical-path existsSync results", () => {
|
|
298
|
+
// Diagnostic logging added so we can tell, in real failures, whether
|
|
299
|
+
// resolveMilestoneFile is reporting files missing that actually exist on
|
|
300
|
+
// disk (basePath/symlink mismatch, stale cache despite the
|
|
301
|
+
// agent-end-recovery flush, legacy descriptor dir, etc.).
|
|
302
|
+
const base = mkBase();
|
|
303
|
+
try {
|
|
304
|
+
drainLogs(); // discard prior test noise
|
|
305
|
+
const cap = mkCapture();
|
|
306
|
+
setPendingAutoStart(base, {
|
|
307
|
+
basePath: base,
|
|
308
|
+
milestoneId: "M001",
|
|
309
|
+
ctx: mkCtx(cap),
|
|
310
|
+
pi: mkPi(cap),
|
|
311
|
+
});
|
|
312
|
+
const handled = maybeHandleReadyPhraseWithoutFiles({
|
|
313
|
+
messages: [assistantMsg("Milestone M001 ready.")],
|
|
314
|
+
});
|
|
315
|
+
assert.equal(handled, true);
|
|
316
|
+
|
|
317
|
+
const logs = drainLogs();
|
|
318
|
+
const diag = logs.find(
|
|
319
|
+
(e) => e.component === "guided" && /ready-phrase-reject diagnostic/.test(e.message),
|
|
320
|
+
);
|
|
321
|
+
assert.ok(diag, "expected diagnostic warning to be logged when nudge fires");
|
|
322
|
+
assert.match(diag!.message, /mid=M001/);
|
|
323
|
+
assert.match(diag!.message, new RegExp(`basePath=${base.replace(/[/\\]/g, "[/\\\\]")}`));
|
|
324
|
+
assert.match(diag!.message, /mDir=/);
|
|
325
|
+
assert.match(diag!.message, /ctx-exists=false/);
|
|
326
|
+
assert.match(diag!.message, /roadmap-exists=false/);
|
|
327
|
+
} finally {
|
|
328
|
+
clearPendingAutoStart();
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test("diagnostic logs ctx-exists=true when file is on disk but cached resolver missed it", () => {
|
|
333
|
+
// Simulates the test123 #5xxx scenario: file exists on disk, cached
|
|
334
|
+
// resolver claims it doesn't. We drop a file with a non-canonical path
|
|
335
|
+
// (forces the legacy-descriptor pattern miss) so resolveMilestoneFile
|
|
336
|
+
// returns null but existsSync on the canonical path returns true.
|
|
337
|
+
//
|
|
338
|
+
// Note: the canonical path probe in the diagnostic uses the literal
|
|
339
|
+
// `${milestoneId}-CONTEXT.md` filename. If a file is at that path,
|
|
340
|
+
// existsSync will see it regardless of resolver behavior.
|
|
341
|
+
const base = mkBase();
|
|
342
|
+
try {
|
|
343
|
+
drainLogs();
|
|
344
|
+
// Write the canonical file directly — both resolver AND existsSync
|
|
345
|
+
// would normally see it. To prove the diagnostic captures the
|
|
346
|
+
// existsSync result independently, we cover the basic case here.
|
|
347
|
+
const cap = mkCapture();
|
|
348
|
+
setPendingAutoStart(base, {
|
|
349
|
+
basePath: base,
|
|
350
|
+
milestoneId: "M001",
|
|
351
|
+
ctx: mkCtx(cap),
|
|
352
|
+
pi: mkPi(cap),
|
|
353
|
+
});
|
|
354
|
+
// No files written — both probes should report false.
|
|
355
|
+
maybeHandleReadyPhraseWithoutFiles({
|
|
356
|
+
messages: [assistantMsg("Milestone M001 ready.")],
|
|
357
|
+
});
|
|
358
|
+
const logs = drainLogs();
|
|
359
|
+
const diag = logs.find(
|
|
360
|
+
(e) => e.component === "guided" && /ready-phrase-reject diagnostic/.test(e.message),
|
|
361
|
+
);
|
|
362
|
+
assert.ok(diag, "diagnostic logged");
|
|
363
|
+
// mDir resolves because mkBase creates the directory
|
|
364
|
+
assert.match(diag!.message, /mDir=.+M001/);
|
|
365
|
+
assert.match(diag!.message, /canonical-ctx=.+M001-CONTEXT\.md/);
|
|
366
|
+
assert.match(diag!.message, /canonical-roadmap=.+M001-ROADMAP\.md/);
|
|
367
|
+
} finally {
|
|
368
|
+
clearPendingAutoStart();
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
222
372
|
test("fresh entry after give-up resets counter", () => {
|
|
223
373
|
const base = mkBase();
|
|
224
374
|
try {
|
|
@@ -344,6 +494,40 @@ describe("#4573 maybeHandleEmptyIntentTurn", () => {
|
|
|
344
494
|
}
|
|
345
495
|
});
|
|
346
496
|
|
|
497
|
+
test("single-line approval prompt with mid-line `?` and conditional intent → treated as user-handoff (regression: #5187 follow-up)", () => {
|
|
498
|
+
// Regression for the discuss-milestone case where the LLM presented a
|
|
499
|
+
// depth summary and ended with: "Did I capture that correctly? If so,
|
|
500
|
+
// say yes and I'll write requirements and the roadmap preview."
|
|
501
|
+
// The previous heuristic only checked for lines *ending* in `?`, so
|
|
502
|
+
// this single-line paragraph (terminating in `.`) bypassed the
|
|
503
|
+
// user-handoff guard, then COMMIT_INTENT_RE matched "I'll write" and
|
|
504
|
+
// the nudge auto-replied while the user was meant to approve.
|
|
505
|
+
const base = mkBase();
|
|
506
|
+
try {
|
|
507
|
+
const cap = mkCapture();
|
|
508
|
+
setPendingAutoStart(base, {
|
|
509
|
+
basePath: base,
|
|
510
|
+
milestoneId: "M001",
|
|
511
|
+
ctx: mkCtx(cap),
|
|
512
|
+
pi: mkPi(cap),
|
|
513
|
+
});
|
|
514
|
+
const handled = maybeHandleEmptyIntentTurn(
|
|
515
|
+
{
|
|
516
|
+
messages: [
|
|
517
|
+
assistantMsg(
|
|
518
|
+
"Did I capture that correctly? If so, say yes and I'll write requirements and the roadmap preview.",
|
|
519
|
+
),
|
|
520
|
+
],
|
|
521
|
+
},
|
|
522
|
+
false,
|
|
523
|
+
);
|
|
524
|
+
assert.equal(handled, false, "any sentence-terminating ? must defer to the user");
|
|
525
|
+
assert.equal(cap.messages.length, 0);
|
|
526
|
+
} finally {
|
|
527
|
+
clearPendingAutoStart();
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
|
|
347
531
|
test('"Let me make sure" meta phrase → not flagged as commit intent (regression)', () => {
|
|
348
532
|
const base = mkBase();
|
|
349
533
|
try {
|
|
@@ -6,7 +6,7 @@ import { tmpdir } from "node:os";
|
|
|
6
6
|
|
|
7
7
|
import { registerHooks } from "../bootstrap/register-hooks.ts";
|
|
8
8
|
import { parseContinue } from "../files.ts";
|
|
9
|
-
import { closeDatabase } from "../gsd-db.ts";
|
|
9
|
+
import { closeDatabase, insertMilestone, insertSlice, openDatabase } from "../gsd-db.ts";
|
|
10
10
|
import { deriveState, invalidateStateCache } from "../state.ts";
|
|
11
11
|
|
|
12
12
|
function createPlanningFixtureBase(): string {
|
|
@@ -39,6 +39,11 @@ function createPlanningFixtureBase(): string {
|
|
|
39
39
|
`,
|
|
40
40
|
);
|
|
41
41
|
|
|
42
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
43
|
+
insertMilestone({ id: "M001", title: "Test Milestone", status: "active" });
|
|
44
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Test Slice", status: "active", risk: "low", depends: [] });
|
|
45
|
+
closeDatabase();
|
|
46
|
+
|
|
42
47
|
return base;
|
|
43
48
|
}
|
|
44
49
|
|
|
@@ -25,12 +25,15 @@ test("register-hooks unlocks milestone depth verification from question id witho
|
|
|
25
25
|
const dir = makeTempDir("manual");
|
|
26
26
|
const originalCwd = process.cwd();
|
|
27
27
|
process.chdir(dir);
|
|
28
|
-
resetWriteGateState();
|
|
28
|
+
resetWriteGateState(dir);
|
|
29
29
|
|
|
30
30
|
t.after(() => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
try {
|
|
32
|
+
resetWriteGateState(dir);
|
|
33
|
+
} finally {
|
|
34
|
+
process.chdir(originalCwd);
|
|
35
|
+
rmSync(dir, { recursive: true, force: true });
|
|
36
|
+
}
|
|
34
37
|
});
|
|
35
38
|
|
|
36
39
|
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<void> | void>>();
|
|
@@ -101,12 +104,15 @@ test("register-hooks clears depth gate when remote (Telegram/Slack/Discord) answ
|
|
|
101
104
|
const dir = makeTempDir("remote");
|
|
102
105
|
const originalCwd = process.cwd();
|
|
103
106
|
process.chdir(dir);
|
|
104
|
-
resetWriteGateState();
|
|
107
|
+
resetWriteGateState(dir);
|
|
105
108
|
|
|
106
109
|
t.after(() => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
try {
|
|
111
|
+
resetWriteGateState(dir);
|
|
112
|
+
} finally {
|
|
113
|
+
process.chdir(originalCwd);
|
|
114
|
+
rmSync(dir, { recursive: true, force: true });
|
|
115
|
+
}
|
|
110
116
|
});
|
|
111
117
|
|
|
112
118
|
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<void> | void>>();
|
|
@@ -167,12 +173,15 @@ test("register-hooks returns hard blocker when depth question is cancelled", asy
|
|
|
167
173
|
const dir = makeTempDir("cancelled");
|
|
168
174
|
const originalCwd = process.cwd();
|
|
169
175
|
process.chdir(dir);
|
|
170
|
-
resetWriteGateState();
|
|
176
|
+
resetWriteGateState(dir);
|
|
171
177
|
|
|
172
178
|
t.after(() => {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
179
|
+
try {
|
|
180
|
+
resetWriteGateState(dir);
|
|
181
|
+
} finally {
|
|
182
|
+
process.chdir(originalCwd);
|
|
183
|
+
rmSync(dir, { recursive: true, force: true });
|
|
184
|
+
}
|
|
176
185
|
});
|
|
177
186
|
|
|
178
187
|
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
|
|
@@ -228,12 +237,15 @@ test("register-hooks gates MCP ask_user_questions cancellation before requiremen
|
|
|
228
237
|
const dir = makeTempDir("mcp-cancelled");
|
|
229
238
|
const originalCwd = process.cwd();
|
|
230
239
|
process.chdir(dir);
|
|
231
|
-
resetWriteGateState();
|
|
240
|
+
resetWriteGateState(dir);
|
|
232
241
|
|
|
233
242
|
t.after(() => {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
243
|
+
try {
|
|
244
|
+
resetWriteGateState(dir);
|
|
245
|
+
} finally {
|
|
246
|
+
process.chdir(originalCwd);
|
|
247
|
+
rmSync(dir, { recursive: true, force: true });
|
|
248
|
+
}
|
|
237
249
|
});
|
|
238
250
|
|
|
239
251
|
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
|
|
@@ -8,6 +8,9 @@ import { fileURLToPath } from 'node:url';
|
|
|
8
8
|
import { parseSummary } from '../files.ts';
|
|
9
9
|
import { deriveState } from '../state.ts';
|
|
10
10
|
|
|
11
|
+
// This suite exercises the explicit legacy markdown derivation path.
|
|
12
|
+
process.env.GSD_ALLOW_MARKDOWN_DERIVE_FALLBACK = '1';
|
|
13
|
+
|
|
11
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
15
|
const worktreePromptsDir = join(__dirname, '..', 'prompts');
|
|
13
16
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { register } from 'node:module';
|
|
2
2
|
import { pathToFileURL } from 'node:url';
|
|
3
3
|
|
|
4
|
+
// Source legacy state tests exercise markdown derivation through deriveState().
|
|
5
|
+
// Production/runtime keeps this fallback disabled unless explicitly requested.
|
|
6
|
+
process.env.GSD_ALLOW_MARKDOWN_DERIVE_FALLBACK ??= '1';
|
|
7
|
+
|
|
4
8
|
// Register hook to redirect imports to the dist directory
|
|
5
9
|
register(new URL('./dist-redirect.mjs', import.meta.url), pathToFileURL('./'));
|