@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.75048e7
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/dist/cli.js +3 -2
- package/dist/help-text.js +10 -6
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +495 -0
- package/dist/resources/extensions/browser-tools/engine/selection.js +16 -0
- package/dist/resources/extensions/browser-tools/extension-manifest.json +2 -2
- package/dist/resources/extensions/browser-tools/index.js +57 -9
- package/dist/resources/extensions/browser-tools/package.json +5 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +167 -16
- package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
- package/dist/resources/extensions/gsd/auto/phases.js +4 -3
- package/dist/resources/extensions/gsd/auto-dashboard.js +92 -17
- package/dist/resources/extensions/gsd/auto-dispatch.js +55 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +134 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +72 -22
- package/dist/resources/extensions/gsd/auto-recovery.js +7 -8
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +94 -15
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +18 -65
- package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
- package/dist/resources/extensions/gsd/auto.js +31 -6
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +89 -4
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +56 -20
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +33 -38
- package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +9 -5
- package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
- package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
- package/dist/resources/extensions/gsd/commands-mcp-status.js +109 -60
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
- package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +2 -1
- package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
- package/dist/resources/extensions/gsd/error-classifier.js +2 -1
- package/dist/resources/extensions/gsd/escalation.js +4 -4
- package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
- package/dist/resources/extensions/gsd/forensics.js +74 -2
- package/dist/resources/extensions/gsd/gsd-db.js +42 -6
- package/dist/resources/extensions/gsd/guided-flow.js +119 -176
- package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
- package/dist/resources/extensions/gsd/mcp-project-config.js +76 -84
- package/dist/resources/extensions/gsd/memory-store.js +4 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
- package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
- package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
- package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
- package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +33 -23
- package/dist/resources/extensions/gsd/prompts/system.md +3 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
- package/dist/resources/extensions/gsd/rule-registry.js +428 -52
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
- package/dist/resources/extensions/gsd/skill-activation.js +20 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
- package/dist/resources/extensions/gsd/state.js +17 -14
- package/dist/resources/extensions/gsd/templates/plan.md +3 -1
- package/dist/resources/extensions/gsd/tool-contract.js +5 -0
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +143 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
- package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +483 -6
- package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -0
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
- package/dist/resources/extensions/gsd/verification-gate.js +72 -1
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
- package/dist/resources/extensions/gsd/workflow-mcp.js +5 -73
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
- package/dist/resources/extensions/mcp-client/manager.js +31 -1
- package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
- package/dist/rtk.d.ts +7 -1
- package/dist/rtk.js +27 -11
- package/dist/update-check.d.ts +15 -1
- package/dist/update-check.js +87 -12
- package/dist/update-cmd.d.ts +1 -0
- package/dist/update-cmd.js +53 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +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 +5 -5
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +5 -3
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +14 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +16 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +32 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- package/packages/gsd-agent-core/dist/index.d.ts +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +1 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
- package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
- package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
- package/packages/gsd-agent-core/package.json +6 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +92 -31
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
- package/packages/mcp-server/dist/remote-questions.js +23 -9
- package/packages/mcp-server/dist/remote-questions.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +84 -2
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +42 -3
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
- package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +6 -1
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/api-registry.d.ts +2 -0
- package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
- package/packages/pi-ai/dist/api-registry.js +23 -0
- package/packages/pi-ai/dist/api-registry.js.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +15 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +411 -39
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +504 -153
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/stream.js +6 -6
- package/packages/pi-ai/dist/stream.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/terminal.d.ts +1 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +8 -4
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
- package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
- package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
- package/src/resources/extensions/browser-tools/index.ts +60 -9
- package/src/resources/extensions/browser-tools/package.json +5 -1
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
- package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
- package/src/resources/extensions/gsd/auto/phases.ts +5 -3
- package/src/resources/extensions/gsd/auto-dashboard.ts +98 -18
- package/src/resources/extensions/gsd/auto-dispatch.ts +67 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +166 -9
- package/src/resources/extensions/gsd/auto-prompts.ts +106 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +7 -7
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
- package/src/resources/extensions/gsd/auto-start.ts +112 -17
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -73
- package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
- package/src/resources/extensions/gsd/auto.ts +47 -5
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +96 -4
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +81 -25
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +70 -63
- package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +9 -5
- package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
- package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
- package/src/resources/extensions/gsd/commands-mcp-status.ts +136 -58
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
- package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +3 -1
- package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
- package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
- package/src/resources/extensions/gsd/error-classifier.ts +2 -1
- package/src/resources/extensions/gsd/escalation.ts +4 -4
- package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
- package/src/resources/extensions/gsd/forensics.ts +99 -5
- package/src/resources/extensions/gsd/gsd-db.ts +46 -8
- package/src/resources/extensions/gsd/guided-flow.ts +215 -217
- package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
- package/src/resources/extensions/gsd/mcp-project-config.ts +105 -88
- package/src/resources/extensions/gsd/memory-store.ts +4 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
- package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
- package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +33 -23
- package/src/resources/extensions/gsd/prompts/system.md +3 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
- package/src/resources/extensions/gsd/rule-registry.ts +558 -58
- package/src/resources/extensions/gsd/rule-types.ts +2 -0
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
- package/src/resources/extensions/gsd/skill-activation.ts +20 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
- package/src/resources/extensions/gsd/state.ts +18 -14
- package/src/resources/extensions/gsd/templates/plan.md +3 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +156 -4
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
- package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
- package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
- package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +72 -10
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
- package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +83 -1
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +493 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +40 -0
- package/src/resources/extensions/gsd/tool-contract.ts +6 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +223 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
- package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +589 -8
- package/src/resources/extensions/gsd/types.ts +69 -5
- package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -0
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
- package/src/resources/extensions/gsd/verification-gate.ts +87 -1
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +5 -73
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
- package/src/resources/extensions/mcp-client/manager.ts +33 -1
- package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
- package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
- /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → h4TGni4xJzlZjGkxaT6uU}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → h4TGni4xJzlZjGkxaT6uU}/_ssgManifest.js +0 -0
|
@@ -40,10 +40,12 @@ function makeMockCtx(base: string): {
|
|
|
40
40
|
calls: NotifyCall[];
|
|
41
41
|
widgets: Array<[string, unknown]>;
|
|
42
42
|
statuses: Array<[string, string | undefined]>;
|
|
43
|
+
newSessions: Array<{ workspaceRoot?: string }>;
|
|
43
44
|
} {
|
|
44
45
|
const calls: NotifyCall[] = [];
|
|
45
46
|
const widgets: Array<[string, unknown]> = [];
|
|
46
47
|
const statuses: Array<[string, string | undefined]> = [];
|
|
48
|
+
const newSessions: Array<{ workspaceRoot?: string }> = [];
|
|
47
49
|
return {
|
|
48
50
|
ctx: {
|
|
49
51
|
cwd: base,
|
|
@@ -58,10 +60,15 @@ function makeMockCtx(base: string): {
|
|
|
58
60
|
statuses.push([key, value]);
|
|
59
61
|
},
|
|
60
62
|
},
|
|
63
|
+
newSession: async (options?: { workspaceRoot?: string }) => {
|
|
64
|
+
newSessions.push(options ?? {});
|
|
65
|
+
return { cancelled: false };
|
|
66
|
+
},
|
|
61
67
|
},
|
|
62
68
|
calls,
|
|
63
69
|
widgets,
|
|
64
70
|
statuses,
|
|
71
|
+
newSessions,
|
|
65
72
|
};
|
|
66
73
|
}
|
|
67
74
|
|
|
@@ -77,7 +84,10 @@ function makeMockPi(): { pi: any; messages: SentMessage[] } {
|
|
|
77
84
|
};
|
|
78
85
|
}
|
|
79
86
|
|
|
80
|
-
function seedValidationBlockedMilestone(
|
|
87
|
+
function seedValidationBlockedMilestone(
|
|
88
|
+
base: string,
|
|
89
|
+
status: "needs-attention" | "needs-remediation" = "needs-attention",
|
|
90
|
+
): void {
|
|
81
91
|
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
82
92
|
insertMilestone({ id: "M006", title: "Mark All Complete", status: "active" });
|
|
83
93
|
insertSlice({
|
|
@@ -91,9 +101,9 @@ function seedValidationBlockedMilestone(base: string): void {
|
|
|
91
101
|
insertAssessment({
|
|
92
102
|
path: "milestones/M006/M006-VALIDATION.md",
|
|
93
103
|
milestoneId: "M006",
|
|
94
|
-
status
|
|
104
|
+
status,
|
|
95
105
|
scope: "milestone-validation",
|
|
96
|
-
fullContent:
|
|
106
|
+
fullContent: `verdict: ${status}`,
|
|
97
107
|
});
|
|
98
108
|
invalidateStateCache();
|
|
99
109
|
}
|
|
@@ -155,6 +165,31 @@ test("dispatcher blocks workflow-advancing aliases while validation is blocked",
|
|
|
155
165
|
}
|
|
156
166
|
});
|
|
157
167
|
|
|
168
|
+
test("dispatcher allows reassess dispatch while validation needs remediation", async () => {
|
|
169
|
+
const base = makeBase();
|
|
170
|
+
try {
|
|
171
|
+
seedValidationBlockedMilestone(base, "needs-remediation");
|
|
172
|
+
const { ctx, calls, newSessions } = makeMockCtx(base);
|
|
173
|
+
const { pi, messages } = makeMockPi();
|
|
174
|
+
|
|
175
|
+
await handleGSDCommand("dispatch reassess", ctx, pi);
|
|
176
|
+
|
|
177
|
+
assert.equal(messages.length, 1);
|
|
178
|
+
assert.equal(messages[0].customType, "gsd-dispatch");
|
|
179
|
+
assert.equal(messages[0].display, false);
|
|
180
|
+
assert.match(messages[0].content, /UNIT: Reassess Roadmap/);
|
|
181
|
+
assert.ok(
|
|
182
|
+
calls.some((call) => call.kind === "info" && /Dispatching reassess-roadmap for M006\/S01/.test(call.message)),
|
|
183
|
+
`expected reassess dispatch notification, got: ${JSON.stringify(calls)}`,
|
|
184
|
+
);
|
|
185
|
+
assert.deepEqual(newSessions, [{ workspaceRoot: base }]);
|
|
186
|
+
} finally {
|
|
187
|
+
closeDatabase();
|
|
188
|
+
invalidateStateCache();
|
|
189
|
+
cleanup(base);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
158
193
|
test("dispatcher still allows recovery commands while validation is blocked", async () => {
|
|
159
194
|
const base = makeBase();
|
|
160
195
|
try {
|
|
@@ -399,8 +399,12 @@ test("handleVerdict needs-remediation override with --rationale rewrites verdict
|
|
|
399
399
|
assert.match(rewritten, /found missing slice/);
|
|
400
400
|
|
|
401
401
|
assert.ok(
|
|
402
|
-
calls.some((c) =>
|
|
403
|
-
"needs-remediation override should suggest
|
|
402
|
+
calls.some((c) => /\/gsd dispatch reassess/.test(c.message)),
|
|
403
|
+
"needs-remediation override should suggest the reassess dispatch follow-up",
|
|
404
|
+
);
|
|
405
|
+
assert.ok(
|
|
406
|
+
calls.every((c) => !/gsd_reassess_roadmap/.test(c.message)),
|
|
407
|
+
"needs-remediation override should not expose the internal tool name",
|
|
404
408
|
);
|
|
405
409
|
} finally {
|
|
406
410
|
closeDatabase();
|
|
@@ -12,6 +12,7 @@ import { tmpdir } from "node:os";
|
|
|
12
12
|
|
|
13
13
|
import { buildSliceSummaryExcerpt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt } from "../auto-prompts.ts";
|
|
14
14
|
import { invalidateAllCaches } from "../cache.ts";
|
|
15
|
+
import { closeDatabase, insertMilestone, openDatabase } from "../gsd-db.ts";
|
|
15
16
|
|
|
16
17
|
// ─── Fixture helpers ──────────────────────────────────────────────────────
|
|
17
18
|
|
|
@@ -364,3 +365,32 @@ test("validate-milestone prompt uses slice excerpts and on-demand paths instead
|
|
|
364
365
|
"validate prompt must not inline full assessment traces",
|
|
365
366
|
);
|
|
366
367
|
});
|
|
368
|
+
|
|
369
|
+
test("validate-milestone prompt inlines planned verification classes as canonical rows", async (t) => {
|
|
370
|
+
const base = createBase();
|
|
371
|
+
t.after(() => {
|
|
372
|
+
try { closeDatabase(); } catch { /* ignore */ }
|
|
373
|
+
cleanup(base);
|
|
374
|
+
});
|
|
375
|
+
invalidateAllCaches();
|
|
376
|
+
|
|
377
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
378
|
+
insertMilestone({
|
|
379
|
+
id: "M001",
|
|
380
|
+
planning: {
|
|
381
|
+
verificationContract: "Local command exits 0.",
|
|
382
|
+
verificationOperational: "No long-running child process remains.",
|
|
383
|
+
},
|
|
384
|
+
});
|
|
385
|
+
writeRoadmap(base, makeRoadmap());
|
|
386
|
+
writeSummary(base, "S01", makeFatSummary("S01"));
|
|
387
|
+
writeSummary(base, "S02", makeFatSummary("S02"));
|
|
388
|
+
|
|
389
|
+
const prompt = await buildValidateMilestonePrompt("M001", "Test Milestone", base);
|
|
390
|
+
|
|
391
|
+
assert.match(prompt, /### Verification Classes \(from planning\)/);
|
|
392
|
+
assert.match(prompt, /Every row in this table must appear in `verificationClasses`/);
|
|
393
|
+
assert.match(prompt, /\| Class \| Planned Check \|/);
|
|
394
|
+
assert.match(prompt, /\| Contract \| Local command exits 0\. \|/);
|
|
395
|
+
assert.match(prompt, /\| Operational \| No long-running child process remains\. \|/);
|
|
396
|
+
});
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
insertMilestone,
|
|
21
21
|
insertSlice,
|
|
22
22
|
insertTask,
|
|
23
|
+
setSliceSummaryMd,
|
|
23
24
|
} from '../gsd-db.ts';
|
|
24
25
|
import { handleCompleteSlice } from '../tools/complete-slice.ts';
|
|
25
26
|
import type { CompleteSliceParams } from '../types.ts';
|
|
@@ -153,4 +154,45 @@ describe('complete-slice verification gate (#3580)', () => {
|
|
|
153
154
|
);
|
|
154
155
|
}
|
|
155
156
|
});
|
|
157
|
+
|
|
158
|
+
test('backfills prior verification narrative when verification is omitted on re-completion', async () => {
|
|
159
|
+
// Seed full_summary_md with a prior verification narrative (simulates a
|
|
160
|
+
// previous completion where the verification text was recorded).
|
|
161
|
+
const priorVerification = 'All 12 API integration tests pass — zero regressions detected.';
|
|
162
|
+
const priorSummary = [
|
|
163
|
+
'---',
|
|
164
|
+
'verification_result: passed',
|
|
165
|
+
'---',
|
|
166
|
+
'',
|
|
167
|
+
'# S01: Test Slice',
|
|
168
|
+
'',
|
|
169
|
+
'## What Happened',
|
|
170
|
+
'',
|
|
171
|
+
'narrative goes here',
|
|
172
|
+
'',
|
|
173
|
+
'## Verification',
|
|
174
|
+
'',
|
|
175
|
+
priorVerification,
|
|
176
|
+
'',
|
|
177
|
+
'## Requirements Advanced',
|
|
178
|
+
'',
|
|
179
|
+
].join('\n');
|
|
180
|
+
setSliceSummaryMd('M001', 'S01', priorSummary, '');
|
|
181
|
+
|
|
182
|
+
// Complete slice without providing verification — handler must backfill
|
|
183
|
+
// from the existing summary rather than writing an empty section.
|
|
184
|
+
const result = await handleCompleteSlice(
|
|
185
|
+
makeParams({ verification: undefined }),
|
|
186
|
+
basePath,
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
assert.ok(!('error' in result), `expected success, got: ${'error' in result ? (result as { error: string }).error : ''}`);
|
|
190
|
+
|
|
191
|
+
const { summaryPath } = result as { summaryPath: string };
|
|
192
|
+
const written = fs.readFileSync(summaryPath, 'utf8');
|
|
193
|
+
assert.ok(
|
|
194
|
+
written.includes(priorVerification),
|
|
195
|
+
`prior verification narrative must be preserved when verification is omitted; got:\n${written}`,
|
|
196
|
+
);
|
|
197
|
+
});
|
|
156
198
|
});
|
|
@@ -6,6 +6,7 @@ import test from "node:test";
|
|
|
6
6
|
import assert from "node:assert/strict";
|
|
7
7
|
|
|
8
8
|
import { GSDDashboardOverlay } from "../dashboard-overlay.ts";
|
|
9
|
+
import type { UnitMetrics } from "../metrics.ts";
|
|
9
10
|
import { assertFullOuterBorder } from "./tui-border-assertions.ts";
|
|
10
11
|
|
|
11
12
|
const fakeTheme = {
|
|
@@ -23,3 +24,47 @@ test("GSDDashboardOverlay renders inside the shared full border", (t) => {
|
|
|
23
24
|
assert.ok(lines.some((line) => line.startsWith("│")), "body rows should have side borders");
|
|
24
25
|
assert.match(lines.at(-1) ?? "", /^╰─+╯$/);
|
|
25
26
|
});
|
|
27
|
+
|
|
28
|
+
test("GSDDashboardOverlay reuses metrics aggregations until the unit count changes", (t) => {
|
|
29
|
+
const overlay = new GSDDashboardOverlay({ requestRender() {} }, fakeTheme as any, () => {});
|
|
30
|
+
t.after(() => overlay.dispose());
|
|
31
|
+
|
|
32
|
+
const firstUnits = [makeUnit("M001/S001/T001", 0.25)];
|
|
33
|
+
const firstMetrics = (overlay as any).ensureMetricsCache(firstUnits);
|
|
34
|
+
|
|
35
|
+
overlay.invalidate();
|
|
36
|
+
|
|
37
|
+
const sameCountUnits = [makeUnit("M001/S001/T002", 0.5)];
|
|
38
|
+
const sameCountMetrics = (overlay as any).ensureMetricsCache(sameCountUnits);
|
|
39
|
+
assert.equal(sameCountMetrics, firstMetrics, "same unit count should reuse cached metrics");
|
|
40
|
+
assert.equal(sameCountMetrics.totals.cost, 0.25);
|
|
41
|
+
|
|
42
|
+
const increasedCountMetrics = (overlay as any).ensureMetricsCache([
|
|
43
|
+
...sameCountUnits,
|
|
44
|
+
makeUnit("M001/S001/T003", 0.75),
|
|
45
|
+
]);
|
|
46
|
+
assert.notEqual(increasedCountMetrics, firstMetrics, "changed unit count should recompute metrics");
|
|
47
|
+
assert.equal(increasedCountMetrics.totals.units, 2);
|
|
48
|
+
assert.equal(increasedCountMetrics.totals.cost, 1.25);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
function makeUnit(id: string, cost: number): UnitMetrics {
|
|
52
|
+
return {
|
|
53
|
+
type: "execute-task",
|
|
54
|
+
id,
|
|
55
|
+
model: "claude-sonnet-4.5",
|
|
56
|
+
startedAt: 1000,
|
|
57
|
+
finishedAt: 2000,
|
|
58
|
+
tokens: {
|
|
59
|
+
input: 100,
|
|
60
|
+
output: 50,
|
|
61
|
+
cacheRead: 25,
|
|
62
|
+
cacheWrite: 10,
|
|
63
|
+
total: 185,
|
|
64
|
+
},
|
|
65
|
+
cost,
|
|
66
|
+
toolCalls: 1,
|
|
67
|
+
assistantMessages: 1,
|
|
68
|
+
userMessages: 1,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -229,6 +229,24 @@ function makeIsolatedBaseWithCleanup(t: TestContext): string {
|
|
|
229
229
|
return base;
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
function setGsdHeadless(t: TestContext): void {
|
|
233
|
+
const previous = process.env.GSD_HEADLESS;
|
|
234
|
+
process.env.GSD_HEADLESS = "1";
|
|
235
|
+
t.after(() => {
|
|
236
|
+
if (previous === undefined) delete process.env.GSD_HEADLESS;
|
|
237
|
+
else process.env.GSD_HEADLESS = previous;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function unsetGsdHeadless(t: TestContext): void {
|
|
242
|
+
const previous = process.env.GSD_HEADLESS;
|
|
243
|
+
delete process.env.GSD_HEADLESS;
|
|
244
|
+
t.after(() => {
|
|
245
|
+
if (previous === undefined) delete process.env.GSD_HEADLESS;
|
|
246
|
+
else process.env.GSD_HEADLESS = previous;
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
232
250
|
function writeValidProject(base: string): void {
|
|
233
251
|
writeFileSync(join(base, ".gsd", "PROJECT.md"), VALID_PROJECT_MD);
|
|
234
252
|
}
|
|
@@ -364,16 +382,33 @@ test("Deep mode: discuss-project does NOT dispatch when planning_depth is 'light
|
|
|
364
382
|
test("Deep mode: discuss-project DOES dispatch when planning_depth is 'deep' and PROJECT.md missing", async (t) => {
|
|
365
383
|
const base = makeIsolatedBaseWithCleanup(t);
|
|
366
384
|
|
|
385
|
+
unsetGsdHeadless(t);
|
|
386
|
+
|
|
367
387
|
const prefs = { planning_depth: "deep" } as GSDPreferences;
|
|
368
388
|
const result = await rule(PROJECT_RULE_NAME).match(makeCtx(base, prefs));
|
|
369
389
|
assert.ok(result && result.action === "dispatch", "deep mode + missing PROJECT.md must dispatch");
|
|
370
390
|
if (result.action === "dispatch") {
|
|
371
391
|
assert.strictEqual(result.unitType, "discuss-project");
|
|
372
392
|
assert.strictEqual(result.unitId, "PROJECT");
|
|
393
|
+
assert.strictEqual(result.pauseAfterDispatch, true);
|
|
373
394
|
assert.ok(result.prompt.length > 0, "prompt must be non-empty");
|
|
374
395
|
}
|
|
375
396
|
});
|
|
376
397
|
|
|
398
|
+
test("Deep mode: discuss-project does not pause when GSD_HEADLESS is set", async (t) => {
|
|
399
|
+
const base = makeIsolatedBaseWithCleanup(t);
|
|
400
|
+
|
|
401
|
+
setGsdHeadless(t);
|
|
402
|
+
|
|
403
|
+
const prefs = { planning_depth: "deep" } as GSDPreferences;
|
|
404
|
+
const result = await rule(PROJECT_RULE_NAME).match(makeCtx(base, prefs));
|
|
405
|
+
assert.ok(result && result.action === "dispatch", "deep mode + missing PROJECT.md must dispatch");
|
|
406
|
+
if (result.action === "dispatch") {
|
|
407
|
+
assert.strictEqual(result.unitType, "discuss-project");
|
|
408
|
+
assert.strictEqual(result.pauseAfterDispatch, false);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
|
|
377
412
|
test("Deep mode: discuss-project does NOT dispatch when PROJECT.md already exists and is valid", async (t) => {
|
|
378
413
|
const base = makeIsolatedBaseWithCleanup(t);
|
|
379
414
|
|
|
@@ -432,6 +467,8 @@ test("Deep mode: discuss-requirements does NOT dispatch when PROJECT.md missing
|
|
|
432
467
|
test("Deep mode: discuss-requirements DOES dispatch when PROJECT.md exists and REQUIREMENTS.md missing", async (t) => {
|
|
433
468
|
const base = makeIsolatedBaseWithCleanup(t);
|
|
434
469
|
|
|
470
|
+
unsetGsdHeadless(t);
|
|
471
|
+
|
|
435
472
|
writeValidProject(base);
|
|
436
473
|
const prefs = { planning_depth: "deep" } as GSDPreferences;
|
|
437
474
|
const result = await rule(REQUIREMENTS_RULE_NAME).match(makeCtx(base, prefs));
|
|
@@ -439,6 +476,22 @@ test("Deep mode: discuss-requirements DOES dispatch when PROJECT.md exists and R
|
|
|
439
476
|
if (result.action === "dispatch") {
|
|
440
477
|
assert.strictEqual(result.unitType, "discuss-requirements");
|
|
441
478
|
assert.strictEqual(result.unitId, "REQUIREMENTS");
|
|
479
|
+
assert.strictEqual(result.pauseAfterDispatch, true);
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
test("Deep mode: discuss-requirements does not pause when GSD_HEADLESS is set", async (t) => {
|
|
484
|
+
const base = makeIsolatedBaseWithCleanup(t);
|
|
485
|
+
|
|
486
|
+
setGsdHeadless(t);
|
|
487
|
+
|
|
488
|
+
writeValidProject(base);
|
|
489
|
+
const prefs = { planning_depth: "deep" } as GSDPreferences;
|
|
490
|
+
const result = await rule(REQUIREMENTS_RULE_NAME).match(makeCtx(base, prefs));
|
|
491
|
+
assert.ok(result && result.action === "dispatch", "deep mode + PROJECT.md present + REQUIREMENTS.md missing must dispatch");
|
|
492
|
+
if (result.action === "dispatch") {
|
|
493
|
+
assert.strictEqual(result.unitType, "discuss-requirements");
|
|
494
|
+
assert.strictEqual(result.pauseAfterDispatch, false);
|
|
442
495
|
}
|
|
443
496
|
});
|
|
444
497
|
|
|
@@ -868,6 +868,14 @@ describe('derive-state-db', async () => {
|
|
|
868
868
|
dbState.blockers.some(b => b.includes('needs-remediation') && b.includes('M001')),
|
|
869
869
|
'remediation-stuck-db: blocker message mentions milestone and verdict',
|
|
870
870
|
);
|
|
871
|
+
assert.ok(
|
|
872
|
+
dbState.blockers.some(b => b.includes('/gsd dispatch reassess')),
|
|
873
|
+
'remediation-stuck-db: blocker message points users to the reassess command',
|
|
874
|
+
);
|
|
875
|
+
assert.ok(
|
|
876
|
+
dbState.blockers.every(b => !b.includes('gsd_reassess_roadmap')),
|
|
877
|
+
'remediation-stuck-db: blocker message does not expose the internal tool name',
|
|
878
|
+
);
|
|
871
879
|
|
|
872
880
|
closeDatabase();
|
|
873
881
|
} finally {
|
|
@@ -473,13 +473,13 @@ describe('derive-state-helpers', () => {
|
|
|
473
473
|
}
|
|
474
474
|
});
|
|
475
475
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
476
|
+
test('getActiveMilestoneId: DB lock path ignores PARKED flag projection', async () => {
|
|
477
|
+
const base = createFixtureBase();
|
|
478
|
+
const previousLock = process.env.GSD_MILESTONE_LOCK;
|
|
479
|
+
const previousWorker = process.env.GSD_PARALLEL_WORKER;
|
|
480
|
+
try {
|
|
481
|
+
process.env.GSD_MILESTONE_LOCK = 'M001';
|
|
482
|
+
process.env.GSD_PARALLEL_WORKER = '1';
|
|
483
483
|
writeFile(base, 'milestones/M001/M001-PARKED.md', '# Parked on disk');
|
|
484
484
|
|
|
485
485
|
openDatabase(':memory:');
|
|
@@ -487,12 +487,41 @@ describe('derive-state-helpers', () => {
|
|
|
487
487
|
|
|
488
488
|
const id = await getActiveMilestoneId(base);
|
|
489
489
|
assert.equal(id, 'M001', 'DB status remains authoritative despite PARKED projection');
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
490
|
+
} finally {
|
|
491
|
+
if (previousLock === undefined) delete process.env.GSD_MILESTONE_LOCK;
|
|
492
|
+
else process.env.GSD_MILESTONE_LOCK = previousLock;
|
|
493
|
+
if (previousWorker === undefined) delete process.env.GSD_PARALLEL_WORKER;
|
|
494
|
+
else process.env.GSD_PARALLEL_WORKER = previousWorker;
|
|
495
|
+
closeDatabase();
|
|
496
|
+
cleanup(base);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
test('deriveStateFromDb: solo milestone lock scopes state to the requested milestone', async () => {
|
|
501
|
+
const base = createFixtureBase();
|
|
502
|
+
const previousLock = process.env.GSD_MILESTONE_LOCK;
|
|
503
|
+
const previousWorker = process.env.GSD_PARALLEL_WORKER;
|
|
504
|
+
try {
|
|
505
|
+
delete process.env.GSD_PARALLEL_WORKER;
|
|
506
|
+
process.env.GSD_MILESTONE_LOCK = 'M002';
|
|
507
|
+
|
|
508
|
+
openDatabase(':memory:');
|
|
509
|
+
insertMilestone({ id: 'M001', title: 'Earlier', status: 'active' });
|
|
510
|
+
insertMilestone({ id: 'M002', title: 'Requested', status: 'active' });
|
|
511
|
+
|
|
512
|
+
invalidateStateCache();
|
|
513
|
+
const state = await deriveStateFromDb(base);
|
|
514
|
+
const id = await getActiveMilestoneId(base);
|
|
515
|
+
|
|
516
|
+
assert.equal(state.activeMilestone?.id, 'M002', 'explicit lock chooses requested milestone');
|
|
517
|
+
assert.deepEqual(state.registry.map((entry) => entry.id), ['M002'], 'registry is scoped to requested milestone');
|
|
518
|
+
assert.equal(id, 'M002', 'active milestone helper honors solo lock');
|
|
519
|
+
} finally {
|
|
520
|
+
if (previousLock === undefined) delete process.env.GSD_MILESTONE_LOCK;
|
|
521
|
+
else process.env.GSD_MILESTONE_LOCK = previousLock;
|
|
522
|
+
if (previousWorker === undefined) delete process.env.GSD_PARALLEL_WORKER;
|
|
523
|
+
else process.env.GSD_PARALLEL_WORKER = previousWorker;
|
|
524
|
+
closeDatabase();
|
|
496
525
|
cleanup(base);
|
|
497
526
|
}
|
|
498
527
|
});
|
|
@@ -526,6 +555,14 @@ describe('derive-state-helpers', () => {
|
|
|
526
555
|
state.blockers.some(b => b.includes('needs-remediation') && b.includes('M001')),
|
|
527
556
|
'remediation-stuck: blocker message mentions milestone and verdict',
|
|
528
557
|
);
|
|
558
|
+
assert.ok(
|
|
559
|
+
state.blockers.some(b => b.includes('/gsd dispatch reassess')),
|
|
560
|
+
'remediation-stuck: blocker message points users to the reassess command',
|
|
561
|
+
);
|
|
562
|
+
assert.ok(
|
|
563
|
+
state.blockers.every(b => !b.includes('gsd_reassess_roadmap')),
|
|
564
|
+
'remediation-stuck: blocker message does not expose the internal tool name',
|
|
565
|
+
);
|
|
529
566
|
} finally {
|
|
530
567
|
closeDatabase();
|
|
531
568
|
cleanup(base);
|
|
@@ -44,14 +44,26 @@ function setGsdHeadless(t: { after: (fn: () => void) => void }): void {
|
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
function unsetGsdHeadless(t: { after: (fn: () => void) => void }): void {
|
|
48
|
+
const previous = process.env.GSD_HEADLESS;
|
|
49
|
+
delete process.env.GSD_HEADLESS;
|
|
50
|
+
t.after(() => {
|
|
51
|
+
if (previous === undefined) delete process.env.GSD_HEADLESS;
|
|
52
|
+
else process.env.GSD_HEADLESS = previous;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
47
56
|
test("auto-dispatch passes structuredQuestionsAvailable=true into discuss-milestone prompt", async (t) => {
|
|
48
57
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-discuss-milestone-structured-"));
|
|
49
58
|
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
50
59
|
|
|
60
|
+
unsetGsdHeadless(t);
|
|
61
|
+
|
|
51
62
|
const result = await resolveDispatch(makeContext(tmp, "needs-discussion", "true"));
|
|
52
63
|
|
|
53
64
|
assert.equal(result.action, "dispatch");
|
|
54
65
|
assert.equal(result.unitType, "discuss-milestone");
|
|
66
|
+
assert.equal(result.pauseAfterDispatch, true);
|
|
55
67
|
assert.match(
|
|
56
68
|
result.prompt,
|
|
57
69
|
/\*\*Structured questions available: true\*\*/,
|
|
@@ -62,10 +74,13 @@ test("auto-dispatch preserves structuredQuestionsAvailable=false for discuss-mil
|
|
|
62
74
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-discuss-milestone-plain-"));
|
|
63
75
|
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
64
76
|
|
|
77
|
+
unsetGsdHeadless(t);
|
|
78
|
+
|
|
65
79
|
const result = await resolveDispatch(makeContext(tmp, "pre-planning", "false"));
|
|
66
80
|
|
|
67
81
|
assert.equal(result.action, "dispatch");
|
|
68
82
|
assert.equal(result.unitType, "discuss-milestone");
|
|
83
|
+
assert.equal(result.pauseAfterDispatch, true);
|
|
69
84
|
assert.match(
|
|
70
85
|
result.prompt,
|
|
71
86
|
/\*\*Structured questions available: false\*\*/,
|
|
@@ -82,6 +97,7 @@ test("auto-dispatch uses discuss-headless prompt when GSD_HEADLESS is set", asyn
|
|
|
82
97
|
|
|
83
98
|
assert.equal(result.action, "dispatch");
|
|
84
99
|
assert.equal(result.unitType, "discuss-milestone");
|
|
100
|
+
assert.equal(result.pauseAfterDispatch, false);
|
|
85
101
|
assert.match(result.prompt, /This is a \*\*headless\*\* flow/);
|
|
86
102
|
assert.doesNotMatch(result.prompt, /\*\*Structured questions available: true\*\*/);
|
|
87
103
|
});
|
|
@@ -96,10 +112,24 @@ test("auto-dispatch uses discuss-headless prompt for needs-discussion when GSD_H
|
|
|
96
112
|
|
|
97
113
|
assert.equal(result.action, "dispatch");
|
|
98
114
|
assert.equal(result.unitType, "discuss-milestone");
|
|
115
|
+
assert.equal(result.pauseAfterDispatch, false);
|
|
99
116
|
assert.match(result.prompt, /This is a \*\*headless\*\* flow/);
|
|
100
117
|
assert.doesNotMatch(result.prompt, /\*\*Structured questions available: true\*\*/);
|
|
101
118
|
});
|
|
102
119
|
|
|
120
|
+
test("auto-dispatch pauses after execution-entry discuss-milestone recovery", async (t) => {
|
|
121
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-discuss-milestone-executing-"));
|
|
122
|
+
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
123
|
+
|
|
124
|
+
unsetGsdHeadless(t);
|
|
125
|
+
|
|
126
|
+
const result = await resolveDispatch(makeContext(tmp, "executing", "true"));
|
|
127
|
+
|
|
128
|
+
assert.equal(result.action, "dispatch");
|
|
129
|
+
assert.equal(result.unitType, "discuss-milestone");
|
|
130
|
+
assert.equal(result.pauseAfterDispatch, true);
|
|
131
|
+
});
|
|
132
|
+
|
|
103
133
|
test("auto-dispatch uses discuss-headless prompt for executing when GSD_HEADLESS is set", async (t) => {
|
|
104
134
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-discuss-milestone-headless-"));
|
|
105
135
|
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
@@ -110,6 +140,7 @@ test("auto-dispatch uses discuss-headless prompt for executing when GSD_HEADLESS
|
|
|
110
140
|
|
|
111
141
|
assert.equal(result.action, "dispatch");
|
|
112
142
|
assert.equal(result.unitType, "discuss-milestone");
|
|
143
|
+
assert.equal(result.pauseAfterDispatch, false);
|
|
113
144
|
assert.match(result.prompt, /This is a \*\*headless\*\* flow/);
|
|
114
145
|
assert.doesNotMatch(result.prompt, /\*\*Structured questions available: true\*\*/);
|
|
115
146
|
});
|
|
@@ -14,7 +14,7 @@ import { execFileSync } from "node:child_process";
|
|
|
14
14
|
|
|
15
15
|
import { DISPATCH_RULES, resolveDispatch, type DispatchContext } from "../auto-dispatch.ts";
|
|
16
16
|
import { AutoSession } from "../auto/session.ts";
|
|
17
|
-
import { closeDatabase, insertMilestone, insertSlice, openDatabase } from "../gsd-db.ts";
|
|
17
|
+
import { closeDatabase, insertAssessment, insertGateRow, insertMilestone, insertSlice, openDatabase } from "../gsd-db.ts";
|
|
18
18
|
|
|
19
19
|
function makeBase(): string {
|
|
20
20
|
const base = mkdtempSync(join(tmpdir(), "gsd-complete-dispatch-"));
|
|
@@ -225,6 +225,14 @@ describe("complete phase dispatch guard (#5683)", () => {
|
|
|
225
225
|
base = makeBase();
|
|
226
226
|
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
227
227
|
insertMilestone({ id: "M001", title: "Milestone One", status: "complete" });
|
|
228
|
+
insertSlice({ milestoneId: "M001", id: "S01", title: "Done", status: "complete" });
|
|
229
|
+
insertAssessment({
|
|
230
|
+
path: "milestones/M001/M001-VALIDATION.md",
|
|
231
|
+
milestoneId: "M001",
|
|
232
|
+
status: "pass",
|
|
233
|
+
scope: "milestone-validation",
|
|
234
|
+
fullContent: "verdict: pass",
|
|
235
|
+
});
|
|
228
236
|
|
|
229
237
|
const ctx = buildDispatchCtx(base);
|
|
230
238
|
ctx.state.phase = "complete";
|
|
@@ -234,6 +242,37 @@ describe("complete phase dispatch guard (#5683)", () => {
|
|
|
234
242
|
assert.equal(result?.action, "stop");
|
|
235
243
|
assert.equal(result?.reason, "All milestones complete.");
|
|
236
244
|
});
|
|
245
|
+
|
|
246
|
+
test("blocks terminal stop when closed milestone still has pending gates", async () => {
|
|
247
|
+
base = makeBase();
|
|
248
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
249
|
+
insertMilestone({ id: "M001", title: "Milestone One", status: "complete" });
|
|
250
|
+
insertSlice({ milestoneId: "M001", id: "S01", title: "Done", status: "complete" });
|
|
251
|
+
insertAssessment({
|
|
252
|
+
path: "milestones/M001/M001-VALIDATION.md",
|
|
253
|
+
milestoneId: "M001",
|
|
254
|
+
status: "pass",
|
|
255
|
+
scope: "milestone-validation",
|
|
256
|
+
fullContent: "verdict: pass",
|
|
257
|
+
});
|
|
258
|
+
insertGateRow({
|
|
259
|
+
milestoneId: "M001",
|
|
260
|
+
sliceId: "S01",
|
|
261
|
+
gateId: "Q3",
|
|
262
|
+
scope: "slice",
|
|
263
|
+
status: "pending",
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const ctx = buildDispatchCtx(base);
|
|
267
|
+
ctx.state.phase = "complete";
|
|
268
|
+
|
|
269
|
+
const result = await rule.match(ctx);
|
|
270
|
+
|
|
271
|
+
assert.equal(result?.action, "stop");
|
|
272
|
+
assert.equal(result?.level, "warning");
|
|
273
|
+
assert.match(result?.reason ?? "", /closeout-consistency-blocked/);
|
|
274
|
+
assert.match(result?.reason ?? "", /quality gate Q3 is still pending/);
|
|
275
|
+
});
|
|
237
276
|
});
|
|
238
277
|
|
|
239
278
|
describe("complete milestone context recovery guard (#5831)", () => {
|
|
@@ -19,6 +19,7 @@ import type { DispatchContext } from "../auto-dispatch.ts";
|
|
|
19
19
|
import type { AutoSession } from "../auto/session.ts";
|
|
20
20
|
import type { GSDState } from "../types.ts";
|
|
21
21
|
import { enableDebug, disableDebug, getDebugLogPath } from "../debug-logger.ts";
|
|
22
|
+
import { closeDatabase, insertMilestone, isDbAvailable, openDatabase } from "../gsd-db.ts";
|
|
22
23
|
|
|
23
24
|
function makeState(overrides: Partial<GSDState> = {}): GSDState {
|
|
24
25
|
return {
|
|
@@ -123,6 +124,29 @@ test("dispatch: missing task plan triggers plan-slice (not stop) — issue #909"
|
|
|
123
124
|
`unitId should be M002/S03, got: ${result.action === "dispatch" ? result.unitId : "(stop)"}`);
|
|
124
125
|
});
|
|
125
126
|
|
|
127
|
+
test("dispatch: closed milestone is not implicitly recovered or reopened", async (t) => {
|
|
128
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-closed-dispatch-"));
|
|
129
|
+
t.after(() => {
|
|
130
|
+
if (isDbAvailable()) closeDatabase();
|
|
131
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (isDbAvailable()) closeDatabase();
|
|
135
|
+
mkdirSync(join(tmp, ".gsd"), { recursive: true });
|
|
136
|
+
openDatabase(join(tmp, ".gsd", "gsd.db"));
|
|
137
|
+
insertMilestone({ id: "M002", title: "Closed Milestone", status: "complete" });
|
|
138
|
+
scaffoldMilestoneContext(tmp, "M002");
|
|
139
|
+
scaffoldSlicePlan(tmp, "M002", "S03");
|
|
140
|
+
|
|
141
|
+
const result = await resolveDispatch(makeContext(tmp));
|
|
142
|
+
|
|
143
|
+
assert.equal(result.action, "stop");
|
|
144
|
+
assert.ok(result.action === "stop");
|
|
145
|
+
assert.equal(result.level, "warning");
|
|
146
|
+
assert.match(result.reason, /Milestone M002 is closed/);
|
|
147
|
+
assert.match(result.reason, /will not reopen or recover it implicitly/);
|
|
148
|
+
});
|
|
149
|
+
|
|
126
150
|
test("dispatch: present task plan proceeds to execute-task normally", async (t) => {
|
|
127
151
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-909-ok-"));
|
|
128
152
|
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
@@ -141,6 +165,42 @@ test("dispatch: present task plan proceeds to execute-task normally", async (t)
|
|
|
141
165
|
`unitId should be M002/S03/T01, got: ${result.action === "dispatch" ? result.unitId : "(stop)"}`);
|
|
142
166
|
});
|
|
143
167
|
|
|
168
|
+
test("dispatch: session milestone mismatch stops before missing-task-plan recovery", async (t) => {
|
|
169
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-session-milestone-mismatch-"));
|
|
170
|
+
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
171
|
+
|
|
172
|
+
const worktreeRoot = join(tmp, ".gsd", "worktrees", "M002");
|
|
173
|
+
mkdirSync(worktreeRoot, { recursive: true });
|
|
174
|
+
|
|
175
|
+
const ctx = makeContextFor(tmp, "M001", "S01", "T01", {
|
|
176
|
+
basePath: worktreeRoot,
|
|
177
|
+
originalBasePath: tmp,
|
|
178
|
+
currentMilestoneId: "M002",
|
|
179
|
+
});
|
|
180
|
+
const result = await resolveDispatch(ctx);
|
|
181
|
+
|
|
182
|
+
assert.equal(result.action, "stop");
|
|
183
|
+
assert.ok(result.action === "stop");
|
|
184
|
+
assert.equal(result.level, "warning");
|
|
185
|
+
assert.match(result.reason, /context mid "M001" does not match session\.currentMilestoneId "M002"/);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("dispatch: worktree path mismatch stops before planning a different milestone", async (t) => {
|
|
189
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-worktree-path-milestone-mismatch-"));
|
|
190
|
+
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
191
|
+
|
|
192
|
+
const worktreeRoot = join(tmp, ".gsd", "worktrees", "M002");
|
|
193
|
+
mkdirSync(worktreeRoot, { recursive: true });
|
|
194
|
+
|
|
195
|
+
const ctx = makeContextFor(worktreeRoot, "M001", "S01", "T01");
|
|
196
|
+
const result = await resolveDispatch(ctx);
|
|
197
|
+
|
|
198
|
+
assert.equal(result.action, "stop");
|
|
199
|
+
assert.ok(result.action === "stop");
|
|
200
|
+
assert.equal(result.level, "warning");
|
|
201
|
+
assert.match(result.reason, /context mid "M001" does not match basePath worktree "M002"/);
|
|
202
|
+
});
|
|
203
|
+
|
|
144
204
|
test("dispatch: executing recovery checks active milestone worktree task plans before re-dispatching plan-slice", async (t) => {
|
|
145
205
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-6192-"));
|
|
146
206
|
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|