@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
|
@@ -38,6 +38,8 @@ import {
|
|
|
38
38
|
} from "../stream-adapter.ts";
|
|
39
39
|
import type { AssistantMessage, Context, Message } from "@gsd/pi-ai";
|
|
40
40
|
import type { SDKUserMessage } from "../sdk-types.ts";
|
|
41
|
+
import { _setAutoActiveForTest } from "../../gsd/auto.ts";
|
|
42
|
+
import { getInFlightToolCount, hasInteractiveToolInFlight, clearInFlightTools, isInteractiveElicitationInFlight } from "../../gsd/auto-tool-tracking.ts";
|
|
41
43
|
|
|
42
44
|
// ---------------------------------------------------------------------------
|
|
43
45
|
// Env helpers — `GSD_WORKFLOW_MCP_*` save/restore
|
|
@@ -58,6 +60,7 @@ const WORKFLOW_MCP_ENV_KEYS = [
|
|
|
58
60
|
"GSD_WORKFLOW_MCP_ARGS",
|
|
59
61
|
"GSD_WORKFLOW_MCP_ENV",
|
|
60
62
|
"GSD_WORKFLOW_MCP_CWD",
|
|
63
|
+
"GSD_WORKFLOW_MCP_STRUCTURED_QUESTIONS",
|
|
61
64
|
"GSD_PROJECT_ROOT",
|
|
62
65
|
"GSD_WORKFLOW_PROJECT_ROOT",
|
|
63
66
|
] as const;
|
|
@@ -796,9 +799,9 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
796
799
|
assert.equal(options.persistSession, true, "persistSession must default to true");
|
|
797
800
|
});
|
|
798
801
|
|
|
799
|
-
test("buildSdkOptions loads project and local settings so approved
|
|
802
|
+
test("buildSdkOptions loads user, project, and local settings so approved Claude Code config is active", () => {
|
|
800
803
|
const options = buildSdkOptions("claude-sonnet-4-20250514", "test prompt");
|
|
801
|
-
assert.deepEqual(options.settingSources, ["project", "local"]);
|
|
804
|
+
assert.deepEqual(options.settingSources, ["user", "project", "local"]);
|
|
802
805
|
});
|
|
803
806
|
|
|
804
807
|
test("buildSdkOptions sets model and prompt correctly", () => {
|
|
@@ -1043,6 +1046,31 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1043
1046
|
}
|
|
1044
1047
|
});
|
|
1045
1048
|
|
|
1049
|
+
test("buildSdkOptions can disable workflow MCP ask_user_questions explicitly", () => {
|
|
1050
|
+
const restore = setWorkflowMcpEnv({
|
|
1051
|
+
GSD_WORKFLOW_MCP_COMMAND: "node",
|
|
1052
|
+
GSD_WORKFLOW_MCP_NAME: "gsd-workflow",
|
|
1053
|
+
GSD_WORKFLOW_MCP_ARGS: JSON.stringify(["packages/mcp-server/dist/cli.js"]),
|
|
1054
|
+
GSD_WORKFLOW_MCP_CWD: "/tmp/project",
|
|
1055
|
+
GSD_WORKFLOW_MCP_STRUCTURED_QUESTIONS: "0",
|
|
1056
|
+
});
|
|
1057
|
+
const originalCwd = process.cwd();
|
|
1058
|
+
const emptyDir = mkdtempSync(join(tmpdir(), "claude-mcp-ask-disabled-"));
|
|
1059
|
+
try {
|
|
1060
|
+
process.chdir(emptyDir);
|
|
1061
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test");
|
|
1062
|
+
assert.ok(
|
|
1063
|
+
(options.disallowedTools as string[]).includes("mcp__gsd-workflow__ask_user_questions"),
|
|
1064
|
+
"explicit opt-out must block the MCP question tool even when workflow wildcard is allowed",
|
|
1065
|
+
);
|
|
1066
|
+
assert.ok((options.disallowedTools as string[]).includes("AskUserQuestion"));
|
|
1067
|
+
} finally {
|
|
1068
|
+
process.chdir(originalCwd);
|
|
1069
|
+
rmSync(emptyDir, { recursive: true, force: true });
|
|
1070
|
+
restore();
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1046
1074
|
test("buildSdkOptions scopes run-uat to exact workflow MCP tools", () => {
|
|
1047
1075
|
const restore = setWorkflowMcpEnv({
|
|
1048
1076
|
GSD_WORKFLOW_MCP_COMMAND: "node",
|
|
@@ -1140,6 +1168,38 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1140
1168
|
assert.equal(inferGsdPhaseFromContext(context), "plan-milestone");
|
|
1141
1169
|
});
|
|
1142
1170
|
|
|
1171
|
+
test("buildSdkOptions presents ask_user_questions for discuss phases", () => {
|
|
1172
|
+
const restore = setWorkflowMcpEnv({
|
|
1173
|
+
GSD_WORKFLOW_MCP_COMMAND: "node",
|
|
1174
|
+
GSD_WORKFLOW_MCP_NAME: "gsd-workflow",
|
|
1175
|
+
GSD_WORKFLOW_MCP_ARGS: JSON.stringify(["packages/mcp-server/dist/cli.js"]),
|
|
1176
|
+
GSD_WORKFLOW_MCP_ENV: JSON.stringify({ GSD_CLI_PATH: "/tmp/gsd" }),
|
|
1177
|
+
GSD_WORKFLOW_MCP_CWD: "/tmp/project",
|
|
1178
|
+
});
|
|
1179
|
+
const originalCwd = process.cwd();
|
|
1180
|
+
const emptyDir = mkdtempSync(join(tmpdir(), "claude-mcp-discuss-"));
|
|
1181
|
+
try {
|
|
1182
|
+
process.chdir(emptyDir);
|
|
1183
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test", undefined, { gsdPhase: "discuss-milestone" });
|
|
1184
|
+
const allowedTools = options.allowedTools as string[];
|
|
1185
|
+
const disallowedTools = options.disallowedTools as string[];
|
|
1186
|
+
|
|
1187
|
+
assert.ok(
|
|
1188
|
+
allowedTools.includes("mcp__gsd-workflow__ask_user_questions"),
|
|
1189
|
+
"discuss phases must expose the exact workflow MCP question tool",
|
|
1190
|
+
);
|
|
1191
|
+
assert.ok(disallowedTools.includes("AskUserQuestion"));
|
|
1192
|
+
assert.ok(
|
|
1193
|
+
!disallowedTools.includes("mcp__gsd-workflow__ask_user_questions"),
|
|
1194
|
+
"workflow MCP ask_user_questions should remain enabled by default",
|
|
1195
|
+
);
|
|
1196
|
+
} finally {
|
|
1197
|
+
process.chdir(originalCwd);
|
|
1198
|
+
rmSync(emptyDir, { recursive: true, force: true });
|
|
1199
|
+
restore();
|
|
1200
|
+
}
|
|
1201
|
+
});
|
|
1202
|
+
|
|
1143
1203
|
test("buildSdkOptions prefers custom workflow MCP question tools over native AskUserQuestion", () => {
|
|
1144
1204
|
const restore = setWorkflowMcpEnv({
|
|
1145
1205
|
GSD_WORKFLOW_MCP_COMMAND: "node",
|
|
@@ -1662,6 +1722,26 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|
|
1662
1722
|
});
|
|
1663
1723
|
});
|
|
1664
1724
|
|
|
1725
|
+
test("createClaudeCodeElicitationHandler returns cancel when custom UI is dismissed", async () => {
|
|
1726
|
+
let selectCalls = 0;
|
|
1727
|
+
const handler = createClaudeCodeElicitationHandler({
|
|
1728
|
+
custom: async () => ({
|
|
1729
|
+
endInterview: false,
|
|
1730
|
+
answers: {},
|
|
1731
|
+
}),
|
|
1732
|
+
select: async () => {
|
|
1733
|
+
selectCalls++;
|
|
1734
|
+
return "Cloud-synced";
|
|
1735
|
+
},
|
|
1736
|
+
} as any);
|
|
1737
|
+
assert.ok(handler);
|
|
1738
|
+
|
|
1739
|
+
const result = await handler!(askUserQuestionsRequest, { signal: new AbortController().signal });
|
|
1740
|
+
|
|
1741
|
+
assert.deepEqual(result, { action: "cancel" });
|
|
1742
|
+
assert.equal(selectCalls, 0, "dismissed custom question must not re-open dialog fallback");
|
|
1743
|
+
});
|
|
1744
|
+
|
|
1665
1745
|
test("parseTextInputElicitation recognizes secure free-text MCP forms", () => {
|
|
1666
1746
|
const request = {
|
|
1667
1747
|
serverName: "gsd-workflow",
|
|
@@ -1773,6 +1853,166 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|
|
1773
1853
|
assert.equal(inputCalls.length, 1);
|
|
1774
1854
|
assert.equal(inputCalls[0]?.opts?.secure, true, "secure_env_collect fields should request secure input");
|
|
1775
1855
|
});
|
|
1856
|
+
|
|
1857
|
+
// -- self-cancel loop fix (#2676 / claude-code-cli) ----------------------
|
|
1858
|
+
//
|
|
1859
|
+
// Under claude-code-cli, ask_user_questions arrives as an SDK elicitation,
|
|
1860
|
+
// not an MCP tool dispatch, so the auto-mode watchdogs never saw an in-flight
|
|
1861
|
+
// tool during the human wait and re-dispatched/aborted the turn hosting the
|
|
1862
|
+
// question (the "self-cancel loop"). The fix brackets the human wait with the
|
|
1863
|
+
// interactive-tool guard and disambiguates a system-teardown abort (decline)
|
|
1864
|
+
// from a deliberate user dismissal (cancel).
|
|
1865
|
+
|
|
1866
|
+
test("makes the SDK elicitation visible to the interactive-tool guard during the human wait", async () => {
|
|
1867
|
+
_setAutoActiveForTest(true);
|
|
1868
|
+
clearInFlightTools();
|
|
1869
|
+
try {
|
|
1870
|
+
let countDuringWait = -1;
|
|
1871
|
+
let interactiveDuringWait = false;
|
|
1872
|
+
const handler = createClaudeCodeElicitationHandler({
|
|
1873
|
+
custom: async () => {
|
|
1874
|
+
// Observe the in-flight guard state WHILE the question is open —
|
|
1875
|
+
// this is the window where the watchdogs previously saw 0 tools.
|
|
1876
|
+
countDuringWait = getInFlightToolCount();
|
|
1877
|
+
interactiveDuringWait = hasInteractiveToolInFlight();
|
|
1878
|
+
return {
|
|
1879
|
+
endInterview: false,
|
|
1880
|
+
answers: { storage_scope: { selected: "Cloud-synced", notes: "" }, platform: { selected: ["Web"], notes: "" } },
|
|
1881
|
+
};
|
|
1882
|
+
},
|
|
1883
|
+
} as any);
|
|
1884
|
+
assert.ok(handler);
|
|
1885
|
+
|
|
1886
|
+
const result = await handler!(askUserQuestionsRequest, { signal: new AbortController().signal });
|
|
1887
|
+
|
|
1888
|
+
assert.equal(countDuringWait, 1, "elicitation must register as an in-flight tool during the human wait");
|
|
1889
|
+
assert.equal(interactiveDuringWait, true, "elicitation must be recognized as an interactive tool during the wait");
|
|
1890
|
+
assert.equal(result.action, "accept");
|
|
1891
|
+
assert.equal(getInFlightToolCount(), 0, "in-flight tool must be cleared after the elicitation resolves");
|
|
1892
|
+
} finally {
|
|
1893
|
+
_setAutoActiveForTest(false);
|
|
1894
|
+
clearInFlightTools();
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1897
|
+
|
|
1898
|
+
test("clears the in-flight tool even when the interview UI throws (finally)", async () => {
|
|
1899
|
+
_setAutoActiveForTest(true);
|
|
1900
|
+
clearInFlightTools();
|
|
1901
|
+
try {
|
|
1902
|
+
const handler = createClaudeCodeElicitationHandler({
|
|
1903
|
+
// custom throws -> showInterviewRound rejects -> handler falls back
|
|
1904
|
+
// to dialogs; the in-flight entry must still be cleared via finally.
|
|
1905
|
+
custom: async () => {
|
|
1906
|
+
throw new Error("simulated UI failure");
|
|
1907
|
+
},
|
|
1908
|
+
select: async (_title: string, options: string[], opts?: { allowMultiple?: boolean }) => {
|
|
1909
|
+
if (opts?.allowMultiple) return ["Web"];
|
|
1910
|
+
return options[0];
|
|
1911
|
+
},
|
|
1912
|
+
input: async () => "note",
|
|
1913
|
+
} as any);
|
|
1914
|
+
assert.ok(handler);
|
|
1915
|
+
|
|
1916
|
+
await handler!(askUserQuestionsRequest, { signal: new AbortController().signal });
|
|
1917
|
+
assert.equal(getInFlightToolCount(), 0, "in-flight tool must be cleared even when the UI throws");
|
|
1918
|
+
} finally {
|
|
1919
|
+
_setAutoActiveForTest(false);
|
|
1920
|
+
clearInFlightTools();
|
|
1921
|
+
}
|
|
1922
|
+
});
|
|
1923
|
+
|
|
1924
|
+
test("returns decline (not cancel) when an interrupt empties the answers", async () => {
|
|
1925
|
+
// A system/host teardown that aborts the signal mid-wait surfaces as
|
|
1926
|
+
// interrupted:true -> the handler must return decline so the model does
|
|
1927
|
+
// not re-ask against a clean user-declined cancel (the re-ask amplifier).
|
|
1928
|
+
const handler = createClaudeCodeElicitationHandler({
|
|
1929
|
+
custom: async () => ({ endInterview: false, answers: {}, interrupted: true }),
|
|
1930
|
+
select: async () => {
|
|
1931
|
+
throw new Error("interrupted elicitation must not re-open dialogs");
|
|
1932
|
+
},
|
|
1933
|
+
} as any);
|
|
1934
|
+
assert.ok(handler);
|
|
1935
|
+
|
|
1936
|
+
const result = await handler!(askUserQuestionsRequest, { signal: new AbortController().signal });
|
|
1937
|
+
assert.deepEqual(result, { action: "decline" });
|
|
1938
|
+
});
|
|
1939
|
+
|
|
1940
|
+
test("returns cancel (today's semantics) when the user genuinely dismisses", async () => {
|
|
1941
|
+
const handler = createClaudeCodeElicitationHandler({
|
|
1942
|
+
custom: async () => ({ endInterview: false, answers: {} }),
|
|
1943
|
+
} as any);
|
|
1944
|
+
assert.ok(handler);
|
|
1945
|
+
|
|
1946
|
+
const result = await handler!(askUserQuestionsRequest, { signal: new AbortController().signal });
|
|
1947
|
+
assert.deepEqual(result, { action: "cancel" });
|
|
1948
|
+
});
|
|
1949
|
+
|
|
1950
|
+
test("does not register an in-flight tool outside auto-mode (wrapper self-gates)", async () => {
|
|
1951
|
+
_setAutoActiveForTest(false);
|
|
1952
|
+
clearInFlightTools();
|
|
1953
|
+
let countDuringWait = -1;
|
|
1954
|
+
const handler = createClaudeCodeElicitationHandler({
|
|
1955
|
+
custom: async () => {
|
|
1956
|
+
countDuringWait = getInFlightToolCount();
|
|
1957
|
+
return { endInterview: false, answers: { storage_scope: { selected: "Cloud-synced", notes: "" }, platform: { selected: ["Web"], notes: "" } } };
|
|
1958
|
+
},
|
|
1959
|
+
} as any);
|
|
1960
|
+
assert.ok(handler);
|
|
1961
|
+
|
|
1962
|
+
await handler!(askUserQuestionsRequest, { signal: new AbortController().signal });
|
|
1963
|
+
assert.equal(countDuringWait, 0, "foreground/non-auto elicitation must not touch the in-flight guard");
|
|
1964
|
+
});
|
|
1965
|
+
|
|
1966
|
+
// The FOREGROUND self-cancel regression guard: the s.active-gated in-flight
|
|
1967
|
+
// guard above is a no-op in foreground, so the foreground approval-gate pause
|
|
1968
|
+
// path needs a SEPARATE, ungated signal to see the elicitation as the active
|
|
1969
|
+
// human boundary. isInteractiveElicitationInFlight() must be true DURING the
|
|
1970
|
+
// wait and false after, even with auto inactive (#cc-elicitation-self-cancel).
|
|
1971
|
+
test("sets the ungated interactive-elicitation marker in FOREGROUND (auto inactive)", async () => {
|
|
1972
|
+
_setAutoActiveForTest(false);
|
|
1973
|
+
clearInFlightTools();
|
|
1974
|
+
try {
|
|
1975
|
+
let markerDuringWait = false;
|
|
1976
|
+
let countDuringWait = -1;
|
|
1977
|
+
const handler = createClaudeCodeElicitationHandler({
|
|
1978
|
+
custom: async () => {
|
|
1979
|
+
markerDuringWait = isInteractiveElicitationInFlight();
|
|
1980
|
+
countDuringWait = getInFlightToolCount();
|
|
1981
|
+
return {
|
|
1982
|
+
endInterview: false,
|
|
1983
|
+
answers: { storage_scope: { selected: "Cloud-synced", notes: "" }, platform: { selected: ["Web"], notes: "" } },
|
|
1984
|
+
};
|
|
1985
|
+
},
|
|
1986
|
+
} as any);
|
|
1987
|
+
assert.ok(handler);
|
|
1988
|
+
|
|
1989
|
+
const result = await handler!(askUserQuestionsRequest, { signal: new AbortController().signal });
|
|
1990
|
+
|
|
1991
|
+
assert.equal(markerDuringWait, true, "ungated marker must be true during the foreground human wait");
|
|
1992
|
+
assert.equal(countDuringWait, 0, "the separate marker must NOT touch the in-flight tool count in foreground");
|
|
1993
|
+
assert.equal(result.action, "accept");
|
|
1994
|
+
assert.equal(isInteractiveElicitationInFlight(), false, "marker must clear after the elicitation resolves");
|
|
1995
|
+
} finally {
|
|
1996
|
+
clearInFlightTools();
|
|
1997
|
+
}
|
|
1998
|
+
});
|
|
1999
|
+
|
|
2000
|
+
test("clears the ungated marker even when the interview UI throws in FOREGROUND (finally)", async () => {
|
|
2001
|
+
_setAutoActiveForTest(false);
|
|
2002
|
+
clearInFlightTools();
|
|
2003
|
+
try {
|
|
2004
|
+
const handler = createClaudeCodeElicitationHandler({
|
|
2005
|
+
custom: async () => {
|
|
2006
|
+
throw new Error("ui exploded");
|
|
2007
|
+
},
|
|
2008
|
+
} as any);
|
|
2009
|
+
assert.ok(handler);
|
|
2010
|
+
await handler!(askUserQuestionsRequest, { signal: new AbortController().signal }).catch(() => undefined);
|
|
2011
|
+
assert.equal(isInteractiveElicitationInFlight(), false, "marker must clear via finally on throw");
|
|
2012
|
+
} finally {
|
|
2013
|
+
clearInFlightTools();
|
|
2014
|
+
}
|
|
2015
|
+
});
|
|
1776
2016
|
});
|
|
1777
2017
|
|
|
1778
2018
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// gsd-pi - Claude Code logical turn assembly
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
AssistantMessage,
|
|
5
|
+
AssistantMessageEvent,
|
|
6
|
+
ToolCall,
|
|
7
|
+
} from "@gsd/pi-ai";
|
|
8
|
+
import { PartialMessageBuilder } from "./partial-builder.js";
|
|
9
|
+
import type {
|
|
10
|
+
BetaRawMessageStreamEvent,
|
|
11
|
+
SDKUserMessage,
|
|
12
|
+
} from "./sdk-types.js";
|
|
13
|
+
|
|
14
|
+
/** A single content block returned by an external (SDK-executed) tool call. */
|
|
15
|
+
export interface ExternalToolResultContentBlock {
|
|
16
|
+
type: string;
|
|
17
|
+
text?: string;
|
|
18
|
+
data?: string;
|
|
19
|
+
mimeType?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The full result payload returned by an external tool, including content blocks and error status. */
|
|
23
|
+
export interface ExternalToolResultPayload {
|
|
24
|
+
content: ExternalToolResultContentBlock[];
|
|
25
|
+
details?: Record<string, unknown>;
|
|
26
|
+
isError: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** A `ToolCall` block augmented with the external result attached by the SDK synthetic user message. */
|
|
30
|
+
export type ToolCallWithExternalResult = ToolCall & {
|
|
31
|
+
externalResult?: ExternalToolResultPayload;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** Normalise heterogeneous SDK tool-result content (string, array, or object) into a uniform `ExternalToolResultContentBlock[]`. */
|
|
35
|
+
function normalizeToolResultContent(content: unknown): ExternalToolResultContentBlock[] {
|
|
36
|
+
if (typeof content === "string") {
|
|
37
|
+
return [{ type: "text", text: content }];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!Array.isArray(content)) {
|
|
41
|
+
if (content == null) return [{ type: "text", text: "" }];
|
|
42
|
+
return [{ type: "text", text: JSON.stringify(content) }];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const blocks: ExternalToolResultContentBlock[] = [];
|
|
46
|
+
|
|
47
|
+
for (const item of content) {
|
|
48
|
+
if (typeof item === "string") {
|
|
49
|
+
blocks.push({ type: "text", text: item });
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!item || typeof item !== "object") {
|
|
53
|
+
blocks.push({ type: "text", text: String(item) });
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const block = item as Record<string, unknown>;
|
|
58
|
+
if (block.type === "text") {
|
|
59
|
+
blocks.push({ type: "text", text: typeof block.text === "string" ? block.text : "" });
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (
|
|
63
|
+
block.type === "image"
|
|
64
|
+
&& typeof block.data === "string"
|
|
65
|
+
&& typeof block.mimeType === "string"
|
|
66
|
+
) {
|
|
67
|
+
blocks.push({ type: "image", data: block.data, mimeType: block.mimeType });
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
blocks.push({ type: "text", text: JSON.stringify(block) });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return blocks.length > 0 ? blocks : [{ type: "text", text: "" }];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extract a `details` payload from an MCP tool-result block.
|
|
79
|
+
*
|
|
80
|
+
* MCP's `CallToolResult` carries structured data in `structuredContent` — the
|
|
81
|
+
* protocol's supported channel for non-text payloads. Claude Code's synthetic
|
|
82
|
+
* user message may surface that field in one of two shapes depending on SDK
|
|
83
|
+
* version: as a sibling on the `mcp_tool_result` block itself, or as a
|
|
84
|
+
* dedicated content sub-block with `type: "structuredContent"`. Snake-case
|
|
85
|
+
* (`structured_content`) is accepted defensively in case a transport hop
|
|
86
|
+
* rewrites casing. All other shapes return undefined, matching the nullable
|
|
87
|
+
* `details` contract consumed by tool result renderers.
|
|
88
|
+
*/
|
|
89
|
+
function extractStructuredDetailsFromBlock(block: Record<string, unknown>): Record<string, unknown> | undefined {
|
|
90
|
+
const sibling = block.structuredContent ?? (block as Record<string, unknown>).structured_content;
|
|
91
|
+
if (sibling && typeof sibling === "object" && !Array.isArray(sibling)) {
|
|
92
|
+
return sibling as Record<string, unknown>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (Array.isArray(block.content)) {
|
|
96
|
+
for (const item of block.content) {
|
|
97
|
+
if (!item || typeof item !== "object") continue;
|
|
98
|
+
const sub = item as Record<string, unknown>;
|
|
99
|
+
if (sub.type !== "structuredContent" && sub.type !== "structured_content") continue;
|
|
100
|
+
const payload = sub.structuredContent ?? sub.structured_content ?? sub.data ?? sub.value;
|
|
101
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
102
|
+
return payload as Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Return undefined (not {}) when no structured payload is present, matching
|
|
108
|
+
// the pre-#4477 contract where `details` was nullable. An empty-object
|
|
109
|
+
// sentinel is truthy and breaks downstream consumers that gate on
|
|
110
|
+
// `if (details)`. `undefined` matches the type of the field these results
|
|
111
|
+
// flow into (`Record<string, unknown> | undefined`).
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* True for items that are MCP `structuredContent` pseudo-blocks living inside
|
|
117
|
+
* a tool-result `content[]` array. These blocks carry the structured payload
|
|
118
|
+
* (extracted separately by `extractStructuredDetailsFromBlock`) and must NOT
|
|
119
|
+
* leak into the visible content rendered to the user — otherwise the renderer
|
|
120
|
+
* stringifies the JSON pseudo-block and shows it next to the actual tool
|
|
121
|
+
* output. See PR #4477 review (post-fix-round).
|
|
122
|
+
*/
|
|
123
|
+
function isStructuredContentPseudoBlock(item: unknown): boolean {
|
|
124
|
+
if (!item || typeof item !== "object") return false;
|
|
125
|
+
const type = (item as Record<string, unknown>).type;
|
|
126
|
+
return type === "structuredContent" || type === "structured_content";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Strip `structuredContent` pseudo-blocks from a tool-result content array
|
|
131
|
+
* before normalization. The structured payload is extracted via the sibling
|
|
132
|
+
* `structuredContent` field (or a dedicated extractor pass on the raw block);
|
|
133
|
+
* the visible content path must not include the pseudo-block itself.
|
|
134
|
+
*/
|
|
135
|
+
function stripStructuredContentPseudoBlocks(content: unknown): unknown {
|
|
136
|
+
if (!Array.isArray(content)) return content;
|
|
137
|
+
return content.filter((item) => !isStructuredContentPseudoBlock(item));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Extract tool result payloads from an SDK synthetic user message, keyed by tool-use ID. */
|
|
141
|
+
export function extractToolResultsFromSdkUserMessage(message: SDKUserMessage): Array<{
|
|
142
|
+
toolUseId: string;
|
|
143
|
+
result: ExternalToolResultPayload;
|
|
144
|
+
}> {
|
|
145
|
+
const extracted: Array<{ toolUseId: string; result: ExternalToolResultPayload }> = [];
|
|
146
|
+
const seen = new Set<string>();
|
|
147
|
+
const rawMessage = message.message as Record<string, unknown> | null | undefined;
|
|
148
|
+
const content = Array.isArray(rawMessage?.content) ? rawMessage.content : [];
|
|
149
|
+
|
|
150
|
+
for (const item of content) {
|
|
151
|
+
if (!item || typeof item !== "object") continue;
|
|
152
|
+
const block = item as Record<string, unknown>;
|
|
153
|
+
const type = typeof block.type === "string" ? block.type : "";
|
|
154
|
+
if (type !== "tool_result" && type !== "mcp_tool_result") continue;
|
|
155
|
+
|
|
156
|
+
const toolUseId = typeof block.tool_use_id === "string" ? block.tool_use_id : "";
|
|
157
|
+
if (!toolUseId || seen.has(toolUseId)) continue;
|
|
158
|
+
seen.add(toolUseId);
|
|
159
|
+
|
|
160
|
+
extracted.push({
|
|
161
|
+
toolUseId,
|
|
162
|
+
result: {
|
|
163
|
+
content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(block.content)),
|
|
164
|
+
details: extractStructuredDetailsFromBlock(block),
|
|
165
|
+
isError: block.is_error === true,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (extracted.length === 0) {
|
|
171
|
+
const fallback = message.tool_use_result;
|
|
172
|
+
if (fallback && typeof fallback === "object") {
|
|
173
|
+
const toolResult = fallback as Record<string, unknown>;
|
|
174
|
+
const toolUseId = typeof toolResult.tool_use_id === "string" ? toolResult.tool_use_id : "";
|
|
175
|
+
if (toolUseId) {
|
|
176
|
+
extracted.push({
|
|
177
|
+
toolUseId,
|
|
178
|
+
result: {
|
|
179
|
+
content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(toolResult.content)),
|
|
180
|
+
details: extractStructuredDetailsFromBlock(toolResult),
|
|
181
|
+
isError: toolResult.is_error === true,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return extracted;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Attach external tool results from the SDK synthetic user message to their corresponding tool-call blocks by ID. */
|
|
192
|
+
export function attachExternalResultsToToolBlocks(
|
|
193
|
+
toolBlocks: AssistantMessage["content"],
|
|
194
|
+
toolResultsById: ReadonlyMap<string, ExternalToolResultPayload>,
|
|
195
|
+
): void {
|
|
196
|
+
for (const block of toolBlocks) {
|
|
197
|
+
if (block.type !== "toolCall" && block.type !== "serverToolUse") continue;
|
|
198
|
+
const externalResult = toolResultsById.get(block.id);
|
|
199
|
+
if (!externalResult) continue;
|
|
200
|
+
(block as ToolCallWithExternalResult & { id: string }).externalResult = externalResult;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Build the final assistant content that Agent Core consumes in
|
|
206
|
+
* `externalToolExecution` mode. This preserves tool-call blocks, attaches any
|
|
207
|
+
* SDK-produced external results by tool-call id, and then appends the final
|
|
208
|
+
* text/thinking blocks for the completed turn.
|
|
209
|
+
*/
|
|
210
|
+
export function buildFinalAssistantContent(params: {
|
|
211
|
+
intermediateToolBlocks: AssistantMessage["content"];
|
|
212
|
+
pendingContent?: AssistantMessage["content"];
|
|
213
|
+
toolResultsById: ReadonlyMap<string, ExternalToolResultPayload>;
|
|
214
|
+
lastThinkingContent?: string;
|
|
215
|
+
lastTextContent?: string;
|
|
216
|
+
fallbackResultText?: string;
|
|
217
|
+
}): AssistantMessage["content"] {
|
|
218
|
+
const mergedToolBlocks = [...params.intermediateToolBlocks];
|
|
219
|
+
if (params.pendingContent) {
|
|
220
|
+
mergePendingToolCalls(mergedToolBlocks, params.pendingContent);
|
|
221
|
+
}
|
|
222
|
+
attachExternalResultsToToolBlocks(mergedToolBlocks, params.toolResultsById);
|
|
223
|
+
|
|
224
|
+
const finalContent: AssistantMessage["content"] = [...mergedToolBlocks];
|
|
225
|
+
if (params.pendingContent && params.pendingContent.length > 0) {
|
|
226
|
+
for (const block of params.pendingContent) {
|
|
227
|
+
if (block.type === "text" || block.type === "thinking") {
|
|
228
|
+
finalContent.push(block);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
if (params.lastThinkingContent) {
|
|
233
|
+
finalContent.push({ type: "thinking", thinking: params.lastThinkingContent });
|
|
234
|
+
}
|
|
235
|
+
if (params.lastTextContent) {
|
|
236
|
+
finalContent.push({ type: "text", text: params.lastTextContent });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (finalContent.length === 0 && params.fallbackResultText) {
|
|
241
|
+
finalContent.push({ type: "text", text: params.fallbackResultText });
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return finalContent;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Merge tool-call blocks from the active partial-message builder into the
|
|
249
|
+
* running list of intermediate tool calls, preserving order and de-duping
|
|
250
|
+
* by tool-call id. Exposed for testing the F3 fix (final-turn tool calls
|
|
251
|
+
* dropped when `result` arrives without a preceding synthetic `user`).
|
|
252
|
+
*/
|
|
253
|
+
export function mergePendingToolCalls(
|
|
254
|
+
intermediate: AssistantMessage["content"],
|
|
255
|
+
pending: AssistantMessage["content"],
|
|
256
|
+
): AssistantMessage["content"] {
|
|
257
|
+
const alreadyIncluded = new Set<string>();
|
|
258
|
+
for (const block of intermediate) {
|
|
259
|
+
if (block.type === "toolCall") alreadyIncluded.add(block.id);
|
|
260
|
+
}
|
|
261
|
+
for (const block of pending) {
|
|
262
|
+
if (block.type !== "toolCall") continue;
|
|
263
|
+
if (alreadyIncluded.has(block.id)) continue;
|
|
264
|
+
alreadyIncluded.add(block.id);
|
|
265
|
+
intermediate.push(block);
|
|
266
|
+
}
|
|
267
|
+
return intermediate;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export function handleClaudeCodePartialStreamEvent(
|
|
271
|
+
builder: PartialMessageBuilder | null,
|
|
272
|
+
event: BetaRawMessageStreamEvent,
|
|
273
|
+
modelId: string,
|
|
274
|
+
): { builder: PartialMessageBuilder | null; assistantEvent: AssistantMessageEvent | null } {
|
|
275
|
+
if (event.type === "message_start") {
|
|
276
|
+
// Claude Code can emit repeated SDK message_start events inside one
|
|
277
|
+
// logical assistant response. Keep appending until a synthetic user
|
|
278
|
+
// tool-result boundary explicitly clears the builder.
|
|
279
|
+
return {
|
|
280
|
+
builder: builder ?? new PartialMessageBuilder((event as any).message?.model ?? modelId),
|
|
281
|
+
assistantEvent: null,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!builder) return { builder, assistantEvent: null };
|
|
286
|
+
return { builder, assistantEvent: builder.handleEvent(event) };
|
|
287
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* for the `gh` CLI body parameters.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { buildPullRequestEvidence } from "../gsd/pull-request-process.js";
|
|
13
13
|
|
|
14
14
|
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
15
15
|
|
|
@@ -116,7 +116,7 @@ export function formatSlicePRBody(data: SliceData): string {
|
|
|
116
116
|
.filter((issueNumber): issueNumber is number => typeof issueNumber === "number")
|
|
117
117
|
.map((issueNumber) => `#${issueNumber}`);
|
|
118
118
|
|
|
119
|
-
return
|
|
119
|
+
return buildPullRequestEvidence({
|
|
120
120
|
milestoneId: data.id,
|
|
121
121
|
subjectId: data.id,
|
|
122
122
|
subjectKind: "slice",
|
|
@@ -267,7 +267,7 @@ export function formatSwarmLanePRBody(data: SwarmLanePRData): string {
|
|
|
267
267
|
`### Transition risks\n${checkedList(data.transitionRisks, "No transition risks identified").join("\n")}`,
|
|
268
268
|
].filter(Boolean);
|
|
269
269
|
|
|
270
|
-
return
|
|
270
|
+
return buildPullRequestEvidence({
|
|
271
271
|
milestoneId: laneLabel,
|
|
272
272
|
subjectId: laneLabel,
|
|
273
273
|
subjectKind: "workflow",
|
|
@@ -62,7 +62,7 @@ describe("templates", () => {
|
|
|
62
62
|
assert.ok(body.includes("- Session type"));
|
|
63
63
|
assert.ok(body.includes("## Linked Issue"));
|
|
64
64
|
assert.ok(body.includes("## Tests Run"));
|
|
65
|
-
assert.ok(body.includes("## AI Assistance Disclosure"));
|
|
65
|
+
assert.ok(!body.includes("## AI Assistance Disclosure"));
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
it("renders task checklist with issue links", () => {
|
|
@@ -173,7 +173,7 @@ describe("templates", () => {
|
|
|
173
173
|
assert.ok(body.includes("- Disable writer sequence enrichment"));
|
|
174
174
|
assert.ok(body.includes("- npm run typecheck:extensions"));
|
|
175
175
|
assert.ok(body.includes("Closes #123"));
|
|
176
|
-
assert.ok(body.includes("## AI Assistance Disclosure"));
|
|
176
|
+
assert.ok(!body.includes("## AI Assistance Disclosure"));
|
|
177
177
|
});
|
|
178
178
|
|
|
179
179
|
it("formats release checklist bodies from lane state", () => {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Resolves closeout artifact projection roots across project and milestone worktrees.
|
|
3
|
+
|
|
4
|
+
import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
|
|
5
|
+
import { resolveWorktreeProjectRoot } from "./worktree-root.js";
|
|
6
|
+
|
|
7
|
+
export interface CloseoutArtifactProjectionInput {
|
|
8
|
+
milestoneId: string;
|
|
9
|
+
basePath: string;
|
|
10
|
+
originalBasePath?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CloseoutArtifactProjection {
|
|
14
|
+
projectRoot: string;
|
|
15
|
+
canonicalMilestoneRoot: string;
|
|
16
|
+
summaryArtifactBasePath: string;
|
|
17
|
+
gateEvidenceBasePath: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function resolveCloseoutArtifactProjection(
|
|
21
|
+
input: CloseoutArtifactProjectionInput,
|
|
22
|
+
): CloseoutArtifactProjection {
|
|
23
|
+
const projectRoot = resolveWorktreeProjectRoot(input.basePath, input.originalBasePath);
|
|
24
|
+
const canonicalMilestoneRoot = resolveCanonicalMilestoneRoot(projectRoot, input.milestoneId);
|
|
25
|
+
return {
|
|
26
|
+
projectRoot,
|
|
27
|
+
canonicalMilestoneRoot,
|
|
28
|
+
summaryArtifactBasePath: canonicalMilestoneRoot,
|
|
29
|
+
gateEvidenceBasePath: canonicalMilestoneRoot,
|
|
30
|
+
};
|
|
31
|
+
}
|