@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
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
|
|
8
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
|
|
10
|
-
import { ModelPolicyDispatchBlockedError, resolvePreferredModelConfig, resolveModelId, selectAndApplyModel } from "../auto-model-selection.js";
|
|
10
|
+
import { ModelPolicyDispatchBlockedError, resolvePreferredModelConfig, resolveModelId, selectAndApplyModel, floorThinkingLevelForUnit } from "../auto-model-selection.js";
|
|
11
11
|
|
|
12
12
|
function makeTempDir(prefix: string): string {
|
|
13
13
|
return mkdtempSync(join(tmpdir(), prefix));
|
|
@@ -534,6 +534,304 @@ test("selectAndApplyModel re-applies captured thinking level after setModel succ
|
|
|
534
534
|
assert.deepEqual(thinkingLevels, [{ effort: "high" }]);
|
|
535
535
|
});
|
|
536
536
|
|
|
537
|
+
// ─── floorThinkingLevelForUnit (#read-bash-thrash) ─────────────────────
|
|
538
|
+
test("floorThinkingLevelForUnit raises minimal/low to the floor for execute-task", () => {
|
|
539
|
+
assert.equal(floorThinkingLevelForUnit("execute-task", "off" as any), "medium");
|
|
540
|
+
assert.equal(floorThinkingLevelForUnit("execute-task", "minimal" as any), "medium");
|
|
541
|
+
assert.equal(floorThinkingLevelForUnit("execute-task", "low" as any), "medium");
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
test("floorThinkingLevelForUnit never lowers a level already at/above the floor", () => {
|
|
545
|
+
assert.equal(floorThinkingLevelForUnit("execute-task", "medium" as any), "medium");
|
|
546
|
+
assert.equal(floorThinkingLevelForUnit("execute-task", "high" as any), "high");
|
|
547
|
+
assert.equal(floorThinkingLevelForUnit("execute-task", "xhigh" as any), "xhigh");
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
test("floorThinkingLevelForUnit leaves non-execute-task units untouched", () => {
|
|
551
|
+
for (const unit of ["plan-slice", "plan-milestone", "research-milestone", "complete-slice", "validate-milestone"]) {
|
|
552
|
+
assert.equal(floorThinkingLevelForUnit(unit, "minimal" as any), "minimal");
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
test("floorThinkingLevelForUnit passes through null/undefined and unrecognized shapes", () => {
|
|
557
|
+
assert.equal(floorThinkingLevelForUnit("execute-task", null), null);
|
|
558
|
+
assert.equal(floorThinkingLevelForUnit("execute-task", undefined), undefined);
|
|
559
|
+
// A richer host snapshot object must not be coerced into a bare string.
|
|
560
|
+
const snapshot = { effort: "minimal" } as any;
|
|
561
|
+
assert.deepEqual(floorThinkingLevelForUnit("execute-task", snapshot), snapshot);
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
test("selectAndApplyModel raises minimal thinking to the floor for execute-task", async (t) => {
|
|
565
|
+
const originalCwd = process.cwd();
|
|
566
|
+
const tempProject = makeTempDir("gsd-routing-thinking-floor-");
|
|
567
|
+
const thinkingLevels: unknown[] = [];
|
|
568
|
+
t.after(() => {
|
|
569
|
+
process.chdir(originalCwd);
|
|
570
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
574
|
+
writeFileSync(
|
|
575
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
576
|
+
["---", "models:", " execute-task: claude-sonnet-4-6", "---"].join("\n"),
|
|
577
|
+
"utf-8",
|
|
578
|
+
);
|
|
579
|
+
process.chdir(tempProject);
|
|
580
|
+
|
|
581
|
+
await selectAndApplyModel(
|
|
582
|
+
{
|
|
583
|
+
modelRegistry: { getAvailable: () => [{ id: "claude-sonnet-4-6", provider: "anthropic", api: "anthropic-messages" }] },
|
|
584
|
+
sessionManager: { getSessionId: () => "test-session" },
|
|
585
|
+
ui: { notify: () => {} },
|
|
586
|
+
model: { provider: "anthropic", id: "claude-sonnet-4-6", api: "anthropic-messages" },
|
|
587
|
+
} as any,
|
|
588
|
+
{
|
|
589
|
+
setModel: async () => true,
|
|
590
|
+
setThinkingLevel: (level: unknown) => { thinkingLevels.push(level); },
|
|
591
|
+
emitBeforeModelSelect: async () => undefined,
|
|
592
|
+
getActiveTools: () => [],
|
|
593
|
+
emitAdjustToolSet: async () => undefined,
|
|
594
|
+
setActiveTools: () => {},
|
|
595
|
+
} as any,
|
|
596
|
+
"execute-task",
|
|
597
|
+
"M001/S01/T01",
|
|
598
|
+
tempProject,
|
|
599
|
+
undefined,
|
|
600
|
+
false,
|
|
601
|
+
{ provider: "anthropic", id: "claude-sonnet-4-6" },
|
|
602
|
+
undefined,
|
|
603
|
+
true,
|
|
604
|
+
undefined,
|
|
605
|
+
"minimal" as any,
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
assert.deepEqual(thinkingLevels, ["medium"]);
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
test("selectAndApplyModel capability-clamps an unsupported thinking level (ADR-026)", async (t) => {
|
|
612
|
+
const originalCwd = process.cwd();
|
|
613
|
+
const tempProject = makeTempDir("gsd-routing-thinking-clamp-");
|
|
614
|
+
const thinkingLevels: unknown[] = [];
|
|
615
|
+
t.after(() => {
|
|
616
|
+
process.chdir(originalCwd);
|
|
617
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// Reasoning-capable model whose map omits xhigh → xhigh must clamp to high.
|
|
621
|
+
const model = {
|
|
622
|
+
id: "claude-sonnet-4-6",
|
|
623
|
+
provider: "anthropic",
|
|
624
|
+
api: "anthropic-messages",
|
|
625
|
+
reasoning: true,
|
|
626
|
+
thinkingLevelMap: { low: "low", medium: "medium", high: "high" },
|
|
627
|
+
};
|
|
628
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
629
|
+
writeFileSync(
|
|
630
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
631
|
+
["---", "models:", " planning: claude-sonnet-4-6", "---"].join("\n"),
|
|
632
|
+
"utf-8",
|
|
633
|
+
);
|
|
634
|
+
process.chdir(tempProject);
|
|
635
|
+
|
|
636
|
+
await selectAndApplyModel(
|
|
637
|
+
{
|
|
638
|
+
modelRegistry: { getAvailable: () => [model] },
|
|
639
|
+
sessionManager: { getSessionId: () => "test-session" },
|
|
640
|
+
ui: { notify: () => {} },
|
|
641
|
+
model: { provider: "anthropic", id: "claude-sonnet-4-6", api: "anthropic-messages" },
|
|
642
|
+
} as any,
|
|
643
|
+
{
|
|
644
|
+
setModel: async () => true,
|
|
645
|
+
setThinkingLevel: (level: unknown) => { thinkingLevels.push(level); },
|
|
646
|
+
emitBeforeModelSelect: async () => undefined,
|
|
647
|
+
getActiveTools: () => [],
|
|
648
|
+
emitAdjustToolSet: async () => undefined,
|
|
649
|
+
setActiveTools: () => {},
|
|
650
|
+
} as any,
|
|
651
|
+
"plan-slice",
|
|
652
|
+
"M001/S01",
|
|
653
|
+
tempProject,
|
|
654
|
+
undefined,
|
|
655
|
+
false,
|
|
656
|
+
{ provider: "anthropic", id: "claude-sonnet-4-6" },
|
|
657
|
+
undefined,
|
|
658
|
+
true,
|
|
659
|
+
undefined,
|
|
660
|
+
"xhigh" as any,
|
|
661
|
+
);
|
|
662
|
+
|
|
663
|
+
assert.deepEqual(thinkingLevels, ["high"]);
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
test("selectAndApplyModel applies an explicit per-phase thinking level (ADR-026)", async (t) => {
|
|
667
|
+
const originalCwd = process.cwd();
|
|
668
|
+
const tempProject = makeTempDir("gsd-routing-thinking-explicit-");
|
|
669
|
+
const thinkingLevels: unknown[] = [];
|
|
670
|
+
t.after(() => {
|
|
671
|
+
process.chdir(originalCwd);
|
|
672
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
const model = {
|
|
676
|
+
id: "claude-sonnet-4-6",
|
|
677
|
+
provider: "anthropic",
|
|
678
|
+
api: "anthropic-messages",
|
|
679
|
+
reasoning: true,
|
|
680
|
+
thinkingLevelMap: { low: "low", medium: "medium", high: "high", xhigh: "xhigh" },
|
|
681
|
+
};
|
|
682
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
683
|
+
writeFileSync(
|
|
684
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
685
|
+
["---", "models:", " planning:", " model: claude-sonnet-4-6", " thinking: xhigh", "---"].join("\n"),
|
|
686
|
+
"utf-8",
|
|
687
|
+
);
|
|
688
|
+
process.chdir(tempProject);
|
|
689
|
+
|
|
690
|
+
await selectAndApplyModel(
|
|
691
|
+
{
|
|
692
|
+
modelRegistry: { getAvailable: () => [model] },
|
|
693
|
+
sessionManager: { getSessionId: () => "test-session" },
|
|
694
|
+
ui: { notify: () => {} },
|
|
695
|
+
model: { provider: "anthropic", id: "claude-sonnet-4-6", api: "anthropic-messages" },
|
|
696
|
+
} as any,
|
|
697
|
+
{
|
|
698
|
+
setModel: async () => true,
|
|
699
|
+
setThinkingLevel: (level: unknown) => { thinkingLevels.push(level); },
|
|
700
|
+
emitBeforeModelSelect: async () => undefined,
|
|
701
|
+
getActiveTools: () => [],
|
|
702
|
+
emitAdjustToolSet: async () => undefined,
|
|
703
|
+
setActiveTools: () => {},
|
|
704
|
+
} as any,
|
|
705
|
+
"plan-slice",
|
|
706
|
+
"M001/S01",
|
|
707
|
+
tempProject,
|
|
708
|
+
undefined,
|
|
709
|
+
false,
|
|
710
|
+
{ provider: "anthropic", id: "claude-sonnet-4-6" },
|
|
711
|
+
undefined,
|
|
712
|
+
true,
|
|
713
|
+
undefined,
|
|
714
|
+
// Session level is "low"; the explicit planning thinking (xhigh) must win.
|
|
715
|
+
"low" as any,
|
|
716
|
+
);
|
|
717
|
+
|
|
718
|
+
assert.deepEqual(thinkingLevels, ["xhigh"]);
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
test("selectAndApplyModel applies explicit thinking with no model pin (interactive, ADR-026)", async (t) => {
|
|
722
|
+
const originalCwd = process.cwd();
|
|
723
|
+
const tempProject = makeTempDir("gsd-routing-thinking-nomodel-");
|
|
724
|
+
const thinkingLevels: unknown[] = [];
|
|
725
|
+
t.after(() => {
|
|
726
|
+
process.chdir(originalCwd);
|
|
727
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
const model = {
|
|
731
|
+
id: "claude-sonnet-4-6",
|
|
732
|
+
provider: "anthropic",
|
|
733
|
+
api: "anthropic-messages",
|
|
734
|
+
reasoning: true,
|
|
735
|
+
thinkingLevelMap: { low: "low", medium: "medium", high: "high", xhigh: "xhigh" },
|
|
736
|
+
};
|
|
737
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
738
|
+
// A `thinking:` block with NO models config — the interactive guided-flow
|
|
739
|
+
// scenario the bug report flagged (no per-phase model, no start model).
|
|
740
|
+
writeFileSync(
|
|
741
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
742
|
+
["---", "thinking:", " planning: high", "---"].join("\n"),
|
|
743
|
+
"utf-8",
|
|
744
|
+
);
|
|
745
|
+
process.chdir(tempProject);
|
|
746
|
+
|
|
747
|
+
await selectAndApplyModel(
|
|
748
|
+
{
|
|
749
|
+
modelRegistry: { getAvailable: () => [model] },
|
|
750
|
+
sessionManager: { getSessionId: () => "test-session" },
|
|
751
|
+
ui: { notify: () => {} },
|
|
752
|
+
model: { provider: "anthropic", id: "claude-sonnet-4-6", api: "anthropic-messages" },
|
|
753
|
+
} as any,
|
|
754
|
+
{
|
|
755
|
+
setModel: async () => true,
|
|
756
|
+
setThinkingLevel: (level: unknown) => { thinkingLevels.push(level); },
|
|
757
|
+
emitBeforeModelSelect: async () => undefined,
|
|
758
|
+
getActiveTools: () => [],
|
|
759
|
+
emitAdjustToolSet: async () => undefined,
|
|
760
|
+
setActiveTools: () => {},
|
|
761
|
+
} as any,
|
|
762
|
+
"plan-slice",
|
|
763
|
+
"M001/S01",
|
|
764
|
+
tempProject,
|
|
765
|
+
undefined,
|
|
766
|
+
false,
|
|
767
|
+
null, // no autoModeStartModel
|
|
768
|
+
undefined,
|
|
769
|
+
false, // isAutoMode = false (interactive)
|
|
770
|
+
undefined,
|
|
771
|
+
undefined, // no captured session thinking level
|
|
772
|
+
);
|
|
773
|
+
|
|
774
|
+
// No model branch runs, but the explicit block thinking must still apply.
|
|
775
|
+
assert.deepEqual(thinkingLevels, ["high"]);
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
test("selectAndApplyModel clamps explicit no-model thinking via ctx.model when registry lookup fails (ADR-026)", async (t) => {
|
|
779
|
+
const originalCwd = process.cwd();
|
|
780
|
+
const tempProject = makeTempDir("gsd-routing-thinking-ctxmodel-");
|
|
781
|
+
const thinkingLevels: unknown[] = [];
|
|
782
|
+
t.after(() => {
|
|
783
|
+
process.chdir(originalCwd);
|
|
784
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
// ctx.model carries reasoning capability (map omits xhigh) but the registry
|
|
788
|
+
// returns nothing, so resolveModelId fails and ctx.model is the clamp source.
|
|
789
|
+
const ctxModel = {
|
|
790
|
+
id: "claude-sonnet-4-6",
|
|
791
|
+
provider: "anthropic",
|
|
792
|
+
api: "anthropic-messages",
|
|
793
|
+
reasoning: true,
|
|
794
|
+
thinkingLevelMap: { low: "low", medium: "medium", high: "high" },
|
|
795
|
+
};
|
|
796
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
797
|
+
writeFileSync(
|
|
798
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
799
|
+
["---", "thinking:", " planning: xhigh", "---"].join("\n"),
|
|
800
|
+
"utf-8",
|
|
801
|
+
);
|
|
802
|
+
process.chdir(tempProject);
|
|
803
|
+
|
|
804
|
+
await selectAndApplyModel(
|
|
805
|
+
{
|
|
806
|
+
modelRegistry: { getAvailable: () => [] }, // registry lookup fails
|
|
807
|
+
sessionManager: { getSessionId: () => "test-session" },
|
|
808
|
+
ui: { notify: () => {} },
|
|
809
|
+
model: ctxModel,
|
|
810
|
+
} as any,
|
|
811
|
+
{
|
|
812
|
+
setModel: async () => true,
|
|
813
|
+
setThinkingLevel: (level: unknown) => { thinkingLevels.push(level); },
|
|
814
|
+
emitBeforeModelSelect: async () => undefined,
|
|
815
|
+
getActiveTools: () => [],
|
|
816
|
+
emitAdjustToolSet: async () => undefined,
|
|
817
|
+
setActiveTools: () => {},
|
|
818
|
+
} as any,
|
|
819
|
+
"plan-slice",
|
|
820
|
+
"M001/S01",
|
|
821
|
+
tempProject,
|
|
822
|
+
undefined,
|
|
823
|
+
false,
|
|
824
|
+
null,
|
|
825
|
+
undefined,
|
|
826
|
+
false,
|
|
827
|
+
undefined,
|
|
828
|
+
undefined,
|
|
829
|
+
);
|
|
830
|
+
|
|
831
|
+
// xhigh is unsupported by ctx.model → clamped to high, never sent verbatim.
|
|
832
|
+
assert.deepEqual(thinkingLevels, ["high"]);
|
|
833
|
+
});
|
|
834
|
+
|
|
537
835
|
test("resolveModelId: anthropic wins over claude-code when session provider is not claude-code", () => {
|
|
538
836
|
const availableModels = [
|
|
539
837
|
{ id: "claude-sonnet-4-6", provider: "claude-code" },
|
|
@@ -173,6 +173,38 @@ test("cleanupAfterLoopExit preserves completion closeout surface after stopAuto
|
|
|
173
173
|
}
|
|
174
174
|
});
|
|
175
175
|
|
|
176
|
+
test("cleanupAfterLoopExit clears completionStopInProgress even when preserveStepSurfaceAfterLoopExit is also set", async () => {
|
|
177
|
+
const statusCalls: unknown[] = [];
|
|
178
|
+
const widgetCalls: unknown[] = [];
|
|
179
|
+
|
|
180
|
+
autoSession.reset();
|
|
181
|
+
autoSession.active = true;
|
|
182
|
+
autoSession.paused = false;
|
|
183
|
+
autoSession.completionStopInProgress = true;
|
|
184
|
+
autoSession.preserveStepSurfaceAfterLoopExit = true;
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
await cleanupAfterLoopExit({
|
|
188
|
+
hasUI: true,
|
|
189
|
+
ui: {
|
|
190
|
+
setStatus: (...args: unknown[]) => statusCalls.push(args),
|
|
191
|
+
setWidget: (...args: unknown[]) => widgetCalls.push(args),
|
|
192
|
+
setHeader: () => {},
|
|
193
|
+
notify: () => {},
|
|
194
|
+
},
|
|
195
|
+
} as any);
|
|
196
|
+
|
|
197
|
+
assert.equal(
|
|
198
|
+
autoSession.completionStopInProgress,
|
|
199
|
+
false,
|
|
200
|
+
"completionStopInProgress must be cleared even when preserveStepSurfaceAfterLoopExit was also set",
|
|
201
|
+
);
|
|
202
|
+
assert.equal(autoSession.preserveStepSurfaceAfterLoopExit, false);
|
|
203
|
+
} finally {
|
|
204
|
+
autoSession.reset();
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
176
208
|
test("pauseAuto preserves artifact retry counts across pause/resume", async () => {
|
|
177
209
|
const base = mkdtempSync(join(tmpdir(), "gsd-pause-retry-count-"));
|
|
178
210
|
const previousCwd = process.cwd();
|
|
@@ -207,6 +207,7 @@ test("runFinalize merges a verified complete-milestone immediately and only once
|
|
|
207
207
|
const startedAt = Date.now();
|
|
208
208
|
let lifecycleMergeCalls = 0;
|
|
209
209
|
let resolverMergeCalls = 0;
|
|
210
|
+
const stopAutoCalls: Array<{ reason?: string; options?: unknown }> = [];
|
|
210
211
|
s.basePath = base;
|
|
211
212
|
s.originalBasePath = base;
|
|
212
213
|
s.currentMilestoneId = "M001";
|
|
@@ -219,6 +220,9 @@ test("runFinalize merges a verified complete-milestone immediately and only once
|
|
|
219
220
|
const result = await runFinalizeWithDeps(s, {
|
|
220
221
|
preflightCleanRoot: () => ({ stashPushed: false }),
|
|
221
222
|
postflightPopStash: () => ({ needsManualRecovery: false }),
|
|
223
|
+
stopAuto: async (_ctx: unknown, _pi: unknown, reason?: string, options?: unknown) => {
|
|
224
|
+
stopAutoCalls.push({ reason, options });
|
|
225
|
+
},
|
|
222
226
|
resolver: {
|
|
223
227
|
mergeAndExit() {
|
|
224
228
|
resolverMergeCalls++;
|
|
@@ -232,10 +236,19 @@ test("runFinalize merges a verified complete-milestone immediately and only once
|
|
|
232
236
|
},
|
|
233
237
|
});
|
|
234
238
|
|
|
235
|
-
assert.equal(result.action, "
|
|
239
|
+
assert.equal(result.action, "break");
|
|
240
|
+
assert.equal(result.reason, "milestone-complete");
|
|
236
241
|
assert.equal(lifecycleMergeCalls, 1);
|
|
237
242
|
assert.equal(resolverMergeCalls, 0);
|
|
238
243
|
assert.equal(s.milestoneMergedInPhases, true);
|
|
244
|
+
assert.equal(stopAutoCalls.length, 1);
|
|
245
|
+
assert.equal(stopAutoCalls[0]?.reason, "Milestone M001 complete");
|
|
246
|
+
assert.deepEqual(stopAutoCalls[0]?.options, {
|
|
247
|
+
completionWidget: {
|
|
248
|
+
milestoneId: "M001",
|
|
249
|
+
milestoneTitle: "Milestone",
|
|
250
|
+
},
|
|
251
|
+
});
|
|
239
252
|
|
|
240
253
|
s.currentUnit = {
|
|
241
254
|
type: "complete-milestone",
|
|
@@ -245,6 +258,9 @@ test("runFinalize merges a verified complete-milestone immediately and only once
|
|
|
245
258
|
const second = await runFinalizeWithDeps(s, {
|
|
246
259
|
preflightCleanRoot: () => ({ stashPushed: false }),
|
|
247
260
|
postflightPopStash: () => ({ needsManualRecovery: false }),
|
|
261
|
+
stopAuto: async (_ctx: unknown, _pi: unknown, reason?: string, options?: unknown) => {
|
|
262
|
+
stopAutoCalls.push({ reason, options });
|
|
263
|
+
},
|
|
248
264
|
resolver: {
|
|
249
265
|
mergeAndExit() {
|
|
250
266
|
resolverMergeCalls++;
|
|
@@ -258,9 +274,11 @@ test("runFinalize merges a verified complete-milestone immediately and only once
|
|
|
258
274
|
},
|
|
259
275
|
});
|
|
260
276
|
|
|
261
|
-
assert.equal(second.action, "
|
|
277
|
+
assert.equal(second.action, "break");
|
|
278
|
+
assert.equal(second.reason, "milestone-complete");
|
|
262
279
|
assert.equal(lifecycleMergeCalls, 1);
|
|
263
280
|
assert.equal(resolverMergeCalls, 0);
|
|
281
|
+
assert.equal(stopAutoCalls.length, 2);
|
|
264
282
|
});
|
|
265
283
|
|
|
266
284
|
test("runFinalize does not render next-phase handoff for complete-milestone", async (t) => {
|
|
@@ -302,7 +320,7 @@ test("runFinalize does not render next-phase handoff for complete-milestone", as
|
|
|
302
320
|
},
|
|
303
321
|
);
|
|
304
322
|
|
|
305
|
-
assert.equal(result.action, "
|
|
323
|
+
assert.equal(result.action, "break");
|
|
306
324
|
assert.equal(
|
|
307
325
|
widgetCalls.some(([key]) => key === "gsd-outcome"),
|
|
308
326
|
false,
|
|
@@ -310,6 +328,60 @@ test("runFinalize does not render next-phase handoff for complete-milestone", as
|
|
|
310
328
|
);
|
|
311
329
|
});
|
|
312
330
|
|
|
331
|
+
test("runFinalize clears gsd-step and gsd-progress before stopAuto on complete-milestone", async (t) => {
|
|
332
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-finalize-stale-widget-"));
|
|
333
|
+
t.after(() => {
|
|
334
|
+
rmSync(base, { recursive: true, force: true });
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
const s = new AutoSession();
|
|
338
|
+
s.basePath = base;
|
|
339
|
+
s.originalBasePath = base;
|
|
340
|
+
s.currentMilestoneId = "M001";
|
|
341
|
+
s.currentUnit = {
|
|
342
|
+
type: "complete-milestone",
|
|
343
|
+
id: "M001",
|
|
344
|
+
startedAt: Date.now(),
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const statusCalls: Array<[string, unknown]> = [];
|
|
348
|
+
const widgetCalls: Array<[string, unknown]> = [];
|
|
349
|
+
|
|
350
|
+
await runFinalizeWithDeps(
|
|
351
|
+
s,
|
|
352
|
+
{
|
|
353
|
+
preflightCleanRoot: () => ({ stashPushed: false }),
|
|
354
|
+
postflightPopStash: () => ({ needsManualRecovery: false }),
|
|
355
|
+
lifecycle: {
|
|
356
|
+
exitMilestone() {
|
|
357
|
+
return { ok: true, merged: true, codeFilesChanged: false };
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
hasUI: true,
|
|
363
|
+
ui: {
|
|
364
|
+
notify() {},
|
|
365
|
+
setStatus(key: string, value: unknown) {
|
|
366
|
+
statusCalls.push([key, value]);
|
|
367
|
+
},
|
|
368
|
+
setWidget(key: string, value: unknown) {
|
|
369
|
+
widgetCalls.push([key, value]);
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
assert.ok(
|
|
376
|
+
statusCalls.some(([key, val]) => key === "gsd-step" && val === undefined),
|
|
377
|
+
"gsd-step status should be cleared before stopAuto",
|
|
378
|
+
);
|
|
379
|
+
assert.ok(
|
|
380
|
+
widgetCalls.some(([key, val]) => key === "gsd-progress" && val === undefined),
|
|
381
|
+
"gsd-progress widget should be cleared before stopAuto",
|
|
382
|
+
);
|
|
383
|
+
});
|
|
384
|
+
|
|
313
385
|
test("runFinalize stops before merge when an isolated unit leaks app files into project root", async (t) => {
|
|
314
386
|
const root = mkdtempSync(join(tmpdir(), "gsd-root-leak-root-"));
|
|
315
387
|
const worktree = join(root, ".gsd", "worktrees", "M001");
|
|
@@ -9,7 +9,7 @@ import { randomUUID } from "node:crypto";
|
|
|
9
9
|
|
|
10
10
|
import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, diagnoseWorktreeIntegrityFailure, buildLoopRemediationSteps, writeBlockerPlaceholder, refreshRecoveryDbForArtifact, writeReactiveExecuteBlocker } from "../auto-recovery.ts";
|
|
11
11
|
import { resolveMilestoneFile } from "../paths.ts";
|
|
12
|
-
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertGateRow, insertTask, insertAssessment, getMilestone, getMilestoneCommitAttributionShas, getTask } from "../gsd-db.ts";
|
|
12
|
+
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertGateRow, insertTask, insertAssessment, getMilestone, getMilestoneCommitAttributionShas, getTask, saveGateResult } from "../gsd-db.ts";
|
|
13
13
|
import { readEvents } from "../workflow-events.ts";
|
|
14
14
|
import { clearParseCache } from "../files.ts";
|
|
15
15
|
import { parseRoadmap } from "../parsers-legacy.ts";
|
|
@@ -1613,6 +1613,27 @@ test("verifyExpectedArtifact checks pending gate-evaluate artifacts without ESM
|
|
|
1613
1613
|
assert.equal(verified, false, "pending gates should keep gate-evaluate unverified");
|
|
1614
1614
|
});
|
|
1615
1615
|
|
|
1616
|
+
test("verifyExpectedArtifact fails closed for gate-evaluate when the DB is unavailable", () => {
|
|
1617
|
+
const base = makeTmpProject();
|
|
1618
|
+
closeDatabase();
|
|
1619
|
+
|
|
1620
|
+
const verified = verifyExpectedArtifact("gate-evaluate", "M001/S01/gates+Q3", base);
|
|
1621
|
+
|
|
1622
|
+
assert.equal(verified, false, "gate-evaluate must verify against the DB-backed gate rows");
|
|
1623
|
+
});
|
|
1624
|
+
|
|
1625
|
+
test("verifyExpectedArtifact ignores complete-slice gates in stale gate-evaluate unit ids", () => {
|
|
1626
|
+
const base = makeTmpProject();
|
|
1627
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
|
|
1628
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q8", scope: "slice" });
|
|
1629
|
+
saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", verdict: "pass", rationale: "OK", findings: "" });
|
|
1630
|
+
saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", verdict: "pass", rationale: "OK", findings: "" });
|
|
1631
|
+
|
|
1632
|
+
const verified = verifyExpectedArtifact("gate-evaluate", "M001/S01/gates+Q3,Q4,Q8", base);
|
|
1633
|
+
|
|
1634
|
+
assert.equal(verified, true, "pending Q8 belongs to complete-slice and must not keep gate-evaluate unverified");
|
|
1635
|
+
});
|
|
1636
|
+
|
|
1616
1637
|
// ─── #4414 regressions ────────────────────────────────────────────────────────
|
|
1617
1638
|
|
|
1618
1639
|
test("#4414: writeBlockerPlaceholder invalidates path cache so dispatch guard sees file", () => {
|
|
@@ -20,6 +20,10 @@ test('resolveAutoSupervisorConfig provides safe timeout defaults', () => {
|
|
|
20
20
|
assert.equal(supervisor.soft_timeout_minutes, 20);
|
|
21
21
|
assert.equal(supervisor.idle_timeout_minutes, 10);
|
|
22
22
|
assert.equal(supervisor.hard_timeout_minutes, 30);
|
|
23
|
+
// A single hung tool gets its own short budget, well below the idle window,
|
|
24
|
+
// so a genuinely stuck tool is recovered in minutes instead of waiting out
|
|
25
|
+
// the full idle timeout.
|
|
26
|
+
assert.equal(supervisor.stalled_tool_timeout_minutes, 5);
|
|
23
27
|
} finally {
|
|
24
28
|
if (previousGsdHome === undefined) {
|
|
25
29
|
delete process.env.GSD_HOME;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
import { _setAutoActiveForTest } from "../auto.ts";
|
|
8
|
+
import { autoSession } from "../auto-runtime-state.js";
|
|
9
|
+
import { registerHooks } from "../bootstrap/register-hooks.ts";
|
|
10
|
+
|
|
11
|
+
type HookHandler = (event: any, ctx?: any) => Promise<any> | any;
|
|
12
|
+
|
|
13
|
+
function createHookHandlers(): Map<string, HookHandler[]> {
|
|
14
|
+
const handlers = new Map<string, HookHandler[]>();
|
|
15
|
+
const pi = {
|
|
16
|
+
on(event: string, handler: HookHandler) {
|
|
17
|
+
const existing = handlers.get(event) ?? [];
|
|
18
|
+
existing.push(handler);
|
|
19
|
+
handlers.set(event, existing);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
registerHooks(pi as any, []);
|
|
24
|
+
return handlers;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function requireHook(handlers: Map<string, HookHandler[]>, event: string): HookHandler {
|
|
28
|
+
const handler = handlers.get(event)?.[0];
|
|
29
|
+
assert.ok(handler, `${event} hook should be registered`);
|
|
30
|
+
return handler;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
test("before_provider_request truncates tool results outside auto-mode", async (t) => {
|
|
34
|
+
const dir = mkdtempSync(join(tmpdir(), "gsd-before-provider-context-"));
|
|
35
|
+
const gsdHome = join(dir, "home");
|
|
36
|
+
const project = join(dir, "project");
|
|
37
|
+
const previousCwd = process.cwd();
|
|
38
|
+
const previousGsdHome = process.env.GSD_HOME;
|
|
39
|
+
|
|
40
|
+
mkdirSync(join(project, ".gsd"), { recursive: true });
|
|
41
|
+
mkdirSync(gsdHome, { recursive: true });
|
|
42
|
+
writeFileSync(
|
|
43
|
+
join(project, ".gsd", "PREFERENCES.md"),
|
|
44
|
+
[
|
|
45
|
+
"---",
|
|
46
|
+
"version: 1",
|
|
47
|
+
"context_management:",
|
|
48
|
+
" tool_result_max_chars: 200",
|
|
49
|
+
" observation_mask_turns: 1",
|
|
50
|
+
"---",
|
|
51
|
+
"",
|
|
52
|
+
].join("\n"),
|
|
53
|
+
"utf-8",
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
process.env.GSD_HOME = gsdHome;
|
|
57
|
+
process.chdir(project);
|
|
58
|
+
_setAutoActiveForTest(false);
|
|
59
|
+
|
|
60
|
+
t.after(() => {
|
|
61
|
+
_setAutoActiveForTest(false);
|
|
62
|
+
process.chdir(previousCwd);
|
|
63
|
+
if (previousGsdHome === undefined) delete process.env.GSD_HOME;
|
|
64
|
+
else process.env.GSD_HOME = previousGsdHome;
|
|
65
|
+
rmSync(dir, { recursive: true, force: true });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const beforeProviderRequest = requireHook(createHookHandlers(), "before_provider_request");
|
|
69
|
+
const messageText = "m".repeat(250);
|
|
70
|
+
const responsesOutput = "r".repeat(250);
|
|
71
|
+
const payload = {
|
|
72
|
+
messages: [
|
|
73
|
+
{ role: "user", content: [{ type: "text", text: "keep me" }] },
|
|
74
|
+
{
|
|
75
|
+
role: "toolResult",
|
|
76
|
+
toolCallId: "toolu_test",
|
|
77
|
+
toolName: "Read",
|
|
78
|
+
isError: false,
|
|
79
|
+
content: [{ type: "text", text: messageText }],
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
input: [
|
|
83
|
+
{ role: "user", content: [{ type: "input_text", text: "keep me" }] },
|
|
84
|
+
{ type: "function_call_output", call_id: "call_test", output: responsesOutput },
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
await beforeProviderRequest({ payload });
|
|
89
|
+
|
|
90
|
+
const truncatedMessage = (payload.messages[1]?.content as Array<{ text?: string }>)[0]?.text ?? "";
|
|
91
|
+
const truncatedResponsesOutput = String(payload.input[1]?.output ?? "");
|
|
92
|
+
|
|
93
|
+
assert.match(truncatedMessage, /\[truncated\]/);
|
|
94
|
+
assert.match(truncatedResponsesOutput, /\[truncated\]/);
|
|
95
|
+
assert.ok(truncatedMessage.length < messageText.length);
|
|
96
|
+
assert.ok(truncatedResponsesOutput.length < responsesOutput.length);
|
|
97
|
+
assert.doesNotMatch(truncatedMessage, /result masked/);
|
|
98
|
+
assert.doesNotMatch(truncatedResponsesOutput, /result masked/);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("successful shell result clears source context before provider injection", async (t) => {
|
|
102
|
+
const dir = mkdtempSync(join(tmpdir(), "gsd-before-provider-source-"));
|
|
103
|
+
const project = join(dir, "project");
|
|
104
|
+
mkdirSync(project, { recursive: true });
|
|
105
|
+
writeFileSync(join(project, "app.ts"), "export const value = 'before';\n");
|
|
106
|
+
|
|
107
|
+
autoSession.reset();
|
|
108
|
+
autoSession.active = true;
|
|
109
|
+
autoSession.basePath = project;
|
|
110
|
+
autoSession.setCurrentUnit({
|
|
111
|
+
type: "execute-task",
|
|
112
|
+
id: "M001/S01/T01",
|
|
113
|
+
startedAt: 123,
|
|
114
|
+
workspaceRoot: project,
|
|
115
|
+
});
|
|
116
|
+
autoSession.sourceObservations.observeRead({ path: "app.ts" });
|
|
117
|
+
|
|
118
|
+
t.after(() => {
|
|
119
|
+
autoSession.reset();
|
|
120
|
+
rmSync(dir, { recursive: true, force: true });
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
assert.match(autoSession.sourceObservations.renderActiveBlock() ?? "", /before/);
|
|
124
|
+
|
|
125
|
+
const handlers = createHookHandlers();
|
|
126
|
+
const toolResult = requireHook(handlers, "tool_result");
|
|
127
|
+
const beforeProviderRequest = requireHook(handlers, "before_provider_request");
|
|
128
|
+
|
|
129
|
+
await toolResult({
|
|
130
|
+
toolCallId: "toolu_bash",
|
|
131
|
+
toolName: "bash",
|
|
132
|
+
input: { command: "printf after > app.ts" },
|
|
133
|
+
isError: false,
|
|
134
|
+
result: "ok",
|
|
135
|
+
}, { cwd: project });
|
|
136
|
+
|
|
137
|
+
const payload = {
|
|
138
|
+
messages: [{ role: "user", content: [{ type: "text", text: "continue" }] }],
|
|
139
|
+
};
|
|
140
|
+
await beforeProviderRequest({ payload });
|
|
141
|
+
|
|
142
|
+
assert.equal(autoSession.sourceObservations.renderActiveBlock(), null);
|
|
143
|
+
assert.equal(payload.messages.length, 1);
|
|
144
|
+
assert.doesNotMatch(payload.messages[0].content[0].text, /Source Context Block/);
|
|
145
|
+
});
|
|
@@ -76,3 +76,12 @@ test('BUNDLED_SKILL_TRIGGERS: skill ids are unique', () => {
|
|
|
76
76
|
seen.add(skill);
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
|
+
|
|
80
|
+
test('BUNDLED_SKILL_TRIGGERS: gsd-browser and agent-browser stay distinct', () => {
|
|
81
|
+
const gsdBrowser = BUNDLED_SKILL_TRIGGERS.find(entry => entry.skill === 'gsd-browser');
|
|
82
|
+
const agentBrowser = BUNDLED_SKILL_TRIGGERS.find(entry => entry.skill === 'agent-browser');
|
|
83
|
+
|
|
84
|
+
assert.ok(gsdBrowser, 'gsd-browser trigger should be registered');
|
|
85
|
+
assert.ok(agentBrowser, 'agent-browser trigger should be registered');
|
|
86
|
+
assert.notStrictEqual(gsdBrowser.trigger, agentBrowser.trigger);
|
|
87
|
+
});
|