@opengsd/gsd-pi 1.2.0-dev.844675c9 → 1.2.0-dev.b1abb545
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-web-branch.d.ts +2 -0
- package/dist/cli-web-branch.js +9 -2
- package/dist/help-text.js +5 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +78 -23
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +84 -228
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
- package/dist/resources/extensions/github-sync/templates.js +3 -3
- package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
- package/dist/resources/extensions/gsd/auto/loop.js +74 -56
- package/dist/resources/extensions/gsd/auto/orchestrator.js +109 -11
- package/dist/resources/extensions/gsd/auto/phases.js +28 -3
- package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
- package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
- package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
- package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
- package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
- package/dist/resources/extensions/gsd/auto-start.js +12 -23
- package/dist/resources/extensions/gsd/auto-timers.js +16 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
- package/dist/resources/extensions/gsd/auto-verification.js +7 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +21 -19
- package/dist/resources/extensions/gsd/auto.js +11 -7
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +11 -37
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +100 -138
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +63 -4
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
- package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
- package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
- package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
- package/dist/resources/extensions/gsd/commands-ship.js +2 -2
- package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
- package/dist/resources/extensions/gsd/db-workspace.js +103 -0
- package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
- package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/dist/resources/extensions/gsd/doctor.js +16 -9
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
- package/dist/resources/extensions/gsd/gsd-db.js +12 -0
- package/dist/resources/extensions/gsd/guided-flow.js +34 -468
- package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
- package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
- package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
- package/dist/resources/extensions/gsd/md-importer.js +4 -3
- package/dist/resources/extensions/gsd/migrate/safety.js +2 -2
- package/dist/resources/extensions/gsd/migration-auto-check.js +3 -2
- package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
- package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
- package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
- package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
- package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
- package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
- package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
- package/dist/resources/extensions/gsd/preferences.js +147 -29
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
- package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
- package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
- package/dist/resources/extensions/gsd/question-transport.js +86 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/state.js +13 -5
- package/dist/resources/extensions/gsd/templates/plan.md +7 -0
- package/dist/resources/extensions/gsd/templates/project.md +1 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/dist/resources/extensions/gsd/templates/uat.md +5 -1
- package/dist/resources/extensions/gsd/tool-contract.js +52 -8
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
- package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
- package/dist/resources/extensions/gsd/uat-policy.js +16 -10
- package/dist/resources/extensions/gsd/uat-run.js +9 -14
- package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
- package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
- package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
- package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
- package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
- package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
- package/dist/resources/extensions/shared/interview-ui.js +2 -2
- package/dist/resources/shared/claude-runtime-floor.js +182 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/update-cmd.js +20 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-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/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
- package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
- package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
- package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web-mode.d.ts +2 -0
- package/dist/web-mode.js +20 -8
- package/package.json +2 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- 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 +106 -40
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/server.d.ts +10 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +8 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +2 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +8 -93
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +35 -120
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/components/input.js +1 -1
- package/packages/pi-tui/dist/components/input.js.map +1 -1
- package/packages/pi-tui/dist/keys.d.ts.map +1 -1
- package/packages/pi-tui/dist/keys.js +39 -30
- package/packages/pi-tui/dist/keys.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +22 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +87 -24
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +108 -281
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +240 -0
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
- package/src/resources/extensions/github-sync/templates.ts +3 -3
- package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
- package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
- package/src/resources/extensions/gsd/auto/loop.ts +83 -61
- package/src/resources/extensions/gsd/auto/orchestrator.ts +125 -12
- package/src/resources/extensions/gsd/auto/phases.ts +35 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
- package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
- package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
- package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
- package/src/resources/extensions/gsd/auto-start.ts +17 -20
- package/src/resources/extensions/gsd/auto-timers.ts +16 -2
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
- package/src/resources/extensions/gsd/auto-verification.ts +7 -8
- package/src/resources/extensions/gsd/auto-worktree.ts +33 -26
- package/src/resources/extensions/gsd/auto.ts +15 -8
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -37
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +116 -151
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +107 -3
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
- package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
- package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
- package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
- package/src/resources/extensions/gsd/commands-ship.ts +2 -2
- package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
- package/src/resources/extensions/gsd/db-workspace.ts +170 -0
- package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
- package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/src/resources/extensions/gsd/doctor.ts +15 -5
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
- package/src/resources/extensions/gsd/gsd-db.ts +12 -0
- package/src/resources/extensions/gsd/guided-flow.ts +47 -558
- package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
- package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
- package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
- package/src/resources/extensions/gsd/md-importer.ts +3 -3
- package/src/resources/extensions/gsd/migrate/safety.ts +2 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
- package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
- package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
- package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
- package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
- package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
- package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +173 -28
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
- package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
- package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
- package/src/resources/extensions/gsd/question-transport.ts +138 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/state.ts +15 -5
- package/src/resources/extensions/gsd/templates/plan.md +7 -0
- package/src/resources/extensions/gsd/templates/project.md +1 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/src/resources/extensions/gsd/templates/uat.md +5 -1
- package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +321 -5
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +94 -0
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +86 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +79 -0
- package/src/resources/extensions/gsd/tool-contract.ts +86 -8
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
- package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
- package/src/resources/extensions/gsd/uat-policy.ts +19 -10
- package/src/resources/extensions/gsd/uat-run.ts +10 -14
- package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
- package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
- package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
- package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +7 -16
- package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
- package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
- package/src/resources/extensions/shared/interview-ui.ts +15 -2
- package/src/resources/shared/claude-runtime-floor.ts +248 -0
- package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
- package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
- package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
- package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
- package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_ssgManifest.js +0 -0
|
@@ -4,6 +4,7 @@ import { readFileSync } from "node:fs";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import {
|
|
6
6
|
RUN_UAT_BROWSER_TOOL_NAMES,
|
|
7
|
+
resolveToolPresentationPlan,
|
|
7
8
|
buildRunUatResultPresentation,
|
|
8
9
|
buildRunUatPresentationForType,
|
|
9
10
|
RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
@@ -179,6 +180,33 @@ test("browser-executable UAT presentation uses direct browser tools", () => {
|
|
|
179
180
|
assert.ok(!presentation.presentedTools.some((toolName) => toolName.startsWith("mcp__gsd-browser__")));
|
|
180
181
|
});
|
|
181
182
|
|
|
183
|
+
test("run-uat presentation plans carry typed tool-surface snapshots", () => {
|
|
184
|
+
const plan = resolveToolPresentationPlan({
|
|
185
|
+
phase: "run-uat",
|
|
186
|
+
surface: "mcp",
|
|
187
|
+
workflowMcpServerName: "gsd-workflow",
|
|
188
|
+
availableToolNames: [
|
|
189
|
+
"gsd_uat_exec",
|
|
190
|
+
"gsd_uat_result_save",
|
|
191
|
+
"read",
|
|
192
|
+
],
|
|
193
|
+
includeBrowserTools: [],
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
assert.equal(plan.toolSurface.source, "presentation-plan");
|
|
197
|
+
assert.equal(plan.toolSurface.phase, "run-uat");
|
|
198
|
+
assert.deepEqual(plan.toolSurface.scopedToolNames, [
|
|
199
|
+
"gsd_uat_exec",
|
|
200
|
+
"gsd_uat_result_save",
|
|
201
|
+
"read",
|
|
202
|
+
]);
|
|
203
|
+
assert.deepEqual(plan.toolSurface.presentedToolNames, [
|
|
204
|
+
"mcp__gsd-workflow__gsd_uat_exec",
|
|
205
|
+
"mcp__gsd-workflow__gsd_uat_result_save",
|
|
206
|
+
"read",
|
|
207
|
+
]);
|
|
208
|
+
});
|
|
209
|
+
|
|
182
210
|
test("live-runtime and mixed UAT presentations also surface browser tools", () => {
|
|
183
211
|
// Regression (M001/S03): the run-uat prompt tells live-runtime and mixed to
|
|
184
212
|
// drive a browser, so the runner must actually receive the browser tools and
|
|
@@ -517,6 +545,24 @@ test("plan-slice prompt clarifies gsd_plan_slice handles task persistence", () =
|
|
|
517
545
|
assert.match(prompt, /gsd_plan_slice` handles task persistence/i);
|
|
518
546
|
});
|
|
519
547
|
|
|
548
|
+
test("plan-slice prompt references web app UAT guidance when planning browser work", () => {
|
|
549
|
+
const prompt = readPrompt("plan-slice");
|
|
550
|
+
assert.match(prompt, /Web App UAT guidance/i);
|
|
551
|
+
assert.match(prompt, /Playwright smoke scaffolding/i);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
test("complete-slice prompt references web app UAT mode rules", () => {
|
|
555
|
+
const prompt = readPrompt("complete-slice");
|
|
556
|
+
assert.match(prompt, /Web App UAT guidance/i);
|
|
557
|
+
assert.match(prompt, /browser-executable|runtime-executable/i);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test("plan-milestone prompt seeds web verification strategy", () => {
|
|
561
|
+
const prompt = readPrompt("plan-milestone");
|
|
562
|
+
assert.match(prompt, /Web apps/i);
|
|
563
|
+
assert.match(prompt, /Playwright|browser_\*/i);
|
|
564
|
+
});
|
|
565
|
+
|
|
520
566
|
test("replan-slice prompt uses gsd_replan_slice as canonical DB-backed tool", () => {
|
|
521
567
|
const prompt = readPrompt("replan-slice");
|
|
522
568
|
assert.match(prompt, /gsd_replan_slice/);
|
|
@@ -740,6 +740,15 @@ test("MAX_TRANSIENT_AUTO_RESUMES is at least 8 for sustained overload resilience
|
|
|
740
740
|
);
|
|
741
741
|
});
|
|
742
742
|
|
|
743
|
+
// ── OpenAI-completions mid-stream cut (#577) ─────────────────────────────────
|
|
744
|
+
|
|
745
|
+
test("classifyError: 'Stream ended without finish_reason' is transient network (#577)", () => {
|
|
746
|
+
const result = classifyError("Stream ended without finish_reason");
|
|
747
|
+
assert.ok(isTransient(result), "Stream ended without finish_reason must be transient");
|
|
748
|
+
assert.equal(result.kind, "network");
|
|
749
|
+
assert.ok("retryAfterMs" in result && result.retryAfterMs > 0);
|
|
750
|
+
});
|
|
751
|
+
|
|
743
752
|
// ── Stream idle timeout / partial response (#4558) ──────────────────────────
|
|
744
753
|
|
|
745
754
|
test("classifyError: 'Stream idle timeout - partial response received' is transient network", () => {
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
import type { ContextManagementConfig } from "../preferences-types.js";
|
|
5
|
+
import type { ProviderPayloadPolicyDeps } from "../provider-payload-policy.js";
|
|
6
|
+
|
|
7
|
+
import { applyProviderPayloadPolicy } from "../provider-payload-policy.js";
|
|
8
|
+
|
|
9
|
+
function createDeps(
|
|
10
|
+
overrides: Partial<ProviderPayloadPolicyDeps> & {
|
|
11
|
+
context?: ContextManagementConfig | undefined;
|
|
12
|
+
autoActive?: boolean;
|
|
13
|
+
sourceContextBlock?: string | null;
|
|
14
|
+
} = {},
|
|
15
|
+
): ProviderPayloadPolicyDeps {
|
|
16
|
+
return {
|
|
17
|
+
isAutoActive: () => overrides.autoActive ?? false,
|
|
18
|
+
loadContextManagementConfig: () => overrides.context,
|
|
19
|
+
renderSourceContextBlock: () => overrides.sourceContextBlock ?? null,
|
|
20
|
+
getEffectiveServiceTier: () => undefined,
|
|
21
|
+
supportsServiceTier: () => false,
|
|
22
|
+
...overrides,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function textFromMessage(message: { content?: unknown }): string {
|
|
27
|
+
const content = message.content;
|
|
28
|
+
if (typeof content === "string") return content;
|
|
29
|
+
if (!Array.isArray(content)) return "";
|
|
30
|
+
const text = content.find((block): block is { text: string } => {
|
|
31
|
+
return Boolean(block && typeof block === "object" && "text" in block && typeof block.text === "string");
|
|
32
|
+
});
|
|
33
|
+
return text?.text ?? "";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
test("provider payload policy truncates tool results outside auto-mode without masking", () => {
|
|
37
|
+
const messageText = "m".repeat(50);
|
|
38
|
+
const responsesOutput = "r".repeat(50);
|
|
39
|
+
const payload = {
|
|
40
|
+
messages: [
|
|
41
|
+
{ role: "user", content: [{ type: "text", text: "keep me" }] },
|
|
42
|
+
{ role: "toolResult", content: [{ type: "text", text: messageText }] },
|
|
43
|
+
],
|
|
44
|
+
input: [
|
|
45
|
+
{ role: "user", content: [{ type: "input_text", text: "keep me" }] },
|
|
46
|
+
{ type: "function_call_output", call_id: "call_test", output: responsesOutput },
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
applyProviderPayloadPolicy({
|
|
51
|
+
payload,
|
|
52
|
+
deps: createDeps({ context: { observation_mask_turns: 1, tool_result_max_chars: 10 } }),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const truncatedMessage = textFromMessage(payload.messages[1]);
|
|
56
|
+
const truncatedResponsesOutput = String(payload.input[1]?.output ?? "");
|
|
57
|
+
assert.match(truncatedMessage, /\[truncated\]/);
|
|
58
|
+
assert.match(truncatedResponsesOutput, /\[truncated\]/);
|
|
59
|
+
assert.doesNotMatch(truncatedMessage, /result masked/);
|
|
60
|
+
assert.doesNotMatch(truncatedResponsesOutput, /result masked/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("provider payload policy appends source context after masking and truncation", () => {
|
|
64
|
+
const sourceContextBlock = "## Source Context Block\n\n" + "full source text ".repeat(20);
|
|
65
|
+
const payload = {
|
|
66
|
+
messages: [
|
|
67
|
+
{ role: "user", content: [{ type: "text", text: "old turn" }] },
|
|
68
|
+
{ role: "toolResult", content: [{ type: "text", text: "old result ".repeat(20) }] },
|
|
69
|
+
{ role: "assistant", content: [{ type: "text", text: "ok" }] },
|
|
70
|
+
{ role: "user", content: [{ type: "text", text: "new turn" }] },
|
|
71
|
+
{ role: "toolResult", content: [{ type: "text", text: "new result ".repeat(20) }] },
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
applyProviderPayloadPolicy({
|
|
76
|
+
payload,
|
|
77
|
+
deps: createDeps({
|
|
78
|
+
autoActive: true,
|
|
79
|
+
context: { observation_mask_turns: 1, tool_result_max_chars: 80 },
|
|
80
|
+
sourceContextBlock,
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const oldResult = textFromMessage(payload.messages[1]);
|
|
85
|
+
const newResult = textFromMessage(payload.messages[4]);
|
|
86
|
+
const appendedContext = textFromMessage(payload.messages[payload.messages.length - 1]);
|
|
87
|
+
|
|
88
|
+
assert.match(oldResult, /result masked/);
|
|
89
|
+
assert.match(newResult, /\[truncated\]/);
|
|
90
|
+
assert.equal(appendedContext, sourceContextBlock);
|
|
91
|
+
assert.doesNotMatch(appendedContext, /\[truncated\]/);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("provider payload policy applies ordering to Responses input payloads", () => {
|
|
95
|
+
const sourceContextBlock = "## Source Context Block\n\n" + "responses source text ".repeat(20);
|
|
96
|
+
const payload = {
|
|
97
|
+
input: [
|
|
98
|
+
{ role: "user", content: [{ type: "input_text", text: "old turn" }] },
|
|
99
|
+
{ type: "function_call_output", call_id: "call_old", output: "old result ".repeat(20) },
|
|
100
|
+
{ type: "message", role: "assistant", content: [{ type: "output_text", text: "ok" }] },
|
|
101
|
+
{ role: "user", content: [{ type: "input_text", text: "new turn" }] },
|
|
102
|
+
{ type: "function_call_output", call_id: "call_new", output: "new result ".repeat(20) },
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
applyProviderPayloadPolicy({
|
|
107
|
+
payload,
|
|
108
|
+
deps: createDeps({
|
|
109
|
+
autoActive: true,
|
|
110
|
+
context: { observation_mask_turns: 1, tool_result_max_chars: 80 },
|
|
111
|
+
sourceContextBlock,
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
assert.match(String(payload.input[1]?.output ?? ""), /result masked/);
|
|
116
|
+
assert.match(String(payload.input[4]?.output ?? ""), /\[truncated\]/);
|
|
117
|
+
assert.equal(textFromMessage(payload.input[payload.input.length - 1]), sourceContextBlock);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("provider payload policy replaces existing source context blocks", () => {
|
|
121
|
+
const payload = {
|
|
122
|
+
messages: [
|
|
123
|
+
{ role: "user", content: [{ type: "text", text: "keep me" }] },
|
|
124
|
+
{ role: "user", content: [{ type: "text", text: "## Source Context Block\n\nstale" }] },
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
applyProviderPayloadPolicy({
|
|
129
|
+
payload,
|
|
130
|
+
deps: createDeps({
|
|
131
|
+
autoActive: true,
|
|
132
|
+
sourceContextBlock: "## Source Context Block\n\nfresh",
|
|
133
|
+
}),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const sourceMessages = payload.messages.filter((message) => {
|
|
137
|
+
return textFromMessage(message).startsWith("## Source Context Block");
|
|
138
|
+
});
|
|
139
|
+
assert.equal(sourceMessages.length, 1);
|
|
140
|
+
assert.equal(textFromMessage(sourceMessages[0]), "## Source Context Block\n\nfresh");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("provider payload policy sets service tier only for supported models", () => {
|
|
144
|
+
const unsupported = {};
|
|
145
|
+
applyProviderPayloadPolicy({
|
|
146
|
+
payload: unsupported,
|
|
147
|
+
modelId: "claude-opus-4-6",
|
|
148
|
+
deps: createDeps({
|
|
149
|
+
getEffectiveServiceTier: () => "priority",
|
|
150
|
+
supportsServiceTier: (modelId) => modelId === "gpt-5.4",
|
|
151
|
+
}),
|
|
152
|
+
});
|
|
153
|
+
assert.equal("service_tier" in unsupported, false);
|
|
154
|
+
|
|
155
|
+
const supported: Record<string, unknown> = {};
|
|
156
|
+
applyProviderPayloadPolicy({
|
|
157
|
+
payload: supported,
|
|
158
|
+
modelId: "gpt-5.4",
|
|
159
|
+
deps: createDeps({
|
|
160
|
+
getEffectiveServiceTier: () => "priority",
|
|
161
|
+
supportsServiceTier: (modelId) => modelId === "gpt-5.4",
|
|
162
|
+
}),
|
|
163
|
+
});
|
|
164
|
+
assert.equal(supported.service_tier, "priority");
|
|
165
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Tests for process-level pull request policy.
|
|
3
|
+
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
buildPullRequestEvidence,
|
|
9
|
+
createDraftPullRequestFromEvidence,
|
|
10
|
+
} from "../pull-request-process.js";
|
|
11
|
+
|
|
12
|
+
test("buildPullRequestEvidence omits AI credit by policy", () => {
|
|
13
|
+
const evidence = buildPullRequestEvidence({
|
|
14
|
+
milestoneId: "M001",
|
|
15
|
+
milestoneTitle: "Git process",
|
|
16
|
+
aiAssisted: true,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
assert.equal(evidence.title, "feat: Git process");
|
|
20
|
+
assert.ok(!evidence.body.includes("## AI Assistance Disclosure"));
|
|
21
|
+
assert.ok(!evidence.body.includes("AI assistance"));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("createDraftPullRequestFromEvidence forwards exact evidence and branch options", () => {
|
|
25
|
+
const calls: unknown[][] = [];
|
|
26
|
+
const url = createDraftPullRequestFromEvidence(
|
|
27
|
+
"/repo",
|
|
28
|
+
"M001",
|
|
29
|
+
{ title: "feat: Git process", body: "body" },
|
|
30
|
+
{ head: "milestone/M001", base: "main" },
|
|
31
|
+
{
|
|
32
|
+
createDraftPR: (basePath, milestoneId, title, body, opts) => {
|
|
33
|
+
calls.push([basePath, milestoneId, title, body, opts]);
|
|
34
|
+
return "https://github.example/pr/1";
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
assert.equal(url, "https://github.example/pr/1");
|
|
40
|
+
assert.deepEqual(calls, [[
|
|
41
|
+
"/repo",
|
|
42
|
+
"M001",
|
|
43
|
+
"feat: Git process",
|
|
44
|
+
"body",
|
|
45
|
+
{ head: "milestone/M001", base: "main" },
|
|
46
|
+
]]);
|
|
47
|
+
});
|
|
@@ -18,6 +18,11 @@ import {
|
|
|
18
18
|
} from "../bootstrap/write-gate.ts";
|
|
19
19
|
import { classifyCommand } from "../safety/destructive-guard.ts";
|
|
20
20
|
import { toRoundResultResponse } from "../../remote-questions/manager.ts";
|
|
21
|
+
import {
|
|
22
|
+
markInteractiveElicitationStart,
|
|
23
|
+
markInteractiveElicitationEnd,
|
|
24
|
+
clearInFlightTools,
|
|
25
|
+
} from "../auto-tool-tracking.ts";
|
|
21
26
|
|
|
22
27
|
function makeTempDir(prefix: string): string {
|
|
23
28
|
const dir = join(
|
|
@@ -708,3 +713,92 @@ test("register-hooks gates MCP ask_user_questions cancellation before requiremen
|
|
|
708
713
|
assert.equal(requirementBlock?.block, true, "requirement save must be blocked while gate is pending");
|
|
709
714
|
assert.match(requirementBlock?.reason ?? "", /has not been confirmed/);
|
|
710
715
|
});
|
|
716
|
+
|
|
717
|
+
// ─── Foreground self-cancel regression (#cc-elicitation-self-cancel) ───
|
|
718
|
+
// Product-visible symptom: under claude-code-cli + gsd-MCP, ask_user_questions
|
|
719
|
+
// is routed as an SDK elicitation (the human boundary). The message_update hook
|
|
720
|
+
// would arm the approval-gate pause and emit the "waiting for your approval -
|
|
721
|
+
// pausing" notice, tearing down that elicitation and looping a re-ask. The fix
|
|
722
|
+
// makes message_update bail while an interactive elicitation is in flight, while
|
|
723
|
+
// still pausing for prose-only approvals (native-TUI provider, where the marker
|
|
724
|
+
// is always false). This drives the real registered hook end-to-end.
|
|
725
|
+
test("register-hooks message_update does NOT pause while an interactive elicitation is the human boundary, but still pauses otherwise", async (t) => {
|
|
726
|
+
const dir = makeTempDir("elicitation-pause-guard");
|
|
727
|
+
const originalCwd = process.cwd();
|
|
728
|
+
process.chdir(dir);
|
|
729
|
+
resetWriteGateState(dir);
|
|
730
|
+
clearPendingAutoStart(dir);
|
|
731
|
+
clearInFlightTools();
|
|
732
|
+
|
|
733
|
+
t.after(() => {
|
|
734
|
+
try {
|
|
735
|
+
resetWriteGateState(dir);
|
|
736
|
+
clearPendingAutoStart(dir);
|
|
737
|
+
clearInFlightTools();
|
|
738
|
+
} finally {
|
|
739
|
+
process.chdir(originalCwd);
|
|
740
|
+
rmSync(dir, { recursive: true, force: true });
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
|
|
745
|
+
const pi = {
|
|
746
|
+
on(event: string, handler: (event: any, ctx?: any) => Promise<any> | any) {
|
|
747
|
+
const existing = handlers.get(event) ?? [];
|
|
748
|
+
existing.push(handler);
|
|
749
|
+
handlers.set(event, existing);
|
|
750
|
+
},
|
|
751
|
+
} as any;
|
|
752
|
+
|
|
753
|
+
const notices: Array<{ text: string; level: string }> = [];
|
|
754
|
+
const ctx = {
|
|
755
|
+
cwd: dir,
|
|
756
|
+
ui: { notify: (text: string, level: string) => notices.push({ text, level }) },
|
|
757
|
+
} as any;
|
|
758
|
+
|
|
759
|
+
registerHooks(pi, []);
|
|
760
|
+
|
|
761
|
+
// A discuss-milestone is the active unit, so the approval text would normally
|
|
762
|
+
// arm the pause/notice path.
|
|
763
|
+
setPendingAutoStart(dir, {
|
|
764
|
+
basePath: dir,
|
|
765
|
+
milestoneId: "M001",
|
|
766
|
+
ctx,
|
|
767
|
+
pi: { sendMessage: () => undefined } as any,
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
// The model's plain-text approval question — identical in both phases.
|
|
771
|
+
const approvalMessage = {
|
|
772
|
+
role: "assistant",
|
|
773
|
+
content: [
|
|
774
|
+
{ type: "text", text: "Here is the milestone plan.\n\nDid I capture the project correctly?" },
|
|
775
|
+
],
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
const fireMessageUpdate = async () => {
|
|
779
|
+
for (const handler of handlers.get("message_update") ?? []) {
|
|
780
|
+
await handler({ message: approvalMessage }, ctx);
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
// Phase 1 — FIX: an interactive elicitation is in flight (claude-code-cli
|
|
785
|
+
// foreground). The pause/notice MUST be suppressed.
|
|
786
|
+
markInteractiveElicitationStart();
|
|
787
|
+
await fireMessageUpdate();
|
|
788
|
+
assert.equal(
|
|
789
|
+
notices.some((n) => /waiting for your approval - pausing/.test(n.text)),
|
|
790
|
+
false,
|
|
791
|
+
"must NOT emit the approval-pause notice while the elicitation is the human boundary",
|
|
792
|
+
);
|
|
793
|
+
markInteractiveElicitationEnd();
|
|
794
|
+
|
|
795
|
+
// Phase 2 — control: no elicitation in flight (native-TUI provider or a
|
|
796
|
+
// prose-only approval). The same message MUST still pause.
|
|
797
|
+
notices.length = 0;
|
|
798
|
+
await fireMessageUpdate();
|
|
799
|
+
assert.equal(
|
|
800
|
+
notices.some((n) => /discuss-milestone M001 is waiting for your approval - pausing/.test(n.text)),
|
|
801
|
+
true,
|
|
802
|
+
"prose-only approval with no elicitation in flight must still arm the pause notice",
|
|
803
|
+
);
|
|
804
|
+
});
|
|
@@ -396,4 +396,44 @@ test('T. #1736: Checkbox format unchanged', () => {
|
|
|
396
396
|
assert.deepStrictEqual(slices[1].done, false, '#1736 checkbox compat: S02 not done');
|
|
397
397
|
});
|
|
398
398
|
|
|
399
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
400
|
+
// U. Regression #566: double-bracket depends serialization recovery
|
|
401
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
402
|
+
test('U. #566: double-bracket depends:[[S01]] recovers to ["S01"]', () => {
|
|
403
|
+
// Simulates a roadmap written by markdown-renderer when the DB had
|
|
404
|
+
// depends=["[S01]"] — produces `depends:[[S01]]` on disk.
|
|
405
|
+
const content = [
|
|
406
|
+
'# M020: Corrupted Depends',
|
|
407
|
+
'',
|
|
408
|
+
'## Slices',
|
|
409
|
+
'',
|
|
410
|
+
'- [ ] **S01: Foundation** `risk:low` `depends:[]`',
|
|
411
|
+
'- [ ] **S02: Build** `risk:medium` `depends:[[S01]]`',
|
|
412
|
+
'- [ ] **S03: Ship** `risk:high` `depends:[[S01, S02]]`',
|
|
413
|
+
'',
|
|
414
|
+
].join('\n');
|
|
415
|
+
|
|
416
|
+
const slices = parseRoadmapSlices(content);
|
|
417
|
+
assert.deepStrictEqual(slices.length, 3, '#566 double-bracket: 3 slices');
|
|
418
|
+
assert.deepStrictEqual(slices[1].depends, ['S01'], '#566: S02 depends recovered to ["S01"]');
|
|
419
|
+
assert.deepStrictEqual(slices[2].depends, ['S01', 'S02'], '#566: S03 depends recovered to ["S01","S02"]');
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test('U. #566: bracket-wrapped single element depends:[[S01]] recovers to ["S01"]', () => {
|
|
423
|
+
// Simulates the exact DB corruption seen in the forensic evidence: depends=["[S01]"]
|
|
424
|
+
const content = [
|
|
425
|
+
'# M020: Single Bracket Corruption',
|
|
426
|
+
'',
|
|
427
|
+
'## Slices',
|
|
428
|
+
'',
|
|
429
|
+
'- [ ] **S01: First** `risk:low` `depends:[]`',
|
|
430
|
+
'- [ ] **S02: Second** `risk:medium` `depends:[[S01]]`',
|
|
431
|
+
'',
|
|
432
|
+
].join('\n');
|
|
433
|
+
|
|
434
|
+
const slices = parseRoadmapSlices(content);
|
|
435
|
+
assert.deepStrictEqual(slices[1].depends.length, 1, '#566 single: S02 has exactly 1 dep');
|
|
436
|
+
assert.deepStrictEqual(slices[1].depends[0], 'S01', '#566 single: dep is "S01" not "[S01]"');
|
|
437
|
+
});
|
|
438
|
+
|
|
399
439
|
});
|
|
@@ -6,7 +6,7 @@ import assert from "node:assert/strict";
|
|
|
6
6
|
|
|
7
7
|
import { classifyFailure } from "../recovery-classification.js";
|
|
8
8
|
import { reconcileBeforeDispatch } from "../state-reconciliation.js";
|
|
9
|
-
import { compileUnitToolContract } from "../tool-contract.js";
|
|
9
|
+
import { compileUnitContextContract, compileUnitToolContract } from "../tool-contract.js";
|
|
10
10
|
import { shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
|
|
11
11
|
import type { GSDState } from "../types.js";
|
|
12
12
|
|
|
@@ -68,6 +68,16 @@ test("Tool Contract compiles known Unit prompt and tool policy", () => {
|
|
|
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
70
|
assert.ok(result.ok && result.contract.validationRules.includes("source-observation-contract-present"));
|
|
71
|
+
assert.deepEqual(result.ok && result.contract.promptContext.artifacts.inline, [
|
|
72
|
+
"task-plan",
|
|
73
|
+
"slice-plan",
|
|
74
|
+
"prior-task-summaries",
|
|
75
|
+
"templates",
|
|
76
|
+
]);
|
|
77
|
+
assert.deepEqual(result.ok && result.contract.promptContext.artifacts.onDemand, ["slice-research"]);
|
|
78
|
+
assert.ok(result.ok && result.contract.promptObligations.includes("context-inline:task-plan,slice-plan,prior-task-summaries,templates"));
|
|
79
|
+
assert.ok(result.ok && result.contract.promptObligations.includes("context-on-demand:slice-research"));
|
|
80
|
+
assert.ok(result.ok && result.contract.promptObligations.includes("source-observations:whole-file-active-unit"));
|
|
71
81
|
assert.deepEqual(result.ok && result.contract.sourceObservations, {
|
|
72
82
|
mode: "whole-file-active-unit",
|
|
73
83
|
seedFields: ["task.files", "task.inputs"],
|
|
@@ -77,6 +87,20 @@ test("Tool Contract compiles known Unit prompt and tool policy", () => {
|
|
|
77
87
|
});
|
|
78
88
|
});
|
|
79
89
|
|
|
90
|
+
test("Unit Context Contract exposes prompt context without workflow tool surface", () => {
|
|
91
|
+
const result = compileUnitContextContract("execute-task");
|
|
92
|
+
|
|
93
|
+
assert.equal(result.ok, true);
|
|
94
|
+
assert.equal(result.ok && result.contract.unitType, "execute-task");
|
|
95
|
+
assert.equal(result.ok && result.contract.contextMode, "execution");
|
|
96
|
+
assert.equal(result.ok && result.contract.toolsPolicy.mode, "all");
|
|
97
|
+
assert.deepEqual(result.ok && result.contract.artifacts.excerpt, []);
|
|
98
|
+
assert.deepEqual(result.ok && result.contract.artifacts.computed, []);
|
|
99
|
+
assert.deepEqual(result.ok && result.contract.artifacts.prepend, []);
|
|
100
|
+
assert.equal(result.ok && result.contract.maxSystemPromptChars, 1_500_000);
|
|
101
|
+
assert.equal(result.ok && result.contract.sourceObservations.mode, "whole-file-active-unit");
|
|
102
|
+
});
|
|
103
|
+
|
|
80
104
|
test("Tool Contract records high-risk cross-phase tool boundaries without single-owning every tool", () => {
|
|
81
105
|
const completeSlice = compileUnitToolContract("complete-slice");
|
|
82
106
|
const runUat = compileUnitToolContract("run-uat");
|
|
@@ -24,6 +24,7 @@ import { fileURLToPath } from "node:url";
|
|
|
24
24
|
|
|
25
25
|
import { autoSession } from "../auto-runtime-state.ts";
|
|
26
26
|
import { registerHooks } from "../bootstrap/register-hooks.ts";
|
|
27
|
+
import { _resetPreferenceDiagnosticNotificationsForTests } from "../preferences-diagnostics.ts";
|
|
27
28
|
|
|
28
29
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
29
30
|
const HOOKS_SOURCE = readFileSync(
|
|
@@ -485,3 +486,82 @@ test("session_start and session_switch apply disabled model provider policy from
|
|
|
485
486
|
"session_switch should re-read preferences for the switched project/session context",
|
|
486
487
|
);
|
|
487
488
|
});
|
|
489
|
+
|
|
490
|
+
test("session_start surfaces malformed preference diagnostics through visible notifications", async (t) => {
|
|
491
|
+
const dir = join(
|
|
492
|
+
tmpdir(),
|
|
493
|
+
`gsd-session-pref-diagnostics-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
494
|
+
);
|
|
495
|
+
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
496
|
+
const tempGsdHome = join(dir, "home");
|
|
497
|
+
mkdirSync(tempGsdHome, { recursive: true });
|
|
498
|
+
|
|
499
|
+
const originalCwd = process.cwd();
|
|
500
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
501
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
502
|
+
process.chdir(dir);
|
|
503
|
+
_resetPreferenceDiagnosticNotificationsForTests();
|
|
504
|
+
t.after(() => {
|
|
505
|
+
process.chdir(originalCwd);
|
|
506
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
507
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
508
|
+
_resetPreferenceDiagnosticNotificationsForTests();
|
|
509
|
+
try { rmSync(dir, { recursive: true, force: true }); } catch { /* best-effort */ }
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
writeFileSync(
|
|
513
|
+
join(dir, ".gsd", "PREFERENCES.md"),
|
|
514
|
+
[
|
|
515
|
+
"---",
|
|
516
|
+
"version: 1",
|
|
517
|
+
"models:",
|
|
518
|
+
" validation:",
|
|
519
|
+
" openrouter/deepseek/deepseek-v4-pro",
|
|
520
|
+
" thinking: high",
|
|
521
|
+
"---",
|
|
522
|
+
"",
|
|
523
|
+
].join("\n"),
|
|
524
|
+
"utf-8",
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
const notifications: Array<{ message: string; level?: string }> = [];
|
|
528
|
+
const handlers = new Map<string, (event: unknown, ctx: any) => Promise<void> | void>();
|
|
529
|
+
const pi = {
|
|
530
|
+
on(event: string, handler: (event: unknown, ctx: any) => Promise<void> | void) {
|
|
531
|
+
handlers.set(event, handler);
|
|
532
|
+
},
|
|
533
|
+
} as any;
|
|
534
|
+
const ctx = {
|
|
535
|
+
hasUI: true,
|
|
536
|
+
ui: {
|
|
537
|
+
notify: (message: string, level?: string) => notifications.push({ message, level }),
|
|
538
|
+
setStatus: () => {},
|
|
539
|
+
setFooter: () => {},
|
|
540
|
+
setWorkingMessage: () => {},
|
|
541
|
+
onTerminalInput: () => () => {},
|
|
542
|
+
setWidget: () => {},
|
|
543
|
+
},
|
|
544
|
+
sessionManager: { getSessionId: () => null },
|
|
545
|
+
model: null,
|
|
546
|
+
setCompactionThresholdOverride: () => {},
|
|
547
|
+
modelRegistry: {
|
|
548
|
+
setDisabledModelProviders: () => {},
|
|
549
|
+
getProviderAuthMode: () => undefined,
|
|
550
|
+
isProviderRequestReady: () => false,
|
|
551
|
+
},
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
registerHooks(pi, []);
|
|
555
|
+
|
|
556
|
+
const sessionStart = handlers.get("session_start");
|
|
557
|
+
assert.ok(sessionStart, "session_start handler must be registered");
|
|
558
|
+
await sessionStart!({}, ctx);
|
|
559
|
+
|
|
560
|
+
const diagnostic = notifications.find((notification) =>
|
|
561
|
+
notification.message.includes("GSD project preferences error"),
|
|
562
|
+
);
|
|
563
|
+
assert.equal(diagnostic?.level, "error");
|
|
564
|
+
assert.match(diagnostic?.message ?? "", /could not be parsed/);
|
|
565
|
+
assert.match(diagnostic?.message ?? "", /line 5, column 5/);
|
|
566
|
+
assert.match(diagnostic?.message ?? "", /Preferences from this file were ignored/);
|
|
567
|
+
});
|