@opengsd/gsd-pi 1.1.1-dev.3ea310e → 1.1.1-dev.595401e
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/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
- package/dist/resources/extensions/gsd/auto/phases.js +4 -3
- package/dist/resources/extensions/gsd/auto-dashboard.js +92 -17
- package/dist/resources/extensions/gsd/auto-dispatch.js +5 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +132 -8
- package/dist/resources/extensions/gsd/auto-prompts.js +68 -22
- package/dist/resources/extensions/gsd/auto-start.js +41 -12
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +2 -1
- package/dist/resources/extensions/gsd/auto.js +12 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +82 -3
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +30 -9
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
- package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
- package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +2 -1
- package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
- package/dist/resources/extensions/gsd/error-classifier.js +2 -1
- package/dist/resources/extensions/gsd/escalation.js +4 -4
- package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
- package/dist/resources/extensions/gsd/forensics.js +74 -2
- package/dist/resources/extensions/gsd/gsd-db.js +5 -2
- package/dist/resources/extensions/gsd/guided-flow.js +29 -68
- package/dist/resources/extensions/gsd/memory-store.js +4 -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 +48 -24
- package/dist/resources/extensions/gsd/prompts/system.md +3 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/dist/resources/extensions/gsd/rule-registry.js +428 -52
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
- package/dist/resources/extensions/gsd/skill-activation.js +20 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
- package/dist/resources/extensions/gsd/state.js +3 -3
- package/dist/resources/extensions/gsd/templates/plan.md +3 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
- package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +403 -3
- package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
- package/dist/resources/extensions/gsd/verification-gate.js +72 -1
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +1 -1
- package/dist/resources/extensions/gsd/workflow-mcp.js +5 -1
- package/dist/rtk.d.ts +7 -1
- package/dist/rtk.js +27 -11
- 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/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 +3 -2
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +14 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +16 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +32 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- package/packages/gsd-agent-core/dist/index.d.ts +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +1 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
- package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
- package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
- package/packages/gsd-agent-core/package.json +6 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +89 -31
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
- package/packages/mcp-server/dist/remote-questions.js +23 -9
- package/packages/mcp-server/dist/remote-questions.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +84 -2
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +38 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +3 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/api-registry.d.ts +2 -0
- package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
- package/packages/pi-ai/dist/api-registry.js +23 -0
- package/packages/pi-ai/dist/api-registry.js.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +15 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +86 -18
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +108 -40
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/stream.js +6 -6
- package/packages/pi-ai/dist/stream.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/terminal.d.ts +1 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +8 -4
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
- package/src/resources/extensions/gsd/auto/phases.ts +5 -3
- package/src/resources/extensions/gsd/auto-dashboard.ts +98 -18
- package/src/resources/extensions/gsd/auto-dispatch.ts +5 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +164 -7
- package/src/resources/extensions/gsd/auto-prompts.ts +102 -15
- package/src/resources/extensions/gsd/auto-start.ts +54 -14
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +2 -1
- package/src/resources/extensions/gsd/auto.ts +15 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +89 -3
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +51 -14
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
- package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
- package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +3 -1
- package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
- package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
- package/src/resources/extensions/gsd/error-classifier.ts +2 -1
- package/src/resources/extensions/gsd/escalation.ts +4 -4
- package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
- package/src/resources/extensions/gsd/forensics.ts +99 -5
- package/src/resources/extensions/gsd/gsd-db.ts +5 -2
- package/src/resources/extensions/gsd/guided-flow.ts +90 -82
- package/src/resources/extensions/gsd/memory-store.ts +4 -1
- package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +48 -24
- package/src/resources/extensions/gsd/prompts/system.md +3 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/src/resources/extensions/gsd/rule-registry.ts +558 -58
- package/src/resources/extensions/gsd/rule-types.ts +2 -0
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
- package/src/resources/extensions/gsd/skill-activation.ts +20 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
- package/src/resources/extensions/gsd/state.ts +3 -3
- package/src/resources/extensions/gsd/templates/plan.md +3 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +156 -4
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +16 -3
- package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +66 -10
- package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
- package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +53 -1
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +213 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
- package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +489 -3
- package/src/resources/extensions/gsd/types.ts +67 -4
- package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
- package/src/resources/extensions/gsd/verification-gate.ts +87 -1
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +1 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +5 -1
- /package/dist/web/standalone/.next/static/{xACmObbrDjwLriepRgaa9 → IDKjyRHLIaumjgonPcYiX}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{xACmObbrDjwLriepRgaa9 → IDKjyRHLIaumjgonPcYiX}/_ssgManifest.js +0 -0
|
@@ -36,7 +36,9 @@ import { resolveSkillManifest } from "../skill-manifest.js";
|
|
|
36
36
|
import { applyUnitSkillVisibility, unitHasSkillManifest } from "../skill-scope.js";
|
|
37
37
|
import { getGuidedUnitContext } from "../guided-unit-context.js";
|
|
38
38
|
import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
|
|
39
|
-
import { AUTO_UNIT_SCOPED_TOOLS, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
|
|
39
|
+
import { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
|
|
40
|
+
import { filterToolsForProvider } from "../model-router.js";
|
|
41
|
+
import { RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
|
|
40
42
|
|
|
41
43
|
let approvalQuestionAbortInFlight = false;
|
|
42
44
|
|
|
@@ -123,6 +125,7 @@ export const MINIMAL_GSD_TOOL_NAMES = [
|
|
|
123
125
|
"gsd_resume",
|
|
124
126
|
"gsd_milestone_status",
|
|
125
127
|
"gsd_checkpoint_db",
|
|
128
|
+
"gsd_plan_milestone",
|
|
126
129
|
"memory_query",
|
|
127
130
|
"capture_thought",
|
|
128
131
|
] as const;
|
|
@@ -226,6 +229,9 @@ export function buildMinimalAutoGsdToolSet(
|
|
|
226
229
|
unitType: string | undefined,
|
|
227
230
|
registeredToolNames: readonly string[] = activeToolNames,
|
|
228
231
|
): string[] {
|
|
232
|
+
if (unitType === "run-uat") {
|
|
233
|
+
return buildRunUatGsdToolSet(activeToolNames, registeredToolNames);
|
|
234
|
+
}
|
|
229
235
|
const unitTools = unitType ? AUTO_UNIT_SCOPED_TOOLS[unitType] ?? [] : [];
|
|
230
236
|
const autoBaseTools = new Set<string>(MINIMAL_AUTO_BASE_TOOL_NAMES);
|
|
231
237
|
const availableBaseTools = registeredToolNames.filter((name) => autoBaseTools.has(name));
|
|
@@ -240,6 +246,17 @@ export function buildMinimalAutoGsdToolSet(
|
|
|
240
246
|
return withPreservedShimTools([...new Set([...preserved, ...scoped])]);
|
|
241
247
|
}
|
|
242
248
|
|
|
249
|
+
export function buildRunUatGsdToolSet(
|
|
250
|
+
activeToolNames: readonly string[],
|
|
251
|
+
registeredToolNames: readonly string[] = activeToolNames,
|
|
252
|
+
): string[] {
|
|
253
|
+
const scoped = resolveScopedToolNames(
|
|
254
|
+
[...activeToolNames, ...registeredToolNames],
|
|
255
|
+
[...RUN_UAT_WORKFLOW_TOOL_NAMES, "subagent", ...RUN_UAT_BROWSER_TOOL_NAMES],
|
|
256
|
+
);
|
|
257
|
+
return [...new Set(scoped)];
|
|
258
|
+
}
|
|
259
|
+
|
|
243
260
|
export function buildMinimalGsdWorkflowToolSet(
|
|
244
261
|
activeToolNames: readonly string[],
|
|
245
262
|
registeredToolNames: readonly string[] = activeToolNames,
|
|
@@ -1022,9 +1039,8 @@ export function registerHooks(
|
|
|
1022
1039
|
if (result.block) return result;
|
|
1023
1040
|
});
|
|
1024
1041
|
|
|
1025
|
-
// ── Safety harness: evidence collection + destructive command
|
|
1042
|
+
// ── Safety harness: evidence collection + destructive command blocking ──
|
|
1026
1043
|
pi.on("tool_call", async (event, ctx) => {
|
|
1027
|
-
if (!isAutoActive()) return;
|
|
1028
1044
|
markToolStart(event.toolCallId, event.toolName);
|
|
1029
1045
|
safetyRecordToolCall(event.toolCallId, event.toolName, event.input as Record<string, unknown>);
|
|
1030
1046
|
|
|
@@ -1041,17 +1057,28 @@ export function registerHooks(
|
|
|
1041
1057
|
}
|
|
1042
1058
|
}
|
|
1043
1059
|
|
|
1044
|
-
// Destructive command classification
|
|
1060
|
+
// Destructive command classification + hard gate in all modes.
|
|
1045
1061
|
if (isToolCallEventType("bash", event)) {
|
|
1046
1062
|
const classification = classifyCommand(event.input.command);
|
|
1047
1063
|
if (classification.destructive) {
|
|
1064
|
+
const reason = [
|
|
1065
|
+
"HARD BLOCK: destructive Bash command requires explicit human confirmation.",
|
|
1066
|
+
`Detected: ${classification.labels.join(", ")}`,
|
|
1067
|
+
"Run this via ask_user_questions, wait for the user's response,",
|
|
1068
|
+
"then issue the command only when confirmed in the current turn.",
|
|
1069
|
+
].join(" ");
|
|
1048
1070
|
safetyLogWarning("safety", `destructive command: ${classification.labels.join(", ")}`, {
|
|
1049
1071
|
command: String(event.input.command).slice(0, 200),
|
|
1050
1072
|
});
|
|
1051
|
-
ctx
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1073
|
+
if (ctx) {
|
|
1074
|
+
await maybePauseAutoForApprovalGate(
|
|
1075
|
+
ctx,
|
|
1076
|
+
pi,
|
|
1077
|
+
isAutoActive(),
|
|
1078
|
+
"Depth confirmation is waiting for your answer — pausing auto-mode.",
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
return { block: true, reason };
|
|
1055
1082
|
}
|
|
1056
1083
|
}
|
|
1057
1084
|
});
|
|
@@ -1320,19 +1347,27 @@ export function registerHooks(
|
|
|
1320
1347
|
const fullToolsRequested = isFullGsdToolSurfaceRequested();
|
|
1321
1348
|
const dropAliases = !fullToolsRequested;
|
|
1322
1349
|
const dropBrowser = !fullToolsRequested && !isBrowserToolSurfaceRequested();
|
|
1323
|
-
const
|
|
1324
|
-
(name) => !(dropAliases && isWorkflowAliasTool(name))
|
|
1350
|
+
const aliasFilteredCompatible = compatible.filter(
|
|
1351
|
+
(name) => !(dropAliases && isWorkflowAliasTool(name)),
|
|
1352
|
+
);
|
|
1353
|
+
const providerCompatible = aliasFilteredCompatible.filter(
|
|
1354
|
+
(name) => !(dropBrowser && isBrowserTool(name)),
|
|
1325
1355
|
);
|
|
1326
1356
|
const surfaceReduced = providerCompatible.length !== compatible.length;
|
|
1327
1357
|
if (fullToolsRequested) {
|
|
1328
1358
|
return surfaceReduced ? { toolNames: providerCompatible } : undefined;
|
|
1329
1359
|
}
|
|
1330
1360
|
const registeredToolNames = resolveRegisteredToolNames(pi, event.activeToolNames);
|
|
1361
|
+
const compatibleRegisteredToolNames = filterToolsForProvider(
|
|
1362
|
+
registeredToolNames,
|
|
1363
|
+
event.selectedModelApi,
|
|
1364
|
+
event.selectedModelProvider,
|
|
1365
|
+
).compatible.filter((name) => !(dropAliases && isWorkflowAliasTool(name)));
|
|
1331
1366
|
const guidedUnit = getGuidedUnitContext();
|
|
1332
1367
|
const requestScoped = buildRequestScopedGsdToolSet(
|
|
1333
|
-
providerCompatible,
|
|
1368
|
+
guidedUnit?.unitType === "run-uat" ? aliasFilteredCompatible : providerCompatible,
|
|
1334
1369
|
event.requestCustomMessages,
|
|
1335
|
-
registeredToolNames,
|
|
1370
|
+
guidedUnit?.unitType === "run-uat" ? compatibleRegisteredToolNames : registeredToolNames,
|
|
1336
1371
|
guidedUnit?.unitType,
|
|
1337
1372
|
);
|
|
1338
1373
|
if (requestScoped) {
|
|
@@ -1342,9 +1377,11 @@ export function registerHooks(
|
|
|
1342
1377
|
if (dash.active && dash.currentUnit) {
|
|
1343
1378
|
return {
|
|
1344
1379
|
toolNames: buildMinimalAutoGsdToolSet(
|
|
1345
|
-
providerCompatible,
|
|
1380
|
+
dash.currentUnit.type === "run-uat" ? aliasFilteredCompatible : providerCompatible,
|
|
1346
1381
|
dash.currentUnit.type,
|
|
1347
|
-
|
|
1382
|
+
dash.currentUnit.type === "run-uat"
|
|
1383
|
+
? compatibleRegisteredToolNames
|
|
1384
|
+
: resolveRegisteredToolNames(pi, event.activeToolNames),
|
|
1348
1385
|
),
|
|
1349
1386
|
};
|
|
1350
1387
|
}
|
|
@@ -679,6 +679,7 @@ const PLANNING_SUBAGENT_TOOLS = new Set(["subagent", "task"]);
|
|
|
679
679
|
* manifests still declare per-unit subsets via ToolsPolicy.allowedSubagents.
|
|
680
680
|
*/
|
|
681
681
|
const PLANNING_DISPATCH_AGENT_REGISTRY = {
|
|
682
|
+
mnemo: { readOnlySpecialist: true },
|
|
682
683
|
scout: { readOnlySpecialist: true },
|
|
683
684
|
planner: { readOnlySpecialist: true },
|
|
684
685
|
reviewer: { readOnlySpecialist: true },
|
|
@@ -692,7 +693,7 @@ export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set<string>(
|
|
|
692
693
|
.map(([agentId]) => agentId),
|
|
693
694
|
);
|
|
694
695
|
|
|
695
|
-
let
|
|
696
|
+
let warnedMissingControlledDispatchAgentClasses = false;
|
|
696
697
|
|
|
697
698
|
function isReadOnlySpecialist(agentId: string): boolean {
|
|
698
699
|
const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId as keyof typeof PLANNING_DISPATCH_AGENT_REGISTRY];
|
|
@@ -703,11 +704,20 @@ function allowedPlanningDispatchAgentsList(): string {
|
|
|
703
704
|
return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
|
|
704
705
|
}
|
|
705
706
|
|
|
706
|
-
function
|
|
707
|
-
|
|
708
|
-
|
|
707
|
+
function allowsControlledSubagentDispatch(
|
|
708
|
+
policy: ToolsPolicy,
|
|
709
|
+
): policy is ToolsPolicy & { readonly allowedSubagents: readonly string[] } {
|
|
710
|
+
return (
|
|
711
|
+
(policy.mode === "planning-dispatch" || policy.mode === "verification") &&
|
|
712
|
+
Array.isArray((policy as { readonly allowedSubagents?: unknown }).allowedSubagents)
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function warnMissingControlledDispatchAgentClasses(unitType: string, mode: string, toolName: string): void {
|
|
717
|
+
if (warnedMissingControlledDispatchAgentClasses) return;
|
|
718
|
+
warnedMissingControlledDispatchAgentClasses = true;
|
|
709
719
|
// TODO(#5060): Remove this migration shim once all subagent/task callers are verified to forward agent identities.
|
|
710
|
-
const message = `[write-gate]
|
|
720
|
+
const message = `[write-gate] controlled-dispatch: shouldBlockPlanningUnit called for tool "${toolName}" ` +
|
|
711
721
|
`on unit "${unitType}" without agentClasses - stale caller; blocking dispatch.`;
|
|
712
722
|
console.warn(message);
|
|
713
723
|
logWarning("intercept", message, {
|
|
@@ -777,8 +787,9 @@ function blockReason(unitType: string, mode: string, what: string): string {
|
|
|
777
787
|
* - "docs" → like "planning" but also allows writes to paths
|
|
778
788
|
* matching `allowedPathGlobs` relative to basePath.
|
|
779
789
|
* - "verification"
|
|
780
|
-
* → allows Bash for project verification commands,
|
|
781
|
-
* writes restricted to .gsd
|
|
790
|
+
* → allows Bash for project verification commands, keeps
|
|
791
|
+
* writes restricted to .gsd/, and permits subagent dispatch
|
|
792
|
+
* only when the manifest declares allowedSubagents.
|
|
782
793
|
*
|
|
783
794
|
* `pathOrCommand` is the file path for write/edit-shaped tools and the
|
|
784
795
|
* shell command for bash. Other tools ignore this argument.
|
|
@@ -825,7 +836,7 @@ export function shouldBlockPlanningUnit(
|
|
|
825
836
|
if (tool.startsWith("gsd_")) return { block: false };
|
|
826
837
|
|
|
827
838
|
if (PLANNING_SUBAGENT_TOOLS.has(tool)) {
|
|
828
|
-
if (policy
|
|
839
|
+
if (allowsControlledSubagentDispatch(policy)) {
|
|
829
840
|
const requested = (agentClasses ?? []).map(a => a.trim()).filter(Boolean);
|
|
830
841
|
const dispatchContract = compileSubagentPermissionContract(policy);
|
|
831
842
|
const allowedSubagents = dispatchContract.allowedSubagents;
|
|
@@ -834,7 +845,7 @@ export function shouldBlockPlanningUnit(
|
|
|
834
845
|
// agent identities yet. Block and warn so stale callers surface in telemetry
|
|
835
846
|
// instead of silently bypassing the gate.
|
|
836
847
|
if (agentClasses === undefined) {
|
|
837
|
-
|
|
848
|
+
warnMissingControlledDispatchAgentClasses(unitType, policy.mode, tool);
|
|
838
849
|
return {
|
|
839
850
|
block: true,
|
|
840
851
|
reason: blockReason(
|
|
@@ -857,7 +868,7 @@ export function shouldBlockPlanningUnit(
|
|
|
857
868
|
reason: blockReason(
|
|
858
869
|
unitType,
|
|
859
870
|
policy.mode,
|
|
860
|
-
`subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from
|
|
871
|
+
`subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`,
|
|
861
872
|
),
|
|
862
873
|
};
|
|
863
874
|
}
|
|
@@ -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 {
|
|
@@ -75,7 +75,7 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
|
|
|
75
75
|
" /gsd new-milestone Create milestone from headless context (used by gsd headless)",
|
|
76
76
|
" /gsd new-project Bootstrap a new project (use --deep for staged project-level discovery)",
|
|
77
77
|
" /gsd quick Execute a quick task without full planning overhead",
|
|
78
|
-
" /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|uat|replan]",
|
|
78
|
+
" /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|validate|reassess|uat|replan]",
|
|
79
79
|
" /gsd verdict <v> Override milestone validation verdict [pass|needs-attention|needs-remediation] [--milestone Mxxx] [--rationale \"...\"]",
|
|
80
80
|
" /gsd parallel Parallel milestone orchestration [start|status|stop|pause|resume|merge|watch]",
|
|
81
81
|
" /gsd workflow Custom workflow lifecycle [new|run|list|validate|pause|resume]",
|
|
@@ -23,6 +23,9 @@ import {
|
|
|
23
23
|
import { loadFile, saveFile, splitFrontmatter, parseFrontmatterMap } from "./files.js";
|
|
24
24
|
import { runClaudeImportFlow } from "./claude-import.js";
|
|
25
25
|
|
|
26
|
+
const DEFAULT_WIDGET_MODE = "small";
|
|
27
|
+
const WIDGET_MODE_OPTIONS = [DEFAULT_WIDGET_MODE, "full", "min", "off"] as const;
|
|
28
|
+
|
|
26
29
|
/** Extract body content after frontmatter closing delimiter, or null if none. */
|
|
27
30
|
function extractBodyAfterFrontmatter(content: string): string | null {
|
|
28
31
|
const closingIdx = content.indexOf("\n---", content.indexOf("---"));
|
|
@@ -1558,7 +1561,7 @@ async function configureAdvanced(ctx: ExtensionCommandContext, prefs: Record<str
|
|
|
1558
1561
|
prefs.min_request_interval_ms = minRequestInterval;
|
|
1559
1562
|
}
|
|
1560
1563
|
|
|
1561
|
-
const widget = await promptEnum(ctx, "Auto-mode widget display", prefs.widget_mode,
|
|
1564
|
+
const widget = await promptEnum(ctx, "Auto-mode widget display", prefs.widget_mode, WIDGET_MODE_OPTIONS, DEFAULT_WIDGET_MODE);
|
|
1562
1565
|
if (widget !== undefined) prefs.widget_mode = widget;
|
|
1563
1566
|
|
|
1564
1567
|
const experimental = (prefs.experimental as Record<string, unknown> | undefined) ?? {};
|
|
@@ -238,7 +238,7 @@ export async function handleVerdict(
|
|
|
238
238
|
|
|
239
239
|
if (effectiveVerdict === "needs-remediation") {
|
|
240
240
|
ctx.ui.notify(
|
|
241
|
-
"Follow up with
|
|
241
|
+
"Follow up with /gsd dispatch reassess to add remediation slices, then re-run /gsd auto.",
|
|
242
242
|
"info",
|
|
243
243
|
);
|
|
244
244
|
}
|
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
resolveAutoSupervisorConfig,
|
|
24
24
|
} from "./preferences.js";
|
|
25
25
|
|
|
26
|
+
const DEFAULT_WIDGET_MODE = "small";
|
|
27
|
+
|
|
26
28
|
// ─── Data Collection ──────────────────────────────────────────────────────
|
|
27
29
|
|
|
28
30
|
interface ConfigSection {
|
|
@@ -160,7 +162,7 @@ function collectConfigSections(): ConfigSection[] {
|
|
|
160
162
|
if (prefs?.service_tier) toggleRows.push({ label: "service_tier", value: prefs.service_tier });
|
|
161
163
|
if (prefs?.search_provider && prefs.search_provider !== "auto") toggleRows.push({ label: "search_provider", value: prefs.search_provider });
|
|
162
164
|
if (prefs?.context_selection) toggleRows.push({ label: "context_selection", value: prefs.context_selection });
|
|
163
|
-
if (prefs?.widget_mode && prefs.widget_mode !==
|
|
165
|
+
if (prefs?.widget_mode && prefs.widget_mode !== DEFAULT_WIDGET_MODE) toggleRows.push({ label: "widget_mode", value: prefs.widget_mode });
|
|
164
166
|
if (prefs?.experimental?.rtk) toggleRows.push({ label: "experimental.rtk", value: "on" });
|
|
165
167
|
if (toggleRows.length > 0) sections.push({ title: "Toggles", rows: toggleRows });
|
|
166
168
|
|
|
@@ -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
|
});
|
|
@@ -47,9 +47,10 @@ export function resetRetryState(state: RetryState): void {
|
|
|
47
47
|
const PERMANENT_RE = /auth|unauthorized|forbidden|invalid.*key|invalid.*api|billing|quota exceeded|account/i;
|
|
48
48
|
// Include provider-specific quota-window phrasing like:
|
|
49
49
|
// - "You've hit your limit"
|
|
50
|
+
// - "You've reached your limit"
|
|
50
51
|
// - "usage limit" / "quota reached"
|
|
51
52
|
// - "out of extra usage"
|
|
52
|
-
const RATE_LIMIT_RE = /rate.?limit|too many requests|429|hit your limit|usage limit|out of extra usage|quota (?:reached|hit)|limit.*resets?/i;
|
|
53
|
+
const RATE_LIMIT_RE = /rate.?limit|too many requests|429|(?:hit|reached) your (?:\w+ )?limit|(?:usage|session|weekly|daily|monthly|quota) limit|out of extra usage|quota (?:reached|hit)|limit.*resets?/i;
|
|
53
54
|
// OpenRouter affordability-style quota errors should be treated as transient
|
|
54
55
|
// so core retry logic can lower maxTokens and continue in-session.
|
|
55
56
|
const AFFORDABILITY_RE = /requires more credits|can only afford|insufficient credits|not enough credits|fewer max_tokens/i;
|
|
@@ -159,13 +159,13 @@ export function readEscalationArtifact(path: string): EscalationArtifact | null
|
|
|
159
159
|
// ─── Detection ────────────────────────────────────────────────────────────
|
|
160
160
|
|
|
161
161
|
/**
|
|
162
|
-
* Returns the task id of the first task with an
|
|
163
|
-
*
|
|
164
|
-
*
|
|
162
|
+
* Returns the task id of the first task with an unresolved escalation.
|
|
163
|
+
* `continueWithDefault=true` artifacts keep the awaiting_review flag for
|
|
164
|
+
* compatibility, but still pause dispatch until the user explicitly responds.
|
|
165
165
|
*/
|
|
166
166
|
export function detectPendingEscalation(tasks: TaskRow[], basePath: string): string | null {
|
|
167
167
|
for (const t of tasks) {
|
|
168
|
-
if (t.escalation_pending !== 1) continue;
|
|
168
|
+
if (t.escalation_pending !== 1 && t.escalation_awaiting_review !== 1) continue;
|
|
169
169
|
if (!t.escalation_artifact_path) continue;
|
|
170
170
|
const art = readEscalationArtifact(t.escalation_artifact_path);
|
|
171
171
|
if (art && !art.respondedAt) return t.id;
|
|
@@ -20,6 +20,8 @@ export interface ExecSandboxRequest {
|
|
|
20
20
|
script: string;
|
|
21
21
|
/** Optional purpose/label recorded in meta.json. */
|
|
22
22
|
purpose?: string;
|
|
23
|
+
/** Optional structured metadata recorded in meta.json. */
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
23
25
|
/** Per-invocation timeout in ms. Clamped to `clamp_timeout_ms`. */
|
|
24
26
|
timeout_ms?: number;
|
|
25
27
|
}
|
|
@@ -315,6 +317,7 @@ function writeMeta(
|
|
|
315
317
|
id: result.id,
|
|
316
318
|
runtime: result.runtime,
|
|
317
319
|
purpose: request.purpose ?? null,
|
|
320
|
+
...(request.metadata ? { metadata: request.metadata } : {}),
|
|
318
321
|
script_chars: request.script.length,
|
|
319
322
|
started_at: now.toISOString(),
|
|
320
323
|
finished_at: new Date(now.getTime() + result.duration_ms).toISOString(),
|
|
@@ -328,6 +331,7 @@ function writeMeta(
|
|
|
328
331
|
stderr_truncated: result.stderr_truncated,
|
|
329
332
|
stdout_path: result.stdout_path,
|
|
330
333
|
stderr_path: result.stderr_path,
|
|
334
|
+
...(request.metadata ? { metadata: request.metadata } : {}),
|
|
331
335
|
};
|
|
332
336
|
writeFileSync(path, `${JSON.stringify(meta, null, 2)}\n`);
|
|
333
337
|
}
|
|
@@ -123,6 +123,91 @@ interface ForensicReport {
|
|
|
123
123
|
worktreeTelemetry: WorktreeTelemetrySummary | null;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
// ─── Filing Tool Scope ───────────────────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
const FORENSICS_FILING_TOOLS = ["bash", "write"] as const;
|
|
129
|
+
|
|
130
|
+
type ForensicsFilingTool = typeof FORENSICS_FILING_TOOLS[number];
|
|
131
|
+
|
|
132
|
+
export interface ForensicsToolScope {
|
|
133
|
+
savedTools: string[];
|
|
134
|
+
activeToolsForTurn: string[];
|
|
135
|
+
availableFilingTools: ForensicsFilingTool[];
|
|
136
|
+
missingFilingTools: ForensicsFilingTool[];
|
|
137
|
+
toolsChanged: boolean;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function uniqueAppend(base: readonly string[], additions: readonly string[]): string[] {
|
|
141
|
+
const seen = new Set(base);
|
|
142
|
+
const next = [...base];
|
|
143
|
+
for (const name of additions) {
|
|
144
|
+
if (seen.has(name)) continue;
|
|
145
|
+
seen.add(name);
|
|
146
|
+
next.push(name);
|
|
147
|
+
}
|
|
148
|
+
return next;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function sameOrderedTools(a: readonly string[], b: readonly string[]): boolean {
|
|
152
|
+
return a.length === b.length && a.every((name, index) => name === b[index]);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function getRegisteredToolNames(
|
|
156
|
+
pi: Pick<ExtensionAPI, "getActiveTools"> & Partial<Pick<ExtensionAPI, "getAllTools">>,
|
|
157
|
+
fallback: readonly string[],
|
|
158
|
+
): string[] {
|
|
159
|
+
if (typeof pi.getAllTools === "function") {
|
|
160
|
+
return pi.getAllTools().map((tool) => tool.name);
|
|
161
|
+
}
|
|
162
|
+
return [...fallback];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function createForensicsToolScope(
|
|
166
|
+
pi: Pick<ExtensionAPI, "getActiveTools"> & Partial<Pick<ExtensionAPI, "getAllTools">>,
|
|
167
|
+
): ForensicsToolScope {
|
|
168
|
+
const savedTools = [...pi.getActiveTools()];
|
|
169
|
+
const registeredTools = new Set([...getRegisteredToolNames(pi, savedTools), ...savedTools]);
|
|
170
|
+
const availableFilingTools = FORENSICS_FILING_TOOLS.filter((name) => registeredTools.has(name));
|
|
171
|
+
const missingFilingTools = FORENSICS_FILING_TOOLS.filter((name) => !registeredTools.has(name));
|
|
172
|
+
const activeToolsForTurn = uniqueAppend(savedTools, availableFilingTools);
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
savedTools,
|
|
176
|
+
activeToolsForTurn,
|
|
177
|
+
availableFilingTools,
|
|
178
|
+
missingFilingTools,
|
|
179
|
+
toolsChanged: !sameOrderedTools(savedTools, activeToolsForTurn),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function applyForensicsToolScope(pi: Pick<ExtensionAPI, "setActiveTools">, scope: ForensicsToolScope): void {
|
|
184
|
+
if (scope.toolsChanged) pi.setActiveTools(scope.activeToolsForTurn);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function restoreForensicsToolScope(pi: Pick<ExtensionAPI, "setActiveTools">, scope: ForensicsToolScope): void {
|
|
188
|
+
if (scope.toolsChanged) pi.setActiveTools(scope.savedTools);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function buildForensicsToolingSection(scope: ForensicsToolScope): string {
|
|
192
|
+
const available = new Set(scope.availableFilingTools);
|
|
193
|
+
const requested = scope.availableFilingTools.length
|
|
194
|
+
? scope.availableFilingTools.map((name) => `\`${name}\``).join(", ")
|
|
195
|
+
: "none";
|
|
196
|
+
const statusFor = (name: ForensicsFilingTool) => available.has(name)
|
|
197
|
+
? `- \`${name}\`: available for this queued forensics turn`
|
|
198
|
+
: `- \`${name}\`: unavailable in this host session`;
|
|
199
|
+
|
|
200
|
+
return `
|
|
201
|
+
## Filing Tool Availability
|
|
202
|
+
|
|
203
|
+
For this queued forensic turn, the extension requested the registered filing tools: ${requested}.
|
|
204
|
+
|
|
205
|
+
${FORENSICS_FILING_TOOLS.map(statusFor).join("\n")}
|
|
206
|
+
|
|
207
|
+
If \`bash\` is available, use the GitHub duplicate-check and issue-creation protocols below. If \`bash\` is unavailable, do not attempt duplicate-check or issue-creation tool calls with another tool; provide the paste-once shell script fallback instead.
|
|
208
|
+
`;
|
|
209
|
+
}
|
|
210
|
+
|
|
126
211
|
// ─── Duplicate Detection ──────────────────────────────────────────────────────
|
|
127
212
|
|
|
128
213
|
const DEDUP_PROMPT_SECTION = `
|
|
@@ -134,6 +219,8 @@ Before reading GSD source code or performing deep analysis, you MUST search for
|
|
|
134
219
|
|
|
135
220
|
Use keywords from the user's problem description and the anomaly summaries in the forensic report above.
|
|
136
221
|
|
|
222
|
+
If \`bash\` is unavailable in the Filing Tool Availability section, do not attempt live duplicate-search tool calls. Say the live duplicate search must be run by the user, continue the source investigation, and include the duplicate-search commands in the paste-once fallback when issue filing is accepted.
|
|
223
|
+
|
|
137
224
|
1. **Search closed issues** for similar keywords:
|
|
138
225
|
\`\`\`
|
|
139
226
|
gh issue list --repo open-gsd/gsd-pi --state closed --search "<keywords from root cause>" --limit 20
|
|
@@ -265,21 +352,28 @@ export async function handleForensics(
|
|
|
265
352
|
}
|
|
266
353
|
|
|
267
354
|
const forensicData = formatReportForPrompt(report);
|
|
355
|
+
const toolScope = createForensicsToolScope(pi);
|
|
268
356
|
const content = loadPrompt("forensics", {
|
|
269
357
|
problemDescription,
|
|
270
358
|
forensicData,
|
|
271
359
|
gsdSourceDir,
|
|
272
360
|
dedupSection,
|
|
361
|
+
toolingSection: buildForensicsToolingSection(toolScope),
|
|
273
362
|
});
|
|
274
363
|
|
|
275
364
|
ctx.ui.notify(`Forensic report saved: ${relative(basePath, savedPath)}`, "info");
|
|
276
365
|
ctx.ui.setStatus("gsd-forensics", "running");
|
|
277
366
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
367
|
+
try {
|
|
368
|
+
applyForensicsToolScope(pi, toolScope);
|
|
369
|
+
await pi.sendMessage(
|
|
370
|
+
{ customType: "gsd-forensics", content, display: false },
|
|
371
|
+
{ triggerTurn: true },
|
|
372
|
+
);
|
|
373
|
+
} finally {
|
|
374
|
+
restoreForensicsToolScope(pi, toolScope);
|
|
375
|
+
ctx.ui.setStatus("gsd-forensics", undefined);
|
|
376
|
+
}
|
|
283
377
|
|
|
284
378
|
// Persist forensics context so follow-up turns can re-inject it (#2941)
|
|
285
379
|
writeForensicsMarker(basePath, savedPath, content);
|