gsd-pi 2.33.1-dev.ee47f1b → 2.34.0-dev.0150ae9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundled-resource-path.d.ts +8 -0
- package/dist/bundled-resource-path.js +14 -0
- package/dist/headless-query.js +6 -6
- package/dist/resources/extensions/gsd/auto/session.js +27 -32
- package/dist/resources/extensions/gsd/auto-dashboard.js +29 -109
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +6 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +52 -81
- package/dist/resources/extensions/gsd/auto-loop.js +956 -0
- package/dist/resources/extensions/gsd/auto-observability.js +4 -2
- package/dist/resources/extensions/gsd/auto-post-unit.js +75 -185
- package/dist/resources/extensions/gsd/auto-prompts.js +133 -101
- package/dist/resources/extensions/gsd/auto-recovery.js +59 -97
- package/dist/resources/extensions/gsd/auto-start.js +330 -309
- package/dist/resources/extensions/gsd/auto-supervisor.js +5 -11
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +7 -7
- package/dist/resources/extensions/gsd/auto-timers.js +3 -4
- package/dist/resources/extensions/gsd/auto-verification.js +35 -73
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +167 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +291 -126
- package/dist/resources/extensions/gsd/auto.js +283 -1013
- package/dist/resources/extensions/gsd/captures.js +10 -4
- package/dist/resources/extensions/gsd/dispatch-guard.js +7 -8
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +25 -18
- package/dist/resources/extensions/gsd/doctor-checks.js +3 -4
- package/dist/resources/extensions/gsd/git-service.js +1 -1
- package/dist/resources/extensions/gsd/gsd-db.js +296 -151
- package/dist/resources/extensions/gsd/index.js +92 -228
- package/dist/resources/extensions/gsd/post-unit-hooks.js +13 -13
- package/dist/resources/extensions/gsd/progress-score.js +61 -156
- package/dist/resources/extensions/gsd/quick.js +98 -122
- package/dist/resources/extensions/gsd/session-lock.js +13 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
- package/dist/resources/extensions/gsd/undo.js +43 -48
- package/dist/resources/extensions/gsd/unit-runtime.js +16 -15
- package/dist/resources/extensions/gsd/verification-evidence.js +0 -1
- package/dist/resources/extensions/gsd/verification-gate.js +6 -35
- package/dist/resources/extensions/gsd/worktree-command.js +30 -24
- package/dist/resources/extensions/gsd/worktree-manager.js +2 -3
- package/dist/resources/extensions/gsd/worktree-resolver.js +344 -0
- package/dist/resources/extensions/gsd/worktree.js +7 -44
- package/dist/resources/extensions/mcp-client/index.js +2 -1
- package/dist/tool-bootstrap.js +59 -11
- package/dist/worktree-cli.js +7 -7
- package/package.json +1 -1
- package/packages/native/dist/native.d.ts +0 -2
- package/packages/native/dist/native.js +0 -2
- package/packages/native/src/native.ts +0 -3
- package/packages/pi-agent-core/dist/proxy.d.ts +1 -25
- package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/proxy.js +1 -1
- package/packages/pi-agent-core/dist/proxy.js.map +1 -1
- package/packages/pi-agent-core/src/proxy.ts +1 -1
- package/packages/pi-ai/dist/api-registry.d.ts +0 -2
- package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
- package/packages/pi-ai/dist/api-registry.js +0 -10
- package/packages/pi-ai/dist/api-registry.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +3630 -5483
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +735 -2588
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts +0 -8
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/github-copilot-headers.d.ts +0 -1
- package/packages/pi-ai/dist/providers/github-copilot-headers.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/github-copilot-headers.js +1 -1
- package/packages/pi-ai/dist/providers/github-copilot-headers.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts +1 -43
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +2 -2
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.d.ts +0 -4
- package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.d.ts +0 -1
- package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.js +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
- package/packages/pi-ai/dist/utils/event-stream.d.ts +0 -2
- package/packages/pi-ai/dist/utils/event-stream.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/event-stream.js +0 -4
- package/packages/pi-ai/dist/utils/event-stream.js.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.d.ts +0 -4
- package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.js +0 -6
- package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
- package/packages/pi-ai/dist/utils/validation.d.ts +0 -8
- package/packages/pi-ai/dist/utils/validation.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/validation.js +0 -14
- package/packages/pi-ai/dist/utils/validation.js.map +1 -1
- package/packages/pi-ai/src/api-registry.ts +0 -12
- package/packages/pi-ai/src/models.generated.ts +1039 -2892
- package/packages/pi-ai/src/providers/anthropic.ts +1 -1
- package/packages/pi-ai/src/providers/github-copilot-headers.ts +1 -1
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +2 -2
- package/packages/pi-ai/src/providers/google-shared.ts +1 -1
- package/packages/pi-ai/src/providers/register-builtins.ts +1 -1
- package/packages/pi-ai/src/utils/event-stream.ts +0 -5
- package/packages/pi-ai/src/utils/overflow.ts +1 -8
- package/packages/pi-ai/src/utils/validation.ts +0 -15
- package/packages/pi-coding-agent/dist/config.d.ts +0 -9
- package/packages/pi-coding-agent/dist/config.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/config.js +4 -8
- package/packages/pi-coding-agent/dist/config.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.d.ts +0 -4
- package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.js +1 -1
- package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +0 -5
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +0 -13
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts +0 -8
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.js +2 -2
- package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +0 -17
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -62
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.d.ts +0 -2
- package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.js +0 -7
- package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/edits.d.ts +0 -5
- package/packages/pi-coding-agent/dist/core/lsp/edits.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/edits.js +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/edits.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts +0 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +1 -6
- package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.js +1 -28
- package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.d.ts +0 -8
- package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.js +5 -5
- package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +0 -3
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +1 -3
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts +1 -26
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +3 -59
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/prompt-templates.d.ts +0 -17
- package/packages/pi-coding-agent/dist/core/prompt-templates.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/prompt-templates.js +2 -2
- package/packages/pi-coding-agent/dist/core/prompt-templates.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +0 -4
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +2 -4
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +0 -12
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +2 -2
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/migrations.d.ts +0 -16
- package/packages/pi-coding-agent/dist/migrations.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/migrations.js +2 -2
- package/packages/pi-coding-agent/dist/migrations.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.d.ts +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -24
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +50 -512
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts +71 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +514 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +65 -4
- 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 +6 -23
- 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 +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +175 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -0
- package/packages/pi-coding-agent/dist/utils/changelog.d.ts +0 -4
- package/packages/pi-coding-agent/dist/utils/changelog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/changelog.js +1 -1
- package/packages/pi-coding-agent/dist/utils/changelog.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/clipboard-image.d.ts +0 -1
- package/packages/pi-coding-agent/dist/utils/clipboard-image.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/clipboard-image.js +1 -1
- package/packages/pi-coding-agent/dist/utils/clipboard-image.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/photon.d.ts +0 -19
- package/packages/pi-coding-agent/dist/utils/photon.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/photon.js +1 -120
- package/packages/pi-coding-agent/dist/utils/photon.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/tools-manager.d.ts +0 -1
- package/packages/pi-coding-agent/dist/utils/tools-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/tools-manager.js +1 -1
- package/packages/pi-coding-agent/dist/utils/tools-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/config.ts +5 -10
- package/packages/pi-coding-agent/src/core/export-html/ansi-to-html.ts +1 -1
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +0 -13
- package/packages/pi-coding-agent/src/core/keybindings.ts +2 -2
- package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -73
- package/packages/pi-coding-agent/src/core/lsp/config.ts +0 -11
- package/packages/pi-coding-agent/src/core/lsp/edits.ts +1 -1
- package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +1 -1
- package/packages/pi-coding-agent/src/core/lsp/utils.ts +1 -33
- package/packages/pi-coding-agent/src/core/messages.ts +5 -5
- package/packages/pi-coding-agent/src/core/model-registry.ts +0 -2
- package/packages/pi-coding-agent/src/core/model-resolver.ts +3 -77
- package/packages/pi-coding-agent/src/core/prompt-templates.ts +2 -2
- package/packages/pi-coding-agent/src/core/session-manager.ts +2 -4
- package/packages/pi-coding-agent/src/core/settings-manager.ts +2 -2
- package/packages/pi-coding-agent/src/migrations.ts +2 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/session-selector-search.ts +2 -2
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +50 -561
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +653 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +7 -26
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +196 -0
- package/packages/pi-coding-agent/src/utils/changelog.ts +1 -1
- package/packages/pi-coding-agent/src/utils/clipboard-image.ts +1 -1
- package/packages/pi-coding-agent/src/utils/photon.ts +0 -137
- package/packages/pi-coding-agent/src/utils/tools-manager.ts +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +0 -10
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +1 -1
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.d.ts +55 -0
- package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -0
- package/packages/pi-tui/dist/overlay-layout.js +288 -0
- package/packages/pi-tui/dist/overlay-layout.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts +0 -22
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +6 -272
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/dist/utils.d.ts +0 -7
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +0 -44
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/src/components/editor.ts +1 -1
- package/packages/pi-tui/src/overlay-layout.ts +372 -0
- package/packages/pi-tui/src/tui.ts +11 -312
- package/packages/pi-tui/src/utils.ts +0 -43
- package/pkg/dist/core/export-html/ansi-to-html.d.ts +0 -4
- package/pkg/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/pkg/dist/core/export-html/ansi-to-html.js +1 -1
- package/pkg/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts +65 -4
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +6 -23
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts +12 -0
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/themes.js +175 -0
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/session.ts +47 -30
- package/src/resources/extensions/gsd/auto-dashboard.ts +28 -131
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +6 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +135 -91
- package/src/resources/extensions/gsd/auto-loop.ts +1665 -0
- package/src/resources/extensions/gsd/auto-observability.ts +4 -2
- package/src/resources/extensions/gsd/auto-post-unit.ts +85 -228
- package/src/resources/extensions/gsd/auto-prompts.ts +138 -109
- package/src/resources/extensions/gsd/auto-recovery.ts +124 -118
- package/src/resources/extensions/gsd/auto-start.ts +440 -354
- package/src/resources/extensions/gsd/auto-supervisor.ts +5 -12
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +8 -8
- package/src/resources/extensions/gsd/auto-timers.ts +3 -4
- package/src/resources/extensions/gsd/auto-verification.ts +76 -90
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +204 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +389 -141
- package/src/resources/extensions/gsd/auto.ts +515 -1199
- package/src/resources/extensions/gsd/captures.ts +10 -4
- package/src/resources/extensions/gsd/dispatch-guard.ts +13 -9
- package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -18
- package/src/resources/extensions/gsd/doctor-checks.ts +3 -4
- package/src/resources/extensions/gsd/git-service.ts +8 -1
- package/src/resources/extensions/gsd/gitignore.ts +4 -2
- package/src/resources/extensions/gsd/gsd-db.ts +375 -180
- package/src/resources/extensions/gsd/index.ts +104 -263
- package/src/resources/extensions/gsd/post-unit-hooks.ts +13 -13
- package/src/resources/extensions/gsd/progress-score.ts +65 -200
- package/src/resources/extensions/gsd/quick.ts +121 -125
- package/src/resources/extensions/gsd/session-lock.ts +11 -0
- package/src/resources/extensions/gsd/templates/preferences.md +1 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +32 -59
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +75 -27
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1458 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +8 -162
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -108
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +1 -3
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -55
- package/src/resources/extensions/gsd/tests/headless-query.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +8 -11
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +4 -6
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/undo.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +24 -26
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +7 -201
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +705 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +57 -106
- package/src/resources/extensions/gsd/tests/worktree.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +43 -132
- package/src/resources/extensions/gsd/types.ts +90 -81
- package/src/resources/extensions/gsd/undo.ts +42 -46
- package/src/resources/extensions/gsd/unit-runtime.ts +14 -18
- package/src/resources/extensions/gsd/verification-evidence.ts +1 -3
- package/src/resources/extensions/gsd/verification-gate.ts +6 -39
- package/src/resources/extensions/gsd/worktree-command.ts +36 -24
- package/src/resources/extensions/gsd/worktree-manager.ts +2 -3
- package/src/resources/extensions/gsd/worktree-resolver.ts +485 -0
- package/src/resources/extensions/gsd/worktree.ts +7 -44
- package/src/resources/extensions/mcp-client/index.ts +2 -1
- package/dist/resources/extensions/gsd/auto-constants.js +0 -5
- package/dist/resources/extensions/gsd/auto-idempotency.js +0 -106
- package/dist/resources/extensions/gsd/auto-stuck-detection.js +0 -165
- package/dist/resources/extensions/gsd/mechanical-completion.js +0 -351
- package/packages/pi-coding-agent/dist/modes/interactive/theme/dark.json +0 -85
- package/packages/pi-coding-agent/dist/modes/interactive/theme/light.json +0 -84
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.json +0 -335
- package/packages/pi-coding-agent/src/modes/interactive/theme/dark.json +0 -85
- package/packages/pi-coding-agent/src/modes/interactive/theme/light.json +0 -84
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.json +0 -335
- package/pkg/dist/modes/interactive/theme/dark.json +0 -85
- package/pkg/dist/modes/interactive/theme/light.json +0 -84
- package/pkg/dist/modes/interactive/theme/theme-schema.json +0 -335
- package/src/resources/extensions/gsd/auto-constants.ts +0 -6
- package/src/resources/extensions/gsd/auto-idempotency.ts +0 -151
- package/src/resources/extensions/gsd/auto-stuck-detection.ts +0 -221
- package/src/resources/extensions/gsd/mechanical-completion.ts +0 -430
- package/src/resources/extensions/gsd/tests/auto-dispatch-loop.test.ts +0 -691
- package/src/resources/extensions/gsd/tests/auto-reentrancy-guard.test.ts +0 -127
- package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +0 -123
- package/src/resources/extensions/gsd/tests/dispatch-stall-guard.test.ts +0 -126
- package/src/resources/extensions/gsd/tests/loop-regression.test.ts +0 -874
- package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +0 -356
- package/src/resources/extensions/gsd/tests/progress-score.test.ts +0 -206
- package/src/resources/extensions/gsd/tests/session-lock.test.ts +0 -434
|
@@ -5,22 +5,39 @@
|
|
|
5
5
|
* manual `/worktree` which uses `worktree/<name>` branches). This module
|
|
6
6
|
* manages create, enter, detect, and teardown for auto-mode worktrees.
|
|
7
7
|
*/
|
|
8
|
-
import { existsSync,
|
|
8
|
+
import { existsSync, cpSync, readFileSync, readdirSync, mkdirSync, realpathSync, unlinkSync, lstatSync as lstatSyncFn, } from "node:fs";
|
|
9
9
|
import { isAbsolute, join } from "node:path";
|
|
10
10
|
import { GSDError, GSD_IO_ERROR, GSD_GIT_ERROR } from "./errors.js";
|
|
11
|
+
import { copyWorktreeDb, reconcileWorktreeDb, isDbAvailable, } from "./gsd-db.js";
|
|
12
|
+
import { atomicWriteSync } from "./atomic-write.js";
|
|
11
13
|
import { execSync } from "node:child_process";
|
|
14
|
+
import { safeCopy, safeCopyRecursive } from "./safe-fs.js";
|
|
15
|
+
import { gsdRoot } from "./paths.js";
|
|
12
16
|
import { createWorktree, removeWorktree, worktreePath, } from "./worktree-manager.js";
|
|
13
|
-
import { detectWorktreeName, nudgeGitBranchCache } from "./worktree.js";
|
|
14
|
-
import {
|
|
15
|
-
import { MergeConflictError, readIntegrationBranch, } from "./git-service.js";
|
|
17
|
+
import { detectWorktreeName, nudgeGitBranchCache, } from "./worktree.js";
|
|
18
|
+
import { MergeConflictError, readIntegrationBranch } from "./git-service.js";
|
|
16
19
|
import { parseRoadmap } from "./files.js";
|
|
17
20
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
18
|
-
import { gsdRoot } from "./paths.js";
|
|
19
21
|
import { nativeGetCurrentBranch, nativeWorkingTreeStatus, nativeAddAll, nativeCommit, nativeCheckoutBranch, nativeMergeSquash, nativeConflictFiles, nativeCheckoutTheirs, nativeAddPaths, nativeRmForce, nativeBranchDelete, nativeBranchExists, } from "./native-git-bridge.js";
|
|
20
|
-
import { getErrorMessage } from "./error-utils.js";
|
|
21
22
|
// ─── Module State ──────────────────────────────────────────────────────────
|
|
22
23
|
/** Original project root before chdir into auto-worktree. */
|
|
23
24
|
let originalBase = null;
|
|
25
|
+
function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
26
|
+
const gsdDir = gsdRoot(basePath);
|
|
27
|
+
const transientFiles = [
|
|
28
|
+
join(gsdDir, "STATE.md"),
|
|
29
|
+
join(gsdDir, "auto.lock"),
|
|
30
|
+
join(gsdDir, "milestones", milestoneId, `${milestoneId}-META.json`),
|
|
31
|
+
];
|
|
32
|
+
for (const file of transientFiles) {
|
|
33
|
+
try {
|
|
34
|
+
unlinkSync(file);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* non-fatal — file may not exist */
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
24
41
|
// ─── Worktree ↔ Main Repo Sync (#1311) ──────────────────────────────────────
|
|
25
42
|
/**
|
|
26
43
|
* Sync .gsd/ state from the main repo into the worktree.
|
|
@@ -53,7 +70,13 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
53
70
|
if (!existsSync(mainGsd) || !existsSync(wtGsd))
|
|
54
71
|
return { synced };
|
|
55
72
|
// Sync root-level .gsd/ files (DECISIONS, REQUIREMENTS, PROJECT, KNOWLEDGE)
|
|
56
|
-
const rootFiles = [
|
|
73
|
+
const rootFiles = [
|
|
74
|
+
"DECISIONS.md",
|
|
75
|
+
"REQUIREMENTS.md",
|
|
76
|
+
"PROJECT.md",
|
|
77
|
+
"KNOWLEDGE.md",
|
|
78
|
+
"OVERRIDES.md",
|
|
79
|
+
];
|
|
57
80
|
for (const f of rootFiles) {
|
|
58
81
|
const src = join(mainGsd, f);
|
|
59
82
|
const dst = join(wtGsd, f);
|
|
@@ -62,7 +85,9 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
62
85
|
cpSync(src, dst);
|
|
63
86
|
synced.push(f);
|
|
64
87
|
}
|
|
65
|
-
catch {
|
|
88
|
+
catch {
|
|
89
|
+
/* non-fatal */
|
|
90
|
+
}
|
|
66
91
|
}
|
|
67
92
|
}
|
|
68
93
|
// Sync milestones: copy entire milestone directories that are missing
|
|
@@ -71,9 +96,11 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
71
96
|
if (existsSync(mainMilestonesDir)) {
|
|
72
97
|
try {
|
|
73
98
|
mkdirSync(wtMilestonesDir, { recursive: true });
|
|
74
|
-
const mainMilestones = readdirSync(mainMilestonesDir, {
|
|
75
|
-
|
|
76
|
-
|
|
99
|
+
const mainMilestones = readdirSync(mainMilestonesDir, {
|
|
100
|
+
withFileTypes: true,
|
|
101
|
+
})
|
|
102
|
+
.filter((d) => d.isDirectory() && /^M\d{3}/.test(d.name))
|
|
103
|
+
.map((d) => d.name);
|
|
77
104
|
for (const mid of mainMilestones) {
|
|
78
105
|
const srcDir = join(mainMilestonesDir, mid);
|
|
79
106
|
const dstDir = join(wtMilestonesDir, mid);
|
|
@@ -83,13 +110,15 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
83
110
|
cpSync(srcDir, dstDir, { recursive: true });
|
|
84
111
|
synced.push(`milestones/${mid}/`);
|
|
85
112
|
}
|
|
86
|
-
catch {
|
|
113
|
+
catch {
|
|
114
|
+
/* non-fatal */
|
|
115
|
+
}
|
|
87
116
|
}
|
|
88
117
|
else {
|
|
89
118
|
// Milestone directory exists but may be missing files (stale snapshot).
|
|
90
119
|
// Sync individual top-level milestone files (CONTEXT, ROADMAP, RESEARCH, etc.)
|
|
91
120
|
try {
|
|
92
|
-
const srcFiles = readdirSync(srcDir).filter(f => f.endsWith(".md") || f.endsWith(".json"));
|
|
121
|
+
const srcFiles = readdirSync(srcDir).filter((f) => f.endsWith(".md") || f.endsWith(".json"));
|
|
93
122
|
for (const f of srcFiles) {
|
|
94
123
|
const srcFile = join(srcDir, f);
|
|
95
124
|
const dstFile = join(dstDir, f);
|
|
@@ -101,7 +130,9 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
101
130
|
synced.push(`milestones/${mid}/${f}`);
|
|
102
131
|
}
|
|
103
132
|
}
|
|
104
|
-
catch {
|
|
133
|
+
catch {
|
|
134
|
+
/* non-fatal */
|
|
135
|
+
}
|
|
105
136
|
}
|
|
106
137
|
}
|
|
107
138
|
// Sync slices directory if it exists in main but not in worktree
|
|
@@ -112,13 +143,17 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
112
143
|
cpSync(srcSlicesDir, dstSlicesDir, { recursive: true });
|
|
113
144
|
synced.push(`milestones/${mid}/slices/`);
|
|
114
145
|
}
|
|
115
|
-
catch {
|
|
146
|
+
catch {
|
|
147
|
+
/* non-fatal */
|
|
148
|
+
}
|
|
116
149
|
}
|
|
117
150
|
else if (existsSync(srcSlicesDir) && existsSync(dstSlicesDir)) {
|
|
118
151
|
// Both exist — sync missing slice directories
|
|
119
|
-
const srcSlices = readdirSync(srcSlicesDir, {
|
|
120
|
-
|
|
121
|
-
|
|
152
|
+
const srcSlices = readdirSync(srcSlicesDir, {
|
|
153
|
+
withFileTypes: true,
|
|
154
|
+
})
|
|
155
|
+
.filter((d) => d.isDirectory())
|
|
156
|
+
.map((d) => d.name);
|
|
122
157
|
for (const sid of srcSlices) {
|
|
123
158
|
const srcSlice = join(srcSlicesDir, sid);
|
|
124
159
|
const dstSlice = join(dstSlicesDir, sid);
|
|
@@ -127,16 +162,22 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
127
162
|
cpSync(srcSlice, dstSlice, { recursive: true });
|
|
128
163
|
synced.push(`milestones/${mid}/slices/${sid}/`);
|
|
129
164
|
}
|
|
130
|
-
catch {
|
|
165
|
+
catch {
|
|
166
|
+
/* non-fatal */
|
|
167
|
+
}
|
|
131
168
|
}
|
|
132
169
|
}
|
|
133
170
|
}
|
|
134
171
|
}
|
|
135
|
-
catch {
|
|
172
|
+
catch {
|
|
173
|
+
/* non-fatal */
|
|
174
|
+
}
|
|
136
175
|
}
|
|
137
176
|
}
|
|
138
177
|
}
|
|
139
|
-
catch {
|
|
178
|
+
catch {
|
|
179
|
+
/* non-fatal */
|
|
180
|
+
}
|
|
140
181
|
}
|
|
141
182
|
return { synced };
|
|
142
183
|
}
|
|
@@ -177,24 +218,32 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
|
177
218
|
cpSync(src, dst, { force: true });
|
|
178
219
|
synced.push(`milestones/${milestoneId}/${entry.name}`);
|
|
179
220
|
}
|
|
180
|
-
catch {
|
|
221
|
+
catch {
|
|
222
|
+
/* non-fatal */
|
|
223
|
+
}
|
|
181
224
|
}
|
|
182
225
|
}
|
|
183
226
|
}
|
|
184
|
-
catch {
|
|
227
|
+
catch {
|
|
228
|
+
/* non-fatal */
|
|
229
|
+
}
|
|
185
230
|
// Sync slice-level files (summaries, UATs)
|
|
186
231
|
const wtSlicesDir = join(wtMilestoneDir, "slices");
|
|
187
232
|
const mainSlicesDir = join(mainMilestoneDir, "slices");
|
|
188
233
|
if (existsSync(wtSlicesDir)) {
|
|
189
234
|
try {
|
|
190
|
-
for (const sliceEntry of readdirSync(wtSlicesDir, {
|
|
235
|
+
for (const sliceEntry of readdirSync(wtSlicesDir, {
|
|
236
|
+
withFileTypes: true,
|
|
237
|
+
})) {
|
|
191
238
|
if (!sliceEntry.isDirectory())
|
|
192
239
|
continue;
|
|
193
240
|
const sid = sliceEntry.name;
|
|
194
241
|
const wtSliceDir = join(wtSlicesDir, sid);
|
|
195
242
|
const mainSliceDir = join(mainSlicesDir, sid);
|
|
196
243
|
mkdirSync(mainSliceDir, { recursive: true });
|
|
197
|
-
for (const fileEntry of readdirSync(wtSliceDir, {
|
|
244
|
+
for (const fileEntry of readdirSync(wtSliceDir, {
|
|
245
|
+
withFileTypes: true,
|
|
246
|
+
})) {
|
|
198
247
|
if (fileEntry.isFile() && fileEntry.name.endsWith(".md")) {
|
|
199
248
|
const src = join(wtSliceDir, fileEntry.name);
|
|
200
249
|
const dst = join(mainSliceDir, fileEntry.name);
|
|
@@ -202,12 +251,16 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
|
202
251
|
cpSync(src, dst, { force: true });
|
|
203
252
|
synced.push(`milestones/${milestoneId}/slices/${sid}/${fileEntry.name}`);
|
|
204
253
|
}
|
|
205
|
-
catch {
|
|
254
|
+
catch {
|
|
255
|
+
/* non-fatal */
|
|
256
|
+
}
|
|
206
257
|
}
|
|
207
258
|
}
|
|
208
259
|
}
|
|
209
260
|
}
|
|
210
|
-
catch {
|
|
261
|
+
catch {
|
|
262
|
+
/* non-fatal */
|
|
263
|
+
}
|
|
211
264
|
}
|
|
212
265
|
return { synced };
|
|
213
266
|
}
|
|
@@ -247,7 +300,7 @@ export function runWorktreePostCreateHook(sourceDir, worktreeDir, hookPath) {
|
|
|
247
300
|
return null;
|
|
248
301
|
}
|
|
249
302
|
catch (err) {
|
|
250
|
-
const msg =
|
|
303
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
251
304
|
return `Worktree post-create hook failed: ${msg}`;
|
|
252
305
|
}
|
|
253
306
|
}
|
|
@@ -263,6 +316,96 @@ export function autoWorktreeBranch(milestoneId) {
|
|
|
263
316
|
* Atomic: chdir + originalBase update happen in the same try block
|
|
264
317
|
* to prevent split-brain.
|
|
265
318
|
*/
|
|
319
|
+
/**
|
|
320
|
+
* Forward-merge plan checkbox state from the project root into a freshly
|
|
321
|
+
* re-attached worktree (#778).
|
|
322
|
+
*
|
|
323
|
+
* When auto-mode stops via crash (not graceful stop), the milestone branch
|
|
324
|
+
* HEAD may be behind the filesystem state at the project root because
|
|
325
|
+
* syncStateToProjectRoot() runs after every task completion but the final
|
|
326
|
+
* git commit may not have happened before the crash. On restart the worktree
|
|
327
|
+
* is re-attached to the branch HEAD, which has [ ] for the crashed task,
|
|
328
|
+
* causing verifyExpectedArtifact() to fail and triggering an infinite
|
|
329
|
+
* dispatch/skip loop.
|
|
330
|
+
*
|
|
331
|
+
* Fix: after re-attaching, read every *.md plan file in the milestone
|
|
332
|
+
* directory at the project root and apply any [x] checkbox states that are
|
|
333
|
+
* ahead of the worktree version (forward-only: never downgrade [x] → [ ]).
|
|
334
|
+
*
|
|
335
|
+
* This is safe because syncStateToProjectRoot() is the authoritative source
|
|
336
|
+
* of post-task state at the project root — it writes the same [x] the LLM
|
|
337
|
+
* produced, then the auto-commit follows. If the commit never happened, the
|
|
338
|
+
* filesystem copy is still valid and correct.
|
|
339
|
+
*/
|
|
340
|
+
function reconcilePlanCheckboxes(projectRoot, wtPath, milestoneId) {
|
|
341
|
+
const srcMilestone = join(projectRoot, ".gsd", "milestones", milestoneId);
|
|
342
|
+
const dstMilestone = join(wtPath, ".gsd", "milestones", milestoneId);
|
|
343
|
+
if (!existsSync(srcMilestone) || !existsSync(dstMilestone))
|
|
344
|
+
return;
|
|
345
|
+
// Walk all markdown files in the milestone directory (plans, summaries, etc.)
|
|
346
|
+
function walkMd(dir) {
|
|
347
|
+
const results = [];
|
|
348
|
+
try {
|
|
349
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
350
|
+
const full = join(dir, entry.name);
|
|
351
|
+
if (entry.isDirectory()) {
|
|
352
|
+
results.push(...walkMd(full));
|
|
353
|
+
}
|
|
354
|
+
else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
355
|
+
results.push(full);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
/* non-fatal */
|
|
361
|
+
}
|
|
362
|
+
return results;
|
|
363
|
+
}
|
|
364
|
+
for (const srcFile of walkMd(srcMilestone)) {
|
|
365
|
+
const rel = srcFile.slice(srcMilestone.length);
|
|
366
|
+
const dstFile = dstMilestone + rel;
|
|
367
|
+
if (!existsSync(dstFile))
|
|
368
|
+
continue; // only reconcile existing files
|
|
369
|
+
let srcContent;
|
|
370
|
+
let dstContent;
|
|
371
|
+
try {
|
|
372
|
+
srcContent = readFileSync(srcFile, "utf-8");
|
|
373
|
+
dstContent = readFileSync(dstFile, "utf-8");
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (srcContent === dstContent)
|
|
379
|
+
continue;
|
|
380
|
+
// Extract all checked task IDs from the source (project root)
|
|
381
|
+
// Pattern: - [x] **T<id>: or - [x] **S<id>: (case-insensitive x)
|
|
382
|
+
const checkedRe = /^- \[[xX]\] \*\*([TS]\d+):/gm;
|
|
383
|
+
const srcChecked = new Set();
|
|
384
|
+
for (const m of srcContent.matchAll(checkedRe))
|
|
385
|
+
srcChecked.add(m[1]);
|
|
386
|
+
if (srcChecked.size === 0)
|
|
387
|
+
continue;
|
|
388
|
+
// Forward-apply: replace [ ] → [x] for any IDs that are checked in src
|
|
389
|
+
let updated = dstContent;
|
|
390
|
+
let changed = false;
|
|
391
|
+
for (const id of srcChecked) {
|
|
392
|
+
const escapedId = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
393
|
+
const uncheckedRe = new RegExp(`^(- )\\[ \\]( \\*\\*${escapedId}:)`, "gm");
|
|
394
|
+
if (uncheckedRe.test(updated)) {
|
|
395
|
+
updated = updated.replace(new RegExp(`^(- )\\[ \\]( \\*\\*${escapedId}:)`, "gm"), "$1[x]$2");
|
|
396
|
+
changed = true;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (changed) {
|
|
400
|
+
try {
|
|
401
|
+
atomicWriteSync(dstFile, updated, "utf-8");
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
/* non-fatal */
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
266
409
|
export function createAutoWorktree(basePath, milestoneId) {
|
|
267
410
|
const branch = autoWorktreeBranch(milestoneId);
|
|
268
411
|
// Check if the milestone branch already exists — it survives auto-mode
|
|
@@ -273,20 +416,46 @@ export function createAutoWorktree(basePath, milestoneId) {
|
|
|
273
416
|
let info;
|
|
274
417
|
if (branchExists) {
|
|
275
418
|
// Re-attach worktree to the existing milestone branch (preserving commits)
|
|
276
|
-
info = createWorktree(basePath, milestoneId, {
|
|
419
|
+
info = createWorktree(basePath, milestoneId, {
|
|
420
|
+
branch,
|
|
421
|
+
reuseExistingBranch: true,
|
|
422
|
+
});
|
|
277
423
|
}
|
|
278
424
|
else {
|
|
279
425
|
// Fresh start — create branch from integration branch
|
|
280
426
|
const integrationBranch = readIntegrationBranch(basePath, milestoneId) ?? undefined;
|
|
281
|
-
info = createWorktree(basePath, milestoneId, {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
//
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
|
|
427
|
+
info = createWorktree(basePath, milestoneId, {
|
|
428
|
+
branch,
|
|
429
|
+
startPoint: integrationBranch,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
// Copy .gsd/ planning artifacts from the source repo into the new worktree.
|
|
433
|
+
// Worktrees are fresh git checkouts — untracked files don't carry over.
|
|
434
|
+
// Planning artifacts may be untracked if the project's .gitignore had a
|
|
435
|
+
// blanket .gsd/ rule (pre-v2.14.0). Without this copy, auto-mode loops
|
|
436
|
+
// on plan-slice because the plan file doesn't exist in the worktree.
|
|
437
|
+
//
|
|
438
|
+
// IMPORTANT: Skip when re-attaching to an existing branch (#759).
|
|
439
|
+
// The branch checkout already has committed artifacts with correct state
|
|
440
|
+
// (e.g. [x] for completed slices). Copying from the project root would
|
|
441
|
+
// overwrite them with stale data ([ ] checkboxes) because the root is
|
|
442
|
+
// not always fully synced.
|
|
443
|
+
if (!branchExists) {
|
|
444
|
+
copyPlanningArtifacts(basePath, info.path);
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
// Re-attaching to an existing branch: forward-merge any plan checkpoint
|
|
448
|
+
// state from the project root into the worktree (#778).
|
|
449
|
+
//
|
|
450
|
+
// If auto-mode stopped via crash, the milestone branch HEAD may lag behind
|
|
451
|
+
// the project root filesystem because syncStateToProjectRoot() ran after
|
|
452
|
+
// task completion but the auto-commit never fired. On restart the worktree
|
|
453
|
+
// is re-created from the branch HEAD (which has [ ] for the crashed task),
|
|
454
|
+
// causing verifyExpectedArtifact() to return false → stale-key eviction →
|
|
455
|
+
// infinite dispatch/skip loop. Reconciling here ensures the worktree sees
|
|
456
|
+
// the same [x] state that syncStateToProjectRoot() wrote to the root.
|
|
457
|
+
reconcilePlanCheckboxes(basePath, info.path, milestoneId);
|
|
458
|
+
}
|
|
290
459
|
// Run user-configured post-create hook (#597) — e.g. copy .env, symlink assets
|
|
291
460
|
const hookError = runWorktreePostCreateHook(basePath, info.path);
|
|
292
461
|
if (hookError) {
|
|
@@ -301,11 +470,52 @@ export function createAutoWorktree(basePath, milestoneId) {
|
|
|
301
470
|
catch (err) {
|
|
302
471
|
// If chdir fails, the worktree was created but we couldn't enter it.
|
|
303
472
|
// Don't store originalBase -- caller can retry or clean up.
|
|
304
|
-
throw new GSDError(GSD_IO_ERROR, `Auto-worktree created at ${info.path} but chdir failed: ${
|
|
473
|
+
throw new GSDError(GSD_IO_ERROR, `Auto-worktree created at ${info.path} but chdir failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
305
474
|
}
|
|
306
475
|
nudgeGitBranchCache(previousCwd);
|
|
307
476
|
return info.path;
|
|
308
477
|
}
|
|
478
|
+
/**
|
|
479
|
+
* Copy .gsd/ planning artifacts from source repo to a new worktree.
|
|
480
|
+
* Copies milestones/, DECISIONS.md, REQUIREMENTS.md, PROJECT.md, QUEUE.md,
|
|
481
|
+
* STATE.md, KNOWLEDGE.md, and OVERRIDES.md.
|
|
482
|
+
* Skips runtime files (auto.lock, metrics.json, etc.) and the worktrees/ dir.
|
|
483
|
+
* Best-effort — failures are non-fatal since auto-mode can recreate artifacts.
|
|
484
|
+
*/
|
|
485
|
+
function copyPlanningArtifacts(srcBase, wtPath) {
|
|
486
|
+
const srcGsd = join(srcBase, ".gsd");
|
|
487
|
+
const dstGsd = join(wtPath, ".gsd");
|
|
488
|
+
if (!existsSync(srcGsd))
|
|
489
|
+
return;
|
|
490
|
+
// Copy milestones/ directory (planning files, roadmaps, plans, research)
|
|
491
|
+
safeCopyRecursive(join(srcGsd, "milestones"), join(dstGsd, "milestones"), {
|
|
492
|
+
force: true,
|
|
493
|
+
filter: (src) => !src.endsWith("-META.json"),
|
|
494
|
+
});
|
|
495
|
+
// Copy top-level planning files
|
|
496
|
+
for (const file of [
|
|
497
|
+
"DECISIONS.md",
|
|
498
|
+
"REQUIREMENTS.md",
|
|
499
|
+
"PROJECT.md",
|
|
500
|
+
"QUEUE.md",
|
|
501
|
+
"STATE.md",
|
|
502
|
+
"KNOWLEDGE.md",
|
|
503
|
+
"OVERRIDES.md",
|
|
504
|
+
]) {
|
|
505
|
+
safeCopy(join(srcGsd, file), join(dstGsd, file), { force: true });
|
|
506
|
+
}
|
|
507
|
+
// Copy gsd.db if present in source
|
|
508
|
+
const srcDb = join(srcGsd, "gsd.db");
|
|
509
|
+
const destDb = join(dstGsd, "gsd.db");
|
|
510
|
+
if (existsSync(srcDb)) {
|
|
511
|
+
try {
|
|
512
|
+
copyWorktreeDb(srcDb, destDb);
|
|
513
|
+
}
|
|
514
|
+
catch {
|
|
515
|
+
/* non-fatal */
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
309
519
|
/**
|
|
310
520
|
* Teardown an auto-worktree: chdir back to original base, then remove
|
|
311
521
|
* the worktree and its branch.
|
|
@@ -319,50 +529,28 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
|
|
|
319
529
|
originalBase = null;
|
|
320
530
|
}
|
|
321
531
|
catch (err) {
|
|
322
|
-
throw new GSDError(GSD_IO_ERROR, `Failed to chdir back to ${originalBasePath} during teardown: ${
|
|
532
|
+
throw new GSDError(GSD_IO_ERROR, `Failed to chdir back to ${originalBasePath} during teardown: ${err instanceof Error ? err.message : String(err)}`);
|
|
323
533
|
}
|
|
324
534
|
nudgeGitBranchCache(previousCwd);
|
|
325
|
-
removeWorktree(originalBasePath, milestoneId, {
|
|
535
|
+
removeWorktree(originalBasePath, milestoneId, {
|
|
536
|
+
branch,
|
|
537
|
+
deleteBranch: !preserveBranch,
|
|
538
|
+
});
|
|
326
539
|
}
|
|
327
540
|
/**
|
|
328
541
|
* Detect if the process is currently inside an auto-worktree.
|
|
329
542
|
* Checks both module state and git branch prefix.
|
|
330
543
|
*/
|
|
331
544
|
export function isInAutoWorktree(basePath) {
|
|
332
|
-
|
|
333
|
-
// Primary check: use originalBase if available (fast path)
|
|
334
|
-
if (originalBase) {
|
|
335
|
-
const resolvedBase = existsSync(basePath) ? realpathSync(basePath) : basePath;
|
|
336
|
-
const wtDir = join(gsdRoot(resolvedBase), "worktrees");
|
|
337
|
-
if (!cwd.startsWith(wtDir))
|
|
338
|
-
return false;
|
|
339
|
-
const branch = nativeGetCurrentBranch(cwd);
|
|
340
|
-
return branch.startsWith("milestone/");
|
|
341
|
-
}
|
|
342
|
-
// Fallback: infer worktree status structurally when originalBase is null
|
|
343
|
-
// (happens after session restart where module-level state is lost, #1120).
|
|
344
|
-
// Check if cwd is inside a .gsd/worktrees/ directory and has a .git file
|
|
345
|
-
// (worktree marker) pointing to the main repo.
|
|
346
|
-
const worktreeMarker = join(cwd, ".git");
|
|
347
|
-
if (!existsSync(worktreeMarker))
|
|
545
|
+
if (!originalBase)
|
|
348
546
|
return false;
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
// Worktrees have a .git file with "gitdir: ..." pointing to the main repo
|
|
354
|
-
const gitContent = readFileSync(worktreeMarker, "utf-8").trim();
|
|
355
|
-
if (!gitContent.startsWith("gitdir:"))
|
|
356
|
-
return false;
|
|
357
|
-
// Verify we're inside a GSD-managed worktree
|
|
358
|
-
if (!detectWorktreeName(cwd))
|
|
359
|
-
return false;
|
|
360
|
-
const branch = nativeGetCurrentBranch(cwd);
|
|
361
|
-
return branch.startsWith("milestone/");
|
|
362
|
-
}
|
|
363
|
-
catch {
|
|
547
|
+
const cwd = process.cwd();
|
|
548
|
+
const resolvedBase = existsSync(basePath) ? realpathSync(basePath) : basePath;
|
|
549
|
+
const wtDir = join(resolvedBase, ".gsd", "worktrees");
|
|
550
|
+
if (!cwd.startsWith(wtDir))
|
|
364
551
|
return false;
|
|
365
|
-
|
|
552
|
+
const branch = nativeGetCurrentBranch(cwd);
|
|
553
|
+
return branch.startsWith("milestone/");
|
|
366
554
|
}
|
|
367
555
|
/**
|
|
368
556
|
* Get the filesystem path for an auto-worktree, or null if it doesn't exist
|
|
@@ -418,23 +606,13 @@ export function enterAutoWorktree(basePath, milestoneId) {
|
|
|
418
606
|
throw err;
|
|
419
607
|
throw new GSDError(GSD_IO_ERROR, `Auto-worktree path ${p} exists but .git is unreadable`);
|
|
420
608
|
}
|
|
421
|
-
// Ensure worktree shares external state via symlink (#1311).
|
|
422
|
-
// On resume (enterAutoWorktree), the symlink may be missing if it was
|
|
423
|
-
// created before ensureGsdSymlink existed, or the .gsd/ directory may be
|
|
424
|
-
// a stale git-tracked copy instead of a symlink. Refreshing here ensures
|
|
425
|
-
// the worktree sees the same milestone state as the main repo.
|
|
426
|
-
ensureGsdSymlink(p);
|
|
427
|
-
// Sync .gsd/ state from main repo into worktree (#1311).
|
|
428
|
-
// Covers the case where .gsd/ is a real directory (not symlinked) and
|
|
429
|
-
// milestones were created on main after the worktree was last used.
|
|
430
|
-
syncGsdStateToWorktree(basePath, p);
|
|
431
609
|
const previousCwd = process.cwd();
|
|
432
610
|
try {
|
|
433
611
|
process.chdir(p);
|
|
434
612
|
originalBase = basePath;
|
|
435
613
|
}
|
|
436
614
|
catch (err) {
|
|
437
|
-
throw new GSDError(GSD_IO_ERROR, `Failed to enter auto-worktree at ${p}: ${
|
|
615
|
+
throw new GSDError(GSD_IO_ERROR, `Failed to enter auto-worktree at ${p}: ${err instanceof Error ? err.message : String(err)}`);
|
|
438
616
|
}
|
|
439
617
|
nudgeGitBranchCache(previousCwd);
|
|
440
618
|
return p;
|
|
@@ -450,8 +628,10 @@ export function getActiveAutoWorktreeContext() {
|
|
|
450
628
|
if (!originalBase)
|
|
451
629
|
return null;
|
|
452
630
|
const cwd = process.cwd();
|
|
453
|
-
const resolvedBase = existsSync(originalBase)
|
|
454
|
-
|
|
631
|
+
const resolvedBase = existsSync(originalBase)
|
|
632
|
+
? realpathSync(originalBase)
|
|
633
|
+
: originalBase;
|
|
634
|
+
const wtDir = join(resolvedBase, ".gsd", "worktrees");
|
|
455
635
|
if (!cwd.startsWith(wtDir))
|
|
456
636
|
return null;
|
|
457
637
|
const worktreeName = detectWorktreeName(cwd);
|
|
@@ -507,54 +687,34 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
507
687
|
const milestoneBranch = autoWorktreeBranch(milestoneId);
|
|
508
688
|
// 1. Auto-commit dirty state in worktree before leaving
|
|
509
689
|
autoCommitDirtyState(worktreeCwd);
|
|
690
|
+
// Reconcile worktree DB into main DB before leaving worktree context
|
|
691
|
+
if (isDbAvailable()) {
|
|
692
|
+
try {
|
|
693
|
+
const worktreeDbPath = join(worktreeCwd, ".gsd", "gsd.db");
|
|
694
|
+
const mainDbPath = join(originalBasePath_, ".gsd", "gsd.db");
|
|
695
|
+
reconcileWorktreeDb(mainDbPath, worktreeDbPath);
|
|
696
|
+
}
|
|
697
|
+
catch {
|
|
698
|
+
/* non-fatal */
|
|
699
|
+
}
|
|
700
|
+
}
|
|
510
701
|
// 2. Parse roadmap for slice listing
|
|
511
702
|
const roadmap = parseRoadmap(roadmapContent);
|
|
512
|
-
const completedSlices = roadmap.slices.filter(s => s.done);
|
|
703
|
+
const completedSlices = roadmap.slices.filter((s) => s.done);
|
|
513
704
|
// 3. chdir to original base
|
|
514
705
|
const previousCwd = process.cwd();
|
|
515
706
|
process.chdir(originalBasePath_);
|
|
516
|
-
// 3a. Auto-commit any dirty state in the project root. Without this, the
|
|
517
|
-
// squash merge can fail with "Your local changes would be overwritten" (#1127).
|
|
518
|
-
autoCommitDirtyState(originalBasePath_);
|
|
519
|
-
// 3b. Remove untracked .gsd/ runtime files that syncStateToProjectRoot copied.
|
|
520
|
-
// Only clean specific runtime files — NEVER touch milestones/, decisions, or
|
|
521
|
-
// other planning artifacts that represent user work (#1250).
|
|
522
|
-
const runtimeFilesToClean = ["STATE.md", "completed-units.json", "auto.lock", "gsd.db"];
|
|
523
|
-
for (const f of runtimeFilesToClean) {
|
|
524
|
-
const p = join(originalBasePath_, ".gsd", f);
|
|
525
|
-
try {
|
|
526
|
-
if (existsSync(p))
|
|
527
|
-
unlinkSync(p);
|
|
528
|
-
}
|
|
529
|
-
catch { /* non-fatal */ }
|
|
530
|
-
}
|
|
531
|
-
try {
|
|
532
|
-
const runtimeDir = join(originalBasePath_, ".gsd", "runtime");
|
|
533
|
-
if (existsSync(runtimeDir))
|
|
534
|
-
rmSync(runtimeDir, { recursive: true, force: true });
|
|
535
|
-
}
|
|
536
|
-
catch { /* non-fatal */ }
|
|
537
707
|
// 4. Resolve integration branch — prefer milestone metadata, fall back to preferences / "main"
|
|
538
708
|
const prefs = loadEffectiveGSDPreferences()?.preferences?.git ?? {};
|
|
539
709
|
const integrationBranch = readIntegrationBranch(originalBasePath_, milestoneId);
|
|
540
710
|
const mainBranch = integrationBranch ?? prefs.main_branch ?? "main";
|
|
711
|
+
// Remove transient project-root state files before any branch or merge
|
|
712
|
+
// operation. Untracked milestone metadata can otherwise block squash merges.
|
|
713
|
+
clearProjectRootStateFiles(originalBasePath_, milestoneId);
|
|
541
714
|
// 5. Checkout integration branch (skip if already current — avoids git error
|
|
542
715
|
// when main is already checked out in the project-root worktree, #757)
|
|
543
716
|
const currentBranchAtBase = nativeGetCurrentBranch(originalBasePath_);
|
|
544
717
|
if (currentBranchAtBase !== mainBranch) {
|
|
545
|
-
// Remove untracked .gsd/ state files that may conflict with the branch
|
|
546
|
-
// being checked out. These are regenerated by doctor/rebuildState and
|
|
547
|
-
// are not meaningful in the main working tree — the worktree had the
|
|
548
|
-
// real state. Without this, `git checkout main` fails with
|
|
549
|
-
// "Your local changes would be overwritten" (#827).
|
|
550
|
-
const gsdStateFiles = ["STATE.md", "completed-units.json", "auto.lock"];
|
|
551
|
-
for (const f of gsdStateFiles) {
|
|
552
|
-
const p = join(gsdRoot(originalBasePath_), f);
|
|
553
|
-
try {
|
|
554
|
-
unlinkSync(p);
|
|
555
|
-
}
|
|
556
|
-
catch { /* non-fatal — file may not exist */ }
|
|
557
|
-
}
|
|
558
718
|
nativeCheckoutBranch(originalBasePath_, mainBranch);
|
|
559
719
|
}
|
|
560
720
|
// 6. Build rich commit message
|
|
@@ -562,7 +722,9 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
562
722
|
const subject = `feat(${milestoneId}): ${milestoneTitle}`;
|
|
563
723
|
let body = "";
|
|
564
724
|
if (completedSlices.length > 0) {
|
|
565
|
-
const sliceLines = completedSlices
|
|
725
|
+
const sliceLines = completedSlices
|
|
726
|
+
.map((s) => `- ${s.id}: ${s.title}`)
|
|
727
|
+
.join("\n");
|
|
566
728
|
body = `\n\nCompleted slices:\n${sliceLines}\n\nBranch: ${milestoneBranch}`;
|
|
567
729
|
}
|
|
568
730
|
const commitMessage = subject + body;
|
|
@@ -575,11 +737,11 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
575
737
|
: nativeConflictFiles(originalBasePath_);
|
|
576
738
|
if (conflictedFiles.length > 0) {
|
|
577
739
|
// Separate .gsd/ state file conflicts from real code conflicts.
|
|
578
|
-
// GSD state files (STATE.md,
|
|
740
|
+
// GSD state files (STATE.md, auto.lock, etc.)
|
|
579
741
|
// diverge between branches during normal operation — always prefer the
|
|
580
742
|
// milestone branch version since it has the latest execution state.
|
|
581
|
-
const gsdConflicts = conflictedFiles.filter(f => f.startsWith(".gsd/"));
|
|
582
|
-
const codeConflicts = conflictedFiles.filter(f => !f.startsWith(".gsd/"));
|
|
743
|
+
const gsdConflicts = conflictedFiles.filter((f) => f.startsWith(".gsd/"));
|
|
744
|
+
const codeConflicts = conflictedFiles.filter((f) => !f.startsWith(".gsd/"));
|
|
583
745
|
// Auto-resolve .gsd/ conflicts by accepting the milestone branch version
|
|
584
746
|
if (gsdConflicts.length > 0) {
|
|
585
747
|
for (const gsdFile of gsdConflicts) {
|
|
@@ -646,7 +808,10 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
646
808
|
}
|
|
647
809
|
// 10. Remove worktree directory first (must happen before branch deletion)
|
|
648
810
|
try {
|
|
649
|
-
removeWorktree(originalBasePath_, milestoneId, {
|
|
811
|
+
removeWorktree(originalBasePath_, milestoneId, {
|
|
812
|
+
branch: null,
|
|
813
|
+
deleteBranch: false,
|
|
814
|
+
});
|
|
650
815
|
}
|
|
651
816
|
catch {
|
|
652
817
|
// Best-effort -- worktree dir may already be gone
|