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
|
@@ -12,7 +12,7 @@ import { reconcileWorktreeDb, isDbAvailable, getMilestone, getMilestoneSlices, c
|
|
|
12
12
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
13
13
|
import { execFileSync } from "node:child_process";
|
|
14
14
|
import { safeCopy, safeCopyRecursive } from "./safe-fs.js";
|
|
15
|
-
import { gsdRoot } from "./paths.js";
|
|
15
|
+
import { gsdRoot, resolveGsdPathContract } from "./paths.js";
|
|
16
16
|
import { createWorktree, removeWorktree, resolveGitDir, worktreePath, isInsideWorktreesDir, } from "./worktree-manager.js";
|
|
17
17
|
import { detectWorktreeName, nudgeGitBranchCache, } from "./worktree.js";
|
|
18
18
|
import { isGsdWorktreePath, normalizeWorktreePathForCompare, resolveWorktreeProjectRoot, } from "./worktree-root.js";
|
|
@@ -23,6 +23,7 @@ import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
|
23
23
|
import { MILESTONE_ID_RE } from "./milestone-ids.js";
|
|
24
24
|
import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeWorkingTreeStatus, nativeAddAllWithExclusions, nativeCommit, nativeCheckoutBranch, nativeMergeSquash, nativeConflictFiles, nativeCheckoutTheirs, nativeAddPaths, nativeRmForce, nativeBranchDelete, nativeBranchForceReset, nativeBranchExists, nativeDiffNumstat, nativeUpdateRef, nativeIsAncestor, nativeMergeAbort, } from "./native-git-bridge.js";
|
|
25
25
|
import { gsdHome } from "./gsd-home.js";
|
|
26
|
+
import { createWorkspace } from "./workspace.js";
|
|
26
27
|
const PROJECT_PREFERENCES_FILE = "PREFERENCES.md";
|
|
27
28
|
const LEGACY_PROJECT_PREFERENCES_FILE = "preferences.md";
|
|
28
29
|
const LEGACY_DEEP_SETUP_RUNTIME_UNIT_FILES = new Set([
|
|
@@ -34,9 +35,8 @@ const LEGACY_DEEP_SETUP_RUNTIME_UNIT_FILES = new Set([
|
|
|
34
35
|
]);
|
|
35
36
|
// ─── Shared Constants & Helpers ─────────────────────────────────────────────
|
|
36
37
|
/**
|
|
37
|
-
* Root-level .gsd/
|
|
38
|
-
*
|
|
39
|
-
* and the dispatch-level sync functions.
|
|
38
|
+
* Root-level .gsd/ projections copied from project root into worktrees for
|
|
39
|
+
* compatibility. Project root remains the canonical state/projection root.
|
|
40
40
|
*/
|
|
41
41
|
const ROOT_STATE_FILES = [
|
|
42
42
|
"DECISIONS.md",
|
|
@@ -53,6 +53,10 @@ const ROOT_STATE_FILES = [
|
|
|
53
53
|
// Back-sync (worktree → main) must NEVER overwrite the project root's copy
|
|
54
54
|
// because the project root is authoritative for preferences (#2684).
|
|
55
55
|
];
|
|
56
|
+
const ROOT_DIAGNOSTIC_FILES = [
|
|
57
|
+
"completed-units.json",
|
|
58
|
+
"metrics.json",
|
|
59
|
+
];
|
|
56
60
|
/**
|
|
57
61
|
* Pop a stash entry by tracking the unique marker embedded in its message so
|
|
58
62
|
* concurrent stash operations against the same project root cannot cause us to
|
|
@@ -137,7 +141,7 @@ const VERDICT_RE = /verdict:\s*[\w-]+/i;
|
|
|
137
141
|
* destination when the source copy contains a `verdict:` field.
|
|
138
142
|
*
|
|
139
143
|
* This is the targeted fix for the UAT stuck-loop (#2821): the main
|
|
140
|
-
* safeCopyRecursive uses force:false to protect worktree-
|
|
144
|
+
* safeCopyRecursive uses force:false to protect worktree-local projection
|
|
141
145
|
* files (#1886), but ASSESSMENT files written by run-uat must be
|
|
142
146
|
* forward-synced when the project root has a verdict. Without this,
|
|
143
147
|
* the worktree retains a stale FAIL or missing ASSESSMENT and
|
|
@@ -192,8 +196,14 @@ function forceOverwriteAssessmentsWithVerdict(srcMilestoneDir, dstMilestoneDir)
|
|
|
192
196
|
}
|
|
193
197
|
}
|
|
194
198
|
// ─── Module State ──────────────────────────────────────────────────────────
|
|
195
|
-
/**
|
|
196
|
-
let
|
|
199
|
+
/** Active workspace registry — replaces the legacy `originalBase` singleton. */
|
|
200
|
+
let activeWorkspace = null;
|
|
201
|
+
function setActiveWorkspace(ws) {
|
|
202
|
+
activeWorkspace = ws;
|
|
203
|
+
}
|
|
204
|
+
function getActiveWorkspace() {
|
|
205
|
+
return activeWorkspace;
|
|
206
|
+
}
|
|
197
207
|
function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
198
208
|
const gsdDir = gsdRoot(basePath);
|
|
199
209
|
const transientFiles = [
|
|
@@ -212,9 +222,9 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
|
212
222
|
}
|
|
213
223
|
}
|
|
214
224
|
}
|
|
215
|
-
// Clean up
|
|
216
|
-
//
|
|
217
|
-
//
|
|
225
|
+
// Clean up legacy synced milestone directories and runtime/units.
|
|
226
|
+
// Older versions copied these into the project root during execution.
|
|
227
|
+
// If they remain as untracked files when we attempt
|
|
218
228
|
// `git merge --squash`, git rejects the merge with "local changes would
|
|
219
229
|
// be overwritten", causing silent data loss (#1738).
|
|
220
230
|
const syncedDirs = [
|
|
@@ -272,13 +282,41 @@ export const isSafeToAutoResolve = (filePath) => filePath.startsWith(".gsd/") ||
|
|
|
272
282
|
* gsd.db in the worktree so it rebuilds from fresh disk state (#853).
|
|
273
283
|
* Non-fatal — sync failure should never block dispatch.
|
|
274
284
|
*/
|
|
285
|
+
/**
|
|
286
|
+
* Scope-typed variant of syncProjectRootToWorktree.
|
|
287
|
+
*
|
|
288
|
+
* Takes an explicit (rootScope, worktreeScope) pair where rootScope is the
|
|
289
|
+
* project root and worktreeScope is the auto-worktree. Direction is encoded
|
|
290
|
+
* in argument order. Asserts both scopes belong to the same workspace identity
|
|
291
|
+
* to prevent silent mismatch bugs.
|
|
292
|
+
*/
|
|
293
|
+
export function syncProjectRootToWorktreeByScope(rootScope, worktreeScope) {
|
|
294
|
+
if (rootScope.workspace.identityKey !== worktreeScope.workspace.identityKey) {
|
|
295
|
+
throw new Error(`syncProjectRootToWorktreeByScope: scope identity mismatch — ` +
|
|
296
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}" ` +
|
|
297
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}"`);
|
|
298
|
+
}
|
|
299
|
+
if (rootScope.milestoneId !== worktreeScope.milestoneId) {
|
|
300
|
+
throw new Error(`syncProjectRootToWorktreeByScope: milestoneId mismatch — ` +
|
|
301
|
+
`rootScope.milestoneId="${rootScope.milestoneId}" worktreeScope.milestoneId="${worktreeScope.milestoneId}"`);
|
|
302
|
+
}
|
|
303
|
+
const projectRoot = rootScope.workspace.projectRoot;
|
|
304
|
+
const worktreePath_ = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
305
|
+
const milestoneId = rootScope.milestoneId;
|
|
306
|
+
syncProjectRootToWorktree(projectRoot, worktreePath_, milestoneId);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* @deprecated Use syncProjectRootToWorktreeByScope instead.
|
|
310
|
+
* TODO(C-future): remove once all callers migrated.
|
|
311
|
+
*/
|
|
275
312
|
export function syncProjectRootToWorktree(projectRoot, worktreePath_, milestoneId) {
|
|
276
313
|
if (!worktreePath_ || !projectRoot || worktreePath_ === projectRoot)
|
|
277
314
|
return;
|
|
278
315
|
if (!milestoneId)
|
|
279
316
|
return;
|
|
280
|
-
const
|
|
281
|
-
const
|
|
317
|
+
const contract = resolveGsdPathContract(worktreePath_, projectRoot);
|
|
318
|
+
const prGsd = contract.projectGsd;
|
|
319
|
+
const wtGsd = contract.worktreeGsd ?? join(worktreePath_, ".gsd");
|
|
282
320
|
// When .gsd is a symlink to the same external directory in both locations,
|
|
283
321
|
// cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
|
|
284
322
|
// Compare realpaths and skip when they resolve to the same physical path (#2184).
|
|
@@ -286,12 +324,12 @@ export function syncProjectRootToWorktree(projectRoot, worktreePath_, milestoneI
|
|
|
286
324
|
return;
|
|
287
325
|
// Copy milestone directory from project root to worktree — additive only.
|
|
288
326
|
// force:false prevents cpSync from overwriting existing worktree files.
|
|
289
|
-
// Without this, worktree-
|
|
327
|
+
// Without this, worktree-local files (e.g. VALIDATION.md written
|
|
290
328
|
// by validate-milestone) get clobbered by stale project root copies,
|
|
291
329
|
// causing an infinite re-validation loop (#1886).
|
|
292
330
|
safeCopyRecursive(join(prGsd, "milestones", milestoneId), join(wtGsd, "milestones", milestoneId), { force: false });
|
|
293
331
|
// Force-sync ASSESSMENT files that have a verdict from project root (#2821).
|
|
294
|
-
// The additive-only copy above preserves worktree-
|
|
332
|
+
// The additive-only copy above preserves worktree-local files, but
|
|
295
333
|
// ASSESSMENT files are special: after run-uat writes a verdict and post-unit
|
|
296
334
|
// syncs it to the project root, the worktree may retain a stale copy (e.g.
|
|
297
335
|
// verdict:fail while the project root has verdict:pass from a retry). On
|
|
@@ -303,11 +341,9 @@ export function syncProjectRootToWorktree(projectRoot, worktreePath_, milestoneI
|
|
|
303
341
|
// Project root is authoritative for completion state after crash recovery;
|
|
304
342
|
// without this, the worktree re-dispatches already-completed units (#1886).
|
|
305
343
|
safeCopy(join(prGsd, "completed-units.json"), join(wtGsd, "completed-units.json"), { force: true });
|
|
306
|
-
// Delete worktree gsd.db ONLY if it is empty (0 bytes).
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
// preserved — deleting it truncates the file to 0 bytes when
|
|
310
|
-
// openDatabase re-creates it, causing "no such table" failures (#2815).
|
|
344
|
+
// Delete a legacy worktree-local gsd.db ONLY if it is empty (0 bytes).
|
|
345
|
+
// Runtime opens contract.projectDb; this cleanup only removes corrupt
|
|
346
|
+
// pre-upgrade local DB projections.
|
|
311
347
|
try {
|
|
312
348
|
const wtDb = join(wtGsd, "gsd.db");
|
|
313
349
|
let deleteSidecars = false;
|
|
@@ -342,33 +378,57 @@ export function syncProjectRootToWorktree(projectRoot, worktreePath_, milestoneI
|
|
|
342
378
|
}
|
|
343
379
|
}
|
|
344
380
|
/**
|
|
345
|
-
*
|
|
381
|
+
* Scope-typed variant of syncStateToProjectRoot.
|
|
382
|
+
*
|
|
383
|
+
* Takes an explicit (worktreeScope, rootScope) pair. Direction is encoded in
|
|
384
|
+
* argument order (worktree → root). Asserts both scopes belong to the same
|
|
385
|
+
* workspace identity to prevent silent mismatch bugs.
|
|
386
|
+
*/
|
|
387
|
+
export function syncStateToProjectRootByScope(worktreeScope, rootScope) {
|
|
388
|
+
if (worktreeScope.workspace.identityKey !== rootScope.workspace.identityKey) {
|
|
389
|
+
throw new Error(`syncStateToProjectRootByScope: scope identity mismatch — ` +
|
|
390
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}" ` +
|
|
391
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}"`);
|
|
392
|
+
}
|
|
393
|
+
if (worktreeScope.milestoneId !== rootScope.milestoneId) {
|
|
394
|
+
throw new Error(`syncStateToProjectRootByScope: milestoneId mismatch — ` +
|
|
395
|
+
`worktreeScope.milestoneId="${worktreeScope.milestoneId}" rootScope.milestoneId="${rootScope.milestoneId}"`);
|
|
396
|
+
}
|
|
397
|
+
const worktreePath_ = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
398
|
+
const projectRoot = rootScope.workspace.projectRoot;
|
|
399
|
+
const milestoneId = worktreeScope.milestoneId;
|
|
400
|
+
syncStateToProjectRoot(worktreePath_, projectRoot, milestoneId);
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Sync worktree diagnostics from worktree to project root.
|
|
346
404
|
* Only runs when inside an auto-worktree (worktreePath differs from projectRoot).
|
|
347
|
-
*
|
|
405
|
+
* DB/project-root state remains authoritative; markdown projections are not
|
|
406
|
+
* copied from the worktree back to the project root.
|
|
348
407
|
* Non-fatal — sync failure should never block dispatch.
|
|
408
|
+
* @deprecated Use syncStateToProjectRootByScope instead.
|
|
409
|
+
* TODO(C-future): remove once all callers migrated.
|
|
349
410
|
*/
|
|
350
411
|
export function syncStateToProjectRoot(worktreePath_, projectRoot, milestoneId) {
|
|
351
412
|
if (!worktreePath_ || !projectRoot || worktreePath_ === projectRoot)
|
|
352
413
|
return;
|
|
353
414
|
if (!milestoneId)
|
|
354
415
|
return;
|
|
355
|
-
const
|
|
356
|
-
const
|
|
416
|
+
const contract = resolveGsdPathContract(worktreePath_, projectRoot);
|
|
417
|
+
const wtGsd = contract.worktreeGsd ?? join(worktreePath_, ".gsd");
|
|
418
|
+
const prGsd = contract.projectGsd;
|
|
357
419
|
// When .gsd is a symlink to the same external directory in both locations,
|
|
358
420
|
// cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
|
|
359
421
|
// Compare realpaths and skip when they resolve to the same physical path (#2184).
|
|
360
422
|
if (isSamePath(wtGsd, prGsd))
|
|
361
423
|
return;
|
|
362
|
-
//
|
|
363
|
-
safeCopy(join(wtGsd, "STATE.md"), join(prGsd, "STATE.md"), { force: true });
|
|
364
|
-
// 2. Milestone directory — ROADMAP, slice PLANs, task summaries
|
|
365
|
-
// Copy the entire milestone .gsd subtree so deriveState reads current checkboxes
|
|
366
|
-
safeCopyRecursive(join(wtGsd, "milestones", milestoneId), join(prGsd, "milestones", milestoneId), { force: true });
|
|
367
|
-
// 3. metrics.json — session cost/token tracking (#2313).
|
|
424
|
+
// metrics.json — session cost/token tracking (#2313).
|
|
368
425
|
// Without this, metrics accumulated in the worktree are invisible from the
|
|
369
426
|
// project root and never appear in the dashboard or skill-health reports.
|
|
370
427
|
safeCopy(join(wtGsd, "metrics.json"), join(prGsd, "metrics.json"), { force: true });
|
|
371
|
-
//
|
|
428
|
+
// completed-units.json — runtime completion diagnostics used to avoid
|
|
429
|
+
// re-dispatching work already completed in an isolated worktree.
|
|
430
|
+
safeCopy(join(wtGsd, "completed-units.json"), join(prGsd, "completed-units.json"), { force: true });
|
|
431
|
+
// Runtime records — unit dispatch diagnostics used by selfHealRuntimeRecords().
|
|
372
432
|
// Without this, a crash during a unit leaves the runtime record only in the
|
|
373
433
|
// worktree. If the next session resolves basePath before worktree re-entry,
|
|
374
434
|
// selfHeal can't find or clear the stale record (#769).
|
|
@@ -518,6 +578,24 @@ export function cleanStaleRuntimeUnits(gsdRootPath, hasMilestoneSummary) {
|
|
|
518
578
|
return cleaned;
|
|
519
579
|
}
|
|
520
580
|
// ─── Worktree ↔ Main Repo Sync (#1311) ──────────────────────────────────────
|
|
581
|
+
/**
|
|
582
|
+
* Scope-typed variant of syncGsdStateToWorktree.
|
|
583
|
+
*
|
|
584
|
+
* Takes an explicit (rootScope, worktreeScope) pair. Note: milestoneId is not
|
|
585
|
+
* used by syncGsdStateToWorktree — this variant only requires workspace
|
|
586
|
+
* identity. Asserts both scopes belong to the same workspace identity to
|
|
587
|
+
* prevent silent mismatch bugs.
|
|
588
|
+
*/
|
|
589
|
+
export function syncGsdStateToWorktreeByScope(rootScope, worktreeScope) {
|
|
590
|
+
if (rootScope.workspace.identityKey !== worktreeScope.workspace.identityKey) {
|
|
591
|
+
throw new Error(`syncGsdStateToWorktreeByScope: scope identity mismatch — ` +
|
|
592
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}" ` +
|
|
593
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}"`);
|
|
594
|
+
}
|
|
595
|
+
const mainBasePath = rootScope.workspace.projectRoot;
|
|
596
|
+
const worktreePath_ = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
597
|
+
return syncGsdStateToWorktree(mainBasePath, worktreePath_);
|
|
598
|
+
}
|
|
521
599
|
/**
|
|
522
600
|
* Sync .gsd/ state from the main repo into the worktree.
|
|
523
601
|
*
|
|
@@ -529,12 +607,16 @@ export function cleanStaleRuntimeUnits(gsdRootPath, hasMilestoneSummary) {
|
|
|
529
607
|
* missing milestones, CONTEXT, ROADMAP, DECISIONS, REQUIREMENTS, and
|
|
530
608
|
* PROJECT files from the main repo's .gsd/ into the worktree's .gsd/.
|
|
531
609
|
*
|
|
532
|
-
* Only adds missing content — never overwrites existing files in the worktree
|
|
533
|
-
*
|
|
610
|
+
* Only adds missing content — never overwrites existing files in the worktree.
|
|
611
|
+
* Worktree files are compatibility projections; DB/project root remains
|
|
612
|
+
* authoritative for runtime state.
|
|
613
|
+
* @deprecated Use syncGsdStateToWorktreeByScope instead.
|
|
614
|
+
* TODO(C-future): remove once all callers migrated.
|
|
534
615
|
*/
|
|
535
616
|
export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
536
|
-
const
|
|
537
|
-
const
|
|
617
|
+
const contract = resolveGsdPathContract(worktreePath_, mainBasePath);
|
|
618
|
+
const mainGsd = contract.projectGsd;
|
|
619
|
+
const wtGsd = contract.worktreeGsd ?? join(worktreePath_, ".gsd");
|
|
538
620
|
const synced = [];
|
|
539
621
|
// If both resolve to the same directory (symlink), no sync needed
|
|
540
622
|
if (isSamePath(mainGsd, wtGsd))
|
|
@@ -678,28 +760,22 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
678
760
|
return { synced };
|
|
679
761
|
}
|
|
680
762
|
/**
|
|
681
|
-
* Sync
|
|
682
|
-
*
|
|
683
|
-
*
|
|
763
|
+
* Sync compatibility artifacts from worktree back to the main external state
|
|
764
|
+
* directory. Canonical workflow state lives in the project DB; worktree .gsd
|
|
765
|
+
* content is legacy projection/diagnostic data only.
|
|
684
766
|
*
|
|
685
767
|
* Syncs:
|
|
686
|
-
* 1.
|
|
687
|
-
*
|
|
688
|
-
* worktree is the authoritative execution context.
|
|
689
|
-
* 2. ALL milestone directories found in the worktree — not just the
|
|
690
|
-
* current milestoneId. The complete-milestone unit may create artifacts
|
|
691
|
-
* for the *next* milestone (CONTEXT, ROADMAP, new requirements) which
|
|
692
|
-
* must survive worktree teardown.
|
|
768
|
+
* 1. Legacy worktree DBs are reconciled into the canonical project DB.
|
|
769
|
+
* 2. Runtime diagnostic files may be copied for operator visibility.
|
|
693
770
|
*
|
|
694
|
-
*
|
|
695
|
-
*
|
|
696
|
-
*
|
|
697
|
-
* squash merge carries nothing. This caused next-milestone artifacts and
|
|
698
|
-
* updated REQUIREMENTS/PROJECT to be silently lost on teardown.
|
|
771
|
+
* Markdown milestone directories are projections and are not copied from
|
|
772
|
+
* worktrees into the project root. Current workflow state must arrive through
|
|
773
|
+
* the shared project DB or the pre-upgrade DB reconciliation path above.
|
|
699
774
|
*/
|
|
700
775
|
export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
701
|
-
const
|
|
702
|
-
const
|
|
776
|
+
const contract = resolveGsdPathContract(worktreePath, mainBasePath);
|
|
777
|
+
const mainGsd = contract.projectGsd;
|
|
778
|
+
const wtGsd = contract.worktreeGsd ?? join(worktreePath, ".gsd");
|
|
703
779
|
const synced = [];
|
|
704
780
|
// If both resolve to the same directory (symlink), no sync needed
|
|
705
781
|
if (isSamePath(mainGsd, wtGsd))
|
|
@@ -712,7 +788,7 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
|
712
788
|
// files. This handles in-flight worktrees that were created before the
|
|
713
789
|
// upgrade to shared WAL mode.
|
|
714
790
|
const wtLocalDb = join(wtGsd, "gsd.db");
|
|
715
|
-
const mainDb =
|
|
791
|
+
const mainDb = contract.projectDb;
|
|
716
792
|
if (existsSync(wtLocalDb) && existsSync(mainDb)) {
|
|
717
793
|
try {
|
|
718
794
|
reconcileWorktreeDb(mainDb, wtLocalDb);
|
|
@@ -723,13 +799,10 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
|
723
799
|
logError("worktree", `DB reconciliation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
724
800
|
}
|
|
725
801
|
}
|
|
726
|
-
// ── 1. Sync root-level
|
|
727
|
-
//
|
|
728
|
-
//
|
|
729
|
-
|
|
730
|
-
// written during milestone closeout and lost on teardown without explicit sync
|
|
731
|
-
// (#1787, #2313).
|
|
732
|
-
for (const f of ROOT_STATE_FILES) {
|
|
802
|
+
// ── 1. Sync root-level diagnostic files back ─────────────────────────
|
|
803
|
+
// Markdown/JSON state projections remain project-root/DB authoritative.
|
|
804
|
+
// These diagnostic files are copied for observability only.
|
|
805
|
+
for (const f of ROOT_DIAGNOSTIC_FILES) {
|
|
733
806
|
const src = join(wtGsd, f);
|
|
734
807
|
const dst = join(mainGsd, f);
|
|
735
808
|
if (existsSync(src)) {
|
|
@@ -743,103 +816,8 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
|
743
816
|
}
|
|
744
817
|
}
|
|
745
818
|
}
|
|
746
|
-
// ── 2. Sync ALL milestone directories ────────────────────────────────
|
|
747
|
-
// The complete-milestone unit may create next-milestone artifacts (e.g.
|
|
748
|
-
// M007 setup while closing M006). We must sync every milestone directory
|
|
749
|
-
// in the worktree, not just the current one.
|
|
750
|
-
const wtMilestonesDir = join(wtGsd, "milestones");
|
|
751
|
-
if (!existsSync(wtMilestonesDir))
|
|
752
|
-
return { synced };
|
|
753
|
-
try {
|
|
754
|
-
const wtMilestones = readdirSync(wtMilestonesDir, { withFileTypes: true })
|
|
755
|
-
.filter((d) => d.isDirectory())
|
|
756
|
-
.map((d) => d.name);
|
|
757
|
-
for (const mid of wtMilestones) {
|
|
758
|
-
// Skip the current milestone being merged — its files are already in the
|
|
759
|
-
// milestone branch and would conflict with the squash merge (#3641).
|
|
760
|
-
if (mid === milestoneId)
|
|
761
|
-
continue;
|
|
762
|
-
syncMilestoneDir(wtGsd, mainGsd, mid, synced);
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
catch (err) {
|
|
766
|
-
/* non-fatal */
|
|
767
|
-
logWarning("worktree", `milestone sync-back failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
768
|
-
}
|
|
769
819
|
return { synced };
|
|
770
820
|
}
|
|
771
|
-
function syncCurrentMilestoneStateAfterMerge(mainBasePath, worktreePath, milestoneId) {
|
|
772
|
-
const mainGsd = gsdRoot(mainBasePath);
|
|
773
|
-
const wtGsd = gsdRoot(worktreePath);
|
|
774
|
-
const synced = [];
|
|
775
|
-
if (isSamePath(mainGsd, wtGsd))
|
|
776
|
-
return { synced };
|
|
777
|
-
if (!existsSync(wtGsd) || !existsSync(mainGsd))
|
|
778
|
-
return { synced };
|
|
779
|
-
syncMilestoneDir(wtGsd, mainGsd, milestoneId, synced);
|
|
780
|
-
return { synced };
|
|
781
|
-
}
|
|
782
|
-
/**
|
|
783
|
-
* Sync a single milestone directory from worktree to main.
|
|
784
|
-
* Copies milestone-level .md files, slice-level files, and task summaries.
|
|
785
|
-
*/
|
|
786
|
-
/** Copy matching files from srcDir to dstDir (non-fatal per file). */
|
|
787
|
-
function syncDirFiles(srcDir, dstDir, filter, synced, prefix) {
|
|
788
|
-
try {
|
|
789
|
-
for (const entry of readdirSync(srcDir, { withFileTypes: true })) {
|
|
790
|
-
if (!entry.isFile() || !filter(entry.name))
|
|
791
|
-
continue;
|
|
792
|
-
try {
|
|
793
|
-
cpSync(join(srcDir, entry.name), join(dstDir, entry.name), { force: true });
|
|
794
|
-
synced.push(`${prefix}${entry.name}`);
|
|
795
|
-
}
|
|
796
|
-
catch (err) {
|
|
797
|
-
/* non-fatal */
|
|
798
|
-
logWarning("worktree", `file copy failed (${prefix}${entry.name}): ${err instanceof Error ? err.message : String(err)}`);
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
catch (err) {
|
|
803
|
-
/* non-fatal — srcDir may not be readable */
|
|
804
|
-
logWarning("worktree", `directory read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
function syncMilestoneDir(wtGsd, mainGsd, mid, synced) {
|
|
808
|
-
const wtMilestoneDir = join(wtGsd, "milestones", mid);
|
|
809
|
-
const mainMilestoneDir = join(mainGsd, "milestones", mid);
|
|
810
|
-
if (!existsSync(wtMilestoneDir))
|
|
811
|
-
return;
|
|
812
|
-
mkdirSync(mainMilestoneDir, { recursive: true });
|
|
813
|
-
const isMd = (name) => name.endsWith(".md");
|
|
814
|
-
// Sync milestone-level files (SUMMARY, VALIDATION, ROADMAP, CONTEXT)
|
|
815
|
-
syncDirFiles(wtMilestoneDir, mainMilestoneDir, isMd, synced, `milestones/${mid}/`);
|
|
816
|
-
// Sync slice-level files (summaries, UATs) and task summaries (#1678)
|
|
817
|
-
const wtSlicesDir = join(wtMilestoneDir, "slices");
|
|
818
|
-
const mainSlicesDir = join(mainMilestoneDir, "slices");
|
|
819
|
-
if (!existsSync(wtSlicesDir))
|
|
820
|
-
return;
|
|
821
|
-
try {
|
|
822
|
-
for (const sliceEntry of readdirSync(wtSlicesDir, { withFileTypes: true })) {
|
|
823
|
-
if (!sliceEntry.isDirectory())
|
|
824
|
-
continue;
|
|
825
|
-
const sid = sliceEntry.name;
|
|
826
|
-
const wtSliceDir = join(wtSlicesDir, sid);
|
|
827
|
-
const mainSliceDir = join(mainSlicesDir, sid);
|
|
828
|
-
mkdirSync(mainSliceDir, { recursive: true });
|
|
829
|
-
syncDirFiles(wtSliceDir, mainSliceDir, isMd, synced, `milestones/${mid}/slices/${sid}/`);
|
|
830
|
-
const wtTasksDir = join(wtSliceDir, "tasks");
|
|
831
|
-
const mainTasksDir = join(mainSliceDir, "tasks");
|
|
832
|
-
if (existsSync(wtTasksDir)) {
|
|
833
|
-
mkdirSync(mainTasksDir, { recursive: true });
|
|
834
|
-
syncDirFiles(wtTasksDir, mainTasksDir, isMd, synced, `milestones/${mid}/slices/${sid}/tasks/`);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
catch (err) {
|
|
839
|
-
/* non-fatal */
|
|
840
|
-
logWarning("worktree", `milestone slice sync failed (${mid}): ${err instanceof Error ? err.message : String(err)}`);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
821
|
// ─── Worktree Post-Create Hook (#597) ────────────────────────────────────────
|
|
844
822
|
/**
|
|
845
823
|
* Run the user-configured post-create hook script after worktree creation.
|
|
@@ -1002,10 +980,35 @@ export function enterBranchModeForMilestone(basePath, milestoneId) {
|
|
|
1002
980
|
* directory at the project root and apply any [x] checkbox states that are
|
|
1003
981
|
* ahead of the worktree version (forward-only: never downgrade [x] → [ ]).
|
|
1004
982
|
*
|
|
1005
|
-
* This is
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1008
|
-
|
|
983
|
+
* This is forward-only compatibility for legacy projection copies. The DB
|
|
984
|
+
* remains authoritative; this never downgrades checked boxes in a local
|
|
985
|
+
* worktree projection.
|
|
986
|
+
*/
|
|
987
|
+
/**
|
|
988
|
+
* Scope-typed variant of reconcilePlanCheckboxes.
|
|
989
|
+
*
|
|
990
|
+
* Takes an explicit (rootScope, worktreeScope) pair. milestoneId is taken
|
|
991
|
+
* from rootScope. Asserts both scopes belong to the same workspace identity
|
|
992
|
+
* to prevent silent mismatch bugs.
|
|
993
|
+
*/
|
|
994
|
+
export function reconcilePlanCheckboxesByScope(rootScope, worktreeScope) {
|
|
995
|
+
if (rootScope.workspace.identityKey !== worktreeScope.workspace.identityKey) {
|
|
996
|
+
throw new Error(`reconcilePlanCheckboxesByScope: scope identity mismatch — ` +
|
|
997
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}" ` +
|
|
998
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}"`);
|
|
999
|
+
}
|
|
1000
|
+
if (rootScope.milestoneId !== worktreeScope.milestoneId) {
|
|
1001
|
+
throw new Error(`reconcilePlanCheckboxesByScope: milestoneId mismatch — ` +
|
|
1002
|
+
`rootScope.milestoneId="${rootScope.milestoneId}" worktreeScope.milestoneId="${worktreeScope.milestoneId}"`);
|
|
1003
|
+
}
|
|
1004
|
+
const projectRoot = rootScope.workspace.projectRoot;
|
|
1005
|
+
const wtPath = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
1006
|
+
const milestoneId = rootScope.milestoneId;
|
|
1007
|
+
reconcilePlanCheckboxes(projectRoot, wtPath, milestoneId);
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* @deprecated Use reconcilePlanCheckboxesByScope instead.
|
|
1011
|
+
* TODO(C-future): remove once all callers migrated.
|
|
1009
1012
|
*/
|
|
1010
1013
|
function reconcilePlanCheckboxes(projectRoot, wtPath, milestoneId) {
|
|
1011
1014
|
const srcMilestone = join(projectRoot, ".gsd", "milestones", milestoneId);
|
|
@@ -1160,11 +1163,11 @@ export function createAutoWorktree(basePath, milestoneId) {
|
|
|
1160
1163
|
const previousCwd = process.cwd();
|
|
1161
1164
|
try {
|
|
1162
1165
|
process.chdir(info.path);
|
|
1163
|
-
|
|
1166
|
+
setActiveWorkspace(createWorkspace(basePath));
|
|
1164
1167
|
}
|
|
1165
1168
|
catch (err) {
|
|
1166
1169
|
// If chdir fails, the worktree was created but we couldn't enter it.
|
|
1167
|
-
// Don't
|
|
1170
|
+
// Don't set activeWorkspace -- caller can retry or clean up.
|
|
1168
1171
|
throw new GSDError(GSD_IO_ERROR, `Auto-worktree created at ${info.path} but chdir failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1169
1172
|
}
|
|
1170
1173
|
nudgeGitBranchCache(previousCwd);
|
|
@@ -1224,41 +1227,79 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
|
|
|
1224
1227
|
const branch = autoWorktreeBranch(milestoneId);
|
|
1225
1228
|
const { preserveBranch = false } = opts;
|
|
1226
1229
|
const previousCwd = process.cwd();
|
|
1230
|
+
// Wrap the entire teardown body in a single try/finally so activeWorkspace
|
|
1231
|
+
// is ALWAYS cleared — even if process.chdir throws (e.g. originalBasePath
|
|
1232
|
+
// was deleted before teardown ran). Previously the finally only covered
|
|
1233
|
+
// removeWorktree, leaving the registry stale on a chdir failure (H3 fix).
|
|
1227
1234
|
try {
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
`Remove it manually with: rm -rf "${wtDir.replaceAll("\\", "/")}"`, { worktree: milestoneId });
|
|
1247
|
-
// Attempt a direct filesystem removal as a fallback — but ONLY if the
|
|
1248
|
-
// path is safely inside .gsd/worktrees/ to prevent #2365 data loss.
|
|
1249
|
-
if (isInsideWorktreesDir(originalBasePath, wtDir)) {
|
|
1235
|
+
try {
|
|
1236
|
+
process.chdir(originalBasePath);
|
|
1237
|
+
}
|
|
1238
|
+
catch (err) {
|
|
1239
|
+
throw new GSDError(GSD_IO_ERROR, `Failed to chdir back to ${originalBasePath} during teardown: ${err instanceof Error ? err.message : String(err)}`);
|
|
1240
|
+
}
|
|
1241
|
+
// Mirror cleanup steps from mergeMilestoneToMain abort path:
|
|
1242
|
+
// 1. Remove transient state files (STATE.md, auto.lock, {MID}-META.json).
|
|
1243
|
+
// Non-fatal — must not block teardown.
|
|
1244
|
+
try {
|
|
1245
|
+
clearProjectRootStateFiles(originalBasePath, milestoneId);
|
|
1246
|
+
}
|
|
1247
|
+
catch (err) {
|
|
1248
|
+
logWarning("worktree", `clearProjectRootStateFiles failed during teardown: ${err instanceof Error ? err.message : String(err)}`);
|
|
1249
|
+
}
|
|
1250
|
+
// 2. Reconcile worktree-local gsd.db into project root DB if both exist.
|
|
1251
|
+
// Non-fatal — handles legacy worktrees that have a local copy.
|
|
1252
|
+
if (isDbAvailable()) {
|
|
1250
1253
|
try {
|
|
1251
|
-
|
|
1254
|
+
const contract = resolveGsdPathContract(previousCwd, originalBasePath);
|
|
1255
|
+
const worktreeDbPath = join(contract.worktreeGsd ?? join(previousCwd, ".gsd"), "gsd.db");
|
|
1256
|
+
const mainDbPath = contract.projectDb;
|
|
1257
|
+
if (existsSync(worktreeDbPath) && !isSamePath(worktreeDbPath, mainDbPath)) {
|
|
1258
|
+
reconcileWorktreeDb(mainDbPath, worktreeDbPath);
|
|
1259
|
+
}
|
|
1252
1260
|
}
|
|
1253
1261
|
catch (err) {
|
|
1254
|
-
|
|
1255
|
-
|
|
1262
|
+
/* non-fatal */
|
|
1263
|
+
logError("worktree", `DB reconciliation failed during teardown: ${err instanceof Error ? err.message : String(err)}`);
|
|
1256
1264
|
}
|
|
1257
1265
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1266
|
+
nudgeGitBranchCache(previousCwd);
|
|
1267
|
+
// 3. Remove the worktree. Errors propagate naturally — the outer finally
|
|
1268
|
+
// ensures activeWorkspace is cleared regardless.
|
|
1269
|
+
removeWorktree(originalBasePath, milestoneId, {
|
|
1270
|
+
branch,
|
|
1271
|
+
deleteBranch: !preserveBranch,
|
|
1272
|
+
});
|
|
1273
|
+
// Verify cleanup succeeded — warn if the worktree directory is still on disk.
|
|
1274
|
+
// On Windows, bash-based cleanup can silently fail when paths contain
|
|
1275
|
+
// backslashes (#1436), leaving ~1 GB+ orphaned directories.
|
|
1276
|
+
const wtDir = worktreePath(originalBasePath, milestoneId);
|
|
1277
|
+
if (existsSync(wtDir)) {
|
|
1278
|
+
logWarning("reconcile", `Worktree directory still exists after teardown: ${wtDir}. ` +
|
|
1279
|
+
`This is likely an orphaned directory consuming disk space. ` +
|
|
1280
|
+
`Remove it manually with: rm -rf "${wtDir.replaceAll("\\", "/")}"`, { worktree: milestoneId });
|
|
1281
|
+
// Attempt a direct filesystem removal as a fallback — but ONLY if the
|
|
1282
|
+
// path is safely inside .gsd/worktrees/ to prevent #2365 data loss.
|
|
1283
|
+
if (isInsideWorktreesDir(originalBasePath, wtDir)) {
|
|
1284
|
+
try {
|
|
1285
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
1286
|
+
}
|
|
1287
|
+
catch (err) {
|
|
1288
|
+
// Non-fatal — the warning above tells the user how to clean up
|
|
1289
|
+
logWarning("worktree", `worktree directory removal failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
else {
|
|
1293
|
+
console.error(`[GSD] REFUSING fallback rmSync — path is outside .gsd/worktrees/: ${wtDir}`);
|
|
1294
|
+
}
|
|
1260
1295
|
}
|
|
1261
1296
|
}
|
|
1297
|
+
finally {
|
|
1298
|
+
// Clear module state unconditionally — regardless of which step above
|
|
1299
|
+
// failed. A stale activeWorkspace causes getActiveAutoWorktreeContext()
|
|
1300
|
+
// to return wrong data for subsequent operations.
|
|
1301
|
+
setActiveWorkspace(null);
|
|
1302
|
+
}
|
|
1262
1303
|
}
|
|
1263
1304
|
/**
|
|
1264
1305
|
* Detect if the process is currently inside an auto-worktree.
|
|
@@ -1269,8 +1310,9 @@ export function isInAutoWorktree(basePath) {
|
|
|
1269
1310
|
const targetPath = isGsdWorktreePath(basePath) ? basePath : process.cwd();
|
|
1270
1311
|
if (!isGsdWorktreePath(targetPath))
|
|
1271
1312
|
return false;
|
|
1272
|
-
const
|
|
1273
|
-
const
|
|
1313
|
+
const storedBase = getAutoWorktreeOriginalBase();
|
|
1314
|
+
const projectRoot = resolveWorktreeProjectRoot(basePath, storedBase);
|
|
1315
|
+
const targetProjectRoot = resolveWorktreeProjectRoot(targetPath, storedBase);
|
|
1274
1316
|
if (normalizeWorktreePathForCompare(projectRoot) !==
|
|
1275
1317
|
normalizeWorktreePathForCompare(targetProjectRoot)) {
|
|
1276
1318
|
return false;
|
|
@@ -1343,7 +1385,7 @@ export function enterAutoWorktree(basePath, milestoneId) {
|
|
|
1343
1385
|
const previousCwd = process.cwd();
|
|
1344
1386
|
try {
|
|
1345
1387
|
process.chdir(p);
|
|
1346
|
-
|
|
1388
|
+
setActiveWorkspace(createWorkspace(basePath));
|
|
1347
1389
|
}
|
|
1348
1390
|
catch (err) {
|
|
1349
1391
|
throw new GSDError(GSD_IO_ERROR, `Failed to enter auto-worktree at ${p}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -1356,14 +1398,16 @@ export function enterAutoWorktree(basePath, milestoneId) {
|
|
|
1356
1398
|
* Returns null if not currently in an auto-worktree.
|
|
1357
1399
|
*/
|
|
1358
1400
|
export function getAutoWorktreeOriginalBase() {
|
|
1359
|
-
return
|
|
1401
|
+
return getActiveWorkspace()?.projectRoot ?? null;
|
|
1360
1402
|
}
|
|
1361
1403
|
export function _resetAutoWorktreeOriginalBaseForTests() {
|
|
1362
|
-
|
|
1404
|
+
setActiveWorkspace(null);
|
|
1363
1405
|
}
|
|
1364
1406
|
export function getActiveAutoWorktreeContext() {
|
|
1365
|
-
|
|
1407
|
+
const ws = getActiveWorkspace();
|
|
1408
|
+
if (!ws)
|
|
1366
1409
|
return null;
|
|
1410
|
+
const originalBase = ws.projectRoot;
|
|
1367
1411
|
const cwd = process.cwd();
|
|
1368
1412
|
if (!isGsdWorktreePath(cwd))
|
|
1369
1413
|
return null;
|
|
@@ -1433,11 +1477,11 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1433
1477
|
// integration branch captures dirty files from OTHER milestones under a
|
|
1434
1478
|
// misleading commit message, contaminating the main branch (#2929).
|
|
1435
1479
|
//
|
|
1436
|
-
// When
|
|
1480
|
+
// When activeWorkspace is null (branch mode, no worktree), autoCommitDirtyState
|
|
1437
1481
|
// runs unconditionally — the caller is responsible for cwd placement.
|
|
1438
1482
|
{
|
|
1439
1483
|
let shouldAutoCommit = true;
|
|
1440
|
-
if (
|
|
1484
|
+
if (getActiveWorkspace() !== null) {
|
|
1441
1485
|
try {
|
|
1442
1486
|
const currentBranch = nativeGetCurrentBranch(worktreeCwd);
|
|
1443
1487
|
shouldAutoCommit = currentBranch === milestoneBranch;
|
|
@@ -1457,9 +1501,10 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1457
1501
|
// database (#2823).
|
|
1458
1502
|
if (isDbAvailable()) {
|
|
1459
1503
|
try {
|
|
1460
|
-
const
|
|
1461
|
-
const
|
|
1462
|
-
|
|
1504
|
+
const contract = resolveGsdPathContract(worktreeCwd, originalBasePath_);
|
|
1505
|
+
const worktreeDbPath = join(contract.worktreeGsd ?? join(worktreeCwd, ".gsd"), "gsd.db");
|
|
1506
|
+
const mainDbPath = contract.projectDb;
|
|
1507
|
+
if (existsSync(worktreeDbPath) && !isSamePath(worktreeDbPath, mainDbPath)) {
|
|
1463
1508
|
reconcileWorktreeDb(mainDbPath, worktreeDbPath);
|
|
1464
1509
|
}
|
|
1465
1510
|
}
|
|
@@ -1964,23 +2009,6 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1964
2009
|
}
|
|
1965
2010
|
// 9a-iii. Restore sheltered queued milestone directories (#2505).
|
|
1966
2011
|
restoreShelter();
|
|
1967
|
-
// 9a-iv. Preserve current milestone artifacts that may be untracked in git.
|
|
1968
|
-
// syncWorktreeStateBack intentionally skips the current milestone before the
|
|
1969
|
-
// squash merge to avoid conflicting with the merge content. Once the squash
|
|
1970
|
-
// commit is complete, copy those files back so summaries, validation, and
|
|
1971
|
-
// task outputs survive worktree teardown in external/.gitignored .gsd setups.
|
|
1972
|
-
try {
|
|
1973
|
-
const { synced } = syncCurrentMilestoneStateAfterMerge(originalBasePath_, worktreeCwd, milestoneId);
|
|
1974
|
-
if (synced.length > 0) {
|
|
1975
|
-
debugLog("mergeMilestoneToMain", {
|
|
1976
|
-
phase: "current-milestone-sync-after-merge",
|
|
1977
|
-
synced: synced.length,
|
|
1978
|
-
});
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1981
|
-
catch (err) {
|
|
1982
|
-
logWarning("worktree", `current milestone sync after merge failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1983
|
-
}
|
|
1984
2012
|
// 9b. Safety check (#1792): if nothing was committed, verify the milestone
|
|
1985
2013
|
// work is already on the integration branch before allowing teardown.
|
|
1986
2014
|
// Compare only non-.gsd/ paths — .gsd/ state files diverge normally and
|
|
@@ -2137,7 +2165,7 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
2137
2165
|
logWarning("worktree", `git branch-delete failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2138
2166
|
}
|
|
2139
2167
|
// 14. Clear module state
|
|
2140
|
-
|
|
2168
|
+
setActiveWorkspace(null);
|
|
2141
2169
|
nudgeGitBranchCache(previousCwd);
|
|
2142
2170
|
// 15. Anchor cwd at the project root on success-return. Step 12 removed
|
|
2143
2171
|
// the worktree dir; if cwd was inside it, every subsequent process.cwd()
|