@opengsd/gsd-pi 1.1.1-dev.a5a2de8 → 1.1.1-dev.b2556262
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/headless-recover.js +56 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +18 -2
- package/dist/resources/extensions/browser-tools/engine/selection.js +1 -1
- package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/dist/resources/extensions/browser-tools/index.js +68 -24
- package/dist/resources/extensions/browser-tools/state.js +12 -0
- package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
- package/dist/resources/extensions/browser-tools/utils.js +3 -3
- package/dist/resources/extensions/browser-tools/web-app-detect.js +52 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +87 -12
- package/dist/resources/extensions/gsd/auto/session.js +22 -1
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +81 -13
- package/dist/resources/extensions/gsd/auto-model-selection.js +154 -9
- package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +26 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-timers.js +24 -10
- package/dist/resources/extensions/gsd/auto.js +40 -15
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +192 -77
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
- package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
- package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
- package/dist/resources/extensions/gsd/commands-mcp-status.js +1 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
- package/dist/resources/extensions/gsd/config-overlay.js +1 -0
- package/dist/resources/extensions/gsd/context-masker.js +129 -5
- package/dist/resources/extensions/gsd/db-writer.js +35 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/dist/resources/extensions/gsd/gsd-db.js +480 -172
- package/dist/resources/extensions/gsd/guided-flow.js +4 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
- package/dist/resources/extensions/gsd/md-importer.js +38 -3
- package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
- package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
- package/dist/resources/extensions/gsd/planner-handoff.js +98 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
- package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
- package/dist/resources/extensions/gsd/preferences-models.js +111 -43
- package/dist/resources/extensions/gsd/preferences-types.js +13 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
- package/dist/resources/extensions/gsd/preferences.js +4 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +2 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
- package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
- package/dist/resources/extensions/gsd/skill-manifest.js +12 -0
- package/dist/resources/extensions/gsd/source-observations.js +306 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
- package/dist/resources/extensions/gsd/state.js +7 -3
- package/dist/resources/extensions/gsd/tool-contract.js +15 -1
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +24 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +28 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
- package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +62 -406
- package/dist/resources/extensions/gsd/uat-policy.js +130 -0
- package/dist/resources/extensions/gsd/uat-run.js +414 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +38 -14
- package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
- package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -3
- package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +26 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +96 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
- package/dist/resources/extensions/shared/gsd-browser-cli.js +6 -0
- package/dist/resources/extensions/subagent/agents.js +1 -0
- package/dist/resources/extensions/subagent/index.js +27 -12
- package/dist/resources/extensions/subagent/launch.js +7 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- 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 +6 -6
- 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/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +4 -4
- 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/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -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 +25 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.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 +18 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/dist/native.js +22 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +30 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +174 -29
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +178 -54
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +8 -1
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/utils.d.ts +11 -0
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +119 -6
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/themes.js +1 -1
- package/pkg/dist/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/scripts/install/handoff.js +16 -3
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +21 -2
- package/src/resources/extensions/browser-tools/engine/selection.ts +1 -1
- package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/src/resources/extensions/browser-tools/index.ts +75 -27
- package/src/resources/extensions/browser-tools/state.ts +13 -0
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +2 -2
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +37 -0
- package/src/resources/extensions/browser-tools/tests/web-app-detect.test.mjs +68 -0
- package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
- package/src/resources/extensions/browser-tools/utils.ts +3 -3
- package/src/resources/extensions/browser-tools/web-app-detect.ts +63 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +89 -15
- package/src/resources/extensions/gsd/auto/session.ts +24 -1
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +117 -12
- package/src/resources/extensions/gsd/auto-model-selection.ts +190 -12
- package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +25 -22
- package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-timers.ts +25 -9
- package/src/resources/extensions/gsd/auto.ts +41 -14
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +250 -78
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
- package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
- package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
- package/src/resources/extensions/gsd/commands-mcp-status.ts +1 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
- package/src/resources/extensions/gsd/config-overlay.ts +1 -0
- package/src/resources/extensions/gsd/context-masker.ts +152 -5
- package/src/resources/extensions/gsd/db-writer.ts +38 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/src/resources/extensions/gsd/gsd-db.ts +564 -186
- package/src/resources/extensions/gsd/guided-flow.ts +4 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
- package/src/resources/extensions/gsd/md-importer.ts +49 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
- package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
- package/src/resources/extensions/gsd/planner-handoff.ts +149 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
- package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
- package/src/resources/extensions/gsd/preferences-models.ts +113 -43
- package/src/resources/extensions/gsd/preferences-types.ts +47 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
- package/src/resources/extensions/gsd/preferences.ts +5 -0
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +2 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
- package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
- package/src/resources/extensions/gsd/skill-manifest.ts +12 -0
- package/src/resources/extensions/gsd/source-observations.ts +402 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
- package/src/resources/extensions/gsd/state.ts +7 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +66 -4
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +4 -0
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +56 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +17 -2
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/planner-handoff.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +77 -10
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +260 -5
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
- package/src/resources/extensions/gsd/tool-contract.ts +29 -1
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +41 -6
- package/src/resources/extensions/gsd/tools/complete-slice.ts +29 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
- package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +71 -489
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/uat-policy.ts +191 -0
- package/src/resources/extensions/gsd/uat-run.ts +550 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +38 -14
- package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
- package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -3
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +32 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +103 -0
- package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
- package/src/resources/extensions/shared/gsd-browser-cli.ts +6 -0
- package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
- package/src/resources/extensions/subagent/agents.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +28 -3
- package/src/resources/extensions/subagent/launch.ts +8 -0
- package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
- /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Optional gsd-planner handoff after milestone planning.
|
|
3
|
+
|
|
4
|
+
import { spawn as spawnChild, type ChildProcess, type SpawnOptions } from "node:child_process";
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
|
|
8
|
+
import { gsdRoot } from "./paths.js";
|
|
9
|
+
|
|
10
|
+
export const PLANNER_HANDOFF_RULE_NAME = "planning review handoff -> gsd-planner";
|
|
11
|
+
export const GSD_PLANNER_COMMAND = "gsd-planner";
|
|
12
|
+
|
|
13
|
+
export interface GsdPlannerSpawnPlan {
|
|
14
|
+
command: string;
|
|
15
|
+
args: string[];
|
|
16
|
+
cwd: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface GsdPlannerLaunchInput {
|
|
20
|
+
basePath: string;
|
|
21
|
+
milestoneId?: string | null;
|
|
22
|
+
extraArgs?: string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type GsdPlannerLaunchResult =
|
|
26
|
+
| { status: "launched"; plan: GsdPlannerSpawnPlan }
|
|
27
|
+
| { status: "failed"; plan: GsdPlannerSpawnPlan; error: Error };
|
|
28
|
+
|
|
29
|
+
type SpawnLike = (
|
|
30
|
+
command: string,
|
|
31
|
+
args: readonly string[],
|
|
32
|
+
options: SpawnOptions,
|
|
33
|
+
) => ChildProcess;
|
|
34
|
+
|
|
35
|
+
export interface GsdPlannerLaunchDeps {
|
|
36
|
+
spawn?: SpawnLike;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function handoffDir(basePath: string): string {
|
|
40
|
+
return join(gsdRoot(basePath), "runtime", "planner-handoffs");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function safeMilestoneFileSegment(milestoneId: string): string {
|
|
44
|
+
return milestoneId.replace(/[^A-Za-z0-9._-]/g, "_") || "unknown";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function handoffMarkerPath(basePath: string, milestoneId: string): string {
|
|
48
|
+
return join(handoffDir(basePath), `${safeMilestoneFileSegment(milestoneId)}.json`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function hasPlannerHandoffBeenOffered(basePath: string, milestoneId: string): boolean {
|
|
52
|
+
return existsSync(handoffMarkerPath(basePath, milestoneId));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function markPlannerHandoffOffered(
|
|
56
|
+
basePath: string,
|
|
57
|
+
milestoneId: string,
|
|
58
|
+
source: "auto" | "command" = "auto",
|
|
59
|
+
): void {
|
|
60
|
+
mkdirSync(handoffDir(basePath), { recursive: true });
|
|
61
|
+
writeFileSync(
|
|
62
|
+
handoffMarkerPath(basePath, milestoneId),
|
|
63
|
+
JSON.stringify({
|
|
64
|
+
milestoneId,
|
|
65
|
+
source,
|
|
66
|
+
offeredAt: new Date().toISOString(),
|
|
67
|
+
}, null, 2) + "\n",
|
|
68
|
+
"utf-8",
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function buildGsdPlannerSpawnPlan(input: GsdPlannerLaunchInput): GsdPlannerSpawnPlan {
|
|
73
|
+
const args = ["--project", input.basePath];
|
|
74
|
+
const milestoneId = input.milestoneId?.trim();
|
|
75
|
+
if (milestoneId) args.push("--milestone", milestoneId);
|
|
76
|
+
args.push(...(input.extraArgs ?? []));
|
|
77
|
+
return {
|
|
78
|
+
command: GSD_PLANNER_COMMAND,
|
|
79
|
+
args,
|
|
80
|
+
cwd: input.basePath,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function quoteArg(arg: string): string {
|
|
85
|
+
return /^[A-Za-z0-9_./:=@+-]+$/.test(arg) ? arg : JSON.stringify(arg);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function formatGsdPlannerCommand(plan: GsdPlannerSpawnPlan): string {
|
|
89
|
+
return [plan.command, ...plan.args].map(quoteArg).join(" ");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function launchGsdPlanner(
|
|
93
|
+
input: GsdPlannerLaunchInput,
|
|
94
|
+
deps: GsdPlannerLaunchDeps = {},
|
|
95
|
+
): Promise<GsdPlannerLaunchResult> {
|
|
96
|
+
const plan = buildGsdPlannerSpawnPlan(input);
|
|
97
|
+
const spawn = deps.spawn ?? spawnChild;
|
|
98
|
+
|
|
99
|
+
let child: ChildProcess;
|
|
100
|
+
try {
|
|
101
|
+
child = spawn(plan.command, plan.args, {
|
|
102
|
+
cwd: plan.cwd,
|
|
103
|
+
detached: true,
|
|
104
|
+
stdio: "ignore",
|
|
105
|
+
windowsHide: true,
|
|
106
|
+
});
|
|
107
|
+
} catch (err) {
|
|
108
|
+
return {
|
|
109
|
+
status: "failed",
|
|
110
|
+
plan,
|
|
111
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return new Promise((resolve) => {
|
|
116
|
+
let settled = false;
|
|
117
|
+
const settle = (result: GsdPlannerLaunchResult) => {
|
|
118
|
+
if (settled) return;
|
|
119
|
+
settled = true;
|
|
120
|
+
resolve(result);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
child.once("error", (err) => {
|
|
124
|
+
settle({
|
|
125
|
+
status: "failed",
|
|
126
|
+
plan,
|
|
127
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
child.once("spawn", () => {
|
|
131
|
+
child.unref();
|
|
132
|
+
settle({ status: "launched", plan });
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function formatPlannerHandoffPauseReason(milestoneId: string): string {
|
|
138
|
+
return [
|
|
139
|
+
`Milestone ${milestoneId} is planned. Review or customize the plan before implementation if needed.`,
|
|
140
|
+
`Run /gsd planner to launch ${GSD_PLANNER_COMMAND}, or run /gsd auto to continue without planner changes.`,
|
|
141
|
+
].join(" ");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function formatPlannerLaunchUnavailable(plan: GsdPlannerSpawnPlan, error: Error): string {
|
|
145
|
+
return [
|
|
146
|
+
`Could not launch ${GSD_PLANNER_COMMAND}: ${error.message}`,
|
|
147
|
+
`Install ${GSD_PLANNER_COMMAND} or run it manually: ${formatGsdPlannerCommand(plan)}`,
|
|
148
|
+
].join("\n");
|
|
149
|
+
}
|
|
@@ -18,6 +18,13 @@ function isInsideAnyBase(bases: string[], candidate: string): boolean {
|
|
|
18
18
|
return bases.some((base) => isInsideBase(base, candidate));
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function resolvesInsideRoot(root: string, candidate: string): boolean {
|
|
22
|
+
const resolvedCandidate = isAbsolute(candidate)
|
|
23
|
+
? resolve(candidate)
|
|
24
|
+
: resolve(root, candidate);
|
|
25
|
+
return isInsideBase(root, resolvedCandidate);
|
|
26
|
+
}
|
|
27
|
+
|
|
21
28
|
/**
|
|
22
29
|
* Planning IO fields are execution contracts. Absolute paths are only safe when
|
|
23
30
|
* they stay inside the active working directory; in worktree mode, an absolute
|
|
@@ -37,13 +44,24 @@ export function validatePlanningPathScope(
|
|
|
37
44
|
if (!shouldValidatePlanningPathReference(trimmed)) continue;
|
|
38
45
|
|
|
39
46
|
const candidate = normalizePlannedFileReference(raw);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
if (isAbsolute(candidate)) {
|
|
48
|
+
if (isInsideAnyBase(absoluteRoots, resolve(candidate))) continue;
|
|
49
|
+
} else if (absoluteRoots.some((root) => resolvesInsideRoot(root, candidate))) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
44
52
|
return `${field} contains path outside allowed repository roots: ${candidate}. Use a path within one of: ${absoluteRoots.join(", ")}.`;
|
|
45
53
|
}
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
return null;
|
|
49
57
|
}
|
|
58
|
+
|
|
59
|
+
export function validatePathOnlyPlanningFields(fields: PlanningPathScopeField[]): string | null {
|
|
60
|
+
for (const { field, values } of fields) {
|
|
61
|
+
for (const raw of values) {
|
|
62
|
+
if (shouldValidatePlanningPathReference(raw)) continue;
|
|
63
|
+
return `${field} must contain only file paths; invalid entry: ${raw}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
@@ -469,6 +469,13 @@ export function shouldValidatePlanningPathReference(raw: string): boolean {
|
|
|
469
469
|
return shouldValidateInputAsPath(raw);
|
|
470
470
|
}
|
|
471
471
|
|
|
472
|
+
export function extractPlanningPathReference(raw: string): string | null {
|
|
473
|
+
const trimmed = raw.trim();
|
|
474
|
+
if (!trimmed || NON_PATH_SENTINEL_RE.test(trimmed)) return null;
|
|
475
|
+
if (!shouldValidateInputAsPath(trimmed)) return null;
|
|
476
|
+
return extractPathFromAnnotation(trimmed);
|
|
477
|
+
}
|
|
478
|
+
|
|
472
479
|
function shouldValidateInputAsPath(raw: string): boolean {
|
|
473
480
|
const trimmed = raw.trim();
|
|
474
481
|
if (!trimmed) return false;
|
|
@@ -483,7 +490,8 @@ function shouldValidateInputAsPath(raw: string): boolean {
|
|
|
483
490
|
if (URL_SCHEME_PATTERN.test(candidate)) return false;
|
|
484
491
|
if (SCP_PATTERN.test(candidate)) return false;
|
|
485
492
|
|
|
486
|
-
|
|
493
|
+
const explicitlyWrappedPath = /^`+[^`]+`+/.test(trimmed) || /^(["'])([^"']+)\1$/.test(trimmed);
|
|
494
|
+
if (explicitlyWrappedPath && looksLikePathOrUrl(candidate)) {
|
|
487
495
|
return true;
|
|
488
496
|
}
|
|
489
497
|
|
|
@@ -496,7 +504,6 @@ function shouldValidateInputAsPath(raw: string): boolean {
|
|
|
496
504
|
candidate.startsWith("./") ||
|
|
497
505
|
candidate.startsWith("../") ||
|
|
498
506
|
candidate.startsWith("~/") ||
|
|
499
|
-
/[\\/]/.test(candidate) ||
|
|
500
507
|
/[*?[\]{}]/.test(candidate)
|
|
501
508
|
);
|
|
502
509
|
}
|
|
@@ -19,6 +19,9 @@ import type {
|
|
|
19
19
|
GSDPreferences,
|
|
20
20
|
GSDModelConfigV2,
|
|
21
21
|
GSDPhaseModelConfig,
|
|
22
|
+
GSDThinkingLevel,
|
|
23
|
+
GSDModelPhaseKey,
|
|
24
|
+
GSDThinkingConfig,
|
|
22
25
|
ResolvedModelConfig,
|
|
23
26
|
AutoSupervisorConfig,
|
|
24
27
|
} from "./preferences-types.js";
|
|
@@ -37,82 +40,103 @@ export function resolveModelForUnit(unitType: string): string | undefined {
|
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
43
|
+
* Ordered phase-bucket chain a unit type resolves against, most-specific
|
|
44
|
+
* first. The first chain entry with a configured value wins; later entries
|
|
45
|
+
* are siblings the unit falls back to (e.g. `discuss → planning`).
|
|
42
46
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
47
|
+
* Single source of truth for the unit-type → phase mapping, shared by model
|
|
48
|
+
* resolution (`resolveModelWithFallbacksForUnit`) and thinking resolution
|
|
49
|
+
* (`resolveThinkingLevelForUnit`) so the two never drift (ADR-026).
|
|
46
50
|
*/
|
|
47
|
-
export function
|
|
48
|
-
const prefs = loadEffectiveGSDPreferences(undefined, { availableModelIds: [] });
|
|
49
|
-
const models = prefs?.preferences?.models;
|
|
50
|
-
if (!models) return undefined;
|
|
51
|
-
const m = models as GSDModelConfigV2;
|
|
52
|
-
|
|
53
|
-
let phaseConfig: string | GSDPhaseModelConfig | undefined;
|
|
51
|
+
export function phaseChainForUnit(unitType: string): GSDModelPhaseKey[] | undefined {
|
|
54
52
|
switch (unitType) {
|
|
55
53
|
case "research-milestone":
|
|
56
54
|
case "research-slice":
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
// Deep-mode project research orchestrator. Reads PROJECT.md / REQUIREMENTS.md
|
|
56
|
+
// and fans out research subagents. Routes to the research bucket.
|
|
57
|
+
case "research-project":
|
|
58
|
+
return ["research"];
|
|
59
59
|
case "plan-milestone":
|
|
60
60
|
case "plan-slice":
|
|
61
61
|
case "refine-slice":
|
|
62
62
|
case "replan-slice":
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
return ["planning"];
|
|
64
|
+
// Deep-mode project-level discussion units route to the same model bucket
|
|
65
|
+
// as milestone-level discussion (interactive interview style). Workflow
|
|
66
|
+
// preferences and research-decision are tiny ask_user_questions style units
|
|
67
|
+
// that share the discuss bucket because they are conversational. All fall
|
|
68
|
+
// back to planning when no `discuss` bucket is set.
|
|
65
69
|
case "discuss-milestone":
|
|
66
70
|
case "discuss-slice":
|
|
67
|
-
// Deep-mode project-level discussion units route to the same model
|
|
68
|
-
// bucket as milestone-level discussion (interactive interview style).
|
|
69
71
|
case "discuss-project":
|
|
70
72
|
case "discuss-requirements":
|
|
71
|
-
// Workflow preferences and research-decision are tiny ask_user_questions
|
|
72
|
-
// style units; they share the discuss bucket because they are
|
|
73
|
-
// conversational rather than research/execution. Falling back to planning
|
|
74
|
-
// when no `discuss` bucket is set keeps parity with the milestone units.
|
|
75
73
|
case "workflow-preferences":
|
|
76
74
|
case "research-decision":
|
|
77
|
-
|
|
78
|
-
break;
|
|
79
|
-
// Deep-mode project research orchestrator. Reads PROJECT.md / REQUIREMENTS.md
|
|
80
|
-
// and fans out research subagents. Routes to the research bucket so it
|
|
81
|
-
// gets the research-tier model when one is configured.
|
|
82
|
-
case "research-project":
|
|
83
|
-
phaseConfig = m.research;
|
|
84
|
-
break;
|
|
75
|
+
return ["discuss", "planning"];
|
|
85
76
|
case "execute-task":
|
|
86
77
|
case "reactive-execute":
|
|
87
|
-
|
|
88
|
-
break;
|
|
78
|
+
return ["execution"];
|
|
89
79
|
case "execute-task-simple":
|
|
90
|
-
|
|
91
|
-
break;
|
|
80
|
+
return ["execution_simple", "execution"];
|
|
92
81
|
case "complete-slice":
|
|
93
82
|
case "complete-milestone":
|
|
94
83
|
case "worktree-merge":
|
|
95
|
-
|
|
96
|
-
break;
|
|
84
|
+
return ["completion"];
|
|
97
85
|
case "run-uat":
|
|
98
|
-
|
|
99
|
-
break;
|
|
86
|
+
return ["uat", "completion"];
|
|
100
87
|
case "reassess-roadmap":
|
|
101
88
|
case "rewrite-docs":
|
|
102
89
|
case "gate-evaluate":
|
|
103
90
|
case "validate-milestone":
|
|
104
|
-
|
|
105
|
-
break;
|
|
91
|
+
return ["validation", "planning"];
|
|
106
92
|
default:
|
|
107
93
|
// Subagent unit types (e.g., "subagent", "subagent/scout")
|
|
108
94
|
if (unitType === "subagent" || unitType.startsWith("subagent/")) {
|
|
109
|
-
|
|
110
|
-
break;
|
|
95
|
+
return ["subagent"];
|
|
111
96
|
}
|
|
112
97
|
return undefined;
|
|
113
98
|
}
|
|
99
|
+
}
|
|
114
100
|
|
|
115
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Find the phase bucket whose `models` entry wins the chain for a unit, plus
|
|
103
|
+
* that entry. Returns undefined when no phase in the chain is configured.
|
|
104
|
+
*/
|
|
105
|
+
function resolveWinningPhase(
|
|
106
|
+
models: GSDModelConfigV2 | undefined,
|
|
107
|
+
chain: GSDModelPhaseKey[],
|
|
108
|
+
): { phase: GSDModelPhaseKey; config: string | GSDPhaseModelConfig } | undefined {
|
|
109
|
+
if (!models) return undefined;
|
|
110
|
+
for (const key of chain) {
|
|
111
|
+
const config = models[key];
|
|
112
|
+
// Falsy check (not `!= null`) so an empty-string model is treated as
|
|
113
|
+
// unconfigured and the chain falls through — matches the pre-refactor
|
|
114
|
+
// switch, which bailed via `if (!phaseConfig)`.
|
|
115
|
+
if (!config) continue;
|
|
116
|
+
// An object entry only "wins" if it provides a usable model. A model-less
|
|
117
|
+
// object (e.g. `{ provider: x }`, or `{}` left after stripping an invalid
|
|
118
|
+
// `thinking`) must not shadow sibling fallback or yield `{ primary: undefined }`.
|
|
119
|
+
if (typeof config === "object" && !config.model) continue;
|
|
120
|
+
return { phase: key, config };
|
|
121
|
+
}
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Resolve model and fallbacks for a given auto-mode unit type.
|
|
127
|
+
* Returns the primary model and ordered fallbacks, or undefined if not configured.
|
|
128
|
+
*
|
|
129
|
+
* Supports both legacy string format and extended object format:
|
|
130
|
+
* - Legacy: `planning: claude-opus-4-6`
|
|
131
|
+
* - Extended: `planning: { model: claude-opus-4-6, fallbacks: [glm-5, minimax-m2.5] }`
|
|
132
|
+
*/
|
|
133
|
+
export function resolveModelWithFallbacksForUnit(unitType: string): ResolvedModelConfig | undefined {
|
|
134
|
+
const prefs = loadEffectiveGSDPreferences(undefined, { availableModelIds: [] });
|
|
135
|
+
const chain = phaseChainForUnit(unitType);
|
|
136
|
+
if (!chain) return undefined;
|
|
137
|
+
const winner = resolveWinningPhase(prefs?.preferences?.models as GSDModelConfigV2 | undefined, chain);
|
|
138
|
+
if (!winner) return undefined;
|
|
139
|
+
const phaseConfig = winner.config;
|
|
116
140
|
|
|
117
141
|
// Normalize: string -> { model, fallbacks: [] }
|
|
118
142
|
if (typeof phaseConfig === "string") {
|
|
@@ -131,6 +155,51 @@ export function resolveModelWithFallbacksForUnit(unitType: string): ResolvedMode
|
|
|
131
155
|
};
|
|
132
156
|
}
|
|
133
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Resolve the explicitly configured reasoning effort for a unit type (ADR-026).
|
|
160
|
+
*
|
|
161
|
+
* Thinking travels with the model. The chain is walked most-specific-first up to
|
|
162
|
+
* and including the phase whose model won; at each level inline
|
|
163
|
+
* `models.<phase>.thinking` is preferred, then the same phase's `thinking` block
|
|
164
|
+
* entry. This means:
|
|
165
|
+
* - a more-specific block key (`thinking.execution_simple`) surfaces even when
|
|
166
|
+
* the model only resolves on a less-specific sibling (`models.execution`);
|
|
167
|
+
* - inline thinking is honored even on a model-less `models.<phase>` entry
|
|
168
|
+
* (e.g. `{ thinking: "high" }` with no `model`);
|
|
169
|
+
* - a unit that claimed its own model bucket never borrows a *less*-specific
|
|
170
|
+
* sibling's thinking (the walk stops at the winning phase).
|
|
171
|
+
* When no model is configured anywhere in the chain, the walk spans the full
|
|
172
|
+
* chain so inline thinking and the `thinking` block both resolve on their own
|
|
173
|
+
* sibling chain.
|
|
174
|
+
*
|
|
175
|
+
* Returns undefined when nothing explicit is configured — the dispatch path
|
|
176
|
+
* then falls back to the session/default level and applies the code-writing
|
|
177
|
+
* floor. Session level, defaults, the floor, and capability clamping are NOT
|
|
178
|
+
* applied here.
|
|
179
|
+
*/
|
|
180
|
+
export function resolveThinkingLevelForUnit(unitType: string): GSDThinkingLevel | undefined {
|
|
181
|
+
const prefs = loadEffectiveGSDPreferences(undefined, { availableModelIds: [] })?.preferences;
|
|
182
|
+
if (!prefs) return undefined;
|
|
183
|
+
const chain = phaseChainForUnit(unitType);
|
|
184
|
+
if (!chain) return undefined;
|
|
185
|
+
|
|
186
|
+
const models = prefs.models as GSDModelConfigV2 | undefined;
|
|
187
|
+
const block = prefs.thinking as GSDThinkingConfig | undefined;
|
|
188
|
+
|
|
189
|
+
// Walk most-specific-first, up to and including the winning model phase (or
|
|
190
|
+
// the full chain when no model is configured), checking inline then block.
|
|
191
|
+
const winner = resolveWinningPhase(models, chain);
|
|
192
|
+
const limit = winner ? chain.indexOf(winner.phase) + 1 : chain.length;
|
|
193
|
+
for (let i = 0; i < limit; i++) {
|
|
194
|
+
const key = chain[i];
|
|
195
|
+
const entry = models?.[key];
|
|
196
|
+
if (typeof entry === "object" && entry?.thinking) return entry.thinking; // inline (incl. model-less)
|
|
197
|
+
const blockLevel = block?.[key];
|
|
198
|
+
if (blockLevel) return blockLevel; // block
|
|
199
|
+
}
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
|
|
134
203
|
/**
|
|
135
204
|
* Resolve the default session model from GSD preferences.
|
|
136
205
|
*
|
|
@@ -372,6 +441,7 @@ export function resolveAutoSupervisorConfig(): AutoSupervisorConfig {
|
|
|
372
441
|
soft_timeout_minutes: configured.soft_timeout_minutes ?? 20,
|
|
373
442
|
idle_timeout_minutes: configured.idle_timeout_minutes ?? 10,
|
|
374
443
|
hard_timeout_minutes: configured.hard_timeout_minutes ?? 30,
|
|
444
|
+
stalled_tool_timeout_minutes: configured.stalled_tool_timeout_minutes ?? 5,
|
|
375
445
|
...(configured.model ? { model: configured.model } : {}),
|
|
376
446
|
};
|
|
377
447
|
}
|
|
@@ -99,6 +99,7 @@ export const KNOWN_PREFERENCE_KEYS = new Set<string>([
|
|
|
99
99
|
"skill_rules",
|
|
100
100
|
"custom_instructions",
|
|
101
101
|
"models",
|
|
102
|
+
"thinking",
|
|
102
103
|
"skill_discovery",
|
|
103
104
|
"skill_staleness_days",
|
|
104
105
|
"auto_supervisor",
|
|
@@ -198,6 +199,28 @@ export interface GSDSkillRule {
|
|
|
198
199
|
avoid?: string[];
|
|
199
200
|
}
|
|
200
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Reasoning effort levels. Mirrors `ThinkingLevel` in `@gsd/pi-agent-core`;
|
|
204
|
+
* declared locally so preference parsing/validation does not import the agent
|
|
205
|
+
* core package. `xhigh` is only honored by models whose `thinkingLevelMap`
|
|
206
|
+
* advertises it — unsupported levels are clamped at dispatch (ADR-026).
|
|
207
|
+
*/
|
|
208
|
+
export type GSDThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
209
|
+
|
|
210
|
+
/** The nine model-routing phase buckets. */
|
|
211
|
+
export const GSD_MODEL_PHASE_KEYS = [
|
|
212
|
+
"research",
|
|
213
|
+
"planning",
|
|
214
|
+
"discuss",
|
|
215
|
+
"execution",
|
|
216
|
+
"execution_simple",
|
|
217
|
+
"completion",
|
|
218
|
+
"validation",
|
|
219
|
+
"subagent",
|
|
220
|
+
"uat",
|
|
221
|
+
] as const;
|
|
222
|
+
export type GSDModelPhaseKey = (typeof GSD_MODEL_PHASE_KEYS)[number];
|
|
223
|
+
|
|
201
224
|
/**
|
|
202
225
|
* Model configuration for a single phase.
|
|
203
226
|
* Supports primary model with optional fallbacks for resilience.
|
|
@@ -209,8 +232,22 @@ export interface GSDPhaseModelConfig {
|
|
|
209
232
|
provider?: string;
|
|
210
233
|
/** Fallback models to try in order if primary fails (e.g., rate limits, credits exhausted) */
|
|
211
234
|
fallbacks?: string[];
|
|
235
|
+
/**
|
|
236
|
+
* Reasoning effort for this phase (ADR-026). Travels with the model: an
|
|
237
|
+
* explicit value here bypasses the `execute-task` thinking floor and is
|
|
238
|
+
* capability-clamped to the resolved model at dispatch. Takes precedence
|
|
239
|
+
* over a same-phase entry in the separate `thinking` block.
|
|
240
|
+
*/
|
|
241
|
+
thinking?: GSDThinkingLevel;
|
|
212
242
|
}
|
|
213
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Separate per-phase reasoning-effort block (ADR-026). An alternative to
|
|
246
|
+
* inline `models.<phase>.thinking` that lets thinking be pinned without
|
|
247
|
+
* pinning a model. Same nine phase keys as `models`.
|
|
248
|
+
*/
|
|
249
|
+
export type GSDThinkingConfig = Partial<Record<GSDModelPhaseKey, GSDThinkingLevel>>;
|
|
250
|
+
|
|
214
251
|
/**
|
|
215
252
|
* Legacy model config -- simple string per phase.
|
|
216
253
|
* Kept for backward compatibility; will be migrated to GSDModelConfigV2 on load.
|
|
@@ -256,6 +293,14 @@ export interface AutoSupervisorConfig {
|
|
|
256
293
|
soft_timeout_minutes?: number;
|
|
257
294
|
idle_timeout_minutes?: number;
|
|
258
295
|
hard_timeout_minutes?: number;
|
|
296
|
+
/**
|
|
297
|
+
* Dedicated budget for a single in-flight tool call before it is treated as
|
|
298
|
+
* hung. Distinct from `idle_timeout_minutes`: a genuinely stuck tool should
|
|
299
|
+
* be recovered in minutes rather than waiting out the full idle window. A
|
|
300
|
+
* long-but-progressing session is not idle, so it must not share the hung-tool
|
|
301
|
+
* threshold.
|
|
302
|
+
*/
|
|
303
|
+
stalled_tool_timeout_minutes?: number;
|
|
259
304
|
}
|
|
260
305
|
|
|
261
306
|
export interface RemoteQuestionsConfig {
|
|
@@ -364,6 +409,8 @@ export interface GSDPreferences {
|
|
|
364
409
|
skill_rules?: GSDSkillRule[];
|
|
365
410
|
custom_instructions?: string[];
|
|
366
411
|
models?: GSDModelConfig | GSDModelConfigV2;
|
|
412
|
+
/** Per-phase reasoning effort, separate from `models` (ADR-026). */
|
|
413
|
+
thinking?: GSDThinkingConfig;
|
|
367
414
|
skill_discovery?: SkillDiscoveryMode;
|
|
368
415
|
skill_staleness_days?: number; // Skills unused for N days get deprioritized (#599). 0 = disabled. Default: 60.
|
|
369
416
|
auto_supervisor?: AutoSupervisorConfig;
|
|
@@ -12,18 +12,30 @@ import type { DynamicRoutingConfig } from "./model-router.js";
|
|
|
12
12
|
import { isAbsolute } from "node:path";
|
|
13
13
|
import { VALID_BRANCH_NAME } from "./git-service.js";
|
|
14
14
|
import { normalizeStringArray } from "../shared/format-utils.js";
|
|
15
|
+
import { getGateIdsForTurn } from "./gate-registry.js";
|
|
15
16
|
|
|
16
17
|
import {
|
|
17
18
|
KNOWN_PREFERENCE_KEYS,
|
|
18
19
|
KNOWN_UNIT_LABELS,
|
|
20
|
+
GSD_MODEL_PHASE_KEYS,
|
|
19
21
|
|
|
20
22
|
SKILL_ACTIONS,
|
|
21
23
|
type WorkflowMode,
|
|
22
24
|
type GSDPreferences,
|
|
23
25
|
type GSDSkillRule,
|
|
26
|
+
type GSDThinkingLevel,
|
|
24
27
|
} from "./preferences-types.js";
|
|
25
28
|
|
|
26
29
|
const VALID_TOKEN_PROFILES = new Set<TokenProfile>(["budget", "balanced", "quality", "burn-max"]);
|
|
30
|
+
const VALID_THINKING_LEVELS = new Set<GSDThinkingLevel>([
|
|
31
|
+
"off",
|
|
32
|
+
"minimal",
|
|
33
|
+
"low",
|
|
34
|
+
"medium",
|
|
35
|
+
"high",
|
|
36
|
+
"xhigh",
|
|
37
|
+
]);
|
|
38
|
+
const KNOWN_MODEL_PHASE_KEYS = new Set<string>(GSD_MODEL_PHASE_KEYS);
|
|
27
39
|
const VALID_UOK_TURN_ACTIONS = new Set<"commit" | "snapshot" | "status-only">([
|
|
28
40
|
"commit",
|
|
29
41
|
"snapshot",
|
|
@@ -37,6 +49,7 @@ const VALID_POST_UNIT_HOOK_ON_BLOCK_ACTIONS = new Set([
|
|
|
37
49
|
"queue-slice",
|
|
38
50
|
"pause",
|
|
39
51
|
]);
|
|
52
|
+
const VALID_GATE_EVALUATE_SLICE_GATES = new Set<string>(getGateIdsForTurn("gate-evaluate"));
|
|
40
53
|
|
|
41
54
|
export function validatePreferences(preferences: GSDPreferences): {
|
|
42
55
|
preferences: GSDPreferences;
|
|
@@ -390,12 +403,66 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
390
403
|
// ─── Models ─────────────────────────────────────────────────────────
|
|
391
404
|
if (preferences.models !== undefined) {
|
|
392
405
|
if (preferences.models && typeof preferences.models === "object") {
|
|
393
|
-
|
|
406
|
+
// Static check for inline per-phase thinking (ADR-026). The resolved
|
|
407
|
+
// model isn't known until dispatch, so capability is clamped there; here
|
|
408
|
+
// we warn on illegal level strings AND strip them, so a typo can't reach
|
|
409
|
+
// resolveThinkingLevelForUnit and be treated as explicit configuration.
|
|
410
|
+
const sanitizedModels: Record<string, unknown> = {};
|
|
411
|
+
for (const [phase, entry] of Object.entries(preferences.models as Record<string, unknown>)) {
|
|
412
|
+
if (entry && typeof entry === "object" && "thinking" in entry) {
|
|
413
|
+
const level = (entry as { thinking?: unknown }).thinking;
|
|
414
|
+
if (level !== undefined && !VALID_THINKING_LEVELS.has(level as GSDThinkingLevel)) {
|
|
415
|
+
warnings.push(
|
|
416
|
+
`models.${phase}.thinking "${String(level)}" is not a valid thinking level ` +
|
|
417
|
+
`(off, minimal, low, medium, high, xhigh) — ignored`,
|
|
418
|
+
);
|
|
419
|
+
const { thinking: _ignored, ...rest } = entry as Record<string, unknown>;
|
|
420
|
+
// If stripping the bad thinking leaves no usable model, drop the
|
|
421
|
+
// phase entirely rather than storing a hollow `{}` / `{ provider }`
|
|
422
|
+
// entry that resolveWinningPhase would otherwise treat as configured.
|
|
423
|
+
if (rest.model) {
|
|
424
|
+
sanitizedModels[phase] = rest;
|
|
425
|
+
}
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
sanitizedModels[phase] = entry;
|
|
430
|
+
}
|
|
431
|
+
validated.models = sanitizedModels as GSDPreferences["models"];
|
|
394
432
|
} else {
|
|
395
433
|
errors.push("models must be an object");
|
|
396
434
|
}
|
|
397
435
|
}
|
|
398
436
|
|
|
437
|
+
// ─── Thinking (separate per-phase block, ADR-026) ───────────────────
|
|
438
|
+
if (preferences.thinking !== undefined) {
|
|
439
|
+
if (preferences.thinking && typeof preferences.thinking === "object" && !Array.isArray(preferences.thinking)) {
|
|
440
|
+
const validatedThinking: Record<string, GSDThinkingLevel> = {};
|
|
441
|
+
for (const [phase, level] of Object.entries(preferences.thinking as Record<string, unknown>)) {
|
|
442
|
+
if (!KNOWN_MODEL_PHASE_KEYS.has(phase)) {
|
|
443
|
+
warnings.push(
|
|
444
|
+
`unknown thinking phase "${phase}" — must be one of: ` +
|
|
445
|
+
`${[...KNOWN_MODEL_PHASE_KEYS].join(", ")} — ignored`,
|
|
446
|
+
);
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
if (!VALID_THINKING_LEVELS.has(level as GSDThinkingLevel)) {
|
|
450
|
+
warnings.push(
|
|
451
|
+
`thinking.${phase} "${String(level)}" is not a valid thinking level ` +
|
|
452
|
+
`(off, minimal, low, medium, high, xhigh) — ignored`,
|
|
453
|
+
);
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
validatedThinking[phase] = level as GSDThinkingLevel;
|
|
457
|
+
}
|
|
458
|
+
if (Object.keys(validatedThinking).length > 0) {
|
|
459
|
+
validated.thinking = validatedThinking;
|
|
460
|
+
}
|
|
461
|
+
} else {
|
|
462
|
+
errors.push("thinking must be an object");
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
399
466
|
// ─── Auto Supervisor ────────────────────────────────────────────────
|
|
400
467
|
if (preferences.auto_supervisor !== undefined) {
|
|
401
468
|
if (preferences.auto_supervisor && typeof preferences.auto_supervisor === "object") {
|
|
@@ -907,7 +974,14 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
907
974
|
}
|
|
908
975
|
if (ge.slice_gates !== undefined) {
|
|
909
976
|
if (Array.isArray(ge.slice_gates) && ge.slice_gates.every((g: unknown) => typeof g === "string")) {
|
|
910
|
-
|
|
977
|
+
const invalid = ge.slice_gates.filter((g) => !VALID_GATE_EVALUATE_SLICE_GATES.has(g));
|
|
978
|
+
if (invalid.length === 0) {
|
|
979
|
+
validGe.slice_gates = ge.slice_gates;
|
|
980
|
+
} else {
|
|
981
|
+
errors.push(
|
|
982
|
+
`gate_evaluation.slice_gates must contain only gate-evaluate slice gates: ${[...VALID_GATE_EVALUATE_SLICE_GATES].join(", ")}`,
|
|
983
|
+
);
|
|
984
|
+
}
|
|
911
985
|
} else {
|
|
912
986
|
errors.push("gate_evaluation.slice_gates must be an array of strings");
|
|
913
987
|
}
|
|
@@ -86,6 +86,8 @@ export function resolveSkillStalenessDays(basePath?: string): number {
|
|
|
86
86
|
export {
|
|
87
87
|
resolveModelForUnit,
|
|
88
88
|
resolveModelWithFallbacksForUnit,
|
|
89
|
+
resolveThinkingLevelForUnit,
|
|
90
|
+
phaseChainForUnit,
|
|
89
91
|
getNextFallbackModel,
|
|
90
92
|
isTransientNetworkError,
|
|
91
93
|
validateModelId,
|
|
@@ -437,6 +439,9 @@ function mergePreferences(base: GSDPreferences, override: GSDPreferences): GSDPr
|
|
|
437
439
|
skill_rules: [...(base.skill_rules ?? []), ...(override.skill_rules ?? [])],
|
|
438
440
|
custom_instructions: mergeStringLists(base.custom_instructions, override.custom_instructions),
|
|
439
441
|
models: { ...(base.models ?? {}), ...(override.models ?? {}) },
|
|
442
|
+
thinking: (base.thinking || override.thinking)
|
|
443
|
+
? { ...(base.thinking ?? {}), ...(override.thinking ?? {}) }
|
|
444
|
+
: undefined,
|
|
440
445
|
skill_discovery: override.skill_discovery ?? base.skill_discovery,
|
|
441
446
|
skill_staleness_days: override.skill_staleness_days ?? base.skill_staleness_days,
|
|
442
447
|
auto_supervisor: { ...(base.auto_supervisor ?? {}), ...(override.auto_supervisor ?? {}) },
|
|
@@ -38,7 +38,7 @@ You are evaluating **quality gates in parallel** for this slice. Each gate is an
|
|
|
38
38
|
3. **Verify each gate wrote its result** by checking that `gsd_save_gate_result` was called for each gate ID.
|
|
39
39
|
- Call it **directly** — do **not** use `ToolSearch` (it is not available in GSD).
|
|
40
40
|
- Inside Claude Code use the active MCP-scoped workflow name for `gsd_save_gate_result`; otherwise use `gsd_save_gate_result`.
|
|
41
|
-
- Always pass all required fields (camelCase): `milestoneId`, `sliceId`, `gateId`, `verdict`, `rationale
|
|
41
|
+
- Always pass all required fields (camelCase): `milestoneId`, `sliceId`, `gateId`, `verdict`, `rationale`, and `findings` (empty string if none). Never call with an empty `{}` object.
|
|
42
42
|
4. **Report the batch outcome** — which gates passed, which flagged concerns, and which were omitted as not applicable.
|
|
43
43
|
|
|
44
44
|
Gate agents may return `verdict: "omitted"` if the gate question is not applicable to this slice (e.g., no auth surface for Q3, no existing requirements touched for Q4). This is expected for simple slices.
|