@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
|
@@ -3,11 +3,21 @@ import assert from "node:assert/strict";
|
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import {
|
|
6
|
+
RUN_UAT_BROWSER_TOOL_NAMES,
|
|
6
7
|
buildRunUatResultPresentation,
|
|
8
|
+
buildRunUatPresentationForType,
|
|
7
9
|
RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
8
10
|
RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
9
11
|
RUN_UAT_WORKFLOW_TOOL_NAMES,
|
|
10
12
|
} from "../tool-presentation-plan.ts";
|
|
13
|
+
import {
|
|
14
|
+
buildMinimalAutoGsdToolSet,
|
|
15
|
+
MINIMAL_AUTO_BASE_TOOL_NAMES,
|
|
16
|
+
MINIMAL_GSD_TOOL_NAMES,
|
|
17
|
+
} from "../bootstrap/register-hooks.ts";
|
|
18
|
+
import { shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.ts";
|
|
19
|
+
import { UNIT_TOOL_CONTRACTS } from "../unit-tool-contracts.ts";
|
|
20
|
+
import { uatTypeIncludesBrowser } from "../uat-policy.ts";
|
|
11
21
|
|
|
12
22
|
const promptsDir = join(process.cwd(), "src/resources/extensions/gsd/prompts");
|
|
13
23
|
const templatesDir = join(process.cwd(), "src/resources/extensions/gsd/templates");
|
|
@@ -20,6 +30,84 @@ function readTemplate(name: string): string {
|
|
|
20
30
|
return readFileSync(join(templatesDir, `${name}.md`), "utf-8");
|
|
21
31
|
}
|
|
22
32
|
|
|
33
|
+
function escapeRegExp(value: string): string {
|
|
34
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const registeredPhaseToolNames = [
|
|
38
|
+
...new Set([
|
|
39
|
+
...MINIMAL_AUTO_BASE_TOOL_NAMES,
|
|
40
|
+
...MINIMAL_GSD_TOOL_NAMES,
|
|
41
|
+
...Object.values(UNIT_TOOL_CONTRACTS).flatMap((contract) => contract.allowedGsdTools),
|
|
42
|
+
]),
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const PHASE_PROMPT_TOOL_CALLS: Record<string, readonly string[]> = {
|
|
46
|
+
"research-milestone": ["gsd_summary_save"],
|
|
47
|
+
"plan-milestone": [
|
|
48
|
+
"gsd_milestone_status",
|
|
49
|
+
"gsd_plan_milestone",
|
|
50
|
+
"gsd_plan_slice",
|
|
51
|
+
"gsd_decision_save",
|
|
52
|
+
],
|
|
53
|
+
"research-slice": ["gsd_summary_save"],
|
|
54
|
+
"plan-slice": ["gsd_reassess_roadmap", "gsd_plan_slice", "gsd_decision_save"],
|
|
55
|
+
"refine-slice": ["gsd_plan_slice", "gsd_decision_save"],
|
|
56
|
+
"replan-slice": ["gsd_replan_slice"],
|
|
57
|
+
"execute-task": ["gsd_task_complete"],
|
|
58
|
+
"reactive-execute": ["gsd_summary_save"],
|
|
59
|
+
"complete-slice": [
|
|
60
|
+
"gsd_exec",
|
|
61
|
+
"gsd_task_reopen",
|
|
62
|
+
"gsd_replan_slice",
|
|
63
|
+
"gsd_requirement_update",
|
|
64
|
+
"capture_thought",
|
|
65
|
+
"gsd_slice_complete",
|
|
66
|
+
"gsd_summary_save",
|
|
67
|
+
],
|
|
68
|
+
"reassess-roadmap": ["gsd_milestone_status", "gsd_reassess_roadmap"],
|
|
69
|
+
"validate-milestone": ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap"],
|
|
70
|
+
"run-uat": ["gsd_uat_exec", "gsd_uat_result_save"],
|
|
71
|
+
"gate-evaluate": ["gsd_save_gate_result"],
|
|
72
|
+
"complete-milestone": [
|
|
73
|
+
"gsd_milestone_status",
|
|
74
|
+
"gsd_requirement_update",
|
|
75
|
+
"gsd_summary_save",
|
|
76
|
+
"capture_thought",
|
|
77
|
+
"gsd_complete_milestone",
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
test("auto phase prompt tool calls are available in scoped tool surfaces", () => {
|
|
82
|
+
for (const [unitType, promptTools] of Object.entries(PHASE_PROMPT_TOOL_CALLS)) {
|
|
83
|
+
const prompt = readPrompt(unitType);
|
|
84
|
+
const activeTools = buildMinimalAutoGsdToolSet(
|
|
85
|
+
registeredPhaseToolNames,
|
|
86
|
+
unitType,
|
|
87
|
+
registeredPhaseToolNames,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
for (const toolName of promptTools) {
|
|
91
|
+
assert.match(
|
|
92
|
+
prompt,
|
|
93
|
+
new RegExp(`\\b${escapeRegExp(toolName)}\\b`),
|
|
94
|
+
`${unitType} prompt should mention ${toolName}`,
|
|
95
|
+
);
|
|
96
|
+
assert.ok(
|
|
97
|
+
activeTools.includes(toolName),
|
|
98
|
+
`${unitType} prompt mentions ${toolName}, but scoped tools are ${activeTools.join(", ")}`,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const scopeResult = shouldBlockAutoUnitToolCall(unitType, toolName);
|
|
102
|
+
assert.equal(
|
|
103
|
+
scopeResult.block,
|
|
104
|
+
false,
|
|
105
|
+
`${unitType} phase gate blocked ${toolName}: ${scopeResult.reason ?? "unknown reason"}`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
23
111
|
test("reactive-execute prompt keeps task summaries with subagents and avoids batch commits", () => {
|
|
24
112
|
const prompt = readPrompt("reactive-execute");
|
|
25
113
|
assert.match(prompt, /subagent-written summary as authoritative/i);
|
|
@@ -81,6 +169,45 @@ test("run-uat prompt gives the complete UAT result-save presentation contract",
|
|
|
81
169
|
);
|
|
82
170
|
});
|
|
83
171
|
|
|
172
|
+
test("browser-executable UAT presentation uses direct browser tools", () => {
|
|
173
|
+
const presentation = buildRunUatPresentationForType("browser-executable");
|
|
174
|
+
|
|
175
|
+
assert.equal(presentation.surface, "hybrid");
|
|
176
|
+
for (const toolName of RUN_UAT_BROWSER_TOOL_NAMES) {
|
|
177
|
+
assert.ok(presentation.presentedTools.includes(toolName), `presentation should include browser tool ${toolName}`);
|
|
178
|
+
}
|
|
179
|
+
assert.ok(!presentation.presentedTools.some((toolName) => toolName.startsWith("mcp__gsd-browser__")));
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("live-runtime and mixed UAT presentations also surface browser tools", () => {
|
|
183
|
+
// Regression (M001/S03): the run-uat prompt tells live-runtime and mixed to
|
|
184
|
+
// drive a browser, so the runner must actually receive the browser tools and
|
|
185
|
+
// a hybrid surface — otherwise live checks silently downgrade to NEEDS-HUMAN.
|
|
186
|
+
for (const uatType of ["live-runtime", "mixed", "human-experience"] as const) {
|
|
187
|
+
assert.equal(uatTypeIncludesBrowser(uatType), true, `${uatType} policy should include browser tools`);
|
|
188
|
+
const presentation = buildRunUatPresentationForType(uatType);
|
|
189
|
+
assert.equal(presentation.surface, "hybrid", `${uatType} should use the hybrid surface`);
|
|
190
|
+
for (const toolName of RUN_UAT_BROWSER_TOOL_NAMES) {
|
|
191
|
+
assert.ok(
|
|
192
|
+
presentation.presentedTools.includes(toolName),
|
|
193
|
+
`${uatType} presentation should include browser tool ${toolName}`,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("artifact-driven and runtime-executable UAT presentations stay browser-free", () => {
|
|
200
|
+
for (const uatType of ["artifact-driven", "runtime-executable"] as const) {
|
|
201
|
+
assert.equal(uatTypeIncludesBrowser(uatType), false, `${uatType} policy should stay browser-free`);
|
|
202
|
+
const presentation = buildRunUatPresentationForType(uatType);
|
|
203
|
+
assert.equal(presentation.surface, "mcp", `${uatType} should use the mcp surface`);
|
|
204
|
+
assert.ok(
|
|
205
|
+
!RUN_UAT_BROWSER_TOOL_NAMES.some((toolName) => presentation.presentedTools.includes(toolName)),
|
|
206
|
+
`${uatType} presentation should not include browser tools`,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
84
211
|
test("workflow-start prompt defaults to autonomy instead of per-phase confirmation", () => {
|
|
85
212
|
const prompt = readPrompt("workflow-start");
|
|
86
213
|
assert.match(prompt, /Keep moving by default/i);
|
|
@@ -535,6 +662,12 @@ test("parallel subagent prompts forbid serialized tasks arrays", () => {
|
|
|
535
662
|
}
|
|
536
663
|
});
|
|
537
664
|
|
|
665
|
+
test("gate-evaluate prompt requires gate result findings field", () => {
|
|
666
|
+
const prompt = readPrompt("gate-evaluate");
|
|
667
|
+
assert.match(prompt, /`findings`/);
|
|
668
|
+
assert.match(prompt, /empty string if none/i);
|
|
669
|
+
});
|
|
670
|
+
|
|
538
671
|
// ─── Project-shape classifier + 3-or-4-options-with-Other-hatch contract ──
|
|
539
672
|
|
|
540
673
|
test("guided-discuss-project classifies project shape and persists the verdict to PROJECT.md", () => {
|
|
@@ -210,6 +210,61 @@ test("end-to-end: audit event is emitted when an auto trace is active", async ()
|
|
|
210
210
|
}
|
|
211
211
|
});
|
|
212
212
|
|
|
213
|
+
test("same-API transform with changes does not fire the observer (no real provider switch)", async () => {
|
|
214
|
+
const { basePath, cleanup } = withTempBasePath();
|
|
215
|
+
try {
|
|
216
|
+
initNotificationStore(basePath);
|
|
217
|
+
installProviderSwitchObserver();
|
|
218
|
+
|
|
219
|
+
// Target api === source api. The conversation ends on an unresolved tool
|
|
220
|
+
// call, so a synthetic tool result IS backfilled (a non-empty report) — but
|
|
221
|
+
// this is a within-provider normalization, not a cross-provider switch.
|
|
222
|
+
// `sourceApi` is omitted (the common case), so fromApi defaults to the
|
|
223
|
+
// target api and equals toApi. The observer must stay silent.
|
|
224
|
+
const sameApiModel = {
|
|
225
|
+
id: "gpt-5",
|
|
226
|
+
name: "GPT-5",
|
|
227
|
+
api: "openai-responses",
|
|
228
|
+
provider: "openai",
|
|
229
|
+
baseUrl: "",
|
|
230
|
+
reasoning: false,
|
|
231
|
+
input: ["text"],
|
|
232
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
233
|
+
contextWindow: 128000,
|
|
234
|
+
maxTokens: 8192,
|
|
235
|
+
} as Parameters<typeof transformMessagesWithReport>[1];
|
|
236
|
+
|
|
237
|
+
const messages = [
|
|
238
|
+
{
|
|
239
|
+
role: "assistant" as const,
|
|
240
|
+
content: [
|
|
241
|
+
{ type: "toolCall" as const, id: "call_orphan_1", name: "bash", arguments: {} },
|
|
242
|
+
],
|
|
243
|
+
api: "openai-responses",
|
|
244
|
+
provider: "openai",
|
|
245
|
+
model: "gpt-5",
|
|
246
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
|
|
247
|
+
stopReason: "stop" as const,
|
|
248
|
+
timestamp: Date.now(),
|
|
249
|
+
},
|
|
250
|
+
];
|
|
251
|
+
|
|
252
|
+
transformMessagesWithReport(
|
|
253
|
+
messages as Parameters<typeof transformMessagesWithReport>[0],
|
|
254
|
+
sameApiModel,
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
assert.equal(getProviderSwitchStats().totalSwitches, 0, "same→same transform must not count as a provider switch");
|
|
258
|
+
assert.equal(
|
|
259
|
+
readNotifications(basePath).filter((n) => n.message.includes("Provider switch")).length,
|
|
260
|
+
0,
|
|
261
|
+
"same→same transform must not emit a provider-switch notification",
|
|
262
|
+
);
|
|
263
|
+
} finally {
|
|
264
|
+
cleanup();
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
213
268
|
test("empty report does not bump counter or emit a notification", async () => {
|
|
214
269
|
const { basePath, cleanup } = withTempBasePath();
|
|
215
270
|
try {
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import test from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
-
import { mkdirSync, rmSync } from "node:fs";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
|
|
7
7
|
import { registerHooks } from "../bootstrap/register-hooks.ts";
|
|
8
|
+
import {
|
|
9
|
+
clearPendingAutoStart,
|
|
10
|
+
setPendingAutoStart,
|
|
11
|
+
} from "../guided-flow.ts";
|
|
12
|
+
import { closeDatabase, getMilestone } from "../gsd-db.ts";
|
|
13
|
+
import { deriveState, invalidateStateCache } from "../state.ts";
|
|
8
14
|
import {
|
|
9
15
|
getPendingGate,
|
|
10
16
|
resetWriteGateState,
|
|
@@ -186,6 +192,100 @@ test("register-hooks unlocks milestone depth verification from question id witho
|
|
|
186
192
|
);
|
|
187
193
|
});
|
|
188
194
|
|
|
195
|
+
test("register-hooks persists first structured question round for new milestone re-entry", async (t) => {
|
|
196
|
+
const dir = makeTempDir("question-draft");
|
|
197
|
+
mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
|
|
198
|
+
const originalCwd = process.cwd();
|
|
199
|
+
process.chdir(dir);
|
|
200
|
+
resetWriteGateState(dir);
|
|
201
|
+
clearPendingAutoStart(dir);
|
|
202
|
+
|
|
203
|
+
t.after(() => {
|
|
204
|
+
try {
|
|
205
|
+
resetWriteGateState(dir);
|
|
206
|
+
clearPendingAutoStart(dir);
|
|
207
|
+
closeDatabase();
|
|
208
|
+
} finally {
|
|
209
|
+
process.chdir(originalCwd);
|
|
210
|
+
rmSync(dir, { recursive: true, force: true });
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<void> | void>>();
|
|
215
|
+
const pi = {
|
|
216
|
+
on(event: string, handler: (event: any, ctx?: any) => Promise<void> | void) {
|
|
217
|
+
const existing = handlers.get(event) ?? [];
|
|
218
|
+
existing.push(handler);
|
|
219
|
+
handlers.set(event, existing);
|
|
220
|
+
},
|
|
221
|
+
} as any;
|
|
222
|
+
const ctx = { cwd: dir, ui: { notify: () => undefined } } as any;
|
|
223
|
+
|
|
224
|
+
registerHooks(pi, []);
|
|
225
|
+
setPendingAutoStart(dir, {
|
|
226
|
+
basePath: dir,
|
|
227
|
+
milestoneId: "M004",
|
|
228
|
+
ctx,
|
|
229
|
+
pi: { sendMessage: () => undefined } as any,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const questions = [
|
|
233
|
+
{
|
|
234
|
+
id: "m004_shape",
|
|
235
|
+
header: "M004 Shape",
|
|
236
|
+
question: "What are you picturing for M004?",
|
|
237
|
+
options: [
|
|
238
|
+
{ label: "Planning metadata (Recommended)", description: "Plan the next metadata layer." },
|
|
239
|
+
{ label: "Find and organize", description: "Improve searching and organizing." },
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
id: "boundary",
|
|
244
|
+
header: "Boundary",
|
|
245
|
+
question: "Which boundary should I plan around?",
|
|
246
|
+
options: [
|
|
247
|
+
{ label: "No new dependencies (Recommended)", description: "Keep implementation vanilla." },
|
|
248
|
+
{ label: "Browser APIs OK", description: "Use browser-native capabilities." },
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
];
|
|
252
|
+
|
|
253
|
+
for (const handler of handlers.get("tool_result") ?? []) {
|
|
254
|
+
await handler({
|
|
255
|
+
toolName: "ask_user_questions",
|
|
256
|
+
input: { questions },
|
|
257
|
+
details: {
|
|
258
|
+
response: {
|
|
259
|
+
answers: {
|
|
260
|
+
m004_shape: { selected: "Planning metadata (Recommended)" },
|
|
261
|
+
boundary: { selected: "No new dependencies (Recommended)" },
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
}, ctx);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const milestoneDir = join(dir, ".gsd", "milestones", "M004");
|
|
269
|
+
const draftPath = join(milestoneDir, "M004-CONTEXT-DRAFT.md");
|
|
270
|
+
const discussionPath = join(milestoneDir, "M004-DISCUSSION.md");
|
|
271
|
+
|
|
272
|
+
assert.equal(existsSync(draftPath), true, "first answer round should create a resumable context draft");
|
|
273
|
+
assert.equal(existsSync(discussionPath), true, "first answer round should create a discussion log");
|
|
274
|
+
|
|
275
|
+
const draft = readFileSync(draftPath, "utf-8");
|
|
276
|
+
assert.match(draft, /What are you picturing for M004\?/);
|
|
277
|
+
assert.match(draft, /Planning metadata \(Recommended\)/);
|
|
278
|
+
assert.match(draft, /No new dependencies \(Recommended\)/);
|
|
279
|
+
|
|
280
|
+
const row = getMilestone("M004");
|
|
281
|
+
assert.equal(row?.status, "queued", "new milestone shell should be registered in the DB");
|
|
282
|
+
|
|
283
|
+
invalidateStateCache();
|
|
284
|
+
const state = await deriveState(dir);
|
|
285
|
+
assert.equal(state.activeMilestone?.id, "M004");
|
|
286
|
+
assert.equal(state.phase, "needs-discussion");
|
|
287
|
+
});
|
|
288
|
+
|
|
189
289
|
test("register-hooks clears depth gate when remote (Telegram/Slack/Discord) answer is normalized (#4406)", async (t) => {
|
|
190
290
|
const dir = makeTempDir("remote");
|
|
191
291
|
const originalCwd = process.cwd();
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import test from "node:test";
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
|
-
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { mkdtempSync, mkdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { execFileSync } from "node:child_process";
|
|
@@ -117,7 +117,7 @@ test("repository registry keeps project root anchored to .gsd project in monorep
|
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
test("repository registry uses external-state worktree checkout as project root", (t) => {
|
|
120
|
-
const base = mkdtempSync(join(tmpdir(), "gsd-repo-registry-external-"));
|
|
120
|
+
const base = realpathSync(mkdtempSync(join(tmpdir(), "gsd-repo-registry-external-")));
|
|
121
121
|
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
122
122
|
const worktree = join(base, ".gsd", "projects", "abc123", "worktrees", "M001");
|
|
123
123
|
mkdirSync(worktree, { recursive: true });
|
|
@@ -67,6 +67,14 @@ test("Tool Contract compiles known Unit prompt and tool policy", () => {
|
|
|
67
67
|
assert.deepEqual(result.ok && result.contract.forbiddenWorkflowTools, []);
|
|
68
68
|
assert.equal(result.ok && result.contract.toolsPolicy.mode, "all");
|
|
69
69
|
assert.ok(result.ok && result.contract.validationRules.includes("closeout-tool-present"));
|
|
70
|
+
assert.ok(result.ok && result.contract.validationRules.includes("source-observation-contract-present"));
|
|
71
|
+
assert.deepEqual(result.ok && result.contract.sourceObservations, {
|
|
72
|
+
mode: "whole-file-active-unit",
|
|
73
|
+
seedFields: ["task.files", "task.inputs"],
|
|
74
|
+
excludedFields: ["expectedOutput"],
|
|
75
|
+
maxBytes: 50 * 1024,
|
|
76
|
+
maxLines: 2000,
|
|
77
|
+
});
|
|
70
78
|
});
|
|
71
79
|
|
|
72
80
|
test("Tool Contract records high-risk cross-phase tool boundaries without single-owning every tool", () => {
|
|
@@ -108,6 +116,26 @@ test("auto Unit tool scope blocks complete-slice from saving UAT Assessment", ()
|
|
|
108
116
|
assert.match(result.reason ?? "", /Run UAT owns persisted UAT Assessment/);
|
|
109
117
|
});
|
|
110
118
|
|
|
119
|
+
test("auto Unit tool scope allows plan-slice to reassess invalid roadmap assumptions", () => {
|
|
120
|
+
const result = shouldBlockAutoUnitToolCall("plan-slice", "gsd_reassess_roadmap");
|
|
121
|
+
|
|
122
|
+
assert.equal(result.block, false);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("auto Unit tool scope allows status/read helpers named by closeout prompts", () => {
|
|
126
|
+
for (const unitType of ["plan-milestone", "validate-milestone", "complete-milestone", "reassess-roadmap"]) {
|
|
127
|
+
const result = shouldBlockAutoUnitToolCall(unitType, "gsd_milestone_status");
|
|
128
|
+
assert.equal(result.block, false, `${unitType} should be able to call gsd_milestone_status`);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("auto Unit tool scope blocks stale per-task planner in slice planning phases", () => {
|
|
133
|
+
for (const unitType of ["plan-slice", "refine-slice", "replan-slice"]) {
|
|
134
|
+
const result = shouldBlockAutoUnitToolCall(unitType, "gsd_plan_task");
|
|
135
|
+
assert.equal(result.block, true, `${unitType} should not call stale gsd_plan_task`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
111
139
|
test("Recovery Classification covers ADR-015 failure families", () => {
|
|
112
140
|
const cases = [
|
|
113
141
|
["invalid tool schema enum", "tool-schema", "stop"],
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
openDatabase,
|
|
25
25
|
closeDatabase,
|
|
26
26
|
_getAdapter,
|
|
27
|
+
SCHEMA_VERSION,
|
|
27
28
|
} from '../gsd-db.ts';
|
|
28
29
|
|
|
29
30
|
const _require = createRequire(import.meta.url);
|
|
@@ -403,9 +404,10 @@ test('schema v21 migration: upgrading from v20 lands on current SCHEMA_VERSION',
|
|
|
403
404
|
// The DB must reach the current SCHEMA_VERSION. If the v21 block was
|
|
404
405
|
// skipped (as it would be when SCHEMA_VERSION was still 20), this
|
|
405
406
|
// assertion catches it.
|
|
406
|
-
assert.
|
|
407
|
-
maxVersion
|
|
408
|
-
|
|
407
|
+
assert.equal(
|
|
408
|
+
maxVersion,
|
|
409
|
+
SCHEMA_VERSION,
|
|
410
|
+
`DB upgraded from v20 must reach schema version ${SCHEMA_VERSION}; got ${maxVersion}`,
|
|
409
411
|
);
|
|
410
412
|
} finally {
|
|
411
413
|
cleanup(base);
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
// gsd-pi / V27 + V28 schema migration regression tests
|
|
1
|
+
// gsd-pi / V27 + V28 + V29 schema migration regression tests
|
|
2
2
|
//
|
|
3
3
|
// Same bug class as #4591 (schema-v21-sequence): a migration block can be
|
|
4
4
|
// added but the SCHEMA_VERSION constant left unchanged, causing fresh-install
|
|
5
|
-
// + upgrade paths to silently skip the column add. This file pins
|
|
6
|
-
// (artifacts.content_hash)
|
|
7
|
-
// write-path level
|
|
5
|
+
// + upgrade paths to silently skip the column add. This file pins V27
|
|
6
|
+
// (artifacts.content_hash), V28 (memories.last_hit_at), and V29
|
|
7
|
+
// (target_repositories) at the schema/write-path level.
|
|
8
8
|
|
|
9
9
|
import test from "node:test";
|
|
10
10
|
import assert from "node:assert/strict";
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
12
|
import * as path from "node:path";
|
|
13
13
|
import * as os from "node:os";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
14
15
|
|
|
15
16
|
import {
|
|
16
17
|
openDatabase,
|
|
@@ -22,8 +23,10 @@ import {
|
|
|
22
23
|
SCHEMA_VERSION,
|
|
23
24
|
} from "../gsd-db.ts";
|
|
24
25
|
|
|
26
|
+
const _require = createRequire(import.meta.url);
|
|
27
|
+
|
|
25
28
|
function makeTmp(): string {
|
|
26
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), "gsd-
|
|
29
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), "gsd-v27v29-"));
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
function cleanup(base: string): void {
|
|
@@ -31,10 +34,114 @@ function cleanup(base: string): void {
|
|
|
31
34
|
try { fs.rmSync(base, { recursive: true, force: true }); } catch { /* noop */ }
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
function columnNames(table: string): Set<string> {
|
|
38
|
+
const db = _getAdapter()!;
|
|
39
|
+
const cols = db.prepare(`PRAGMA table_info(${table})`).all() as Array<Record<string, unknown>>;
|
|
40
|
+
return new Set(cols.map((c) => c["name"] as string));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function createV28Db(dbPath: string): void {
|
|
44
|
+
const sqlite = _require("node:sqlite") as {
|
|
45
|
+
DatabaseSync: new (p: string) => {
|
|
46
|
+
exec(sql: string): void;
|
|
47
|
+
close(): void;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const db = new sqlite.DatabaseSync(dbPath);
|
|
51
|
+
db.exec("PRAGMA journal_mode=WAL");
|
|
52
|
+
db.exec(`
|
|
53
|
+
CREATE TABLE schema_version (
|
|
54
|
+
version INTEGER NOT NULL,
|
|
55
|
+
applied_at TEXT NOT NULL
|
|
56
|
+
);
|
|
57
|
+
INSERT INTO schema_version (version, applied_at) VALUES (28, '2026-01-01T00:00:00.000Z');
|
|
58
|
+
|
|
59
|
+
CREATE TABLE milestones (
|
|
60
|
+
id TEXT PRIMARY KEY,
|
|
61
|
+
title TEXT NOT NULL DEFAULT '',
|
|
62
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
63
|
+
depends_on TEXT NOT NULL DEFAULT '[]',
|
|
64
|
+
created_at TEXT NOT NULL DEFAULT '',
|
|
65
|
+
completed_at TEXT DEFAULT NULL,
|
|
66
|
+
vision TEXT NOT NULL DEFAULT '',
|
|
67
|
+
success_criteria TEXT NOT NULL DEFAULT '[]',
|
|
68
|
+
key_risks TEXT NOT NULL DEFAULT '[]',
|
|
69
|
+
proof_strategy TEXT NOT NULL DEFAULT '[]',
|
|
70
|
+
verification_contract TEXT NOT NULL DEFAULT '',
|
|
71
|
+
verification_integration TEXT NOT NULL DEFAULT '',
|
|
72
|
+
verification_operational TEXT NOT NULL DEFAULT '',
|
|
73
|
+
verification_uat TEXT NOT NULL DEFAULT '',
|
|
74
|
+
definition_of_done TEXT NOT NULL DEFAULT '[]',
|
|
75
|
+
requirement_coverage TEXT NOT NULL DEFAULT '',
|
|
76
|
+
boundary_map_markdown TEXT NOT NULL DEFAULT '',
|
|
77
|
+
sequence INTEGER DEFAULT 0
|
|
78
|
+
);
|
|
79
|
+
CREATE TABLE slices (
|
|
80
|
+
milestone_id TEXT NOT NULL,
|
|
81
|
+
id TEXT NOT NULL,
|
|
82
|
+
title TEXT NOT NULL DEFAULT '',
|
|
83
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
84
|
+
risk TEXT NOT NULL DEFAULT 'medium',
|
|
85
|
+
depends TEXT NOT NULL DEFAULT '[]',
|
|
86
|
+
demo TEXT NOT NULL DEFAULT '',
|
|
87
|
+
created_at TEXT NOT NULL DEFAULT '',
|
|
88
|
+
completed_at TEXT DEFAULT NULL,
|
|
89
|
+
full_summary_md TEXT NOT NULL DEFAULT '',
|
|
90
|
+
full_uat_md TEXT NOT NULL DEFAULT '',
|
|
91
|
+
goal TEXT NOT NULL DEFAULT '',
|
|
92
|
+
success_criteria TEXT NOT NULL DEFAULT '',
|
|
93
|
+
proof_level TEXT NOT NULL DEFAULT '',
|
|
94
|
+
integration_closure TEXT NOT NULL DEFAULT '',
|
|
95
|
+
observability_impact TEXT NOT NULL DEFAULT '',
|
|
96
|
+
sequence INTEGER DEFAULT 0,
|
|
97
|
+
replan_triggered_at TEXT DEFAULT NULL,
|
|
98
|
+
is_sketch INTEGER NOT NULL DEFAULT 0,
|
|
99
|
+
sketch_scope TEXT NOT NULL DEFAULT '',
|
|
100
|
+
PRIMARY KEY (milestone_id, id),
|
|
101
|
+
FOREIGN KEY (milestone_id) REFERENCES milestones(id)
|
|
102
|
+
);
|
|
103
|
+
CREATE TABLE tasks (
|
|
104
|
+
milestone_id TEXT NOT NULL,
|
|
105
|
+
slice_id TEXT NOT NULL,
|
|
106
|
+
id TEXT NOT NULL,
|
|
107
|
+
title TEXT NOT NULL DEFAULT '',
|
|
108
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
109
|
+
one_liner TEXT NOT NULL DEFAULT '',
|
|
110
|
+
narrative TEXT NOT NULL DEFAULT '',
|
|
111
|
+
verification_result TEXT NOT NULL DEFAULT '',
|
|
112
|
+
duration TEXT NOT NULL DEFAULT '',
|
|
113
|
+
completed_at TEXT DEFAULT NULL,
|
|
114
|
+
blocker_discovered INTEGER DEFAULT 0,
|
|
115
|
+
blocker_source TEXT NOT NULL DEFAULT '',
|
|
116
|
+
escalation_pending INTEGER NOT NULL DEFAULT 0,
|
|
117
|
+
escalation_awaiting_review INTEGER NOT NULL DEFAULT 0,
|
|
118
|
+
escalation_artifact_path TEXT DEFAULT NULL,
|
|
119
|
+
escalation_override_applied_at TEXT DEFAULT NULL,
|
|
120
|
+
deviations TEXT NOT NULL DEFAULT '',
|
|
121
|
+
known_issues TEXT NOT NULL DEFAULT '',
|
|
122
|
+
key_files TEXT NOT NULL DEFAULT '[]',
|
|
123
|
+
key_decisions TEXT NOT NULL DEFAULT '[]',
|
|
124
|
+
full_summary_md TEXT NOT NULL DEFAULT '',
|
|
125
|
+
description TEXT NOT NULL DEFAULT '',
|
|
126
|
+
estimate TEXT NOT NULL DEFAULT '',
|
|
127
|
+
files TEXT NOT NULL DEFAULT '[]',
|
|
128
|
+
verify TEXT NOT NULL DEFAULT '',
|
|
129
|
+
inputs TEXT NOT NULL DEFAULT '[]',
|
|
130
|
+
expected_output TEXT NOT NULL DEFAULT '[]',
|
|
131
|
+
observability_impact TEXT NOT NULL DEFAULT '',
|
|
132
|
+
full_plan_md TEXT NOT NULL DEFAULT '',
|
|
133
|
+
sequence INTEGER DEFAULT 0,
|
|
134
|
+
PRIMARY KEY (milestone_id, slice_id, id),
|
|
135
|
+
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
|
|
136
|
+
);
|
|
137
|
+
`);
|
|
138
|
+
db.close();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
test("SCHEMA_VERSION constant is at least 29 (V29 migration committed)", () => {
|
|
35
142
|
assert.ok(
|
|
36
|
-
SCHEMA_VERSION >=
|
|
37
|
-
`SCHEMA_VERSION must be ≥
|
|
143
|
+
SCHEMA_VERSION >= 29,
|
|
144
|
+
`SCHEMA_VERSION must be ≥ 29 after V29 migration; got ${SCHEMA_VERSION}`,
|
|
38
145
|
);
|
|
39
146
|
});
|
|
40
147
|
|
|
@@ -43,11 +150,8 @@ test("fresh-install DB has artifacts.content_hash column (V27)", () => {
|
|
|
43
150
|
const dbPath = path.join(base, "gsd.db");
|
|
44
151
|
try {
|
|
45
152
|
openDatabase(dbPath);
|
|
46
|
-
const db = _getAdapter()!;
|
|
47
|
-
const cols = db.prepare("PRAGMA table_info(artifacts)").all() as Array<Record<string, unknown>>;
|
|
48
|
-
const colNames = new Set(cols.map((c) => c["name"] as string));
|
|
49
153
|
assert.ok(
|
|
50
|
-
|
|
154
|
+
columnNames("artifacts").has("content_hash"),
|
|
51
155
|
"V27 must add content_hash column to artifacts on fresh install",
|
|
52
156
|
);
|
|
53
157
|
} finally {
|
|
@@ -60,11 +164,8 @@ test("fresh-install DB has memories.last_hit_at column (V28)", () => {
|
|
|
60
164
|
const dbPath = path.join(base, "gsd.db");
|
|
61
165
|
try {
|
|
62
166
|
openDatabase(dbPath);
|
|
63
|
-
const db = _getAdapter()!;
|
|
64
|
-
const cols = db.prepare("PRAGMA table_info(memories)").all() as Array<Record<string, unknown>>;
|
|
65
|
-
const colNames = new Set(cols.map((c) => c["name"] as string));
|
|
66
167
|
assert.ok(
|
|
67
|
-
|
|
168
|
+
columnNames("memories").has("last_hit_at"),
|
|
68
169
|
"V28 must add last_hit_at column to memories on fresh install",
|
|
69
170
|
);
|
|
70
171
|
} finally {
|
|
@@ -72,15 +173,58 @@ test("fresh-install DB has memories.last_hit_at column (V28)", () => {
|
|
|
72
173
|
}
|
|
73
174
|
});
|
|
74
175
|
|
|
75
|
-
test("fresh-install DB
|
|
176
|
+
test("fresh-install DB has target_repositories columns (V29)", () => {
|
|
76
177
|
const base = makeTmp();
|
|
77
178
|
const dbPath = path.join(base, "gsd.db");
|
|
78
179
|
try {
|
|
79
180
|
openDatabase(dbPath);
|
|
181
|
+
assert.ok(
|
|
182
|
+
columnNames("slices").has("target_repositories"),
|
|
183
|
+
"V29 must add target_repositories column to slices on fresh install",
|
|
184
|
+
);
|
|
185
|
+
assert.ok(
|
|
186
|
+
columnNames("tasks").has("target_repositories"),
|
|
187
|
+
"V29 must add target_repositories column to tasks on fresh install",
|
|
188
|
+
);
|
|
189
|
+
} finally {
|
|
190
|
+
cleanup(base);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("fresh-install DB stamps current SCHEMA_VERSION in schema_version table", () => {
|
|
195
|
+
const base = makeTmp();
|
|
196
|
+
const dbPath = path.join(base, "gsd.db");
|
|
197
|
+
try {
|
|
198
|
+
openDatabase(dbPath);
|
|
199
|
+
const db = _getAdapter()!;
|
|
200
|
+
const row = db.prepare("SELECT MAX(version) as v FROM schema_version").get() as Record<string, unknown> | undefined;
|
|
201
|
+
const max = (row?.["v"] as number) ?? 0;
|
|
202
|
+
assert.equal(max, SCHEMA_VERSION, `fresh install must record schema_version ${SCHEMA_VERSION}; got ${max}`);
|
|
203
|
+
} finally {
|
|
204
|
+
cleanup(base);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("upgrading from V28 adds target_repositories and stamps V29", () => {
|
|
209
|
+
const base = makeTmp();
|
|
210
|
+
const dbPath = path.join(base, "gsd.db");
|
|
211
|
+
createV28Db(dbPath);
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
openDatabase(dbPath);
|
|
215
|
+
assert.ok(
|
|
216
|
+
columnNames("slices").has("target_repositories"),
|
|
217
|
+
"V29 migration must add target_repositories column to existing slices table",
|
|
218
|
+
);
|
|
219
|
+
assert.ok(
|
|
220
|
+
columnNames("tasks").has("target_repositories"),
|
|
221
|
+
"V29 migration must add target_repositories column to existing tasks table",
|
|
222
|
+
);
|
|
223
|
+
|
|
80
224
|
const db = _getAdapter()!;
|
|
81
225
|
const row = db.prepare("SELECT MAX(version) as v FROM schema_version").get() as Record<string, unknown> | undefined;
|
|
82
226
|
const max = (row?.["v"] as number) ?? 0;
|
|
83
|
-
assert.
|
|
227
|
+
assert.equal(max, SCHEMA_VERSION, `V28 DB must upgrade to schema_version ${SCHEMA_VERSION}; got ${max}`);
|
|
84
228
|
} finally {
|
|
85
229
|
cleanup(base);
|
|
86
230
|
}
|