gsd-pi 2.78.1-dev.b0759e59b → 2.78.1-dev.d8826a445
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 +8 -5
- package/dist/headless-recover.d.ts +23 -0
- package/dist/headless-recover.js +93 -0
- package/dist/headless.js +9 -0
- package/dist/help-text.js +1 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +8 -1
- package/dist/resources/extensions/gsd/auto/phases.js +7 -2
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +7 -58
- package/dist/resources/extensions/gsd/auto-post-unit.js +14 -28
- package/dist/resources/extensions/gsd/auto-start.js +1 -8
- package/dist/resources/extensions/gsd/auto-worktree.js +244 -216
- package/dist/resources/extensions/gsd/auto.js +86 -7
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -77
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -16
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +67 -55
- package/dist/resources/extensions/gsd/commands-codebase.js +2 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +5 -5
- package/dist/resources/extensions/gsd/commands-logs.js +2 -2
- package/dist/resources/extensions/gsd/commands-scan.js +2 -2
- package/dist/resources/extensions/gsd/commands-ship.js +2 -2
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +5 -5
- package/dist/resources/extensions/gsd/db-writer.js +106 -95
- package/dist/resources/extensions/gsd/delegation-policy.js +155 -0
- package/dist/resources/extensions/gsd/dispatch-guard.js +6 -10
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +2 -2
- package/dist/resources/extensions/gsd/gsd-db.js +268 -8
- package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
- package/dist/resources/extensions/gsd/guided-flow.js +141 -32
- package/dist/resources/extensions/gsd/markdown-renderer.js +14 -51
- package/dist/resources/extensions/gsd/metrics.js +287 -1
- package/dist/resources/extensions/gsd/parallel-merge.js +14 -13
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +5 -2
- package/dist/resources/extensions/gsd/paths.js +114 -9
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
- package/dist/resources/extensions/gsd/queue-order.js +6 -1
- package/dist/resources/extensions/gsd/rethink.js +2 -2
- package/dist/resources/extensions/gsd/state.js +91 -372
- package/dist/resources/extensions/gsd/templates/project.md +10 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -5
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -12
- package/dist/resources/extensions/gsd/tools/complete-task.js +19 -31
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -5
- package/dist/resources/extensions/gsd/workflow-manifest.js +2 -1
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -21
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
- package/dist/resources/extensions/gsd/workflow-reconcile.js +3 -3
- package/dist/resources/extensions/gsd/workspace.js +59 -0
- package/dist/resources/extensions/gsd/worktree-command.js +4 -3
- package/dist/resources/extensions/gsd/worktree-resolver.js +15 -2
- package/dist/resources/extensions/gsd/write-intercept.js +3 -3
- 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 +12 -12
- 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/required-server-files.json +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.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/chunks/6336.js +1 -0
- package/dist/web/standalone/.next/server/chunks/6897.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/server.js +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/README.md +2 -11
- package/packages/mcp-server/dist/remote-questions.d.ts +27 -0
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
- package/packages/mcp-server/dist/remote-questions.js +28 -0
- package/packages/mcp-server/dist/remote-questions.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts +28 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +94 -4
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +6 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +56 -2
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/mcp-server.test.ts +226 -0
- package/packages/mcp-server/src/parse-workflow-args.test.ts +80 -0
- package/packages/mcp-server/src/remote-questions.test.ts +103 -0
- package/packages/mcp-server/src/remote-questions.ts +35 -0
- package/packages/mcp-server/src/server.ts +129 -6
- package/packages/mcp-server/src/workflow-tools.ts +62 -3
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +13 -2
- package/src/resources/extensions/gsd/auto/phases.ts +8 -2
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -62
- package/src/resources/extensions/gsd/auto-post-unit.ts +15 -27
- package/src/resources/extensions/gsd/auto-start.ts +1 -8
- package/src/resources/extensions/gsd/auto-worktree.ts +286 -251
- package/src/resources/extensions/gsd/auto.ts +102 -7
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +9 -84
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -17
- package/src/resources/extensions/gsd/bootstrap/tests/write-gate-basepath.test.ts +103 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -55
- package/src/resources/extensions/gsd/commands-codebase.ts +2 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +5 -5
- package/src/resources/extensions/gsd/commands-logs.ts +2 -2
- package/src/resources/extensions/gsd/commands-scan.ts +2 -2
- package/src/resources/extensions/gsd/commands-ship.ts +2 -2
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +5 -5
- package/src/resources/extensions/gsd/db-writer.ts +123 -94
- package/src/resources/extensions/gsd/delegation-policy.ts +197 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +6 -11
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +2 -2
- package/src/resources/extensions/gsd/gsd-db.ts +269 -8
- package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
- package/src/resources/extensions/gsd/guided-flow.ts +181 -32
- package/src/resources/extensions/gsd/markdown-renderer.ts +13 -64
- package/src/resources/extensions/gsd/metrics.ts +321 -1
- package/src/resources/extensions/gsd/parallel-merge.ts +14 -13
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +5 -2
- package/src/resources/extensions/gsd/paths.ts +122 -9
- package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
- package/src/resources/extensions/gsd/queue-order.ts +6 -1
- package/src/resources/extensions/gsd/rethink.ts +2 -2
- package/src/resources/extensions/gsd/state.ts +91 -389
- package/src/resources/extensions/gsd/templates/project.md +10 -0
- package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +14 -14
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +21 -34
- package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +331 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +6 -7
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +12 -27
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +18 -5
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/db-writer-path-containment.test.ts +152 -0
- package/src/resources/extensions/gsd/tests/db-writer-root-artifact.test.ts +221 -0
- package/src/resources/extensions/gsd/tests/db-writer-scope.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/delegation-policy.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +10 -38
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +136 -56
- package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +119 -61
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/dispatch-backgroundable-annotation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +6 -20
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +14 -15
- package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +3 -23
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +11 -16
- package/src/resources/extensions/gsd/tests/escalation.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +193 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +246 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +218 -0
- package/src/resources/extensions/gsd/tests/gsd-db-failed-open-restore.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/gsd-db-workspace-scope.test.ts +226 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/gsd-root-canonical.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/gsd-root-home-guard.test.ts +68 -5
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +15 -36
- package/src/resources/extensions/gsd/tests/guided-flow-prompt-consolidation.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/handler-worktree-write-isolation.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +15 -15
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +15 -5
- package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +371 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +14 -8
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/metrics-atomic-merge.test.ts +222 -0
- package/src/resources/extensions/gsd/tests/metrics-lock-hardening.test.ts +400 -0
- package/src/resources/extensions/gsd/tests/metrics-lock-not-acquired.test.ts +141 -0
- package/src/resources/extensions/gsd/tests/metrics-lock-retry-sleep.test.ts +287 -0
- package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +149 -0
- package/src/resources/extensions/gsd/tests/metrics-scope.test.ts +378 -0
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +329 -0
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/path-cache-decoupled.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/path-normalization-unified.test.ts +175 -0
- package/src/resources/extensions/gsd/tests/paths-cache.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +25 -16
- package/src/resources/extensions/gsd/tests/projection-regression.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +150 -7
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +184 -0
- package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +28 -16
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/resolve-ts.mjs +4 -0
- package/src/resources/extensions/gsd/tests/resume-missing-worktree-warning.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +10 -56
- package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +15 -16
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +23 -27
- package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +13 -14
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +10 -33
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +162 -0
- package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +239 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +12 -7
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +26 -3
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/workspace.test.ts +190 -0
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +65 -71
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +26 -151
- package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +35 -35
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -52
- package/src/resources/extensions/gsd/tests/write-intercept.test.ts +1 -1
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -5
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -14
- package/src/resources/extensions/gsd/tools/complete-task.ts +19 -34
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +7 -5
- package/src/resources/extensions/gsd/workflow-manifest.ts +4 -1
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -18
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/workspace.ts +95 -0
- package/src/resources/extensions/gsd/worktree-command.ts +4 -3
- package/src/resources/extensions/gsd/worktree-resolver.ts +16 -2
- package/src/resources/extensions/gsd/write-intercept.ts +3 -3
- package/dist/web/standalone/.next/server/chunks/8527.js +0 -1
- /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → AT5qi39nKXkdmQIOIoh0f}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → AT5qi39nKXkdmQIOIoh0f}/_ssgManifest.js +0 -0
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
33
33
|
import { execFileSync } from "node:child_process";
|
|
34
34
|
import { safeCopy, safeCopyRecursive } from "./safe-fs.js";
|
|
35
|
-
import { gsdRoot } from "./paths.js";
|
|
35
|
+
import { gsdRoot, resolveGsdPathContract } from "./paths.js";
|
|
36
36
|
import {
|
|
37
37
|
createWorktree,
|
|
38
38
|
removeWorktree,
|
|
@@ -76,6 +76,7 @@ import {
|
|
|
76
76
|
nativeMergeAbort,
|
|
77
77
|
} from "./native-git-bridge.js";
|
|
78
78
|
import { gsdHome } from "./gsd-home.js";
|
|
79
|
+
import { type MilestoneScope, type GsdWorkspace, createWorkspace } from "./workspace.js";
|
|
79
80
|
|
|
80
81
|
const PROJECT_PREFERENCES_FILE = "PREFERENCES.md";
|
|
81
82
|
const LEGACY_PROJECT_PREFERENCES_FILE = "preferences.md";
|
|
@@ -90,9 +91,8 @@ const LEGACY_DEEP_SETUP_RUNTIME_UNIT_FILES = new Set([
|
|
|
90
91
|
// ─── Shared Constants & Helpers ─────────────────────────────────────────────
|
|
91
92
|
|
|
92
93
|
/**
|
|
93
|
-
* Root-level .gsd/
|
|
94
|
-
*
|
|
95
|
-
* and the dispatch-level sync functions.
|
|
94
|
+
* Root-level .gsd/ projections copied from project root into worktrees for
|
|
95
|
+
* compatibility. Project root remains the canonical state/projection root.
|
|
96
96
|
*/
|
|
97
97
|
const ROOT_STATE_FILES = [
|
|
98
98
|
"DECISIONS.md",
|
|
@@ -110,6 +110,11 @@ const ROOT_STATE_FILES = [
|
|
|
110
110
|
// because the project root is authoritative for preferences (#2684).
|
|
111
111
|
] as const;
|
|
112
112
|
|
|
113
|
+
const ROOT_DIAGNOSTIC_FILES = [
|
|
114
|
+
"completed-units.json",
|
|
115
|
+
"metrics.json",
|
|
116
|
+
] as const;
|
|
117
|
+
|
|
113
118
|
/**
|
|
114
119
|
* Pop a stash entry by tracking the unique marker embedded in its message so
|
|
115
120
|
* concurrent stash operations against the same project root cannot cause us to
|
|
@@ -194,7 +199,7 @@ const VERDICT_RE = /verdict:\s*[\w-]+/i;
|
|
|
194
199
|
* destination when the source copy contains a `verdict:` field.
|
|
195
200
|
*
|
|
196
201
|
* This is the targeted fix for the UAT stuck-loop (#2821): the main
|
|
197
|
-
* safeCopyRecursive uses force:false to protect worktree-
|
|
202
|
+
* safeCopyRecursive uses force:false to protect worktree-local projection
|
|
198
203
|
* files (#1886), but ASSESSMENT files written by run-uat must be
|
|
199
204
|
* forward-synced when the project root has a verdict. Without this,
|
|
200
205
|
* the worktree retains a stale FAIL or missing ASSESSMENT and
|
|
@@ -250,8 +255,16 @@ function forceOverwriteAssessmentsWithVerdict(
|
|
|
250
255
|
|
|
251
256
|
// ─── Module State ──────────────────────────────────────────────────────────
|
|
252
257
|
|
|
253
|
-
/**
|
|
254
|
-
let
|
|
258
|
+
/** Active workspace registry — replaces the legacy `originalBase` singleton. */
|
|
259
|
+
let activeWorkspace: GsdWorkspace | null = null;
|
|
260
|
+
|
|
261
|
+
function setActiveWorkspace(ws: GsdWorkspace | null): void {
|
|
262
|
+
activeWorkspace = ws;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function getActiveWorkspace(): GsdWorkspace | null {
|
|
266
|
+
return activeWorkspace;
|
|
267
|
+
}
|
|
255
268
|
|
|
256
269
|
function clearProjectRootStateFiles(basePath: string, milestoneId: string): void {
|
|
257
270
|
const gsdDir = gsdRoot(basePath);
|
|
@@ -272,9 +285,9 @@ function clearProjectRootStateFiles(basePath: string, milestoneId: string): void
|
|
|
272
285
|
}
|
|
273
286
|
}
|
|
274
287
|
|
|
275
|
-
// Clean up
|
|
276
|
-
//
|
|
277
|
-
//
|
|
288
|
+
// Clean up legacy synced milestone directories and runtime/units.
|
|
289
|
+
// Older versions copied these into the project root during execution.
|
|
290
|
+
// If they remain as untracked files when we attempt
|
|
278
291
|
// `git merge --squash`, git rejects the merge with "local changes would
|
|
279
292
|
// be overwritten", causing silent data loss (#1738).
|
|
280
293
|
const syncedDirs = [
|
|
@@ -341,6 +354,41 @@ export const isSafeToAutoResolve = (filePath: string): boolean =>
|
|
|
341
354
|
* gsd.db in the worktree so it rebuilds from fresh disk state (#853).
|
|
342
355
|
* Non-fatal — sync failure should never block dispatch.
|
|
343
356
|
*/
|
|
357
|
+
/**
|
|
358
|
+
* Scope-typed variant of syncProjectRootToWorktree.
|
|
359
|
+
*
|
|
360
|
+
* Takes an explicit (rootScope, worktreeScope) pair where rootScope is the
|
|
361
|
+
* project root and worktreeScope is the auto-worktree. Direction is encoded
|
|
362
|
+
* in argument order. Asserts both scopes belong to the same workspace identity
|
|
363
|
+
* to prevent silent mismatch bugs.
|
|
364
|
+
*/
|
|
365
|
+
export function syncProjectRootToWorktreeByScope(
|
|
366
|
+
rootScope: MilestoneScope,
|
|
367
|
+
worktreeScope: MilestoneScope,
|
|
368
|
+
): void {
|
|
369
|
+
if (rootScope.workspace.identityKey !== worktreeScope.workspace.identityKey) {
|
|
370
|
+
throw new Error(
|
|
371
|
+
`syncProjectRootToWorktreeByScope: scope identity mismatch — ` +
|
|
372
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}" ` +
|
|
373
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}"`,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
if (rootScope.milestoneId !== worktreeScope.milestoneId) {
|
|
377
|
+
throw new Error(
|
|
378
|
+
`syncProjectRootToWorktreeByScope: milestoneId mismatch — ` +
|
|
379
|
+
`rootScope.milestoneId="${rootScope.milestoneId}" worktreeScope.milestoneId="${worktreeScope.milestoneId}"`,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
const projectRoot = rootScope.workspace.projectRoot;
|
|
383
|
+
const worktreePath_ = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
384
|
+
const milestoneId = rootScope.milestoneId;
|
|
385
|
+
syncProjectRootToWorktree(projectRoot, worktreePath_, milestoneId);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* @deprecated Use syncProjectRootToWorktreeByScope instead.
|
|
390
|
+
* TODO(C-future): remove once all callers migrated.
|
|
391
|
+
*/
|
|
344
392
|
export function syncProjectRootToWorktree(
|
|
345
393
|
projectRoot: string,
|
|
346
394
|
worktreePath_: string,
|
|
@@ -349,8 +397,9 @@ export function syncProjectRootToWorktree(
|
|
|
349
397
|
if (!worktreePath_ || !projectRoot || worktreePath_ === projectRoot) return;
|
|
350
398
|
if (!milestoneId) return;
|
|
351
399
|
|
|
352
|
-
const
|
|
353
|
-
const
|
|
400
|
+
const contract = resolveGsdPathContract(worktreePath_, projectRoot);
|
|
401
|
+
const prGsd = contract.projectGsd;
|
|
402
|
+
const wtGsd = contract.worktreeGsd ?? join(worktreePath_, ".gsd");
|
|
354
403
|
|
|
355
404
|
// When .gsd is a symlink to the same external directory in both locations,
|
|
356
405
|
// cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
|
|
@@ -359,7 +408,7 @@ export function syncProjectRootToWorktree(
|
|
|
359
408
|
|
|
360
409
|
// Copy milestone directory from project root to worktree — additive only.
|
|
361
410
|
// force:false prevents cpSync from overwriting existing worktree files.
|
|
362
|
-
// Without this, worktree-
|
|
411
|
+
// Without this, worktree-local files (e.g. VALIDATION.md written
|
|
363
412
|
// by validate-milestone) get clobbered by stale project root copies,
|
|
364
413
|
// causing an infinite re-validation loop (#1886).
|
|
365
414
|
safeCopyRecursive(
|
|
@@ -369,7 +418,7 @@ export function syncProjectRootToWorktree(
|
|
|
369
418
|
);
|
|
370
419
|
|
|
371
420
|
// Force-sync ASSESSMENT files that have a verdict from project root (#2821).
|
|
372
|
-
// The additive-only copy above preserves worktree-
|
|
421
|
+
// The additive-only copy above preserves worktree-local files, but
|
|
373
422
|
// ASSESSMENT files are special: after run-uat writes a verdict and post-unit
|
|
374
423
|
// syncs it to the project root, the worktree may retain a stale copy (e.g.
|
|
375
424
|
// verdict:fail while the project root has verdict:pass from a retry). On
|
|
@@ -390,11 +439,9 @@ export function syncProjectRootToWorktree(
|
|
|
390
439
|
{ force: true },
|
|
391
440
|
);
|
|
392
441
|
|
|
393
|
-
// Delete worktree gsd.db ONLY if it is empty (0 bytes).
|
|
394
|
-
//
|
|
395
|
-
//
|
|
396
|
-
// preserved — deleting it truncates the file to 0 bytes when
|
|
397
|
-
// openDatabase re-creates it, causing "no such table" failures (#2815).
|
|
442
|
+
// Delete a legacy worktree-local gsd.db ONLY if it is empty (0 bytes).
|
|
443
|
+
// Runtime opens contract.projectDb; this cleanup only removes corrupt
|
|
444
|
+
// pre-upgrade local DB projections.
|
|
398
445
|
try {
|
|
399
446
|
const wtDb = join(wtGsd, "gsd.db");
|
|
400
447
|
let deleteSidecars = false;
|
|
@@ -428,10 +475,43 @@ export function syncProjectRootToWorktree(
|
|
|
428
475
|
}
|
|
429
476
|
|
|
430
477
|
/**
|
|
431
|
-
*
|
|
478
|
+
* Scope-typed variant of syncStateToProjectRoot.
|
|
479
|
+
*
|
|
480
|
+
* Takes an explicit (worktreeScope, rootScope) pair. Direction is encoded in
|
|
481
|
+
* argument order (worktree → root). Asserts both scopes belong to the same
|
|
482
|
+
* workspace identity to prevent silent mismatch bugs.
|
|
483
|
+
*/
|
|
484
|
+
export function syncStateToProjectRootByScope(
|
|
485
|
+
worktreeScope: MilestoneScope,
|
|
486
|
+
rootScope: MilestoneScope,
|
|
487
|
+
): void {
|
|
488
|
+
if (worktreeScope.workspace.identityKey !== rootScope.workspace.identityKey) {
|
|
489
|
+
throw new Error(
|
|
490
|
+
`syncStateToProjectRootByScope: scope identity mismatch — ` +
|
|
491
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}" ` +
|
|
492
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}"`,
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
if (worktreeScope.milestoneId !== rootScope.milestoneId) {
|
|
496
|
+
throw new Error(
|
|
497
|
+
`syncStateToProjectRootByScope: milestoneId mismatch — ` +
|
|
498
|
+
`worktreeScope.milestoneId="${worktreeScope.milestoneId}" rootScope.milestoneId="${rootScope.milestoneId}"`,
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
const worktreePath_ = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
502
|
+
const projectRoot = rootScope.workspace.projectRoot;
|
|
503
|
+
const milestoneId = worktreeScope.milestoneId;
|
|
504
|
+
syncStateToProjectRoot(worktreePath_, projectRoot, milestoneId);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Sync worktree diagnostics from worktree to project root.
|
|
432
509
|
* Only runs when inside an auto-worktree (worktreePath differs from projectRoot).
|
|
433
|
-
*
|
|
510
|
+
* DB/project-root state remains authoritative; markdown projections are not
|
|
511
|
+
* copied from the worktree back to the project root.
|
|
434
512
|
* Non-fatal — sync failure should never block dispatch.
|
|
513
|
+
* @deprecated Use syncStateToProjectRootByScope instead.
|
|
514
|
+
* TODO(C-future): remove once all callers migrated.
|
|
435
515
|
*/
|
|
436
516
|
export function syncStateToProjectRoot(
|
|
437
517
|
worktreePath_: string,
|
|
@@ -441,31 +521,25 @@ export function syncStateToProjectRoot(
|
|
|
441
521
|
if (!worktreePath_ || !projectRoot || worktreePath_ === projectRoot) return;
|
|
442
522
|
if (!milestoneId) return;
|
|
443
523
|
|
|
444
|
-
const
|
|
445
|
-
const
|
|
524
|
+
const contract = resolveGsdPathContract(worktreePath_, projectRoot);
|
|
525
|
+
const wtGsd = contract.worktreeGsd ?? join(worktreePath_, ".gsd");
|
|
526
|
+
const prGsd = contract.projectGsd;
|
|
446
527
|
|
|
447
528
|
// When .gsd is a symlink to the same external directory in both locations,
|
|
448
529
|
// cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
|
|
449
530
|
// Compare realpaths and skip when they resolve to the same physical path (#2184).
|
|
450
531
|
if (isSamePath(wtGsd, prGsd)) return;
|
|
451
532
|
|
|
452
|
-
//
|
|
453
|
-
safeCopy(join(wtGsd, "STATE.md"), join(prGsd, "STATE.md"), { force: true });
|
|
454
|
-
|
|
455
|
-
// 2. Milestone directory — ROADMAP, slice PLANs, task summaries
|
|
456
|
-
// Copy the entire milestone .gsd subtree so deriveState reads current checkboxes
|
|
457
|
-
safeCopyRecursive(
|
|
458
|
-
join(wtGsd, "milestones", milestoneId),
|
|
459
|
-
join(prGsd, "milestones", milestoneId),
|
|
460
|
-
{ force: true },
|
|
461
|
-
);
|
|
462
|
-
|
|
463
|
-
// 3. metrics.json — session cost/token tracking (#2313).
|
|
533
|
+
// metrics.json — session cost/token tracking (#2313).
|
|
464
534
|
// Without this, metrics accumulated in the worktree are invisible from the
|
|
465
535
|
// project root and never appear in the dashboard or skill-health reports.
|
|
466
536
|
safeCopy(join(wtGsd, "metrics.json"), join(prGsd, "metrics.json"), { force: true });
|
|
467
537
|
|
|
468
|
-
//
|
|
538
|
+
// completed-units.json — runtime completion diagnostics used to avoid
|
|
539
|
+
// re-dispatching work already completed in an isolated worktree.
|
|
540
|
+
safeCopy(join(wtGsd, "completed-units.json"), join(prGsd, "completed-units.json"), { force: true });
|
|
541
|
+
|
|
542
|
+
// Runtime records — unit dispatch diagnostics used by selfHealRuntimeRecords().
|
|
469
543
|
// Without this, a crash during a unit leaves the runtime record only in the
|
|
470
544
|
// worktree. If the next session resolves basePath before worktree re-entry,
|
|
471
545
|
// selfHeal can't find or clear the stale record (#769).
|
|
@@ -627,6 +701,30 @@ export function cleanStaleRuntimeUnits(
|
|
|
627
701
|
|
|
628
702
|
// ─── Worktree ↔ Main Repo Sync (#1311) ──────────────────────────────────────
|
|
629
703
|
|
|
704
|
+
/**
|
|
705
|
+
* Scope-typed variant of syncGsdStateToWorktree.
|
|
706
|
+
*
|
|
707
|
+
* Takes an explicit (rootScope, worktreeScope) pair. Note: milestoneId is not
|
|
708
|
+
* used by syncGsdStateToWorktree — this variant only requires workspace
|
|
709
|
+
* identity. Asserts both scopes belong to the same workspace identity to
|
|
710
|
+
* prevent silent mismatch bugs.
|
|
711
|
+
*/
|
|
712
|
+
export function syncGsdStateToWorktreeByScope(
|
|
713
|
+
rootScope: MilestoneScope,
|
|
714
|
+
worktreeScope: MilestoneScope,
|
|
715
|
+
): { synced: string[] } {
|
|
716
|
+
if (rootScope.workspace.identityKey !== worktreeScope.workspace.identityKey) {
|
|
717
|
+
throw new Error(
|
|
718
|
+
`syncGsdStateToWorktreeByScope: scope identity mismatch — ` +
|
|
719
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}" ` +
|
|
720
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}"`,
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
const mainBasePath = rootScope.workspace.projectRoot;
|
|
724
|
+
const worktreePath_ = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
725
|
+
return syncGsdStateToWorktree(mainBasePath, worktreePath_);
|
|
726
|
+
}
|
|
727
|
+
|
|
630
728
|
/**
|
|
631
729
|
* Sync .gsd/ state from the main repo into the worktree.
|
|
632
730
|
*
|
|
@@ -638,15 +736,19 @@ export function cleanStaleRuntimeUnits(
|
|
|
638
736
|
* missing milestones, CONTEXT, ROADMAP, DECISIONS, REQUIREMENTS, and
|
|
639
737
|
* PROJECT files from the main repo's .gsd/ into the worktree's .gsd/.
|
|
640
738
|
*
|
|
641
|
-
* Only adds missing content — never overwrites existing files in the worktree
|
|
642
|
-
*
|
|
739
|
+
* Only adds missing content — never overwrites existing files in the worktree.
|
|
740
|
+
* Worktree files are compatibility projections; DB/project root remains
|
|
741
|
+
* authoritative for runtime state.
|
|
742
|
+
* @deprecated Use syncGsdStateToWorktreeByScope instead.
|
|
743
|
+
* TODO(C-future): remove once all callers migrated.
|
|
643
744
|
*/
|
|
644
745
|
export function syncGsdStateToWorktree(
|
|
645
746
|
mainBasePath: string,
|
|
646
747
|
worktreePath_: string,
|
|
647
748
|
): { synced: string[] } {
|
|
648
|
-
const
|
|
649
|
-
const
|
|
749
|
+
const contract = resolveGsdPathContract(worktreePath_, mainBasePath);
|
|
750
|
+
const mainGsd = contract.projectGsd;
|
|
751
|
+
const wtGsd = contract.worktreeGsd ?? join(worktreePath_, ".gsd");
|
|
650
752
|
const synced: string[] = [];
|
|
651
753
|
|
|
652
754
|
// If both resolve to the same directory (symlink), no sync needed
|
|
@@ -790,32 +892,26 @@ export function syncGsdStateToWorktree(
|
|
|
790
892
|
}
|
|
791
893
|
|
|
792
894
|
/**
|
|
793
|
-
* Sync
|
|
794
|
-
*
|
|
795
|
-
*
|
|
895
|
+
* Sync compatibility artifacts from worktree back to the main external state
|
|
896
|
+
* directory. Canonical workflow state lives in the project DB; worktree .gsd
|
|
897
|
+
* content is legacy projection/diagnostic data only.
|
|
796
898
|
*
|
|
797
899
|
* Syncs:
|
|
798
|
-
* 1.
|
|
799
|
-
*
|
|
800
|
-
* worktree is the authoritative execution context.
|
|
801
|
-
* 2. ALL milestone directories found in the worktree — not just the
|
|
802
|
-
* current milestoneId. The complete-milestone unit may create artifacts
|
|
803
|
-
* for the *next* milestone (CONTEXT, ROADMAP, new requirements) which
|
|
804
|
-
* must survive worktree teardown.
|
|
900
|
+
* 1. Legacy worktree DBs are reconciled into the canonical project DB.
|
|
901
|
+
* 2. Runtime diagnostic files may be copied for operator visibility.
|
|
805
902
|
*
|
|
806
|
-
*
|
|
807
|
-
*
|
|
808
|
-
*
|
|
809
|
-
* squash merge carries nothing. This caused next-milestone artifacts and
|
|
810
|
-
* updated REQUIREMENTS/PROJECT to be silently lost on teardown.
|
|
903
|
+
* Markdown milestone directories are projections and are not copied from
|
|
904
|
+
* worktrees into the project root. Current workflow state must arrive through
|
|
905
|
+
* the shared project DB or the pre-upgrade DB reconciliation path above.
|
|
811
906
|
*/
|
|
812
907
|
export function syncWorktreeStateBack(
|
|
813
908
|
mainBasePath: string,
|
|
814
909
|
worktreePath: string,
|
|
815
910
|
milestoneId: string,
|
|
816
911
|
): { synced: string[] } {
|
|
817
|
-
const
|
|
818
|
-
const
|
|
912
|
+
const contract = resolveGsdPathContract(worktreePath, mainBasePath);
|
|
913
|
+
const mainGsd = contract.projectGsd;
|
|
914
|
+
const wtGsd = contract.worktreeGsd ?? join(worktreePath, ".gsd");
|
|
819
915
|
const synced: string[] = [];
|
|
820
916
|
|
|
821
917
|
// If both resolve to the same directory (symlink), no sync needed
|
|
@@ -829,7 +925,7 @@ export function syncWorktreeStateBack(
|
|
|
829
925
|
// files. This handles in-flight worktrees that were created before the
|
|
830
926
|
// upgrade to shared WAL mode.
|
|
831
927
|
const wtLocalDb = join(wtGsd, "gsd.db");
|
|
832
|
-
const mainDb =
|
|
928
|
+
const mainDb = contract.projectDb;
|
|
833
929
|
if (existsSync(wtLocalDb) && existsSync(mainDb)) {
|
|
834
930
|
try {
|
|
835
931
|
reconcileWorktreeDb(mainDb, wtLocalDb);
|
|
@@ -840,13 +936,10 @@ export function syncWorktreeStateBack(
|
|
|
840
936
|
}
|
|
841
937
|
}
|
|
842
938
|
|
|
843
|
-
// ── 1. Sync root-level
|
|
844
|
-
//
|
|
845
|
-
//
|
|
846
|
-
|
|
847
|
-
// written during milestone closeout and lost on teardown without explicit sync
|
|
848
|
-
// (#1787, #2313).
|
|
849
|
-
for (const f of ROOT_STATE_FILES) {
|
|
939
|
+
// ── 1. Sync root-level diagnostic files back ─────────────────────────
|
|
940
|
+
// Markdown/JSON state projections remain project-root/DB authoritative.
|
|
941
|
+
// These diagnostic files are copied for observability only.
|
|
942
|
+
for (const f of ROOT_DIAGNOSTIC_FILES) {
|
|
850
943
|
const src = join(wtGsd, f);
|
|
851
944
|
const dst = join(mainGsd, f);
|
|
852
945
|
if (existsSync(src)) {
|
|
@@ -860,121 +953,8 @@ export function syncWorktreeStateBack(
|
|
|
860
953
|
}
|
|
861
954
|
}
|
|
862
955
|
|
|
863
|
-
// ── 2. Sync ALL milestone directories ────────────────────────────────
|
|
864
|
-
// The complete-milestone unit may create next-milestone artifacts (e.g.
|
|
865
|
-
// M007 setup while closing M006). We must sync every milestone directory
|
|
866
|
-
// in the worktree, not just the current one.
|
|
867
|
-
const wtMilestonesDir = join(wtGsd, "milestones");
|
|
868
|
-
if (!existsSync(wtMilestonesDir)) return { synced };
|
|
869
|
-
|
|
870
|
-
try {
|
|
871
|
-
const wtMilestones = readdirSync(wtMilestonesDir, { withFileTypes: true })
|
|
872
|
-
.filter((d) => d.isDirectory())
|
|
873
|
-
.map((d) => d.name);
|
|
874
|
-
|
|
875
|
-
for (const mid of wtMilestones) {
|
|
876
|
-
// Skip the current milestone being merged — its files are already in the
|
|
877
|
-
// milestone branch and would conflict with the squash merge (#3641).
|
|
878
|
-
if (mid === milestoneId) continue;
|
|
879
|
-
syncMilestoneDir(wtGsd, mainGsd, mid, synced);
|
|
880
|
-
}
|
|
881
|
-
} catch (err) {
|
|
882
|
-
/* non-fatal */
|
|
883
|
-
logWarning("worktree", `milestone sync-back failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
884
|
-
}
|
|
885
|
-
|
|
886
956
|
return { synced };
|
|
887
957
|
}
|
|
888
|
-
|
|
889
|
-
function syncCurrentMilestoneStateAfterMerge(
|
|
890
|
-
mainBasePath: string,
|
|
891
|
-
worktreePath: string,
|
|
892
|
-
milestoneId: string,
|
|
893
|
-
): { synced: string[] } {
|
|
894
|
-
const mainGsd = gsdRoot(mainBasePath);
|
|
895
|
-
const wtGsd = gsdRoot(worktreePath);
|
|
896
|
-
const synced: string[] = [];
|
|
897
|
-
|
|
898
|
-
if (isSamePath(mainGsd, wtGsd)) return { synced };
|
|
899
|
-
if (!existsSync(wtGsd) || !existsSync(mainGsd)) return { synced };
|
|
900
|
-
|
|
901
|
-
syncMilestoneDir(wtGsd, mainGsd, milestoneId, synced);
|
|
902
|
-
return { synced };
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
/**
|
|
906
|
-
* Sync a single milestone directory from worktree to main.
|
|
907
|
-
* Copies milestone-level .md files, slice-level files, and task summaries.
|
|
908
|
-
*/
|
|
909
|
-
/** Copy matching files from srcDir to dstDir (non-fatal per file). */
|
|
910
|
-
function syncDirFiles(
|
|
911
|
-
srcDir: string,
|
|
912
|
-
dstDir: string,
|
|
913
|
-
filter: (name: string) => boolean,
|
|
914
|
-
synced: string[],
|
|
915
|
-
prefix: string,
|
|
916
|
-
): void {
|
|
917
|
-
try {
|
|
918
|
-
for (const entry of readdirSync(srcDir, { withFileTypes: true })) {
|
|
919
|
-
if (!entry.isFile() || !filter(entry.name)) continue;
|
|
920
|
-
try {
|
|
921
|
-
cpSync(join(srcDir, entry.name), join(dstDir, entry.name), { force: true });
|
|
922
|
-
synced.push(`${prefix}${entry.name}`);
|
|
923
|
-
} catch (err) {
|
|
924
|
-
/* non-fatal */
|
|
925
|
-
logWarning("worktree", `file copy failed (${prefix}${entry.name}): ${err instanceof Error ? err.message : String(err)}`);
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
} catch (err) {
|
|
929
|
-
/* non-fatal — srcDir may not be readable */
|
|
930
|
-
logWarning("worktree", `directory read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
function syncMilestoneDir(
|
|
935
|
-
wtGsd: string,
|
|
936
|
-
mainGsd: string,
|
|
937
|
-
mid: string,
|
|
938
|
-
synced: string[],
|
|
939
|
-
): void {
|
|
940
|
-
const wtMilestoneDir = join(wtGsd, "milestones", mid);
|
|
941
|
-
const mainMilestoneDir = join(mainGsd, "milestones", mid);
|
|
942
|
-
|
|
943
|
-
if (!existsSync(wtMilestoneDir)) return;
|
|
944
|
-
mkdirSync(mainMilestoneDir, { recursive: true });
|
|
945
|
-
|
|
946
|
-
const isMd = (name: string): boolean => name.endsWith(".md");
|
|
947
|
-
|
|
948
|
-
// Sync milestone-level files (SUMMARY, VALIDATION, ROADMAP, CONTEXT)
|
|
949
|
-
syncDirFiles(wtMilestoneDir, mainMilestoneDir, isMd, synced, `milestones/${mid}/`);
|
|
950
|
-
|
|
951
|
-
// Sync slice-level files (summaries, UATs) and task summaries (#1678)
|
|
952
|
-
const wtSlicesDir = join(wtMilestoneDir, "slices");
|
|
953
|
-
const mainSlicesDir = join(mainMilestoneDir, "slices");
|
|
954
|
-
if (!existsSync(wtSlicesDir)) return;
|
|
955
|
-
|
|
956
|
-
try {
|
|
957
|
-
for (const sliceEntry of readdirSync(wtSlicesDir, { withFileTypes: true })) {
|
|
958
|
-
if (!sliceEntry.isDirectory()) continue;
|
|
959
|
-
const sid = sliceEntry.name;
|
|
960
|
-
const wtSliceDir = join(wtSlicesDir, sid);
|
|
961
|
-
const mainSliceDir = join(mainSlicesDir, sid);
|
|
962
|
-
mkdirSync(mainSliceDir, { recursive: true });
|
|
963
|
-
|
|
964
|
-
syncDirFiles(wtSliceDir, mainSliceDir, isMd, synced, `milestones/${mid}/slices/${sid}/`);
|
|
965
|
-
|
|
966
|
-
const wtTasksDir = join(wtSliceDir, "tasks");
|
|
967
|
-
const mainTasksDir = join(mainSliceDir, "tasks");
|
|
968
|
-
if (existsSync(wtTasksDir)) {
|
|
969
|
-
mkdirSync(mainTasksDir, { recursive: true });
|
|
970
|
-
syncDirFiles(wtTasksDir, mainTasksDir, isMd, synced, `milestones/${mid}/slices/${sid}/tasks/`);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
} catch (err) {
|
|
974
|
-
/* non-fatal */
|
|
975
|
-
logWarning("worktree", `milestone slice sync failed (${mid}): ${err instanceof Error ? err.message : String(err)}`);
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
958
|
// ─── Worktree Post-Create Hook (#597) ────────────────────────────────────────
|
|
979
959
|
|
|
980
960
|
/**
|
|
@@ -1160,10 +1140,43 @@ export function enterBranchModeForMilestone(
|
|
|
1160
1140
|
* directory at the project root and apply any [x] checkbox states that are
|
|
1161
1141
|
* ahead of the worktree version (forward-only: never downgrade [x] → [ ]).
|
|
1162
1142
|
*
|
|
1163
|
-
* This is
|
|
1164
|
-
*
|
|
1165
|
-
*
|
|
1166
|
-
|
|
1143
|
+
* This is forward-only compatibility for legacy projection copies. The DB
|
|
1144
|
+
* remains authoritative; this never downgrades checked boxes in a local
|
|
1145
|
+
* worktree projection.
|
|
1146
|
+
*/
|
|
1147
|
+
/**
|
|
1148
|
+
* Scope-typed variant of reconcilePlanCheckboxes.
|
|
1149
|
+
*
|
|
1150
|
+
* Takes an explicit (rootScope, worktreeScope) pair. milestoneId is taken
|
|
1151
|
+
* from rootScope. Asserts both scopes belong to the same workspace identity
|
|
1152
|
+
* to prevent silent mismatch bugs.
|
|
1153
|
+
*/
|
|
1154
|
+
export function reconcilePlanCheckboxesByScope(
|
|
1155
|
+
rootScope: MilestoneScope,
|
|
1156
|
+
worktreeScope: MilestoneScope,
|
|
1157
|
+
): void {
|
|
1158
|
+
if (rootScope.workspace.identityKey !== worktreeScope.workspace.identityKey) {
|
|
1159
|
+
throw new Error(
|
|
1160
|
+
`reconcilePlanCheckboxesByScope: scope identity mismatch — ` +
|
|
1161
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}" ` +
|
|
1162
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}"`,
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
if (rootScope.milestoneId !== worktreeScope.milestoneId) {
|
|
1166
|
+
throw new Error(
|
|
1167
|
+
`reconcilePlanCheckboxesByScope: milestoneId mismatch — ` +
|
|
1168
|
+
`rootScope.milestoneId="${rootScope.milestoneId}" worktreeScope.milestoneId="${worktreeScope.milestoneId}"`,
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
const projectRoot = rootScope.workspace.projectRoot;
|
|
1172
|
+
const wtPath = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
1173
|
+
const milestoneId = rootScope.milestoneId;
|
|
1174
|
+
reconcilePlanCheckboxes(projectRoot, wtPath, milestoneId);
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/**
|
|
1178
|
+
* @deprecated Use reconcilePlanCheckboxesByScope instead.
|
|
1179
|
+
* TODO(C-future): remove once all callers migrated.
|
|
1167
1180
|
*/
|
|
1168
1181
|
function reconcilePlanCheckboxes(
|
|
1169
1182
|
projectRoot: string,
|
|
@@ -1341,10 +1354,10 @@ export function createAutoWorktree(
|
|
|
1341
1354
|
|
|
1342
1355
|
try {
|
|
1343
1356
|
process.chdir(info.path);
|
|
1344
|
-
|
|
1357
|
+
setActiveWorkspace(createWorkspace(basePath));
|
|
1345
1358
|
} catch (err) {
|
|
1346
1359
|
// If chdir fails, the worktree was created but we couldn't enter it.
|
|
1347
|
-
// Don't
|
|
1360
|
+
// Don't set activeWorkspace -- caller can retry or clean up.
|
|
1348
1361
|
throw new GSDError(
|
|
1349
1362
|
GSD_IO_ERROR,
|
|
1350
1363
|
`Auto-worktree created at ${info.path} but chdir failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -1425,48 +1438,87 @@ export function teardownAutoWorktree(
|
|
|
1425
1438
|
const { preserveBranch = false } = opts;
|
|
1426
1439
|
const previousCwd = process.cwd();
|
|
1427
1440
|
|
|
1441
|
+
// Wrap the entire teardown body in a single try/finally so activeWorkspace
|
|
1442
|
+
// is ALWAYS cleared — even if process.chdir throws (e.g. originalBasePath
|
|
1443
|
+
// was deleted before teardown ran). Previously the finally only covered
|
|
1444
|
+
// removeWorktree, leaving the registry stale on a chdir failure (H3 fix).
|
|
1428
1445
|
try {
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1446
|
+
try {
|
|
1447
|
+
process.chdir(originalBasePath);
|
|
1448
|
+
} catch (err) {
|
|
1449
|
+
throw new GSDError(
|
|
1450
|
+
GSD_IO_ERROR,
|
|
1451
|
+
`Failed to chdir back to ${originalBasePath} during teardown: ${err instanceof Error ? err.message : String(err)}`,
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1437
1454
|
|
|
1438
|
-
|
|
1439
|
-
removeWorktree(originalBasePath, milestoneId, {
|
|
1440
|
-
branch,
|
|
1441
|
-
deleteBranch: !preserveBranch,
|
|
1442
|
-
});
|
|
1455
|
+
// Mirror cleanup steps from mergeMilestoneToMain abort path:
|
|
1443
1456
|
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
);
|
|
1456
|
-
// Attempt a direct filesystem removal as a fallback — but ONLY if the
|
|
1457
|
-
// path is safely inside .gsd/worktrees/ to prevent #2365 data loss.
|
|
1458
|
-
if (isInsideWorktreesDir(originalBasePath, wtDir)) {
|
|
1457
|
+
// 1. Remove transient state files (STATE.md, auto.lock, {MID}-META.json).
|
|
1458
|
+
// Non-fatal — must not block teardown.
|
|
1459
|
+
try {
|
|
1460
|
+
clearProjectRootStateFiles(originalBasePath, milestoneId);
|
|
1461
|
+
} catch (err) {
|
|
1462
|
+
logWarning("worktree", `clearProjectRootStateFiles failed during teardown: ${err instanceof Error ? err.message : String(err)}`);
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// 2. Reconcile worktree-local gsd.db into project root DB if both exist.
|
|
1466
|
+
// Non-fatal — handles legacy worktrees that have a local copy.
|
|
1467
|
+
if (isDbAvailable()) {
|
|
1459
1468
|
try {
|
|
1460
|
-
|
|
1469
|
+
const contract = resolveGsdPathContract(previousCwd, originalBasePath);
|
|
1470
|
+
const worktreeDbPath = join(contract.worktreeGsd ?? join(previousCwd, ".gsd"), "gsd.db");
|
|
1471
|
+
const mainDbPath = contract.projectDb;
|
|
1472
|
+
if (existsSync(worktreeDbPath) && !isSamePath(worktreeDbPath, mainDbPath)) {
|
|
1473
|
+
reconcileWorktreeDb(mainDbPath, worktreeDbPath);
|
|
1474
|
+
}
|
|
1461
1475
|
} catch (err) {
|
|
1462
|
-
|
|
1463
|
-
|
|
1476
|
+
/* non-fatal */
|
|
1477
|
+
logError("worktree", `DB reconciliation failed during teardown: ${err instanceof Error ? err.message : String(err)}`);
|
|
1464
1478
|
}
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
nudgeGitBranchCache(previousCwd);
|
|
1482
|
+
|
|
1483
|
+
// 3. Remove the worktree. Errors propagate naturally — the outer finally
|
|
1484
|
+
// ensures activeWorkspace is cleared regardless.
|
|
1485
|
+
removeWorktree(originalBasePath, milestoneId, {
|
|
1486
|
+
branch,
|
|
1487
|
+
deleteBranch: !preserveBranch,
|
|
1488
|
+
});
|
|
1489
|
+
|
|
1490
|
+
// Verify cleanup succeeded — warn if the worktree directory is still on disk.
|
|
1491
|
+
// On Windows, bash-based cleanup can silently fail when paths contain
|
|
1492
|
+
// backslashes (#1436), leaving ~1 GB+ orphaned directories.
|
|
1493
|
+
const wtDir = worktreePath(originalBasePath, milestoneId);
|
|
1494
|
+
if (existsSync(wtDir)) {
|
|
1495
|
+
logWarning(
|
|
1496
|
+
"reconcile",
|
|
1497
|
+
`Worktree directory still exists after teardown: ${wtDir}. ` +
|
|
1498
|
+
`This is likely an orphaned directory consuming disk space. ` +
|
|
1499
|
+
`Remove it manually with: rm -rf "${wtDir.replaceAll("\\", "/")}"`,
|
|
1500
|
+
{ worktree: milestoneId },
|
|
1468
1501
|
);
|
|
1502
|
+
// Attempt a direct filesystem removal as a fallback — but ONLY if the
|
|
1503
|
+
// path is safely inside .gsd/worktrees/ to prevent #2365 data loss.
|
|
1504
|
+
if (isInsideWorktreesDir(originalBasePath, wtDir)) {
|
|
1505
|
+
try {
|
|
1506
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
1507
|
+
} catch (err) {
|
|
1508
|
+
// Non-fatal — the warning above tells the user how to clean up
|
|
1509
|
+
logWarning("worktree", `worktree directory removal failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1510
|
+
}
|
|
1511
|
+
} else {
|
|
1512
|
+
console.error(
|
|
1513
|
+
`[GSD] REFUSING fallback rmSync — path is outside .gsd/worktrees/: ${wtDir}`,
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1469
1516
|
}
|
|
1517
|
+
} finally {
|
|
1518
|
+
// Clear module state unconditionally — regardless of which step above
|
|
1519
|
+
// failed. A stale activeWorkspace causes getActiveAutoWorktreeContext()
|
|
1520
|
+
// to return wrong data for subsequent operations.
|
|
1521
|
+
setActiveWorkspace(null);
|
|
1470
1522
|
}
|
|
1471
1523
|
}
|
|
1472
1524
|
|
|
@@ -1479,8 +1531,9 @@ export function isInAutoWorktree(basePath: string): boolean {
|
|
|
1479
1531
|
const targetPath = isGsdWorktreePath(basePath) ? basePath : process.cwd();
|
|
1480
1532
|
if (!isGsdWorktreePath(targetPath)) return false;
|
|
1481
1533
|
|
|
1482
|
-
const
|
|
1483
|
-
const
|
|
1534
|
+
const storedBase = getAutoWorktreeOriginalBase();
|
|
1535
|
+
const projectRoot = resolveWorktreeProjectRoot(basePath, storedBase);
|
|
1536
|
+
const targetProjectRoot = resolveWorktreeProjectRoot(targetPath, storedBase);
|
|
1484
1537
|
if (
|
|
1485
1538
|
normalizeWorktreePathForCompare(projectRoot) !==
|
|
1486
1539
|
normalizeWorktreePathForCompare(targetProjectRoot)
|
|
@@ -1576,7 +1629,7 @@ export function enterAutoWorktree(
|
|
|
1576
1629
|
|
|
1577
1630
|
try {
|
|
1578
1631
|
process.chdir(p);
|
|
1579
|
-
|
|
1632
|
+
setActiveWorkspace(createWorkspace(basePath));
|
|
1580
1633
|
} catch (err) {
|
|
1581
1634
|
throw new GSDError(
|
|
1582
1635
|
GSD_IO_ERROR,
|
|
@@ -1593,11 +1646,11 @@ export function enterAutoWorktree(
|
|
|
1593
1646
|
* Returns null if not currently in an auto-worktree.
|
|
1594
1647
|
*/
|
|
1595
1648
|
export function getAutoWorktreeOriginalBase(): string | null {
|
|
1596
|
-
return
|
|
1649
|
+
return getActiveWorkspace()?.projectRoot ?? null;
|
|
1597
1650
|
}
|
|
1598
1651
|
|
|
1599
1652
|
export function _resetAutoWorktreeOriginalBaseForTests(): void {
|
|
1600
|
-
|
|
1653
|
+
setActiveWorkspace(null);
|
|
1601
1654
|
}
|
|
1602
1655
|
|
|
1603
1656
|
export function getActiveAutoWorktreeContext(): {
|
|
@@ -1605,7 +1658,9 @@ export function getActiveAutoWorktreeContext(): {
|
|
|
1605
1658
|
worktreeName: string;
|
|
1606
1659
|
branch: string;
|
|
1607
1660
|
} | null {
|
|
1608
|
-
|
|
1661
|
+
const ws = getActiveWorkspace();
|
|
1662
|
+
if (!ws) return null;
|
|
1663
|
+
const originalBase = ws.projectRoot;
|
|
1609
1664
|
const cwd = process.cwd();
|
|
1610
1665
|
if (!isGsdWorktreePath(cwd)) return null;
|
|
1611
1666
|
const cwdProjectRoot = resolveWorktreeProjectRoot(cwd, originalBase);
|
|
@@ -1686,11 +1741,11 @@ export function mergeMilestoneToMain(
|
|
|
1686
1741
|
// integration branch captures dirty files from OTHER milestones under a
|
|
1687
1742
|
// misleading commit message, contaminating the main branch (#2929).
|
|
1688
1743
|
//
|
|
1689
|
-
// When
|
|
1744
|
+
// When activeWorkspace is null (branch mode, no worktree), autoCommitDirtyState
|
|
1690
1745
|
// runs unconditionally — the caller is responsible for cwd placement.
|
|
1691
1746
|
{
|
|
1692
1747
|
let shouldAutoCommit = true;
|
|
1693
|
-
if (
|
|
1748
|
+
if (getActiveWorkspace() !== null) {
|
|
1694
1749
|
try {
|
|
1695
1750
|
const currentBranch = nativeGetCurrentBranch(worktreeCwd);
|
|
1696
1751
|
shouldAutoCommit = currentBranch === milestoneBranch;
|
|
@@ -1710,9 +1765,10 @@ export function mergeMilestoneToMain(
|
|
|
1710
1765
|
// database (#2823).
|
|
1711
1766
|
if (isDbAvailable()) {
|
|
1712
1767
|
try {
|
|
1713
|
-
const
|
|
1714
|
-
const
|
|
1715
|
-
|
|
1768
|
+
const contract = resolveGsdPathContract(worktreeCwd, originalBasePath_);
|
|
1769
|
+
const worktreeDbPath = join(contract.worktreeGsd ?? join(worktreeCwd, ".gsd"), "gsd.db");
|
|
1770
|
+
const mainDbPath = contract.projectDb;
|
|
1771
|
+
if (existsSync(worktreeDbPath) && !isSamePath(worktreeDbPath, mainDbPath)) {
|
|
1716
1772
|
reconcileWorktreeDb(mainDbPath, worktreeDbPath);
|
|
1717
1773
|
}
|
|
1718
1774
|
} catch (err) {
|
|
@@ -2248,27 +2304,6 @@ export function mergeMilestoneToMain(
|
|
|
2248
2304
|
// 9a-iii. Restore sheltered queued milestone directories (#2505).
|
|
2249
2305
|
restoreShelter();
|
|
2250
2306
|
|
|
2251
|
-
// 9a-iv. Preserve current milestone artifacts that may be untracked in git.
|
|
2252
|
-
// syncWorktreeStateBack intentionally skips the current milestone before the
|
|
2253
|
-
// squash merge to avoid conflicting with the merge content. Once the squash
|
|
2254
|
-
// commit is complete, copy those files back so summaries, validation, and
|
|
2255
|
-
// task outputs survive worktree teardown in external/.gitignored .gsd setups.
|
|
2256
|
-
try {
|
|
2257
|
-
const { synced } = syncCurrentMilestoneStateAfterMerge(
|
|
2258
|
-
originalBasePath_,
|
|
2259
|
-
worktreeCwd,
|
|
2260
|
-
milestoneId,
|
|
2261
|
-
);
|
|
2262
|
-
if (synced.length > 0) {
|
|
2263
|
-
debugLog("mergeMilestoneToMain", {
|
|
2264
|
-
phase: "current-milestone-sync-after-merge",
|
|
2265
|
-
synced: synced.length,
|
|
2266
|
-
});
|
|
2267
|
-
}
|
|
2268
|
-
} catch (err) {
|
|
2269
|
-
logWarning("worktree", `current milestone sync after merge failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
2307
|
// 9b. Safety check (#1792): if nothing was committed, verify the milestone
|
|
2273
2308
|
// work is already on the integration branch before allowing teardown.
|
|
2274
2309
|
// Compare only non-.gsd/ paths — .gsd/ state files diverge normally and
|
|
@@ -2445,7 +2480,7 @@ export function mergeMilestoneToMain(
|
|
|
2445
2480
|
}
|
|
2446
2481
|
|
|
2447
2482
|
// 14. Clear module state
|
|
2448
|
-
|
|
2483
|
+
setActiveWorkspace(null);
|
|
2449
2484
|
nudgeGitBranchCache(previousCwd);
|
|
2450
2485
|
|
|
2451
2486
|
// 15. Anchor cwd at the project root on success-return. Step 12 removed
|