@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.9bb7453
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 +44 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +134 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +68 -22
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -4
- 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 +2 -1
- package/dist/resources/extensions/gsd/auto.js +31 -6
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +83 -4
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +39 -14
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
- package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
- 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 +30 -69
- 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/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 +48 -24
- 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/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-presentation-plan.js +120 -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 +403 -3
- package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
- 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 -1
- 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 +6 -6
- 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 +6 -6
- 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/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 +38 -0
- 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/types.d.ts +3 -0
- 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 +406 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +484 -116
- 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/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/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 +53 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +166 -9
- package/src/resources/extensions/gsd/auto-prompts.ts +102 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +4 -4
- 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 +2 -1
- package/src/resources/extensions/gsd/auto.ts +47 -5
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +90 -4
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +60 -19
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
- package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
- 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 +91 -83
- 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/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 +48 -24
- 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/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-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/browser-evidence.test.ts +142 -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-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/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.test.ts +12 -9
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +66 -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/migration-auto-check.test.ts +3 -3
- 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 +53 -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 +35 -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/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 +213 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +167 -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 +489 -3
- 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/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 -1
- 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/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → jBtwT9v1u2lUA3UEOy_ZH}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → jBtwT9v1u2lUA3UEOy_ZH}/_ssgManifest.js +0 -0
|
@@ -32,6 +32,8 @@ export interface RuleLifecycle {
|
|
|
32
32
|
retry_on?: string;
|
|
33
33
|
/** Max times this hook can fire for the same trigger unit. */
|
|
34
34
|
max_cycles?: number;
|
|
35
|
+
/** Whether this hook is advisory or blocking. */
|
|
36
|
+
criticality?: PostUnitHookConfig["criticality"];
|
|
35
37
|
/** Idempotency key pattern for this hook. */
|
|
36
38
|
idempotency_key?: string;
|
|
37
39
|
}
|
|
@@ -24,6 +24,9 @@ const DESTRUCTIVE_PATTERNS: readonly DestructivePattern[] = [
|
|
|
24
24
|
{ pattern: /\btruncate\s+table\b/i, label: "SQL truncate" },
|
|
25
25
|
{ pattern: /\bchmod\s+777\b/, label: "world-writable permissions" },
|
|
26
26
|
{ pattern: /\bcurl\s.*\|\s*(bash|sh|zsh)\b/, label: "pipe to shell" },
|
|
27
|
+
{ pattern: /\bterra(form|grunt)\s+(apply|destroy)/i, label: "IaC apply/destroy" },
|
|
28
|
+
{ pattern: /\baws\s+\w+\s+(delete|create|put|remove|terminate)\b/i, label: "AWS mutation" },
|
|
29
|
+
{ pattern: /\bkubectl\s+(delete|apply)\b/i, label: "kubectl mutation" },
|
|
27
30
|
];
|
|
28
31
|
|
|
29
32
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
@@ -50,6 +50,16 @@ function tokenizeSkillContext(...parts: Array<string | null | undefined>): Set<s
|
|
|
50
50
|
return tokens;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
function tokenizeUnitType(unitType: string | undefined): Set<string> {
|
|
54
|
+
const tokens = new Set<string>();
|
|
55
|
+
const value = unitType?.trim().toLowerCase();
|
|
56
|
+
if (!value) return tokens;
|
|
57
|
+
tokens.add(value);
|
|
58
|
+
tokens.add(value.replace(/[-_]+/g, " "));
|
|
59
|
+
tokens.add(value.replace(/[-_\s]+/g, ""));
|
|
60
|
+
return tokens;
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
function skillMatchesContext(skill: Skill, contextTokens: Set<string>): boolean {
|
|
54
64
|
const haystacks = [
|
|
55
65
|
skill.name.toLowerCase(),
|
|
@@ -79,17 +89,25 @@ function ruleMatchesContext(when: string, contextTokens: Set<string>): boolean {
|
|
|
79
89
|
);
|
|
80
90
|
}
|
|
81
91
|
|
|
92
|
+
function ruleMatchesUnitType(when: string, unitType: string | undefined): boolean {
|
|
93
|
+
if (!unitType) return false;
|
|
94
|
+
const whenTokens = tokenizeSkillContext(when);
|
|
95
|
+
const unitTokens = tokenizeUnitType(unitType);
|
|
96
|
+
return [...unitTokens].some(token => whenTokens.has(token));
|
|
97
|
+
}
|
|
98
|
+
|
|
82
99
|
function resolveSkillRuleMatches(
|
|
83
100
|
prefs: GSDPreferences | undefined,
|
|
84
101
|
contextTokens: Set<string>,
|
|
85
102
|
base: string,
|
|
103
|
+
unitType?: string,
|
|
86
104
|
): { include: string[]; avoid: string[] } {
|
|
87
105
|
if (!prefs?.skill_rules?.length) return { include: [], avoid: [] };
|
|
88
106
|
|
|
89
107
|
const include: string[] = [];
|
|
90
108
|
const avoid: string[] = [];
|
|
91
109
|
for (const rule of prefs.skill_rules) {
|
|
92
|
-
if (!ruleMatchesContext(rule.when, contextTokens)) continue;
|
|
110
|
+
if (!ruleMatchesContext(rule.when, contextTokens) && !ruleMatchesUnitType(rule.when, unitType)) continue;
|
|
93
111
|
include.push(...resolvePreferenceSkillNames([...(rule.use ?? []), ...(rule.prefer ?? [])], base));
|
|
94
112
|
avoid.push(...resolvePreferenceSkillNames(rule.avoid ?? [], base));
|
|
95
113
|
}
|
|
@@ -196,7 +214,7 @@ export function buildSkillActivationBlock(params: {
|
|
|
196
214
|
matched.add(name);
|
|
197
215
|
}
|
|
198
216
|
|
|
199
|
-
const ruleMatches = resolveSkillRuleMatches(prefs, contextTokens, params.base);
|
|
217
|
+
const ruleMatches = resolveSkillRuleMatches(prefs, contextTokens, params.base, params.unitType);
|
|
200
218
|
for (const name of ruleMatches.include) matched.add(name);
|
|
201
219
|
for (const name of ruleMatches.avoid) avoided.add(name);
|
|
202
220
|
|
|
@@ -434,7 +434,8 @@ export function repairArtifactDbDrift(
|
|
|
434
434
|
`Artifact/DB status drift in ${record.milestoneId}` +
|
|
435
435
|
`${record.sliceId ? `/${record.sliceId}` : ""}` +
|
|
436
436
|
`${record.taskId ? `/${record.taskId}` : ""}: ${record.reason}. ` +
|
|
437
|
-
"Runtime will not silently import completion artifacts into DB state
|
|
437
|
+
"Runtime will not silently import completion artifacts into DB state. " +
|
|
438
|
+
"Run `/gsd rebuild markdown` after review to quarantine stale projections and re-render from the DB; use `/gsd recover --confirm` only when markdown should repopulate a lost or corrupt DB.",
|
|
438
439
|
);
|
|
439
440
|
}
|
|
440
441
|
|
|
@@ -461,7 +462,8 @@ export function describeArtifactDbDriftBlocker(
|
|
|
461
462
|
`Artifact/DB status drift in ${record.milestoneId}` +
|
|
462
463
|
`${record.sliceId ? `/${record.sliceId}` : ""}` +
|
|
463
464
|
`${record.taskId ? `/${record.taskId}` : ""}: ${record.reason}. ` +
|
|
464
|
-
"Runtime will not silently import completion artifacts into DB state
|
|
465
|
+
"Runtime will not silently import completion artifacts into DB state. " +
|
|
466
|
+
"Run `/gsd rebuild markdown` after review to quarantine stale projections and re-render from the DB; use `/gsd recover --confirm` only when markdown should repopulate a lost or corrupt DB."
|
|
465
467
|
);
|
|
466
468
|
}
|
|
467
469
|
|
|
@@ -55,7 +55,7 @@ export function repairUnregisteredMilestone(
|
|
|
55
55
|
): void {
|
|
56
56
|
throw new Error(
|
|
57
57
|
`Milestone ${record.milestoneId} exists only as markdown projection. ` +
|
|
58
|
-
"Runtime reconciliation will not import markdown into the authoritative DB; run `/gsd recover` if this markdown should repopulate the database.",
|
|
58
|
+
"Runtime reconciliation will not import markdown into the authoritative DB; run `/gsd recover --confirm` if this markdown should repopulate the database.",
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -9,6 +9,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
9
9
|
import {
|
|
10
10
|
getMilestone,
|
|
11
11
|
getMilestoneSlices,
|
|
12
|
+
getSliceTasks,
|
|
12
13
|
isDbAvailable,
|
|
13
14
|
} from "../../gsd-db.js";
|
|
14
15
|
import { renderRoadmapFromDb } from "../../markdown-renderer.js";
|
|
@@ -30,6 +31,19 @@ function arraysEqual(a: readonly string[], b: readonly string[]): boolean {
|
|
|
30
31
|
return true;
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
function getSlicesReadyForDivergenceCheck(
|
|
35
|
+
milestoneId: string,
|
|
36
|
+
dbSlices: ReturnType<typeof getMilestoneSlices>,
|
|
37
|
+
): Set<string> {
|
|
38
|
+
const ready = new Set<string>();
|
|
39
|
+
for (const slice of dbSlices) {
|
|
40
|
+
if (isClosedStatus(slice.status) || getSliceTasks(milestoneId, slice.id).length > 0) {
|
|
41
|
+
ready.add(slice.id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return ready;
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
function milestoneHasDivergence(
|
|
34
48
|
basePath: string,
|
|
35
49
|
milestoneId: string,
|
|
@@ -46,6 +60,10 @@ function milestoneHasDivergence(
|
|
|
46
60
|
|
|
47
61
|
const dbSlices = getMilestoneSlices(milestoneId);
|
|
48
62
|
const dbSliceMap = new Map(dbSlices.map((s) => [s.id, s]));
|
|
63
|
+
const readySliceIds = getSlicesReadyForDivergenceCheck(milestoneId, dbSlices);
|
|
64
|
+
if (dbSlices.length > 0 && readySliceIds.size === 0) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
49
67
|
const roadmapSliceIds = new Set<string>();
|
|
50
68
|
|
|
51
69
|
for (let i = 0; i < roadmap.slices.length; i++) {
|
|
@@ -54,11 +72,13 @@ function milestoneHasDivergence(
|
|
|
54
72
|
const expectedSequence = i + 1;
|
|
55
73
|
const dbSlice = dbSliceMap.get(roadmapSlice.id);
|
|
56
74
|
if (!dbSlice) return true; // Roadmap has a slice the DB doesn't.
|
|
75
|
+
if (!readySliceIds.has(dbSlice.id)) continue;
|
|
57
76
|
if (dbSlice.sequence !== expectedSequence) return true;
|
|
58
77
|
if (!arraysEqual(dbSlice.depends, roadmapSlice.depends)) return true;
|
|
59
78
|
if (isClosedStatus(dbSlice.status) !== roadmapSlice.done) return true;
|
|
60
79
|
}
|
|
61
80
|
for (const dbSlice of dbSlices) {
|
|
81
|
+
if (!readySliceIds.has(dbSlice.id)) continue;
|
|
62
82
|
if (!roadmapSliceIds.has(dbSlice.id)) return true;
|
|
63
83
|
}
|
|
64
84
|
return false;
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
deriveState as defaultDeriveState,
|
|
7
7
|
invalidateStateCache as defaultInvalidate,
|
|
8
8
|
} from "../state.js";
|
|
9
|
+
import { clearParseCache as defaultClearParseCache } from "../files.js";
|
|
9
10
|
import type { GSDState } from "../types.js";
|
|
10
11
|
|
|
11
12
|
import {
|
|
@@ -37,6 +38,7 @@ const MAX_PASSES = 2;
|
|
|
37
38
|
const defaultDeps: ReconciliationDeps = {
|
|
38
39
|
invalidateStateCache: defaultInvalidate,
|
|
39
40
|
deriveState: defaultDeriveState,
|
|
41
|
+
clearParseCache: defaultClearParseCache,
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
/**
|
|
@@ -58,6 +60,7 @@ export async function reconcileBeforeDispatch(
|
|
|
58
60
|
deps: ReconciliationDeps = defaultDeps,
|
|
59
61
|
): Promise<ReconciliationResult> {
|
|
60
62
|
const registry = deps.registry ?? DRIFT_REGISTRY;
|
|
63
|
+
const clearParseCache = deps.clearParseCache ?? defaultClearParseCache;
|
|
61
64
|
const repaired: DriftRecord[] = [];
|
|
62
65
|
|
|
63
66
|
for (let pass = 0; pass < MAX_PASSES; pass++) {
|
|
@@ -103,6 +106,9 @@ export async function reconcileBeforeDispatch(
|
|
|
103
106
|
}
|
|
104
107
|
}
|
|
105
108
|
|
|
109
|
+
if (repairedThisPass) {
|
|
110
|
+
clearParseCache();
|
|
111
|
+
}
|
|
106
112
|
if (blockers.length > 0) {
|
|
107
113
|
let blockerState = stateSnapshot;
|
|
108
114
|
if (repairedThisPass) {
|
|
@@ -101,6 +101,7 @@ export interface ReconciliationDeps {
|
|
|
101
101
|
basePath: string,
|
|
102
102
|
opts?: DeriveStateOptions,
|
|
103
103
|
) => Promise<GSDState>;
|
|
104
|
+
clearParseCache?: () => void;
|
|
104
105
|
/**
|
|
105
106
|
* Override of the drift handler catalog. Defaults to DRIFT_REGISTRY. Each
|
|
106
107
|
* handler is parameterized over its own DriftRecord variant; the union of
|
|
@@ -83,7 +83,7 @@ function formatNeedsRemediationBlocker(milestoneId: string): string {
|
|
|
83
83
|
return [
|
|
84
84
|
`Milestone ${milestoneId} is blocked because milestone validation returned needs-remediation, but all slices are complete.`,
|
|
85
85
|
`Fix options:`,
|
|
86
|
-
`1.
|
|
86
|
+
`1. Run \`/gsd dispatch reassess\` to add remediation slices, then run \`/gsd auto\``,
|
|
87
87
|
`2. If the finding is acceptable, override it: \`/gsd verdict pass --rationale "why this is okay"\``,
|
|
88
88
|
`3. If this should wait, defer it explicitly: \`/gsd park ${milestoneId}\``,
|
|
89
89
|
].join("\n");
|
|
@@ -279,10 +279,17 @@ export function invalidateStateCache(): void {
|
|
|
279
279
|
/**
|
|
280
280
|
* Returns the ID of the first incomplete milestone, or null if all are complete.
|
|
281
281
|
*/
|
|
282
|
+
function getRequestedMilestoneLock(): string | undefined {
|
|
283
|
+
const lock = process.env.GSD_MILESTONE_LOCK?.trim();
|
|
284
|
+
return lock || undefined;
|
|
285
|
+
}
|
|
286
|
+
|
|
282
287
|
export async function getActiveMilestoneId(basePath: string): Promise<string | null> {
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
|
|
288
|
+
// Milestone-scoped execution. Parallel workers and explicit solo commands
|
|
289
|
+
// such as `/gsd auto M002` both set GSD_MILESTONE_LOCK; state derivation must
|
|
290
|
+
// honor it so recovery/adoption sees the requested milestone, not the first
|
|
291
|
+
// open milestone in queue order.
|
|
292
|
+
const milestoneLock = getRequestedMilestoneLock();
|
|
286
293
|
if (milestoneLock) {
|
|
287
294
|
if (isDbAvailable()) {
|
|
288
295
|
const locked = getAllMilestones().find(m => m.id === milestoneLock);
|
|
@@ -720,7 +727,7 @@ export async function deriveStateFromDb(
|
|
|
720
727
|
|
|
721
728
|
const allMilestones = getAllMilestones();
|
|
722
729
|
|
|
723
|
-
const milestoneLock =
|
|
730
|
+
const milestoneLock = getRequestedMilestoneLock();
|
|
724
731
|
const milestones = milestoneLock
|
|
725
732
|
? allMilestones.filter(m => m.id === milestoneLock)
|
|
726
733
|
: allMilestones;
|
|
@@ -889,8 +896,8 @@ export async function deriveStateFromDb(
|
|
|
889
896
|
}
|
|
890
897
|
|
|
891
898
|
// ADR-011 Phase 2: pause-on-escalation takes precedence over dispatching the
|
|
892
|
-
// next task. `awaiting_review` tasks (continueWithDefault=true)
|
|
893
|
-
//
|
|
899
|
+
// next task. `awaiting_review` tasks (continueWithDefault=true) still pause
|
|
900
|
+
// here so silence is never treated as consent.
|
|
894
901
|
//
|
|
895
902
|
// We do NOT gate this on `phases.mid_execution_escalation` — creation of
|
|
896
903
|
// new escalations is gated at the write site (tools/complete-task.ts:315),
|
|
@@ -959,13 +966,10 @@ export async function _deriveStateImpl(
|
|
|
959
966
|
const customOrder = loadQueueOrder(basePath);
|
|
960
967
|
const milestoneIds = sortByQueueOrder(diskIds, customOrder);
|
|
961
968
|
|
|
962
|
-
// ──
|
|
963
|
-
//
|
|
964
|
-
//
|
|
965
|
-
|
|
966
|
-
// don't exist). This gives each worker complete isolation without
|
|
967
|
-
// modifying any other state derivation logic.
|
|
968
|
-
const milestoneLock = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_MILESTONE_LOCK : undefined;
|
|
969
|
+
// ── Milestone-scoped execution ─────────────────────────────────────────
|
|
970
|
+
// Parallel workers and explicit solo recovery both scope auto-mode to one
|
|
971
|
+
// milestone through GSD_MILESTONE_LOCK.
|
|
972
|
+
const milestoneLock = getRequestedMilestoneLock();
|
|
969
973
|
if (milestoneLock && milestoneIds.includes(milestoneLock)) {
|
|
970
974
|
milestoneIds.length = 0;
|
|
971
975
|
milestoneIds.push(milestoneLock);
|
|
@@ -132,14 +132,16 @@
|
|
|
132
132
|
Verify field rules:
|
|
133
133
|
- MUST be a mechanically executable command: `npm test`, `grep -q "pattern" file`, `test -f path`
|
|
134
134
|
- MUST NOT use shell pipes, redirects, semicolons, backticks, command substitution, output trimming, or grep regex alternation with `|`
|
|
135
|
+
- For absence checks, use `! grep -q "pattern" file` or `! rg -q "pattern" file`; do not use `grep -c` or `rg -c` to assert zero matches because count commands exit 1 when they find zero matches
|
|
135
136
|
- MUST NOT use inline `node -e` assertions for verification; put assertions in a real test file and run it with `node --test` or a package test script
|
|
136
137
|
- For content/document tasks: verify file existence, section count, YAML validity, or word count
|
|
137
138
|
NOT exact phrasing, specific formulas, or "zero TBD" aspirational criteria
|
|
138
139
|
- If no command can verify the output, write: "Manual review — file exists and is non-empty"
|
|
139
140
|
- BAD: `python3 -m pytest tests/ -q --tb=short 2>&1 | tail -5`
|
|
141
|
+
- BAD: `grep -c "old_api" src/index.ts`
|
|
140
142
|
- BAD: "Sections 3.1 and 3.2 exist with exact formulas. Zero TBD/TODO."
|
|
141
143
|
- GOOD: `python3 -m pytest tests/ -q --tb=short`
|
|
142
|
-
- GOOD: `node --test tests/verify-doc.test.js`, `grep -q "Required heading" doc.md`, `test -s doc.md`
|
|
144
|
+
- GOOD: `node --test tests/verify-doc.test.js`, `grep -q "Required heading" doc.md`, `! grep -q "old_api" src/index.ts`, `test -s doc.md`
|
|
143
145
|
|
|
144
146
|
Integration closure rule:
|
|
145
147
|
- At least one slice in any multi-boundary milestone should perform real composition/wiring, not just contract hardening
|
|
@@ -4,6 +4,7 @@ import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { execFileSync } from "node:child_process";
|
|
7
|
+
import { visibleWidth } from "@gsd/pi-tui";
|
|
7
8
|
|
|
8
9
|
import {
|
|
9
10
|
unitVerb,
|
|
@@ -16,11 +17,13 @@ import {
|
|
|
16
17
|
buildPhaseHandoffOutcome,
|
|
17
18
|
updateProgressWidget,
|
|
18
19
|
setAutoOutcomeWidget,
|
|
20
|
+
setAutoActiveStatus,
|
|
19
21
|
setCompletionProgressWidget,
|
|
20
22
|
getRoadmapSlicesSync,
|
|
21
23
|
clearSliceProgressCache,
|
|
22
24
|
getWidgetMode,
|
|
23
25
|
cycleWidgetMode,
|
|
26
|
+
setWidgetMode,
|
|
24
27
|
_resetWidgetModeForTests,
|
|
25
28
|
_resetLastCommitCacheForTests,
|
|
26
29
|
_refreshLastCommitForTests,
|
|
@@ -55,6 +58,17 @@ function cleanup(dir: string): void {
|
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
|
|
61
|
+
function assertLinesFit(lines: string[], width: number): void {
|
|
62
|
+
for (const line of lines) {
|
|
63
|
+
assert.ok(
|
|
64
|
+
visibleWidth(line) <= width,
|
|
65
|
+
`line exceeds width ${width}: ${visibleWidth(line)} "${line}"`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
type RenderableWidget = { render(width: number): string[]; invalidate(): void; dispose?: () => void };
|
|
71
|
+
|
|
58
72
|
// ─── unitVerb ─────────────────────────────────────────────────────────────
|
|
59
73
|
|
|
60
74
|
test("unitVerb maps known unit types to verbs", () => {
|
|
@@ -78,6 +92,26 @@ test("unitVerb handles hook types", () => {
|
|
|
78
92
|
assert.equal(unitVerb("hook/"), "hook: ");
|
|
79
93
|
});
|
|
80
94
|
|
|
95
|
+
test("setAutoActiveStatus clears stale outcome surfaces", () => {
|
|
96
|
+
const statusCalls: Array<[string, string]> = [];
|
|
97
|
+
const widgetCalls: Array<[string, unknown]> = [];
|
|
98
|
+
|
|
99
|
+
setAutoActiveStatus({
|
|
100
|
+
hasUI: true,
|
|
101
|
+
ui: {
|
|
102
|
+
setStatus: (key: string, value: string) => {
|
|
103
|
+
statusCalls.push([key, value]);
|
|
104
|
+
},
|
|
105
|
+
setWidget: (key: string, value: unknown) => {
|
|
106
|
+
widgetCalls.push([key, value]);
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
} as any, "next");
|
|
110
|
+
|
|
111
|
+
assert.deepEqual(statusCalls, [["gsd-auto", "next"]]);
|
|
112
|
+
assert.deepEqual(widgetCalls, [["gsd-outcome", undefined]]);
|
|
113
|
+
});
|
|
114
|
+
|
|
81
115
|
// ─── unitPhaseLabel ───────────────────────────────────────────────────────
|
|
82
116
|
|
|
83
117
|
test("unitPhaseLabel maps known types to labels", () => {
|
|
@@ -571,14 +605,21 @@ test("updateProgressWidget refreshes slice progress cache immediately", (t) => {
|
|
|
571
605
|
test("updateProgressWidget full mode keeps footer-owned signals out of auto deck", (t) => {
|
|
572
606
|
const dir = makeTempDir("command-deck");
|
|
573
607
|
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
608
|
+
const projectPrefsPath = join(dir, ".gsd", "preferences.md");
|
|
609
|
+
const globalPrefsPath = join(dir, ".gsd", "global-preferences.md");
|
|
610
|
+
writeFileSync(projectPrefsPath, "---\nversion: 1\n---\n", "utf-8");
|
|
574
611
|
let widget: { render(width: number): string[]; dispose?: () => void } | null = null;
|
|
575
612
|
|
|
576
613
|
t.after(() => {
|
|
577
614
|
widget?.dispose?.();
|
|
615
|
+
_resetWidgetModeForTests();
|
|
578
616
|
clearSliceProgressCache();
|
|
579
617
|
cleanup(dir);
|
|
580
618
|
});
|
|
581
619
|
|
|
620
|
+
_resetWidgetModeForTests();
|
|
621
|
+
setWidgetMode("full", projectPrefsPath, globalPrefsPath);
|
|
622
|
+
|
|
582
623
|
updateProgressWidget(
|
|
583
624
|
{
|
|
584
625
|
hasUI: true,
|
|
@@ -633,6 +674,95 @@ test("updateProgressWidget full mode keeps footer-owned signals out of auto deck
|
|
|
633
674
|
assert.doesNotMatch(rendered, /\$/, "footer owns session cost display");
|
|
634
675
|
});
|
|
635
676
|
|
|
677
|
+
test("updateProgressWidget small mode renders the dense horizontal grid", (t) => {
|
|
678
|
+
const dir = makeTempDir("small-dense-grid");
|
|
679
|
+
const homeDir = makeTempDir("small-dense-grid-home");
|
|
680
|
+
const projectPrefsPath = join(dir, ".gsd", "preferences.md");
|
|
681
|
+
const globalPrefsPath = join(homeDir, ".gsd", "preferences.md");
|
|
682
|
+
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
683
|
+
mkdirSync(join(homeDir, ".gsd"), { recursive: true });
|
|
684
|
+
writeFileSync(projectPrefsPath, "---\nversion: 1\nwidget_mode: full\n---\n", "utf-8");
|
|
685
|
+
writeFileSync(globalPrefsPath, "---\nversion: 1\nwidget_mode: full\n---\n", "utf-8");
|
|
686
|
+
|
|
687
|
+
const holder: { widget?: RenderableWidget } = {};
|
|
688
|
+
|
|
689
|
+
t.after(() => {
|
|
690
|
+
holder.widget?.dispose?.();
|
|
691
|
+
closeDatabase();
|
|
692
|
+
clearSliceProgressCache();
|
|
693
|
+
_resetWidgetModeForTests();
|
|
694
|
+
cleanup(dir);
|
|
695
|
+
cleanup(homeDir);
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
openDatabase(join(dir, ".gsd", "gsd.db"));
|
|
699
|
+
insertMilestone({ id: "M004", title: "Budget Tracking", status: "active" });
|
|
700
|
+
insertSlice({ milestoneId: "M004", id: "S01", title: "Schema migration", status: "complete", sequence: 1 });
|
|
701
|
+
insertSlice({ milestoneId: "M004", id: "S02", title: "Expense add", status: "pending", sequence: 2 });
|
|
702
|
+
insertTask({ milestoneId: "M004", sliceId: "S01", id: "T01", title: "Add repeat column via idempotent ALTER TABLE", status: "complete" });
|
|
703
|
+
insertTask({ milestoneId: "M004", sliceId: "S01", id: "T02", title: "Backfill repeat metadata", status: "pending" });
|
|
704
|
+
|
|
705
|
+
_resetWidgetModeForTests();
|
|
706
|
+
setWidgetMode("small", projectPrefsPath, globalPrefsPath);
|
|
707
|
+
|
|
708
|
+
updateProgressWidget(
|
|
709
|
+
{
|
|
710
|
+
hasUI: true,
|
|
711
|
+
ui: {
|
|
712
|
+
setHeader() {},
|
|
713
|
+
setStatus() {},
|
|
714
|
+
setWidget(_key: string, factory: any) {
|
|
715
|
+
if (_key === "gsd-progress") {
|
|
716
|
+
holder.widget = factory(
|
|
717
|
+
{ requestRender() {} },
|
|
718
|
+
{ fg: (_color: string, text: string) => text, bold: (text: string) => text },
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
},
|
|
722
|
+
},
|
|
723
|
+
} as any,
|
|
724
|
+
"execute-task",
|
|
725
|
+
"M004/S01/T02",
|
|
726
|
+
{
|
|
727
|
+
phase: "executing",
|
|
728
|
+
activeMilestone: { id: "M004", title: "Budget Tracking" },
|
|
729
|
+
activeSlice: { id: "S01", title: "Schema migration" },
|
|
730
|
+
activeTask: { id: "T02", title: "Backfill repeat metadata" },
|
|
731
|
+
} as any,
|
|
732
|
+
{
|
|
733
|
+
getAutoStartTime: () => Date.now() - 18_000,
|
|
734
|
+
isStepMode: () => false,
|
|
735
|
+
getCmdCtx: () => null,
|
|
736
|
+
getBasePath: () => dir,
|
|
737
|
+
isVerbose: () => false,
|
|
738
|
+
isSessionSwitching: () => false,
|
|
739
|
+
getCurrentDispatchedModelId: () => null,
|
|
740
|
+
},
|
|
741
|
+
);
|
|
742
|
+
|
|
743
|
+
assert.ok(holder.widget, "progress widget should be installed");
|
|
744
|
+
const widget = holder.widget;
|
|
745
|
+
const lines = widget.render(120);
|
|
746
|
+
const rendered = lines.join("\n");
|
|
747
|
+
|
|
748
|
+
assert.equal(lines.length, 4, `small widget should render as rule + two dense rows + rule:\n${rendered}`);
|
|
749
|
+
assert.match(rendered, /STATUS\s+.*AUTO\s+running/);
|
|
750
|
+
assert.match(rendered, /UNIT\s+M004\/S01\/T02/);
|
|
751
|
+
assert.match(rendered, /SPEND/);
|
|
752
|
+
assert.match(rendered, /TIME/);
|
|
753
|
+
assert.match(rendered, /PHASE\s+execute-task/);
|
|
754
|
+
assert.match(rendered, /WORK\s+T02: Backfill repeat m/);
|
|
755
|
+
assert.match(rendered, /TASK\s+2\/2/);
|
|
756
|
+
assert.match(rendered, /SLICE.*1\/2/);
|
|
757
|
+
assert.doesNotMatch(rendered, /\/gsd next|\/gsd status/);
|
|
758
|
+
assert.doesNotMatch(rendered, /dashboard|esc pause/);
|
|
759
|
+
|
|
760
|
+
for (const width of [40, 80, 120]) {
|
|
761
|
+
widget.invalidate();
|
|
762
|
+
assertLinesFit(widget.render(width), width);
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
|
|
636
766
|
test("updateProgressWidget shows provider-waiting state consistently for auto and next modes", (t) => {
|
|
637
767
|
const dir = makeTempDir("auto-next-dashboard");
|
|
638
768
|
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
@@ -691,14 +821,14 @@ test("updateProgressWidget shows provider-waiting state consistently for auto an
|
|
|
691
821
|
const autoRendered = renderDashboard(false);
|
|
692
822
|
const nextRendered = renderDashboard(true);
|
|
693
823
|
|
|
694
|
-
assert.match(autoRendered, /
|
|
695
|
-
assert.match(nextRendered, /
|
|
824
|
+
assert.match(autoRendered, /STATUS\s+.*AUTO\s+running/);
|
|
825
|
+
assert.match(nextRendered, /STATUS\s+.*NEXT\s+running/);
|
|
696
826
|
assert.doesNotMatch(autoRendered.split("\n")[1] ?? "", /completing M003\/S01/);
|
|
697
827
|
assert.doesNotMatch(nextRendered.split("\n")[1] ?? "", /completing M003\/S01/);
|
|
698
828
|
assert.doesNotMatch(autoRendered, /waiting on provider.*Waiting on provider/i);
|
|
699
829
|
assert.doesNotMatch(nextRendered, /waiting on provider.*Waiting on provider/i);
|
|
700
|
-
assert.match(autoRendered, /
|
|
701
|
-
assert.match(nextRendered, /
|
|
830
|
+
assert.match(autoRendered, /PHASE\s+complete-slice/);
|
|
831
|
+
assert.match(nextRendered, /PHASE\s+complete-slice/);
|
|
702
832
|
assert.doesNotMatch(autoRendered, /Working/);
|
|
703
833
|
assert.doesNotMatch(nextRendered, /Working/);
|
|
704
834
|
});
|
|
@@ -812,3 +942,25 @@ test("widget mode respects project preference precedence and persists there", (t
|
|
|
812
942
|
assert.match(projectPrefs, /widget_mode:\s*min/);
|
|
813
943
|
assert.match(globalPrefs, /widget_mode:\s*off/);
|
|
814
944
|
});
|
|
945
|
+
|
|
946
|
+
test("widget mode defaults to small when preferences do not set it", (t) => {
|
|
947
|
+
const homeDir = makeTempDir("home-no-widget-pref");
|
|
948
|
+
const projectDir = makeTempDir("project-no-widget-pref");
|
|
949
|
+
const globalPrefsPath = join(homeDir, ".gsd", "preferences.md");
|
|
950
|
+
const projectPrefsPath = join(projectDir, ".gsd", "preferences.md");
|
|
951
|
+
|
|
952
|
+
mkdirSync(join(homeDir, ".gsd"), { recursive: true });
|
|
953
|
+
mkdirSync(join(projectDir, ".gsd"), { recursive: true });
|
|
954
|
+
writeFileSync(globalPrefsPath, "---\nversion: 1\n---\n", "utf-8");
|
|
955
|
+
writeFileSync(projectPrefsPath, "---\nversion: 1\n---\n", "utf-8");
|
|
956
|
+
|
|
957
|
+
t.after(() => {
|
|
958
|
+
cleanup(homeDir);
|
|
959
|
+
cleanup(projectDir);
|
|
960
|
+
_resetWidgetModeForTests();
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
_resetWidgetModeForTests();
|
|
964
|
+
|
|
965
|
+
assert.equal(getWidgetMode(projectPrefsPath, globalPrefsPath), "small");
|
|
966
|
+
});
|
|
@@ -574,6 +574,43 @@ test("completeActiveUnit allows a different next unit to advance", async () => {
|
|
|
574
574
|
assert.deepEqual(second.unit, { unitType: "execute-task", unitId: "T02" });
|
|
575
575
|
});
|
|
576
576
|
|
|
577
|
+
test("completeActiveUnit guard survives an intervening advance and blocks X→Y→X re-dispatch", async () => {
|
|
578
|
+
// Regression test for issue #415: lastFinalizedUnitKey was wiped on every advance(),
|
|
579
|
+
// allowing completed units to be re-dispatched after any interleaving unit (X→Y→X).
|
|
580
|
+
let nextTaskId = "T01";
|
|
581
|
+
const { deps } = makeDeps({
|
|
582
|
+
dispatch: {
|
|
583
|
+
async decideNextUnit() {
|
|
584
|
+
return { unitType: "execute-task", unitId: nextTaskId, reason: "ready", preconditions: [] };
|
|
585
|
+
},
|
|
586
|
+
},
|
|
587
|
+
});
|
|
588
|
+
const orchestrator = createAutoOrchestrator(deps);
|
|
589
|
+
|
|
590
|
+
// Step 1: advance X (T01)
|
|
591
|
+
const first = await orchestrator.advance();
|
|
592
|
+
assert.equal(first.kind, "advanced");
|
|
593
|
+
if (first.kind !== "advanced") throw new Error("expected first advance");
|
|
594
|
+
|
|
595
|
+
// Step 2: complete X (T01) — sets lastFinalizedUnitKey = 'execute-task:T01'
|
|
596
|
+
await orchestrator.completeActiveUnit(first.unit);
|
|
597
|
+
|
|
598
|
+
// Step 3: advance Y (T02) — must NOT clear lastFinalizedUnitKey
|
|
599
|
+
nextTaskId = "T02";
|
|
600
|
+
const second = await orchestrator.advance();
|
|
601
|
+
assert.equal(second.kind, "advanced");
|
|
602
|
+
if (second.kind !== "advanced") throw new Error("expected second advance (T02)");
|
|
603
|
+
assert.deepEqual(second.unit, { unitType: "execute-task", unitId: "T02" });
|
|
604
|
+
|
|
605
|
+
// Step 4: re-select X (T01) — must be blocked because T01 was finalized
|
|
606
|
+
nextTaskId = "T01";
|
|
607
|
+
const third = await orchestrator.advance();
|
|
608
|
+
assert.equal(third.kind, "blocked");
|
|
609
|
+
if (third.kind !== "blocked") throw new Error("expected X→Y→X re-dispatch to be blocked");
|
|
610
|
+
assert.equal(third.action, "stop");
|
|
611
|
+
assert.equal(third.reason, "state did not advance after finalized execute-task T01");
|
|
612
|
+
});
|
|
613
|
+
|
|
577
614
|
test("retryActiveUnit clears in-flight idempotency without marking the unit finalized", async () => {
|
|
578
615
|
const { deps, calls } = makeDeps();
|
|
579
616
|
const orchestrator = createAutoOrchestrator(deps);
|
|
@@ -1246,6 +1283,92 @@ test("wired DispatchAdapter forwards constructor session when advance input omit
|
|
|
1246
1283
|
}
|
|
1247
1284
|
});
|
|
1248
1285
|
|
|
1286
|
+
test("wired DispatchAdapter adopts next active milestone after the session milestone is closed", async (t) => {
|
|
1287
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-orchestrator-milestone-adopt-"));
|
|
1288
|
+
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
1289
|
+
|
|
1290
|
+
const stateSnapshot: GSDState = {
|
|
1291
|
+
...makeState(),
|
|
1292
|
+
activeMilestone: { id: "M002", title: "Next" },
|
|
1293
|
+
registry: [
|
|
1294
|
+
{ id: "M001", title: "First", status: "complete" },
|
|
1295
|
+
{ id: "M002", title: "Next", status: "active" },
|
|
1296
|
+
],
|
|
1297
|
+
};
|
|
1298
|
+
const captured: DispatchContext[] = [];
|
|
1299
|
+
const captureRule: UnifiedRule = {
|
|
1300
|
+
name: "test-milestone-adoption",
|
|
1301
|
+
when: "dispatch",
|
|
1302
|
+
evaluation: "first-match",
|
|
1303
|
+
where: async (ctx: DispatchContext) => {
|
|
1304
|
+
captured.push(ctx);
|
|
1305
|
+
return {
|
|
1306
|
+
action: "dispatch" as const,
|
|
1307
|
+
unitType: "execute-task",
|
|
1308
|
+
unitId: "M002/S01/T01",
|
|
1309
|
+
prompt: "adopted-milestone-fixture",
|
|
1310
|
+
};
|
|
1311
|
+
},
|
|
1312
|
+
then: (r: unknown) => r,
|
|
1313
|
+
};
|
|
1314
|
+
setRegistry(new RuleRegistry([captureRule]));
|
|
1315
|
+
|
|
1316
|
+
try {
|
|
1317
|
+
const ctx = { model: {}, modelRegistry: { getAll: () => [] } } as any;
|
|
1318
|
+
const pi = { getActiveTools: () => [] } as any;
|
|
1319
|
+
const session = {
|
|
1320
|
+
basePath: base,
|
|
1321
|
+
originalBasePath: base,
|
|
1322
|
+
currentMilestoneId: "M001",
|
|
1323
|
+
} as any;
|
|
1324
|
+
const adapter = createWiredDispatchAdapter(ctx, pi, base, session);
|
|
1325
|
+
|
|
1326
|
+
const result = await adapter.decideNextUnit({ stateSnapshot });
|
|
1327
|
+
|
|
1328
|
+
assert.ok(result);
|
|
1329
|
+
if (!("unitType" in result)) assert.fail(`expected dispatch decision, got ${JSON.stringify(result)}`);
|
|
1330
|
+
assert.equal(result.unitId, "M002/S01/T01");
|
|
1331
|
+
assert.equal(session.currentMilestoneId, "M002");
|
|
1332
|
+
assert.equal(captured[0]?.session?.currentMilestoneId, "M002");
|
|
1333
|
+
} finally {
|
|
1334
|
+
resetRegistry();
|
|
1335
|
+
}
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
test("wired DispatchAdapter keeps blocking stale milestone worktree scope", async (t) => {
|
|
1339
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-orchestrator-worktree-block-"));
|
|
1340
|
+
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
1341
|
+
|
|
1342
|
+
const stateSnapshot: GSDState = {
|
|
1343
|
+
...makeState(),
|
|
1344
|
+
activeMilestone: { id: "M002", title: "Next" },
|
|
1345
|
+
registry: [
|
|
1346
|
+
{ id: "M001", title: "First", status: "complete" },
|
|
1347
|
+
{ id: "M002", title: "Next", status: "active" },
|
|
1348
|
+
],
|
|
1349
|
+
};
|
|
1350
|
+
const worktreePath = join(base, ".gsd", "worktrees", "M001");
|
|
1351
|
+
mkdirSync(worktreePath, { recursive: true });
|
|
1352
|
+
const ctx = { model: {}, modelRegistry: { getAll: () => [] } } as any;
|
|
1353
|
+
const pi = { getActiveTools: () => [] } as any;
|
|
1354
|
+
const session = {
|
|
1355
|
+
basePath: worktreePath,
|
|
1356
|
+
originalBasePath: base,
|
|
1357
|
+
currentMilestoneId: "M001",
|
|
1358
|
+
} as any;
|
|
1359
|
+
const adapter = createWiredDispatchAdapter(ctx, pi, base, session);
|
|
1360
|
+
|
|
1361
|
+
const result = await adapter.decideNextUnit({ stateSnapshot });
|
|
1362
|
+
|
|
1363
|
+
assert.deepEqual(result, {
|
|
1364
|
+
kind: "blocked",
|
|
1365
|
+
reason:
|
|
1366
|
+
'Dispatch milestone mismatch: context mid "M002" does not match session.currentMilestoneId "M001". The active worktree/session and derived project state disagree; recover, park, or discard the stranded milestone before continuing.',
|
|
1367
|
+
action: "pause",
|
|
1368
|
+
});
|
|
1369
|
+
assert.equal(session.currentMilestoneId, "M001");
|
|
1370
|
+
});
|
|
1371
|
+
|
|
1249
1372
|
test("wired DispatchAdapter replays pending verification retry dispatch", async () => {
|
|
1250
1373
|
const stateSnapshot = makeState();
|
|
1251
1374
|
const ctx = { model: {}, modelRegistry: { getAll: () => [] } } as any;
|