gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.3a3c6509d
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/README.md +3 -3
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +7 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +5 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +11 -0
- package/dist/resources/extensions/gsd/auto/phases.js +81 -31
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +71 -10
- package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
- package/dist/resources/extensions/gsd/auto-start.js +87 -14
- package/dist/resources/extensions/gsd/auto-verification.js +17 -4
- package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
- package/dist/resources/extensions/gsd/auto.js +37 -5
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -9
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -2
- package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
- package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/forensics.js +3 -3
- package/dist/resources/extensions/gsd/git-service.js +45 -3
- package/dist/resources/extensions/gsd/gsd-db.js +21 -6
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +101 -116
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
- package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/state.js +1 -1
- package/dist/resources/extensions/gsd/status-guards.js +11 -0
- package/dist/resources/extensions/gsd/templates/plan.md +8 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
- package/dist/resources/extensions/gsd/unit-context-manifest.js +7 -8
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
- package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
- package/dist/resources/extensions/visual-brief/prompts.js +29 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- 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/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- 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 +4 -5
- 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 +2 -5
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- 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 +4 -7
- 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 +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +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/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +44 -3
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -8
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +53 -3
- package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +14 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +23 -8
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
- package/packages/pi-tui/dist/terminal.d.ts +2 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +12 -0
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +7 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +8 -5
- package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
- package/src/resources/extensions/gsd/auto/phases.ts +90 -38
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -19
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +78 -8
- package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
- package/src/resources/extensions/gsd/auto-start.ts +94 -12
- package/src/resources/extensions/gsd/auto-verification.ts +22 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
- package/src/resources/extensions/gsd/auto.ts +40 -5
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -9
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +17 -2
- package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
- package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
- package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +1 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/forensics.ts +3 -3
- package/src/resources/extensions/gsd/git-service.ts +51 -4
- package/src/resources/extensions/gsd/gsd-db.ts +21 -6
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +134 -133
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/state.ts +1 -1
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/templates/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +35 -7
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +91 -6
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +86 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +82 -7
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +38 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
- package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
- package/src/resources/extensions/visual-brief/prompts.ts +37 -1
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_ssgManifest.js +0 -0
|
@@ -375,7 +375,7 @@ test("workflow MCP launch config reaches mutation tools over stdio", async () =>
|
|
|
375
375
|
estimate: "10m",
|
|
376
376
|
files: ["src/resources/extensions/gsd/workflow-mcp.ts"],
|
|
377
377
|
verify: "node --test",
|
|
378
|
-
inputs: ["M001-ROADMAP.md"],
|
|
378
|
+
inputs: [".gsd/milestones/M001/M001-ROADMAP.md"],
|
|
379
379
|
expectedOutput: ["S01-PLAN.md", "T01-PLAN.md"],
|
|
380
380
|
},
|
|
381
381
|
],
|
|
@@ -746,3 +746,21 @@ test("transport compatibility still blocks units whose MCP tools are not exposed
|
|
|
746
746
|
assert.match(error ?? "", /requires secure_env_collect/);
|
|
747
747
|
assert.match(error ?? "", /currently exposes only/);
|
|
748
748
|
});
|
|
749
|
+
|
|
750
|
+
test("transport compatibility accepts MCP-namespaced runtime tools", () => {
|
|
751
|
+
const error = getWorkflowTransportSupportError(
|
|
752
|
+
"claude-code",
|
|
753
|
+
["gsd_summary_save"],
|
|
754
|
+
{
|
|
755
|
+
projectRoot: "/tmp/project",
|
|
756
|
+
env: { GSD_WORKFLOW_MCP_COMMAND: "node" },
|
|
757
|
+
surface: "auto-mode",
|
|
758
|
+
unitType: "research-slice",
|
|
759
|
+
authMode: "externalCli",
|
|
760
|
+
baseUrl: "local://claude-code",
|
|
761
|
+
activeTools: ["mcp__gsd-workflow__gsd_summary_save"],
|
|
762
|
+
},
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
assert.equal(error, null);
|
|
766
|
+
});
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
5
|
import test from "node:test";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
measureMemoryPressure,
|
|
9
|
+
shouldCheckMemoryPressure,
|
|
10
|
+
} from "../auto/workflow-memory-pressure.ts";
|
|
8
11
|
|
|
9
12
|
const mb = 1024 * 1024;
|
|
10
13
|
|
|
@@ -69,3 +72,20 @@ test("measureMemoryPressure falls back when heap limit cannot be read", () => {
|
|
|
69
72
|
pct: 0.25,
|
|
70
73
|
});
|
|
71
74
|
});
|
|
75
|
+
|
|
76
|
+
test("shouldCheckMemoryPressure covers the first auto-mode iteration", () => {
|
|
77
|
+
assert.equal(shouldCheckMemoryPressure(1, 5), true);
|
|
78
|
+
assert.equal(shouldCheckMemoryPressure(2, 5), false);
|
|
79
|
+
assert.equal(shouldCheckMemoryPressure(5, 5), true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("shouldCheckMemoryPressure rejects invalid intervals", () => {
|
|
83
|
+
assert.throws(
|
|
84
|
+
() => shouldCheckMemoryPressure(1, 0),
|
|
85
|
+
/positive integer/,
|
|
86
|
+
);
|
|
87
|
+
assert.throws(
|
|
88
|
+
() => shouldCheckMemoryPressure(1, 1.5),
|
|
89
|
+
/positive integer/,
|
|
90
|
+
);
|
|
91
|
+
});
|
|
@@ -246,7 +246,7 @@ test("executePlanSlice writes task planning state and rendered plan artifacts",
|
|
|
246
246
|
estimate: "15m",
|
|
247
247
|
files: ["src/resources/extensions/gsd/tools/workflow-tool-executors.ts"],
|
|
248
248
|
verify: "node --test",
|
|
249
|
-
inputs: ["ROADMAP.md"],
|
|
249
|
+
inputs: [".gsd/milestones/M001/M001-ROADMAP.md"],
|
|
250
250
|
expectedOutput: ["S01-PLAN.md", "T01-PLAN.md"],
|
|
251
251
|
},
|
|
252
252
|
],
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync, realpathSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { execFileSync } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
import { _gitPathspecForWorktreePath } from "../auto-worktree.ts";
|
|
9
|
+
|
|
10
|
+
function run(cmd: string, args: string[], cwd: string): string {
|
|
11
|
+
return execFileSync(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("worktree git pathspec", () => {
|
|
15
|
+
test("skips external GSD bookkeeping directories outside the git work-tree", () => {
|
|
16
|
+
const root = realpathSync(mkdtempSync(join(tmpdir(), "gsd-pathspec-")));
|
|
17
|
+
const repo = join(root, "project");
|
|
18
|
+
const externalGsd = join(root, ".gsd", "projects", "abc123");
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
mkdirSync(repo, { recursive: true });
|
|
22
|
+
mkdirSync(join(externalGsd, "milestones", "M002-wa00fm"), { recursive: true });
|
|
23
|
+
mkdirSync(join(externalGsd, "runtime", "units"), { recursive: true });
|
|
24
|
+
run("git", ["init"], repo);
|
|
25
|
+
writeFileSync(join(repo, "README.md"), "# test\n");
|
|
26
|
+
|
|
27
|
+
assert.equal(
|
|
28
|
+
_gitPathspecForWorktreePath(repo, join(externalGsd, "milestones", "M002-wa00fm")),
|
|
29
|
+
null,
|
|
30
|
+
);
|
|
31
|
+
assert.equal(
|
|
32
|
+
_gitPathspecForWorktreePath(repo, join(externalGsd, "runtime", "units")),
|
|
33
|
+
null,
|
|
34
|
+
);
|
|
35
|
+
} finally {
|
|
36
|
+
if (existsSync(root)) rmSync(root, { recursive: true, force: true });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -30,11 +30,13 @@ function initGitRepoIn(base: string, isolation: "worktree" | "branch" | "none"):
|
|
|
30
30
|
}
|
|
31
31
|
import {
|
|
32
32
|
WorktreeLifecycle,
|
|
33
|
+
resetRecentWorktreeMergeFailuresForTest,
|
|
33
34
|
type WorktreeLifecycleDeps,
|
|
34
35
|
type NotifyCtx,
|
|
35
36
|
} from "../worktree-lifecycle.js";
|
|
36
37
|
import { WorktreeStateProjection } from "../worktree-state-projection.js";
|
|
37
38
|
import { type TaskCommitContext } from "../worktree.js";
|
|
39
|
+
import { MergeConflictError } from "../git-service.js";
|
|
38
40
|
|
|
39
41
|
// ADR-016 phase 2 / C-track retired all worktree-manager + cache + prefs
|
|
40
42
|
// fields from `WorktreeLifecycleDeps`. Tests still pass them as overrides
|
|
@@ -141,6 +143,20 @@ function readJournalEntries(basePath: string): JournalEntry[] {
|
|
|
141
143
|
}
|
|
142
144
|
}
|
|
143
145
|
|
|
146
|
+
function setupMergeWorktree(basePath: string, milestoneId: string): string {
|
|
147
|
+
initGitRepoIn(basePath, "worktree");
|
|
148
|
+
execFileSync("git", ["checkout", "-b", `milestone/${milestoneId}`], { cwd: basePath, stdio: "pipe" });
|
|
149
|
+
execFileSync("git", ["checkout", "main"], { cwd: basePath, stdio: "pipe" });
|
|
150
|
+
const wt = join(basePath, ".gsd", "worktrees", milestoneId);
|
|
151
|
+
execFileSync("git", ["worktree", "add", wt, `milestone/${milestoneId}`], { cwd: basePath, stdio: "pipe" });
|
|
152
|
+
mkdirSync(join(basePath, ".gsd", "milestones", milestoneId), { recursive: true });
|
|
153
|
+
writeFileSync(
|
|
154
|
+
join(basePath, ".gsd", "milestones", milestoneId, `${milestoneId}-ROADMAP.md`),
|
|
155
|
+
`# ${milestoneId}\n- [x] S01: Slice one\n`,
|
|
156
|
+
);
|
|
157
|
+
return wt;
|
|
158
|
+
}
|
|
159
|
+
|
|
144
160
|
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
145
161
|
|
|
146
162
|
describe("worktree journal events", () => {
|
|
@@ -148,6 +164,7 @@ describe("worktree journal events", () => {
|
|
|
148
164
|
const originalCwd = process.cwd();
|
|
149
165
|
|
|
150
166
|
beforeEach(() => {
|
|
167
|
+
resetRecentWorktreeMergeFailuresForTest();
|
|
151
168
|
// realpathSync to match what `auto-worktree.ts` returns from
|
|
152
169
|
// `resolveWorktreeProjectRoot` (macOS resolves `/var` → `/private/var`).
|
|
153
170
|
tmp = realpathSync(mkdtempSync(join(tmpdir(), "wt-journal-")));
|
|
@@ -284,17 +301,7 @@ describe("worktree journal events", () => {
|
|
|
284
301
|
});
|
|
285
302
|
|
|
286
303
|
test("mergeAndExit emits worktree-merge-failed on error", () => {
|
|
287
|
-
|
|
288
|
-
execFileSync("git", ["checkout", "-b", "milestone/M001"], { cwd: tmp, stdio: "pipe" });
|
|
289
|
-
execFileSync("git", ["checkout", "main"], { cwd: tmp, stdio: "pipe" });
|
|
290
|
-
const wt = join(tmp, ".gsd", "worktrees", "M001");
|
|
291
|
-
execFileSync("git", ["worktree", "add", wt, "milestone/M001"], { cwd: tmp, stdio: "pipe" });
|
|
292
|
-
mkdirSync(join(tmp, ".gsd", "milestones", "M001"), { recursive: true });
|
|
293
|
-
writeFileSync(
|
|
294
|
-
join(tmp, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
|
|
295
|
-
"# M001\n- [x] S01: Slice one\n",
|
|
296
|
-
);
|
|
297
|
-
|
|
304
|
+
const wt = setupMergeWorktree(tmp, "M001");
|
|
298
305
|
const s = makeSession({ basePath: wt, originalBasePath: tmp });
|
|
299
306
|
const deps = makeDeps({
|
|
300
307
|
mergeMilestoneToMain: () => { throw new Error("conflict in main"); },
|
|
@@ -318,11 +325,56 @@ describe("worktree journal events", () => {
|
|
|
318
325
|
);
|
|
319
326
|
}
|
|
320
327
|
|
|
328
|
+
new WorktreeLifecycle(s, deps).exitMilestone(
|
|
329
|
+
"M001",
|
|
330
|
+
{ merge: true },
|
|
331
|
+
makeNotifyCtx(),
|
|
332
|
+
);
|
|
333
|
+
|
|
321
334
|
const entries = readJournalEntries(tmp);
|
|
322
|
-
const
|
|
335
|
+
const failures = entries.filter(e => e.eventType === "worktree-merge-failed");
|
|
336
|
+
const failed = failures[0];
|
|
323
337
|
assert.ok(failed, "worktree-merge-failed event should be emitted");
|
|
324
338
|
assert.equal(failed!.data?.milestoneId, "M001");
|
|
325
339
|
assert.equal(failed!.data?.error, "conflict in main");
|
|
340
|
+
assert.equal(failures.length, 1, "duplicate merge failures are journaled once");
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
test("merge failure dedupe uses stable conflict category and expires", (t) => {
|
|
344
|
+
let now = 1_000_000;
|
|
345
|
+
t.mock.method(Date, "now", () => now);
|
|
346
|
+
const wt = setupMergeWorktree(tmp, "M001");
|
|
347
|
+
const s = makeSession({ basePath: wt, originalBasePath: tmp });
|
|
348
|
+
let attempt = 0;
|
|
349
|
+
const deps = makeDeps({
|
|
350
|
+
mergeMilestoneToMain: () => {
|
|
351
|
+
attempt += 1;
|
|
352
|
+
throw new MergeConflictError(
|
|
353
|
+
attempt === 1 ? ["src/a.ts"] : ["src/b.ts", "src/c.ts"],
|
|
354
|
+
"squash",
|
|
355
|
+
"milestone/M001",
|
|
356
|
+
"main",
|
|
357
|
+
);
|
|
358
|
+
},
|
|
359
|
+
});
|
|
360
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
361
|
+
|
|
362
|
+
lifecycle.exitMilestone("M001", { merge: true }, makeNotifyCtx());
|
|
363
|
+
lifecycle.exitMilestone("M001", { merge: true }, makeNotifyCtx());
|
|
364
|
+
|
|
365
|
+
let failures = readJournalEntries(tmp).filter(e => e.eventType === "worktree-merge-failed");
|
|
366
|
+
assert.equal(failures.length, 1, "variable conflict filenames should not bypass dedupe");
|
|
367
|
+
assert.match(
|
|
368
|
+
String(failures[0]!.data?.error),
|
|
369
|
+
/src\/a\.ts/,
|
|
370
|
+
"journal payload keeps the original error message",
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
now += 60_001;
|
|
374
|
+
lifecycle.exitMilestone("M001", { merge: true }, makeNotifyCtx());
|
|
375
|
+
|
|
376
|
+
failures = readJournalEntries(tmp).filter(e => e.eventType === "worktree-merge-failed");
|
|
377
|
+
assert.equal(failures.length, 2, "same merge failure is journaled again after dedupe expiry");
|
|
326
378
|
});
|
|
327
379
|
|
|
328
380
|
test("journal entries have valid flowId, seq, and ts fields", () => {
|
|
@@ -26,6 +26,7 @@ const PLANNING_DISPATCH_REVIEW: ToolsPolicy = {
|
|
|
26
26
|
};
|
|
27
27
|
const READ_ONLY: ToolsPolicy = { mode: 'read-only' };
|
|
28
28
|
const ALL: ToolsPolicy = { mode: 'all' };
|
|
29
|
+
const VERIFICATION: ToolsPolicy = { mode: 'verification' };
|
|
29
30
|
const DOCS: ToolsPolicy = {
|
|
30
31
|
mode: 'docs',
|
|
31
32
|
allowedPathGlobs: ['docs/**', 'README.md', 'README.*.md', 'CHANGELOG.md', '*.md'],
|
|
@@ -157,6 +158,13 @@ test('planning-dispatch: allows subagent dispatch (delegated recon/planner durin
|
|
|
157
158
|
assert.strictEqual(r.block, false);
|
|
158
159
|
});
|
|
159
160
|
|
|
161
|
+
test('planning-dispatch: allows markdown agent filenames after identity normalization', () => {
|
|
162
|
+
const agentClasses = extractSubagentAgentClasses({ agent: 'scout.md' });
|
|
163
|
+
assert.deepEqual(agentClasses, ['scout']);
|
|
164
|
+
const r = shouldBlockPlanningUnit('subagent', '', BASE, 'plan-slice', PLANNING_DISPATCH, agentClasses);
|
|
165
|
+
assert.strictEqual(r.block, false);
|
|
166
|
+
});
|
|
167
|
+
|
|
160
168
|
test('planning-dispatch: allows task dispatch (delegated recon/planner during slice planning)', () => {
|
|
161
169
|
const r = shouldBlockPlanningUnit('task', '', BASE, 'plan-slice', PLANNING_DISPATCH, ['planner']);
|
|
162
170
|
assert.strictEqual(r.block, false);
|
|
@@ -331,6 +339,36 @@ test('all-mode: execute-task can dispatch subagents', () => {
|
|
|
331
339
|
assert.strictEqual(r.block, false);
|
|
332
340
|
});
|
|
333
341
|
|
|
342
|
+
// ─── verification mode: bash allowed, writes still scoped ─────────────────
|
|
343
|
+
|
|
344
|
+
test('verification-mode: run-uat can run build commands', () => {
|
|
345
|
+
const r = shouldBlockPlanningUnit('bash', 'npm run build 2>&1', BASE, 'run-uat', VERIFICATION);
|
|
346
|
+
assert.strictEqual(r.block, false);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
test('verification-mode: run-uat blocks destructive bash (rm -rf)', () => {
|
|
350
|
+
const r = shouldBlockPlanningUnit('bash', 'rm -rf dist', BASE, 'run-uat', VERIFICATION);
|
|
351
|
+
assert.strictEqual(r.block, true);
|
|
352
|
+
assert.match(r.reason!, /bash is restricted to build\/test verification commands/);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test('verification-mode: run-uat allows read-only investigative bash (git status)', () => {
|
|
356
|
+
const r = shouldBlockPlanningUnit('bash', 'git status', BASE, 'run-uat', VERIFICATION);
|
|
357
|
+
assert.strictEqual(r.block, false);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
test('verification-mode: run-uat still blocks user source edits', () => {
|
|
361
|
+
const r = shouldBlockPlanningUnit('edit', join(BASE, 'src', 'main.ts'), BASE, 'run-uat', VERIFICATION);
|
|
362
|
+
assert.strictEqual(r.block, true);
|
|
363
|
+
assert.match(r.reason!, /tools-policy "verification"/);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
test('verification-mode: run-uat still blocks subagent dispatch', () => {
|
|
367
|
+
const r = shouldBlockPlanningUnit('subagent', '', BASE, 'run-uat', VERIFICATION);
|
|
368
|
+
assert.strictEqual(r.block, true);
|
|
369
|
+
assert.match(r.reason!, /subagent dispatch is not permitted/);
|
|
370
|
+
});
|
|
371
|
+
|
|
334
372
|
// ─── read-only mode ───────────────────────────────────────────────────────
|
|
335
373
|
|
|
336
374
|
test('read-only: blocks any edit even to .gsd/', () => {
|
|
@@ -38,9 +38,9 @@ export interface CompleteMilestoneParams {
|
|
|
38
38
|
definitionOfDoneResults?: string;
|
|
39
39
|
/** @optional — empty/omitted renders as "Not provided." */
|
|
40
40
|
requirementOutcomes?: string;
|
|
41
|
-
/** @optional — empty/omitted renders as
|
|
41
|
+
/** @optional — empty/omitted renders as an empty frontmatter list */
|
|
42
42
|
keyDecisions?: string[];
|
|
43
|
-
/** @optional — empty/omitted renders as
|
|
43
|
+
/** @optional — empty/omitted renders as an empty frontmatter list */
|
|
44
44
|
keyFiles?: string[];
|
|
45
45
|
/** @optional — empty/omitted renders as "(none)" */
|
|
46
46
|
lessonsLearned?: string[];
|
|
@@ -70,12 +70,12 @@ function renderMilestoneSummaryMarkdown(params: CompleteMilestoneParams, complet
|
|
|
70
70
|
const lessonsLearned = params.lessonsLearned ?? [];
|
|
71
71
|
|
|
72
72
|
const keyDecisionsYaml = keyDecisions.length > 0
|
|
73
|
-
? keyDecisions.map(d => ` - ${d}`).join("\n")
|
|
74
|
-
: "
|
|
73
|
+
? `\n${keyDecisions.map(d => ` - ${d}`).join("\n")}`
|
|
74
|
+
: " []";
|
|
75
75
|
|
|
76
76
|
const keyFilesYaml = keyFiles.length > 0
|
|
77
|
-
? keyFiles.map(f => ` - ${f}`).join("\n")
|
|
78
|
-
: "
|
|
77
|
+
? `\n${keyFiles.map(f => ` - ${f}`).join("\n")}`
|
|
78
|
+
: " []";
|
|
79
79
|
|
|
80
80
|
const lessonsYaml = lessonsLearned.length > 0
|
|
81
81
|
? lessonsLearned.map(l => ` - ${l}`).join("\n")
|
|
@@ -86,10 +86,8 @@ id: ${params.milestoneId}
|
|
|
86
86
|
title: "${displayTitle}"
|
|
87
87
|
status: complete
|
|
88
88
|
completed_at: ${completedAt}
|
|
89
|
-
key_decisions
|
|
90
|
-
|
|
91
|
-
key_files:
|
|
92
|
-
${keyFilesYaml}
|
|
89
|
+
key_decisions:${keyDecisionsYaml}
|
|
90
|
+
key_files:${keyFilesYaml}
|
|
93
91
|
lessons_learned:
|
|
94
92
|
${lessonsYaml}
|
|
95
93
|
---
|
|
@@ -104,12 +104,12 @@ function renderSliceSummaryMarkdown(params: CompleteSliceParams): string {
|
|
|
104
104
|
: " []";
|
|
105
105
|
|
|
106
106
|
const keyFilesYaml = keyFiles.length > 0
|
|
107
|
-
? keyFiles.map(f => ` - ${f}`).join("\n")
|
|
108
|
-
: "
|
|
107
|
+
? `\n${keyFiles.map(f => ` - ${f}`).join("\n")}`
|
|
108
|
+
: " []";
|
|
109
109
|
|
|
110
110
|
const keyDecisionsYaml = keyDecisions.length > 0
|
|
111
|
-
? keyDecisions.map(d => ` - ${d}`).join("\n")
|
|
112
|
-
: "
|
|
111
|
+
? `\n${keyDecisions.map(d => ` - ${d}`).join("\n")}`
|
|
112
|
+
: " []";
|
|
113
113
|
|
|
114
114
|
const patternsYaml = patternsEstablished.length > 0
|
|
115
115
|
? patternsEstablished.map(p => ` - ${p}`).join("\n")
|
|
@@ -155,10 +155,8 @@ requires:
|
|
|
155
155
|
${requiresYaml}
|
|
156
156
|
affects:
|
|
157
157
|
${affectsYaml}
|
|
158
|
-
key_files
|
|
159
|
-
|
|
160
|
-
key_decisions:
|
|
161
|
-
${keyDecisionsYaml}
|
|
158
|
+
key_files:${keyFilesYaml}
|
|
159
|
+
key_decisions:${keyDecisionsYaml}
|
|
162
160
|
patterns_established:
|
|
163
161
|
${patternsYaml}
|
|
164
162
|
observability_surfaces:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { clearParseCache } from "../files.js";
|
|
2
2
|
import { isClosedStatus } from "../status-guards.js";
|
|
3
|
-
import { isNonEmptyString, validateStringArray } from "../validation.js";
|
|
3
|
+
import { isNonEmptyString, validateStringArray, validateTitle } from "../validation.js";
|
|
4
4
|
import {
|
|
5
5
|
transaction,
|
|
6
6
|
getMilestone,
|
|
@@ -148,6 +148,8 @@ function validateSlices(value: unknown): PlanMilestoneSliceInput[] {
|
|
|
148
148
|
if (seen.has(sliceId)) throw new Error(`slices[${index}].sliceId must be unique`);
|
|
149
149
|
seen.add(sliceId);
|
|
150
150
|
if (!isNonEmptyString(title)) throw new Error(`slices[${index}].title must be a non-empty string`);
|
|
151
|
+
const titleIssue = validateTitle(title);
|
|
152
|
+
if (titleIssue) throw new Error(`slices[${index}].title is invalid: ${titleIssue}`);
|
|
151
153
|
if (!isNonEmptyString(risk)) throw new Error(`slices[${index}].risk must be a non-empty string`);
|
|
152
154
|
if (!Array.isArray(depends) || depends.some((item) => !isNonEmptyString(item))) {
|
|
153
155
|
throw new Error(`slices[${index}].depends must be an array of non-empty strings`);
|
|
@@ -190,6 +192,8 @@ function validateParams(params: PlanMilestoneParams): PlanMilestoneParams {
|
|
|
190
192
|
if (!isNonEmptyString(params?.milestoneId)) throw new Error("milestoneId is required");
|
|
191
193
|
if (!isNonEmptyString(params?.title)) throw new Error("title is required");
|
|
192
194
|
if (!isNonEmptyString(params?.vision)) throw new Error("vision is required");
|
|
195
|
+
const milestoneTitleIssue = validateTitle(params.title);
|
|
196
|
+
if (milestoneTitleIssue) throw new Error(`title is invalid: ${milestoneTitleIssue}`);
|
|
193
197
|
|
|
194
198
|
return {
|
|
195
199
|
...params,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { existsSync, rmSync } from "node:fs";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
1
3
|
import { clearParseCache } from "../files.js";
|
|
2
4
|
import { isClosedStatus, isDeferredStatus } from "../status-guards.js";
|
|
3
5
|
import { isNonEmptyString, validateStringArray } from "../validation.js";
|
|
@@ -5,11 +7,15 @@ import {
|
|
|
5
7
|
transaction,
|
|
6
8
|
getMilestone,
|
|
7
9
|
getSlice,
|
|
10
|
+
getSliceTasks,
|
|
8
11
|
insertTask,
|
|
9
12
|
upsertSlicePlanning,
|
|
10
13
|
upsertTaskPlanning,
|
|
11
14
|
insertGateRow,
|
|
12
15
|
updateSliceStatus,
|
|
16
|
+
setSliceSketchFlag,
|
|
17
|
+
deleteTask,
|
|
18
|
+
deleteArtifactByPath,
|
|
13
19
|
} from "../gsd-db.js";
|
|
14
20
|
import type { GateId } from "../types.js";
|
|
15
21
|
import { invalidateStateCache } from "../state.js";
|
|
@@ -19,6 +25,9 @@ import { writeManifest } from "../workflow-manifest.js";
|
|
|
19
25
|
import { appendEvent } from "../workflow-events.js";
|
|
20
26
|
import { logWarning } from "../workflow-logger.js";
|
|
21
27
|
import { validatePlanningPathScope } from "../planning-path-scope.js";
|
|
28
|
+
import { checkFilePathConsistency, checkTaskOrdering } from "../pre-execution-checks.js";
|
|
29
|
+
import type { TaskRow } from "../db-task-slice-rows.js";
|
|
30
|
+
import { buildTaskFileName, gsdRoot, resolveTasksDir } from "../paths.js";
|
|
22
31
|
|
|
23
32
|
export interface PlanSliceTaskInput {
|
|
24
33
|
taskId: string;
|
|
@@ -86,16 +95,10 @@ function validateTasks(value: unknown): PlanSliceTaskInput[] {
|
|
|
86
95
|
if (!isNonEmptyString(title)) throw new Error(`tasks[${index}].title must be a non-empty string`);
|
|
87
96
|
if (!isNonEmptyString(description)) throw new Error(`tasks[${index}].description must be a non-empty string`);
|
|
88
97
|
if (!isNonEmptyString(estimate)) throw new Error(`tasks[${index}].estimate must be a non-empty string`);
|
|
89
|
-
|
|
90
|
-
throw new Error(`tasks[${index}].files must be an array of non-empty strings`);
|
|
91
|
-
}
|
|
98
|
+
const validatedFiles = validateStringArray(files, `tasks[${index}].files`);
|
|
92
99
|
if (!isNonEmptyString(verify)) throw new Error(`tasks[${index}].verify must be a non-empty string`);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
if (!Array.isArray(expectedOutput) || expectedOutput.some((item) => !isNonEmptyString(item))) {
|
|
97
|
-
throw new Error(`tasks[${index}].expectedOutput must be an array of non-empty strings`);
|
|
98
|
-
}
|
|
100
|
+
const validatedInputs = validateStringArray(inputs, `tasks[${index}].inputs`);
|
|
101
|
+
const validatedExpectedOutput = validateStringArray(expectedOutput, `tasks[${index}].expectedOutput`);
|
|
99
102
|
if (observabilityImpact !== undefined && !isNonEmptyString(observabilityImpact)) {
|
|
100
103
|
throw new Error(`tasks[${index}].observabilityImpact must be a non-empty string when provided`);
|
|
101
104
|
}
|
|
@@ -105,10 +108,10 @@ function validateTasks(value: unknown): PlanSliceTaskInput[] {
|
|
|
105
108
|
title,
|
|
106
109
|
description,
|
|
107
110
|
estimate,
|
|
108
|
-
files,
|
|
111
|
+
files: validatedFiles,
|
|
109
112
|
verify,
|
|
110
|
-
inputs,
|
|
111
|
-
expectedOutput,
|
|
113
|
+
inputs: validatedInputs,
|
|
114
|
+
expectedOutput: validatedExpectedOutput,
|
|
112
115
|
observabilityImpact: typeof observabilityImpact === "string" ? observabilityImpact : "",
|
|
113
116
|
};
|
|
114
117
|
});
|
|
@@ -131,6 +134,56 @@ function validateParams(params: PlanSliceParams): PlanSliceParams {
|
|
|
131
134
|
};
|
|
132
135
|
}
|
|
133
136
|
|
|
137
|
+
function toTaskRows(params: PlanSliceParams): TaskRow[] {
|
|
138
|
+
return params.tasks.map((task, index) => ({
|
|
139
|
+
milestone_id: params.milestoneId,
|
|
140
|
+
slice_id: params.sliceId,
|
|
141
|
+
id: task.taskId,
|
|
142
|
+
title: task.title,
|
|
143
|
+
status: "pending",
|
|
144
|
+
one_liner: "",
|
|
145
|
+
narrative: "",
|
|
146
|
+
verification_result: "",
|
|
147
|
+
duration: "",
|
|
148
|
+
completed_at: null,
|
|
149
|
+
blocker_discovered: false,
|
|
150
|
+
deviations: "",
|
|
151
|
+
known_issues: "",
|
|
152
|
+
key_files: [],
|
|
153
|
+
key_decisions: [],
|
|
154
|
+
full_summary_md: "",
|
|
155
|
+
description: task.description,
|
|
156
|
+
estimate: task.estimate,
|
|
157
|
+
files: task.files,
|
|
158
|
+
verify: task.verify,
|
|
159
|
+
inputs: task.inputs,
|
|
160
|
+
expected_output: task.expectedOutput,
|
|
161
|
+
observability_impact: task.observabilityImpact ?? "",
|
|
162
|
+
full_plan_md: task.fullPlanMd ?? "",
|
|
163
|
+
sequence: index + 1,
|
|
164
|
+
blocker_source: "",
|
|
165
|
+
escalation_pending: 0,
|
|
166
|
+
escalation_awaiting_review: 0,
|
|
167
|
+
escalation_artifact_path: null,
|
|
168
|
+
escalation_override_applied_at: null,
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function validateTaskPathsBeforePersist(params: PlanSliceParams, basePath: string): string | null {
|
|
173
|
+
const taskRows = toTaskRows(params);
|
|
174
|
+
const checks = [
|
|
175
|
+
...checkFilePathConsistency(taskRows, basePath),
|
|
176
|
+
...checkTaskOrdering(taskRows, basePath),
|
|
177
|
+
];
|
|
178
|
+
const blocking = checks.filter((check) => !check.passed && check.blocking);
|
|
179
|
+
|
|
180
|
+
if (blocking.length === 0) return null;
|
|
181
|
+
|
|
182
|
+
return blocking
|
|
183
|
+
.map((check) => `[${check.category}] ${check.target}: ${check.message}`)
|
|
184
|
+
.join("\n");
|
|
185
|
+
}
|
|
186
|
+
|
|
134
187
|
export async function handlePlanSlice(
|
|
135
188
|
rawParams: PlanSliceParams,
|
|
136
189
|
basePath: string,
|
|
@@ -154,10 +207,16 @@ export async function handlePlanSlice(
|
|
|
154
207
|
return { error: `validation failed: ${pathScopeError}` };
|
|
155
208
|
}
|
|
156
209
|
|
|
210
|
+
const pathError = validateTaskPathsBeforePersist(params, basePath);
|
|
211
|
+
if (pathError) {
|
|
212
|
+
return { error: `pre-execution validation failed:\n${pathError}` };
|
|
213
|
+
}
|
|
214
|
+
|
|
157
215
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
158
216
|
// Guards must be inside the transaction so the state they check cannot
|
|
159
217
|
// change between the read and the write (#2723).
|
|
160
218
|
let guardError: string | null = null;
|
|
219
|
+
let omittedTaskIds: string[] = [];
|
|
161
220
|
|
|
162
221
|
try {
|
|
163
222
|
transaction(() => {
|
|
@@ -181,9 +240,23 @@ export async function handlePlanSlice(
|
|
|
181
240
|
return;
|
|
182
241
|
}
|
|
183
242
|
|
|
243
|
+
const newTaskIds = new Set(params.tasks.map((task) => task.taskId));
|
|
244
|
+
const existingTasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
245
|
+
omittedTaskIds = existingTasks
|
|
246
|
+
.filter((task) => !newTaskIds.has(task.id))
|
|
247
|
+
.map((task) => task.id);
|
|
248
|
+
|
|
249
|
+
for (const task of existingTasks) {
|
|
250
|
+
if (!newTaskIds.has(task.id) && isClosedStatus(task.status)) {
|
|
251
|
+
guardError = `cannot remove completed task ${task.id}`;
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
184
256
|
if (isDeferredStatus(parentSlice.status)) {
|
|
185
257
|
updateSliceStatus(params.milestoneId, params.sliceId, "pending");
|
|
186
258
|
}
|
|
259
|
+
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
187
260
|
|
|
188
261
|
upsertSlicePlanning(params.milestoneId, params.sliceId, {
|
|
189
262
|
goal: params.goal,
|
|
@@ -193,6 +266,10 @@ export async function handlePlanSlice(
|
|
|
193
266
|
observabilityImpact: params.observabilityImpact,
|
|
194
267
|
});
|
|
195
268
|
|
|
269
|
+
for (const taskId of omittedTaskIds) {
|
|
270
|
+
deleteTask(params.milestoneId, params.sliceId, taskId);
|
|
271
|
+
}
|
|
272
|
+
|
|
196
273
|
for (const task of params.tasks) {
|
|
197
274
|
insertTask({
|
|
198
275
|
id: task.taskId,
|
|
@@ -237,6 +314,15 @@ export async function handlePlanSlice(
|
|
|
237
314
|
}
|
|
238
315
|
|
|
239
316
|
try {
|
|
317
|
+
const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
|
|
318
|
+
for (const taskId of omittedTaskIds) {
|
|
319
|
+
if (!tasksDir) continue;
|
|
320
|
+
const taskPlanPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
321
|
+
if (existsSync(taskPlanPath)) rmSync(taskPlanPath, { force: true });
|
|
322
|
+
const artifactPath = relative(gsdRoot(basePath), taskPlanPath).replace(/\\/g, "/");
|
|
323
|
+
deleteArtifactByPath(artifactPath);
|
|
324
|
+
}
|
|
325
|
+
|
|
240
326
|
const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
241
327
|
invalidateStateCache();
|
|
242
328
|
clearParseCache();
|
|
@@ -106,7 +106,7 @@ export interface AuditWarning {
|
|
|
106
106
|
export interface VerificationResult {
|
|
107
107
|
passed: boolean; // true if all checks passed (or no checks discovered)
|
|
108
108
|
checks: VerificationCheck[]; // per-command results
|
|
109
|
-
discoverySource: "preference" | "task-plan" | "package-json" | "none";
|
|
109
|
+
discoverySource: "preference" | "task-plan" | "package-json" | "python-project" | "none";
|
|
110
110
|
timestamp: number; // Date.now() at gate start
|
|
111
111
|
runtimeErrors?: RuntimeError[]; // optional — populated by captureRuntimeErrors()
|
|
112
112
|
auditWarnings?: AuditWarning[]; // optional — populated by runDependencyAudit()
|
|
@@ -132,6 +132,9 @@ export type ContextModePolicy =
|
|
|
132
132
|
* the explicit `allowedPathGlobs` set; Bash safe-allowlist;
|
|
133
133
|
* no subagents. Reserved for rewrite-docs, which legitimately
|
|
134
134
|
* edits project markdown outside .gsd/.
|
|
135
|
+
* - "verification"
|
|
136
|
+
* — Read tools + Bash for verification commands, writes
|
|
137
|
+
* restricted to .gsd/**, no subagents.
|
|
135
138
|
*
|
|
136
139
|
* The allowlist for "docs" is declared per-manifest rather than hardcoded so
|
|
137
140
|
* projects with non-standard doc layouts can extend it without forking the
|
|
@@ -143,7 +146,8 @@ export type ToolsPolicy =
|
|
|
143
146
|
| { readonly mode: "read-only" }
|
|
144
147
|
| { readonly mode: "planning" }
|
|
145
148
|
| { readonly mode: "planning-dispatch"; readonly allowedSubagents: readonly string[] }
|
|
146
|
-
| { readonly mode: "docs"; readonly allowedPathGlobs: readonly string[] }
|
|
149
|
+
| { readonly mode: "docs"; readonly allowedPathGlobs: readonly string[] }
|
|
150
|
+
| { readonly mode: "verification" };
|
|
147
151
|
|
|
148
152
|
// ─── Computed-artifact registry (#4924 v2 contract) ───────────────────────
|
|
149
153
|
|
|
@@ -288,6 +292,7 @@ const COMMON_BUDGET_SMALL = 250_000; // ~65K tokens
|
|
|
288
292
|
|
|
289
293
|
const TOOLS_ALL: ToolsPolicy = { mode: "all" };
|
|
290
294
|
const TOOLS_PLANNING: ToolsPolicy = { mode: "planning" };
|
|
295
|
+
const TOOLS_VERIFICATION: ToolsPolicy = { mode: "verification" };
|
|
291
296
|
// Like TOOLS_PLANNING but permits dispatch to read-only recon/planning
|
|
292
297
|
// specialists. Runtime-enforced by write-gate.ts before the subagent tool runs.
|
|
293
298
|
const TOOLS_PLANNING_DISPATCH_RECON: ToolsPolicy = {
|
|
@@ -406,8 +411,8 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
406
411
|
contextMode: "verification",
|
|
407
412
|
// planning-dispatch: validation is a verification-fan-out unit. It reads
|
|
408
413
|
// the milestone surface and dispatches reviewer/security/tester subagents
|
|
409
|
-
// to report findings without touching user source.
|
|
410
|
-
//
|
|
414
|
+
// to report findings without touching user source. Write isolation to
|
|
415
|
+
// .gsd/ is preserved.
|
|
411
416
|
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
412
417
|
artifacts: {
|
|
413
418
|
inline: ["roadmap", "slice-summary", "slice-uat", "requirements", "decisions", "templates"],
|
|
@@ -423,11 +428,9 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
423
428
|
codebaseMap: false,
|
|
424
429
|
preferences: "active-only",
|
|
425
430
|
contextMode: "verification",
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
|
|
429
|
-
// preserved.
|
|
430
|
-
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
431
|
+
// Milestone closeout must run unrestricted shell verification commands
|
|
432
|
+
// against the final diff before recording completion.
|
|
433
|
+
tools: TOOLS_ALL,
|
|
431
434
|
artifacts: {
|
|
432
435
|
// #4780 landed slice-summary as excerpt for this unit; phase 2 of
|
|
433
436
|
// the architecture will read this manifest as the source of truth
|
|
@@ -589,7 +592,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
589
592
|
codebaseMap: false,
|
|
590
593
|
preferences: "active-only",
|
|
591
594
|
contextMode: "verification",
|
|
592
|
-
tools:
|
|
595
|
+
tools: TOOLS_VERIFICATION,
|
|
593
596
|
artifacts: {
|
|
594
597
|
// Phase 3 migration (#4782): manifest matches today's actual
|
|
595
598
|
// buildRunUatPrompt inlining. Prior phase-1 entry listed
|