@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
|
@@ -4,7 +4,7 @@ import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
|
4
4
|
|
|
5
5
|
import { minimatch } from "minimatch";
|
|
6
6
|
|
|
7
|
-
import { shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
|
|
7
|
+
import { GSD_PHASE_SCOPE_DISPLAY_REASON, shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
|
|
8
8
|
import { getIsolationMode } from "../preferences.js";
|
|
9
9
|
import { compileSubagentPermissionContract, type ToolsPolicy } from "../unit-context-manifest.js";
|
|
10
10
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -772,6 +772,20 @@ function blockReason(unitType: string, mode: string, what: string): string {
|
|
|
772
772
|
].join(" ");
|
|
773
773
|
}
|
|
774
774
|
|
|
775
|
+
function planningBlock(unitType: string, mode: string, what: string): PlanningUnitBlockResult {
|
|
776
|
+
return {
|
|
777
|
+
block: true,
|
|
778
|
+
reason: blockReason(unitType, mode, what),
|
|
779
|
+
displayReason: GSD_PHASE_SCOPE_DISPLAY_REASON,
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
type PlanningUnitBlockResult = {
|
|
784
|
+
block: boolean;
|
|
785
|
+
reason?: string;
|
|
786
|
+
displayReason?: string;
|
|
787
|
+
};
|
|
788
|
+
|
|
775
789
|
/**
|
|
776
790
|
* Planning-unit tool-policy enforcement. Returns { block } per the policy
|
|
777
791
|
* resolved from the active unit's manifest:
|
|
@@ -812,7 +826,7 @@ export function shouldBlockPlanningUnit(
|
|
|
812
826
|
agentClasses?: readonly string[],
|
|
813
827
|
toolInput?: unknown,
|
|
814
828
|
unitId?: string,
|
|
815
|
-
):
|
|
829
|
+
): PlanningUnitBlockResult {
|
|
816
830
|
const tool = canonicalToolName(toolName);
|
|
817
831
|
const autoScopeGuard = shouldBlockAutoUnitToolCall(unitType, toolName, toolInput, unitId);
|
|
818
832
|
if (autoScopeGuard.block) return autoScopeGuard;
|
|
@@ -825,10 +839,10 @@ export function shouldBlockPlanningUnit(
|
|
|
825
839
|
if (PLANNING_SAFE_TOOLS.has(tool)) return { block: false };
|
|
826
840
|
if (tool.startsWith("gsd_")) return { block: false };
|
|
827
841
|
if (PLANNING_WRITE_TOOLS.has(tool) || tool === "bash" || PLANNING_SUBAGENT_TOOLS.has(tool)) {
|
|
828
|
-
return
|
|
842
|
+
return planningBlock(unitType, policy.mode, `${tool} is not permitted (read-only)`);
|
|
829
843
|
}
|
|
830
844
|
// Unknown tool in read-only mode — block by default.
|
|
831
|
-
return
|
|
845
|
+
return planningBlock(unitType, policy.mode, `tool "${tool}" is not on the read-only allowlist`);
|
|
832
846
|
}
|
|
833
847
|
|
|
834
848
|
// planning / planning-dispatch / docs / verification modes share the same surface for safe tools, bash, and subagent.
|
|
@@ -846,14 +860,11 @@ export function shouldBlockPlanningUnit(
|
|
|
846
860
|
// instead of silently bypassing the gate.
|
|
847
861
|
if (agentClasses === undefined) {
|
|
848
862
|
warnMissingControlledDispatchAgentClasses(unitType, policy.mode, tool);
|
|
849
|
-
return
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
`subagent dispatch blocked: stale caller did not supply agent identities for "${tool}"; update extractSubagentAgentClasses to handle this input shape`,
|
|
855
|
-
),
|
|
856
|
-
};
|
|
863
|
+
return planningBlock(
|
|
864
|
+
unitType,
|
|
865
|
+
policy.mode,
|
|
866
|
+
`subagent dispatch blocked: stale caller did not supply agent identities for "${tool}"; update extractSubagentAgentClasses to handle this input shape`,
|
|
867
|
+
);
|
|
857
868
|
}
|
|
858
869
|
// agentClasses was explicitly provided but resolved to an empty list (for
|
|
859
870
|
// example, a bare tool call with no agent field). Pass through; no agents
|
|
@@ -863,57 +874,45 @@ export function shouldBlockPlanningUnit(
|
|
|
863
874
|
}
|
|
864
875
|
const globallyDisallowed = requested.find(a => !isReadOnlySpecialist(a));
|
|
865
876
|
if (globallyDisallowed) {
|
|
866
|
-
return
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
`subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`,
|
|
872
|
-
),
|
|
873
|
-
};
|
|
877
|
+
return planningBlock(
|
|
878
|
+
unitType,
|
|
879
|
+
policy.mode,
|
|
880
|
+
`subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`,
|
|
881
|
+
);
|
|
874
882
|
}
|
|
875
883
|
const disallowedByPolicy = requested.find(a => !allowed.has(a));
|
|
876
884
|
if (disallowedByPolicy) {
|
|
877
|
-
return
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
`subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`,
|
|
883
|
-
),
|
|
884
|
-
};
|
|
885
|
+
return planningBlock(
|
|
886
|
+
unitType,
|
|
887
|
+
policy.mode,
|
|
888
|
+
`subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`,
|
|
889
|
+
);
|
|
885
890
|
}
|
|
886
891
|
return { block: false };
|
|
887
892
|
}
|
|
888
|
-
return
|
|
893
|
+
return planningBlock(unitType, policy.mode, "subagent dispatch is not permitted in planning units");
|
|
889
894
|
}
|
|
890
895
|
|
|
891
896
|
if (tool === "bash") {
|
|
892
897
|
if (policy.mode === "verification") {
|
|
893
898
|
if (BASH_VERIFICATION_RE.test(pathOrCommand) || BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
|
|
894
|
-
return
|
|
895
|
-
block: true,
|
|
896
|
-
reason: blockReason(
|
|
897
|
-
unitType,
|
|
898
|
-
policy.mode,
|
|
899
|
-
`bash is restricted to build/test verification commands (npm run build, npm test, etc.); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`,
|
|
900
|
-
),
|
|
901
|
-
};
|
|
902
|
-
}
|
|
903
|
-
if (BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
|
|
904
|
-
return {
|
|
905
|
-
block: true,
|
|
906
|
-
reason: blockReason(
|
|
899
|
+
return planningBlock(
|
|
907
900
|
unitType,
|
|
908
901
|
policy.mode,
|
|
909
|
-
`bash is restricted to
|
|
910
|
-
)
|
|
911
|
-
}
|
|
902
|
+
`bash is restricted to build/test verification commands (npm run build, npm test, etc.); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`,
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
if (BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
|
|
906
|
+
return planningBlock(
|
|
907
|
+
unitType,
|
|
908
|
+
policy.mode,
|
|
909
|
+
`bash is restricted to read-only commands (cat/grep/git log/etc); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`,
|
|
910
|
+
);
|
|
912
911
|
}
|
|
913
912
|
|
|
914
913
|
if (PLANNING_WRITE_TOOLS.has(tool)) {
|
|
915
914
|
if (!pathOrCommand) {
|
|
916
|
-
return
|
|
915
|
+
return planningBlock(unitType, policy.mode, `${tool} called with empty path`);
|
|
917
916
|
}
|
|
918
917
|
const absPath = isAbsolute(pathOrCommand) ? pathOrCommand : resolve(basePath, pathOrCommand);
|
|
919
918
|
|
|
@@ -925,14 +924,11 @@ export function shouldBlockPlanningUnit(
|
|
|
925
924
|
return { block: false };
|
|
926
925
|
}
|
|
927
926
|
|
|
928
|
-
return
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
`cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`,
|
|
934
|
-
),
|
|
935
|
-
};
|
|
927
|
+
return planningBlock(
|
|
928
|
+
unitType,
|
|
929
|
+
policy.mode,
|
|
930
|
+
`cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`,
|
|
931
|
+
);
|
|
936
932
|
}
|
|
937
933
|
|
|
938
934
|
// Unknown tool name — pass through. Other layers (queue, pending-gate,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Shared browser-observable UAT requirement and evidence detection.
|
|
3
3
|
|
|
4
|
-
export const BROWSER_REQUIREMENT_RE = /\b(?:
|
|
4
|
+
export const BROWSER_REQUIREMENT_RE = /\b(?:file:\/\/|localhost|playwright|chrome|screenshot|snapshot|browser_(?:assert|batch|find|verify|snapshot_refs))\b|\b(?:open|launch|navigate|load|visit|serve|start)\b.{0,80}\b(?:browser|page|localhost|file:\/\/)\b|\bbrowser\s+(?:check|session|test|uat|tool|automation|interaction|flow)\b/i;
|
|
5
5
|
export const NO_BROWSER_EVIDENCE_RE = /\b(?:no|without|not|wasn'?t|isn'?t)\s+(?:automated\s+)?(?:live\s+)?browser(?:\s+(?:session|test|uat))?|\bno\s+automated\s+browser\b|\bnot\s+conducted\b/i;
|
|
6
6
|
export const BROWSER_RUNTIME_RE = /\b(?:browser|playwright|chrome|camoufox|browser_(?:assert|batch|find|verify|snapshot_refs)|screenshot|snapshot|file:\/\/|localhost)\b/i;
|
|
7
7
|
export const BROWSER_ACTION_RE = /\b(?:open(?:ed)?|navigate(?:d)?|click(?:ed)?|type(?:d)?|reload(?:ed)?|capture(?:d)?|screenshot|snapshot)\b/i;
|
|
8
8
|
export const BROWSER_ASSERTION_RE = /\b(?:assert(?:ed|ion)?|observed|confirmed|verified|expected|visible|text|count|label|strikethrough|localstorage|screenshot|snapshot|passed)\b/i;
|
|
9
|
+
const NON_REQUIREMENT_BROWSER_HEADING_RE = /^(?:not\s+proven|not\s+covered|out\s+of\s+scope|deferred|follow-?ups?|known\s+limitations|notes\s+for\s+tester)\b/i;
|
|
10
|
+
const NON_REQUIREMENT_BROWSER_LINE_RE = /\b(?:deferred|not\s+proven|not\s+covered|out\s+of\s+scope|future\s+slice|follow-?up|no\s+(?:live\s+)?browser|without\s+(?:a\s+)?browser|not\s+(?:a\s+)?browser)\b/i;
|
|
9
11
|
|
|
10
12
|
export function compactTextParts(parts: Array<string | string[] | null | undefined>): string {
|
|
11
13
|
return parts.flatMap((part) => Array.isArray(part) ? part : [part])
|
|
@@ -14,7 +16,29 @@ export function compactTextParts(parts: Array<string | string[] | null | undefin
|
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export function hasBrowserRequiredText(text: string): boolean {
|
|
17
|
-
|
|
19
|
+
let inNonRequirementSection = false;
|
|
20
|
+
let nonRequirementDepth = 0;
|
|
21
|
+
for (const line of text.split(/\r?\n/)) {
|
|
22
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+?)\s*$/);
|
|
23
|
+
if (headingMatch) {
|
|
24
|
+
const depth = headingMatch[1]!.length;
|
|
25
|
+
const title = headingMatch[2] ?? "";
|
|
26
|
+
// Only update section context when at the same or higher level than the
|
|
27
|
+
// heading that opened the non-requirement zone. A sub-heading deeper than
|
|
28
|
+
// the opening heading must not escape or re-enter the zone on its own.
|
|
29
|
+
if (!inNonRequirementSection || depth <= nonRequirementDepth) {
|
|
30
|
+
inNonRequirementSection = NON_REQUIREMENT_BROWSER_HEADING_RE.test(title);
|
|
31
|
+
nonRequirementDepth = inNonRequirementSection ? depth : 0;
|
|
32
|
+
}
|
|
33
|
+
// Check the heading title itself — section state is already updated, so
|
|
34
|
+
// we correctly skip headings that opened a non-requirement zone.
|
|
35
|
+
if (!inNonRequirementSection && BROWSER_REQUIREMENT_RE.test(title)) return true;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (inNonRequirementSection || NON_REQUIREMENT_BROWSER_LINE_RE.test(line)) continue;
|
|
39
|
+
if (BROWSER_REQUIREMENT_RE.test(line)) return true;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
18
42
|
}
|
|
19
43
|
|
|
20
44
|
export function hasBrowserEvidenceText(text: string): boolean {
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Shared DB-backed guard for milestone closeout finalization.
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
getDbPath,
|
|
6
|
+
getLatestAssessmentByScope,
|
|
7
|
+
getMilestone,
|
|
8
|
+
getMilestoneSlices,
|
|
9
|
+
getPendingGates,
|
|
10
|
+
getSliceTasks,
|
|
11
|
+
isDbAvailable,
|
|
12
|
+
refreshOpenDatabaseFromDisk,
|
|
13
|
+
} from "./gsd-db.js";
|
|
14
|
+
import { isClosedStatus } from "./status-guards.js";
|
|
15
|
+
|
|
16
|
+
export const CLOSEOUT_CONSISTENCY_BLOCKED_REASON = "closeout-consistency-blocked";
|
|
17
|
+
|
|
18
|
+
export type CloseoutConsistencyFailureReason =
|
|
19
|
+
| "db-unavailable"
|
|
20
|
+
| "db-refresh-failed"
|
|
21
|
+
| "milestone-missing"
|
|
22
|
+
| "milestone-open"
|
|
23
|
+
| "validation-not-pass"
|
|
24
|
+
| "slice-missing"
|
|
25
|
+
| "slice-open"
|
|
26
|
+
| "task-open"
|
|
27
|
+
| "quality-gate-pending";
|
|
28
|
+
|
|
29
|
+
export type CloseoutConsistencyResult =
|
|
30
|
+
| { ok: true }
|
|
31
|
+
| {
|
|
32
|
+
ok: false;
|
|
33
|
+
reason: CloseoutConsistencyFailureReason;
|
|
34
|
+
recoveryReason: typeof CLOSEOUT_CONSISTENCY_BLOCKED_REASON;
|
|
35
|
+
message: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export interface CloseoutConsistencyOptions {
|
|
39
|
+
refreshFromDisk?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function blocked(reason: CloseoutConsistencyFailureReason, message: string): CloseoutConsistencyResult {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
reason,
|
|
46
|
+
recoveryReason: CLOSEOUT_CONSISTENCY_BLOCKED_REASON,
|
|
47
|
+
message,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isFileBackedDbPath(path: string | null): boolean {
|
|
52
|
+
return Boolean(path && path !== ":memory:");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function checkCloseoutConsistencyGate(
|
|
56
|
+
milestoneId: string,
|
|
57
|
+
options: CloseoutConsistencyOptions = {},
|
|
58
|
+
): CloseoutConsistencyResult {
|
|
59
|
+
if (!isDbAvailable()) {
|
|
60
|
+
return blocked(
|
|
61
|
+
"db-unavailable",
|
|
62
|
+
`Closeout consistency blocked for ${milestoneId}: canonical DB is unavailable.`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (options.refreshFromDisk && isFileBackedDbPath(getDbPath()) && !refreshOpenDatabaseFromDisk()) {
|
|
67
|
+
return blocked(
|
|
68
|
+
"db-refresh-failed",
|
|
69
|
+
`Closeout consistency blocked for ${milestoneId}: canonical DB refresh failed.`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const milestone = getMilestone(milestoneId);
|
|
74
|
+
if (!milestone) {
|
|
75
|
+
return blocked(
|
|
76
|
+
"milestone-missing",
|
|
77
|
+
`Closeout consistency blocked for ${milestoneId}: milestone is missing from canonical DB.`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
if (!isClosedStatus(milestone.status)) {
|
|
81
|
+
return blocked(
|
|
82
|
+
"milestone-open",
|
|
83
|
+
`Closeout consistency blocked for ${milestoneId}: canonical DB milestone status is "${milestone.status}".`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (milestone.status !== "skipped") {
|
|
88
|
+
const validation = getLatestAssessmentByScope(milestoneId, "milestone-validation");
|
|
89
|
+
if (validation?.status !== "pass") {
|
|
90
|
+
return blocked(
|
|
91
|
+
"validation-not-pass",
|
|
92
|
+
`Closeout consistency blocked for ${milestoneId}: latest milestone validation is "${validation?.status ?? "absent"}".`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const slices = getMilestoneSlices(milestoneId);
|
|
98
|
+
if (slices.length === 0 && milestone.status !== "skipped") {
|
|
99
|
+
return blocked(
|
|
100
|
+
"slice-missing",
|
|
101
|
+
`Closeout consistency blocked for ${milestoneId}: no slices exist in canonical DB.`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const slice of slices) {
|
|
106
|
+
if (!isClosedStatus(slice.status)) {
|
|
107
|
+
return blocked(
|
|
108
|
+
"slice-open",
|
|
109
|
+
`Closeout consistency blocked for ${milestoneId}: slice ${slice.id} status is "${slice.status}".`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for (const task of getSliceTasks(milestoneId, slice.id)) {
|
|
114
|
+
if (!isClosedStatus(task.status)) {
|
|
115
|
+
return blocked(
|
|
116
|
+
"task-open",
|
|
117
|
+
`Closeout consistency blocked for ${milestoneId}: task ${slice.id}/${task.id} status is "${task.status}".`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const pendingGate = getPendingGates(milestoneId, slice.id)[0];
|
|
123
|
+
if (pendingGate) {
|
|
124
|
+
return blocked(
|
|
125
|
+
"quality-gate-pending",
|
|
126
|
+
`Closeout consistency blocked for ${milestoneId}: quality gate ${pendingGate.gate_id} is still pending for ${slice.id}.`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return { ok: true };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function formatCloseoutConsistencyBlock(result: CloseoutConsistencyResult): string {
|
|
135
|
+
if (result.ok) return "";
|
|
136
|
+
return `${result.message} Recovery reason: ${result.recoveryReason}. Resolve the canonical DB state and run /gsd auto to retry.`;
|
|
137
|
+
}
|
|
@@ -282,8 +282,8 @@ Examples:
|
|
|
282
282
|
await handleInspect(ctx);
|
|
283
283
|
return true;
|
|
284
284
|
}
|
|
285
|
-
if (trimmed === "update" || trimmed === "upgrade") {
|
|
286
|
-
await handleUpdate(ctx);
|
|
285
|
+
if (trimmed === "update" || trimmed.startsWith("update ") || trimmed === "upgrade" || trimmed.startsWith("upgrade ")) {
|
|
286
|
+
await handleUpdate(ctx, trimmed.replace(/^(?:update|upgrade)\s*/, "").trim());
|
|
287
287
|
return true;
|
|
288
288
|
}
|
|
289
289
|
if (trimmed === "fast" || trimmed.startsWith("fast ")) {
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
9
9
|
import { existsSync, readFileSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { execFileSync } from "node:child_process";
|
|
11
|
+
import { createRequire } from "node:module";
|
|
10
12
|
import { join, resolve as resolvePath, sep } from "node:path";
|
|
11
13
|
import { homedir } from "node:os";
|
|
12
14
|
import { deriveState } from "./state.js";
|
|
@@ -37,7 +39,10 @@ import {
|
|
|
37
39
|
scopeGsdWorkflowToolsForDispatch,
|
|
38
40
|
} from "./bootstrap/register-hooks.js";
|
|
39
41
|
|
|
42
|
+
const GSD_PI_PACKAGE = "@opengsd/gsd-pi";
|
|
43
|
+
const GSD_BROWSER_PACKAGE = "@opengsd/gsd-browser";
|
|
40
44
|
const UPDATE_REGISTRY_URL = "https://registry.npmjs.org/@opengsd%2fgsd-pi/latest";
|
|
45
|
+
const BROWSER_UPDATE_REGISTRY_URL = "https://registry.npmjs.org/@opengsd%2fgsd-browser/latest";
|
|
41
46
|
const UPDATE_FETCH_TIMEOUT_MS = 5000;
|
|
42
47
|
|
|
43
48
|
// Detects a bun-installed gsd via `process.argv[1]`. Mirrors isBunInstall in
|
|
@@ -62,12 +67,12 @@ function resolveInstallCommand(pkg: string): string {
|
|
|
62
67
|
return `npm install -g ${pkg}`;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
async function fetchLatestVersionForCommand(): Promise<string | null> {
|
|
70
|
+
async function fetchLatestVersionForCommand(registryUrl: string = UPDATE_REGISTRY_URL): Promise<string | null> {
|
|
66
71
|
const controller = new AbortController();
|
|
67
72
|
const timeout = setTimeout(() => controller.abort(), UPDATE_FETCH_TIMEOUT_MS);
|
|
68
73
|
|
|
69
74
|
try {
|
|
70
|
-
const res = await fetch(
|
|
75
|
+
const res = await fetch(registryUrl, { signal: controller.signal });
|
|
71
76
|
if (!res.ok) return null;
|
|
72
77
|
const data = (await res.json()) as { version?: string };
|
|
73
78
|
const latest = typeof data.version === "string" ? data.version.trim().replace(/^v/, "") : "";
|
|
@@ -79,6 +84,19 @@ async function fetchLatestVersionForCommand(): Promise<string | null> {
|
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
86
|
|
|
87
|
+
function resolveInstalledPackageVersionForCommand(packageName: string): string | null {
|
|
88
|
+
try {
|
|
89
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
90
|
+
const packageJsonPath = requireFromHere.resolve(`${packageName}/package.json`);
|
|
91
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as { version?: unknown };
|
|
92
|
+
return typeof pkg.version === "string" && pkg.version.trim().length > 0
|
|
93
|
+
? pkg.version.trim().replace(/^v/, "")
|
|
94
|
+
: null;
|
|
95
|
+
} catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
82
100
|
export function dispatchDoctorHeal(pi: ExtensionAPI, scope: string | undefined, reportText: string, structuredIssues: string): void {
|
|
83
101
|
const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(gsdHome(), "agent", "GSD-WORKFLOW.md");
|
|
84
102
|
const workflow = readFileSync(workflowPath, "utf-8");
|
|
@@ -473,34 +491,81 @@ function compareSemverLocal(a: string, b: string): number {
|
|
|
473
491
|
return 0
|
|
474
492
|
}
|
|
475
493
|
|
|
476
|
-
|
|
494
|
+
function formatCommandVersion(version: string | null): string {
|
|
495
|
+
return version ? `v${version}` : "unknown";
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function pickHigherVersionForCommand(a: string | null, b: string | null): string | null {
|
|
499
|
+
if (!a) return b;
|
|
500
|
+
if (!b) return a;
|
|
501
|
+
return compareSemverLocal(a, b) >= 0 ? a : b;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Mirrors resolveGsdBrowserPathVersion in src/update-check.ts — duplicated because
|
|
505
|
+
// tsconfig.resources.json rootDir prevents importing from src/.
|
|
506
|
+
function resolveGsdBrowserPathVersionForCommand(env: NodeJS.ProcessEnv = process.env): string | null {
|
|
507
|
+
const explicit = env.GSD_BROWSER_PATH_VERSION?.trim();
|
|
508
|
+
if (explicit) return explicit.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
|
|
509
|
+
try {
|
|
510
|
+
const out = execFileSync("gsd-browser", ["--version"], {
|
|
511
|
+
encoding: "utf-8",
|
|
512
|
+
env,
|
|
513
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
514
|
+
timeout: 2000,
|
|
515
|
+
});
|
|
516
|
+
return out.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
|
|
517
|
+
} catch {
|
|
518
|
+
return null;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export async function handleUpdate(ctx: ExtensionCommandContext, args = ""): Promise<void> {
|
|
477
523
|
const { execSync } = await import("node:child_process");
|
|
478
524
|
|
|
479
|
-
const
|
|
480
|
-
const
|
|
525
|
+
const target = args.trim();
|
|
526
|
+
const browserUpdate = target === "browser" || target === "gsd-browser";
|
|
527
|
+
if (target && !browserUpdate) {
|
|
528
|
+
ctx.ui.notify("Usage: /gsd update [browser]", "warning");
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const NPM_PACKAGE = browserUpdate ? GSD_BROWSER_PACKAGE : GSD_PI_PACKAGE;
|
|
533
|
+
const registryUrl = browserUpdate ? BROWSER_UPDATE_REGISTRY_URL : UPDATE_REGISTRY_URL;
|
|
534
|
+
const bundledVersion = browserUpdate
|
|
535
|
+
? resolveInstalledPackageVersionForCommand(GSD_BROWSER_PACKAGE)
|
|
536
|
+
: null;
|
|
537
|
+
const current = browserUpdate
|
|
538
|
+
? pickHigherVersionForCommand(bundledVersion, resolveGsdBrowserPathVersionForCommand())
|
|
539
|
+
: process.env.GSD_VERSION || "0.0.0";
|
|
540
|
+
const label = browserUpdate ? "gsd-browser version" : "version";
|
|
481
541
|
|
|
482
|
-
ctx.ui.notify(`Current
|
|
542
|
+
ctx.ui.notify(`Current ${label}: ${formatCommandVersion(current)}\nChecking npm registry...`, "info");
|
|
483
543
|
|
|
484
|
-
const latest = await fetchLatestVersionForCommand();
|
|
544
|
+
const latest = await fetchLatestVersionForCommand(registryUrl);
|
|
485
545
|
if (!latest) {
|
|
486
546
|
ctx.ui.notify("Failed to reach npm registry. Check your network connection.", "error");
|
|
487
547
|
return;
|
|
488
548
|
}
|
|
489
549
|
|
|
490
|
-
if (compareSemverLocal(latest, current) <= 0) {
|
|
491
|
-
ctx.ui.notify(`Already up to date (
|
|
550
|
+
if (current && compareSemverLocal(latest, current) <= 0) {
|
|
551
|
+
ctx.ui.notify(`Already up to date (${formatCommandVersion(current)}).`, "info");
|
|
492
552
|
return;
|
|
493
553
|
}
|
|
494
554
|
|
|
495
|
-
ctx.ui.notify(`Updating:
|
|
555
|
+
ctx.ui.notify(`Updating: ${formatCommandVersion(current)} → v${latest}...`, "info");
|
|
496
556
|
|
|
497
557
|
const installCmd = resolveInstallCommand(`${NPM_PACKAGE}@latest`);
|
|
498
558
|
try {
|
|
499
559
|
execSync(installCmd, {
|
|
500
560
|
stdio: ["ignore", "pipe", "ignore"],
|
|
501
561
|
});
|
|
562
|
+
const newPathVersion = browserUpdate ? resolveGsdBrowserPathVersionForCommand() : null;
|
|
563
|
+
const pathReady = !browserUpdate || (!!newPathVersion && compareSemverLocal(newPathVersion, latest) >= 0);
|
|
502
564
|
ctx.ui.notify(
|
|
503
|
-
|
|
565
|
+
browserUpdate
|
|
566
|
+
? `Updated gsd-browser to v${latest}. Restart your GSD session to use the new browser automation version.` +
|
|
567
|
+
(pathReady ? "" : "\nNote: Ensure the npm global bin directory is on your PATH so MCP automation uses the updated binary.")
|
|
568
|
+
: `Updated to v${latest}. Restart your GSD session to use the new version.`,
|
|
504
569
|
"info",
|
|
505
570
|
);
|
|
506
571
|
} catch {
|
|
@@ -72,7 +72,8 @@ export function formatMcpInitResult(
|
|
|
72
72
|
`Project: ${targetPath}`,
|
|
73
73
|
`Config: ${configPath}`,
|
|
74
74
|
"",
|
|
75
|
-
"MCP-capable clients can now load the GSD workflow MCP
|
|
75
|
+
"MCP-capable clients can now load the GSD workflow and gsd-browser MCP servers from this folder.",
|
|
76
|
+
"Pi Providers use the managed gsd-browser engine directly; this project config is for External MCP Clients.",
|
|
76
77
|
"Restart or reconnect any client that already has this project open.",
|
|
77
78
|
].join("\n");
|
|
78
79
|
}
|
|
@@ -71,6 +71,14 @@ export class GSDDashboardOverlay {
|
|
|
71
71
|
private refreshInFlight: Promise<void> | null = null;
|
|
72
72
|
private disposed = false;
|
|
73
73
|
private resizeHandler: (() => void) | null = null;
|
|
74
|
+
private cachedMetrics: {
|
|
75
|
+
totals: ReturnType<typeof getProjectTotals>;
|
|
76
|
+
promptStats: ReturnType<typeof getPromptSizeStats>;
|
|
77
|
+
phases: ReturnType<typeof aggregateByPhase>;
|
|
78
|
+
slices: ReturnType<typeof aggregateBySlice>;
|
|
79
|
+
models: ReturnType<typeof aggregateByModel>;
|
|
80
|
+
} | null = null;
|
|
81
|
+
private lastSeenUnitCount = -1;
|
|
74
82
|
|
|
75
83
|
constructor(
|
|
76
84
|
tui: { requestRender: () => void },
|
|
@@ -123,7 +131,8 @@ export class GSDDashboardOverlay {
|
|
|
123
131
|
this.dashData = getAutoDashboardData();
|
|
124
132
|
const nextIdentity = this.computeDashboardIdentity(this.dashData);
|
|
125
133
|
|
|
126
|
-
|
|
134
|
+
const identityChanged = initial || nextIdentity !== this.loadedDashboardIdentity;
|
|
135
|
+
if (identityChanged) {
|
|
127
136
|
const loaded = await this.loadData();
|
|
128
137
|
if (this.disposed) return;
|
|
129
138
|
if (loaded) {
|
|
@@ -135,7 +144,9 @@ export class GSDDashboardOverlay {
|
|
|
135
144
|
this.loading = false;
|
|
136
145
|
}
|
|
137
146
|
|
|
138
|
-
|
|
147
|
+
if (identityChanged) {
|
|
148
|
+
this.invalidate();
|
|
149
|
+
}
|
|
139
150
|
this.tui.requestRender();
|
|
140
151
|
}
|
|
141
152
|
|
|
@@ -459,7 +470,7 @@ export class GSDDashboardOverlay {
|
|
|
459
470
|
|
|
460
471
|
const ledger = getLedger();
|
|
461
472
|
if (ledger && ledger.units.length > 0) {
|
|
462
|
-
const totals =
|
|
473
|
+
const { totals, promptStats, phases, slices, models } = this.ensureMetricsCache(ledger.units);
|
|
463
474
|
|
|
464
475
|
lines.push(blank());
|
|
465
476
|
lines.push(hr());
|
|
@@ -496,7 +507,6 @@ export class GSDDashboardOverlay {
|
|
|
496
507
|
lines.push(row(budgetParts.join(` ${th.fg("dim", "·")} `)));
|
|
497
508
|
}
|
|
498
509
|
|
|
499
|
-
const promptStats = getPromptSizeStats(ledger.units);
|
|
500
510
|
if (promptStats) {
|
|
501
511
|
const promptParts = [
|
|
502
512
|
`${th.fg("dim", "avg prompt:")} ${th.fg("text", formatCharCount(promptStats.averagePromptChars))}`,
|
|
@@ -508,7 +518,6 @@ export class GSDDashboardOverlay {
|
|
|
508
518
|
lines.push(row(promptParts.join(` ${th.fg("dim", "·")} `)));
|
|
509
519
|
}
|
|
510
520
|
|
|
511
|
-
const phases = aggregateByPhase(ledger.units);
|
|
512
521
|
if (phases.length > 0) {
|
|
513
522
|
lines.push(blank());
|
|
514
523
|
lines.push(row(th.fg("dim", "By Phase")));
|
|
@@ -520,7 +529,6 @@ export class GSDDashboardOverlay {
|
|
|
520
529
|
}
|
|
521
530
|
}
|
|
522
531
|
|
|
523
|
-
const slices = aggregateBySlice(ledger.units);
|
|
524
532
|
if (slices.length > 0) {
|
|
525
533
|
lines.push(blank());
|
|
526
534
|
lines.push(row(th.fg("dim", "By Slice")));
|
|
@@ -551,7 +559,6 @@ export class GSDDashboardOverlay {
|
|
|
551
559
|
}
|
|
552
560
|
}
|
|
553
561
|
|
|
554
|
-
const models = aggregateByModel(ledger.units);
|
|
555
562
|
if (models.length >= 1) {
|
|
556
563
|
lines.push(blank());
|
|
557
564
|
lines.push(row(th.fg("dim", "By Model")));
|
|
@@ -625,6 +632,20 @@ export class GSDDashboardOverlay {
|
|
|
625
632
|
return `${th.fg("dim", labelText)}${" ".repeat(gap)}${bar}${" ".repeat(gap)}${th.fg("dim", rightText)}`;
|
|
626
633
|
}
|
|
627
634
|
|
|
635
|
+
private ensureMetricsCache(units: UnitMetrics[]) {
|
|
636
|
+
if (!this.cachedMetrics || units.length !== this.lastSeenUnitCount) {
|
|
637
|
+
this.cachedMetrics = {
|
|
638
|
+
totals: getProjectTotals(units),
|
|
639
|
+
promptStats: getPromptSizeStats(units),
|
|
640
|
+
phases: aggregateByPhase(units),
|
|
641
|
+
slices: aggregateBySlice(units),
|
|
642
|
+
models: aggregateByModel(units),
|
|
643
|
+
};
|
|
644
|
+
this.lastSeenUnitCount = units.length;
|
|
645
|
+
}
|
|
646
|
+
return this.cachedMetrics!;
|
|
647
|
+
}
|
|
648
|
+
|
|
628
649
|
invalidate(): void {
|
|
629
650
|
this.cachedWidth = undefined;
|
|
630
651
|
this.cachedLines = undefined;
|
|
@@ -305,10 +305,18 @@ This config sets a parent workspace with two child repositories. The implicit `p
|
|
|
305
305
|
- `max_cycles`: number — max times this hook fires per trigger (default: 1, max: 10).
|
|
306
306
|
- `model`: string — optional model override.
|
|
307
307
|
- `artifact`: string — expected output file name (relative to task/slice dir). Hook is skipped if file already exists (idempotent).
|
|
308
|
+
- `criticality`: `"advisory"` or `"blocking"` — advisory preserves current best-effort behavior; blocking requires clean hook completion plus a valid outcome verdict before auto-mode advances. Default: `"advisory"`.
|
|
308
309
|
- `retry_on`: string — if this file is produced instead of the artifact, re-run the trigger unit then re-run hooks.
|
|
310
|
+
- `on_block`: object — optional routing for blocking findings:
|
|
311
|
+
- `action`: `"retry-unit"`, `"retry-task"`, `"queue-task"`, `"queue-slice"`, or `"pause"`.
|
|
312
|
+
- `artifact`: string — optional compatibility artifact for retry routing.
|
|
309
313
|
- `agent`: string — agent definition file to use for hook execution.
|
|
310
314
|
- `enabled`: boolean — toggle without removing (default: `true`).
|
|
311
315
|
|
|
316
|
+
Blocking hook artifacts must begin with YAML frontmatter containing either `verdict` or `outcome.verdict`.
|
|
317
|
+
Supported verdicts are `pass`, `advisory`, `needs-rework`, `needs-remediation`, and `needs-attention`.
|
|
318
|
+
`pass` and `advisory` continue; `needs-rework` retries the trigger unit when routed with `retry-unit`/`retry-task`; `needs-remediation` and `needs-attention` pause with recovery guidance.
|
|
319
|
+
|
|
312
320
|
- `pre_dispatch_hooks`: array — hooks that fire before a unit is dispatched. Each entry has:
|
|
313
321
|
- `name`: string — unique hook identifier.
|
|
314
322
|
- `before`: string[] — unit types to intercept.
|
|
@@ -269,14 +269,14 @@ export async function checkRuntimeHealth(
|
|
|
269
269
|
} catch {
|
|
270
270
|
count = MAX_UAT_ATTEMPTS + 1;
|
|
271
271
|
}
|
|
272
|
-
if (count
|
|
272
|
+
if (count < MAX_UAT_ATTEMPTS) continue;
|
|
273
273
|
|
|
274
274
|
issues.push({
|
|
275
275
|
severity: "warning",
|
|
276
276
|
code: "uat_retry_exhausted",
|
|
277
277
|
scope: "slice",
|
|
278
278
|
unitId: `${mid}/${sid}`,
|
|
279
|
-
message: `run-uat for ${mid}/${sid} exhausted ${count
|
|
279
|
+
message: `run-uat for ${mid}/${sid} exhausted ${count} attempt(s) without an ASSESSMENT verdict. Reset the retry counter after fixing the underlying UAT/tool issue, then rerun /gsd auto.`,
|
|
280
280
|
file: `.gsd/runtime/${fileName}`,
|
|
281
281
|
fixable: true,
|
|
282
282
|
});
|