@opengsd/gsd-pi 1.1.1-dev.b2556262 → 1.2.0-dev.4813ead6
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/project-sessions.js +4 -2
- 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 +101 -237
- 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/contracts.js +8 -1
- package/dist/resources/extensions/gsd/auto/loop.js +74 -56
- package/dist/resources/extensions/gsd/auto/orchestrator.js +763 -63
- 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 +191 -9
- package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
- package/dist/resources/extensions/gsd/auto-runtime-state.js +17 -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 +37 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +33 -29
- package/dist/resources/extensions/gsd/auto-verification.js +7 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +45 -36
- package/dist/resources/extensions/gsd/auto.js +73 -471
- 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 +103 -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/debug-logger.js +10 -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-proactive.js +7 -2
- 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 +36 -470
- package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +33 -33
- package/dist/resources/extensions/gsd/mcp-filter.js +8 -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/native-git-bridge.js +45 -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/discuss.md +6 -7
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
- 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/schemas/parsers.js +6 -1
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +21 -1
- 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/tools/workflow-tool-executors.js +169 -20
- 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 +65 -4
- 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 -0
- 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 +5 -5
- 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/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +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 +5 -5
- package/dist/web/standalone/.next/server/chunks/5047.js +2 -0
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -0
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- 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/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web/standalone/node_modules/postcss/lib/container.js +26 -18
- package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +47 -14
- package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
- package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
- package/dist/web/standalone/node_modules/postcss/lib/input.js +54 -29
- package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +47 -37
- package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +26 -9
- package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +57 -55
- package/dist/web/standalone/node_modules/postcss/lib/node.js +99 -31
- package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
- package/dist/web/standalone/node_modules/postcss/lib/parser.js +10 -9
- package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
- package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +30 -11
- package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
- package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
- package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
- package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +69 -28
- package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +6 -2
- package/dist/web/standalone/node_modules/postcss/package.json +48 -48
- package/dist/web-mode.d.ts +2 -0
- package/dist/web-mode.js +20 -8
- package/package.json +17 -11
- 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/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -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.js +1 -1
- 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 +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/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 +8 -127
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +47 -166
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +11 -3
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +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/scripts/install/deps.js +10 -0
- package/scripts/link-workspace-packages.cjs +7 -40
- package/src/resources/extensions/ask-user-questions.ts +87 -24
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +126 -289
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +242 -2
- 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 +40 -121
- 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 +913 -64
- 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 +220 -9
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
- package/src/resources/extensions/gsd/auto-runtime-state.ts +30 -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 +40 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +42 -30
- package/src/resources/extensions/gsd/auto-verification.ts +7 -8
- package/src/resources/extensions/gsd/auto-worktree.ts +57 -42
- package/src/resources/extensions/gsd/auto.ts +96 -508
- 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 +120 -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/debug-logger.ts +11 -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-proactive.ts +8 -2
- 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 +49 -560
- package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +40 -20
- package/src/resources/extensions/gsd/mcp-filter.ts +9 -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/native-git-bridge.ts +48 -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/discuss.md +6 -7
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/research-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
- 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/schemas/parsers.ts +6 -1
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +31 -10
- 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/artifact-db-drift-memo.test.ts +66 -0
- 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-dispatch-baseline-harness.test.ts +53 -0
- 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 +709 -845
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +38 -10
- 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/debug-logger.test.ts +15 -0
- 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-summary-save-empty-project.test.ts +64 -1
- 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/integration/merge-strategy-regular.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer-parse-cache.test.ts +75 -0
- 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/native-merge-regular.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/orchestrator-legacy-parity.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/parse-project-milestone-bridge.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +6 -2
- 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 +75 -2
- 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/research-milestone-composer.test.ts +65 -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 +21 -6
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +38 -0
- 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 +147 -0
- 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-safety.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -3
- 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/tools/workflow-tool-executors.ts +183 -21
- 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 +55 -5
- 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/server/chunks/678.js +0 -2
- 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/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +0 -21
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +0 -213
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts +0 -28
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js +0 -249
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts +0 -19
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js +0 -797
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js.map +0 -1
- package/scripts/ensure-workspace-builds.cjs +0 -129
- /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_ssgManifest.js +0 -0
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
renderPreferencesForSystemPrompt,
|
|
27
27
|
_resetParseWarningFlag,
|
|
28
28
|
} from "../preferences.ts";
|
|
29
|
+
import { collectPreferenceDiagnostics, formatPreferenceDiagnostic } from "../preferences-diagnostics.ts";
|
|
29
30
|
import { formatConfiguredModel, toPersistedModelId } from "../commands-prefs-wizard.ts";
|
|
30
31
|
import { _resetLogs, peekLogs } from "../workflow-logger.ts";
|
|
31
32
|
import type { GSDPreferences, GSDModelConfigV2, GSDPhaseModelConfig } from "../preferences.ts";
|
|
@@ -819,6 +820,188 @@ bad: [
|
|
|
819
820
|
_resetLogs();
|
|
820
821
|
});
|
|
821
822
|
|
|
823
|
+
test("malformed global preferences load with a structured parse diagnostic", (t) => {
|
|
824
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
825
|
+
const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-diagnostic-home-"));
|
|
826
|
+
t.after(() => {
|
|
827
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
828
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
829
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
830
|
+
_resetParseWarningFlag();
|
|
831
|
+
_resetLogs();
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
835
|
+
_resetParseWarningFlag();
|
|
836
|
+
_resetLogs();
|
|
837
|
+
writeFileSync(
|
|
838
|
+
join(tempGsdHome, "PREFERENCES.md"),
|
|
839
|
+
[
|
|
840
|
+
"---",
|
|
841
|
+
"version: 1",
|
|
842
|
+
"models:",
|
|
843
|
+
" validation:",
|
|
844
|
+
" openrouter/deepseek/deepseek-v4-pro",
|
|
845
|
+
" thinking: high",
|
|
846
|
+
"---",
|
|
847
|
+
"",
|
|
848
|
+
].join("\n"),
|
|
849
|
+
"utf-8",
|
|
850
|
+
);
|
|
851
|
+
|
|
852
|
+
const loaded = loadGlobalGSDPreferences();
|
|
853
|
+
assert.notEqual(loaded, null);
|
|
854
|
+
assert.deepEqual(loaded!.preferences, {});
|
|
855
|
+
const diagnostic = loaded!.diagnostics?.[0];
|
|
856
|
+
assert.equal(diagnostic?.kind, "parse");
|
|
857
|
+
assert.equal(diagnostic?.severity, "error");
|
|
858
|
+
assert.equal(diagnostic?.line, 5);
|
|
859
|
+
assert.equal(diagnostic?.column, 5);
|
|
860
|
+
assert.equal(diagnostic?.ignored, true);
|
|
861
|
+
assert.match(diagnostic?.message ?? "", /Implicit keys need/);
|
|
862
|
+
|
|
863
|
+
const formatted = formatPreferenceDiagnostic(diagnostic!);
|
|
864
|
+
assert.match(formatted, /GSD global preferences error/);
|
|
865
|
+
assert.match(formatted, /line 5, column 5/);
|
|
866
|
+
assert.match(formatted, /Preferences from this file were ignored/);
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
test("project preference validation errors load with structured diagnostics", (t) => {
|
|
870
|
+
const originalCwd = process.cwd();
|
|
871
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
872
|
+
const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-validation-project-"));
|
|
873
|
+
const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-validation-home-"));
|
|
874
|
+
t.after(() => {
|
|
875
|
+
process.chdir(originalCwd);
|
|
876
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
877
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
878
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
879
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
883
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
884
|
+
process.chdir(tempProject);
|
|
885
|
+
writeFileSync(
|
|
886
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
887
|
+
"---\nversion: 3\n---\n",
|
|
888
|
+
"utf-8",
|
|
889
|
+
);
|
|
890
|
+
|
|
891
|
+
const loaded = loadProjectGSDPreferences(tempProject);
|
|
892
|
+
assert.notEqual(loaded, null);
|
|
893
|
+
assert.equal(loaded!.preferences.version, undefined);
|
|
894
|
+
const diagnostic = loaded!.diagnostics?.find((item) => item.kind === "validation");
|
|
895
|
+
assert.equal(diagnostic?.scope, "project");
|
|
896
|
+
assert.equal(diagnostic?.severity, "error");
|
|
897
|
+
assert.equal(diagnostic?.sanitized, true);
|
|
898
|
+
assert.match(diagnostic?.message ?? "", /unsupported version 3/);
|
|
899
|
+
|
|
900
|
+
const collected = collectPreferenceDiagnostics(tempProject);
|
|
901
|
+
assert.ok(
|
|
902
|
+
collected.some((item) => item.path === loaded!.path && item.message.includes("unsupported version 3")),
|
|
903
|
+
"collector should include project validation diagnostics",
|
|
904
|
+
);
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
test("malformed project preferences do not override effective global wrapper", (t) => {
|
|
908
|
+
const originalCwd = process.cwd();
|
|
909
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
910
|
+
const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-project-"));
|
|
911
|
+
const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-home-"));
|
|
912
|
+
t.after(() => {
|
|
913
|
+
process.chdir(originalCwd);
|
|
914
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
915
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
916
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
917
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
918
|
+
_resetParseWarningFlag();
|
|
919
|
+
_resetLogs();
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
923
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
924
|
+
process.chdir(tempProject);
|
|
925
|
+
_resetParseWarningFlag();
|
|
926
|
+
_resetLogs();
|
|
927
|
+
|
|
928
|
+
const globalPath = getGlobalGSDPreferencesPath();
|
|
929
|
+
const projectPath = getProjectGSDPreferencesPath(tempProject);
|
|
930
|
+
writeFileSync(globalPath, "---\nlanguage: Spanish\n---\n", "utf-8");
|
|
931
|
+
writeFileSync(
|
|
932
|
+
projectPath,
|
|
933
|
+
[
|
|
934
|
+
"---",
|
|
935
|
+
"version: 1",
|
|
936
|
+
"models:",
|
|
937
|
+
" validation:",
|
|
938
|
+
" openrouter/deepseek/deepseek-v4-pro",
|
|
939
|
+
" thinking: high",
|
|
940
|
+
"---",
|
|
941
|
+
"",
|
|
942
|
+
].join("\n"),
|
|
943
|
+
"utf-8",
|
|
944
|
+
);
|
|
945
|
+
|
|
946
|
+
const projectPrefs = loadProjectGSDPreferences(tempProject);
|
|
947
|
+
assert.equal(projectPrefs?.ignored, true);
|
|
948
|
+
|
|
949
|
+
const loaded = loadEffectiveGSDPreferences(tempProject);
|
|
950
|
+
assert.notEqual(loaded, null);
|
|
951
|
+
assert.equal(loaded!.path, globalPath);
|
|
952
|
+
assert.equal(loaded!.scope, "global");
|
|
953
|
+
assert.equal(loaded!.preferences.language, "Spanish");
|
|
954
|
+
assert.ok(
|
|
955
|
+
loaded!.diagnostics?.some((item) => item.path === projectPath && item.kind === "parse"),
|
|
956
|
+
"effective global preferences should carry malformed project diagnostics",
|
|
957
|
+
);
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
test("malformed global preferences: loadEffectiveGSDPreferences returns null without project file", (t) => {
|
|
961
|
+
const originalCwd = process.cwd();
|
|
962
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
963
|
+
const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-malformed-global-"));
|
|
964
|
+
const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-malformed-home-"));
|
|
965
|
+
t.after(() => {
|
|
966
|
+
process.chdir(originalCwd);
|
|
967
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
968
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
969
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
970
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
971
|
+
_resetParseWarningFlag();
|
|
972
|
+
_resetLogs();
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
976
|
+
process.chdir(tempProject);
|
|
977
|
+
_resetParseWarningFlag();
|
|
978
|
+
_resetLogs();
|
|
979
|
+
|
|
980
|
+
const globalPath = getGlobalGSDPreferencesPath();
|
|
981
|
+
writeFileSync(
|
|
982
|
+
globalPath,
|
|
983
|
+
[
|
|
984
|
+
"---",
|
|
985
|
+
"version: 1",
|
|
986
|
+
"models:",
|
|
987
|
+
" validation:",
|
|
988
|
+
" openrouter/deepseek/deepseek-v4-pro",
|
|
989
|
+
" thinking: high",
|
|
990
|
+
"---",
|
|
991
|
+
"",
|
|
992
|
+
].join("\n"),
|
|
993
|
+
"utf-8",
|
|
994
|
+
);
|
|
995
|
+
|
|
996
|
+
const globalPrefs = loadGlobalGSDPreferences();
|
|
997
|
+
assert.equal(globalPrefs?.ignored, true, "malformed global should be marked ignored");
|
|
998
|
+
|
|
999
|
+
// Symmetric with malformed project + no global: effective result should be null,
|
|
1000
|
+
// not an effective object with ignored:true leaking through.
|
|
1001
|
+
const loaded = loadEffectiveGSDPreferences(tempProject);
|
|
1002
|
+
assert.equal(loaded, null, "effective preferences should be null when only global file is malformed");
|
|
1003
|
+
});
|
|
1004
|
+
|
|
822
1005
|
// ── Experimental preferences ─────────────────────────────────────────────────
|
|
823
1006
|
|
|
824
1007
|
test("experimental.rtk: true is accepted and stored", () => {
|
|
@@ -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/);
|
|
@@ -564,6 +610,33 @@ test("validate-milestone prompt dispatches parallel reviewers", () => {
|
|
|
564
610
|
assert.match(prompt, /assessment evidence/i);
|
|
565
611
|
});
|
|
566
612
|
|
|
613
|
+
// ─── ADR-029: forward preloaded evidence to validate reviewers ────────
|
|
614
|
+
test("validate-milestone forwards preloaded evidence to reviewers and keeps full reads on-demand", () => {
|
|
615
|
+
const prompt = readPrompt("validate-milestone");
|
|
616
|
+
// Orchestrator is told to embed the preloaded evidence into reviewer tasks.
|
|
617
|
+
assert.match(prompt, /[Ee]mbed the relevant preloaded evidence/);
|
|
618
|
+
// Each reviewer is told to use the preloaded evidence, not re-read from disk.
|
|
619
|
+
const useCount = (prompt.match(/do not re-read them from disk/g) ?? []).length;
|
|
620
|
+
assert.ok(useCount >= 3, `expected all three reviewers to use preloaded evidence, found ${useCount}`);
|
|
621
|
+
// Full reads are explicitly the on-demand exception, not the routine path.
|
|
622
|
+
assert.match(prompt, /only if (its|the) preloaded (excerpt|evidence) is missing, truncated, or inconsistent/i);
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
// ─── ADR-029: research-milestone grounds instead of surveying ─────────
|
|
626
|
+
test("research-milestone prompt grounds in preloaded context instead of open-ended survey", () => {
|
|
627
|
+
const prompt = readPrompt("research-milestone");
|
|
628
|
+
// Grounded-research invariant present.
|
|
629
|
+
assert.match(prompt, /do not re-survey/i);
|
|
630
|
+
assert.match(prompt, /Codebase Snapshot and Project Classification/);
|
|
631
|
+
// The old open-ended survey license is gone (no "use `scout` to build a broad map").
|
|
632
|
+
assert.doesNotMatch(prompt, /use `scout` to build a broad map/);
|
|
633
|
+
// resolve_library/docs lookups remain permitted (bounded, external).
|
|
634
|
+
assert.match(prompt, /resolve_library/);
|
|
635
|
+
// Incremental save enables resume after interruption.
|
|
636
|
+
assert.match(prompt, /Save \*\*incrementally\*\*/);
|
|
637
|
+
assert.match(prompt, /Resume — Prior Partial Research/);
|
|
638
|
+
});
|
|
639
|
+
|
|
567
640
|
// ─── Prompt migration: replan-slice → gsd_replan_slice ────────────────
|
|
568
641
|
|
|
569
642
|
test("replan-slice prompt names gsd_replan_slice as the tool to use", () => {
|
|
@@ -700,8 +773,8 @@ test("guided-discuss prompts require 3-or-4 options plus Other-let-me-discuss in
|
|
|
700
773
|
);
|
|
701
774
|
assert.match(
|
|
702
775
|
prompt,
|
|
703
|
-
/grounded in (the |your |)investigation/i,
|
|
704
|
-
`${name} must require options grounded in prior investigation`,
|
|
776
|
+
/grounded in (the |your |)(investigation|preloaded context)/i,
|
|
777
|
+
`${name} must require options grounded in the preloaded context / prior investigation`,
|
|
705
778
|
);
|
|
706
779
|
}
|
|
707
780
|
});
|
|
@@ -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
|
+
});
|