@opengsd/gsd-pi 1.1.1-dev.74e8dd1 → 1.1.1-dev.a5a2de8
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/gsd/auto/orchestrator.js +0 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +77 -13
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +21 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +63 -22
- package/dist/resources/extensions/gsd/auto-recovery.js +3 -4
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +18 -66
- package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
- package/dist/resources/extensions/gsd/auto.js +9 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +20 -14
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +28 -13
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +18 -29
- 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/handlers/ops.js +2 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
- package/dist/resources/extensions/gsd/commands-mcp-status.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/escalation.js +4 -4
- package/dist/resources/extensions/gsd/forensics.js +74 -2
- package/dist/resources/extensions/gsd/gsd-db.js +5 -2
- package/dist/resources/extensions/gsd/guided-flow.js +118 -175
- package/dist/resources/extensions/gsd/mcp-project-config.js +9 -76
- package/dist/resources/extensions/gsd/memory-store.js +4 -1
- 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 +25 -21
- 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/state.js +2 -2
- 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 +17 -7
- 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/validate-milestone.js +46 -16
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +132 -18
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -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.js +3 -75
- 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 +7 -7
- 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 +7 -7
- 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 +4 -2
- package/packages/cloud-mcp-gateway/package.json +2 -2
- 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/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.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +20 -0
- 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/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.js +2 -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/models.generated.d.ts +74 -6
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +78 -10
- 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/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/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/gsd/auto/orchestrator.ts +0 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +82 -14
- package/src/resources/extensions/gsd/auto-dispatch.ts +19 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +28 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +97 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +3 -3
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -74
- package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
- package/src/resources/extensions/gsd/auto.ts +12 -2
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +20 -14
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +32 -13
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +50 -54
- 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/handlers/ops.ts +2 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
- package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -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/escalation.ts +4 -4
- package/src/resources/extensions/gsd/forensics.ts +99 -5
- package/src/resources/extensions/gsd/gsd-db.ts +5 -2
- package/src/resources/extensions/gsd/guided-flow.ts +214 -216
- package/src/resources/extensions/gsd/mcp-project-config.ts +13 -78
- package/src/resources/extensions/gsd/memory-store.ts +4 -1
- 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-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 +25 -21
- 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/state.ts +2 -2
- package/src/resources/extensions/gsd/templates/plan.md +3 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +105 -4
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +37 -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-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/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/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/doctor-runtime-checks.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
- 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/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 +69 -10
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +2 -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/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/plan-slice-prompt.test.ts +9 -0
- 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 +61 -1
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +44 -0
- 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/state-reconciliation-drift.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
- 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/verification-gate.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +351 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -0
- package/src/resources/extensions/gsd/tool-contract.ts +6 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +38 -8
- 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/validate-milestone.ts +46 -15
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +163 -20
- package/src/resources/extensions/gsd/types.ts +69 -5
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -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.ts +3 -75
- 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/{eRWf-RI9bzbrwEurm_3uI → 9y3LeeR2uGr2yRj9RjY3D}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → 9y3LeeR2uGr2yRj9RjY3D}/_ssgManifest.js +0 -0
|
@@ -115,15 +115,10 @@ async function runQuickTaskChoice(ctx, pi) {
|
|
|
115
115
|
}
|
|
116
116
|
async function dispatchDiscussForNextMilestoneWithBacklog(ctx, pi, basePath, nextId) {
|
|
117
117
|
const backlogContext = buildRequirementsBacklogDiscussContext(nextId);
|
|
118
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
119
118
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
120
|
-
const basePrompt =
|
|
121
|
-
workingDirectory: basePath,
|
|
122
|
-
milestoneId: nextId,
|
|
123
|
-
milestoneTitle: `New milestone ${nextId}`,
|
|
124
|
-
inlinedTemplates: discussMilestoneTemplates,
|
|
125
|
-
structuredQuestionsAvailable,
|
|
119
|
+
const basePrompt = await buildDiscussMilestonePrompt(nextId, `New milestone ${nextId}`, basePath, structuredQuestionsAvailable, {
|
|
126
120
|
commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): milestone context from discuss`),
|
|
121
|
+
includeContextMode: false,
|
|
127
122
|
fastPathInstruction: [
|
|
128
123
|
"> **Requirements backlog active.**",
|
|
129
124
|
"> Map unmapped active requirements to this milestone before finalizing context.",
|
|
@@ -183,6 +178,84 @@ export function _roadmapHasParseableSlicesForTest(roadmapContent) {
|
|
|
183
178
|
return false;
|
|
184
179
|
return parseRoadmapSlices(roadmapContent).length > 0;
|
|
185
180
|
}
|
|
181
|
+
function hasExecutablePlanForHandoff(milestoneId, roadmapFile) {
|
|
182
|
+
if (isDbAvailable()) {
|
|
183
|
+
return getMilestoneSlices(milestoneId).length > 0;
|
|
184
|
+
}
|
|
185
|
+
if (!roadmapFile)
|
|
186
|
+
return false;
|
|
187
|
+
try {
|
|
188
|
+
return parseRoadmapSlices(readFileSync(roadmapFile, "utf-8")).length > 0;
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
logWarning("guided", `failed to parse roadmap slices for ${milestoneId}: ${e.message}`);
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function formatAcceptedDiscussHandoffMessage(milestoneId, contextFile, hasExecutablePlan) {
|
|
196
|
+
if (hasExecutablePlan)
|
|
197
|
+
return `Milestone ${milestoneId} ready.`;
|
|
198
|
+
if (contextFile)
|
|
199
|
+
return `Milestone ${milestoneId} context captured. Continuing the planning pipeline.`;
|
|
200
|
+
return `Milestone ${milestoneId} planning artifacts captured. Continuing the planning pipeline.`;
|
|
201
|
+
}
|
|
202
|
+
function manifestContainsMilestone(basePath, milestoneId) {
|
|
203
|
+
try {
|
|
204
|
+
const manifest = readManifest(basePath);
|
|
205
|
+
return (Array.isArray(manifest?.milestones) &&
|
|
206
|
+
manifest.milestones.some(m => m.id === milestoneId));
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
logWarning("guided", `R3b: failed to read state manifest: ${e.message}`);
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function notifyDbRowRecoveryFailed(entry) {
|
|
214
|
+
entry.ctx.ui.notify(`Milestone ${entry.milestoneId}: DB row recovery failed ${entry.r3bRecoveryCount} times. ` +
|
|
215
|
+
`Re-run /gsd to reset the recovery counter, or run /gsd-debug to diagnose without resetting.`, "error");
|
|
216
|
+
}
|
|
217
|
+
function noteDbRowRecoveryMiss(entry) {
|
|
218
|
+
entry.r3bRecoveryCount += 1;
|
|
219
|
+
if (entry.r3bRecoveryCount >= MAX_DB_ROW_RECOVERIES) {
|
|
220
|
+
notifyDbRowRecoveryFailed(entry);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function ensureMilestoneRowForAcceptedHandoff(entry, contextFile) {
|
|
224
|
+
if (!isDbAvailable())
|
|
225
|
+
return true;
|
|
226
|
+
const { basePath, milestoneId } = entry;
|
|
227
|
+
const milestoneRow = getMilestone(milestoneId);
|
|
228
|
+
if (milestoneRow)
|
|
229
|
+
return true;
|
|
230
|
+
if (manifestContainsMilestone(basePath, milestoneId)) {
|
|
231
|
+
logWarning("guided", `R3b: getMilestone(${milestoneId}) returned null but manifest has the row — treating as stale read`);
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
if (!contextFile) {
|
|
235
|
+
entry.ctx.ui.notify(`Milestone ${milestoneId}: discuss artifacts on disk but no DB row exists. ` +
|
|
236
|
+
`PROJECT.md may have failed to register milestones. ` +
|
|
237
|
+
`Re-save PROJECT.md with canonical "- [ ] M001: Title — One-liner" lines, ` +
|
|
238
|
+
`then re-run /gsd to recover.`, "error");
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
if (entry.r3bRecoveryCount >= MAX_DB_ROW_RECOVERIES) {
|
|
242
|
+
logWarning("guided", `R3b: milestone ${milestoneId} DB-row recovery limit reached ` +
|
|
243
|
+
`(${entry.r3bRecoveryCount}/${MAX_DB_ROW_RECOVERIES}); user already notified`);
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
logWarning("guided", `R3b: ${milestoneId} has CONTEXT.md but no DB row — inserting placeholder "queued" row ` +
|
|
247
|
+
`(attempt ${entry.r3bRecoveryCount + 1}/${MAX_DB_ROW_RECOVERIES})`);
|
|
248
|
+
try {
|
|
249
|
+
insertMilestone({ id: milestoneId, title: milestoneId, status: "queued" });
|
|
250
|
+
}
|
|
251
|
+
catch (e) {
|
|
252
|
+
logWarning("guided", `R3b: insertMilestone failed: ${e.message}`);
|
|
253
|
+
}
|
|
254
|
+
if (getMilestone(milestoneId))
|
|
255
|
+
return true;
|
|
256
|
+
noteDbRowRecoveryMiss(entry);
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
186
259
|
// ─── Commit Instruction Helpers ──────────────────────────────────────────────
|
|
187
260
|
/** Build commit instruction for planning prompts. .gsd/ is managed externally and always gitignored. */
|
|
188
261
|
function buildDocsCommitInstruction(_message) {
|
|
@@ -191,10 +264,8 @@ function buildDocsCommitInstruction(_message) {
|
|
|
191
264
|
// #4573: cap for how many times we nudge the LLM after a premature ready
|
|
192
265
|
// phrase before giving up and asking the user to re-run /gsd.
|
|
193
266
|
const MAX_READY_REJECTS = 2;
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
// to investigate manually.
|
|
197
|
-
const MAX_PLAN_BLOCKED_RECOVERIES = 3;
|
|
267
|
+
// Cap failed in-flight DB row repair attempts before escalating to the user.
|
|
268
|
+
const MAX_DB_ROW_RECOVERIES = 3;
|
|
198
269
|
// #4573: matches the canonical ready phrase the discuss prompt asks the LLM
|
|
199
270
|
// to emit. Accepts any M-prefixed milestone ID (three digits + optional
|
|
200
271
|
// suffix) with optional trailing punctuation.
|
|
@@ -425,56 +496,12 @@ export function checkAutoStartAfterDiscuss(lookupBasePath) {
|
|
|
425
496
|
return false;
|
|
426
497
|
}
|
|
427
498
|
}
|
|
428
|
-
// Gate 1b:
|
|
429
|
-
//
|
|
430
|
-
//
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
//
|
|
434
|
-
if (isDbAvailable()) {
|
|
435
|
-
const dbRow = getMilestone(milestoneId);
|
|
436
|
-
if (dbRow?.status === "queued" && contextFile) {
|
|
437
|
-
if (entry.planBlockedRecoveryCount >= MAX_PLAN_BLOCKED_RECOVERIES) {
|
|
438
|
-
// H1: recovery loop cap reached — stop triggering new turns, escalate to user.
|
|
439
|
-
logWarning("guided", `Gate 1b: milestone ${milestoneId} plan-blocked recovery limit reached ` +
|
|
440
|
-
`(${entry.planBlockedRecoveryCount}/${MAX_PLAN_BLOCKED_RECOVERIES}); escalating to user`);
|
|
441
|
-
ctx.ui.notify(`Milestone ${milestoneId} plan_milestone has been blocked ${entry.planBlockedRecoveryCount} times. ` +
|
|
442
|
-
`Re-run /gsd to reset the recovery counter, or run /gsd-debug to diagnose without resetting.`, "error");
|
|
443
|
-
return false;
|
|
444
|
-
}
|
|
445
|
-
logWarning("guided", `Gate 1b: milestone ${milestoneId} queued with CONTEXT.md present — ` +
|
|
446
|
-
`plan_milestone was blocked; emitting recovery hint ` +
|
|
447
|
-
`(attempt ${entry.planBlockedRecoveryCount + 1}/${MAX_PLAN_BLOCKED_RECOVERIES})`);
|
|
448
|
-
ctx.ui.notify(`Milestone ${milestoneId}: context file exists but milestone is still queued. ` +
|
|
449
|
-
`Retrying gsd_plan_milestone to complete the blocked planning step.`, "warning");
|
|
450
|
-
try {
|
|
451
|
-
pi.sendMessage({
|
|
452
|
-
customType: "gsd-plan-milestone-blocked-recovery",
|
|
453
|
-
content: `Milestone ${milestoneId} has ${contextFile} on disk but its DB row is still ` +
|
|
454
|
-
`"queued". The gsd_plan_milestone tool was previously blocked by the ` +
|
|
455
|
-
`depth-verification gate. Call gsd_plan_milestone now to complete the ` +
|
|
456
|
-
`planning phase.`,
|
|
457
|
-
display: false,
|
|
458
|
-
}, { triggerTurn: true });
|
|
459
|
-
// Increment only after a successful dispatch so transient sendMessage
|
|
460
|
-
// failures do not consume recovery budget.
|
|
461
|
-
entry.planBlockedRecoveryCount += 1;
|
|
462
|
-
}
|
|
463
|
-
catch (e) {
|
|
464
|
-
logWarning("guided", `Gate 1b recovery sendMessage failed: ${e.message}`);
|
|
465
|
-
}
|
|
466
|
-
return false;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
// Gate 2: STATE.md must exist — written as the last step in the discuss
|
|
470
|
-
// output phase. This prevents auto-start from firing during Phase 3
|
|
471
|
-
// (sequential readiness gates for remaining milestones) in multi-milestone
|
|
472
|
-
// discussions, where M001-CONTEXT.md exists but M002/M003 haven't been
|
|
473
|
-
// processed yet.
|
|
474
|
-
const stateFilePath = entry.scope.stateFile();
|
|
475
|
-
if (!existsSync(stateFilePath))
|
|
476
|
-
return false; // discussion not finalized yet
|
|
477
|
-
// Gate 3: Multi-milestone completeness warning
|
|
499
|
+
// Gate 1b: accept the in-flight discuss handoff. A queued DB row with pinned
|
|
500
|
+
// CONTEXT.md is Discussion Complete, Planning Pending, not a plan-blocked
|
|
501
|
+
// failure. If the row is missing, only this pending handoff may repair it.
|
|
502
|
+
if (!ensureMilestoneRowForAcceptedHandoff(entry, contextFile))
|
|
503
|
+
return false;
|
|
504
|
+
// Gate 2: Multi-milestone completeness warning
|
|
478
505
|
// Parse PROJECT.md for milestone sequence, warn if any are missing context.
|
|
479
506
|
// Don't block — milestones can be intentionally queued without context.
|
|
480
507
|
const projectFile = resolveGsdRootFile(basePath, "PROJECT");
|
|
@@ -500,7 +527,7 @@ export function checkAutoStartAfterDiscuss(lookupBasePath) {
|
|
|
500
527
|
logWarning("guided", `PROJECT.md parsing failed: ${e.message}`);
|
|
501
528
|
}
|
|
502
529
|
}
|
|
503
|
-
// Gate
|
|
530
|
+
// Gate 3: Discussion manifest process verification (multi-milestone only)
|
|
504
531
|
// The LLM writes DISCUSSION-MANIFEST.json after each Phase 3 gate decision.
|
|
505
532
|
// When it exists, validate it before auto-starting. Project history alone is
|
|
506
533
|
// not a reliable signal for the current discussion mode.
|
|
@@ -546,59 +573,9 @@ export function checkAutoStartAfterDiscuss(lookupBasePath) {
|
|
|
546
573
|
logWarning("guided", `manifest unlink failed: ${e.message}`);
|
|
547
574
|
}
|
|
548
575
|
}
|
|
549
|
-
// R3b: belt-and-suspenders for silent registration failure. The discuss flow
|
|
550
|
-
// finished and STATE.md exists, but the milestone may never have landed in
|
|
551
|
-
// the DB. Without this guard, the user sees "Milestone M001 ready." and then
|
|
552
|
-
// /gsd reports "No Active Milestone".
|
|
553
|
-
if (isDbAvailable()) {
|
|
554
|
-
const milestoneRow = getMilestone(milestoneId);
|
|
555
|
-
if (!milestoneRow) {
|
|
556
|
-
let manifestHasMilestone = false;
|
|
557
|
-
try {
|
|
558
|
-
const manifest = readManifest(basePath);
|
|
559
|
-
manifestHasMilestone = Array.isArray(manifest?.milestones) && manifest.milestones.some(m => m.id === milestoneId);
|
|
560
|
-
}
|
|
561
|
-
catch (e) {
|
|
562
|
-
logWarning("guided", `R3b: failed to read state manifest: ${e.message}`);
|
|
563
|
-
}
|
|
564
|
-
if (manifestHasMilestone) {
|
|
565
|
-
logWarning("guided", `R3b: getMilestone(${milestoneId}) returned null but manifest has the row — treating as stale read`);
|
|
566
|
-
}
|
|
567
|
-
else if (contextFile) {
|
|
568
|
-
// R3b-recovery: CONTEXT.md is on disk but gsd_plan_milestone was never called
|
|
569
|
-
// (likely blocked by the depth-verification gate re-firing on post-verification
|
|
570
|
-
// text). Auto-register as "queued" so Gate 1b can pick it up and retry
|
|
571
|
-
// gsd_plan_milestone on the next checkAutoStartAfterDiscuss call.
|
|
572
|
-
if (entry.r3bRecoveryCount >= MAX_PLAN_BLOCKED_RECOVERIES) {
|
|
573
|
-
logWarning("guided", `R3b: milestone ${milestoneId} DB-row recovery limit reached ` +
|
|
574
|
-
`(${entry.r3bRecoveryCount}/${MAX_PLAN_BLOCKED_RECOVERIES}); escalating to user`);
|
|
575
|
-
ctx.ui.notify(`Milestone ${milestoneId}: DB row recovery failed ${entry.r3bRecoveryCount} times. ` +
|
|
576
|
-
`Re-run /gsd to reset the recovery counter, or run /gsd-debug to diagnose without resetting.`, "error");
|
|
577
|
-
return false;
|
|
578
|
-
}
|
|
579
|
-
logWarning("guided", `R3b: ${milestoneId} has CONTEXT.md but no DB row — inserting placeholder "queued" row ` +
|
|
580
|
-
`for Gate 1b recovery (attempt ${entry.r3bRecoveryCount + 1}/${MAX_PLAN_BLOCKED_RECOVERIES})`);
|
|
581
|
-
try {
|
|
582
|
-
insertMilestone({ id: milestoneId, title: milestoneId, status: "queued" });
|
|
583
|
-
}
|
|
584
|
-
catch (e) {
|
|
585
|
-
logWarning("guided", `R3b: insertMilestone failed: ${e.message}`);
|
|
586
|
-
}
|
|
587
|
-
entry.r3bRecoveryCount += 1;
|
|
588
|
-
ctx.ui.notify(`Milestone ${milestoneId}: context file exists but DB row was missing — recovering. Retrying gsd_plan_milestone.`, "warning");
|
|
589
|
-
return false;
|
|
590
|
-
}
|
|
591
|
-
else {
|
|
592
|
-
ctx.ui.notify(`Milestone ${milestoneId}: discuss artifacts on disk but no DB row exists. ` +
|
|
593
|
-
`PROJECT.md may have failed to register milestones. ` +
|
|
594
|
-
`Re-save PROJECT.md with canonical "- [ ] M001: Title — One-liner" lines, ` +
|
|
595
|
-
`then re-run /gsd to recover.`, "error");
|
|
596
|
-
return false;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
576
|
deletePendingAutoStart(basePath);
|
|
601
|
-
|
|
577
|
+
const hasExecutablePlan = hasExecutablePlanForHandoff(milestoneId, roadmapFile);
|
|
578
|
+
ctx.ui.notify(formatAcceptedDiscussHandoffMessage(milestoneId, contextFile, hasExecutablePlan), "success");
|
|
602
579
|
if (entry.startAuto !== false) {
|
|
603
580
|
scheduleAutoStartAfterIdle(ctx, pi, basePath, false, { step: step ?? true });
|
|
604
581
|
}
|
|
@@ -1054,7 +1031,7 @@ function buildHeadlessDiscussPrompt(nextId, seedContext, _basePath) {
|
|
|
1054
1031
|
* @param basePath - Root directory of the project
|
|
1055
1032
|
* @returns The discuss prompt string
|
|
1056
1033
|
*/
|
|
1057
|
-
async function buildDiscussPreparationContext(ctx, basePath, mode = "greenfield") {
|
|
1034
|
+
async function buildDiscussPreparationContext(ctx, basePath, mode = "greenfield", skipPriorContext = false) {
|
|
1058
1035
|
const prefs = loadEffectiveGSDPreferences()?.preferences ?? {};
|
|
1059
1036
|
if (prefs.discuss_preparation === false)
|
|
1060
1037
|
return "";
|
|
@@ -1071,7 +1048,7 @@ async function buildDiscussPreparationContext(ctx, basePath, mode = "greenfield"
|
|
|
1071
1048
|
const parts = [];
|
|
1072
1049
|
if (codebaseBrief)
|
|
1073
1050
|
parts.push(`### Codebase Brief\n\n${codebaseBrief}`);
|
|
1074
|
-
if (priorContextBrief)
|
|
1051
|
+
if (priorContextBrief && !skipPriorContext)
|
|
1075
1052
|
parts.push(`### Prior Context Brief\n\n${priorContextBrief}`);
|
|
1076
1053
|
if (parts.length === 0)
|
|
1077
1054
|
return "";
|
|
@@ -1103,17 +1080,11 @@ async function dispatchNewMilestoneDiscuss(ctx, pi, basePath, nextId, stepMode,
|
|
|
1103
1080
|
await dispatchWorkflow(pi, prompt, "gsd-run", ctx, "discuss-milestone", { basePath });
|
|
1104
1081
|
return;
|
|
1105
1082
|
}
|
|
1106
|
-
const preparationContext = await buildDiscussPreparationContext(ctx, basePath, "milestone");
|
|
1107
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1083
|
+
const preparationContext = await buildDiscussPreparationContext(ctx, basePath, "milestone", true);
|
|
1108
1084
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1109
|
-
let prompt =
|
|
1110
|
-
workingDirectory: basePath,
|
|
1111
|
-
milestoneId: nextId,
|
|
1112
|
-
milestoneTitle: `New milestone ${nextId}`,
|
|
1113
|
-
inlinedTemplates: discussMilestoneTemplates,
|
|
1114
|
-
structuredQuestionsAvailable,
|
|
1085
|
+
let prompt = await buildDiscussMilestonePrompt(nextId, `New milestone ${nextId}`, basePath, structuredQuestionsAvailable, {
|
|
1115
1086
|
commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): milestone context from discuss`),
|
|
1116
|
-
|
|
1087
|
+
includeContextMode: false,
|
|
1117
1088
|
});
|
|
1118
1089
|
if (preparationContext)
|
|
1119
1090
|
prompt += preparationContext;
|
|
@@ -1364,8 +1335,6 @@ export async function showDiscuss(ctx, pi, basePath, options) {
|
|
|
1364
1335
|
// Special case: milestone is in needs-discussion phase (has CONTEXT-DRAFT.md but no roadmap yet).
|
|
1365
1336
|
// Route to the draft discussion flow instead of erroring — the discussion IS how the roadmap gets created.
|
|
1366
1337
|
if (state.phase === "needs-discussion") {
|
|
1367
|
-
const draftFile = resolveMilestoneFile(basePath, mid, "CONTEXT-DRAFT");
|
|
1368
|
-
const draftContent = draftFile ? await loadFile(draftFile) : null;
|
|
1369
1338
|
const choice = await showNextAction(ctx, {
|
|
1370
1339
|
title: `GSD — ${mid}: ${milestoneTitle}`,
|
|
1371
1340
|
summary: ["This milestone has a draft context from a prior discussion.", "It needs a dedicated discussion before auto-planning can begin."],
|
|
@@ -1390,30 +1359,23 @@ export async function showDiscuss(ctx, pi, basePath, options) {
|
|
|
1390
1359
|
notYetMessage: "Run /gsd discuss when ready to discuss this milestone.",
|
|
1391
1360
|
});
|
|
1392
1361
|
if (choice === "discuss_draft") {
|
|
1393
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1394
1362
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1395
|
-
const
|
|
1396
|
-
workingDirectory: basePath,
|
|
1397
|
-
milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
1363
|
+
const seed = await buildDiscussMilestonePrompt(mid, milestoneTitle, basePath, structuredQuestionsAvailable, {
|
|
1398
1364
|
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
1399
|
-
|
|
1365
|
+
includeContextMode: false,
|
|
1400
1366
|
});
|
|
1401
|
-
const seed = draftContent
|
|
1402
|
-
? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
|
|
1403
|
-
: basePrompt;
|
|
1404
1367
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: mid, step: true });
|
|
1405
1368
|
await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
1406
1369
|
}
|
|
1407
1370
|
else if (choice === "discuss_fresh") {
|
|
1408
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1409
1371
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1410
|
-
|
|
1411
|
-
await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
|
|
1412
|
-
workingDirectory: basePath,
|
|
1413
|
-
milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
1372
|
+
const prompt = await buildDiscussMilestonePrompt(mid, milestoneTitle, basePath, structuredQuestionsAvailable, {
|
|
1414
1373
|
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
1415
|
-
|
|
1416
|
-
|
|
1374
|
+
includeContextMode: false,
|
|
1375
|
+
includeDraftSeed: false,
|
|
1376
|
+
});
|
|
1377
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: mid, step: true });
|
|
1378
|
+
await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
1417
1379
|
}
|
|
1418
1380
|
else if (choice === "skip_milestone") {
|
|
1419
1381
|
const { ensureDbOpen } = await import("./bootstrap/dynamic-tools.js");
|
|
@@ -1631,20 +1593,12 @@ async function dispatchDiscussForMilestone(ctx, pi, basePath, mid, milestoneTitl
|
|
|
1631
1593
|
"> Ask only questions where the answer would materially change scope.",
|
|
1632
1594
|
].join("\n")
|
|
1633
1595
|
: "";
|
|
1634
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1635
1596
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1636
|
-
const
|
|
1637
|
-
workingDirectory: basePath,
|
|
1638
|
-
milestoneId: mid,
|
|
1639
|
-
milestoneTitle,
|
|
1640
|
-
inlinedTemplates: discussMilestoneTemplates,
|
|
1641
|
-
structuredQuestionsAvailable,
|
|
1597
|
+
const prompt = await buildDiscussMilestonePrompt(mid, milestoneTitle, basePath, structuredQuestionsAvailable, {
|
|
1642
1598
|
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
1599
|
+
includeContextMode: false,
|
|
1643
1600
|
fastPathInstruction,
|
|
1644
1601
|
});
|
|
1645
|
-
const prompt = draftContent
|
|
1646
|
-
? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
|
|
1647
|
-
: basePrompt;
|
|
1648
1602
|
await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
1649
1603
|
}
|
|
1650
1604
|
// ─── Smart Entry Point ────────────────────────────────────────────────────────
|
|
@@ -2122,8 +2076,6 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
2122
2076
|
}
|
|
2123
2077
|
// ── Draft milestone — needs discussion before planning ────────────────
|
|
2124
2078
|
if (state.phase === "needs-discussion") {
|
|
2125
|
-
const draftFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT-DRAFT");
|
|
2126
|
-
const draftContent = draftFile ? await loadFile(draftFile) : null;
|
|
2127
2079
|
const choice = await showNextAction(ctx, {
|
|
2128
2080
|
title: `GSD — ${milestoneId}: ${milestoneTitle}`,
|
|
2129
2081
|
summary: ["This milestone has a draft context from a prior discussion.", "It needs a dedicated discussion before auto-planning can begin."],
|
|
@@ -2148,30 +2100,23 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
2148
2100
|
notYetMessage: "Run /gsd when ready to discuss this milestone.",
|
|
2149
2101
|
});
|
|
2150
2102
|
if (choice === "discuss_draft") {
|
|
2151
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2152
2103
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2153
|
-
const
|
|
2154
|
-
workingDirectory: basePath,
|
|
2155
|
-
milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
2104
|
+
const seed = await buildDiscussMilestonePrompt(milestoneId, milestoneTitle, basePath, structuredQuestionsAvailable, {
|
|
2156
2105
|
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2157
|
-
|
|
2106
|
+
includeContextMode: false,
|
|
2158
2107
|
});
|
|
2159
|
-
const seed = draftContent
|
|
2160
|
-
? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
|
|
2161
|
-
: basePrompt;
|
|
2162
2108
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
2163
2109
|
await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
2164
2110
|
}
|
|
2165
2111
|
else if (choice === "discuss_fresh") {
|
|
2166
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2167
2112
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2168
|
-
|
|
2169
|
-
await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
|
|
2170
|
-
workingDirectory: basePath,
|
|
2171
|
-
milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
2113
|
+
const prompt = await buildDiscussMilestonePrompt(milestoneId, milestoneTitle, basePath, structuredQuestionsAvailable, {
|
|
2172
2114
|
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2173
|
-
|
|
2174
|
-
|
|
2115
|
+
includeContextMode: false,
|
|
2116
|
+
includeDraftSeed: false,
|
|
2117
|
+
});
|
|
2118
|
+
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
2119
|
+
await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
2175
2120
|
}
|
|
2176
2121
|
else if (choice === "skip_milestone") {
|
|
2177
2122
|
const milestoneIds = findMilestoneIds(basePath);
|
|
@@ -2279,14 +2224,12 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
2279
2224
|
await dispatchWorkflow(pi, await buildPlanMilestonePrompt(milestoneId, milestoneTitle, basePath), "gsd-run", ctx, "plan-milestone", { basePath });
|
|
2280
2225
|
}
|
|
2281
2226
|
else if (choice === "discuss") {
|
|
2282
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2283
2227
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2284
|
-
await
|
|
2285
|
-
workingDirectory: basePath,
|
|
2286
|
-
milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
2228
|
+
const prompt = await buildDiscussMilestonePrompt(milestoneId, milestoneTitle, basePath, structuredQuestionsAvailable, {
|
|
2287
2229
|
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2288
|
-
|
|
2289
|
-
})
|
|
2230
|
+
includeContextMode: false,
|
|
2231
|
+
});
|
|
2232
|
+
await dispatchWorkflow(pi, prompt, "gsd-run", ctx, "discuss-milestone", { basePath });
|
|
2290
2233
|
}
|
|
2291
2234
|
else if (choice === "skip_milestone") {
|
|
2292
2235
|
const milestoneIds = findMilestoneIds(basePath);
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
-
import {
|
|
4
|
-
import { basename, resolve } from "node:path";
|
|
2
|
+
import { resolve } from "node:path";
|
|
5
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { GSD_BROWSER_MCP_SERVER_NAME, resolveBundledGsdBrowserCliPath, resolveGsdBrowserMcpLaunchConfig, } from "../shared/gsd-browser-cli.js";
|
|
6
5
|
import { assertSafeDirectory } from "./validate-directory.js";
|
|
7
6
|
import { detectWorkflowMcpLaunchConfig } from "./workflow-mcp.js";
|
|
8
7
|
export const GSD_WORKFLOW_MCP_SERVER_NAME = "gsd-workflow";
|
|
9
|
-
export
|
|
8
|
+
export { GSD_BROWSER_MCP_SERVER_NAME, resolveBundledGsdBrowserCliPath };
|
|
10
9
|
export function resolveBundledGsdCliPath(env = process.env) {
|
|
11
10
|
const explicit = env.GSD_CLI_PATH?.trim() || env.GSD_BIN_PATH?.trim();
|
|
12
11
|
if (explicit)
|
|
@@ -22,30 +21,6 @@ export function resolveBundledGsdCliPath(env = process.env) {
|
|
|
22
21
|
}
|
|
23
22
|
return null;
|
|
24
23
|
}
|
|
25
|
-
export function resolveBundledGsdBrowserCliPath(env = process.env) {
|
|
26
|
-
const explicit = env.GSD_BROWSER_CLI_PATH?.trim() || env.GSD_BROWSER_BIN_PATH?.trim();
|
|
27
|
-
if (explicit)
|
|
28
|
-
return explicit;
|
|
29
|
-
try {
|
|
30
|
-
const requireFromHere = createRequire(import.meta.url);
|
|
31
|
-
const packageJsonPath = requireFromHere.resolve("@opengsd/gsd-browser/package.json");
|
|
32
|
-
const candidate = resolve(packageJsonPath, "..", "bin", "gsd-browser");
|
|
33
|
-
if (existsSync(candidate))
|
|
34
|
-
return candidate;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
// Fall through to path candidates for source/dist layouts.
|
|
38
|
-
}
|
|
39
|
-
const candidates = [
|
|
40
|
-
resolve(fileURLToPath(new URL("../../../../node_modules/@opengsd/gsd-browser/bin/gsd-browser", import.meta.url))),
|
|
41
|
-
resolve(fileURLToPath(new URL("../../../../node_modules/.bin/gsd-browser", import.meta.url))),
|
|
42
|
-
];
|
|
43
|
-
for (const candidate of candidates) {
|
|
44
|
-
if (existsSync(candidate))
|
|
45
|
-
return candidate;
|
|
46
|
-
}
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
24
|
export function buildProjectWorkflowMcpServerConfig(projectRoot, env = process.env) {
|
|
50
25
|
return buildProjectWorkflowMcpServerSpec(projectRoot, env).server;
|
|
51
26
|
}
|
|
@@ -69,68 +44,26 @@ function buildProjectWorkflowMcpServerSpec(projectRoot, env = process.env) {
|
|
|
69
44
|
},
|
|
70
45
|
};
|
|
71
46
|
}
|
|
72
|
-
function parseJsonEnv(env, name) {
|
|
73
|
-
const raw = env[name];
|
|
74
|
-
if (!raw)
|
|
75
|
-
return undefined;
|
|
76
|
-
try {
|
|
77
|
-
return JSON.parse(raw);
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
throw new Error(`Invalid JSON in ${name}`);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
47
|
function isEnvDisabled(value) {
|
|
84
48
|
if (!value)
|
|
85
49
|
return false;
|
|
86
50
|
const normalized = value.trim().toLowerCase();
|
|
87
51
|
return normalized === "0" || normalized === "false" || normalized === "off";
|
|
88
52
|
}
|
|
89
|
-
function buildBrowserSessionName(projectRoot) {
|
|
90
|
-
const resolvedProjectRoot = resolve(projectRoot);
|
|
91
|
-
const base = basename(resolvedProjectRoot)
|
|
92
|
-
.replace(/[^a-zA-Z0-9._-]+/g, "-")
|
|
93
|
-
.replace(/^-+|-+$/g, "") || "project";
|
|
94
|
-
const hash = createHash("sha1").update(resolvedProjectRoot).digest("hex").slice(0, 8);
|
|
95
|
-
return `gsd-${base}-${hash}`;
|
|
96
|
-
}
|
|
97
53
|
export function buildProjectBrowserMcpServerConfig(projectRoot, env = process.env) {
|
|
98
54
|
return buildProjectBrowserMcpServerSpec(projectRoot, env)?.server ?? null;
|
|
99
55
|
}
|
|
100
56
|
function buildProjectBrowserMcpServerSpec(projectRoot, env = process.env) {
|
|
101
57
|
if (isEnvDisabled(env.GSD_BROWSER_MCP_ENABLED))
|
|
102
58
|
return null;
|
|
103
|
-
const
|
|
104
|
-
const serverName = env.GSD_BROWSER_MCP_NAME?.trim() || GSD_BROWSER_MCP_SERVER_NAME;
|
|
105
|
-
const explicitArgs = parseJsonEnv(env, "GSD_BROWSER_MCP_ARGS");
|
|
106
|
-
const explicitEnv = parseJsonEnv(env, "GSD_BROWSER_MCP_ENV");
|
|
107
|
-
const explicitCommand = env.GSD_BROWSER_MCP_COMMAND?.trim();
|
|
108
|
-
const explicitCliPath = env.GSD_BROWSER_CLI_PATH?.trim() || env.GSD_BROWSER_BIN_PATH?.trim();
|
|
109
|
-
const bundledCliPath = !explicitCommand && !explicitCliPath ? resolveBundledGsdBrowserCliPath(env) : null;
|
|
110
|
-
const command = explicitCommand
|
|
111
|
-
|| explicitCliPath
|
|
112
|
-
|| (bundledCliPath ? process.execPath : undefined)
|
|
113
|
-
|| "gsd-browser";
|
|
114
|
-
const args = Array.isArray(explicitArgs) && explicitArgs.length > 0
|
|
115
|
-
? explicitArgs.map(String)
|
|
116
|
-
: [
|
|
117
|
-
...(bundledCliPath ? [bundledCliPath] : []),
|
|
118
|
-
"mcp",
|
|
119
|
-
"--session",
|
|
120
|
-
buildBrowserSessionName(resolvedProjectRoot),
|
|
121
|
-
"--identity-scope",
|
|
122
|
-
"project",
|
|
123
|
-
"--identity-project",
|
|
124
|
-
resolvedProjectRoot,
|
|
125
|
-
];
|
|
126
|
-
const cwd = env.GSD_BROWSER_MCP_CWD?.trim() || resolvedProjectRoot;
|
|
59
|
+
const launch = resolveGsdBrowserMcpLaunchConfig(projectRoot, env);
|
|
127
60
|
return {
|
|
128
|
-
serverName,
|
|
61
|
+
serverName: launch.serverName,
|
|
129
62
|
server: {
|
|
130
|
-
command,
|
|
131
|
-
args,
|
|
132
|
-
cwd,
|
|
133
|
-
...(
|
|
63
|
+
command: launch.command,
|
|
64
|
+
args: launch.args,
|
|
65
|
+
cwd: launch.cwd,
|
|
66
|
+
...(launch.env ? { env: launch.env } : {}),
|
|
134
67
|
},
|
|
135
68
|
};
|
|
136
69
|
}
|
|
@@ -614,7 +614,10 @@ export function decayStaleMemories(thresholdUnits = 20) {
|
|
|
614
614
|
return []; // not enough processed units yet
|
|
615
615
|
const cutoff = row['processed_at'];
|
|
616
616
|
const affected = adapter.prepare(`SELECT id FROM memories
|
|
617
|
-
WHERE superseded_by IS NULL
|
|
617
|
+
WHERE superseded_by IS NULL
|
|
618
|
+
AND updated_at < :cutoff
|
|
619
|
+
AND confidence > 0.1
|
|
620
|
+
AND (structured_fields IS NULL OR structured_fields NOT LIKE '%"sourceDecisionId"%')`).all({ ':cutoff': cutoff }).map((r) => r['id']);
|
|
618
621
|
decayMemoriesBefore(cutoff, new Date().toISOString());
|
|
619
622
|
return affected;
|
|
620
623
|
}
|
|
@@ -15,6 +15,7 @@ import { extractVerdict, isAcceptableUatVerdict } from "./verdict-parser.js";
|
|
|
15
15
|
import { logWarning } from "./workflow-logger.js";
|
|
16
16
|
import { hasImplementationArtifacts } from "./milestone-implementation-evidence.js";
|
|
17
17
|
import { buildCompleteMilestonePrompt } from "./auto-prompts.js";
|
|
18
|
+
import { checkCloseoutConsistencyGate } from "./closeout-consistency-gate.js";
|
|
18
19
|
import { commitPendingMilestoneCloseoutChanges, findMissingSummaries, isVerificationNotApplicable, readUatGateVerdict, } from "./auto-dispatch.js";
|
|
19
20
|
const COMPLETE_MILESTONE_DB_SETTLE_MS = 1500;
|
|
20
21
|
const COMPLETE_MILESTONE_DB_SETTLE_POLL_MS = 100;
|
|
@@ -28,7 +29,8 @@ export async function isMilestoneCloseoutSettled(mid, basePath) {
|
|
|
28
29
|
if (isDbAvailable()) {
|
|
29
30
|
const milestone = getMilestone(mid);
|
|
30
31
|
if (milestone && isClosedStatus(milestone.status)) {
|
|
31
|
-
|
|
32
|
+
const closeoutGate = checkCloseoutConsistencyGate(mid, { refreshFromDisk: true });
|
|
33
|
+
if (closeoutGate.ok && verifyExpectedArtifact("complete-milestone", mid, basePath)) {
|
|
32
34
|
return true;
|
|
33
35
|
}
|
|
34
36
|
}
|
|
@@ -19,6 +19,15 @@ export function isRetryPending() {
|
|
|
19
19
|
export function consumeRetryTrigger() {
|
|
20
20
|
return getOrCreateRegistry().consumeRetryTrigger();
|
|
21
21
|
}
|
|
22
|
+
export function consumeHookFailure() {
|
|
23
|
+
return getOrCreateRegistry().consumeHookFailure();
|
|
24
|
+
}
|
|
25
|
+
export function isGateBlockPending() {
|
|
26
|
+
return getOrCreateRegistry().isGateBlockPending();
|
|
27
|
+
}
|
|
28
|
+
export function consumeGateBlock() {
|
|
29
|
+
return getOrCreateRegistry().consumeGateBlock();
|
|
30
|
+
}
|
|
22
31
|
export function resetHookState() {
|
|
23
32
|
getOrCreateRegistry().resetState();
|
|
24
33
|
}
|