@opengsd/gsd-pi 1.1.1-dev.a5a2de8 → 1.1.1-dev.b2556262
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/headless-recover.js +56 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +18 -2
- package/dist/resources/extensions/browser-tools/engine/selection.js +1 -1
- package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/dist/resources/extensions/browser-tools/index.js +68 -24
- package/dist/resources/extensions/browser-tools/state.js +12 -0
- package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
- package/dist/resources/extensions/browser-tools/utils.js +3 -3
- package/dist/resources/extensions/browser-tools/web-app-detect.js +52 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +87 -12
- package/dist/resources/extensions/gsd/auto/session.js +22 -1
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +81 -13
- package/dist/resources/extensions/gsd/auto-model-selection.js +154 -9
- package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +26 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-timers.js +24 -10
- package/dist/resources/extensions/gsd/auto.js +40 -15
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +192 -77
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
- package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
- package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
- package/dist/resources/extensions/gsd/commands-mcp-status.js +1 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
- package/dist/resources/extensions/gsd/config-overlay.js +1 -0
- package/dist/resources/extensions/gsd/context-masker.js +129 -5
- package/dist/resources/extensions/gsd/db-writer.js +35 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/dist/resources/extensions/gsd/gsd-db.js +480 -172
- package/dist/resources/extensions/gsd/guided-flow.js +4 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
- package/dist/resources/extensions/gsd/md-importer.js +38 -3
- package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
- package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
- package/dist/resources/extensions/gsd/planner-handoff.js +98 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
- package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
- package/dist/resources/extensions/gsd/preferences-models.js +111 -43
- package/dist/resources/extensions/gsd/preferences-types.js +13 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
- package/dist/resources/extensions/gsd/preferences.js +4 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +2 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
- package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
- package/dist/resources/extensions/gsd/skill-manifest.js +12 -0
- package/dist/resources/extensions/gsd/source-observations.js +306 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
- package/dist/resources/extensions/gsd/state.js +7 -3
- package/dist/resources/extensions/gsd/tool-contract.js +15 -1
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +24 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +28 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
- package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +62 -406
- package/dist/resources/extensions/gsd/uat-policy.js +130 -0
- package/dist/resources/extensions/gsd/uat-run.js +414 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +38 -14
- package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
- package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -3
- package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +26 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +96 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
- package/dist/resources/extensions/shared/gsd-browser-cli.js +6 -0
- package/dist/resources/extensions/subagent/agents.js +1 -0
- package/dist/resources/extensions/subagent/index.js +27 -12
- package/dist/resources/extensions/subagent/launch.js +7 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
- 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/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/node_modules/@gsd/native/dist/native.js +22 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +4 -4
- 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/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
- 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 +25 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/dist/native.js +22 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +30 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +174 -29
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +178 -54
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +8 -1
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/utils.d.ts +11 -0
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +119 -6
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/themes.js +1 -1
- package/pkg/dist/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/scripts/install/handoff.js +16 -3
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +21 -2
- package/src/resources/extensions/browser-tools/engine/selection.ts +1 -1
- package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/src/resources/extensions/browser-tools/index.ts +75 -27
- package/src/resources/extensions/browser-tools/state.ts +13 -0
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +2 -2
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +37 -0
- package/src/resources/extensions/browser-tools/tests/web-app-detect.test.mjs +68 -0
- package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
- package/src/resources/extensions/browser-tools/utils.ts +3 -3
- package/src/resources/extensions/browser-tools/web-app-detect.ts +63 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +89 -15
- package/src/resources/extensions/gsd/auto/session.ts +24 -1
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +117 -12
- package/src/resources/extensions/gsd/auto-model-selection.ts +190 -12
- package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +25 -22
- package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-timers.ts +25 -9
- package/src/resources/extensions/gsd/auto.ts +41 -14
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +250 -78
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
- package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
- package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
- package/src/resources/extensions/gsd/commands-mcp-status.ts +1 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
- package/src/resources/extensions/gsd/config-overlay.ts +1 -0
- package/src/resources/extensions/gsd/context-masker.ts +152 -5
- package/src/resources/extensions/gsd/db-writer.ts +38 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/src/resources/extensions/gsd/gsd-db.ts +564 -186
- package/src/resources/extensions/gsd/guided-flow.ts +4 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
- package/src/resources/extensions/gsd/md-importer.ts +49 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
- package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
- package/src/resources/extensions/gsd/planner-handoff.ts +149 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
- package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
- package/src/resources/extensions/gsd/preferences-models.ts +113 -43
- package/src/resources/extensions/gsd/preferences-types.ts +47 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
- package/src/resources/extensions/gsd/preferences.ts +5 -0
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +2 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
- package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
- package/src/resources/extensions/gsd/skill-manifest.ts +12 -0
- package/src/resources/extensions/gsd/source-observations.ts +402 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
- package/src/resources/extensions/gsd/state.ts +7 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +66 -4
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +4 -0
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +56 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +17 -2
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/planner-handoff.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +77 -10
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +260 -5
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
- package/src/resources/extensions/gsd/tool-contract.ts +29 -1
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +41 -6
- package/src/resources/extensions/gsd/tools/complete-slice.ts +29 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
- package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +71 -489
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/uat-policy.ts +191 -0
- package/src/resources/extensions/gsd/uat-run.ts +550 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +38 -14
- package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
- package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -3
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +32 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +103 -0
- package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
- package/src/resources/extensions/shared/gsd-browser-cli.ts +6 -0
- package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
- package/src/resources/extensions/subagent/agents.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +28 -3
- package/src/resources/extensions/subagent/launch.ts +8 -0
- package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
- /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
* (e.g. `passed` → `pass`) are applied consistently across the codebase.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { extractUatType } from "./files.js";
|
|
9
|
-
import type { UatType } from "./files.js";
|
|
10
8
|
import { splitFrontmatter, parseFrontmatterMap } from "../shared/frontmatter.js";
|
|
11
9
|
import { parse as parseYaml } from "yaml";
|
|
10
|
+
import { getDeclaredUatType, isPartialEligibleUatType, type UatType } from "./uat-policy.js";
|
|
12
11
|
|
|
13
12
|
function normalizeVerdict(value: unknown): string | undefined {
|
|
14
13
|
if (typeof value !== "string") return undefined;
|
|
@@ -103,12 +102,6 @@ export const UAT_ACCEPTABLE_VERDICTS: readonly string[] = ["pass", "passed"];
|
|
|
103
102
|
* UAT types whose results may legitimately produce a `partial` verdict
|
|
104
103
|
* when all automatable checks pass but human-only checks remain.
|
|
105
104
|
*/
|
|
106
|
-
const PARTIAL_ELIGIBLE_UAT_TYPES: readonly UatType[] = [
|
|
107
|
-
"mixed",
|
|
108
|
-
"human-experience",
|
|
109
|
-
"live-runtime",
|
|
110
|
-
];
|
|
111
|
-
|
|
112
105
|
/**
|
|
113
106
|
* Check whether a verdict is acceptable for a given UAT type.
|
|
114
107
|
*
|
|
@@ -117,7 +110,7 @@ const PARTIAL_ELIGIBLE_UAT_TYPES: readonly UatType[] = [
|
|
|
117
110
|
*/
|
|
118
111
|
export function isAcceptableUatVerdict(verdict: string, uatType: UatType | undefined): boolean {
|
|
119
112
|
if (UAT_ACCEPTABLE_VERDICTS.includes(verdict)) return true;
|
|
120
|
-
if (verdict === "partial" &&
|
|
113
|
+
if (verdict === "partial" && isPartialEligibleUatType(uatType)) {
|
|
121
114
|
return true;
|
|
122
115
|
}
|
|
123
116
|
return false;
|
|
@@ -147,5 +140,5 @@ export function isValidMilestoneVerdict(verdict: string): verdict is ValidationV
|
|
|
147
140
|
* the codebase when a UAT file lacks an explicit `## UAT Type` section.
|
|
148
141
|
*/
|
|
149
142
|
export function getUatType(content: string): UatType {
|
|
150
|
-
return
|
|
143
|
+
return getDeclaredUatType(content);
|
|
151
144
|
}
|
|
@@ -6,24 +6,70 @@ import {
|
|
|
6
6
|
readTransaction,
|
|
7
7
|
restoreManifest,
|
|
8
8
|
} from "./gsd-db.js";
|
|
9
|
-
import type { MilestoneRow } from "./db-milestone-artifact-rows.js";
|
|
9
|
+
import type { ArtifactRow, MilestoneRow } from "./db-milestone-artifact-rows.js";
|
|
10
10
|
import type { SliceRow, TaskRow } from "./db-task-slice-rows.js";
|
|
11
11
|
import type { VerificationEvidenceRow } from "./db-verification-evidence-rows.js";
|
|
12
|
-
import type { Decision } from "./types.js";
|
|
12
|
+
import type { Decision, GateRow, Requirement } from "./types.js";
|
|
13
13
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
14
|
+
import { getAllDecisionsFromMemories } from "./context-store.js";
|
|
15
|
+
import { backfillDecisionsToMemories } from "./memory-backfill.js";
|
|
16
|
+
import { invalidateAllCaches } from "./cache.js";
|
|
14
17
|
import { readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
15
|
-
import { join } from "node:path";
|
|
18
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
16
19
|
|
|
17
20
|
// ─── Manifest Types ──────────────────────────────────────────────────────
|
|
18
21
|
|
|
22
|
+
export interface ManifestArtifactRow extends ArtifactRow {
|
|
23
|
+
content_hash: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ReplanHistoryManifestRow {
|
|
27
|
+
id: number;
|
|
28
|
+
milestone_id: string;
|
|
29
|
+
slice_id: string | null;
|
|
30
|
+
task_id: string | null;
|
|
31
|
+
summary: string;
|
|
32
|
+
previous_artifact_path: string | null;
|
|
33
|
+
replacement_artifact_path: string | null;
|
|
34
|
+
created_at: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface AssessmentManifestRow {
|
|
38
|
+
path: string;
|
|
39
|
+
milestone_id: string;
|
|
40
|
+
slice_id: string | null;
|
|
41
|
+
task_id: string | null;
|
|
42
|
+
status: string;
|
|
43
|
+
scope: string;
|
|
44
|
+
full_content: string;
|
|
45
|
+
created_at: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface MilestoneCommitAttributionManifestRow {
|
|
49
|
+
commit_sha: string;
|
|
50
|
+
milestone_id: string;
|
|
51
|
+
slice_id: string | null;
|
|
52
|
+
task_id: string | null;
|
|
53
|
+
source: string;
|
|
54
|
+
confidence: number;
|
|
55
|
+
files_json: string;
|
|
56
|
+
created_at: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
19
59
|
export interface StateManifest {
|
|
20
60
|
version: 1;
|
|
21
61
|
exported_at: string; // ISO 8601
|
|
62
|
+
requirements?: Requirement[];
|
|
63
|
+
artifacts?: ManifestArtifactRow[];
|
|
22
64
|
milestones: MilestoneRow[];
|
|
23
65
|
slices: SliceRow[];
|
|
24
66
|
tasks: TaskRow[];
|
|
25
67
|
decisions: Decision[];
|
|
68
|
+
replan_history?: ReplanHistoryManifestRow[];
|
|
69
|
+
assessments?: AssessmentManifestRow[];
|
|
70
|
+
quality_gates?: GateRow[];
|
|
26
71
|
verification_evidence: VerificationEvidenceRow[];
|
|
72
|
+
milestone_commit_attributions?: MilestoneCommitAttributionManifestRow[];
|
|
27
73
|
}
|
|
28
74
|
|
|
29
75
|
// ─── helpers ─────────────────────────────────────────────────────────────
|
|
@@ -51,11 +97,26 @@ export function toNumeric(value: unknown, fallback: number | null = null): numbe
|
|
|
51
97
|
return fallback;
|
|
52
98
|
}
|
|
53
99
|
|
|
100
|
+
function mergeDecisionSurfaces(legacyDecisions: Decision[], memoryDecisions: Decision[]): Decision[] {
|
|
101
|
+
const byId = new Map<string, Decision>();
|
|
102
|
+
for (const decision of legacyDecisions) {
|
|
103
|
+
byId.set(decision.id, decision);
|
|
104
|
+
}
|
|
105
|
+
for (const decision of memoryDecisions) {
|
|
106
|
+
byId.set(decision.id, decision);
|
|
107
|
+
}
|
|
108
|
+
return Array.from(byId.values()).sort((a, b) => {
|
|
109
|
+
const seqDelta = (a.seq ?? 0) - (b.seq ?? 0);
|
|
110
|
+
return seqDelta === 0 ? a.id.localeCompare(b.id) : seqDelta;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
54
114
|
// ─── snapshotState ───────────────────────────────────────────────────────
|
|
55
115
|
|
|
56
116
|
/**
|
|
57
|
-
* Capture
|
|
58
|
-
*
|
|
117
|
+
* Capture DB-backed workflow state as a StateManifest.
|
|
118
|
+
* Runtime soft state and append-only audit streams stay outside this recovery
|
|
119
|
+
* substrate; correctness records and persisted evidence are included.
|
|
59
120
|
*
|
|
60
121
|
* Note: rows returned from raw queries are plain objects with TEXT columns for
|
|
61
122
|
* JSON arrays. We parse them into typed Row objects using the same logic as
|
|
@@ -67,6 +128,34 @@ export function snapshotState(): StateManifest {
|
|
|
67
128
|
// Wrap all reads in a deferred transaction so the snapshot is consistent
|
|
68
129
|
// (all SELECTs see the same DB state even if a concurrent write lands between them).
|
|
69
130
|
return readTransaction(() => {
|
|
131
|
+
const rawRequirements = db.prepare("SELECT * FROM requirements ORDER BY id").all() as Record<string, unknown>[];
|
|
132
|
+
const requirements: Requirement[] = rawRequirements.map((r) => ({
|
|
133
|
+
id: r["id"] as string,
|
|
134
|
+
class: (r["class"] as string) ?? "",
|
|
135
|
+
status: (r["status"] as string) ?? "",
|
|
136
|
+
description: (r["description"] as string) ?? "",
|
|
137
|
+
why: (r["why"] as string) ?? "",
|
|
138
|
+
source: (r["source"] as string) ?? "",
|
|
139
|
+
primary_owner: (r["primary_owner"] as string) ?? "",
|
|
140
|
+
supporting_slices: (r["supporting_slices"] as string) ?? "",
|
|
141
|
+
validation: (r["validation"] as string) ?? "",
|
|
142
|
+
notes: (r["notes"] as string) ?? "",
|
|
143
|
+
full_content: (r["full_content"] as string) ?? "",
|
|
144
|
+
superseded_by: (r["superseded_by"] as string) ?? null,
|
|
145
|
+
}));
|
|
146
|
+
|
|
147
|
+
const rawArtifacts = db.prepare("SELECT * FROM artifacts ORDER BY path").all() as Record<string, unknown>[];
|
|
148
|
+
const artifacts: ManifestArtifactRow[] = rawArtifacts.map((r) => ({
|
|
149
|
+
path: r["path"] as string,
|
|
150
|
+
artifact_type: (r["artifact_type"] as string) ?? "",
|
|
151
|
+
milestone_id: (r["milestone_id"] as string) ?? null,
|
|
152
|
+
slice_id: (r["slice_id"] as string) ?? null,
|
|
153
|
+
task_id: (r["task_id"] as string) ?? null,
|
|
154
|
+
full_content: (r["full_content"] as string) ?? "",
|
|
155
|
+
imported_at: (r["imported_at"] as string) ?? "",
|
|
156
|
+
content_hash: (r["content_hash"] as string) ?? null,
|
|
157
|
+
}));
|
|
158
|
+
|
|
70
159
|
const rawMilestones = db.prepare(
|
|
71
160
|
"SELECT * FROM milestones ORDER BY CASE WHEN sequence > 0 THEN 0 ELSE 1 END, sequence, id",
|
|
72
161
|
).all() as Record<string, unknown>[];
|
|
@@ -152,7 +241,7 @@ export function snapshotState(): StateManifest {
|
|
|
152
241
|
}));
|
|
153
242
|
|
|
154
243
|
const rawDecisions = db.prepare("SELECT * FROM decisions ORDER BY seq").all() as Record<string, unknown>[];
|
|
155
|
-
const
|
|
244
|
+
const legacyDecisions: Decision[] = rawDecisions.map((r) => ({
|
|
156
245
|
seq: toNumeric(r["seq"], 0) as number,
|
|
157
246
|
id: r["id"] as string,
|
|
158
247
|
when_context: (r["when_context"] as string) ?? "",
|
|
@@ -165,6 +254,45 @@ export function snapshotState(): StateManifest {
|
|
|
165
254
|
source: (r["source"] as string) ?? "discussion",
|
|
166
255
|
superseded_by: (r["superseded_by"] as string) ?? null,
|
|
167
256
|
}));
|
|
257
|
+
const decisions = mergeDecisionSurfaces(legacyDecisions, getAllDecisionsFromMemories());
|
|
258
|
+
|
|
259
|
+
const rawReplanHistory = db.prepare("SELECT * FROM replan_history ORDER BY id").all() as Record<string, unknown>[];
|
|
260
|
+
const replan_history: ReplanHistoryManifestRow[] = rawReplanHistory.map((r) => ({
|
|
261
|
+
id: toNumeric(r["id"], 0) as number,
|
|
262
|
+
milestone_id: (r["milestone_id"] as string) ?? "",
|
|
263
|
+
slice_id: (r["slice_id"] as string) ?? null,
|
|
264
|
+
task_id: (r["task_id"] as string) ?? null,
|
|
265
|
+
summary: (r["summary"] as string) ?? "",
|
|
266
|
+
previous_artifact_path: (r["previous_artifact_path"] as string) ?? null,
|
|
267
|
+
replacement_artifact_path: (r["replacement_artifact_path"] as string) ?? null,
|
|
268
|
+
created_at: (r["created_at"] as string) ?? "",
|
|
269
|
+
}));
|
|
270
|
+
|
|
271
|
+
const rawAssessments = db.prepare("SELECT * FROM assessments ORDER BY path").all() as Record<string, unknown>[];
|
|
272
|
+
const assessments: AssessmentManifestRow[] = rawAssessments.map((r) => ({
|
|
273
|
+
path: r["path"] as string,
|
|
274
|
+
milestone_id: (r["milestone_id"] as string) ?? "",
|
|
275
|
+
slice_id: (r["slice_id"] as string) ?? null,
|
|
276
|
+
task_id: (r["task_id"] as string) ?? null,
|
|
277
|
+
status: (r["status"] as string) ?? "",
|
|
278
|
+
scope: (r["scope"] as string) ?? "",
|
|
279
|
+
full_content: (r["full_content"] as string) ?? "",
|
|
280
|
+
created_at: (r["created_at"] as string) ?? "",
|
|
281
|
+
}));
|
|
282
|
+
|
|
283
|
+
const rawQualityGates = db.prepare("SELECT * FROM quality_gates ORDER BY milestone_id, slice_id, gate_id, task_id").all() as Record<string, unknown>[];
|
|
284
|
+
const quality_gates: GateRow[] = rawQualityGates.map((r) => ({
|
|
285
|
+
milestone_id: r["milestone_id"] as string,
|
|
286
|
+
slice_id: r["slice_id"] as string,
|
|
287
|
+
gate_id: r["gate_id"] as GateRow["gate_id"],
|
|
288
|
+
scope: r["scope"] as GateRow["scope"],
|
|
289
|
+
task_id: (r["task_id"] as string) ?? "",
|
|
290
|
+
status: r["status"] as GateRow["status"],
|
|
291
|
+
verdict: r["status"] === "pending" ? null : (r["verdict"] as GateRow["verdict"]),
|
|
292
|
+
rationale: (r["rationale"] as string) ?? "",
|
|
293
|
+
findings: (r["findings"] as string) ?? "",
|
|
294
|
+
evaluated_at: (r["evaluated_at"] as string) ?? null,
|
|
295
|
+
}));
|
|
168
296
|
|
|
169
297
|
const rawEvidence = db.prepare("SELECT * FROM verification_evidence ORDER BY id").all() as Record<string, unknown>[];
|
|
170
298
|
const verification_evidence: VerificationEvidenceRow[] = rawEvidence.map((r) => ({
|
|
@@ -179,14 +307,34 @@ export function snapshotState(): StateManifest {
|
|
|
179
307
|
created_at: r["created_at"] as string,
|
|
180
308
|
}));
|
|
181
309
|
|
|
310
|
+
const rawCommitAttributions = db.prepare(
|
|
311
|
+
"SELECT * FROM milestone_commit_attributions ORDER BY milestone_id, commit_sha",
|
|
312
|
+
).all() as Record<string, unknown>[];
|
|
313
|
+
const milestone_commit_attributions: MilestoneCommitAttributionManifestRow[] = rawCommitAttributions.map((r) => ({
|
|
314
|
+
commit_sha: r["commit_sha"] as string,
|
|
315
|
+
milestone_id: r["milestone_id"] as string,
|
|
316
|
+
slice_id: (r["slice_id"] as string) ?? null,
|
|
317
|
+
task_id: (r["task_id"] as string) ?? null,
|
|
318
|
+
source: (r["source"] as string) ?? "recorded",
|
|
319
|
+
confidence: toNumeric(r["confidence"], 1) as number,
|
|
320
|
+
files_json: (r["files_json"] as string) ?? "[]",
|
|
321
|
+
created_at: (r["created_at"] as string) ?? "",
|
|
322
|
+
}));
|
|
323
|
+
|
|
182
324
|
const result: StateManifest = {
|
|
183
325
|
version: 1,
|
|
184
326
|
exported_at: new Date().toISOString(),
|
|
327
|
+
requirements,
|
|
328
|
+
artifacts,
|
|
185
329
|
milestones,
|
|
186
330
|
slices,
|
|
187
331
|
tasks,
|
|
188
332
|
decisions,
|
|
333
|
+
replan_history,
|
|
334
|
+
assessments,
|
|
335
|
+
quality_gates,
|
|
189
336
|
verification_evidence,
|
|
337
|
+
milestone_commit_attributions,
|
|
190
338
|
};
|
|
191
339
|
|
|
192
340
|
return result;
|
|
@@ -232,20 +380,55 @@ export function readManifest(basePath: string): StateManifest | null {
|
|
|
232
380
|
throw new Error(`Unsupported manifest version: ${parsed.version}`);
|
|
233
381
|
}
|
|
234
382
|
|
|
235
|
-
// Validate required fields to avoid cryptic errors during restore
|
|
383
|
+
// Validate required fields to avoid cryptic errors during restore.
|
|
236
384
|
if (!Array.isArray(parsed.milestones) || !Array.isArray(parsed.slices) ||
|
|
237
385
|
!Array.isArray(parsed.tasks) || !Array.isArray(parsed.decisions) ||
|
|
238
386
|
!Array.isArray(parsed.verification_evidence)) {
|
|
239
387
|
throw new Error("Malformed manifest: missing or invalid required arrays");
|
|
240
388
|
}
|
|
241
389
|
|
|
390
|
+
for (const key of ["requirements", "artifacts", "replan_history", "assessments", "quality_gates", "milestone_commit_attributions"] as const) {
|
|
391
|
+
if (parsed[key] !== undefined && !Array.isArray(parsed[key])) {
|
|
392
|
+
throw new Error(`Malformed manifest: ${key} must be an array when present`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
242
396
|
return parsed;
|
|
243
397
|
}
|
|
244
398
|
|
|
399
|
+
function stripGsdPrefix(path: string): string {
|
|
400
|
+
return path.startsWith(".gsd/") ? path.slice(".gsd/".length) : path;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function artifactProjectionPath(basePath: string, artifactPath: string): string {
|
|
404
|
+
const gsdDir = resolve(basePath, ".gsd");
|
|
405
|
+
const fullPath = resolve(gsdDir, stripGsdPrefix(artifactPath));
|
|
406
|
+
const rel = relative(gsdDir, fullPath);
|
|
407
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
408
|
+
throw new Error(`Malformed manifest: artifact path escapes .gsd: ${artifactPath}`);
|
|
409
|
+
}
|
|
410
|
+
return fullPath;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function restoreArtifactProjections(basePath: string, manifest: StateManifest): void {
|
|
414
|
+
if (manifest.artifacts === undefined) return;
|
|
415
|
+
|
|
416
|
+
for (const artifact of manifest.artifacts) {
|
|
417
|
+
atomicWriteSync(
|
|
418
|
+
artifactProjectionPath(basePath, artifact.path),
|
|
419
|
+
artifact.full_content ?? "",
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
245
424
|
// ─── bootstrapFromManifest ──────────────────────────────────────────────
|
|
246
425
|
|
|
247
426
|
/**
|
|
248
427
|
* Read state-manifest.json and restore DB state from it.
|
|
428
|
+
* Rehydrates artifact projection files for restored artifacts so file-based
|
|
429
|
+
* fallback paths see the same evidence as the DB.
|
|
430
|
+
* Re-mirrors restored legacy decisions into memories so the ADR-013
|
|
431
|
+
* memory-backed decision readers see bootstrapped decisions immediately.
|
|
249
432
|
* Returns true if bootstrap succeeded, false if manifest file doesn't exist.
|
|
250
433
|
*/
|
|
251
434
|
export function bootstrapFromManifest(basePath: string): boolean {
|
|
@@ -256,5 +439,8 @@ export function bootstrapFromManifest(basePath: string): boolean {
|
|
|
256
439
|
}
|
|
257
440
|
|
|
258
441
|
restoreManifest(manifest);
|
|
442
|
+
restoreArtifactProjections(basePath, manifest);
|
|
443
|
+
backfillDecisionsToMemories();
|
|
444
|
+
invalidateAllCaches();
|
|
259
445
|
return true;
|
|
260
446
|
}
|
|
@@ -487,10 +487,9 @@ export function getWorkflowTransportSupportError(
|
|
|
487
487
|
}
|
|
488
488
|
|
|
489
489
|
const uniqueRequired = [...new Set(requiredTools)];
|
|
490
|
-
const piRuntimeRequired = uniqueRequired.filter((tool) => !MCP_WORKFLOW_TOOL_SURFACE.has(tool));
|
|
491
490
|
const missing = (options.activeTools && options.activeTools.length > 0)
|
|
492
|
-
?
|
|
493
|
-
:
|
|
491
|
+
? uniqueRequired.filter((tool) => !hasRequiredTool(tool, options.activeTools!))
|
|
492
|
+
: uniqueRequired.filter((tool) => !MCP_WORKFLOW_TOOL_SURFACE.has(tool));
|
|
494
493
|
if (missing.length === 0) return null;
|
|
495
494
|
|
|
496
495
|
if (options.activeTools && options.activeTools.length > 0) {
|
|
@@ -546,6 +546,15 @@ export async function regenerateIfMissing(
|
|
|
546
546
|
return false;
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
+
// A sketch slice (or any slice not yet planned into tasks) legitimately has
|
|
550
|
+
// no PLAN.md to project. renderPlanFromDb throws on a zero-task slice, so
|
|
551
|
+
// skip cleanly here rather than logging a spurious failure. The PLAN.md will
|
|
552
|
+
// be created once the slice is refined and its first task is written through
|
|
553
|
+
// the single writer.
|
|
554
|
+
if (fileType === "PLAN" && getSliceTasks(milestoneId, sliceId).length === 0) {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
|
|
549
558
|
// Regenerate the missing file. Each renderer may swallow its own errors
|
|
550
559
|
// (e.g. renderStateProjection), so confirm the file actually exists on
|
|
551
560
|
// disk before reporting success — true must mean "file is there now".
|
|
@@ -259,6 +259,38 @@ export function resolveCanonicalMilestoneRoot(
|
|
|
259
259
|
return wtPath;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Build human-facing guidance for manually validating a milestone's work.
|
|
264
|
+
*
|
|
265
|
+
* When a milestone runs in a git worktree, its checkout lives under the hidden
|
|
266
|
+
* `.gsd/worktrees/<MID>/` path that a human can't easily discover. The UAT
|
|
267
|
+
* pause/handoff and the saved assessment use this to tell the human exactly
|
|
268
|
+
* where to `cd` to run or inspect the app before signing off on NEEDS-HUMAN
|
|
269
|
+
* checks, rather than leaving them to hunt for a buried path.
|
|
270
|
+
*
|
|
271
|
+
* Returns null when no milestone id is available.
|
|
272
|
+
*/
|
|
273
|
+
export function buildManualValidationGuidance(
|
|
274
|
+
basePath: string,
|
|
275
|
+
milestoneId: string,
|
|
276
|
+
opts: { uatPath?: string } = {},
|
|
277
|
+
): string | null {
|
|
278
|
+
if (!milestoneId) return null;
|
|
279
|
+
const validationRoot = resolveCanonicalMilestoneRoot(basePath, milestoneId);
|
|
280
|
+
const inWorktree = validationRoot.includes(`${sep}.gsd${sep}worktrees${sep}`);
|
|
281
|
+
const lines: string[] = [`Validate the work here: ${validationRoot}`];
|
|
282
|
+
if (inWorktree) {
|
|
283
|
+
lines.push(
|
|
284
|
+
"This milestone runs in a git worktree, so the code lives under the hidden " +
|
|
285
|
+
`\`.gsd/worktrees/\` path. Open it with: cd "${validationRoot}"`,
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
if (opts.uatPath) {
|
|
289
|
+
lines.push(`Follow the UAT checklist at: ${opts.uatPath}`);
|
|
290
|
+
}
|
|
291
|
+
return lines.join("\n");
|
|
292
|
+
}
|
|
293
|
+
|
|
262
294
|
// ─── Core Operations ───────────────────────────────────────────────────────
|
|
263
295
|
|
|
264
296
|
/**
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Deterministically re-enter the active milestone's worktree on a
|
|
3
|
+
// cold start (after /quit + relaunch). Without this, Claude Code relaunches with
|
|
4
|
+
// cwd at the project root, and a bare /gsd leaves the agent there — forcing it to
|
|
5
|
+
// search the filesystem ("git worktree list", branch sniffing) to find its way
|
|
6
|
+
// back into the worktree. The worktree path is fully derivable from state, so we
|
|
7
|
+
// resolve and chdir into it directly instead.
|
|
8
|
+
|
|
9
|
+
import { readdirSync } from "node:fs";
|
|
10
|
+
|
|
11
|
+
import { enterAutoWorktree, getAutoWorktreePath } from "./auto-worktree.js";
|
|
12
|
+
import { getIsolationMode } from "./preferences.js";
|
|
13
|
+
import { worktreesDir } from "./worktree-manager.js";
|
|
14
|
+
import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "./worktree-root.js";
|
|
15
|
+
|
|
16
|
+
interface LiveWorktree {
|
|
17
|
+
id: string;
|
|
18
|
+
path: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Enumerate the live (valid git) auto-worktrees under <projectRoot>/.gsd/worktrees/.
|
|
23
|
+
* Reuses getAutoWorktreePath's validation so stray directories are ignored.
|
|
24
|
+
*/
|
|
25
|
+
function liveMilestoneWorktrees(projectRoot: string): LiveWorktree[] {
|
|
26
|
+
let names: string[];
|
|
27
|
+
try {
|
|
28
|
+
names = readdirSync(worktreesDir(projectRoot));
|
|
29
|
+
} catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const live: LiveWorktree[] = [];
|
|
33
|
+
for (const id of names) {
|
|
34
|
+
const path = getAutoWorktreePath(projectRoot, id);
|
|
35
|
+
if (path) live.push({ id, path });
|
|
36
|
+
}
|
|
37
|
+
return live;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* If we're sitting at the project root with worktree isolation enabled and the
|
|
42
|
+
* active milestone has a live worktree, chdir into it. No-op when already inside
|
|
43
|
+
* a worktree, when isolation is off, or when the target is ambiguous.
|
|
44
|
+
*
|
|
45
|
+
* Single live worktree → enter it (covers the common case without deriveState).
|
|
46
|
+
* Multiple live worktrees → disambiguate by the active milestone from state;
|
|
47
|
+
* if that can't be resolved unambiguously, do nothing.
|
|
48
|
+
*
|
|
49
|
+
* Best-effort: any failure resolves to a no-op so it can never block startup.
|
|
50
|
+
*
|
|
51
|
+
* @returns the worktree path entered, or null when nothing was done.
|
|
52
|
+
*/
|
|
53
|
+
export async function reenterActiveWorktreeIfNeeded(
|
|
54
|
+
basePath: string,
|
|
55
|
+
opts: { notify?: (message: string) => void } = {},
|
|
56
|
+
): Promise<string | null> {
|
|
57
|
+
let projectRoot: string;
|
|
58
|
+
try {
|
|
59
|
+
projectRoot = resolveWorktreeProjectRoot(basePath);
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Only worktree-isolation projects have worktrees to re-enter.
|
|
65
|
+
if (getIsolationMode(projectRoot) !== "worktree") return null;
|
|
66
|
+
|
|
67
|
+
// Already inside a worktree (warm session, or auto-mode already entered) —
|
|
68
|
+
// nothing to do.
|
|
69
|
+
let cwd: string;
|
|
70
|
+
try {
|
|
71
|
+
cwd = process.cwd();
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
if (isGsdWorktreePath(cwd)) return null;
|
|
76
|
+
|
|
77
|
+
const live = liveMilestoneWorktrees(projectRoot);
|
|
78
|
+
if (live.length === 0) return null;
|
|
79
|
+
|
|
80
|
+
let target: LiveWorktree | null = live.length === 1 ? live[0]! : null;
|
|
81
|
+
if (!target) {
|
|
82
|
+
// Multiple live worktrees — disambiguate by the active milestone.
|
|
83
|
+
try {
|
|
84
|
+
const { deriveState } = await import("./state.js");
|
|
85
|
+
const state = await deriveState(projectRoot);
|
|
86
|
+
const activeId = state.activeMilestone?.id;
|
|
87
|
+
target = activeId ? live.find((w) => w.id === activeId) ?? null : null;
|
|
88
|
+
} catch {
|
|
89
|
+
target = null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!target) return null;
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const entered = enterAutoWorktree(projectRoot, target.id);
|
|
96
|
+
opts.notify?.(`Resumed in worktree for ${target.id}.`);
|
|
97
|
+
return entered;
|
|
98
|
+
} catch {
|
|
99
|
+
// Worktree vanished or chdir failed — leave cwd as-is, caller falls back to
|
|
100
|
+
// the project root.
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -123,36 +123,29 @@ function forceOverwriteAssessmentsWithVerdict(
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
function
|
|
126
|
+
function syncOtherMilestoneArtifacts(
|
|
127
127
|
srcMilestonesDir: string,
|
|
128
128
|
dstMilestonesDir: string,
|
|
129
|
+
currentMilestoneId: string,
|
|
129
130
|
): void {
|
|
130
131
|
if (!existsSync(srcMilestonesDir)) return;
|
|
131
132
|
|
|
132
133
|
try {
|
|
133
134
|
for (const milestoneEntry of readdirSync(srcMilestonesDir, { withFileTypes: true })) {
|
|
134
135
|
if (!milestoneEntry.isDirectory()) continue;
|
|
136
|
+
// The current milestone is already fully projected by the caller's
|
|
137
|
+
// additive safeCopyRecursive; skip it here to avoid redundant work.
|
|
138
|
+
if (milestoneEntry.name === currentMilestoneId) continue;
|
|
135
139
|
const srcMilestoneDir = join(srcMilestonesDir, milestoneEntry.name);
|
|
136
140
|
const dstMilestoneDir = join(dstMilestonesDir, milestoneEntry.name);
|
|
137
141
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
join(srcMilestoneDir, fileEntry.name),
|
|
146
|
-
join(dstMilestoneDir, fileEntry.name),
|
|
147
|
-
{ force: false },
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
} catch (err) {
|
|
151
|
-
logWarning(
|
|
152
|
-
"worktree",
|
|
153
|
-
`milestone top-level artifact sync failed (${milestoneEntry.name}): ${err instanceof Error ? err.message : String(err)}`,
|
|
154
|
-
);
|
|
155
|
-
}
|
|
142
|
+
// Additively project the entire milestone subtree (force:false), not just
|
|
143
|
+
// top-level files. Prior completed milestones keep their per-slice and
|
|
144
|
+
// per-task SUMMARY.md / UAT.md on disk so the worktree's stale-render
|
|
145
|
+
// detector doesn't flag them as missing (DB has summary, disk doesn't).
|
|
146
|
+
// force:false preserves any worktree-local files (#1886 invariant) and
|
|
147
|
+
// only fills in files absent from the worktree projection.
|
|
148
|
+
safeCopyRecursive(srcMilestoneDir, dstMilestoneDir, { force: false });
|
|
156
149
|
}
|
|
157
150
|
} catch (err) {
|
|
158
151
|
logWarning(
|
|
@@ -248,9 +241,16 @@ export function _projectRootToWorktreeImpl(
|
|
|
248
241
|
{ force: false },
|
|
249
242
|
);
|
|
250
243
|
|
|
251
|
-
// Additively project
|
|
252
|
-
//
|
|
253
|
-
|
|
244
|
+
// Additively project the full subtree of every OTHER milestone so
|
|
245
|
+
// worktree-bound units can read prior-milestone context artifacts and so
|
|
246
|
+
// completed milestones retain their per-slice/per-task SUMMARY.md and
|
|
247
|
+
// UAT.md on the worktree filesystem (otherwise the stale-render detector
|
|
248
|
+
// flags them as "complete in DB but missing on disk").
|
|
249
|
+
syncOtherMilestoneArtifacts(
|
|
250
|
+
join(prGsd, "milestones"),
|
|
251
|
+
join(wtGsd, "milestones"),
|
|
252
|
+
milestoneId,
|
|
253
|
+
);
|
|
254
254
|
|
|
255
255
|
// Force-sync ASSESSMENT files that have a verdict from project root (#2821).
|
|
256
256
|
// The additive-only copy above preserves worktree-local files, but
|
|
@@ -140,6 +140,10 @@ export function resolveGsdBrowserMcpLaunchConfig(
|
|
|
140
140
|
: null;
|
|
141
141
|
const sessionName =
|
|
142
142
|
options.sessionName?.trim() || buildGsdBrowserSessionName(resolvedProjectRoot, options.sessionSuffix);
|
|
143
|
+
// Stable per-project identity key (no per-session suffix) so the browser
|
|
144
|
+
// profile/cookies persist across pi sessions for the same project. gsd-browser
|
|
145
|
+
// rejects --identity-scope unless --identity-key is also supplied.
|
|
146
|
+
const identityKey = env.GSD_BROWSER_IDENTITY_KEY?.trim() || buildGsdBrowserSessionName(resolvedProjectRoot);
|
|
143
147
|
const command =
|
|
144
148
|
explicitCommand
|
|
145
149
|
|| explicitCliPath
|
|
@@ -155,6 +159,8 @@ export function resolveGsdBrowserMcpLaunchConfig(
|
|
|
155
159
|
sessionName,
|
|
156
160
|
"--identity-scope",
|
|
157
161
|
"project",
|
|
162
|
+
"--identity-key",
|
|
163
|
+
identityKey,
|
|
158
164
|
"--identity-project",
|
|
159
165
|
resolvedProjectRoot,
|
|
160
166
|
];
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
centerLine,
|
|
12
12
|
fitColumns,
|
|
13
13
|
} from "../layout-utils.js";
|
|
14
|
+
import { visibleWidth } from "@gsd/pi-tui";
|
|
14
15
|
|
|
15
16
|
describe("formatDuration", () => {
|
|
16
17
|
it("formats seconds", () => {
|
|
@@ -59,8 +60,10 @@ describe("joinColumns", () => {
|
|
|
59
60
|
|
|
60
61
|
it("truncates when content overflows", () => {
|
|
61
62
|
const result = joinColumns("a".repeat(20), "b".repeat(20), 30);
|
|
62
|
-
//
|
|
63
|
-
|
|
63
|
+
// truncateToWidth is ANSI-aware and brackets the ellipsis with zero-width
|
|
64
|
+
// SGR resets, so the visible width — not the raw string length — is the
|
|
65
|
+
// invariant that must hold within the column budget.
|
|
66
|
+
assert.ok(visibleWidth(result) <= 30);
|
|
64
67
|
});
|
|
65
68
|
});
|
|
66
69
|
|
|
@@ -72,7 +75,9 @@ describe("centerLine", () => {
|
|
|
72
75
|
|
|
73
76
|
it("truncates when content exceeds width", () => {
|
|
74
77
|
const result = centerLine("abcdefgh", 4);
|
|
75
|
-
|
|
78
|
+
// Visible width is the meaningful budget; the result may carry zero-width
|
|
79
|
+
// SGR reset codes around the ellipsis (see truncateToWidth).
|
|
80
|
+
assert.ok(visibleWidth(result) <= 4);
|
|
76
81
|
});
|
|
77
82
|
});
|
|
78
83
|
|
|
@@ -15,6 +15,8 @@ export interface AgentConfig {
|
|
|
15
15
|
description: string;
|
|
16
16
|
tools?: string[];
|
|
17
17
|
model?: string;
|
|
18
|
+
/** Default reasoning effort for this agent, forwarded as `--thinking` (#508). */
|
|
19
|
+
thinking?: string;
|
|
18
20
|
conflictsWith?: string[];
|
|
19
21
|
systemPrompt: string;
|
|
20
22
|
source: "user" | "project";
|
|
@@ -31,6 +33,7 @@ interface AgentFrontmatter extends Record<string, unknown> {
|
|
|
31
33
|
description?: string;
|
|
32
34
|
tools?: string | string[];
|
|
33
35
|
model?: string;
|
|
36
|
+
thinking?: string;
|
|
34
37
|
conflicts_with?: string;
|
|
35
38
|
}
|
|
36
39
|
|
|
@@ -100,6 +103,7 @@ function loadAgentsFromDir(dir: string, source: "user" | "project"): AgentConfig
|
|
|
100
103
|
description: frontmatter.description,
|
|
101
104
|
tools: tools && tools.length > 0 ? tools : undefined,
|
|
102
105
|
model: frontmatter.model,
|
|
106
|
+
thinking: typeof frontmatter.thinking === "string" ? frontmatter.thinking : undefined,
|
|
103
107
|
conflictsWith,
|
|
104
108
|
systemPrompt: body,
|
|
105
109
|
source,
|