gsd-pi 2.81.0 → 2.82.0-dev.20138ae42
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 +64 -33
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +116 -13
- package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
- package/dist/resources/extensions/gsd/auto/phases.js +220 -98
- package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
- package/dist/resources/extensions/gsd/auto/session.js +9 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +247 -178
- package/dist/resources/extensions/gsd/auto-dispatch.js +27 -17
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +240 -128
- package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
- package/dist/resources/extensions/gsd/auto-recovery.js +34 -179
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
- package/dist/resources/extensions/gsd/auto-start.js +105 -35
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
- package/dist/resources/extensions/gsd/auto-verification.js +38 -26
- package/dist/resources/extensions/gsd/auto-worktree.js +119 -1
- package/dist/resources/extensions/gsd/auto.js +400 -108
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +38 -12
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -4
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +38 -1
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/git-service.js +41 -2
- package/dist/resources/extensions/gsd/gsd-db.js +8 -23
- package/dist/resources/extensions/gsd/guided-flow.js +93 -111
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
- package/dist/resources/extensions/gsd/health-widget.js +4 -10
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -96
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +62 -26
- package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
- package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
- package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +28 -10
- package/dist/resources/extensions/gsd/prompts/discuss.md +29 -11
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
- package/dist/resources/extensions/gsd/session-lock.js +40 -0
- package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +252 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +45 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +82 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
- package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
- package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
- package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
- package/dist/resources/extensions/gsd/status-guards.js +4 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/resources/extensions/gsd/templates/plan.md +8 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
- package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +769 -319
- package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +5 -8
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -8
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- 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/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/dist/welcome-screen.d.ts +0 -7
- package/dist/welcome-screen.js +60 -69
- package/package.json +6 -5
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +14 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +33 -42
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +33 -44
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
- package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.js +9 -6
- package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
- package/packages/pi-tui/src/overlay-layout.ts +10 -7
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +105 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +27 -26
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +10 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
- package/src/resources/extensions/gsd/auto/loop.ts +121 -14
- package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
- package/src/resources/extensions/gsd/auto/phases.ts +180 -20
- package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
- package/src/resources/extensions/gsd/auto/session.ts +10 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +301 -183
- package/src/resources/extensions/gsd/auto-dispatch.ts +29 -7
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +273 -140
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
- package/src/resources/extensions/gsd/auto-recovery.ts +36 -209
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +114 -31
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
- package/src/resources/extensions/gsd/auto-verification.ts +46 -38
- package/src/resources/extensions/gsd/auto-worktree.ts +127 -1
- package/src/resources/extensions/gsd/auto.ts +441 -107
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +54 -12
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +16 -4
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +41 -1
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/git-service.ts +47 -1
- package/src/resources/extensions/gsd/gsd-db.ts +10 -23
- package/src/resources/extensions/gsd/guided-flow.ts +126 -128
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
- package/src/resources/extensions/gsd/health-widget.ts +6 -10
- package/src/resources/extensions/gsd/journal.ts +2 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +10 -96
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +68 -25
- package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
- package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
- package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +28 -10
- package/src/resources/extensions/gsd/prompts/discuss.md +29 -11
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
- package/src/resources/extensions/gsd/session-lock.ts +41 -0
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +344 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +66 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +101 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
- package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
- package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
- package/src/resources/extensions/gsd/status-guards.ts +5 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/templates/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +783 -176
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +292 -4
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +20 -5
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +79 -4
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +17 -7
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +129 -1
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
- package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +81 -3
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +71 -58
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +1048 -0
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +211 -59
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +597 -118
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +72 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
- package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +1196 -518
- package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-9ecfd95f343793f0.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/page-200592a7f3baf579.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → xRy4LqKSNKdT7y6ATYyEl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → xRy4LqKSNKdT7y6ATYyEl}/_ssgManifest.js +0 -0
|
@@ -16,18 +16,44 @@
|
|
|
16
16
|
* call the same body during its internal `mergeAndEnterNext` recursion without
|
|
17
17
|
* a circular reference. Both classes share the body until the Resolver retires.
|
|
18
18
|
*/
|
|
19
|
-
import { existsSync, unlinkSync } from "node:fs";
|
|
19
|
+
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
20
20
|
import { randomUUID } from "node:crypto";
|
|
21
21
|
import { join } from "node:path";
|
|
22
22
|
import { debugLog } from "./debug-logger.js";
|
|
23
|
+
import { logWarning } from "./workflow-logger.js";
|
|
23
24
|
import { emitJournalEvent } from "./journal.js";
|
|
24
25
|
import { emitWorktreeCreated, emitWorktreeMerged } from "./worktree-telemetry.js";
|
|
25
26
|
import { resolveWorktreeProjectRoot, normalizeWorktreePathForCompare, } from "./worktree-root.js";
|
|
26
27
|
import { claimMilestoneLease, refreshMilestoneLease, releaseMilestoneLease, } from "./db/milestone-leases.js";
|
|
27
28
|
import { MergeConflictError } from "./git-service.js";
|
|
28
29
|
import { getCollapseCadence, getMilestoneResquash, resquashMilestoneOnMain, } from "./slice-cadence.js";
|
|
29
|
-
|
|
30
|
+
// ADR-016 phase 2 / C3 (#5626): cache + preferences + path helpers inlined
|
|
31
|
+
// as direct imports. They are leaf-level functions that do not vary across
|
|
32
|
+
// callers — production wiring previously injected them via deps; the seam
|
|
33
|
+
// added type churn without enabling test variation.
|
|
34
|
+
import { loadEffectiveGSDPreferences, getIsolationMode } from "./preferences.js";
|
|
35
|
+
import { invalidateAllCaches } from "./cache.js";
|
|
36
|
+
import { resolveMilestoneFile } from "./paths.js";
|
|
30
37
|
import { createWorkspace, scopeMilestone } from "./workspace.js";
|
|
38
|
+
// ADR-016 phase 2 / C1 (#5624): file-system + git-CLI leaf primitives
|
|
39
|
+
// inlined as direct imports rather than injected through `WorktreeLifecycleDeps`.
|
|
40
|
+
// These four symbols (`readFileSync` from node:fs, `getCurrentBranch` and
|
|
41
|
+
// `autoCommitCurrentBranch` from `./worktree.js`, `nativeCheckoutBranch` from
|
|
42
|
+
// `./native-git-bridge.js`) are leaf-level primitives — no environment varies
|
|
43
|
+
// across callers — so the dependency-injection seam they used to inhabit was
|
|
44
|
+
// adding type churn without enabling any test variation.
|
|
45
|
+
import { autoCommitCurrentBranch, getCurrentBranch, } from "./worktree.js";
|
|
46
|
+
import { nativeCheckoutBranch } from "./native-git-bridge.js";
|
|
47
|
+
// ADR-016 phase 2 / C2 (#5625): worktree-manager helpers inlined from
|
|
48
|
+
// `./auto-worktree.js`. These seven functions are not real seams — Lifecycle
|
|
49
|
+
// is the only Module that calls them, and they live alongside the Module's
|
|
50
|
+
// other primitives in `auto-worktree.ts`.
|
|
51
|
+
import { autoWorktreeBranch, createAutoWorktree, enterAutoWorktree, enterBranchModeForMilestone, getAutoWorktreePath, isInAutoWorktree, teardownAutoWorktree, } from "./auto-worktree.js";
|
|
52
|
+
const recentWorktreeMergeFailures = new Map();
|
|
53
|
+
const MERGE_FAILURE_DEDUPE_MS = 60_000;
|
|
54
|
+
export function resetRecentWorktreeMergeFailuresForTest() {
|
|
55
|
+
recentWorktreeMergeFailures.clear();
|
|
56
|
+
}
|
|
31
57
|
/**
|
|
32
58
|
* Internal sentinel — thrown by `_mergeBranchMode` when it has already
|
|
33
59
|
* emitted a user-visible error. The outer `mergeAndExit` catches the type
|
|
@@ -59,6 +85,85 @@ function isValidMilestoneId(milestoneId) {
|
|
|
59
85
|
function invalidMilestoneIdError(milestoneId) {
|
|
60
86
|
return new Error(`Invalid milestoneId: ${milestoneId} — contains path separators or traversal`);
|
|
61
87
|
}
|
|
88
|
+
function primitiveOverrides(deps) {
|
|
89
|
+
return deps;
|
|
90
|
+
}
|
|
91
|
+
function readLifecycleFile(deps, path) {
|
|
92
|
+
return primitiveOverrides(deps).readFileSync?.(path, "utf-8") ??
|
|
93
|
+
readFileSync(path, "utf-8");
|
|
94
|
+
}
|
|
95
|
+
function currentLifecycleBranch(deps, basePath) {
|
|
96
|
+
return primitiveOverrides(deps).getCurrentBranch?.(basePath) ??
|
|
97
|
+
getCurrentBranch(basePath);
|
|
98
|
+
}
|
|
99
|
+
function checkoutLifecycleBranch(deps, basePath, branch) {
|
|
100
|
+
const checkoutBranch = primitiveOverrides(deps).checkoutBranch;
|
|
101
|
+
if (checkoutBranch) {
|
|
102
|
+
checkoutBranch(basePath, branch);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
nativeCheckoutBranch(basePath, branch);
|
|
106
|
+
}
|
|
107
|
+
function autoCommitLifecycleBranch(deps, basePath, unitType, unitId) {
|
|
108
|
+
return primitiveOverrides(deps).autoCommitCurrentBranch?.(basePath, unitType, unitId) ?? autoCommitCurrentBranch(basePath, unitType, unitId);
|
|
109
|
+
}
|
|
110
|
+
// ADR-016 phase 2 / C2-inlined worktree-manager primitives — helpers that
|
|
111
|
+
// honour the structural-typing override pattern so legacy test fixtures keep
|
|
112
|
+
// working without rewriting them onto real-git fixtures.
|
|
113
|
+
function lifecycleIsInAutoWorktree(deps, basePath) {
|
|
114
|
+
return primitiveOverrides(deps).isInAutoWorktree?.(basePath) ??
|
|
115
|
+
isInAutoWorktree(basePath);
|
|
116
|
+
}
|
|
117
|
+
function lifecycleAutoWorktreeBranch(deps, milestoneId) {
|
|
118
|
+
return primitiveOverrides(deps).autoWorktreeBranch?.(milestoneId) ??
|
|
119
|
+
autoWorktreeBranch(milestoneId);
|
|
120
|
+
}
|
|
121
|
+
function lifecycleTeardownAutoWorktree(deps, basePath, milestoneId, opts) {
|
|
122
|
+
const override = primitiveOverrides(deps).teardownAutoWorktree;
|
|
123
|
+
if (override) {
|
|
124
|
+
override(basePath, milestoneId, opts);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
teardownAutoWorktree(basePath, milestoneId, opts);
|
|
128
|
+
}
|
|
129
|
+
function lifecycleCreateAutoWorktree(deps, basePath, milestoneId) {
|
|
130
|
+
return primitiveOverrides(deps).createAutoWorktree?.(basePath, milestoneId) ??
|
|
131
|
+
createAutoWorktree(basePath, milestoneId);
|
|
132
|
+
}
|
|
133
|
+
function lifecycleEnterAutoWorktree(deps, basePath, milestoneId) {
|
|
134
|
+
return primitiveOverrides(deps).enterAutoWorktree?.(basePath, milestoneId) ??
|
|
135
|
+
enterAutoWorktree(basePath, milestoneId);
|
|
136
|
+
}
|
|
137
|
+
function lifecycleEnterBranchMode(deps, basePath, milestoneId) {
|
|
138
|
+
const override = primitiveOverrides(deps).enterBranchModeForMilestone;
|
|
139
|
+
if (override) {
|
|
140
|
+
override(basePath, milestoneId);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
enterBranchModeForMilestone(basePath, milestoneId);
|
|
144
|
+
}
|
|
145
|
+
// ADR-016 phase 2 / C3-inlined cache + preferences + path helpers.
|
|
146
|
+
function lifecycleGetIsolationMode(deps, basePath) {
|
|
147
|
+
return primitiveOverrides(deps).getIsolationMode?.(basePath) ??
|
|
148
|
+
getIsolationMode(basePath);
|
|
149
|
+
}
|
|
150
|
+
function lifecycleInvalidateAllCaches(deps) {
|
|
151
|
+
const override = primitiveOverrides(deps).invalidateAllCaches;
|
|
152
|
+
if (override) {
|
|
153
|
+
override();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
invalidateAllCaches();
|
|
157
|
+
}
|
|
158
|
+
function lifecycleResolveMilestoneFile(deps, basePath, milestoneId, fileType) {
|
|
159
|
+
return primitiveOverrides(deps).resolveMilestoneFile?.(basePath, milestoneId, fileType) ?? resolveMilestoneFile(basePath, milestoneId, fileType);
|
|
160
|
+
}
|
|
161
|
+
function lifecycleLoadPreferences(deps, basePath) {
|
|
162
|
+
const override = primitiveOverrides(deps).loadEffectiveGSDPreferences;
|
|
163
|
+
if (override)
|
|
164
|
+
return override(basePath);
|
|
165
|
+
return loadEffectiveGSDPreferences(basePath);
|
|
166
|
+
}
|
|
62
167
|
/**
|
|
63
168
|
* Throwing variant used by the merge/exit paths that surface failures via
|
|
64
169
|
* the typed `ExitResult` (callers wrap the throw → cause). The enter path
|
|
@@ -109,7 +214,7 @@ export function _enterMilestoneCore(s, deps, milestoneId, ctx) {
|
|
|
109
214
|
}
|
|
110
215
|
// Phase B: claim a milestone lease before any worktree mutation. Two
|
|
111
216
|
// workers cannot enter the same milestone concurrently. Best-effort:
|
|
112
|
-
//
|
|
217
|
+
// warn if no worker registered (single-worker fallback) or skip if DB
|
|
113
218
|
// unavailable; reuse existing lease if we already hold it on this
|
|
114
219
|
// milestone (re-entry within the same session).
|
|
115
220
|
if (s.workerId) {
|
|
@@ -189,11 +294,14 @@ export function _enterMilestoneCore(s, deps, milestoneId, ctx) {
|
|
|
189
294
|
}
|
|
190
295
|
}
|
|
191
296
|
}
|
|
297
|
+
else {
|
|
298
|
+
logWarning("worktree", `enterMilestone(${milestoneId}) ran before auto worker registration; milestone lease was not claimed.`);
|
|
299
|
+
}
|
|
192
300
|
// Resolve the project root for worktree operations via shared helper.
|
|
193
301
|
// Handles the case where originalBasePath is falsy and basePath is itself
|
|
194
302
|
// a worktree path — prevents double-nested worktree paths (#3729).
|
|
195
303
|
const basePath = resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
|
|
196
|
-
const mode =
|
|
304
|
+
const mode = getIsolationMode(basePath);
|
|
197
305
|
if (mode === "none") {
|
|
198
306
|
debugLog("WorktreeLifecycle", {
|
|
199
307
|
action: "enterMilestone",
|
|
@@ -231,12 +339,12 @@ export function _enterMilestoneCore(s, deps, milestoneId, ctx) {
|
|
|
231
339
|
// ── Branch mode: create/checkout milestone branch, stay in project root ──
|
|
232
340
|
if (mode === "branch") {
|
|
233
341
|
try {
|
|
234
|
-
deps
|
|
342
|
+
lifecycleEnterBranchMode(deps, basePath, milestoneId);
|
|
235
343
|
// basePath does not change — no worktree, no chdir.
|
|
236
344
|
// Rebuild GitService so the new HEAD is reflected, then flush any
|
|
237
345
|
// path-keyed caches that may have been populated before the checkout.
|
|
238
346
|
rebuildGitService(s, deps);
|
|
239
|
-
|
|
347
|
+
invalidateAllCaches();
|
|
240
348
|
debugLog("WorktreeLifecycle", {
|
|
241
349
|
action: "enterMilestone",
|
|
242
350
|
milestoneId,
|
|
@@ -269,17 +377,17 @@ export function _enterMilestoneCore(s, deps, milestoneId, ctx) {
|
|
|
269
377
|
}
|
|
270
378
|
// ── Worktree mode ────────────────────────────────────────────────────────
|
|
271
379
|
try {
|
|
272
|
-
const existingPath = deps.getAutoWorktreePath(basePath, milestoneId);
|
|
380
|
+
const existingPath = (primitiveOverrides(deps).getAutoWorktreePath ?? getAutoWorktreePath)(basePath, milestoneId);
|
|
273
381
|
let wtPath;
|
|
274
382
|
if (existingPath) {
|
|
275
|
-
wtPath = deps
|
|
383
|
+
wtPath = lifecycleEnterAutoWorktree(deps, basePath, milestoneId);
|
|
276
384
|
}
|
|
277
385
|
else {
|
|
278
|
-
wtPath = deps
|
|
386
|
+
wtPath = lifecycleCreateAutoWorktree(deps, basePath, milestoneId);
|
|
279
387
|
}
|
|
280
388
|
s.basePath = wtPath;
|
|
281
389
|
rebuildGitService(s, deps);
|
|
282
|
-
|
|
390
|
+
invalidateAllCaches();
|
|
283
391
|
// Per ADR-016: Lifecycle calls Projection on entry, before any Unit
|
|
284
392
|
// dispatches. Build a temporary scope from the new basePath; callers may
|
|
285
393
|
// later set s.scope via their own rebuildScope hook (the two are
|
|
@@ -354,9 +462,427 @@ export function _enterMilestoneCore(s, deps, milestoneId, ctx) {
|
|
|
354
462
|
return { ok: false, reason: "creation-failed", cause: err };
|
|
355
463
|
}
|
|
356
464
|
}
|
|
465
|
+
/**
|
|
466
|
+
* Resolve the basePath to adopt on resume from a paused session.
|
|
467
|
+
*
|
|
468
|
+
* Returns `persistedWorktreePath` when the path is non-null and exists on
|
|
469
|
+
* disk; otherwise falls back to `base`. Used by
|
|
470
|
+
* `WorktreeLifecycle.resumeFromPausedSession` (#5621). Exported as a pure
|
|
471
|
+
* function so unit tests can exercise the path-resolution logic without
|
|
472
|
+
* constructing a `WorktreeLifecycle` instance.
|
|
473
|
+
*
|
|
474
|
+
* The optional `pathExists` parameter exists only for tests that need to
|
|
475
|
+
* substitute a stub for `existsSync`.
|
|
476
|
+
*/
|
|
477
|
+
export function resolvePausedResumeBasePath(base, persistedWorktreePath, pathExists = existsSync) {
|
|
478
|
+
return persistedWorktreePath && pathExists(persistedWorktreePath)
|
|
479
|
+
? persistedWorktreePath
|
|
480
|
+
: base;
|
|
481
|
+
}
|
|
357
482
|
function rebuildGitService(s, deps) {
|
|
358
|
-
|
|
359
|
-
|
|
483
|
+
// ADR-016 phase 2 / C4 (#5627): the gitConfig load and constructor
|
|
484
|
+
// construction live behind `gitServiceFactory`. Lifecycle no longer
|
|
485
|
+
// sees the constructor shape, the gitConfig type, or the unknown→
|
|
486
|
+
// GitService cast.
|
|
487
|
+
s.gitService = deps.gitServiceFactory(s.basePath);
|
|
488
|
+
}
|
|
489
|
+
function emitWorktreeMergeFailedOnce(basePath, milestoneId, err) {
|
|
490
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
491
|
+
const errorCategory = err instanceof Error ? err.name : "Error";
|
|
492
|
+
const now = Date.now();
|
|
493
|
+
const key = `${basePath}\0${milestoneId}\0${errorCategory}`;
|
|
494
|
+
const previous = recentWorktreeMergeFailures.get(key);
|
|
495
|
+
if (previous && now - previous < MERGE_FAILURE_DEDUPE_MS)
|
|
496
|
+
return;
|
|
497
|
+
for (const [candidate, ts] of recentWorktreeMergeFailures) {
|
|
498
|
+
if (now - ts >= MERGE_FAILURE_DEDUPE_MS) {
|
|
499
|
+
recentWorktreeMergeFailures.delete(candidate);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
emitJournalEvent(basePath, {
|
|
503
|
+
ts: new Date().toISOString(),
|
|
504
|
+
flowId: randomUUID(),
|
|
505
|
+
seq: 0,
|
|
506
|
+
eventType: "worktree-merge-failed",
|
|
507
|
+
data: { milestoneId, error: msg },
|
|
508
|
+
});
|
|
509
|
+
recentWorktreeMergeFailures.set(key, now);
|
|
510
|
+
}
|
|
511
|
+
// ─── Session-less merge entry (ADR-016 phase 2 / A1) ─────────────────────
|
|
512
|
+
/**
|
|
513
|
+
* Worktree-mode merge body. Session-less — operates on a `MergeContext`.
|
|
514
|
+
*
|
|
515
|
+
* On error: emits the "worktree-merge-failed" journal event, notifies the
|
|
516
|
+
* user, cleans up stale `SQUASH_MSG` / `MERGE_HEAD` / `MERGE_MSG` files
|
|
517
|
+
* (#1389), and chdirs back to project root before rethrowing. Session-side
|
|
518
|
+
* cleanup (`restoreToProjectRoot`, `gitService` rebuild) is the caller's
|
|
519
|
+
* responsibility.
|
|
520
|
+
*/
|
|
521
|
+
function _mergeWorktreeModeImpl(deps, mctx) {
|
|
522
|
+
const { originalBasePath, worktreeBasePath, milestoneId, notify } = mctx;
|
|
523
|
+
if (!originalBasePath) {
|
|
524
|
+
debugLog("WorktreeLifecycle", {
|
|
525
|
+
action: "mergeAndExit",
|
|
526
|
+
milestoneId,
|
|
527
|
+
mode: "worktree",
|
|
528
|
+
skipped: true,
|
|
529
|
+
reason: "missing-original-base",
|
|
530
|
+
});
|
|
531
|
+
return {
|
|
532
|
+
merged: false,
|
|
533
|
+
mode: "worktree",
|
|
534
|
+
codeFilesChanged: false,
|
|
535
|
+
pushed: false,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
try {
|
|
539
|
+
// ADR-016: final projection before teardown. Replaces the legacy
|
|
540
|
+
// syncWorktreeStateBack(originalBase, basePath, milestoneId) call.
|
|
541
|
+
const finalScope = scopeMilestone(createWorkspace(worktreeBasePath), milestoneId);
|
|
542
|
+
const { synced } = deps.worktreeProjection.finalizeProjectionForMerge(finalScope);
|
|
543
|
+
if (synced.length > 0) {
|
|
544
|
+
debugLog("WorktreeLifecycle", {
|
|
545
|
+
action: "mergeAndExit",
|
|
546
|
+
milestoneId,
|
|
547
|
+
phase: "reverse-sync",
|
|
548
|
+
synced: synced.length,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
// Resolve roadmap — try project root first, then worktree path as
|
|
552
|
+
// fallback. The worktree may hold the only copy when state-back
|
|
553
|
+
// projection silently dropped it or .gsd/ is not symlinked. Without
|
|
554
|
+
// the fallback, a missing roadmap triggers bare teardown which
|
|
555
|
+
// deletes the branch and orphans all milestone commits (#1573).
|
|
556
|
+
let roadmapPath = resolveMilestoneFile(originalBasePath, milestoneId, "ROADMAP");
|
|
557
|
+
if (!roadmapPath &&
|
|
558
|
+
!isSamePathPhysical(worktreeBasePath, originalBasePath)) {
|
|
559
|
+
roadmapPath = resolveMilestoneFile(worktreeBasePath, milestoneId, "ROADMAP");
|
|
560
|
+
if (roadmapPath) {
|
|
561
|
+
debugLog("WorktreeLifecycle", {
|
|
562
|
+
action: "mergeAndExit",
|
|
563
|
+
milestoneId,
|
|
564
|
+
phase: "roadmap-fallback",
|
|
565
|
+
note: "resolved from worktree path",
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (!roadmapPath) {
|
|
570
|
+
// No roadmap at either location — teardown but PRESERVE the branch
|
|
571
|
+
// so commits are not orphaned (#1573).
|
|
572
|
+
lifecycleTeardownAutoWorktree(deps, originalBasePath, milestoneId, {
|
|
573
|
+
preserveBranch: true,
|
|
574
|
+
});
|
|
575
|
+
notify(`Exited worktree for ${milestoneId} (no roadmap found — branch preserved for manual merge).`, "warning");
|
|
576
|
+
return {
|
|
577
|
+
merged: false,
|
|
578
|
+
mode: "worktree",
|
|
579
|
+
codeFilesChanged: false,
|
|
580
|
+
pushed: false,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const roadmapContent = readLifecycleFile(deps, roadmapPath);
|
|
584
|
+
const mergeResult = deps.mergeMilestoneToMain(originalBasePath, milestoneId, roadmapContent);
|
|
585
|
+
// #2945 Bug 3: mergeMilestoneToMain performs best-effort worktree
|
|
586
|
+
// cleanup internally (step 12), but it can silently fail on Windows
|
|
587
|
+
// or when the worktree directory is locked. Perform a secondary
|
|
588
|
+
// teardown here to ensure the worktree is properly cleaned up.
|
|
589
|
+
// Idempotent — if already removed, teardownAutoWorktree no-ops.
|
|
590
|
+
try {
|
|
591
|
+
lifecycleTeardownAutoWorktree(deps, originalBasePath, milestoneId);
|
|
592
|
+
}
|
|
593
|
+
catch {
|
|
594
|
+
// Best-effort — primary cleanup in mergeMilestoneToMain may have
|
|
595
|
+
// already removed the worktree.
|
|
596
|
+
}
|
|
597
|
+
if (mergeResult.codeFilesChanged) {
|
|
598
|
+
notify(`Milestone ${milestoneId} merged to main.${mergeResult.pushed ? " Pushed to remote." : ""}`, "info");
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
// #1906 — milestone produced only .gsd/ metadata. Surface
|
|
602
|
+
// clearly so the user knows the milestone is not truly complete.
|
|
603
|
+
notify(`WARNING: Milestone ${milestoneId} merged to main but contained NO code changes — only .gsd/ metadata files. ` +
|
|
604
|
+
`The milestone summary may describe planned work that was never implemented. ` +
|
|
605
|
+
`Review the milestone output and re-run if code is missing.`, "warning");
|
|
606
|
+
}
|
|
607
|
+
return {
|
|
608
|
+
merged: true,
|
|
609
|
+
mode: "worktree",
|
|
610
|
+
codeFilesChanged: mergeResult.codeFilesChanged,
|
|
611
|
+
pushed: mergeResult.pushed,
|
|
612
|
+
commitMessage: mergeResult.commitMessage,
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
catch (err) {
|
|
616
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
617
|
+
debugLog("WorktreeLifecycle", {
|
|
618
|
+
action: "mergeAndExit",
|
|
619
|
+
milestoneId,
|
|
620
|
+
result: "error",
|
|
621
|
+
error: msg,
|
|
622
|
+
fallback: "chdir-to-project-root",
|
|
623
|
+
});
|
|
624
|
+
emitWorktreeMergeFailedOnce(originalBasePath || worktreeBasePath, milestoneId, err);
|
|
625
|
+
// Surface a clear, actionable error. Worktree and milestone branch
|
|
626
|
+
// are intentionally preserved — nothing has been deleted. User can
|
|
627
|
+
// retry /gsd dispatch complete-milestone or merge manually once the
|
|
628
|
+
// underlying issue is fixed (#1668, #1891).
|
|
629
|
+
notify(`Milestone merge failed: ${msg}. Your worktree and milestone branch are preserved — retry with \`/gsd dispatch complete-milestone\` or merge manually.`, "warning");
|
|
630
|
+
// Clean up stale merge state left by failed squash-merge (#1389)
|
|
631
|
+
try {
|
|
632
|
+
const gitDir = join(originalBasePath || worktreeBasePath, ".git");
|
|
633
|
+
for (const f of ["SQUASH_MSG", "MERGE_HEAD", "MERGE_MSG"]) {
|
|
634
|
+
const p = join(gitDir, f);
|
|
635
|
+
if (existsSync(p))
|
|
636
|
+
unlinkSync(p);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
catch {
|
|
640
|
+
/* best-effort */
|
|
641
|
+
}
|
|
642
|
+
// Error recovery: chdir back to project root only when no real worktree
|
|
643
|
+
// path is available. Session-side cleanup (restoreToProjectRoot,
|
|
644
|
+
// gitService rebuild) is the caller's responsibility.
|
|
645
|
+
if (originalBasePath && !worktreeBasePath) {
|
|
646
|
+
try {
|
|
647
|
+
process.chdir(originalBasePath);
|
|
648
|
+
}
|
|
649
|
+
catch {
|
|
650
|
+
/* best-effort */
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
// Re-throw: MergeConflictError stops the auto loop (#2330);
|
|
654
|
+
// non-conflict errors must also propagate so broken states are
|
|
655
|
+
// diagnosable (#4380).
|
|
656
|
+
throw err;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Branch-mode merge body. Session-less.
|
|
661
|
+
*
|
|
662
|
+
* Session-side `gitService` rebuild after HEAD changes is the caller's
|
|
663
|
+
* responsibility. The branch-mode `UserNotifiedError` sentinel still flows
|
|
664
|
+
* through unchanged so the outer caller can suppress duplicate toasts.
|
|
665
|
+
*/
|
|
666
|
+
function _mergeBranchModeImpl(deps, mctx) {
|
|
667
|
+
const { worktreeBasePath, milestoneId, notify } = mctx;
|
|
668
|
+
try {
|
|
669
|
+
const currentBranch = currentLifecycleBranch(deps, worktreeBasePath);
|
|
670
|
+
const milestoneBranch = lifecycleAutoWorktreeBranch(deps, milestoneId);
|
|
671
|
+
if (currentBranch !== milestoneBranch) {
|
|
672
|
+
// #5538-followup: previous behaviour was to silently `return false`
|
|
673
|
+
// when HEAD wasn't on the milestone branch — that let the loop
|
|
674
|
+
// advance with the milestone's commits stranded on the branch.
|
|
675
|
+
// Attempt recovery by force-checking-out the milestone branch; if
|
|
676
|
+
// that fails, throw so the caller pauses auto-mode and the user
|
|
677
|
+
// sees the failure instead of a silent merge skip.
|
|
678
|
+
debugLog("WorktreeLifecycle", {
|
|
679
|
+
action: "mergeAndExit",
|
|
680
|
+
milestoneId,
|
|
681
|
+
mode: "branch",
|
|
682
|
+
recovery: "checkout-milestone-branch",
|
|
683
|
+
currentBranch,
|
|
684
|
+
milestoneBranch,
|
|
685
|
+
});
|
|
686
|
+
try {
|
|
687
|
+
checkoutLifecycleBranch(deps, worktreeBasePath, milestoneBranch);
|
|
688
|
+
}
|
|
689
|
+
catch (checkoutErr) {
|
|
690
|
+
const checkoutMsg = checkoutErr instanceof Error
|
|
691
|
+
? checkoutErr.message
|
|
692
|
+
: String(checkoutErr);
|
|
693
|
+
notify(`Cannot merge milestone ${milestoneId}: working tree is on ${currentBranch} and checkout to ${milestoneBranch} failed (${checkoutMsg}). Resolve manually and run /gsd auto to resume.`, "error");
|
|
694
|
+
throw new UserNotifiedError(checkoutMsg, checkoutErr);
|
|
695
|
+
}
|
|
696
|
+
const reverify = currentLifecycleBranch(deps, worktreeBasePath);
|
|
697
|
+
if (reverify !== milestoneBranch) {
|
|
698
|
+
const reverifyMsg = `branch checkout to ${milestoneBranch} reported success but current branch is ${reverify}`;
|
|
699
|
+
notify(`Cannot merge milestone ${milestoneId}: ${reverifyMsg}. Resolve manually and run /gsd auto to resume.`, "error");
|
|
700
|
+
throw new UserNotifiedError(reverifyMsg);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const roadmapPath = resolveMilestoneFile(worktreeBasePath, milestoneId, "ROADMAP");
|
|
704
|
+
if (!roadmapPath) {
|
|
705
|
+
debugLog("WorktreeLifecycle", {
|
|
706
|
+
action: "mergeAndExit",
|
|
707
|
+
milestoneId,
|
|
708
|
+
mode: "branch",
|
|
709
|
+
skipped: true,
|
|
710
|
+
reason: "no-roadmap",
|
|
711
|
+
});
|
|
712
|
+
return {
|
|
713
|
+
merged: false,
|
|
714
|
+
mode: "branch",
|
|
715
|
+
codeFilesChanged: false,
|
|
716
|
+
pushed: false,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
const roadmapContent = readLifecycleFile(deps, roadmapPath);
|
|
720
|
+
const mergeResult = deps.mergeMilestoneToMain(worktreeBasePath, milestoneId, roadmapContent);
|
|
721
|
+
if (mergeResult.codeFilesChanged) {
|
|
722
|
+
notify(`Milestone ${milestoneId} merged (branch mode).${mergeResult.pushed ? " Pushed to remote." : ""}`, "info");
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
notify(`WARNING: Milestone ${milestoneId} merged (branch mode) but contained NO code changes — only .gsd/ metadata. ` +
|
|
726
|
+
`Review the milestone output and re-run if code is missing.`, "warning");
|
|
727
|
+
}
|
|
728
|
+
debugLog("WorktreeLifecycle", {
|
|
729
|
+
action: "mergeAndExit",
|
|
730
|
+
milestoneId,
|
|
731
|
+
mode: "branch",
|
|
732
|
+
result: "success",
|
|
733
|
+
});
|
|
734
|
+
return {
|
|
735
|
+
merged: true,
|
|
736
|
+
mode: "branch",
|
|
737
|
+
codeFilesChanged: mergeResult.codeFilesChanged,
|
|
738
|
+
pushed: mergeResult.pushed,
|
|
739
|
+
commitMessage: mergeResult.commitMessage,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
catch (err) {
|
|
743
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
744
|
+
debugLog("WorktreeLifecycle", {
|
|
745
|
+
action: "mergeAndExit",
|
|
746
|
+
milestoneId,
|
|
747
|
+
mode: "branch",
|
|
748
|
+
result: "error",
|
|
749
|
+
error: msg,
|
|
750
|
+
});
|
|
751
|
+
if (!(err instanceof UserNotifiedError)) {
|
|
752
|
+
notify(`Milestone merge failed (branch mode): ${msg}`, "warning");
|
|
753
|
+
}
|
|
754
|
+
// Re-throw all errors so callers can apply their own recovery (#4380).
|
|
755
|
+
throw err;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Session-less merge entry (ADR-016 phase 2 / A1, issue #5618).
|
|
760
|
+
*
|
|
761
|
+
* Runs the worktree-mode or branch-mode merge body without touching session
|
|
762
|
+
* state. Used directly by `parallel-merge.ts` and indirectly (via
|
|
763
|
+
* `_mergeAndExit`) by the single-loop path. Caller is responsible for any
|
|
764
|
+
* session-side cleanup based on the returned `mode`.
|
|
765
|
+
*
|
|
766
|
+
* **CWD anchor**: anchors `process.cwd()` at `originalBasePath` before
|
|
767
|
+
* non-worktree merge paths to mirror the single-loop guard against ENOENT
|
|
768
|
+
* after teardown (de73fb43d). Worktree-mode merge paths keep the real
|
|
769
|
+
* worktree as cwd because `mergeMilestoneToMain()` infers source worktree
|
|
770
|
+
* state from `process.cwd()`. Best-effort; silent on failure.
|
|
771
|
+
*
|
|
772
|
+
* **Failure handling**: `MergeConflictError` and other unrecoverable errors
|
|
773
|
+
* propagate to the caller. The caller is responsible for any state restore
|
|
774
|
+
* (single-loop callers re-`chdir` and `restoreToProjectRoot`; parallel
|
|
775
|
+
* callers surface to the user as a `MergeResult` with `success: false`).
|
|
776
|
+
*/
|
|
777
|
+
export function mergeMilestoneStandalone(deps, mctx) {
|
|
778
|
+
const { originalBasePath, worktreeBasePath, milestoneId, notify } = mctx;
|
|
779
|
+
validateMilestoneId(milestoneId);
|
|
780
|
+
if (mctx.isolationDegraded) {
|
|
781
|
+
if (originalBasePath) {
|
|
782
|
+
try {
|
|
783
|
+
process.chdir(originalBasePath);
|
|
784
|
+
}
|
|
785
|
+
catch (err) {
|
|
786
|
+
debugLog("WorktreeLifecycle", {
|
|
787
|
+
action: "mergeAndExit",
|
|
788
|
+
phase: "pre-merge-chdir-failed",
|
|
789
|
+
milestoneId,
|
|
790
|
+
originalBasePath,
|
|
791
|
+
error: err instanceof Error ? err.message : String(err),
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
debugLog("WorktreeLifecycle", {
|
|
796
|
+
action: "mergeAndExit",
|
|
797
|
+
milestoneId,
|
|
798
|
+
skipped: true,
|
|
799
|
+
reason: "isolation-degraded",
|
|
800
|
+
});
|
|
801
|
+
notify(`Skipping worktree merge for ${milestoneId} — isolation was degraded (worktree creation failed earlier). Work is on the current branch.`, "info");
|
|
802
|
+
return {
|
|
803
|
+
merged: false,
|
|
804
|
+
mode: "skipped",
|
|
805
|
+
codeFilesChanged: false,
|
|
806
|
+
pushed: false,
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
const mode = getIsolationMode(originalBasePath || worktreeBasePath);
|
|
810
|
+
debugLog("WorktreeLifecycle", {
|
|
811
|
+
action: "mergeAndExit",
|
|
812
|
+
milestoneId,
|
|
813
|
+
mode,
|
|
814
|
+
basePath: worktreeBasePath,
|
|
815
|
+
});
|
|
816
|
+
emitJournalEvent(originalBasePath || worktreeBasePath, {
|
|
817
|
+
ts: new Date().toISOString(),
|
|
818
|
+
flowId: randomUUID(),
|
|
819
|
+
seq: 0,
|
|
820
|
+
eventType: "worktree-merge-start",
|
|
821
|
+
data: { milestoneId, mode },
|
|
822
|
+
});
|
|
823
|
+
// #2625: If we are physically inside an auto-worktree, we MUST merge
|
|
824
|
+
// regardless of the current isolation config. This prevents data loss
|
|
825
|
+
// when the default isolation mode changes between versions.
|
|
826
|
+
const inWorktree = lifecycleIsInAutoWorktree(deps, worktreeBasePath) && Boolean(originalBasePath);
|
|
827
|
+
if (mode === "none" && !inWorktree) {
|
|
828
|
+
debugLog("WorktreeLifecycle", {
|
|
829
|
+
action: "mergeAndExit",
|
|
830
|
+
milestoneId,
|
|
831
|
+
skipped: true,
|
|
832
|
+
reason: "mode-none",
|
|
833
|
+
});
|
|
834
|
+
// Anchor cwd at project root before the early return so subsequent
|
|
835
|
+
// process.cwd() calls after the skip don't ENOENT if we were inside a
|
|
836
|
+
// worktree directory that gets torn down later. Best-effort.
|
|
837
|
+
if (originalBasePath) {
|
|
838
|
+
try {
|
|
839
|
+
process.chdir(originalBasePath);
|
|
840
|
+
}
|
|
841
|
+
catch {
|
|
842
|
+
/* best-effort */
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return {
|
|
846
|
+
merged: false,
|
|
847
|
+
mode: "skipped",
|
|
848
|
+
codeFilesChanged: false,
|
|
849
|
+
pushed: false,
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
// Set cwd to the correct anchor before dispatching to mode implementations.
|
|
853
|
+
// Worktree mode / in-worktree override must run from the live worktree so
|
|
854
|
+
// mergeMilestoneToMain can find worktree-local state; branch mode runs from
|
|
855
|
+
// the original project root. Best-effort for synthetic test paths.
|
|
856
|
+
const targetCwd = mode === "worktree" || inWorktree
|
|
857
|
+
? worktreeBasePath
|
|
858
|
+
: originalBasePath;
|
|
859
|
+
if (targetCwd) {
|
|
860
|
+
try {
|
|
861
|
+
process.chdir(targetCwd);
|
|
862
|
+
}
|
|
863
|
+
catch (err) {
|
|
864
|
+
debugLog("WorktreeLifecycle", {
|
|
865
|
+
action: "mergeAndExit",
|
|
866
|
+
phase: "pre-merge-chdir-failed",
|
|
867
|
+
milestoneId,
|
|
868
|
+
targetCwd,
|
|
869
|
+
error: err instanceof Error ? err.message : String(err),
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (mode === "worktree" || inWorktree) {
|
|
874
|
+
return _mergeWorktreeModeImpl(deps, mctx);
|
|
875
|
+
}
|
|
876
|
+
if (mode === "branch") {
|
|
877
|
+
return _mergeBranchModeImpl(deps, mctx);
|
|
878
|
+
}
|
|
879
|
+
// Defensive fallback — should not reach here given the mode-none guard above.
|
|
880
|
+
return {
|
|
881
|
+
merged: false,
|
|
882
|
+
mode: "skipped",
|
|
883
|
+
codeFilesChanged: false,
|
|
884
|
+
pushed: false,
|
|
885
|
+
};
|
|
360
886
|
}
|
|
361
887
|
// ─── Module class ────────────────────────────────────────────────────────
|
|
362
888
|
/**
|
|
@@ -401,7 +927,11 @@ export class WorktreeLifecycle {
|
|
|
401
927
|
if (opts.merge) {
|
|
402
928
|
try {
|
|
403
929
|
const merged = this._mergeAndExit(milestoneId, ctx);
|
|
404
|
-
return {
|
|
930
|
+
return {
|
|
931
|
+
ok: true,
|
|
932
|
+
merged: merged.merged,
|
|
933
|
+
codeFilesChanged: merged.codeFilesChanged,
|
|
934
|
+
};
|
|
405
935
|
}
|
|
406
936
|
catch (err) {
|
|
407
937
|
if (err instanceof MergeConflictError) {
|
|
@@ -435,7 +965,7 @@ export class WorktreeLifecycle {
|
|
|
435
965
|
let merged = false;
|
|
436
966
|
let mergeThrew = false;
|
|
437
967
|
try {
|
|
438
|
-
merged = this._mergeAndExit(currentMilestoneId, ctx);
|
|
968
|
+
merged = this._mergeAndExit(currentMilestoneId, ctx).merged;
|
|
439
969
|
}
|
|
440
970
|
catch (err) {
|
|
441
971
|
if (err instanceof UserNotifiedError)
|
|
@@ -470,7 +1000,7 @@ export class WorktreeLifecycle {
|
|
|
470
1000
|
// ── Private — exit without merge ─────────────────────────────────────
|
|
471
1001
|
_exitWithoutMerge(milestoneId, ctx, opts) {
|
|
472
1002
|
validateMilestoneId(milestoneId);
|
|
473
|
-
if (!this.deps
|
|
1003
|
+
if (!lifecycleIsInAutoWorktree(this.deps, this.s.basePath)) {
|
|
474
1004
|
debugLog("WorktreeLifecycle", {
|
|
475
1005
|
action: "exitMilestone",
|
|
476
1006
|
milestoneId,
|
|
@@ -485,7 +1015,7 @@ export class WorktreeLifecycle {
|
|
|
485
1015
|
basePath: this.s.basePath,
|
|
486
1016
|
});
|
|
487
1017
|
try {
|
|
488
|
-
this.deps
|
|
1018
|
+
autoCommitLifecycleBranch(this.deps, this.s.basePath, "stop", milestoneId);
|
|
489
1019
|
}
|
|
490
1020
|
catch (err) {
|
|
491
1021
|
debugLog("WorktreeLifecycle", {
|
|
@@ -494,7 +1024,7 @@ export class WorktreeLifecycle {
|
|
|
494
1024
|
phase: "auto-commit-failed",
|
|
495
1025
|
error: err instanceof Error ? err.message : String(err),
|
|
496
1026
|
});
|
|
497
|
-
ctx.notify(`Auto-commit before exiting ${milestoneId} failed: ${err instanceof Error ? err.message : String(err)}. Branch ${this.deps
|
|
1027
|
+
ctx.notify(`Auto-commit before exiting ${milestoneId} failed: ${err instanceof Error ? err.message : String(err)}. Branch ${lifecycleAutoWorktreeBranch(this.deps, milestoneId)} is preserved for recovery.`, "warning");
|
|
498
1028
|
}
|
|
499
1029
|
if (this.s.originalBasePath) {
|
|
500
1030
|
try {
|
|
@@ -508,12 +1038,12 @@ export class WorktreeLifecycle {
|
|
|
508
1038
|
originalBasePath: this.s.originalBasePath,
|
|
509
1039
|
error: err instanceof Error ? err.message : String(err),
|
|
510
1040
|
});
|
|
511
|
-
ctx.notify(`Could not leave milestone worktree before cleanup: ${err instanceof Error ? err.message : String(err)}. Branch ${this.deps
|
|
1041
|
+
ctx.notify(`Could not leave milestone worktree before cleanup: ${err instanceof Error ? err.message : String(err)}. Branch ${lifecycleAutoWorktreeBranch(this.deps, milestoneId)} is preserved for recovery.`, "warning");
|
|
512
1042
|
}
|
|
513
1043
|
}
|
|
514
1044
|
let teardownFailed = false;
|
|
515
1045
|
try {
|
|
516
|
-
this.deps
|
|
1046
|
+
lifecycleTeardownAutoWorktree(this.deps, this.s.originalBasePath, milestoneId, {
|
|
517
1047
|
preserveBranch: opts.preserveBranch ?? false,
|
|
518
1048
|
});
|
|
519
1049
|
}
|
|
@@ -525,7 +1055,7 @@ export class WorktreeLifecycle {
|
|
|
525
1055
|
phase: "teardown-failed",
|
|
526
1056
|
error: err instanceof Error ? err.message : String(err),
|
|
527
1057
|
});
|
|
528
|
-
ctx.notify(`Worktree cleanup failed for ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. Branch ${this.deps
|
|
1058
|
+
ctx.notify(`Worktree cleanup failed for ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. Branch ${lifecycleAutoWorktreeBranch(this.deps, milestoneId)} is preserved for recovery.`, "warning");
|
|
529
1059
|
}
|
|
530
1060
|
this.restoreToProjectRoot();
|
|
531
1061
|
debugLog("WorktreeLifecycle", {
|
|
@@ -542,91 +1072,56 @@ export class WorktreeLifecycle {
|
|
|
542
1072
|
/**
|
|
543
1073
|
* Merge the completed milestone branch back to main and exit the worktree.
|
|
544
1074
|
*
|
|
545
|
-
* -
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
* -
|
|
550
|
-
*
|
|
551
|
-
* -
|
|
1075
|
+
* Session-bound wrapper around `mergeMilestoneStandalone`. Builds a
|
|
1076
|
+
* `MergeContext` from `this.s`, layers session-side bookkeeping on top of
|
|
1077
|
+
* the result:
|
|
1078
|
+
*
|
|
1079
|
+
* - resquash-on-merge using `s.milestoneStartShas`
|
|
1080
|
+
* - merge-completion telemetry (duration)
|
|
1081
|
+
* - mode-specific session restore: worktree-mode → `restoreToProjectRoot`,
|
|
1082
|
+
* branch-mode → `gitService` rebuild
|
|
552
1083
|
*
|
|
553
|
-
* Returns
|
|
554
|
-
* (
|
|
1084
|
+
* Returns the session-less merge result. Errors propagate after
|
|
1085
|
+
* `restoreToProjectRoot()` runs so callers always receive a consistent
|
|
1086
|
+
* session.
|
|
555
1087
|
*/
|
|
556
1088
|
_mergeAndExit(milestoneId, ctx) {
|
|
557
|
-
validateMilestoneId(milestoneId);
|
|
558
|
-
// Anchor cwd at the project root before any merge work. Some merge
|
|
559
|
-
// paths (mergeMilestoneToMain, slice-cadence) chdir explicitly; others
|
|
560
|
-
// (branch-mode, isolation-degraded skip) do not. If the worktree dir
|
|
561
|
-
// is later torn down while cwd still points into it, every subsequent
|
|
562
|
-
// process.cwd() throws ENOENT — which after de73fb43d surfaces as a
|
|
563
|
-
// session-failed cancel and (in headless mode) terminates the whole
|
|
564
|
-
// gsd process. Best-effort: silent on failure so synthetic test paths
|
|
565
|
-
// still pass.
|
|
566
|
-
if (this.s.originalBasePath) {
|
|
567
|
-
try {
|
|
568
|
-
process.chdir(this.s.originalBasePath);
|
|
569
|
-
}
|
|
570
|
-
catch (err) {
|
|
571
|
-
debugLog("WorktreeLifecycle", {
|
|
572
|
-
action: "mergeAndExit",
|
|
573
|
-
phase: "pre-merge-chdir-failed",
|
|
574
|
-
milestoneId,
|
|
575
|
-
originalBasePath: this.s.originalBasePath,
|
|
576
|
-
error: err instanceof Error ? err.message : String(err),
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
1089
|
// #4764 — telemetry: record start timestamp so we can emit merge duration.
|
|
581
1090
|
const mergeStartedAt = new Date().toISOString();
|
|
582
1091
|
const mergeStartMs = Date.now();
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
reason: "isolation-degraded",
|
|
589
|
-
});
|
|
590
|
-
ctx.notify(`Skipping worktree merge for ${milestoneId} — isolation was degraded (worktree creation failed earlier). Work is on the current branch.`, "info");
|
|
591
|
-
return false;
|
|
592
|
-
}
|
|
593
|
-
const mode = this.deps.getIsolationMode(this.s.originalBasePath || this.s.basePath);
|
|
594
|
-
debugLog("WorktreeLifecycle", {
|
|
595
|
-
action: "mergeAndExit",
|
|
596
|
-
milestoneId,
|
|
597
|
-
mode,
|
|
598
|
-
basePath: this.s.basePath,
|
|
599
|
-
});
|
|
600
|
-
emitJournalEvent(this.s.originalBasePath || this.s.basePath, {
|
|
601
|
-
ts: new Date().toISOString(),
|
|
602
|
-
flowId: randomUUID(),
|
|
603
|
-
seq: 0,
|
|
604
|
-
eventType: "worktree-merge-start",
|
|
605
|
-
data: { milestoneId, mode },
|
|
606
|
-
});
|
|
607
|
-
// #2625: If we are physically inside an auto-worktree, we MUST merge
|
|
608
|
-
// regardless of the current isolation config. This prevents data loss
|
|
609
|
-
// when the default isolation mode changes between versions.
|
|
610
|
-
const inWorktree = this.deps.isInAutoWorktree(this.s.basePath) && this.s.originalBasePath;
|
|
611
|
-
if (mode === "none" && !inWorktree) {
|
|
612
|
-
debugLog("WorktreeLifecycle", {
|
|
613
|
-
action: "mergeAndExit",
|
|
1092
|
+
let result;
|
|
1093
|
+
try {
|
|
1094
|
+
result = mergeMilestoneStandalone(this.deps, {
|
|
1095
|
+
originalBasePath: this.s.originalBasePath,
|
|
1096
|
+
worktreeBasePath: this.s.basePath,
|
|
614
1097
|
milestoneId,
|
|
615
|
-
|
|
616
|
-
|
|
1098
|
+
isolationDegraded: this.s.isolationDegraded,
|
|
1099
|
+
notify: ctx.notify,
|
|
617
1100
|
});
|
|
618
|
-
return false;
|
|
619
1101
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
1102
|
+
catch (err) {
|
|
1103
|
+
// Standalone has already done its session-less cleanup
|
|
1104
|
+
// (chdir, SQUASH_MSG cleanup, journal event). Layer session-side
|
|
1105
|
+
// restore on top so callers get a consistent session.
|
|
1106
|
+
this.restoreToProjectRoot();
|
|
1107
|
+
throw err;
|
|
626
1108
|
}
|
|
627
|
-
if (!
|
|
1109
|
+
if (!result.merged) {
|
|
1110
|
+
// Skip / no-roadmap / mode-none paths. milestoneStartShas housekeeping
|
|
1111
|
+
// is unconditional; mode-specific session restore happens for
|
|
1112
|
+
// worktree-mode (preserve-branch path tore down the worktree, so
|
|
1113
|
+
// basePath must restore) and not for branch-mode (no basePath change).
|
|
628
1114
|
this.s.milestoneStartShas.delete(milestoneId);
|
|
629
|
-
|
|
1115
|
+
if (result.mode === "worktree") {
|
|
1116
|
+
this.restoreToProjectRoot();
|
|
1117
|
+
debugLog("WorktreeLifecycle", {
|
|
1118
|
+
action: "mergeAndExit",
|
|
1119
|
+
milestoneId,
|
|
1120
|
+
result: "done",
|
|
1121
|
+
basePath: this.s.basePath,
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
return result;
|
|
630
1125
|
}
|
|
631
1126
|
// #4765 — when collapse_cadence=slice AND milestone_resquash=true, the
|
|
632
1127
|
// N per-slice commits on main should be collapsed into one milestone
|
|
@@ -635,11 +1130,11 @@ export class WorktreeLifecycle {
|
|
|
635
1130
|
try {
|
|
636
1131
|
const startSha = this.s.milestoneStartShas.get(milestoneId);
|
|
637
1132
|
if (startSha) {
|
|
638
|
-
const prefs =
|
|
1133
|
+
const prefs = lifecycleLoadPreferences(this.deps, this.s.originalBasePath || this.s.basePath)?.preferences;
|
|
639
1134
|
if (getCollapseCadence(prefs) === "slice" &&
|
|
640
1135
|
getMilestoneResquash(prefs)) {
|
|
641
|
-
const
|
|
642
|
-
if (
|
|
1136
|
+
const resquashResult = resquashMilestoneOnMain(this.s.originalBasePath || this.s.basePath, milestoneId, startSha);
|
|
1137
|
+
if (resquashResult.resquashed) {
|
|
643
1138
|
ctx.notify(`slice-cadence: re-squashed slice commits for ${milestoneId} into a single milestone commit.`, "info");
|
|
644
1139
|
}
|
|
645
1140
|
}
|
|
@@ -672,232 +1167,27 @@ export class WorktreeLifecycle {
|
|
|
672
1167
|
: String(telemetryErr),
|
|
673
1168
|
});
|
|
674
1169
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
_mergeWorktreeMode(milestoneId, ctx) {
|
|
679
|
-
const originalBase = this.s.originalBasePath;
|
|
680
|
-
if (!originalBase) {
|
|
681
|
-
debugLog("WorktreeLifecycle", {
|
|
682
|
-
action: "mergeAndExit",
|
|
683
|
-
milestoneId,
|
|
684
|
-
mode: "worktree",
|
|
685
|
-
skipped: true,
|
|
686
|
-
reason: "missing-original-base",
|
|
687
|
-
});
|
|
688
|
-
return false;
|
|
689
|
-
}
|
|
690
|
-
let merged = false;
|
|
691
|
-
try {
|
|
692
|
-
// ADR-016: final projection before teardown. Replaces the legacy
|
|
693
|
-
// syncWorktreeStateBack(originalBase, basePath, milestoneId) call.
|
|
694
|
-
const finalScope = scopeMilestone(createWorkspace(this.s.basePath), milestoneId);
|
|
695
|
-
const { synced } = this.deps.worktreeProjection.finalizeProjectionForMerge(finalScope);
|
|
696
|
-
if (synced.length > 0) {
|
|
697
|
-
debugLog("WorktreeLifecycle", {
|
|
698
|
-
action: "mergeAndExit",
|
|
699
|
-
milestoneId,
|
|
700
|
-
phase: "reverse-sync",
|
|
701
|
-
synced: synced.length,
|
|
702
|
-
});
|
|
703
|
-
}
|
|
704
|
-
// Resolve roadmap — try project root first, then worktree path as
|
|
705
|
-
// fallback. The worktree may hold the only copy when state-back
|
|
706
|
-
// projection silently dropped it or .gsd/ is not symlinked. Without
|
|
707
|
-
// the fallback, a missing roadmap triggers bare teardown which
|
|
708
|
-
// deletes the branch and orphans all milestone commits (#1573).
|
|
709
|
-
let roadmapPath = this.deps.resolveMilestoneFile(originalBase, milestoneId, "ROADMAP");
|
|
710
|
-
if (!roadmapPath &&
|
|
711
|
-
!isSamePathPhysical(this.s.basePath, originalBase)) {
|
|
712
|
-
roadmapPath = this.deps.resolveMilestoneFile(this.s.basePath, milestoneId, "ROADMAP");
|
|
713
|
-
if (roadmapPath) {
|
|
714
|
-
debugLog("WorktreeLifecycle", {
|
|
715
|
-
action: "mergeAndExit",
|
|
716
|
-
milestoneId,
|
|
717
|
-
phase: "roadmap-fallback",
|
|
718
|
-
note: "resolved from worktree path",
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
if (roadmapPath) {
|
|
723
|
-
const roadmapContent = this.deps.readFileSync(roadmapPath, "utf-8");
|
|
724
|
-
const mergeResult = this.deps.mergeMilestoneToMain(originalBase, milestoneId, roadmapContent);
|
|
725
|
-
merged = true;
|
|
726
|
-
// #2945 Bug 3: mergeMilestoneToMain performs best-effort worktree
|
|
727
|
-
// cleanup internally (step 12), but it can silently fail on Windows
|
|
728
|
-
// or when the worktree directory is locked. Perform a secondary
|
|
729
|
-
// teardown here to ensure the worktree is properly cleaned up.
|
|
730
|
-
// Idempotent — if already removed, teardownAutoWorktree no-ops.
|
|
731
|
-
try {
|
|
732
|
-
this.deps.teardownAutoWorktree(originalBase, milestoneId);
|
|
733
|
-
}
|
|
734
|
-
catch {
|
|
735
|
-
// Best-effort — primary cleanup in mergeMilestoneToMain may have
|
|
736
|
-
// already removed the worktree.
|
|
737
|
-
}
|
|
738
|
-
if (mergeResult.codeFilesChanged) {
|
|
739
|
-
ctx.notify(`Milestone ${milestoneId} merged to main.${mergeResult.pushed ? " Pushed to remote." : ""}`, "info");
|
|
740
|
-
}
|
|
741
|
-
else {
|
|
742
|
-
// #1906 — milestone produced only .gsd/ metadata. Surface
|
|
743
|
-
// clearly so the user knows the milestone is not truly complete.
|
|
744
|
-
ctx.notify(`WARNING: Milestone ${milestoneId} merged to main but contained NO code changes — only .gsd/ metadata files. ` +
|
|
745
|
-
`The milestone summary may describe planned work that was never implemented. ` +
|
|
746
|
-
`Review the milestone output and re-run if code is missing.`, "warning");
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
else {
|
|
750
|
-
// No roadmap at either location — teardown but PRESERVE the branch
|
|
751
|
-
// so commits are not orphaned (#1573).
|
|
752
|
-
this.deps.teardownAutoWorktree(originalBase, milestoneId, {
|
|
753
|
-
preserveBranch: true,
|
|
754
|
-
});
|
|
755
|
-
ctx.notify(`Exited worktree for ${milestoneId} (no roadmap found — branch preserved for manual merge).`, "warning");
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
catch (err) {
|
|
759
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1170
|
+
// Mode-specific session restore.
|
|
1171
|
+
if (result.mode === "worktree") {
|
|
1172
|
+
this.restoreToProjectRoot();
|
|
760
1173
|
debugLog("WorktreeLifecycle", {
|
|
761
1174
|
action: "mergeAndExit",
|
|
762
1175
|
milestoneId,
|
|
763
|
-
result: "
|
|
764
|
-
|
|
765
|
-
fallback: "chdir-to-project-root",
|
|
1176
|
+
result: "done",
|
|
1177
|
+
basePath: this.s.basePath,
|
|
766
1178
|
});
|
|
767
|
-
emitJournalEvent(this.s.originalBasePath || this.s.basePath, {
|
|
768
|
-
ts: new Date().toISOString(),
|
|
769
|
-
flowId: randomUUID(),
|
|
770
|
-
seq: 0,
|
|
771
|
-
eventType: "worktree-merge-failed",
|
|
772
|
-
data: { milestoneId, error: msg },
|
|
773
|
-
});
|
|
774
|
-
// Surface a clear, actionable error. Worktree and milestone branch
|
|
775
|
-
// are intentionally preserved — nothing has been deleted. User can
|
|
776
|
-
// retry /gsd dispatch complete-milestone or merge manually once the
|
|
777
|
-
// underlying issue is fixed (#1668, #1891).
|
|
778
|
-
ctx.notify(`Milestone merge failed: ${msg}. Your worktree and milestone branch are preserved — retry with \`/gsd dispatch complete-milestone\` or merge manually.`, "warning");
|
|
779
|
-
// Clean up stale merge state left by failed squash-merge (#1389)
|
|
780
|
-
try {
|
|
781
|
-
const gitDir = join(originalBase || this.s.basePath, ".git");
|
|
782
|
-
for (const f of ["SQUASH_MSG", "MERGE_HEAD", "MERGE_MSG"]) {
|
|
783
|
-
const p = join(gitDir, f);
|
|
784
|
-
if (existsSync(p))
|
|
785
|
-
unlinkSync(p);
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
catch {
|
|
789
|
-
/* best-effort */
|
|
790
|
-
}
|
|
791
|
-
// Error recovery: always restore to project root
|
|
792
|
-
if (originalBase) {
|
|
793
|
-
try {
|
|
794
|
-
process.chdir(originalBase);
|
|
795
|
-
}
|
|
796
|
-
catch {
|
|
797
|
-
/* best-effort */
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
// Restore state before re-throwing so callers always get a
|
|
801
|
-
// consistent session (#4380).
|
|
802
|
-
this.restoreToProjectRoot();
|
|
803
|
-
// Re-throw: MergeConflictError stops the auto loop (#2330);
|
|
804
|
-
// non-conflict errors must also propagate so broken states are
|
|
805
|
-
// diagnosable (#4380).
|
|
806
|
-
throw err;
|
|
807
1179
|
}
|
|
808
|
-
|
|
809
|
-
this.restoreToProjectRoot();
|
|
810
|
-
debugLog("WorktreeLifecycle", {
|
|
811
|
-
action: "mergeAndExit",
|
|
812
|
-
milestoneId,
|
|
813
|
-
result: "done",
|
|
814
|
-
basePath: this.s.basePath,
|
|
815
|
-
});
|
|
816
|
-
return merged;
|
|
817
|
-
}
|
|
818
|
-
/** Branch-mode merge body. Returns true when a merge actually ran. */
|
|
819
|
-
_mergeBranchMode(milestoneId, ctx) {
|
|
820
|
-
try {
|
|
821
|
-
const currentBranch = this.deps.getCurrentBranch(this.s.basePath);
|
|
822
|
-
const milestoneBranch = this.deps.autoWorktreeBranch(milestoneId);
|
|
823
|
-
if (currentBranch !== milestoneBranch) {
|
|
824
|
-
// #5538-followup: previous behaviour was to silently `return false`
|
|
825
|
-
// when HEAD wasn't on the milestone branch — that let the loop
|
|
826
|
-
// advance with the milestone's commits stranded on the branch.
|
|
827
|
-
// Attempt recovery by force-checking-out the milestone branch; if
|
|
828
|
-
// that fails, throw so the caller pauses auto-mode and the user
|
|
829
|
-
// sees the failure instead of a silent merge skip.
|
|
830
|
-
debugLog("WorktreeLifecycle", {
|
|
831
|
-
action: "mergeAndExit",
|
|
832
|
-
milestoneId,
|
|
833
|
-
mode: "branch",
|
|
834
|
-
recovery: "checkout-milestone-branch",
|
|
835
|
-
currentBranch,
|
|
836
|
-
milestoneBranch,
|
|
837
|
-
});
|
|
838
|
-
try {
|
|
839
|
-
this.deps.checkoutBranch(this.s.basePath, milestoneBranch);
|
|
840
|
-
}
|
|
841
|
-
catch (checkoutErr) {
|
|
842
|
-
const checkoutMsg = checkoutErr instanceof Error
|
|
843
|
-
? checkoutErr.message
|
|
844
|
-
: String(checkoutErr);
|
|
845
|
-
ctx.notify(`Cannot merge milestone ${milestoneId}: working tree is on ${currentBranch} and checkout to ${milestoneBranch} failed (${checkoutMsg}). Resolve manually and run /gsd auto to resume.`, "error");
|
|
846
|
-
throw new UserNotifiedError(checkoutMsg, checkoutErr);
|
|
847
|
-
}
|
|
848
|
-
const reverify = this.deps.getCurrentBranch(this.s.basePath);
|
|
849
|
-
if (reverify !== milestoneBranch) {
|
|
850
|
-
const reverifyMsg = `branch checkout to ${milestoneBranch} reported success but current branch is ${reverify}`;
|
|
851
|
-
ctx.notify(`Cannot merge milestone ${milestoneId}: ${reverifyMsg}. Resolve manually and run /gsd auto to resume.`, "error");
|
|
852
|
-
throw new UserNotifiedError(reverifyMsg);
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
const roadmapPath = this.deps.resolveMilestoneFile(this.s.basePath, milestoneId, "ROADMAP");
|
|
856
|
-
if (!roadmapPath) {
|
|
857
|
-
debugLog("WorktreeLifecycle", {
|
|
858
|
-
action: "mergeAndExit",
|
|
859
|
-
milestoneId,
|
|
860
|
-
mode: "branch",
|
|
861
|
-
skipped: true,
|
|
862
|
-
reason: "no-roadmap",
|
|
863
|
-
});
|
|
864
|
-
return false;
|
|
865
|
-
}
|
|
866
|
-
const roadmapContent = this.deps.readFileSync(roadmapPath, "utf-8");
|
|
867
|
-
const mergeResult = this.deps.mergeMilestoneToMain(this.s.basePath, milestoneId, roadmapContent);
|
|
1180
|
+
else if (result.mode === "branch") {
|
|
868
1181
|
// Rebuild GitService after merge (branch HEAD changed)
|
|
869
1182
|
rebuildGitService(this.s, this.deps);
|
|
870
|
-
if (mergeResult.codeFilesChanged) {
|
|
871
|
-
ctx.notify(`Milestone ${milestoneId} merged (branch mode).${mergeResult.pushed ? " Pushed to remote." : ""}`, "info");
|
|
872
|
-
}
|
|
873
|
-
else {
|
|
874
|
-
ctx.notify(`WARNING: Milestone ${milestoneId} merged (branch mode) but contained NO code changes — only .gsd/ metadata. ` +
|
|
875
|
-
`Review the milestone output and re-run if code is missing.`, "warning");
|
|
876
|
-
}
|
|
877
|
-
debugLog("WorktreeLifecycle", {
|
|
878
|
-
action: "mergeAndExit",
|
|
879
|
-
milestoneId,
|
|
880
|
-
mode: "branch",
|
|
881
|
-
result: "success",
|
|
882
|
-
});
|
|
883
|
-
return true;
|
|
884
|
-
}
|
|
885
|
-
catch (err) {
|
|
886
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
887
|
-
debugLog("WorktreeLifecycle", {
|
|
888
|
-
action: "mergeAndExit",
|
|
889
|
-
milestoneId,
|
|
890
|
-
mode: "branch",
|
|
891
|
-
result: "error",
|
|
892
|
-
error: msg,
|
|
893
|
-
});
|
|
894
|
-
if (!(err instanceof UserNotifiedError)) {
|
|
895
|
-
ctx.notify(`Milestone merge failed (branch mode): ${msg}`, "warning");
|
|
896
|
-
}
|
|
897
|
-
// Re-throw all errors so callers can apply their own recovery (#4380).
|
|
898
|
-
throw err;
|
|
899
1183
|
}
|
|
1184
|
+
return result;
|
|
900
1185
|
}
|
|
1186
|
+
// ── Removed: _mergeWorktreeMode / _mergeBranchMode bodies ────────────
|
|
1187
|
+
// The merge bodies moved to file-scope `_mergeWorktreeModeImpl` and
|
|
1188
|
+
// `_mergeBranchModeImpl`, callable from the session-less
|
|
1189
|
+
// `mergeMilestoneStandalone` entry. The previous private methods are
|
|
1190
|
+
// gone; `_mergeAndExit` above is the only session-bound caller.
|
|
901
1191
|
/**
|
|
902
1192
|
* Fall back to branch-mode for `milestoneId` after a failed worktree
|
|
903
1193
|
* creation, marking the session's isolation as degraded.
|
|
@@ -920,9 +1210,9 @@ export class WorktreeLifecycle {
|
|
|
920
1210
|
}
|
|
921
1211
|
const basePath = resolveWorktreeProjectRoot(this.s.basePath, this.s.originalBasePath);
|
|
922
1212
|
try {
|
|
923
|
-
this.deps
|
|
1213
|
+
lifecycleEnterBranchMode(this.deps, basePath, milestoneId);
|
|
924
1214
|
rebuildGitService(this.s, this.deps);
|
|
925
|
-
|
|
1215
|
+
invalidateAllCaches();
|
|
926
1216
|
this.s.isolationDegraded = true;
|
|
927
1217
|
ctx.notify(`Switched to branch milestone/${milestoneId} (isolation degraded).`, "info");
|
|
928
1218
|
}
|
|
@@ -933,19 +1223,179 @@ export class WorktreeLifecycle {
|
|
|
933
1223
|
}
|
|
934
1224
|
}
|
|
935
1225
|
/**
|
|
936
|
-
* Restore `s.basePath` to `s.originalBasePath
|
|
937
|
-
* No-op when `originalBasePath` is empty (fresh
|
|
1226
|
+
* Restore `s.basePath` to `s.originalBasePath`, chdir process cwd, and
|
|
1227
|
+
* rebuild `s.gitService`. No-op when `originalBasePath` is empty (fresh
|
|
1228
|
+
* sessions).
|
|
938
1229
|
*
|
|
939
1230
|
* Used by error/cleanup paths that need the session to behave as if the
|
|
940
1231
|
* worktree was never entered. Does NOT teardown the worktree directory —
|
|
941
1232
|
* callers that need teardown go through `exitMilestone({ merge: false })`.
|
|
1233
|
+
*
|
|
1234
|
+
* ADR-016 phase 3 (#5693): chdir lives inside the verb so callers do not
|
|
1235
|
+
* pair `restoreToProjectRoot()` with a redundant `process.chdir`. The
|
|
1236
|
+
* chdir runs BEFORE the throwable work (`rebuildGitService`, cache
|
|
1237
|
+
* invalidation) so that cleanup-path cwd is restored even if the
|
|
1238
|
+
* downstream rebuild throws. The chdir itself is best-effort; failure is
|
|
1239
|
+
* logged via debugLog and swallowed.
|
|
942
1240
|
*/
|
|
943
1241
|
restoreToProjectRoot() {
|
|
944
1242
|
if (!this.s.originalBasePath)
|
|
945
1243
|
return;
|
|
946
1244
|
this.s.basePath = this.s.originalBasePath;
|
|
1245
|
+
try {
|
|
1246
|
+
process.chdir(this.s.basePath);
|
|
1247
|
+
}
|
|
1248
|
+
catch (err) {
|
|
1249
|
+
debugLog("WorktreeLifecycle", {
|
|
1250
|
+
action: "restoreToProjectRoot",
|
|
1251
|
+
result: "chdir-failed",
|
|
1252
|
+
basePath: this.s.basePath,
|
|
1253
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
947
1256
|
rebuildGitService(this.s, this.deps);
|
|
948
|
-
|
|
1257
|
+
invalidateAllCaches();
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Adopt a session root (ADR-016 phase 2 / B2, issue #5620).
|
|
1261
|
+
*
|
|
1262
|
+
* Sole owner of `s.basePath` mutation for bootstrap-class transitions:
|
|
1263
|
+
* initial session start, paused-resume entry (before persisted-state
|
|
1264
|
+
* consultation), and hook-trigger session activation. Defensive about
|
|
1265
|
+
* `s.originalBasePath`:
|
|
1266
|
+
*
|
|
1267
|
+
* - When `originalBase` is explicit: overwrite.
|
|
1268
|
+
* - Otherwise, set `s.originalBasePath` only if it is currently empty —
|
|
1269
|
+
* resume paths that already restored `s.originalBasePath` from paused
|
|
1270
|
+
* metadata keep their value.
|
|
1271
|
+
*
|
|
1272
|
+
* Does NOT chdir; callers that need cwd alignment with the new basePath
|
|
1273
|
+
* are responsible for it. Does NOT rebuild `s.gitService` — callers that
|
|
1274
|
+
* mutate `s.basePath` to a non-project-root path (e.g. a worktree on a
|
|
1275
|
+
* subsequent milestone enter) go through `enterMilestone`, which handles
|
|
1276
|
+
* the rebuild.
|
|
1277
|
+
*/
|
|
1278
|
+
adoptSessionRoot(base, originalBase) {
|
|
1279
|
+
this.s.basePath = base;
|
|
1280
|
+
if (originalBase !== undefined) {
|
|
1281
|
+
this.s.originalBasePath = originalBase;
|
|
1282
|
+
}
|
|
1283
|
+
else if (!this.s.originalBasePath) {
|
|
1284
|
+
this.s.originalBasePath = base;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Resume from a paused session (ADR-016 phase 2 / B3, issue #5621).
|
|
1289
|
+
*
|
|
1290
|
+
* Adopts `persistedWorktreePath` as `s.basePath` when the path is
|
|
1291
|
+
* non-null and exists on disk; otherwise falls back to `base`. Mirrors
|
|
1292
|
+
* the resume guard at `auto.ts:2164` — a stale or removed worktree
|
|
1293
|
+
* directory must not strand the resumed session in an invalid root.
|
|
1294
|
+
*
|
|
1295
|
+
* Folds in the body of the legacy `_resolvePausedResumeBasePathForTest`
|
|
1296
|
+
* helper (see `resolvePausedResumeBasePath` below). After this verb
|
|
1297
|
+
* lands the helper is deleted from `auto.ts` per the slice-7 closure
|
|
1298
|
+
* decision to retire `_*ForTest` suffixes from production paths.
|
|
1299
|
+
*
|
|
1300
|
+
* Like `adoptSessionRoot`, this is a pure session-state mutation — no
|
|
1301
|
+
* chdir, no git service rebuild, no cache invalidation.
|
|
1302
|
+
*/
|
|
1303
|
+
resumeFromPausedSession(base, persistedWorktreePath) {
|
|
1304
|
+
this.s.basePath = resolvePausedResumeBasePath(base, persistedWorktreePath);
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Adopt an orphan worktree for a bootstrap-time merge (ADR-016 phase 2 / B4,
|
|
1308
|
+
* issue #5622).
|
|
1309
|
+
*
|
|
1310
|
+
* Owns the swap-run-revert protocol that bootstrap previously open-coded:
|
|
1311
|
+
*
|
|
1312
|
+
* 1. Snapshot prior `s.basePath` and `s.originalBasePath`.
|
|
1313
|
+
* 2. Resolve `getAutoWorktreePath(base, milestoneId) ?? base` before
|
|
1314
|
+
* mutating session state, then set `s.originalBasePath = base` and
|
|
1315
|
+
* `s.basePath` to the resolved path.
|
|
1316
|
+
* 3. Invoke the caller-supplied `run` callback under the swap.
|
|
1317
|
+
* 4. On `!result.merged`: revert to `base` and `chdir(base)` so the
|
|
1318
|
+
* caller can return early without leaving the session in a half-
|
|
1319
|
+
* swapped state.
|
|
1320
|
+
* 5. On `result.merged && !s.active`: revert to the snapshotted prior
|
|
1321
|
+
* paths (the orphan merge succeeded but bootstrap chose not to keep
|
|
1322
|
+
* the session active).
|
|
1323
|
+
* 6. On `result.merged && s.active`: leave the swap in place — the
|
|
1324
|
+
* loop will continue from the worktree path.
|
|
1325
|
+
*
|
|
1326
|
+
* The callback shape forces every caller through the same revert
|
|
1327
|
+
* protocol; an open-coded swap that forgets to revert on failure was the
|
|
1328
|
+
* original bug pattern this verb is designed to prevent.
|
|
1329
|
+
*/
|
|
1330
|
+
adoptOrphanWorktree(milestoneId, base, run) {
|
|
1331
|
+
validateMilestoneId(milestoneId);
|
|
1332
|
+
const priorBasePath = this.s.basePath;
|
|
1333
|
+
const priorOriginalBasePath = this.s.originalBasePath;
|
|
1334
|
+
const restorePriorPaths = (phase) => {
|
|
1335
|
+
this.s.basePath = priorBasePath || base;
|
|
1336
|
+
this.s.originalBasePath = priorOriginalBasePath || base;
|
|
1337
|
+
try {
|
|
1338
|
+
process.chdir(this.s.originalBasePath || base);
|
|
1339
|
+
}
|
|
1340
|
+
catch (err) {
|
|
1341
|
+
debugLog("WorktreeLifecycle", {
|
|
1342
|
+
action: "adoptOrphanWorktree",
|
|
1343
|
+
phase,
|
|
1344
|
+
base: this.s.originalBasePath || base,
|
|
1345
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
let adoptedBasePath;
|
|
1350
|
+
try {
|
|
1351
|
+
const wtPathFn = primitiveOverrides(this.deps).getAutoWorktreePath ?? getAutoWorktreePath;
|
|
1352
|
+
adoptedBasePath = wtPathFn(base, milestoneId) ?? base;
|
|
1353
|
+
}
|
|
1354
|
+
catch (err) {
|
|
1355
|
+
restorePriorPaths("rollback-resolve-worktree-failed");
|
|
1356
|
+
throw err;
|
|
1357
|
+
}
|
|
1358
|
+
// Swap into the orphan worktree.
|
|
1359
|
+
this.s.originalBasePath = base;
|
|
1360
|
+
this.s.basePath = adoptedBasePath;
|
|
1361
|
+
let result;
|
|
1362
|
+
try {
|
|
1363
|
+
result = run();
|
|
1364
|
+
}
|
|
1365
|
+
catch (err) {
|
|
1366
|
+
restorePriorPaths("rollback-run-failed");
|
|
1367
|
+
throw err;
|
|
1368
|
+
}
|
|
1369
|
+
if (!result.merged) {
|
|
1370
|
+
// Failed orphan merge — revert to project root so the caller can
|
|
1371
|
+
// safely return early without leaving the session in an invalid
|
|
1372
|
+
// basePath. Mirror the chdir that bootstrap performed inline.
|
|
1373
|
+
this.s.basePath = base;
|
|
1374
|
+
this.s.originalBasePath = base;
|
|
1375
|
+
try {
|
|
1376
|
+
process.chdir(base);
|
|
1377
|
+
}
|
|
1378
|
+
catch (err) {
|
|
1379
|
+
debugLog("WorktreeLifecycle", {
|
|
1380
|
+
action: "adoptOrphanWorktree",
|
|
1381
|
+
phase: "revert-chdir-failed",
|
|
1382
|
+
base,
|
|
1383
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
return result;
|
|
1387
|
+
}
|
|
1388
|
+
if (!this.s.active) {
|
|
1389
|
+
// Merge succeeded but the session was not (re)activated — restore
|
|
1390
|
+
// the snapshotted paths so the calling context resumes where it
|
|
1391
|
+
// was, with the orphan branch now merged on main.
|
|
1392
|
+
this.s.basePath = priorBasePath || base;
|
|
1393
|
+
this.s.originalBasePath = priorOriginalBasePath || base;
|
|
1394
|
+
}
|
|
1395
|
+
// else: merged && active — leave the swap; the loop continues from
|
|
1396
|
+
// the worktree path. Subsequent milestone enters mutate `s.basePath`
|
|
1397
|
+
// through their own Lifecycle verbs.
|
|
1398
|
+
return result;
|
|
949
1399
|
}
|
|
950
1400
|
/** True if `milestoneId` is the session's currently-active milestone. */
|
|
951
1401
|
isInMilestone(milestoneId) {
|