@opengsd/gsd-pi 1.1.1-dev.74e8dd1 → 1.1.1-dev.75048e7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +3 -2
- package/dist/help-text.js +10 -6
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +495 -0
- package/dist/resources/extensions/browser-tools/engine/selection.js +16 -0
- package/dist/resources/extensions/browser-tools/extension-manifest.json +2 -2
- package/dist/resources/extensions/browser-tools/index.js +57 -9
- package/dist/resources/extensions/browser-tools/package.json +5 -1
- package/dist/resources/extensions/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 +30 -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 +8 -8
- 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 +8 -8
- 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 -23
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +82 -31
- 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 +72 -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 +73 -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 +410 -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 +63 -7
- 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 → h4TGni4xJzlZjGkxaT6uU}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → h4TGni4xJzlZjGkxaT6uU}/_ssgManifest.js +0 -0
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
/** browser-tools —
|
|
1
|
+
/** browser-tools — Pi Browser Automation Contract adapter. */
|
|
2
2
|
import { importExtensionModule, type ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import { closeManagedGsdBrowser, registerManagedGsdBrowserTools } from "./engine/managed-gsd-browser.js";
|
|
5
|
+
import { resolveBrowserEngineMode, type BrowserEngineMode } from "./engine/selection.js";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
let legacyRegistrationPromise: Promise<void> | null = null;
|
|
8
|
+
let managedRegistrationPromise: Promise<void> | null = null;
|
|
9
|
+
let registeredEngine: Exclude<BrowserEngineMode, "off"> | null = null;
|
|
10
|
+
|
|
11
|
+
async function registerLegacyBrowserTools(pi: ExtensionAPI): Promise<void> {
|
|
12
|
+
if (!legacyRegistrationPromise) {
|
|
13
|
+
legacyRegistrationPromise = (async () => {
|
|
9
14
|
const [
|
|
10
15
|
lifecycle,
|
|
11
16
|
capture,
|
|
@@ -136,12 +141,55 @@ async function registerBrowserTools(pi: ExtensionAPI): Promise<void> {
|
|
|
136
141
|
injectionDetection.registerInjectionDetectionTools(pi, deps);
|
|
137
142
|
verify.registerVerifyTools(pi, deps);
|
|
138
143
|
})().catch((error) => {
|
|
139
|
-
|
|
144
|
+
legacyRegistrationPromise = null;
|
|
140
145
|
throw error;
|
|
141
146
|
});
|
|
142
147
|
}
|
|
143
148
|
|
|
144
|
-
return
|
|
149
|
+
return legacyRegistrationPromise;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function registerBrowserTools(pi: ExtensionAPI): Promise<void> {
|
|
153
|
+
const engine = resolveBrowserEngineMode();
|
|
154
|
+
if (engine === "off") return;
|
|
155
|
+
if (registeredEngine && registeredEngine !== engine) {
|
|
156
|
+
throw new Error(
|
|
157
|
+
`Browser tools already registered with GSD_BROWSER_ENGINE=${registeredEngine}. Restart GSD before switching to ${engine}.`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let registration: Promise<void>;
|
|
162
|
+
if (engine === "legacy") {
|
|
163
|
+
registration = registerLegacyBrowserTools(pi);
|
|
164
|
+
} else if (!managedRegistrationPromise) {
|
|
165
|
+
managedRegistrationPromise = Promise.resolve()
|
|
166
|
+
.then(() => {
|
|
167
|
+
registerManagedGsdBrowserTools(pi);
|
|
168
|
+
})
|
|
169
|
+
.catch((error) => {
|
|
170
|
+
managedRegistrationPromise = null;
|
|
171
|
+
throw error;
|
|
172
|
+
});
|
|
173
|
+
registration = managedRegistrationPromise;
|
|
174
|
+
} else {
|
|
175
|
+
registration = managedRegistrationPromise;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
registeredEngine = engine;
|
|
179
|
+
try {
|
|
180
|
+
await registration;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
if (registeredEngine === engine) registeredEngine = null;
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function closeActiveBrowserEngines(): Promise<void> {
|
|
188
|
+
await closeManagedGsdBrowser();
|
|
189
|
+
if (legacyRegistrationPromise) {
|
|
190
|
+
const { closeBrowser } = await importExtensionModule<typeof import("./lifecycle.js")>(import.meta.url, "./lifecycle.js");
|
|
191
|
+
await closeBrowser();
|
|
192
|
+
}
|
|
145
193
|
}
|
|
146
194
|
|
|
147
195
|
export default function (pi: ExtensionAPI) {
|
|
@@ -157,7 +205,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
157
205
|
});
|
|
158
206
|
|
|
159
207
|
pi.on("session_shutdown", async () => {
|
|
160
|
-
|
|
161
|
-
|
|
208
|
+
await closeActiveBrowserEngines();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
pi.on("session_switch", async () => {
|
|
212
|
+
await closeActiveBrowserEngines();
|
|
162
213
|
});
|
|
163
214
|
}
|
|
@@ -4,16 +4,20 @@
|
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "node --test tests/*.test.mjs"
|
|
7
|
+
"test": "node --import ../gsd/tests/resolve-ts.mjs --experimental-strip-types --test tests/*.test.mjs"
|
|
8
8
|
},
|
|
9
9
|
"pi": {
|
|
10
10
|
"extensions": ["./index.ts"]
|
|
11
11
|
},
|
|
12
12
|
"peerDependencies": {
|
|
13
|
+
"@opengsd/gsd-browser": ">=0.1.27",
|
|
13
14
|
"playwright": ">=1.40.0",
|
|
14
15
|
"sharp": ">=0.33.0"
|
|
15
16
|
},
|
|
16
17
|
"peerDependenciesMeta": {
|
|
18
|
+
"@opengsd/gsd-browser": {
|
|
19
|
+
"optional": true
|
|
20
|
+
},
|
|
17
21
|
"playwright": {
|
|
18
22
|
"optional": true
|
|
19
23
|
},
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { dirname } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const jiti = require("jiti")(__dirname, { interopDefault: true, debug: false });
|
|
10
|
+
|
|
11
|
+
const { resolveBrowserEngineMode } = jiti("../engine/selection.ts");
|
|
12
|
+
|
|
13
|
+
describe("resolveBrowserEngineMode", () => {
|
|
14
|
+
it("defaults to gsd-browser", () => {
|
|
15
|
+
assert.equal(resolveBrowserEngineMode({}), "gsd-browser");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("accepts the explicit engine modes", () => {
|
|
19
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "gsd-browser" }), "gsd-browser");
|
|
20
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "legacy" }), "legacy");
|
|
21
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "off" }), "off");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("accepts compatibility aliases", () => {
|
|
25
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "playwright" }), "legacy");
|
|
26
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "false" }), "off");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("rejects unknown engine modes", () => {
|
|
30
|
+
assert.throws(
|
|
31
|
+
() => resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "surprise" }),
|
|
32
|
+
/Expected "gsd-browser", "legacy", or "off"/,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
MANAGED_GSD_BROWSER_TOOL_NAMES,
|
|
6
|
+
registerManagedGsdBrowserTools,
|
|
7
|
+
} = await import("../engine/managed-gsd-browser.ts");
|
|
8
|
+
|
|
9
|
+
describe("registerManagedGsdBrowserTools", () => {
|
|
10
|
+
it("registers the curated Pi browser contract", () => {
|
|
11
|
+
const tools = [];
|
|
12
|
+
registerManagedGsdBrowserTools({
|
|
13
|
+
registerTool(tool) {
|
|
14
|
+
tools.push(tool);
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
assert.deepEqual(tools.map((tool) => tool.name), [...MANAGED_GSD_BROWSER_TOOL_NAMES]);
|
|
19
|
+
assert.equal(new Set(tools.map((tool) => tool.name)).size, tools.length);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("keeps screenshots marked as image-producing evidence", () => {
|
|
23
|
+
const tools = [];
|
|
24
|
+
registerManagedGsdBrowserTools({
|
|
25
|
+
registerTool(tool) {
|
|
26
|
+
tools.push(tool);
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const screenshot = tools.find((tool) => tool.name === "browser_screenshot");
|
|
31
|
+
assert.equal(screenshot?.compatibility?.producesImages, true);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -277,7 +277,6 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
277
277
|
this.status.activeUnit = { unitType: decision.unitType, unitId: decision.unitId };
|
|
278
278
|
this.status.phase = "running";
|
|
279
279
|
this.lastAdvanceKey = nextKey;
|
|
280
|
-
this.lastFinalizedUnitKey = null;
|
|
281
280
|
this.bumpTransition();
|
|
282
281
|
|
|
283
282
|
await this.deps.runtime.journalTransition({
|
|
@@ -13,10 +13,11 @@ import type {
|
|
|
13
13
|
ExtensionCommandContext,
|
|
14
14
|
ReadonlyFooterDataProvider,
|
|
15
15
|
Theme,
|
|
16
|
+
ThemeColor,
|
|
16
17
|
} from "@gsd/pi-coding-agent";
|
|
17
18
|
import type { GSDState } from "./types.js";
|
|
18
19
|
import { getActiveHook } from "./post-unit-hooks.js";
|
|
19
|
-
import { getLedger } from "./metrics.js";
|
|
20
|
+
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
20
21
|
import { getErrorMessage } from "./error-utils.js";
|
|
21
22
|
import { nativeIsRepo } from "./native-git-bridge.js";
|
|
22
23
|
import {
|
|
@@ -304,6 +305,40 @@ export function shouldRenderRoadmapProgress(
|
|
|
304
305
|
return !!progress && progress.total > 0;
|
|
305
306
|
}
|
|
306
307
|
|
|
308
|
+
function widgetGridLabel(theme: Theme, text: string, color: ThemeColor = "borderAccent"): string {
|
|
309
|
+
return theme.fg(color, theme.bold(text.toUpperCase()));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function widgetGridColumn(content: string, width: number): string {
|
|
313
|
+
return padRightVisible(truncateToWidth(content, width, "…"), width);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function widgetGridColumns(theme: Theme, width: number, parts: string[]): string {
|
|
317
|
+
if (parts.length === 0) return "";
|
|
318
|
+
const gap = theme.fg("dim", " │ ");
|
|
319
|
+
const gapWidth = visibleWidth(gap) * (parts.length - 1);
|
|
320
|
+
const available = Math.max(parts.length * 8, width - gapWidth);
|
|
321
|
+
const base = Math.floor(available / parts.length);
|
|
322
|
+
let remaining = available - base * parts.length;
|
|
323
|
+
const columns = parts.map((part) => {
|
|
324
|
+
const columnWidth = base + (remaining > 0 ? 1 : 0);
|
|
325
|
+
remaining--;
|
|
326
|
+
return widgetGridColumn(part, columnWidth);
|
|
327
|
+
});
|
|
328
|
+
return truncateToWidth(columns.join(gap), width, "…");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function formatSmallWidgetSpend(): string {
|
|
332
|
+
const ledger = getLedger();
|
|
333
|
+
if (!ledger || ledger.units.length === 0) return "--";
|
|
334
|
+
|
|
335
|
+
const totals = getProjectTotals(ledger.units);
|
|
336
|
+
const parts: string[] = [];
|
|
337
|
+
if (totals.tokens.total > 0) parts.push(formatWidgetTokens(totals.tokens.total));
|
|
338
|
+
if (totals.cost > 0) parts.push(`$${totals.cost.toFixed(2)}`);
|
|
339
|
+
return parts.length > 0 ? parts.join(" · ") : "--";
|
|
340
|
+
}
|
|
341
|
+
|
|
307
342
|
// ─── ETA Estimation ──────────────────────────────────────────────────────────
|
|
308
343
|
|
|
309
344
|
/**
|
|
@@ -836,29 +871,62 @@ export function updateProgressWidget(
|
|
|
836
871
|
return lines;
|
|
837
872
|
}
|
|
838
873
|
|
|
839
|
-
// ── Mode: small —
|
|
874
|
+
// ── Mode: small — dense horizontal grid ───────────────────────
|
|
840
875
|
if (widgetMode === "small") {
|
|
841
|
-
lines.
|
|
842
|
-
|
|
843
|
-
// Action line
|
|
844
|
-
const target = task ? `${task.id}: ${task.title}` : unitId;
|
|
845
|
-
const actionLeft = `${pad}${theme.fg("accent", "▸")} ${theme.fg("accent", verb)} ${theme.fg("text", target)}`;
|
|
846
|
-
lines.push(rightAlign(actionLeft, theme.fg("dim", phaseLabel), width));
|
|
876
|
+
lines.length = 0;
|
|
877
|
+
lines.push(...ui.bar());
|
|
847
878
|
|
|
848
|
-
// Progress bar
|
|
849
879
|
const roadmapSlices = mid ? getRoadmapSlicesSync() : null;
|
|
880
|
+
const unitLabel = unitId || [mid?.id, slice?.id, task?.id].filter(Boolean).join("/");
|
|
881
|
+
const statusParts = [
|
|
882
|
+
spinner,
|
|
883
|
+
theme.fg("success", modeTag),
|
|
884
|
+
theme.fg(stateColor, activeState),
|
|
885
|
+
];
|
|
886
|
+
if (runtimeSignal?.summary) {
|
|
887
|
+
statusParts.push(theme.fg(healthColor, healthSummary));
|
|
888
|
+
} else if (healthLevel !== "green") {
|
|
889
|
+
statusParts.push(`${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor, healthSummary)}`);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
const timeValue = [elapsed, etaShort].filter(Boolean).join(" · ") || "--";
|
|
893
|
+
const rowOne = widgetGridColumns(theme, width, [
|
|
894
|
+
`${widgetGridLabel(theme, "status", "border")} ${statusParts.join(" ")}`,
|
|
895
|
+
`${widgetGridLabel(theme, "unit")} ${theme.fg("text", unitLabel || "--")}`,
|
|
896
|
+
`${widgetGridLabel(theme, "spend", "border")} ${theme.fg("dim", formatSmallWidgetSpend())}`,
|
|
897
|
+
`${widgetGridLabel(theme, "time")} ${theme.fg("dim", timeValue)}`,
|
|
898
|
+
]);
|
|
899
|
+
|
|
900
|
+
const target = task
|
|
901
|
+
? `${task.id}: ${task.title}`
|
|
902
|
+
: slice
|
|
903
|
+
? `${slice.id}: ${slice.title}`
|
|
904
|
+
: unitId;
|
|
905
|
+
|
|
906
|
+
let taskValue = task?.id ?? "--";
|
|
907
|
+
let sliceValue = slice?.id ?? "--";
|
|
850
908
|
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
851
909
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
852
|
-
const barWidth = Math.max(
|
|
910
|
+
const barWidth = Math.max(4, Math.min(14, Math.floor(width * 0.12)));
|
|
853
911
|
const bar = renderProgressBar(theme, done, total, barWidth);
|
|
854
|
-
|
|
912
|
+
sliceValue = `${bar} ${theme.fg("text", `${done}/${total}`)}`;
|
|
855
913
|
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
856
|
-
const
|
|
857
|
-
|
|
914
|
+
const taskNum = isHook
|
|
915
|
+
? Math.max(activeSliceTasks.done, 1)
|
|
916
|
+
: Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
|
|
917
|
+
taskValue = `${theme.fg("accent", `${taskNum}`)}${theme.fg("dim", `/${activeSliceTasks.total}`)}`;
|
|
858
918
|
}
|
|
859
|
-
lines.push(`${pad}${bar} ${meta}`);
|
|
860
919
|
}
|
|
861
920
|
|
|
921
|
+
const rowTwo = widgetGridColumns(theme, width, [
|
|
922
|
+
`${widgetGridLabel(theme, "phase", "border")} ${theme.fg("dim", unitType)}`,
|
|
923
|
+
`${widgetGridLabel(theme, "work")} ${theme.fg("text", target || "--")}`,
|
|
924
|
+
`${widgetGridLabel(theme, "task", "border")} ${taskValue}`,
|
|
925
|
+
`${widgetGridLabel(theme, "slice")} ${sliceValue}`,
|
|
926
|
+
]);
|
|
927
|
+
|
|
928
|
+
lines.push(rowOne);
|
|
929
|
+
lines.push(rowTwo);
|
|
862
930
|
lines.push(...ui.bar());
|
|
863
931
|
cachedLines = lines;
|
|
864
932
|
cachedWidth = width;
|
|
@@ -96,6 +96,10 @@ import { probeGitConflictState } from "./git-conflict-state.js";
|
|
|
96
96
|
import { runTurnGitAction } from "./git-service.js";
|
|
97
97
|
import { parseUnitId } from "./unit-id.js";
|
|
98
98
|
import { resolveExpectedArtifactPath } from "./auto-artifact-paths.js";
|
|
99
|
+
import {
|
|
100
|
+
checkCloseoutConsistencyGate,
|
|
101
|
+
formatCloseoutConsistencyBlock,
|
|
102
|
+
} from "./closeout-consistency-gate.js";
|
|
99
103
|
|
|
100
104
|
// ─── Types ────────────────────────────────────────────────────────────────
|
|
101
105
|
|
|
@@ -622,6 +626,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
622
626
|
structuredQuestionsAvailable,
|
|
623
627
|
{ headless: !!process.env.GSD_HEADLESS },
|
|
624
628
|
),
|
|
629
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
625
630
|
};
|
|
626
631
|
},
|
|
627
632
|
},
|
|
@@ -772,6 +777,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
772
777
|
structuredQuestionsAvailable,
|
|
773
778
|
{ headless: !!process.env.GSD_HEADLESS },
|
|
774
779
|
),
|
|
780
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
775
781
|
};
|
|
776
782
|
},
|
|
777
783
|
},
|
|
@@ -805,6 +811,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
805
811
|
unitType: "discuss-project",
|
|
806
812
|
unitId: "PROJECT",
|
|
807
813
|
prompt: await buildDiscussProjectPrompt(basePath, structuredQuestionsAvailable),
|
|
814
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
808
815
|
};
|
|
809
816
|
},
|
|
810
817
|
},
|
|
@@ -826,6 +833,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
826
833
|
unitType: "discuss-requirements",
|
|
827
834
|
unitId: "REQUIREMENTS",
|
|
828
835
|
prompt: await buildDiscussRequirementsPrompt(basePath, structuredQuestionsAvailable),
|
|
836
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
829
837
|
};
|
|
830
838
|
},
|
|
831
839
|
},
|
|
@@ -940,6 +948,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
940
948
|
structuredQuestionsAvailable,
|
|
941
949
|
{ headless: !!process.env.GSD_HEADLESS },
|
|
942
950
|
),
|
|
951
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
943
952
|
};
|
|
944
953
|
},
|
|
945
954
|
},
|
|
@@ -1630,6 +1639,16 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
1630
1639
|
prompt: await buildCompleteMilestonePrompt(mid, midTitle, basePath),
|
|
1631
1640
|
};
|
|
1632
1641
|
}
|
|
1642
|
+
if (milestone) {
|
|
1643
|
+
const closeoutGate = checkCloseoutConsistencyGate(mid, { refreshFromDisk: true });
|
|
1644
|
+
if (!closeoutGate.ok) {
|
|
1645
|
+
return {
|
|
1646
|
+
action: "stop",
|
|
1647
|
+
reason: formatCloseoutConsistencyBlock(closeoutGate),
|
|
1648
|
+
level: "warning",
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1633
1652
|
}
|
|
1634
1653
|
return {
|
|
1635
1654
|
action: "stop",
|
|
@@ -55,8 +55,10 @@ import { parseRoadmap as parseLegacyRoadmap } from "./parsers-legacy.js";
|
|
|
55
55
|
import { consumeSignal } from "./session-status-io.js";
|
|
56
56
|
import {
|
|
57
57
|
checkPostUnitHooks,
|
|
58
|
+
consumeHookFailure,
|
|
58
59
|
isRetryPending,
|
|
59
60
|
consumeRetryTrigger,
|
|
61
|
+
consumeGateBlock,
|
|
60
62
|
persistHookState,
|
|
61
63
|
resolveHookArtifactPath,
|
|
62
64
|
} from "./post-unit-hooks.js";
|
|
@@ -2227,11 +2229,11 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
2227
2229
|
// ── Post-unit hooks ──
|
|
2228
2230
|
if (s.currentUnit && !s.stepMode) {
|
|
2229
2231
|
const hookUnit = checkPostUnitHooks(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
2232
|
+
persistHookState(s.basePath);
|
|
2230
2233
|
if (hookUnit) {
|
|
2231
2234
|
if (s.currentUnit) {
|
|
2232
2235
|
await closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
|
|
2233
2236
|
}
|
|
2234
|
-
persistHookState(s.basePath);
|
|
2235
2237
|
|
|
2236
2238
|
return enqueueSidecar(
|
|
2237
2239
|
s, ctx,
|
|
@@ -2240,12 +2242,23 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
2240
2242
|
);
|
|
2241
2243
|
}
|
|
2242
2244
|
|
|
2245
|
+
const hookFailure = consumeHookFailure();
|
|
2246
|
+
if (hookFailure) {
|
|
2247
|
+
ctx.ui.notify(
|
|
2248
|
+
`Post-unit hook ${hookFailure.hookName} failed for ${hookFailure.unitId}: ${hookFailure.reason}. Pausing auto-mode.`,
|
|
2249
|
+
"warning",
|
|
2250
|
+
);
|
|
2251
|
+
await pauseAuto(ctx, pi);
|
|
2252
|
+
return "stopped";
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2243
2255
|
// Check if a hook requested a retry of the trigger unit
|
|
2244
2256
|
if (isRetryPending()) {
|
|
2245
2257
|
const trigger = consumeRetryTrigger();
|
|
2246
2258
|
if (trigger) {
|
|
2259
|
+
persistHookState(s.basePath);
|
|
2247
2260
|
ctx.ui.notify(
|
|
2248
|
-
`Hook requested retry of ${trigger.unitType} ${trigger.unitId} — resetting
|
|
2261
|
+
`Hook requested retry of ${trigger.unitType} ${trigger.unitId} — resetting trigger unit state.`,
|
|
2249
2262
|
"info",
|
|
2250
2263
|
);
|
|
2251
2264
|
|
|
@@ -2299,6 +2312,19 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
2299
2312
|
// Fall through to normal dispatch — deriveState will re-derive the unit
|
|
2300
2313
|
}
|
|
2301
2314
|
}
|
|
2315
|
+
|
|
2316
|
+
const gateBlock = consumeGateBlock();
|
|
2317
|
+
if (gateBlock) {
|
|
2318
|
+
persistHookState(s.basePath);
|
|
2319
|
+
const verdict = gateBlock.verdict ? ` verdict=${gateBlock.verdict};` : "";
|
|
2320
|
+
const artifact = gateBlock.artifact ? ` artifact=${gateBlock.artifact};` : "";
|
|
2321
|
+
const message =
|
|
2322
|
+
`Post-unit gate "${gateBlock.hookName}" blocked ${gateBlock.triggerUnitType} ${gateBlock.triggerUnitId}:` +
|
|
2323
|
+
`${verdict}${artifact} ${gateBlock.reason}. Run /gsd status to inspect, then /gsd auto after recovery.`;
|
|
2324
|
+
ctx.ui.notify(message, "warning");
|
|
2325
|
+
await pauseAuto(ctx, pi);
|
|
2326
|
+
return "stopped";
|
|
2327
|
+
}
|
|
2302
2328
|
}
|
|
2303
2329
|
|
|
2304
2330
|
// ── Fast-path stop detection (#3487) ──
|
|
@@ -45,6 +45,8 @@ import { classifyProject, type ProjectClassification } from "./detection.js";
|
|
|
45
45
|
import { hasBrowserRequiredText } from "./browser-evidence.js";
|
|
46
46
|
import { debugLog } from "./debug-logger.js";
|
|
47
47
|
import { buildSkillActivationBlock, buildSkillDiscoveryVars } from "./skill-activation.js";
|
|
48
|
+
import { findMilestoneIds } from "./milestone-ids.js";
|
|
49
|
+
import { buildRunUatPresentationForType, RUN_UAT_TOOL_PRESENTATION_PLAN_ID } from "./tool-presentation-plan.js";
|
|
48
50
|
|
|
49
51
|
export { buildSkillActivationBlock, buildSkillDiscoveryVars };
|
|
50
52
|
|
|
@@ -1428,7 +1430,7 @@ export async function checkNeedsRunUat(
|
|
|
1428
1430
|
// If the UAT file already contains a verdict, UAT has been run — skip
|
|
1429
1431
|
if (hasVerdict(uatContent)) continue;
|
|
1430
1432
|
// Also check the ASSESSMENT file — the run-uat prompt writes the verdict
|
|
1431
|
-
// there (via
|
|
1433
|
+
// there (via gsd_uat_result_save), not into the
|
|
1432
1434
|
// UAT spec file. Without this check the unit re-dispatches indefinitely.
|
|
1433
1435
|
const assessmentFile = resolveSliceFile(base, mid, sid, "ASSESSMENT");
|
|
1434
1436
|
if (assessmentFile) {
|
|
@@ -1482,21 +1484,84 @@ export async function checkNeedsRunUat(
|
|
|
1482
1484
|
* as a seed when present. The discussion agent interviews the user, writes
|
|
1483
1485
|
* a full CONTEXT.md, and the phase transitions to pre-planning automatically.
|
|
1484
1486
|
*/
|
|
1487
|
+
export interface DiscussMilestonePromptOptions {
|
|
1488
|
+
headless?: boolean;
|
|
1489
|
+
commitInstruction?: string;
|
|
1490
|
+
fastPathInstruction?: string;
|
|
1491
|
+
includeDraftSeed?: boolean;
|
|
1492
|
+
includeContextMode?: boolean;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
export async function buildDiscussMilestoneInlinedContext(mid: string, base: string): Promise<string> {
|
|
1496
|
+
const inlined: string[] = [];
|
|
1497
|
+
|
|
1498
|
+
const roadmapInline = await inlineFileOptional(
|
|
1499
|
+
resolveMilestoneFile(base, mid, "ROADMAP"),
|
|
1500
|
+
relMilestoneFile(base, mid, "ROADMAP"),
|
|
1501
|
+
"Milestone Roadmap",
|
|
1502
|
+
);
|
|
1503
|
+
if (roadmapInline) inlined.push(roadmapInline);
|
|
1504
|
+
|
|
1505
|
+
const contextInline = await inlineFileOptional(
|
|
1506
|
+
resolveMilestoneFile(base, mid, "CONTEXT"),
|
|
1507
|
+
relMilestoneFile(base, mid, "CONTEXT"),
|
|
1508
|
+
"Milestone Context",
|
|
1509
|
+
);
|
|
1510
|
+
if (contextInline) inlined.push(contextInline);
|
|
1511
|
+
|
|
1512
|
+
const researchInline = await inlineFileOptional(
|
|
1513
|
+
resolveMilestoneFile(base, mid, "RESEARCH"),
|
|
1514
|
+
relMilestoneFile(base, mid, "RESEARCH"),
|
|
1515
|
+
"Milestone Research",
|
|
1516
|
+
);
|
|
1517
|
+
if (researchInline) inlined.push(researchInline);
|
|
1518
|
+
|
|
1519
|
+
const decisionsPath = resolveGsdRootFile(base, "DECISIONS");
|
|
1520
|
+
if (existsSync(decisionsPath)) {
|
|
1521
|
+
const decisionsContent = await loadFile(decisionsPath);
|
|
1522
|
+
if (decisionsContent) {
|
|
1523
|
+
inlined.push(`### Decisions Register\nSource: \`${relGsdRootFile("DECISIONS")}\`\n\n${decisionsContent.trim()}`);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
const milestoneIds = findMilestoneIds(base);
|
|
1528
|
+
const currentIndex = milestoneIds.indexOf(mid);
|
|
1529
|
+
const priorMilestoneIds = currentIndex >= 0 ? milestoneIds.slice(0, currentIndex) : milestoneIds;
|
|
1530
|
+
for (const priorMid of priorMilestoneIds) {
|
|
1531
|
+
const summaryInline = await inlineFileOptional(
|
|
1532
|
+
resolveMilestoneFile(base, priorMid, "SUMMARY"),
|
|
1533
|
+
relMilestoneFile(base, priorMid, "SUMMARY"),
|
|
1534
|
+
`${priorMid} Prior Milestone Summary`,
|
|
1535
|
+
);
|
|
1536
|
+
if (summaryInline) inlined.push(summaryInline);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
return inlined.length > 0
|
|
1540
|
+
? `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`
|
|
1541
|
+
: "## Inlined Context\n\n_(no milestone context files found yet — go in blind and ask broad questions)_";
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1485
1544
|
export async function buildDiscussMilestonePrompt(
|
|
1486
1545
|
mid: string,
|
|
1487
1546
|
midTitle: string,
|
|
1488
1547
|
base: string,
|
|
1489
1548
|
structuredQuestionsAvailable = "false",
|
|
1490
|
-
{
|
|
1549
|
+
{
|
|
1550
|
+
headless = false,
|
|
1551
|
+
commitInstruction = "Do not commit planning artifacts — .gsd/ is managed externally.",
|
|
1552
|
+
fastPathInstruction = "",
|
|
1553
|
+
includeDraftSeed = true,
|
|
1554
|
+
includeContextMode = true,
|
|
1555
|
+
}: DiscussMilestonePromptOptions = {},
|
|
1491
1556
|
): Promise<string> {
|
|
1492
|
-
const
|
|
1557
|
+
const contextTemplate = inlineTemplate("context", "Context");
|
|
1493
1558
|
|
|
1494
1559
|
if (headless) {
|
|
1495
1560
|
const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
1496
1561
|
const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
|
|
1497
1562
|
return loadPrompt("discuss-headless", {
|
|
1498
1563
|
seedContext: roadmapContent ?? "",
|
|
1499
|
-
inlinedTemplates:
|
|
1564
|
+
inlinedTemplates: contextTemplate,
|
|
1500
1565
|
workingDirectory: base,
|
|
1501
1566
|
milestoneId: mid,
|
|
1502
1567
|
contextPath: relMilestoneFile(base, mid, "CONTEXT"),
|
|
@@ -1505,7 +1570,9 @@ export async function buildDiscussMilestonePrompt(
|
|
|
1505
1570
|
});
|
|
1506
1571
|
}
|
|
1507
1572
|
|
|
1508
|
-
const
|
|
1573
|
+
const rawInlinedContext = await buildDiscussMilestoneInlinedContext(mid, base);
|
|
1574
|
+
const cappedInlinedContext = capPreamble(rawInlinedContext);
|
|
1575
|
+
const discussTemplates = [cappedInlinedContext, contextTemplate].join("\n\n---\n\n");
|
|
1509
1576
|
|
|
1510
1577
|
const basePrompt = loadPrompt("guided-discuss-milestone", {
|
|
1511
1578
|
workingDirectory: base,
|
|
@@ -1513,20 +1580,22 @@ export async function buildDiscussMilestonePrompt(
|
|
|
1513
1580
|
milestoneTitle: midTitle,
|
|
1514
1581
|
inlinedTemplates: discussTemplates,
|
|
1515
1582
|
structuredQuestionsAvailable,
|
|
1516
|
-
commitInstruction
|
|
1517
|
-
fastPathInstruction
|
|
1583
|
+
commitInstruction,
|
|
1584
|
+
fastPathInstruction,
|
|
1518
1585
|
});
|
|
1519
|
-
const promptWithContextMode =
|
|
1586
|
+
const promptWithContextMode = includeContextMode
|
|
1587
|
+
? prependContextModeToBlock("discuss-milestone", base, basePrompt)
|
|
1588
|
+
: basePrompt;
|
|
1520
1589
|
|
|
1521
1590
|
// If a CONTEXT-DRAFT.md exists, append it as seed material
|
|
1522
1591
|
const draftPath = resolveMilestoneFile(base, mid, "CONTEXT-DRAFT");
|
|
1523
1592
|
const draftContent = draftPath ? await loadFile(draftPath) : null;
|
|
1524
1593
|
|
|
1525
|
-
if (draftContent) {
|
|
1594
|
+
if (includeDraftSeed && draftContent) {
|
|
1526
1595
|
return `${promptWithContextMode}\n\n## Prior Discussion (Draft Seed)\n\nThe following draft was captured from a prior multi-milestone discussion. Use it as seed material — the user has already provided this context. Start with a brief reflection on what the draft covers, then probe for any gaps or open questions before writing the full CONTEXT.md.\n\n${draftContent}`;
|
|
1527
1596
|
}
|
|
1528
1597
|
|
|
1529
|
-
return
|
|
1598
|
+
return promptWithContextMode;
|
|
1530
1599
|
}
|
|
1531
1600
|
|
|
1532
1601
|
/**
|
|
@@ -2918,13 +2987,23 @@ export async function buildValidateMilestonePrompt(
|
|
|
2918
2987
|
if (isDbAvailable()) {
|
|
2919
2988
|
const milestone = getMilestone(mid);
|
|
2920
2989
|
if (milestone) {
|
|
2990
|
+
const escapeCell = (value: string) =>
|
|
2991
|
+
value.replace(/[\\|]/g, (char) => `\\${char}`).replace(/\r?\n/g, " ");
|
|
2921
2992
|
const classes: string[] = [];
|
|
2922
|
-
if (milestone.verification_contract) classes.push(
|
|
2923
|
-
if (milestone.verification_integration) classes.push(
|
|
2924
|
-
if (milestone.verification_operational) classes.push(
|
|
2925
|
-
if (milestone.verification_uat) classes.push(
|
|
2993
|
+
if (milestone.verification_contract) classes.push(`| Contract | ${escapeCell(milestone.verification_contract)} |`);
|
|
2994
|
+
if (milestone.verification_integration) classes.push(`| Integration | ${escapeCell(milestone.verification_integration)} |`);
|
|
2995
|
+
if (milestone.verification_operational) classes.push(`| Operational | ${escapeCell(milestone.verification_operational)} |`);
|
|
2996
|
+
if (milestone.verification_uat) classes.push(`| UAT | ${escapeCell(milestone.verification_uat)} |`);
|
|
2926
2997
|
if (classes.length > 0) {
|
|
2927
|
-
const verificationClasses =
|
|
2998
|
+
const verificationClasses = [
|
|
2999
|
+
"### Verification Classes (from planning)",
|
|
3000
|
+
"",
|
|
3001
|
+
"These verification tiers were defined during milestone planning. Every row in this table must appear in `verificationClasses` with the same canonical class name.",
|
|
3002
|
+
"",
|
|
3003
|
+
"| Class | Planned Check |",
|
|
3004
|
+
"| --- | --- |",
|
|
3005
|
+
...classes,
|
|
3006
|
+
].join("\n");
|
|
2928
3007
|
inlined.push(verificationClasses);
|
|
2929
3008
|
trackPromptContext(contextTelemetry, "verification-classes", "inline", verificationClasses);
|
|
2930
3009
|
}
|
|
@@ -3306,6 +3385,7 @@ export async function buildRunUatPrompt(
|
|
|
3306
3385
|
|
|
3307
3386
|
const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "ASSESSMENT"));
|
|
3308
3387
|
const uatType = resolveEffectiveUatType(uatContent);
|
|
3388
|
+
const canonicalPresentation = JSON.stringify(buildRunUatPresentationForType(uatType), null, 2);
|
|
3309
3389
|
|
|
3310
3390
|
return loadPrompt("run-uat", {
|
|
3311
3391
|
workingDirectory: base,
|
|
@@ -3314,6 +3394,8 @@ export async function buildRunUatPrompt(
|
|
|
3314
3394
|
uatPath,
|
|
3315
3395
|
uatResultPath,
|
|
3316
3396
|
uatType,
|
|
3397
|
+
toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
3398
|
+
canonicalPresentation,
|
|
3317
3399
|
inlinedContext,
|
|
3318
3400
|
skillActivation: buildSkillActivationBlock({
|
|
3319
3401
|
base,
|
|
@@ -54,6 +54,7 @@ import { isGsdWorktreePath } from "./worktree-root.js";
|
|
|
54
54
|
import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
|
|
55
55
|
import { hasImplementationArtifacts } from "./milestone-implementation-evidence.js";
|
|
56
56
|
import { loadAllCaptures, loadPendingCaptures } from "./captures.js";
|
|
57
|
+
import { checkCloseoutConsistencyGate } from "./closeout-consistency-gate.js";
|
|
57
58
|
|
|
58
59
|
// Re-export so existing consumers of auto-recovery.ts keep working.
|
|
59
60
|
export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
|
|
@@ -626,9 +627,8 @@ export function verifyExpectedArtifact(
|
|
|
626
627
|
if (summaryOutcome === "failure") return false;
|
|
627
628
|
const { milestone: mid } = parseUnitId(unitId);
|
|
628
629
|
if (mid && isDbAvailable()) {
|
|
629
|
-
const
|
|
630
|
-
if (!
|
|
631
|
-
if (!isClosedStatus(dbMilestone.status) && summaryOutcome !== "success") return false;
|
|
630
|
+
const closeoutGate = checkCloseoutConsistencyGate(mid, { refreshFromDisk: true });
|
|
631
|
+
if (!closeoutGate.ok) return false;
|
|
632
632
|
}
|
|
633
633
|
if (hasImplementationArtifacts(base, mid) === "absent") return false;
|
|
634
634
|
}
|