@opengsd/gsd-pi 1.1.1-dev.74e8dd1 → 1.1.1-dev.a5a2de8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +3 -2
- package/dist/help-text.js +10 -6
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +495 -0
- package/dist/resources/extensions/browser-tools/engine/selection.js +16 -0
- package/dist/resources/extensions/browser-tools/extension-manifest.json +2 -2
- package/dist/resources/extensions/browser-tools/index.js +57 -9
- package/dist/resources/extensions/browser-tools/package.json +5 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +77 -13
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +21 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +63 -22
- package/dist/resources/extensions/gsd/auto-recovery.js +3 -4
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +18 -66
- package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
- package/dist/resources/extensions/gsd/auto.js +9 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +20 -14
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +28 -13
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +18 -29
- package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
- package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -1
- package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
- package/dist/resources/extensions/gsd/escalation.js +4 -4
- package/dist/resources/extensions/gsd/forensics.js +74 -2
- package/dist/resources/extensions/gsd/gsd-db.js +5 -2
- package/dist/resources/extensions/gsd/guided-flow.js +118 -175
- package/dist/resources/extensions/gsd/mcp-project-config.js +9 -76
- package/dist/resources/extensions/gsd/memory-store.js +4 -1
- package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
- package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
- package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
- package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +25 -21
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
- package/dist/resources/extensions/gsd/rule-registry.js +428 -52
- package/dist/resources/extensions/gsd/state.js +2 -2
- package/dist/resources/extensions/gsd/templates/plan.md +3 -1
- package/dist/resources/extensions/gsd/tool-contract.js +5 -0
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +17 -7
- package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +132 -18
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -0
- package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
- package/dist/resources/extensions/gsd/verification-gate.js +72 -1
- package/dist/resources/extensions/gsd/workflow-mcp.js +3 -75
- package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
- package/dist/rtk.d.ts +7 -1
- package/dist/rtk.js +27 -11
- package/dist/update-check.d.ts +15 -1
- package/dist/update-check.js +87 -12
- package/dist/update-cmd.d.ts +1 -0
- package/dist/update-cmd.js +53 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +4 -2
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +32 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- package/packages/gsd-agent-core/dist/index.d.ts +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +1 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
- package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
- package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
- package/packages/gsd-agent-core/package.json +6 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +20 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
- package/packages/mcp-server/dist/remote-questions.js +23 -9
- package/packages/mcp-server/dist/remote-questions.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +2 -2
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +42 -3
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
- package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +6 -1
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/api-registry.d.ts +2 -0
- package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
- package/packages/pi-ai/dist/api-registry.js +23 -0
- package/packages/pi-ai/dist/api-registry.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +74 -6
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +78 -10
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/stream.js +6 -6
- package/packages/pi-ai/dist/stream.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
- package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
- package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
- package/src/resources/extensions/browser-tools/index.ts +60 -9
- package/src/resources/extensions/browser-tools/package.json +5 -1
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +82 -14
- package/src/resources/extensions/gsd/auto-dispatch.ts +19 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +28 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +97 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +3 -3
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -74
- package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
- package/src/resources/extensions/gsd/auto.ts +12 -2
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +20 -14
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +32 -13
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +50 -54
- package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
- package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -1
- package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
- package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
- package/src/resources/extensions/gsd/escalation.ts +4 -4
- package/src/resources/extensions/gsd/forensics.ts +99 -5
- package/src/resources/extensions/gsd/gsd-db.ts +5 -2
- package/src/resources/extensions/gsd/guided-flow.ts +214 -216
- package/src/resources/extensions/gsd/mcp-project-config.ts +13 -78
- package/src/resources/extensions/gsd/memory-store.ts +4 -1
- package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
- package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +25 -21
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
- package/src/resources/extensions/gsd/rule-registry.ts +558 -58
- package/src/resources/extensions/gsd/rule-types.ts +2 -0
- package/src/resources/extensions/gsd/state.ts +2 -2
- package/src/resources/extensions/gsd/templates/plan.md +3 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +105 -4
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
- package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +69 -10
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +351 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -0
- package/src/resources/extensions/gsd/tool-contract.ts +6 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +38 -8
- package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +163 -20
- package/src/resources/extensions/gsd/types.ts +69 -5
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -0
- package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
- package/src/resources/extensions/gsd/verification-gate.ts +87 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +3 -75
- package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
- /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → 9y3LeeR2uGr2yRj9RjY3D}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → 9y3LeeR2uGr2yRj9RjY3D}/_ssgManifest.js +0 -0
|
@@ -1774,10 +1774,17 @@ export function createWiredAutoOrchestrationModule(ctx, pi, dispatchBasePath, ru
|
|
|
1774
1774
|
async reconcileBeforeDispatch() {
|
|
1775
1775
|
const activeBasePath = getLiveDispatchBasePath();
|
|
1776
1776
|
const result = await reconcileBeforeDispatch(activeBasePath);
|
|
1777
|
-
|
|
1777
|
+
// Failure-path summaries written by gsd_summary_save create
|
|
1778
|
+
// artifact-db-status-divergence blockers for tasks that are still
|
|
1779
|
+
// pending (gsd_task_complete never ran). These tasks can still be
|
|
1780
|
+
// dispatched and the drift self-heals once they complete successfully.
|
|
1781
|
+
const hardBlockers = result.blockers.filter((b) => !b.includes("has SUMMARY artifact while DB status is") &&
|
|
1782
|
+
!b.includes("has SUMMARY on disk while DB status is") &&
|
|
1783
|
+
!b.includes("has task SUMMARY artifacts but no DB tasks"));
|
|
1784
|
+
if (hardBlockers.length > 0) {
|
|
1778
1785
|
return {
|
|
1779
1786
|
ok: false,
|
|
1780
|
-
reason:
|
|
1787
|
+
reason: hardBlockers[0],
|
|
1781
1788
|
stateSnapshot: result.stateSnapshot,
|
|
1782
1789
|
};
|
|
1783
1790
|
}
|
|
@@ -65,6 +65,9 @@ function readDetails(result) {
|
|
|
65
65
|
}
|
|
66
66
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- result shape varies by tool
|
|
67
67
|
function formatToolErrorText(result, details) {
|
|
68
|
+
if (typeof details?.displayReason === "string" && details.displayReason) {
|
|
69
|
+
return details.displayReason;
|
|
70
|
+
}
|
|
68
71
|
const message = details?.error
|
|
69
72
|
?? result?.content?.find((entry) => entry.type === "text")?.text
|
|
70
73
|
?? "unknown";
|
|
@@ -405,6 +408,9 @@ export function registerDbTools(pi) {
|
|
|
405
408
|
kind: StringEnum(["gsd_uat_exec", "gsd_exec", "screenshot", "log", "url", "browser"], { description: "Evidence kind" }),
|
|
406
409
|
ref: Type.String({ description: "Evidence ID, approved .gsd path, or URL" }),
|
|
407
410
|
note: Type.Optional(Type.String({ description: "Short evidence note" })),
|
|
411
|
+
unitType: Type.Optional(Type.String({ description: "Unit that produced the evidence" })),
|
|
412
|
+
tool: Type.Optional(Type.String({ description: "Tool that produced the evidence" })),
|
|
413
|
+
executionId: Type.Optional(Type.String({ description: "Stable execution or artifact id" })),
|
|
408
414
|
});
|
|
409
415
|
const uatCheck = Type.Object({
|
|
410
416
|
id: Type.String({ description: "Stable check ID from the UAT spec" }),
|
|
@@ -416,17 +422,17 @@ export function registerDbTools(pi) {
|
|
|
416
422
|
nonAutomatable: Type.Optional(Type.Boolean({ description: "True when the check is explicitly non-automatable" })),
|
|
417
423
|
});
|
|
418
424
|
const toolPresentationBlock = Type.Object({
|
|
419
|
-
surface: StringEnum(["provider-tools", "claude-code-sdk", "mcp", "hybrid"], { description: "Tool presentation surface" }),
|
|
425
|
+
surface: Type.Optional(StringEnum(["provider-tools", "claude-code-sdk", "mcp", "hybrid"], { description: "Tool presentation surface" })),
|
|
420
426
|
model: Type.Optional(Type.Object({
|
|
421
427
|
provider: Type.Optional(Type.String()),
|
|
422
428
|
api: Type.Optional(Type.String()),
|
|
423
429
|
id: Type.Optional(Type.String()),
|
|
424
430
|
})),
|
|
425
|
-
presentedTools: Type.Array(Type.String(), { description: "Tool names actually presented to the model" }),
|
|
426
|
-
blockedTools: Type.Array(Type.Object({
|
|
431
|
+
presentedTools: Type.Optional(Type.Array(Type.String(), { description: "Tool names actually presented to the model" })),
|
|
432
|
+
blockedTools: Type.Optional(Type.Array(Type.Object({
|
|
427
433
|
name: Type.String(),
|
|
428
434
|
reason: Type.String(),
|
|
429
|
-
}), { description: "Tool names blocked from the model with reasons" }),
|
|
435
|
+
}), { description: "Tool names blocked from the model with reasons" })),
|
|
430
436
|
aliases: Type.Optional(Type.Array(Type.Object({
|
|
431
437
|
requested: Type.String(),
|
|
432
438
|
canonical: Type.String(),
|
|
@@ -448,12 +454,12 @@ export function registerDbTools(pi) {
|
|
|
448
454
|
"Do not use raw gsd_summary_save as a substitute for UAT results.",
|
|
449
455
|
],
|
|
450
456
|
parameters: Type.Object({
|
|
451
|
-
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
452
|
-
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
453
|
-
uatType:
|
|
454
|
-
verdict:
|
|
455
|
-
checks: Type.Array(uatCheck, { description: "Structured check results" }),
|
|
456
|
-
presentation: toolPresentationBlock,
|
|
457
|
+
milestoneId: Type.Optional(Type.String({ description: "Milestone ID (e.g. M001)" })),
|
|
458
|
+
sliceId: Type.Optional(Type.String({ description: "Slice ID (e.g. S01)" })),
|
|
459
|
+
uatType: Type.Optional(Type.String({ description: "Declared UAT mode" })),
|
|
460
|
+
verdict: Type.Optional(Type.String({ description: "Overall UAT verdict: PASS, FAIL, or PARTIAL" })),
|
|
461
|
+
checks: Type.Optional(Type.Array(uatCheck, { description: "Structured check results" })),
|
|
462
|
+
presentation: Type.Optional(toolPresentationBlock),
|
|
457
463
|
notes: Type.Optional(Type.String({ description: "Overall verdict rationale" })),
|
|
458
464
|
attempt: Type.Optional(Type.String({ description: "Attempt number or auto" })),
|
|
459
465
|
previousAttemptId: Type.Optional(Type.String({ description: "Prior attempt ID, when retrying" })),
|
|
@@ -788,7 +794,7 @@ export function registerDbTools(pi) {
|
|
|
788
794
|
recommendation: Type.String({ description: "Option id the executor recommends." }),
|
|
789
795
|
recommendationRationale: Type.String({ description: "Why the recommendation — 1–2 sentences." }),
|
|
790
796
|
continueWithDefault: Type.Boolean({
|
|
791
|
-
description: "When true,
|
|
797
|
+
description: "When true, the recommendation is recorded as the default, but auto-mode still pauses until the user resolves via /gsd escalate resolve.",
|
|
792
798
|
}),
|
|
793
799
|
}, { description: "ADR-011 Phase 2: optional escalation payload. Only honored when phases.mid_execution_escalation is true." })),
|
|
794
800
|
verificationEvidence: Type.Optional(Type.Array(Type.Object({
|
|
@@ -829,7 +835,7 @@ export function registerDbTools(pi) {
|
|
|
829
835
|
sliceTitle: Type.String({ description: "Title of the slice" }),
|
|
830
836
|
oneLiner: Type.String({ description: "One-line summary of what the slice accomplished" }),
|
|
831
837
|
narrative: Type.String({ description: "Detailed narrative of what happened across all tasks" }),
|
|
832
|
-
verification: Type.String({ description: "What was verified across all tasks" }),
|
|
838
|
+
verification: Type.Optional(Type.String({ description: "What was verified across all tasks — if omitted, summary records verification as passed without detail." })),
|
|
833
839
|
uatContent: Type.String({ description: "UAT test content (markdown body)" }),
|
|
834
840
|
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
835
841
|
deviations: Type.Optional(Type.String({ description: "Deviations from the slice plan, or 'None.'" })),
|
|
@@ -1010,7 +1016,7 @@ export function registerDbTools(pi) {
|
|
|
1010
1016
|
promptGuidelines: [
|
|
1011
1017
|
"Use gsd_validate_milestone when all slices are done and the milestone needs validation before completion.",
|
|
1012
1018
|
"Parameters: milestoneId, verdict, remediationRound, successCriteriaChecklist, sliceDeliveryAudit, crossSliceIntegration, requirementCoverage, verificationClasses (optional), verdictRationale, remediationPlan (optional).",
|
|
1013
|
-
"If verification classes were planned, verificationClasses must
|
|
1019
|
+
"If verification classes were planned, verificationClasses must be a complete canonical table with one row for every applicable planned class using the exact class names Contract, Integration, Operational, and UAT. Do not submit a partial table.",
|
|
1014
1020
|
"Planned verification text marked as none/not required/not applicable/N/A (including suffixed variants such as 'not required - backend-only') is treated as not applicable and does not require a class row.",
|
|
1015
1021
|
"If verdict is 'needs-remediation', also provide remediationPlan and use gsd_reassess_roadmap to add remediation slices to the roadmap.",
|
|
1016
1022
|
"On success, returns validationPath where VALIDATION.md was written.",
|
|
@@ -1023,7 +1029,7 @@ export function registerDbTools(pi) {
|
|
|
1023
1029
|
sliceDeliveryAudit: Type.String({ description: "Markdown table auditing each slice's claimed vs delivered output" }),
|
|
1024
1030
|
crossSliceIntegration: Type.String({ description: "Markdown describing any cross-slice boundary mismatches" }),
|
|
1025
1031
|
requirementCoverage: Type.String({ description: "Markdown describing any unaddressed requirements" }),
|
|
1026
|
-
verificationClasses: Type.Optional(Type.String({ description: "
|
|
1032
|
+
verificationClasses: Type.Optional(Type.String({ description: "Complete markdown table describing verification class compliance and gaps; include one canonical row for every applicable planned class (Contract, Integration, Operational, UAT)" })),
|
|
1027
1033
|
verdictRationale: Type.String({ description: "Why this verdict was chosen" }),
|
|
1028
1034
|
remediationPlan: Type.Optional(Type.String({ description: "Remediation plan (required if verdict is needs-remediation)" })),
|
|
1029
1035
|
}),
|
|
@@ -11,7 +11,7 @@ import { canonicalToolName, clearDiscussionFlowState, isDepthConfirmationAnswer,
|
|
|
11
11
|
import { resolveManifest } from "../unit-context-manifest.js";
|
|
12
12
|
import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
|
|
13
13
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
14
|
-
import { clearToolInvocationError, getAutoRuntimeSnapshot, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
|
|
14
|
+
import { clearToolInvocationError, getAutoRuntimeSnapshot, isAutoActive, isAutoCompletionStopInProgress, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
|
|
15
15
|
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
16
16
|
import { maybePauseAutoForApprovalGate, resetPendingGatePauseGuard } from "./pending-gate-pause.js";
|
|
17
17
|
import { saveActivityLog } from "../activity-log.js";
|
|
@@ -30,7 +30,7 @@ import { getGuidedUnitContext } from "../guided-unit-context.js";
|
|
|
30
30
|
import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
|
|
31
31
|
import { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
|
|
32
32
|
import { filterToolsForProvider } from "../model-router.js";
|
|
33
|
-
import { RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
|
|
33
|
+
import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
|
|
34
34
|
let approvalQuestionAbortInFlight = false;
|
|
35
35
|
async function loadWelcomeScreenModule() {
|
|
36
36
|
const candidates = [];
|
|
@@ -204,7 +204,12 @@ export function buildMinimalAutoGsdToolSet(activeToolNames, unitType, registered
|
|
|
204
204
|
return withPreservedShimTools([...new Set([...preserved, ...scoped])]);
|
|
205
205
|
}
|
|
206
206
|
export function buildRunUatGsdToolSet(activeToolNames, registeredToolNames = activeToolNames) {
|
|
207
|
-
const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], [
|
|
207
|
+
const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], [
|
|
208
|
+
...RUN_UAT_WORKFLOW_TOOL_NAMES,
|
|
209
|
+
...RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
210
|
+
"subagent",
|
|
211
|
+
...RUN_UAT_BROWSER_TOOL_NAMES,
|
|
212
|
+
]);
|
|
208
213
|
return [...new Set(scoped)];
|
|
209
214
|
}
|
|
210
215
|
export function buildMinimalGsdWorkflowToolSet(activeToolNames, registeredToolNames = activeToolNames) {
|
|
@@ -382,6 +387,11 @@ function isContextDraftSummarySave(toolName, input) {
|
|
|
382
387
|
return false;
|
|
383
388
|
return input.artifact_type === "CONTEXT-DRAFT";
|
|
384
389
|
}
|
|
390
|
+
function withDepthGateDisplayReason(result, displayReason = "Depth confirmation is waiting for your answer.") {
|
|
391
|
+
if (!result.block)
|
|
392
|
+
return result;
|
|
393
|
+
return { ...result, displayReason };
|
|
394
|
+
}
|
|
385
395
|
function shouldBlockDeferredApprovalTool(toolName, input, basePath) {
|
|
386
396
|
if (deferredApprovalGate?.basePath !== basePath)
|
|
387
397
|
return { block: false };
|
|
@@ -389,14 +399,14 @@ function shouldBlockDeferredApprovalTool(toolName, input, basePath) {
|
|
|
389
399
|
return { block: false };
|
|
390
400
|
if (isContextDraftSummarySave(toolName, input))
|
|
391
401
|
return { block: false };
|
|
392
|
-
return {
|
|
402
|
+
return withDepthGateDisplayReason({
|
|
393
403
|
block: true,
|
|
394
404
|
reason: [
|
|
395
405
|
`HARD BLOCK: Approval question "${deferredApprovalGate.gateId}" has been shown to the user.`,
|
|
396
406
|
`Only CONTEXT-DRAFT persistence may finish in this same assistant turn.`,
|
|
397
407
|
`Wait for the user's answer before calling additional tools.`,
|
|
398
408
|
].join(" "),
|
|
399
|
-
};
|
|
409
|
+
});
|
|
400
410
|
}
|
|
401
411
|
export function resolveNotificationStoreBasePath(basePath) {
|
|
402
412
|
return resolveWorktreeProjectRoot(basePath);
|
|
@@ -424,8 +434,9 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
424
434
|
registerPlanMilestoneSchemaRecovery(pi);
|
|
425
435
|
pi.on("session_start", async (_event, ctx) => {
|
|
426
436
|
const basePath = contextBasePath(ctx);
|
|
437
|
+
const preserveCloseoutSurface = isAutoCompletionStopInProgress();
|
|
427
438
|
initSessionNotifications(ctx);
|
|
428
|
-
if (!isAutoActive()) {
|
|
439
|
+
if (!isAutoActive() && !preserveCloseoutSurface) {
|
|
429
440
|
const { initHealthWidget } = await import("../health-widget.js");
|
|
430
441
|
initHealthWidget(ctx);
|
|
431
442
|
}
|
|
@@ -445,14 +456,17 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
445
456
|
process.env.GSD_SHOW_TOKEN_COST = prefs?.preferences.show_token_cost ? "1" : "";
|
|
446
457
|
}
|
|
447
458
|
catch { /* non-fatal */ }
|
|
448
|
-
|
|
459
|
+
if (!preserveCloseoutSurface) {
|
|
460
|
+
await installWelcomeHeader(ctx);
|
|
461
|
+
}
|
|
449
462
|
await loadToolApiKeysForSession();
|
|
450
|
-
if (isAutoActive()) {
|
|
463
|
+
if (isAutoActive() || preserveCloseoutSurface) {
|
|
451
464
|
ctx.ui.setWidget("gsd-health", undefined);
|
|
452
465
|
}
|
|
453
466
|
});
|
|
454
467
|
pi.on("session_switch", async (_event, ctx) => {
|
|
455
468
|
const basePath = contextBasePath(ctx);
|
|
469
|
+
const preserveCloseoutSurface = isAutoCompletionStopInProgress();
|
|
456
470
|
initSessionNotifications(ctx);
|
|
457
471
|
resetWriteGateState(basePath);
|
|
458
472
|
resetToolCallLoopGuard();
|
|
@@ -464,7 +478,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
464
478
|
await applyCompactionThresholdOverride(ctx);
|
|
465
479
|
await prepareWorkflowMcpForHookContext(ctx, basePath);
|
|
466
480
|
await loadToolApiKeysForSession();
|
|
467
|
-
if (!isAutoActive()) {
|
|
481
|
+
if (!isAutoActive() && !preserveCloseoutSurface) {
|
|
468
482
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
469
483
|
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
470
484
|
const { initHealthWidget } = await import("../health-widget.js");
|
|
@@ -750,7 +764,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
750
764
|
if (ctx) {
|
|
751
765
|
await maybePauseAutoForApprovalGate(ctx, pi, true, "Depth confirmation is waiting for your answer — pausing auto-mode.");
|
|
752
766
|
}
|
|
753
|
-
return bashGuard;
|
|
767
|
+
return withDepthGateDisplayReason(bashGuard);
|
|
754
768
|
}
|
|
755
769
|
}
|
|
756
770
|
else {
|
|
@@ -759,7 +773,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
759
773
|
if (ctx) {
|
|
760
774
|
await maybePauseAutoForApprovalGate(ctx, pi, true, "Depth confirmation is waiting for your answer — pausing auto-mode.");
|
|
761
775
|
}
|
|
762
|
-
return gateGuard;
|
|
776
|
+
return withDepthGateDisplayReason(gateGuard);
|
|
763
777
|
}
|
|
764
778
|
}
|
|
765
779
|
}
|
|
@@ -843,8 +857,9 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
843
857
|
if (!isToolCallEventType("write", event))
|
|
844
858
|
return;
|
|
845
859
|
const result = shouldBlockContextWrite(event.toolName, event.input.path, await getDiscussionMilestoneIdFor(discussionBasePath), isQueuePhaseActive(discussionBasePath), discussionBasePath);
|
|
846
|
-
if (result.block)
|
|
847
|
-
return result;
|
|
860
|
+
if (result.block) {
|
|
861
|
+
return withDepthGateDisplayReason(result, "Depth check required before writing milestone context.");
|
|
862
|
+
}
|
|
848
863
|
});
|
|
849
864
|
// ── Safety harness: evidence collection + destructive command blocking ──
|
|
850
865
|
pi.on("tool_call", async (event, ctx) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { minimatch } from "minimatch";
|
|
5
|
-
import { shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
|
|
5
|
+
import { GSD_PHASE_SCOPE_DISPLAY_REASON, shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
|
|
6
6
|
import { getIsolationMode } from "../preferences.js";
|
|
7
7
|
import { compileSubagentPermissionContract } from "../unit-context-manifest.js";
|
|
8
8
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -643,6 +643,13 @@ function blockReason(unitType, mode, what) {
|
|
|
643
643
|
`the work belongs in execute-task, not in a planning unit.`,
|
|
644
644
|
].join(" ");
|
|
645
645
|
}
|
|
646
|
+
function planningBlock(unitType, mode, what) {
|
|
647
|
+
return {
|
|
648
|
+
block: true,
|
|
649
|
+
reason: blockReason(unitType, mode, what),
|
|
650
|
+
displayReason: GSD_PHASE_SCOPE_DISPLAY_REASON,
|
|
651
|
+
};
|
|
652
|
+
}
|
|
646
653
|
/**
|
|
647
654
|
* Planning-unit tool-policy enforcement. Returns { block } per the policy
|
|
648
655
|
* resolved from the active unit's manifest:
|
|
@@ -690,10 +697,10 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
690
697
|
if (tool.startsWith("gsd_"))
|
|
691
698
|
return { block: false };
|
|
692
699
|
if (PLANNING_WRITE_TOOLS.has(tool) || tool === "bash" || PLANNING_SUBAGENT_TOOLS.has(tool)) {
|
|
693
|
-
return
|
|
700
|
+
return planningBlock(unitType, policy.mode, `${tool} is not permitted (read-only)`);
|
|
694
701
|
}
|
|
695
702
|
// Unknown tool in read-only mode — block by default.
|
|
696
|
-
return
|
|
703
|
+
return planningBlock(unitType, policy.mode, `tool "${tool}" is not on the read-only allowlist`);
|
|
697
704
|
}
|
|
698
705
|
// planning / planning-dispatch / docs / verification modes share the same surface for safe tools, bash, and subagent.
|
|
699
706
|
if (PLANNING_SAFE_TOOLS.has(tool))
|
|
@@ -711,10 +718,7 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
711
718
|
// instead of silently bypassing the gate.
|
|
712
719
|
if (agentClasses === undefined) {
|
|
713
720
|
warnMissingControlledDispatchAgentClasses(unitType, policy.mode, tool);
|
|
714
|
-
return {
|
|
715
|
-
block: true,
|
|
716
|
-
reason: blockReason(unitType, policy.mode, `subagent dispatch blocked: stale caller did not supply agent identities for "${tool}"; update extractSubagentAgentClasses to handle this input shape`),
|
|
717
|
-
};
|
|
721
|
+
return planningBlock(unitType, policy.mode, `subagent dispatch blocked: stale caller did not supply agent identities for "${tool}"; update extractSubagentAgentClasses to handle this input shape`);
|
|
718
722
|
}
|
|
719
723
|
// agentClasses was explicitly provided but resolved to an empty list (for
|
|
720
724
|
// example, a bare tool call with no agent field). Pass through; no agents
|
|
@@ -724,41 +728,29 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
724
728
|
}
|
|
725
729
|
const globallyDisallowed = requested.find(a => !isReadOnlySpecialist(a));
|
|
726
730
|
if (globallyDisallowed) {
|
|
727
|
-
return {
|
|
728
|
-
block: true,
|
|
729
|
-
reason: blockReason(unitType, policy.mode, `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`),
|
|
730
|
-
};
|
|
731
|
+
return planningBlock(unitType, policy.mode, `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`);
|
|
731
732
|
}
|
|
732
733
|
const disallowedByPolicy = requested.find(a => !allowed.has(a));
|
|
733
734
|
if (disallowedByPolicy) {
|
|
734
|
-
return {
|
|
735
|
-
block: true,
|
|
736
|
-
reason: blockReason(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`),
|
|
737
|
-
};
|
|
735
|
+
return planningBlock(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`);
|
|
738
736
|
}
|
|
739
737
|
return { block: false };
|
|
740
738
|
}
|
|
741
|
-
return
|
|
739
|
+
return planningBlock(unitType, policy.mode, "subagent dispatch is not permitted in planning units");
|
|
742
740
|
}
|
|
743
741
|
if (tool === "bash") {
|
|
744
742
|
if (policy.mode === "verification") {
|
|
745
743
|
if (BASH_VERIFICATION_RE.test(pathOrCommand) || BASH_READ_ONLY_RE.test(pathOrCommand))
|
|
746
744
|
return { block: false };
|
|
747
|
-
return {
|
|
748
|
-
block: true,
|
|
749
|
-
reason: blockReason(unitType, policy.mode, `bash is restricted to build/test verification commands (npm run build, npm test, etc.); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`),
|
|
750
|
-
};
|
|
745
|
+
return planningBlock(unitType, policy.mode, `bash is restricted to build/test verification commands (npm run build, npm test, etc.); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`);
|
|
751
746
|
}
|
|
752
747
|
if (BASH_READ_ONLY_RE.test(pathOrCommand))
|
|
753
748
|
return { block: false };
|
|
754
|
-
return {
|
|
755
|
-
block: true,
|
|
756
|
-
reason: blockReason(unitType, policy.mode, `bash is restricted to read-only commands (cat/grep/git log/etc); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`),
|
|
757
|
-
};
|
|
749
|
+
return planningBlock(unitType, policy.mode, `bash is restricted to read-only commands (cat/grep/git log/etc); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`);
|
|
758
750
|
}
|
|
759
751
|
if (PLANNING_WRITE_TOOLS.has(tool)) {
|
|
760
752
|
if (!pathOrCommand) {
|
|
761
|
-
return
|
|
753
|
+
return planningBlock(unitType, policy.mode, `${tool} called with empty path`);
|
|
762
754
|
}
|
|
763
755
|
const absPath = isAbsolute(pathOrCommand) ? pathOrCommand : resolve(basePath, pathOrCommand);
|
|
764
756
|
// Always allow .gsd/ writes — that's where planning artifacts live.
|
|
@@ -768,10 +760,7 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
768
760
|
if (policy.mode === "docs" && matchesAllowedGlob(absPath, basePath, policy.allowedPathGlobs)) {
|
|
769
761
|
return { block: false };
|
|
770
762
|
}
|
|
771
|
-
return {
|
|
772
|
-
block: true,
|
|
773
|
-
reason: blockReason(unitType, policy.mode, `cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`),
|
|
774
|
-
};
|
|
763
|
+
return planningBlock(unitType, policy.mode, `cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`);
|
|
775
764
|
}
|
|
776
765
|
// Unknown tool name — pass through. Other layers (queue, pending-gate,
|
|
777
766
|
// CONTEXT.md write) catch known mutating shapes; defaulting to allow here
|
|
@@ -1,17 +1,44 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Shared browser-observable UAT requirement and evidence detection.
|
|
3
|
-
export const BROWSER_REQUIREMENT_RE = /\b(?:
|
|
3
|
+
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;
|
|
4
4
|
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;
|
|
5
5
|
export const BROWSER_RUNTIME_RE = /\b(?:browser|playwright|chrome|camoufox|browser_(?:assert|batch|find|verify|snapshot_refs)|screenshot|snapshot|file:\/\/|localhost)\b/i;
|
|
6
6
|
export const BROWSER_ACTION_RE = /\b(?:open(?:ed)?|navigate(?:d)?|click(?:ed)?|type(?:d)?|reload(?:ed)?|capture(?:d)?|screenshot|snapshot)\b/i;
|
|
7
7
|
export const BROWSER_ASSERTION_RE = /\b(?:assert(?:ed|ion)?|observed|confirmed|verified|expected|visible|text|count|label|strikethrough|localstorage|screenshot|snapshot|passed)\b/i;
|
|
8
|
+
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;
|
|
9
|
+
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;
|
|
8
10
|
export function compactTextParts(parts) {
|
|
9
11
|
return parts.flatMap((part) => Array.isArray(part) ? part : [part])
|
|
10
12
|
.filter((part) => typeof part === "string" && part.trim().length > 0)
|
|
11
13
|
.join("\n");
|
|
12
14
|
}
|
|
13
15
|
export function hasBrowserRequiredText(text) {
|
|
14
|
-
|
|
16
|
+
let inNonRequirementSection = false;
|
|
17
|
+
let nonRequirementDepth = 0;
|
|
18
|
+
for (const line of text.split(/\r?\n/)) {
|
|
19
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+?)\s*$/);
|
|
20
|
+
if (headingMatch) {
|
|
21
|
+
const depth = headingMatch[1].length;
|
|
22
|
+
const title = headingMatch[2] ?? "";
|
|
23
|
+
// Only update section context when at the same or higher level than the
|
|
24
|
+
// heading that opened the non-requirement zone. A sub-heading deeper than
|
|
25
|
+
// the opening heading must not escape or re-enter the zone on its own.
|
|
26
|
+
if (!inNonRequirementSection || depth <= nonRequirementDepth) {
|
|
27
|
+
inNonRequirementSection = NON_REQUIREMENT_BROWSER_HEADING_RE.test(title);
|
|
28
|
+
nonRequirementDepth = inNonRequirementSection ? depth : 0;
|
|
29
|
+
}
|
|
30
|
+
// Check the heading title itself — section state is already updated, so
|
|
31
|
+
// we correctly skip headings that opened a non-requirement zone.
|
|
32
|
+
if (!inNonRequirementSection && BROWSER_REQUIREMENT_RE.test(title))
|
|
33
|
+
return true;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (inNonRequirementSection || NON_REQUIREMENT_BROWSER_LINE_RE.test(line))
|
|
37
|
+
continue;
|
|
38
|
+
if (BROWSER_REQUIREMENT_RE.test(line))
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
15
42
|
}
|
|
16
43
|
export function hasBrowserEvidenceText(text) {
|
|
17
44
|
if (!text.trim())
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Shared DB-backed guard for milestone closeout finalization.
|
|
3
|
+
import { getDbPath, getLatestAssessmentByScope, getMilestone, getMilestoneSlices, getPendingGates, getSliceTasks, isDbAvailable, refreshOpenDatabaseFromDisk, } from "./gsd-db.js";
|
|
4
|
+
import { isClosedStatus } from "./status-guards.js";
|
|
5
|
+
export const CLOSEOUT_CONSISTENCY_BLOCKED_REASON = "closeout-consistency-blocked";
|
|
6
|
+
function blocked(reason, message) {
|
|
7
|
+
return {
|
|
8
|
+
ok: false,
|
|
9
|
+
reason,
|
|
10
|
+
recoveryReason: CLOSEOUT_CONSISTENCY_BLOCKED_REASON,
|
|
11
|
+
message,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function isFileBackedDbPath(path) {
|
|
15
|
+
return Boolean(path && path !== ":memory:");
|
|
16
|
+
}
|
|
17
|
+
export function checkCloseoutConsistencyGate(milestoneId, options = {}) {
|
|
18
|
+
if (!isDbAvailable()) {
|
|
19
|
+
return blocked("db-unavailable", `Closeout consistency blocked for ${milestoneId}: canonical DB is unavailable.`);
|
|
20
|
+
}
|
|
21
|
+
if (options.refreshFromDisk && isFileBackedDbPath(getDbPath()) && !refreshOpenDatabaseFromDisk()) {
|
|
22
|
+
return blocked("db-refresh-failed", `Closeout consistency blocked for ${milestoneId}: canonical DB refresh failed.`);
|
|
23
|
+
}
|
|
24
|
+
const milestone = getMilestone(milestoneId);
|
|
25
|
+
if (!milestone) {
|
|
26
|
+
return blocked("milestone-missing", `Closeout consistency blocked for ${milestoneId}: milestone is missing from canonical DB.`);
|
|
27
|
+
}
|
|
28
|
+
if (!isClosedStatus(milestone.status)) {
|
|
29
|
+
return blocked("milestone-open", `Closeout consistency blocked for ${milestoneId}: canonical DB milestone status is "${milestone.status}".`);
|
|
30
|
+
}
|
|
31
|
+
if (milestone.status !== "skipped") {
|
|
32
|
+
const validation = getLatestAssessmentByScope(milestoneId, "milestone-validation");
|
|
33
|
+
if (validation?.status !== "pass") {
|
|
34
|
+
return blocked("validation-not-pass", `Closeout consistency blocked for ${milestoneId}: latest milestone validation is "${validation?.status ?? "absent"}".`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const slices = getMilestoneSlices(milestoneId);
|
|
38
|
+
if (slices.length === 0 && milestone.status !== "skipped") {
|
|
39
|
+
return blocked("slice-missing", `Closeout consistency blocked for ${milestoneId}: no slices exist in canonical DB.`);
|
|
40
|
+
}
|
|
41
|
+
for (const slice of slices) {
|
|
42
|
+
if (!isClosedStatus(slice.status)) {
|
|
43
|
+
return blocked("slice-open", `Closeout consistency blocked for ${milestoneId}: slice ${slice.id} status is "${slice.status}".`);
|
|
44
|
+
}
|
|
45
|
+
for (const task of getSliceTasks(milestoneId, slice.id)) {
|
|
46
|
+
if (!isClosedStatus(task.status)) {
|
|
47
|
+
return blocked("task-open", `Closeout consistency blocked for ${milestoneId}: task ${slice.id}/${task.id} status is "${task.status}".`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const pendingGate = getPendingGates(milestoneId, slice.id)[0];
|
|
51
|
+
if (pendingGate) {
|
|
52
|
+
return blocked("quality-gate-pending", `Closeout consistency blocked for ${milestoneId}: quality gate ${pendingGate.gate_id} is still pending for ${slice.id}.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { ok: true };
|
|
56
|
+
}
|
|
57
|
+
export function formatCloseoutConsistencyBlock(result) {
|
|
58
|
+
if (result.ok)
|
|
59
|
+
return "";
|
|
60
|
+
return `${result.message} Recovery reason: ${result.recoveryReason}. Resolve the canonical DB state and run /gsd auto to retry.`;
|
|
61
|
+
}
|
|
@@ -266,8 +266,8 @@ Examples:
|
|
|
266
266
|
await handleInspect(ctx);
|
|
267
267
|
return true;
|
|
268
268
|
}
|
|
269
|
-
if (trimmed === "update" || trimmed === "upgrade") {
|
|
270
|
-
await handleUpdate(ctx);
|
|
269
|
+
if (trimmed === "update" || trimmed.startsWith("update ") || trimmed === "upgrade" || trimmed.startsWith("upgrade ")) {
|
|
270
|
+
await handleUpdate(ctx, trimmed.replace(/^(?:update|upgrade)\s*/, "").trim());
|
|
271
271
|
return true;
|
|
272
272
|
}
|
|
273
273
|
if (trimmed === "fast" || trimmed.startsWith("fast ")) {
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* handleRunHook, handleUpdate, handleSkillHealth
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync, readFileSync, mkdirSync } from "node:fs";
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
9
|
+
import { createRequire } from "node:module";
|
|
8
10
|
import { join, resolve as resolvePath, sep } from "node:path";
|
|
9
11
|
import { homedir } from "node:os";
|
|
10
12
|
import { deriveState } from "./state.js";
|
|
@@ -20,7 +22,10 @@ import { loadPrompt } from "./prompt-loader.js";
|
|
|
20
22
|
import { isPnpmInstall } from "../../shared/package-manager-detection.js";
|
|
21
23
|
import { buildDoctorHealIssuePayload, buildDoctorHealSummary, buildWorkflowDispatchContent, } from "./workflow-protocol.js";
|
|
22
24
|
import { restoreGsdWorkflowTools, scopeGsdWorkflowToolsForDispatch, } from "./bootstrap/register-hooks.js";
|
|
25
|
+
const GSD_PI_PACKAGE = "@opengsd/gsd-pi";
|
|
26
|
+
const GSD_BROWSER_PACKAGE = "@opengsd/gsd-browser";
|
|
23
27
|
const UPDATE_REGISTRY_URL = "https://registry.npmjs.org/@opengsd%2fgsd-pi/latest";
|
|
28
|
+
const BROWSER_UPDATE_REGISTRY_URL = "https://registry.npmjs.org/@opengsd%2fgsd-browser/latest";
|
|
24
29
|
const UPDATE_FETCH_TIMEOUT_MS = 5000;
|
|
25
30
|
// Detects a bun-installed gsd via `process.argv[1]`. Mirrors isBunInstall in
|
|
26
31
|
// src/update-check.ts — duplicated because tsconfig.resources.json rootDir
|
|
@@ -47,11 +52,11 @@ function resolveInstallCommand(pkg) {
|
|
|
47
52
|
return `pnpm add -g ${pkg}`;
|
|
48
53
|
return `npm install -g ${pkg}`;
|
|
49
54
|
}
|
|
50
|
-
async function fetchLatestVersionForCommand() {
|
|
55
|
+
async function fetchLatestVersionForCommand(registryUrl = UPDATE_REGISTRY_URL) {
|
|
51
56
|
const controller = new AbortController();
|
|
52
57
|
const timeout = setTimeout(() => controller.abort(), UPDATE_FETCH_TIMEOUT_MS);
|
|
53
58
|
try {
|
|
54
|
-
const res = await fetch(
|
|
59
|
+
const res = await fetch(registryUrl, { signal: controller.signal });
|
|
55
60
|
if (!res.ok)
|
|
56
61
|
return null;
|
|
57
62
|
const data = (await res.json());
|
|
@@ -65,6 +70,19 @@ async function fetchLatestVersionForCommand() {
|
|
|
65
70
|
clearTimeout(timeout);
|
|
66
71
|
}
|
|
67
72
|
}
|
|
73
|
+
function resolveInstalledPackageVersionForCommand(packageName) {
|
|
74
|
+
try {
|
|
75
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
76
|
+
const packageJsonPath = requireFromHere.resolve(`${packageName}/package.json`);
|
|
77
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
78
|
+
return typeof pkg.version === "string" && pkg.version.trim().length > 0
|
|
79
|
+
? pkg.version.trim().replace(/^v/, "")
|
|
80
|
+
: null;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
68
86
|
export function dispatchDoctorHeal(pi, scope, reportText, structuredIssues) {
|
|
69
87
|
const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(gsdHome(), "agent", "GSD-WORKFLOW.md");
|
|
70
88
|
const workflow = readFileSync(workflowPath, "utf-8");
|
|
@@ -386,27 +404,74 @@ function compareSemverLocal(a, b) {
|
|
|
386
404
|
}
|
|
387
405
|
return 0;
|
|
388
406
|
}
|
|
389
|
-
|
|
407
|
+
function formatCommandVersion(version) {
|
|
408
|
+
return version ? `v${version}` : "unknown";
|
|
409
|
+
}
|
|
410
|
+
function pickHigherVersionForCommand(a, b) {
|
|
411
|
+
if (!a)
|
|
412
|
+
return b;
|
|
413
|
+
if (!b)
|
|
414
|
+
return a;
|
|
415
|
+
return compareSemverLocal(a, b) >= 0 ? a : b;
|
|
416
|
+
}
|
|
417
|
+
// Mirrors resolveGsdBrowserPathVersion in src/update-check.ts — duplicated because
|
|
418
|
+
// tsconfig.resources.json rootDir prevents importing from src/.
|
|
419
|
+
function resolveGsdBrowserPathVersionForCommand(env = process.env) {
|
|
420
|
+
const explicit = env.GSD_BROWSER_PATH_VERSION?.trim();
|
|
421
|
+
if (explicit)
|
|
422
|
+
return explicit.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
|
|
423
|
+
try {
|
|
424
|
+
const out = execFileSync("gsd-browser", ["--version"], {
|
|
425
|
+
encoding: "utf-8",
|
|
426
|
+
env,
|
|
427
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
428
|
+
timeout: 2000,
|
|
429
|
+
});
|
|
430
|
+
return out.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
export async function handleUpdate(ctx, args = "") {
|
|
390
437
|
const { execSync } = await import("node:child_process");
|
|
391
|
-
const
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
438
|
+
const target = args.trim();
|
|
439
|
+
const browserUpdate = target === "browser" || target === "gsd-browser";
|
|
440
|
+
if (target && !browserUpdate) {
|
|
441
|
+
ctx.ui.notify("Usage: /gsd update [browser]", "warning");
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const NPM_PACKAGE = browserUpdate ? GSD_BROWSER_PACKAGE : GSD_PI_PACKAGE;
|
|
445
|
+
const registryUrl = browserUpdate ? BROWSER_UPDATE_REGISTRY_URL : UPDATE_REGISTRY_URL;
|
|
446
|
+
const bundledVersion = browserUpdate
|
|
447
|
+
? resolveInstalledPackageVersionForCommand(GSD_BROWSER_PACKAGE)
|
|
448
|
+
: null;
|
|
449
|
+
const current = browserUpdate
|
|
450
|
+
? pickHigherVersionForCommand(bundledVersion, resolveGsdBrowserPathVersionForCommand())
|
|
451
|
+
: process.env.GSD_VERSION || "0.0.0";
|
|
452
|
+
const label = browserUpdate ? "gsd-browser version" : "version";
|
|
453
|
+
ctx.ui.notify(`Current ${label}: ${formatCommandVersion(current)}\nChecking npm registry...`, "info");
|
|
454
|
+
const latest = await fetchLatestVersionForCommand(registryUrl);
|
|
395
455
|
if (!latest) {
|
|
396
456
|
ctx.ui.notify("Failed to reach npm registry. Check your network connection.", "error");
|
|
397
457
|
return;
|
|
398
458
|
}
|
|
399
|
-
if (compareSemverLocal(latest, current) <= 0) {
|
|
400
|
-
ctx.ui.notify(`Already up to date (
|
|
459
|
+
if (current && compareSemverLocal(latest, current) <= 0) {
|
|
460
|
+
ctx.ui.notify(`Already up to date (${formatCommandVersion(current)}).`, "info");
|
|
401
461
|
return;
|
|
402
462
|
}
|
|
403
|
-
ctx.ui.notify(`Updating:
|
|
463
|
+
ctx.ui.notify(`Updating: ${formatCommandVersion(current)} → v${latest}...`, "info");
|
|
404
464
|
const installCmd = resolveInstallCommand(`${NPM_PACKAGE}@latest`);
|
|
405
465
|
try {
|
|
406
466
|
execSync(installCmd, {
|
|
407
467
|
stdio: ["ignore", "pipe", "ignore"],
|
|
408
468
|
});
|
|
409
|
-
|
|
469
|
+
const newPathVersion = browserUpdate ? resolveGsdBrowserPathVersionForCommand() : null;
|
|
470
|
+
const pathReady = !browserUpdate || (!!newPathVersion && compareSemverLocal(newPathVersion, latest) >= 0);
|
|
471
|
+
ctx.ui.notify(browserUpdate
|
|
472
|
+
? `Updated gsd-browser to v${latest}. Restart your GSD session to use the new browser automation version.` +
|
|
473
|
+
(pathReady ? "" : "\nNote: Ensure the npm global bin directory is on your PATH so MCP automation uses the updated binary.")
|
|
474
|
+
: `Updated to v${latest}. Restart your GSD session to use the new version.`, "info");
|
|
410
475
|
}
|
|
411
476
|
catch {
|
|
412
477
|
ctx.ui.notify(`Update failed. Try manually: ${installCmd}`, "error");
|
|
@@ -33,7 +33,8 @@ export function formatMcpInitResult(status, configPath, targetPath) {
|
|
|
33
33
|
`Project: ${targetPath}`,
|
|
34
34
|
`Config: ${configPath}`,
|
|
35
35
|
"",
|
|
36
|
-
"MCP-capable clients can now load the GSD workflow MCP
|
|
36
|
+
"MCP-capable clients can now load the GSD workflow and gsd-browser MCP servers from this folder.",
|
|
37
|
+
"Pi Providers use the managed gsd-browser engine directly; this project config is for External MCP Clients.",
|
|
37
38
|
"Restart or reconnect any client that already has this project open.",
|
|
38
39
|
].join("\n");
|
|
39
40
|
}
|