@opengsd/gsd-pi 1.2.0-dev.844675c9 → 1.2.0-dev.955e4da0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-web-branch.d.ts +2 -0
- package/dist/cli-web-branch.js +9 -2
- package/dist/help-text.js +5 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +78 -23
- package/dist/resources/extensions/bg-shell/utilities.js +2 -2
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +92 -230
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
- package/dist/resources/extensions/github-sync/templates.js +3 -3
- package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
- package/dist/resources/extensions/gsd/auto/loop.js +74 -56
- package/dist/resources/extensions/gsd/auto/orchestrator.js +142 -15
- package/dist/resources/extensions/gsd/auto/phases.js +34 -4
- 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 +12 -9
- package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
- package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
- package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
- package/dist/resources/extensions/gsd/auto-start.js +20 -36
- package/dist/resources/extensions/gsd/auto-timers.js +16 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
- package/dist/resources/extensions/gsd/auto-verification.js +7 -7
- package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +34 -289
- package/dist/resources/extensions/gsd/auto.js +15 -14
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +20 -43
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +131 -140
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +89 -8
- package/dist/resources/extensions/gsd/captures.js +5 -13
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
- package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
- package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
- 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/engine.js +755 -0
- package/dist/resources/extensions/gsd/db/queries.js +372 -0
- package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
- package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
- package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
- package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
- package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
- package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
- package/dist/resources/extensions/gsd/db-workspace.js +103 -0
- package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
- package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +8 -10
- package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +9 -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/git-service.js +1 -0
- package/dist/resources/extensions/gsd/gitignore.js +3 -0
- package/dist/resources/extensions/gsd/gsd-db.js +183 -2048
- package/dist/resources/extensions/gsd/guided-flow.js +68 -471
- package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
- package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
- package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
- package/dist/resources/extensions/gsd/md-importer.js +4 -3
- package/dist/resources/extensions/gsd/migrate/safety.js +19 -11
- package/dist/resources/extensions/gsd/migration-auto-check.js +27 -5
- 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/model-cost-table.js +1 -0
- package/dist/resources/extensions/gsd/model-router.js +3 -0
- package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
- package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +7 -5
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/paths.js +10 -24
- package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
- package/dist/resources/extensions/gsd/preferences.js +161 -29
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
- package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
- package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
- package/dist/resources/extensions/gsd/question-transport.js +86 -0
- package/dist/resources/extensions/gsd/recovery-classification.js +12 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
- package/dist/resources/extensions/gsd/state.js +13 -5
- package/dist/resources/extensions/gsd/status-guards.js +56 -8
- 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/complete-slice.js +24 -43
- package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -5
- 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/reopen-milestone.js +11 -29
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
- package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
- package/dist/resources/extensions/gsd/uat-policy.js +16 -10
- package/dist/resources/extensions/gsd/uat-run.js +9 -14
- package/dist/resources/extensions/gsd/undo.js +8 -7
- package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
- package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
- package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
- package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
- package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
- package/dist/resources/extensions/gsd/worktree-git-recovery.js +287 -0
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
- package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
- package/dist/resources/extensions/gsd/worktree-root.js +17 -6
- package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
- package/dist/resources/extensions/gsd/worktree-session-state.js +12 -10
- 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/resources/skills/gsd-browser/SKILL.md +1 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/update-cmd.js +20 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- 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.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 +12 -12
- package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
- package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
- package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
- package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web-mode.d.ts +2 -0
- package/dist/web-mode.js +20 -8
- package/dist/worktree-status-banner.js +7 -3
- package/package.json +2 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/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/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 +32 -22
- 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 +2 -2
- package/packages/pi-ai/dist/image-models.generated.js +6 -6
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +295 -98
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +309 -154
- 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/capability-patches.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.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/src/resources/extensions/ask-user-questions.ts +87 -24
- package/src/resources/extensions/bg-shell/utilities.ts +2 -2
- package/src/resources/extensions/claude-code-cli/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +114 -281
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +268 -0
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
- package/src/resources/extensions/github-sync/templates.ts +3 -3
- package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
- package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +3 -1
- package/src/resources/extensions/gsd/auto/loop.ts +83 -61
- package/src/resources/extensions/gsd/auto/orchestrator.ts +164 -17
- package/src/resources/extensions/gsd/auto/phases.ts +45 -4
- 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 +16 -8
- package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
- package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
- package/src/resources/extensions/gsd/auto-start.ts +25 -34
- package/src/resources/extensions/gsd/auto-timers.ts +16 -2
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
- package/src/resources/extensions/gsd/auto-verification.ts +7 -8
- package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +53 -306
- package/src/resources/extensions/gsd/auto.ts +27 -17
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +20 -43
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +147 -153
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +132 -6
- package/src/resources/extensions/gsd/captures.ts +5 -14
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
- package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
- package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
- 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/engine.ts +809 -0
- package/src/resources/extensions/gsd/db/queries.ts +453 -0
- package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
- package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
- package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
- package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
- package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
- package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
- package/src/resources/extensions/gsd/db-workspace.ts +170 -0
- package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
- package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +8 -11
- package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +10 -3
- 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/git-service.ts +1 -0
- package/src/resources/extensions/gsd/gitignore.ts +3 -0
- package/src/resources/extensions/gsd/gsd-db.ts +185 -2373
- package/src/resources/extensions/gsd/guided-flow.ts +81 -561
- package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
- package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
- package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
- package/src/resources/extensions/gsd/md-importer.ts +3 -3
- package/src/resources/extensions/gsd/migrate/safety.ts +17 -9
- package/src/resources/extensions/gsd/migration-auto-check.ts +30 -5
- 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/model-cost-table.ts +1 -0
- package/src/resources/extensions/gsd/model-router.ts +3 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
- package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -5
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/paths.ts +9 -22
- 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 +191 -28
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
- package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
- package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
- package/src/resources/extensions/gsd/question-transport.ts +138 -0
- package/src/resources/extensions/gsd/recovery-classification.ts +14 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
- package/src/resources/extensions/gsd/state.ts +15 -5
- package/src/resources/extensions/gsd/status-guards.ts +59 -8
- package/src/resources/extensions/gsd/templates/plan.md +7 -0
- package/src/resources/extensions/gsd/templates/project.md +1 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/src/resources/extensions/gsd/templates/uat.md +5 -1
- package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +444 -5
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
- 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/auto-worktree-milestone-merge.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +143 -1
- package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +185 -1
- 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/safety-harness-false-positives.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/status-guards.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 +86 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +121 -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/complete-slice.ts +23 -58
- package/src/resources/extensions/gsd/tools/exec-tool.ts +5 -5
- 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/reopen-milestone.ts +11 -38
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
- package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
- package/src/resources/extensions/gsd/uat-policy.ts +19 -10
- package/src/resources/extensions/gsd/uat-run.ts +10 -14
- package/src/resources/extensions/gsd/undo.ts +9 -8
- package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
- package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
- package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
- package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
- package/src/resources/extensions/gsd/worktree-git-recovery.ts +308 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +17 -17
- package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
- package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
- package/src/resources/extensions/gsd/worktree-root.ts +17 -6
- package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
- package/src/resources/extensions/gsd/worktree-session-state.ts +12 -10
- 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/src/resources/skills/gsd-browser/SKILL.md +1 -1
- package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
- package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
- package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
- package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
- package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_ssgManifest.js +0 -0
|
@@ -4,6 +4,7 @@ import { readFileSync } from "node:fs";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import {
|
|
6
6
|
RUN_UAT_BROWSER_TOOL_NAMES,
|
|
7
|
+
resolveToolPresentationPlan,
|
|
7
8
|
buildRunUatResultPresentation,
|
|
8
9
|
buildRunUatPresentationForType,
|
|
9
10
|
RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
@@ -179,6 +180,33 @@ test("browser-executable UAT presentation uses direct browser tools", () => {
|
|
|
179
180
|
assert.ok(!presentation.presentedTools.some((toolName) => toolName.startsWith("mcp__gsd-browser__")));
|
|
180
181
|
});
|
|
181
182
|
|
|
183
|
+
test("run-uat presentation plans carry typed tool-surface snapshots", () => {
|
|
184
|
+
const plan = resolveToolPresentationPlan({
|
|
185
|
+
phase: "run-uat",
|
|
186
|
+
surface: "mcp",
|
|
187
|
+
workflowMcpServerName: "gsd-workflow",
|
|
188
|
+
availableToolNames: [
|
|
189
|
+
"gsd_uat_exec",
|
|
190
|
+
"gsd_uat_result_save",
|
|
191
|
+
"read",
|
|
192
|
+
],
|
|
193
|
+
includeBrowserTools: [],
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
assert.equal(plan.toolSurface.source, "presentation-plan");
|
|
197
|
+
assert.equal(plan.toolSurface.phase, "run-uat");
|
|
198
|
+
assert.deepEqual(plan.toolSurface.scopedToolNames, [
|
|
199
|
+
"gsd_uat_exec",
|
|
200
|
+
"gsd_uat_result_save",
|
|
201
|
+
"read",
|
|
202
|
+
]);
|
|
203
|
+
assert.deepEqual(plan.toolSurface.presentedToolNames, [
|
|
204
|
+
"mcp__gsd-workflow__gsd_uat_exec",
|
|
205
|
+
"mcp__gsd-workflow__gsd_uat_result_save",
|
|
206
|
+
"read",
|
|
207
|
+
]);
|
|
208
|
+
});
|
|
209
|
+
|
|
182
210
|
test("live-runtime and mixed UAT presentations also surface browser tools", () => {
|
|
183
211
|
// Regression (M001/S03): the run-uat prompt tells live-runtime and mixed to
|
|
184
212
|
// drive a browser, so the runner must actually receive the browser tools and
|
|
@@ -517,6 +545,24 @@ test("plan-slice prompt clarifies gsd_plan_slice handles task persistence", () =
|
|
|
517
545
|
assert.match(prompt, /gsd_plan_slice` handles task persistence/i);
|
|
518
546
|
});
|
|
519
547
|
|
|
548
|
+
test("plan-slice prompt references web app UAT guidance when planning browser work", () => {
|
|
549
|
+
const prompt = readPrompt("plan-slice");
|
|
550
|
+
assert.match(prompt, /Web App UAT guidance/i);
|
|
551
|
+
assert.match(prompt, /Playwright smoke scaffolding/i);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
test("complete-slice prompt references web app UAT mode rules", () => {
|
|
555
|
+
const prompt = readPrompt("complete-slice");
|
|
556
|
+
assert.match(prompt, /Web App UAT guidance/i);
|
|
557
|
+
assert.match(prompt, /browser-executable|runtime-executable/i);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test("plan-milestone prompt seeds web verification strategy", () => {
|
|
561
|
+
const prompt = readPrompt("plan-milestone");
|
|
562
|
+
assert.match(prompt, /Web apps/i);
|
|
563
|
+
assert.match(prompt, /Playwright|browser_\*/i);
|
|
564
|
+
});
|
|
565
|
+
|
|
520
566
|
test("replan-slice prompt uses gsd_replan_slice as canonical DB-backed tool", () => {
|
|
521
567
|
const prompt = readPrompt("replan-slice");
|
|
522
568
|
assert.match(prompt, /gsd_replan_slice/);
|
|
@@ -740,6 +740,15 @@ test("MAX_TRANSIENT_AUTO_RESUMES is at least 8 for sustained overload resilience
|
|
|
740
740
|
);
|
|
741
741
|
});
|
|
742
742
|
|
|
743
|
+
// ── OpenAI-completions mid-stream cut (#577) ─────────────────────────────────
|
|
744
|
+
|
|
745
|
+
test("classifyError: 'Stream ended without finish_reason' is transient network (#577)", () => {
|
|
746
|
+
const result = classifyError("Stream ended without finish_reason");
|
|
747
|
+
assert.ok(isTransient(result), "Stream ended without finish_reason must be transient");
|
|
748
|
+
assert.equal(result.kind, "network");
|
|
749
|
+
assert.ok("retryAfterMs" in result && result.retryAfterMs > 0);
|
|
750
|
+
});
|
|
751
|
+
|
|
743
752
|
// ── Stream idle timeout / partial response (#4558) ──────────────────────────
|
|
744
753
|
|
|
745
754
|
test("classifyError: 'Stream idle timeout - partial response received' is transient network", () => {
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
import type { ContextManagementConfig } from "../preferences-types.js";
|
|
5
|
+
import type { ProviderPayloadPolicyDeps } from "../provider-payload-policy.js";
|
|
6
|
+
|
|
7
|
+
import { applyProviderPayloadPolicy } from "../provider-payload-policy.js";
|
|
8
|
+
|
|
9
|
+
function createDeps(
|
|
10
|
+
overrides: Partial<ProviderPayloadPolicyDeps> & {
|
|
11
|
+
context?: ContextManagementConfig | undefined;
|
|
12
|
+
autoActive?: boolean;
|
|
13
|
+
sourceContextBlock?: string | null;
|
|
14
|
+
} = {},
|
|
15
|
+
): ProviderPayloadPolicyDeps {
|
|
16
|
+
return {
|
|
17
|
+
isAutoActive: () => overrides.autoActive ?? false,
|
|
18
|
+
loadContextManagementConfig: () => overrides.context,
|
|
19
|
+
renderSourceContextBlock: () => overrides.sourceContextBlock ?? null,
|
|
20
|
+
getEffectiveServiceTier: () => undefined,
|
|
21
|
+
supportsServiceTier: () => false,
|
|
22
|
+
...overrides,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function textFromMessage(message: { content?: unknown }): string {
|
|
27
|
+
const content = message.content;
|
|
28
|
+
if (typeof content === "string") return content;
|
|
29
|
+
if (!Array.isArray(content)) return "";
|
|
30
|
+
const text = content.find((block): block is { text: string } => {
|
|
31
|
+
return Boolean(block && typeof block === "object" && "text" in block && typeof block.text === "string");
|
|
32
|
+
});
|
|
33
|
+
return text?.text ?? "";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
test("provider payload policy truncates tool results outside auto-mode without masking", () => {
|
|
37
|
+
const messageText = "m".repeat(50);
|
|
38
|
+
const responsesOutput = "r".repeat(50);
|
|
39
|
+
const payload = {
|
|
40
|
+
messages: [
|
|
41
|
+
{ role: "user", content: [{ type: "text", text: "keep me" }] },
|
|
42
|
+
{ role: "toolResult", content: [{ type: "text", text: messageText }] },
|
|
43
|
+
],
|
|
44
|
+
input: [
|
|
45
|
+
{ role: "user", content: [{ type: "input_text", text: "keep me" }] },
|
|
46
|
+
{ type: "function_call_output", call_id: "call_test", output: responsesOutput },
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
applyProviderPayloadPolicy({
|
|
51
|
+
payload,
|
|
52
|
+
deps: createDeps({ context: { observation_mask_turns: 1, tool_result_max_chars: 10 } }),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const truncatedMessage = textFromMessage(payload.messages[1]);
|
|
56
|
+
const truncatedResponsesOutput = String(payload.input[1]?.output ?? "");
|
|
57
|
+
assert.match(truncatedMessage, /\[truncated\]/);
|
|
58
|
+
assert.match(truncatedResponsesOutput, /\[truncated\]/);
|
|
59
|
+
assert.doesNotMatch(truncatedMessage, /result masked/);
|
|
60
|
+
assert.doesNotMatch(truncatedResponsesOutput, /result masked/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("provider payload policy appends source context after masking and truncation", () => {
|
|
64
|
+
const sourceContextBlock = "## Source Context Block\n\n" + "full source text ".repeat(20);
|
|
65
|
+
const payload = {
|
|
66
|
+
messages: [
|
|
67
|
+
{ role: "user", content: [{ type: "text", text: "old turn" }] },
|
|
68
|
+
{ role: "toolResult", content: [{ type: "text", text: "old result ".repeat(20) }] },
|
|
69
|
+
{ role: "assistant", content: [{ type: "text", text: "ok" }] },
|
|
70
|
+
{ role: "user", content: [{ type: "text", text: "new turn" }] },
|
|
71
|
+
{ role: "toolResult", content: [{ type: "text", text: "new result ".repeat(20) }] },
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
applyProviderPayloadPolicy({
|
|
76
|
+
payload,
|
|
77
|
+
deps: createDeps({
|
|
78
|
+
autoActive: true,
|
|
79
|
+
context: { observation_mask_turns: 1, tool_result_max_chars: 80 },
|
|
80
|
+
sourceContextBlock,
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const oldResult = textFromMessage(payload.messages[1]);
|
|
85
|
+
const newResult = textFromMessage(payload.messages[4]);
|
|
86
|
+
const appendedContext = textFromMessage(payload.messages[payload.messages.length - 1]);
|
|
87
|
+
|
|
88
|
+
assert.match(oldResult, /result masked/);
|
|
89
|
+
assert.match(newResult, /\[truncated\]/);
|
|
90
|
+
assert.equal(appendedContext, sourceContextBlock);
|
|
91
|
+
assert.doesNotMatch(appendedContext, /\[truncated\]/);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("provider payload policy applies ordering to Responses input payloads", () => {
|
|
95
|
+
const sourceContextBlock = "## Source Context Block\n\n" + "responses source text ".repeat(20);
|
|
96
|
+
const payload = {
|
|
97
|
+
input: [
|
|
98
|
+
{ role: "user", content: [{ type: "input_text", text: "old turn" }] },
|
|
99
|
+
{ type: "function_call_output", call_id: "call_old", output: "old result ".repeat(20) },
|
|
100
|
+
{ type: "message", role: "assistant", content: [{ type: "output_text", text: "ok" }] },
|
|
101
|
+
{ role: "user", content: [{ type: "input_text", text: "new turn" }] },
|
|
102
|
+
{ type: "function_call_output", call_id: "call_new", output: "new result ".repeat(20) },
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
applyProviderPayloadPolicy({
|
|
107
|
+
payload,
|
|
108
|
+
deps: createDeps({
|
|
109
|
+
autoActive: true,
|
|
110
|
+
context: { observation_mask_turns: 1, tool_result_max_chars: 80 },
|
|
111
|
+
sourceContextBlock,
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
assert.match(String(payload.input[1]?.output ?? ""), /result masked/);
|
|
116
|
+
assert.match(String(payload.input[4]?.output ?? ""), /\[truncated\]/);
|
|
117
|
+
assert.equal(textFromMessage(payload.input[payload.input.length - 1]), sourceContextBlock);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("provider payload policy replaces existing source context blocks", () => {
|
|
121
|
+
const payload = {
|
|
122
|
+
messages: [
|
|
123
|
+
{ role: "user", content: [{ type: "text", text: "keep me" }] },
|
|
124
|
+
{ role: "user", content: [{ type: "text", text: "## Source Context Block\n\nstale" }] },
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
applyProviderPayloadPolicy({
|
|
129
|
+
payload,
|
|
130
|
+
deps: createDeps({
|
|
131
|
+
autoActive: true,
|
|
132
|
+
sourceContextBlock: "## Source Context Block\n\nfresh",
|
|
133
|
+
}),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const sourceMessages = payload.messages.filter((message) => {
|
|
137
|
+
return textFromMessage(message).startsWith("## Source Context Block");
|
|
138
|
+
});
|
|
139
|
+
assert.equal(sourceMessages.length, 1);
|
|
140
|
+
assert.equal(textFromMessage(sourceMessages[0]), "## Source Context Block\n\nfresh");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("provider payload policy sets service tier only for supported models", () => {
|
|
144
|
+
const unsupported = {};
|
|
145
|
+
applyProviderPayloadPolicy({
|
|
146
|
+
payload: unsupported,
|
|
147
|
+
modelId: "claude-opus-4-6",
|
|
148
|
+
deps: createDeps({
|
|
149
|
+
getEffectiveServiceTier: () => "priority",
|
|
150
|
+
supportsServiceTier: (modelId) => modelId === "gpt-5.4",
|
|
151
|
+
}),
|
|
152
|
+
});
|
|
153
|
+
assert.equal("service_tier" in unsupported, false);
|
|
154
|
+
|
|
155
|
+
const supported: Record<string, unknown> = {};
|
|
156
|
+
applyProviderPayloadPolicy({
|
|
157
|
+
payload: supported,
|
|
158
|
+
modelId: "gpt-5.4",
|
|
159
|
+
deps: createDeps({
|
|
160
|
+
getEffectiveServiceTier: () => "priority",
|
|
161
|
+
supportsServiceTier: (modelId) => modelId === "gpt-5.4",
|
|
162
|
+
}),
|
|
163
|
+
});
|
|
164
|
+
assert.equal(supported.service_tier, "priority");
|
|
165
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Tests for process-level pull request policy.
|
|
3
|
+
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
buildPullRequestEvidence,
|
|
9
|
+
createDraftPullRequestFromEvidence,
|
|
10
|
+
} from "../pull-request-process.js";
|
|
11
|
+
|
|
12
|
+
test("buildPullRequestEvidence omits AI credit by policy", () => {
|
|
13
|
+
const evidence = buildPullRequestEvidence({
|
|
14
|
+
milestoneId: "M001",
|
|
15
|
+
milestoneTitle: "Git process",
|
|
16
|
+
aiAssisted: true,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
assert.equal(evidence.title, "feat: Git process");
|
|
20
|
+
assert.ok(!evidence.body.includes("## AI Assistance Disclosure"));
|
|
21
|
+
assert.ok(!evidence.body.includes("AI assistance"));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("createDraftPullRequestFromEvidence forwards exact evidence and branch options", () => {
|
|
25
|
+
const calls: unknown[][] = [];
|
|
26
|
+
const url = createDraftPullRequestFromEvidence(
|
|
27
|
+
"/repo",
|
|
28
|
+
"M001",
|
|
29
|
+
{ title: "feat: Git process", body: "body" },
|
|
30
|
+
{ head: "milestone/M001", base: "main" },
|
|
31
|
+
{
|
|
32
|
+
createDraftPR: (basePath, milestoneId, title, body, opts) => {
|
|
33
|
+
calls.push([basePath, milestoneId, title, body, opts]);
|
|
34
|
+
return "https://github.example/pr/1";
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
assert.equal(url, "https://github.example/pr/1");
|
|
40
|
+
assert.deepEqual(calls, [[
|
|
41
|
+
"/repo",
|
|
42
|
+
"M001",
|
|
43
|
+
"feat: Git process",
|
|
44
|
+
"body",
|
|
45
|
+
{ head: "milestone/M001", base: "main" },
|
|
46
|
+
]]);
|
|
47
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// GSD — recovery-classification: illegal-transition kind (ADR-030)
|
|
2
|
+
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
|
|
6
|
+
import { classifyFailure } from "../recovery-classification.ts";
|
|
7
|
+
import { IllegalPhaseTransitionError } from "../state-transition-matrix.ts";
|
|
8
|
+
|
|
9
|
+
test("classifyFailure recognizes IllegalPhaseTransitionError by class and escalates", () => {
|
|
10
|
+
const classification = classifyFailure({
|
|
11
|
+
error: new IllegalPhaseTransitionError("executing", "complete"),
|
|
12
|
+
unitType: "execute-task",
|
|
13
|
+
unitId: "T-1",
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
assert.equal(classification.failureKind, "illegal-transition");
|
|
17
|
+
assert.equal(classification.action, "escalate");
|
|
18
|
+
assert.equal(classification.exitReason, "illegal-transition");
|
|
19
|
+
assert.match(classification.reason, /Illegal phase transition/);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("classifyFailure routes an explicit illegal-transition failureKind to the same case", () => {
|
|
23
|
+
const classification = classifyFailure({
|
|
24
|
+
error: new Error("derived edge rejected"),
|
|
25
|
+
failureKind: "illegal-transition",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
assert.equal(classification.failureKind, "illegal-transition");
|
|
29
|
+
assert.equal(classification.action, "escalate");
|
|
30
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import test from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
|
|
@@ -13,11 +13,18 @@ import { closeDatabase, getMilestone } from "../gsd-db.ts";
|
|
|
13
13
|
import { deriveState, invalidateStateCache } from "../state.ts";
|
|
14
14
|
import {
|
|
15
15
|
getPendingGate,
|
|
16
|
+
loadWriteGateSnapshot,
|
|
16
17
|
resetWriteGateState,
|
|
18
|
+
setPendingGate,
|
|
17
19
|
shouldBlockContextArtifactSave,
|
|
18
20
|
} from "../bootstrap/write-gate.ts";
|
|
19
21
|
import { classifyCommand } from "../safety/destructive-guard.ts";
|
|
20
22
|
import { toRoundResultResponse } from "../../remote-questions/manager.ts";
|
|
23
|
+
import {
|
|
24
|
+
markInteractiveElicitationStart,
|
|
25
|
+
markInteractiveElicitationEnd,
|
|
26
|
+
clearInFlightTools,
|
|
27
|
+
} from "../auto-tool-tracking.ts";
|
|
21
28
|
|
|
22
29
|
function makeTempDir(prefix: string): string {
|
|
23
30
|
const dir = join(
|
|
@@ -708,3 +715,180 @@ test("register-hooks gates MCP ask_user_questions cancellation before requiremen
|
|
|
708
715
|
assert.equal(requirementBlock?.block, true, "requirement save must be blocked while gate is pending");
|
|
709
716
|
assert.match(requirementBlock?.reason ?? "", /has not been confirmed/);
|
|
710
717
|
});
|
|
718
|
+
|
|
719
|
+
// ─── Foreground self-cancel regression (#cc-elicitation-self-cancel) ───
|
|
720
|
+
// Product-visible symptom: under claude-code-cli + gsd-MCP, ask_user_questions
|
|
721
|
+
// is routed as an SDK elicitation (the human boundary). The message_update hook
|
|
722
|
+
// would arm the approval-gate pause and emit the "waiting for your approval -
|
|
723
|
+
// pausing" notice, tearing down that elicitation and looping a re-ask. The fix
|
|
724
|
+
// makes message_update bail while an interactive elicitation is in flight, while
|
|
725
|
+
// still pausing for prose-only approvals (native-TUI provider, where the marker
|
|
726
|
+
// is always false). This drives the real registered hook end-to-end.
|
|
727
|
+
test("register-hooks message_update does NOT pause while an interactive elicitation is the human boundary, but still pauses otherwise", async (t) => {
|
|
728
|
+
const dir = makeTempDir("elicitation-pause-guard");
|
|
729
|
+
const originalCwd = process.cwd();
|
|
730
|
+
process.chdir(dir);
|
|
731
|
+
resetWriteGateState(dir);
|
|
732
|
+
clearPendingAutoStart(dir);
|
|
733
|
+
clearInFlightTools();
|
|
734
|
+
|
|
735
|
+
t.after(() => {
|
|
736
|
+
try {
|
|
737
|
+
resetWriteGateState(dir);
|
|
738
|
+
clearPendingAutoStart(dir);
|
|
739
|
+
clearInFlightTools();
|
|
740
|
+
} finally {
|
|
741
|
+
process.chdir(originalCwd);
|
|
742
|
+
rmSync(dir, { recursive: true, force: true });
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
|
|
747
|
+
const pi = {
|
|
748
|
+
on(event: string, handler: (event: any, ctx?: any) => Promise<any> | any) {
|
|
749
|
+
const existing = handlers.get(event) ?? [];
|
|
750
|
+
existing.push(handler);
|
|
751
|
+
handlers.set(event, existing);
|
|
752
|
+
},
|
|
753
|
+
} as any;
|
|
754
|
+
|
|
755
|
+
const notices: Array<{ text: string; level: string }> = [];
|
|
756
|
+
const ctx = {
|
|
757
|
+
cwd: dir,
|
|
758
|
+
ui: { notify: (text: string, level: string) => notices.push({ text, level }) },
|
|
759
|
+
} as any;
|
|
760
|
+
|
|
761
|
+
registerHooks(pi, []);
|
|
762
|
+
|
|
763
|
+
// A discuss-milestone is the active unit, so the approval text would normally
|
|
764
|
+
// arm the pause/notice path.
|
|
765
|
+
setPendingAutoStart(dir, {
|
|
766
|
+
basePath: dir,
|
|
767
|
+
milestoneId: "M001",
|
|
768
|
+
ctx,
|
|
769
|
+
pi: { sendMessage: () => undefined } as any,
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
// The model's plain-text approval question — identical in both phases.
|
|
773
|
+
const approvalMessage = {
|
|
774
|
+
role: "assistant",
|
|
775
|
+
content: [
|
|
776
|
+
{ type: "text", text: "Here is the milestone plan.\n\nDid I capture the project correctly?" },
|
|
777
|
+
],
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
const fireMessageUpdate = async () => {
|
|
781
|
+
for (const handler of handlers.get("message_update") ?? []) {
|
|
782
|
+
await handler({ message: approvalMessage }, ctx);
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
// Phase 1 — FIX: an interactive elicitation is in flight (claude-code-cli
|
|
787
|
+
// foreground). The pause/notice MUST be suppressed.
|
|
788
|
+
markInteractiveElicitationStart();
|
|
789
|
+
await fireMessageUpdate();
|
|
790
|
+
assert.equal(
|
|
791
|
+
notices.some((n) => /waiting for your approval - pausing/.test(n.text)),
|
|
792
|
+
false,
|
|
793
|
+
"must NOT emit the approval-pause notice while the elicitation is the human boundary",
|
|
794
|
+
);
|
|
795
|
+
markInteractiveElicitationEnd();
|
|
796
|
+
|
|
797
|
+
// Phase 2 — control: no elicitation in flight (native-TUI provider or a
|
|
798
|
+
// prose-only approval). The same message MUST still pause.
|
|
799
|
+
notices.length = 0;
|
|
800
|
+
await fireMessageUpdate();
|
|
801
|
+
assert.equal(
|
|
802
|
+
notices.some((n) => /discuss-milestone M001 is waiting for your approval - pausing/.test(n.text)),
|
|
803
|
+
true,
|
|
804
|
+
"prose-only approval with no elicitation in flight must still arm the pause notice",
|
|
805
|
+
);
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
test("register-hooks agent_end does not re-arm deferred gate after workflow MCP verified write-gate on disk", async (t) => {
|
|
809
|
+
const dir = makeTempDir("mcp-disk-sync");
|
|
810
|
+
const originalCwd = process.cwd();
|
|
811
|
+
const originalEnv = process.env.GSD_PERSIST_WRITE_GATE_STATE;
|
|
812
|
+
process.chdir(dir);
|
|
813
|
+
resetWriteGateState(dir);
|
|
814
|
+
clearPendingAutoStart(dir);
|
|
815
|
+
process.env.GSD_PERSIST_WRITE_GATE_STATE = "1";
|
|
816
|
+
|
|
817
|
+
const gateId = "depth_verification_M005_confirm";
|
|
818
|
+
const statePath = join(dir, ".gsd", "runtime", "write-gate-state.json");
|
|
819
|
+
|
|
820
|
+
t.after(() => {
|
|
821
|
+
try {
|
|
822
|
+
resetWriteGateState(dir);
|
|
823
|
+
clearPendingAutoStart(dir);
|
|
824
|
+
} finally {
|
|
825
|
+
if (originalEnv === undefined) {
|
|
826
|
+
delete process.env.GSD_PERSIST_WRITE_GATE_STATE;
|
|
827
|
+
} else {
|
|
828
|
+
process.env.GSD_PERSIST_WRITE_GATE_STATE = originalEnv;
|
|
829
|
+
}
|
|
830
|
+
process.chdir(originalCwd);
|
|
831
|
+
rmSync(dir, { recursive: true, force: true });
|
|
832
|
+
}
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
|
|
836
|
+
const pi = {
|
|
837
|
+
on(event: string, handler: (event: any, ctx?: any) => Promise<any> | any) {
|
|
838
|
+
const existing = handlers.get(event) ?? [];
|
|
839
|
+
existing.push(handler);
|
|
840
|
+
handlers.set(event, existing);
|
|
841
|
+
},
|
|
842
|
+
} as any;
|
|
843
|
+
|
|
844
|
+
const ctx = {
|
|
845
|
+
cwd: dir,
|
|
846
|
+
ui: { notify: () => undefined },
|
|
847
|
+
} as any;
|
|
848
|
+
|
|
849
|
+
registerHooks(pi, []);
|
|
850
|
+
|
|
851
|
+
setPendingAutoStart(dir, {
|
|
852
|
+
basePath: dir,
|
|
853
|
+
milestoneId: "M005",
|
|
854
|
+
ctx,
|
|
855
|
+
pi: { sendMessage: () => undefined } as any,
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
const approvalMessage = {
|
|
859
|
+
role: "assistant",
|
|
860
|
+
content: [
|
|
861
|
+
{ type: "text", text: "Did I capture the depth right?" },
|
|
862
|
+
],
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
for (const handler of handlers.get("message_update") ?? []) {
|
|
866
|
+
await handler({ message: approvalMessage }, ctx);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
setPendingGate(gateId, dir);
|
|
870
|
+
mkdirSync(join(dir, ".gsd", "runtime"), { recursive: true });
|
|
871
|
+
writeFileSync(statePath, JSON.stringify({
|
|
872
|
+
verifiedDepthMilestones: ["M005"],
|
|
873
|
+
verifiedApprovalGates: [gateId],
|
|
874
|
+
activeQueuePhase: false,
|
|
875
|
+
pendingGateId: null,
|
|
876
|
+
}, null, 2), "utf-8");
|
|
877
|
+
|
|
878
|
+
for (const handler of handlers.get("agent_end") ?? []) {
|
|
879
|
+
await handler({ messages: [] }, ctx);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
assert.equal(getPendingGate(dir), null, "agent_end must not re-arm a gate the MCP subprocess already verified");
|
|
883
|
+
assert.equal(
|
|
884
|
+
shouldBlockContextArtifactSave("CONTEXT", "M005", null, dir).block,
|
|
885
|
+
false,
|
|
886
|
+
"verified milestone context writes must stay unlocked after agent_end",
|
|
887
|
+
);
|
|
888
|
+
assert.deepEqual(loadWriteGateSnapshot(dir), {
|
|
889
|
+
verifiedDepthMilestones: ["M005"],
|
|
890
|
+
verifiedApprovalGates: [gateId],
|
|
891
|
+
activeQueuePhase: false,
|
|
892
|
+
pendingGateId: null,
|
|
893
|
+
});
|
|
894
|
+
});
|
|
@@ -396,4 +396,44 @@ test('T. #1736: Checkbox format unchanged', () => {
|
|
|
396
396
|
assert.deepStrictEqual(slices[1].done, false, '#1736 checkbox compat: S02 not done');
|
|
397
397
|
});
|
|
398
398
|
|
|
399
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
400
|
+
// U. Regression #566: double-bracket depends serialization recovery
|
|
401
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
402
|
+
test('U. #566: double-bracket depends:[[S01]] recovers to ["S01"]', () => {
|
|
403
|
+
// Simulates a roadmap written by markdown-renderer when the DB had
|
|
404
|
+
// depends=["[S01]"] — produces `depends:[[S01]]` on disk.
|
|
405
|
+
const content = [
|
|
406
|
+
'# M020: Corrupted Depends',
|
|
407
|
+
'',
|
|
408
|
+
'## Slices',
|
|
409
|
+
'',
|
|
410
|
+
'- [ ] **S01: Foundation** `risk:low` `depends:[]`',
|
|
411
|
+
'- [ ] **S02: Build** `risk:medium` `depends:[[S01]]`',
|
|
412
|
+
'- [ ] **S03: Ship** `risk:high` `depends:[[S01, S02]]`',
|
|
413
|
+
'',
|
|
414
|
+
].join('\n');
|
|
415
|
+
|
|
416
|
+
const slices = parseRoadmapSlices(content);
|
|
417
|
+
assert.deepStrictEqual(slices.length, 3, '#566 double-bracket: 3 slices');
|
|
418
|
+
assert.deepStrictEqual(slices[1].depends, ['S01'], '#566: S02 depends recovered to ["S01"]');
|
|
419
|
+
assert.deepStrictEqual(slices[2].depends, ['S01', 'S02'], '#566: S03 depends recovered to ["S01","S02"]');
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test('U. #566: bracket-wrapped single element depends:[[S01]] recovers to ["S01"]', () => {
|
|
423
|
+
// Simulates the exact DB corruption seen in the forensic evidence: depends=["[S01]"]
|
|
424
|
+
const content = [
|
|
425
|
+
'# M020: Single Bracket Corruption',
|
|
426
|
+
'',
|
|
427
|
+
'## Slices',
|
|
428
|
+
'',
|
|
429
|
+
'- [ ] **S01: First** `risk:low` `depends:[]`',
|
|
430
|
+
'- [ ] **S02: Second** `risk:medium` `depends:[[S01]]`',
|
|
431
|
+
'',
|
|
432
|
+
].join('\n');
|
|
433
|
+
|
|
434
|
+
const slices = parseRoadmapSlices(content);
|
|
435
|
+
assert.deepStrictEqual(slices[1].depends.length, 1, '#566 single: S02 has exactly 1 dep');
|
|
436
|
+
assert.deepStrictEqual(slices[1].depends[0], 'S01', '#566 single: dep is "S01" not "[S01]"');
|
|
437
|
+
});
|
|
438
|
+
|
|
399
439
|
});
|
|
@@ -6,7 +6,7 @@ import assert from "node:assert/strict";
|
|
|
6
6
|
|
|
7
7
|
import { classifyFailure } from "../recovery-classification.js";
|
|
8
8
|
import { reconcileBeforeDispatch } from "../state-reconciliation.js";
|
|
9
|
-
import { compileUnitToolContract } from "../tool-contract.js";
|
|
9
|
+
import { compileUnitContextContract, compileUnitToolContract } from "../tool-contract.js";
|
|
10
10
|
import { shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
|
|
11
11
|
import type { GSDState } from "../types.js";
|
|
12
12
|
|
|
@@ -68,6 +68,16 @@ test("Tool Contract compiles known Unit prompt and tool policy", () => {
|
|
|
68
68
|
assert.equal(result.ok && result.contract.toolsPolicy.mode, "all");
|
|
69
69
|
assert.ok(result.ok && result.contract.validationRules.includes("closeout-tool-present"));
|
|
70
70
|
assert.ok(result.ok && result.contract.validationRules.includes("source-observation-contract-present"));
|
|
71
|
+
assert.deepEqual(result.ok && result.contract.promptContext.artifacts.inline, [
|
|
72
|
+
"task-plan",
|
|
73
|
+
"slice-plan",
|
|
74
|
+
"prior-task-summaries",
|
|
75
|
+
"templates",
|
|
76
|
+
]);
|
|
77
|
+
assert.deepEqual(result.ok && result.contract.promptContext.artifacts.onDemand, ["slice-research"]);
|
|
78
|
+
assert.ok(result.ok && result.contract.promptObligations.includes("context-inline:task-plan,slice-plan,prior-task-summaries,templates"));
|
|
79
|
+
assert.ok(result.ok && result.contract.promptObligations.includes("context-on-demand:slice-research"));
|
|
80
|
+
assert.ok(result.ok && result.contract.promptObligations.includes("source-observations:whole-file-active-unit"));
|
|
71
81
|
assert.deepEqual(result.ok && result.contract.sourceObservations, {
|
|
72
82
|
mode: "whole-file-active-unit",
|
|
73
83
|
seedFields: ["task.files", "task.inputs"],
|
|
@@ -77,6 +87,20 @@ test("Tool Contract compiles known Unit prompt and tool policy", () => {
|
|
|
77
87
|
});
|
|
78
88
|
});
|
|
79
89
|
|
|
90
|
+
test("Unit Context Contract exposes prompt context without workflow tool surface", () => {
|
|
91
|
+
const result = compileUnitContextContract("execute-task");
|
|
92
|
+
|
|
93
|
+
assert.equal(result.ok, true);
|
|
94
|
+
assert.equal(result.ok && result.contract.unitType, "execute-task");
|
|
95
|
+
assert.equal(result.ok && result.contract.contextMode, "execution");
|
|
96
|
+
assert.equal(result.ok && result.contract.toolsPolicy.mode, "all");
|
|
97
|
+
assert.deepEqual(result.ok && result.contract.artifacts.excerpt, []);
|
|
98
|
+
assert.deepEqual(result.ok && result.contract.artifacts.computed, []);
|
|
99
|
+
assert.deepEqual(result.ok && result.contract.artifacts.prepend, []);
|
|
100
|
+
assert.equal(result.ok && result.contract.maxSystemPromptChars, 1_500_000);
|
|
101
|
+
assert.equal(result.ok && result.contract.sourceObservations.mode, "whole-file-active-unit");
|
|
102
|
+
});
|
|
103
|
+
|
|
80
104
|
test("Tool Contract records high-risk cross-phase tool boundaries without single-owning every tool", () => {
|
|
81
105
|
const completeSlice = compileUnitToolContract("complete-slice");
|
|
82
106
|
const runUat = compileUnitToolContract("run-uat");
|
|
@@ -266,3 +266,41 @@ test("safety-harness: planned changed file avoids unexpected-file warning", (t)
|
|
|
266
266
|
assert.deepEqual(audit!.unexpectedFiles, [], "planned index.html must not be unexpected");
|
|
267
267
|
assert.deepEqual(audit!.missingFiles, [], "planned index.html must not be missing");
|
|
268
268
|
});
|
|
269
|
+
|
|
270
|
+
// ─── External engine evidence (claude-code-cli pre-executed tools) ──────────
|
|
271
|
+
// External engines skip beforeToolCall/tool_call, so register-hooks.ts records
|
|
272
|
+
// evidence at tool_execution_start instead. These tests lock the collector
|
|
273
|
+
// semantics that wiring relies on: idempotent recording by toolCallId, and
|
|
274
|
+
// capitalized external tool names (Bash/Write/Edit) being recognized.
|
|
275
|
+
|
|
276
|
+
test("safety-harness: recordToolCall is idempotent by toolCallId", () => {
|
|
277
|
+
resetEvidence();
|
|
278
|
+
|
|
279
|
+
// Native tools fire tool_execution_start AND tool_call — both record.
|
|
280
|
+
recordToolCall("tc-dup-1", "bash", { command: "npm test" });
|
|
281
|
+
recordToolCall("tc-dup-1", "bash", { command: "npm test" });
|
|
282
|
+
|
|
283
|
+
assert.equal(getEvidence().length, 1, "same toolCallId must not duplicate");
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test("safety-harness: external capitalized Bash call records and resolves evidence", () => {
|
|
287
|
+
resetEvidence();
|
|
288
|
+
|
|
289
|
+
// tool_execution_start with Claude Code's native tool name
|
|
290
|
+
recordToolCall("ext-bash-1", "Bash", { command: "node /tmp/t01-verify.mjs" });
|
|
291
|
+
const entries = getEvidence().filter((e): e is BashEvidence => e.kind === "bash");
|
|
292
|
+
assert.equal(entries.length, 1, "capitalized Bash must be recognized as execution tool");
|
|
293
|
+
assert.equal(entries[0]!.command, "node /tmp/t01-verify.mjs");
|
|
294
|
+
|
|
295
|
+
// tool_execution_end fills the result
|
|
296
|
+
recordToolResult("ext-bash-1", "Bash", { content: [{ type: "text", text: "13 checks passed" }] }, false);
|
|
297
|
+
assert.equal(entries[0]!.exitCode, 0, "non-error external result resolves to exitCode 0");
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test("safety-harness: external Write call records file evidence", () => {
|
|
301
|
+
resetEvidence();
|
|
302
|
+
|
|
303
|
+
recordToolCall("ext-write-1", "Write", { file_path: "/tmp/app/index.html" });
|
|
304
|
+
const writes = getEvidence().filter((e) => e.kind === "write");
|
|
305
|
+
assert.equal(writes.length, 1, "capitalized Write must record file evidence");
|
|
306
|
+
});
|