mixdog 1.4.0 → 1.4.2

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.
Files changed (493) hide show
  1. package/package.json +3 -2
  2. package/scripts/build-shipped-history.mjs +115 -33
  3. package/scripts/check-voice-runtime-inputs.mjs +25 -0
  4. package/scripts/gate-local.mjs +183 -63
  5. package/scripts/latest-guard.mjs +21 -9
  6. package/scripts/lib/gate-scheduler.mjs +138 -32
  7. package/scripts/lib/gate-timing-reporter.mjs +16 -0
  8. package/scripts/lib/isolated-test-env.mjs +10 -5
  9. package/scripts/lib/run-node-tests.mjs +91 -66
  10. package/scripts/lib/scoped-temp.d.mts +16 -0
  11. package/scripts/lib/scoped-temp.mjs +124 -0
  12. package/scripts/lib/stale-temp.mjs +44 -0
  13. package/scripts/lib/test-failure-records.mjs +14 -1
  14. package/scripts/lib/test-failure-summary.mjs +16 -4
  15. package/scripts/lib/test-spawn-ledger.mjs +12 -3
  16. package/scripts/post-release-check.mjs +1 -6
  17. package/scripts/pptx-kit-index.mjs +17 -5
  18. package/scripts/suite-health.mjs +115 -24
  19. package/scripts/test-data-dir.mjs +10 -7
  20. package/scripts/test.mjs +9 -14
  21. package/src/agents/advisor/AGENT.md +4 -4
  22. package/src/agents/advisor/agent.json +1 -1
  23. package/src/agents/explore/AGENT.md +22 -0
  24. package/src/agents/explore/agent.json +6 -0
  25. package/src/app.mjs +4 -0
  26. package/src/cli.mjs +7 -0
  27. package/src/defaults/agents.json +7 -0
  28. package/src/defaults/shipped-history.json +23 -2
  29. package/src/defaults/skills/browser-use/SKILL.md +10 -5
  30. package/src/defaults/skills/code-tidy/SKILL.md +71 -102
  31. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
  32. package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
  33. package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
  34. package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
  35. package/src/defaults/skills/computer-use/SKILL.md +16 -4
  36. package/src/defaults/skills/goal-management/SKILL.md +1 -1
  37. package/src/defaults/skills/setup/references/actions.md +12 -6
  38. package/src/defaults/skills/setup/references/surfaces.md +2 -2
  39. package/src/defaults/skills/setup-guide/SKILL.md +5 -2
  40. package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
  41. package/src/defaults/skills/skill-creator/SKILL.md +85 -190
  42. package/src/defaults/skills/skill-creator/references/design.md +70 -162
  43. package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
  44. package/src/defaults/skills/test-suite/SKILL.md +194 -0
  45. package/src/defaults/skills/test-suite/references/case-management.md +51 -0
  46. package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
  47. package/src/defaults/skills/test-suite/references/reliability.md +49 -0
  48. package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
  49. package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
  50. package/src/defaults/skills/visualize/SKILL.md +6 -2
  51. package/src/lib/rules-builder.cjs +35 -42
  52. package/src/output-styles/common.md +2 -2
  53. package/src/output-styles/simple.md +1 -1
  54. package/src/rules/agent/AGENT.md +5 -4
  55. package/src/rules/lead/LEAD.md +12 -7
  56. package/src/rules/shared/10-tool-workflow.md +3 -1
  57. package/src/rules/shared/20-research.md +3 -6
  58. package/src/rules/shared/40-editing.md +1 -0
  59. package/src/rules/shared/45-destructive.md +0 -2
  60. package/src/rules/shared/50-execution.md +2 -0
  61. package/src/rules/shared/60-verification.md +10 -9
  62. package/src/rules/shared/70-delivery.md +8 -9
  63. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
  64. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
  65. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
  66. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
  67. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
  69. package/src/runtime/agent/orchestrator/config.mjs +12 -7
  70. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
  71. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
  72. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
  73. package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
  74. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
  75. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
  76. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
  77. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
  78. package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
  79. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
  80. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
  81. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
  82. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
  83. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
  84. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
  85. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
  86. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
  87. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
  89. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
  90. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
  91. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
  92. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
  93. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
  94. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
  95. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
  97. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
  98. package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
  99. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
  100. package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
  101. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
  102. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
  103. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
  104. package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
  105. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
  106. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
  107. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
  108. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
  109. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
  110. package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
  113. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
  114. package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
  115. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
  116. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
  117. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
  118. package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
  119. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  120. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
  121. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
  122. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
  123. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  125. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
  126. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
  127. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  128. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
  129. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
  130. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
  131. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
  132. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
  133. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
  134. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
  135. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
  136. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
  137. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
  138. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
  139. package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
  140. package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
  141. package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
  142. package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
  143. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
  145. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  146. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
  147. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
  148. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  149. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
  150. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
  151. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
  152. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
  153. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
  154. package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
  155. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
  156. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
  157. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  158. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
  159. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
  160. package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
  161. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
  162. package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
  163. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
  164. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
  165. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
  166. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
  167. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
  168. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
  169. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
  170. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
  171. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
  172. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
  173. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
  174. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
  175. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
  176. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
  177. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
  178. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
  179. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
  180. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
  181. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
  182. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
  183. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
  184. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
  185. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
  186. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
  187. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
  188. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
  189. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
  190. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
  191. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
  192. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
  193. package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
  194. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
  195. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
  196. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
  197. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
  198. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
  199. package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
  200. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
  201. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
  202. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
  203. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
  204. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
  206. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
  207. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
  208. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
  209. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
  210. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
  211. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
  212. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
  213. package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
  214. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
  215. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
  216. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
  217. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
  218. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
  219. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
  220. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
  221. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
  222. package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
  223. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
  224. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
  225. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
  226. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
  227. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
  228. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
  229. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
  230. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
  231. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
  232. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
  233. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
  234. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  235. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  236. package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
  237. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
  238. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
  239. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
  240. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
  241. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
  242. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
  243. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
  244. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
  245. package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
  246. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  248. package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
  249. package/src/runtime/channels/lib/whisper-port.mjs +29 -11
  250. package/src/runtime/channels/lib/whisper-server.mjs +10 -1
  251. package/src/runtime/computer-bridge/action-schema.mjs +2 -2
  252. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  253. package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
  254. package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
  255. package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
  256. package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
  257. package/src/runtime/connectors/gmail-app-password.mjs +3 -3
  258. package/src/runtime/explore/explorer.mjs +93 -0
  259. package/src/runtime/explore/tool-defs.mjs +35 -0
  260. package/src/runtime/explore/tool.mjs +123 -0
  261. package/src/runtime/local-provider/server-process.mjs +2 -1
  262. package/src/runtime/media/adapters/gemini-video.mjs +4 -1
  263. package/src/runtime/media/adapters/xai-media.mjs +2 -1
  264. package/src/runtime/memory/index.mjs +4 -0
  265. package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
  266. package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
  267. package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
  268. package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
  269. package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
  270. package/src/runtime/office/design/design-art-direction.mjs +29 -27
  271. package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
  272. package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
  273. package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
  274. package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
  275. package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
  276. package/src/runtime/office/quality/design-review.mjs +1 -5
  277. package/src/runtime/office/quality/document-brief.mjs +1 -5
  278. package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
  279. package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
  280. package/src/runtime/shared/agent-route-config.mjs +17 -2
  281. package/src/runtime/shared/atomic-file.mjs +103 -2
  282. package/src/runtime/shared/background-tasks.mjs +15 -6
  283. package/src/runtime/shared/bot-owned-work.mjs +56 -0
  284. package/src/runtime/shared/connector-accounts.mjs +5 -5
  285. package/src/runtime/shared/connector-catalog.d.mts +11 -4
  286. package/src/runtime/shared/connector-catalog.mjs +60 -52
  287. package/src/runtime/shared/custom-provider-keys.mjs +20 -0
  288. package/src/runtime/shared/defaults-separation.mjs +1 -4
  289. package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
  290. package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
  291. package/src/runtime/shared/file-has-data.mjs +26 -2
  292. package/src/runtime/shared/file-lock.mjs +13 -15
  293. package/src/runtime/shared/git-launch.d.mts +9 -0
  294. package/src/runtime/shared/git-launch.mjs +213 -0
  295. package/src/runtime/shared/git-runner-worker.mjs +2 -1
  296. package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
  297. package/src/runtime/shared/handoff-artifacts.mjs +18 -8
  298. package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
  299. package/src/runtime/shared/llm/cost.mjs +11 -2
  300. package/src/runtime/shared/llm/http-agent.mjs +313 -29
  301. package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
  302. package/src/runtime/shared/llm/model-catalog.mjs +46 -6
  303. package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
  304. package/src/runtime/shared/llm/system-proxy.mjs +452 -0
  305. package/src/runtime/shared/loopback-listener.mjs +25 -2
  306. package/src/runtime/shared/model-route-chain.d.mts +7 -2
  307. package/src/runtime/shared/model-route-chain.mjs +22 -4
  308. package/src/runtime/shared/open-url.mjs +10 -0
  309. package/src/runtime/shared/provider-accounts.mjs +52 -2
  310. package/src/runtime/shared/session-activity-signal.mjs +14 -0
  311. package/src/runtime/shared/session-scratch.mjs +37 -0
  312. package/src/runtime/shared/staged-install-worker.mjs +5 -0
  313. package/src/runtime/shared/staged-update.mjs +47 -2
  314. package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
  315. package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
  316. package/src/runtime/shared/tool-result-summary.mjs +1 -1
  317. package/src/runtime/shared/tool-surface.mjs +113 -36
  318. package/src/runtime/shared/tool-work-units.mjs +6 -0
  319. package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
  320. package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
  321. package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
  322. package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
  323. package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
  324. package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
  325. package/src/runtime/shared/worktrees/contract.mjs +4 -1
  326. package/src/runtime/shared/worktrees/git.mjs +72 -0
  327. package/src/runtime/shared/worktrees/manager.mjs +285 -168
  328. package/src/runtime/shared/worktrees/test-support.mjs +6 -10
  329. package/src/runtime/tidy/install.mjs +95 -15
  330. package/src/runtime/tidy/languages.mjs +17 -15
  331. package/src/runtime/tidy/process.mjs +7 -4
  332. package/src/runtime/tidy/resolve.mjs +19 -16
  333. package/src/runtime/tidy/runners/biome.mjs +3 -3
  334. package/src/runtime/tidy/tool.mjs +1 -1
  335. package/src/runtime/tidy/worktree.mjs +10 -6
  336. package/src/runtime/visualize-bridge/client.mjs +6 -1
  337. package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
  338. package/src/runtime/web-search/index.mjs +1 -1
  339. package/src/session-runtime/agent-home-delivery.mjs +41 -0
  340. package/src/session-runtime/agent-task-sessions.mjs +458 -312
  341. package/src/session-runtime/agent-tool-routing.mjs +8 -41
  342. package/src/session-runtime/boot/tools.mjs +7 -1
  343. package/src/session-runtime/bot-status.mjs +107 -101
  344. package/src/session-runtime/bot-target.mjs +38 -0
  345. package/src/session-runtime/channel-config-api.mjs +6 -1
  346. package/src/session-runtime/connector-merge-migration.mjs +18 -15
  347. package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
  348. package/src/session-runtime/conversation-import/discovery.mjs +401 -36
  349. package/src/session-runtime/conversation-import/service.mjs +35 -8
  350. package/src/session-runtime/handoff-attachments.mjs +82 -31
  351. package/src/session-runtime/held-requests.mjs +3 -1
  352. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
  353. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
  354. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
  355. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
  356. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
  357. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
  358. package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
  359. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
  360. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
  361. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  362. package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
  363. package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
  364. package/src/session-runtime/mixy-heartbeat.mjs +1 -1
  365. package/src/session-runtime/model-route/set-route.mjs +11 -2
  366. package/src/session-runtime/provider-auth/login.mjs +2 -2
  367. package/src/session-runtime/provider-catalog-cache.mjs +82 -36
  368. package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
  369. package/src/session-runtime/provider-models.mjs +4 -2
  370. package/src/session-runtime/resource-mcp-api.mjs +98 -35
  371. package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
  372. package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
  373. package/src/session-runtime/resource-mcp-servers.mjs +5 -4
  374. package/src/session-runtime/resource-recall-api.mjs +6 -1
  375. package/src/session-runtime/runtime-feature-gates.mjs +5 -1
  376. package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
  377. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
  378. package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
  379. package/src/session-runtime/services/agent-tool/render.mjs +71 -17
  380. package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
  381. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
  382. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
  383. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
  384. package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
  385. package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
  386. package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
  387. package/src/session-runtime/services/daemon-candidate.mjs +4 -1
  388. package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
  389. package/src/session-runtime/services/plugin-admin.mjs +10 -6
  390. package/src/session-runtime/services/provider-admin.mjs +283 -11
  391. package/src/session-runtime/session-turn-api.mjs +2 -0
  392. package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
  393. package/src/session-runtime/settings-system-api.mjs +1 -1
  394. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
  395. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
  396. package/src/session-runtime/setup-tool/executor.mjs +6 -2
  397. package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
  398. package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
  399. package/src/session-runtime/turn/agent-ops.mjs +23 -0
  400. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
  401. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
  402. package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
  403. package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
  404. package/src/session-runtime/workspace/activity-guards.mjs +176 -0
  405. package/src/session-runtime/workspace/session-view.mjs +149 -0
  406. package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
  407. package/src/session-runtime/workspace/transition-runner.mjs +188 -0
  408. package/src/session-runtime/workspace/transitions.mjs +108 -1041
  409. package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
  410. package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
  411. package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
  412. package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
  413. package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
  414. package/src/standalone/daemon-desktop-runtime.mjs +2 -0
  415. package/src/standalone/daemon-session-control.mjs +169 -138
  416. package/src/standalone/daemon.mjs +7 -0
  417. package/src/standalone/desktop-service-registry.mjs +9 -0
  418. package/src/standalone/local-session-runtime.mjs +5 -1
  419. package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
  420. package/src/standalone/session-client.mjs +5 -1
  421. package/src/standalone/session-frame-stream.mjs +83 -11
  422. package/src/standalone/session-protocol.mjs +4 -0
  423. package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
  424. package/src/standalone/session-service/agent-tree.mjs +45 -9
  425. package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
  426. package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
  427. package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
  428. package/src/standalone/session-service/stored-reader.mjs +127 -40
  429. package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
  430. package/src/tui/App.jsx +154 -164
  431. package/src/tui/app/app-view/floating-panel.jsx +10 -4
  432. package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
  433. package/src/tui/app/clipboard.mjs +21 -10
  434. package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
  435. package/src/tui/app/model-picker/route-selection.mjs +5 -6
  436. package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
  437. package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
  438. package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
  439. package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
  440. package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
  441. package/src/tui/app/provider-setup/provider-items.mjs +8 -2
  442. package/src/tui/app/provider-setup-picker.mjs +29 -18
  443. package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
  444. package/src/tui/app/slash-commands.mjs +1 -0
  445. package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
  446. package/src/tui/app/slash-dispatch.mjs +1 -1
  447. package/src/tui/app/use-btw-panel.mjs +29 -0
  448. package/src/tui/app/use-context-panel-refresh.mjs +31 -0
  449. package/src/tui/app/use-model-catalog-cache.mjs +13 -10
  450. package/src/tui/app/use-mouse-input.mjs +11 -0
  451. package/src/tui/app/use-onboarding-start.mjs +8 -3
  452. package/src/tui/app/use-panel-transition.mjs +10 -1
  453. package/src/tui/app/use-pasted-buffers.mjs +28 -20
  454. package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
  455. package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
  456. package/src/tui/app/use-prompt-queue-history.mjs +3 -2
  457. package/src/tui/app/use-selection-focus.mjs +11 -2
  458. package/src/tui/app/use-selection-geometry.mjs +18 -9
  459. package/src/tui/app/use-selection-paint.mjs +4 -4
  460. package/src/tui/app/use-selection-stitch.mjs +3 -3
  461. package/src/tui/app/use-slash-palette.mjs +62 -0
  462. package/src/tui/app/use-terminal-chrome.mjs +2 -2
  463. package/src/tui/app/use-transcript-activity.mjs +47 -32
  464. package/src/tui/app/use-transcript-follow.mjs +12 -4
  465. package/src/tui/app/use-transcript-scroll.mjs +46 -17
  466. package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
  467. package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
  468. package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
  469. package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
  470. package/src/tui/app/use-transcript-window.mjs +21 -11
  471. package/src/tui/app/use-tui-ready.mjs +18 -0
  472. package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
  473. package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
  474. package/src/tui/components/Picker.jsx +27 -3
  475. package/src/tui/components/QuestionPanel.jsx +13 -4
  476. package/src/tui/components/SignInUrl.jsx +68 -0
  477. package/src/tui/components/TextEntryPanel.jsx +76 -46
  478. package/src/tui/components/sign-in-url-layout.mjs +24 -0
  479. package/src/tui/dist/index.mjs +1963 -1361
  480. package/src/tui/session/goal-turn-state.mjs +6 -2
  481. package/src/tui/session/session-api/controls.mjs +4 -0
  482. package/src/tui/session/session-api/extensions.mjs +8 -0
  483. package/src/tui/session/session-api/intake/abort.mjs +2 -1
  484. package/src/tui/session/session-api/intake.mjs +2 -0
  485. package/src/tui/session/session-api/integrations.mjs +2 -2
  486. package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
  487. package/src/tui/session/session-api/settings.mjs +2 -2
  488. package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
  489. package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
  490. package/src/tui/session/transcript-spill.mjs +92 -4
  491. package/src/tui/session/transcript-store.mjs +2 -0
  492. package/src/ui/statusline-agents.mjs +1 -3
  493. package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
@@ -40,6 +40,7 @@ import {
40
40
  } from './file-recovery.mjs';
41
41
  import { lstat, mkdir, readdir, readFile, rm, rmdir, stat } from 'node:fs/promises';
42
42
  import { dirname, join, relative, resolve, sep } from 'node:path';
43
+ import { isPidAlive } from '../pid-liveness.mjs';
43
44
  import {
44
45
  managedWorktreePath,
45
46
  managedWorktreeRoot,
@@ -49,6 +50,7 @@ import {
49
50
  WORKTREE_SNAPSHOT_KIND,
50
51
  worktreeBranchName,
51
52
  worktreeError,
53
+ worktreeRefusal,
52
54
  } from './contract.mjs';
53
55
  import {
54
56
  assertCarryable,
@@ -68,6 +70,7 @@ import {
68
70
  listWorktrees,
69
71
  localBranches,
70
72
  parseStatusPaths,
73
+ remoteDefaultBranches,
71
74
  runGit,
72
75
  throwIfAborted,
73
76
  validBranchName,
@@ -84,7 +87,7 @@ import {
84
87
  } from './include.mjs';
85
88
  import { linkWorktreeDependencies } from './dependencies.mjs';
86
89
  import { withRepoLock as withRepoMutationLock } from './lock.mjs';
87
- import { holdWorkspaceActivity } from './activity-gate.mjs';
90
+ import { holdWorkspaceActivityAsync } from './activity-gate.mjs';
88
91
  import { withAdvisoryLocks } from '../../agent/orchestrator/tools/builtin/advisory-lock.mjs';
89
92
  import { mergeBranchIntoCheckout, operationInProgress } from './merge.mjs';
90
93
  import { readOwnerLease, removeOwnerLease, sameOwner, writeOwnerLease } from './owner.mjs';
@@ -122,17 +125,7 @@ function sessionRootOf(record) {
122
125
  // ---------------------------------------------------------------------------
123
126
  // Host configuration (settings source, free-space probe); tests override it.
124
127
 
125
- /** pid probe (signal 0); EPERM means the process exists. */
126
- function processAlive(pid) {
127
- try {
128
- process.kill(pid, 0);
129
- return true;
130
- } catch (error) {
131
- return error?.code === 'EPERM';
132
- }
133
- }
134
-
135
- const DEFAULT_CONFIG = Object.freeze({ settings: null, freeBytes: freeBytesAt, processAlive });
128
+ const DEFAULT_CONFIG = Object.freeze({ settings: null, freeBytes: freeBytesAt, processAlive: isPidAlive });
136
129
  let config = { ...DEFAULT_CONFIG };
137
130
 
138
131
  /**
@@ -757,6 +750,11 @@ export async function resolveBranchWorkspace({
757
750
  repoCommonDir: repo.repoCommonDir,
758
751
  };
759
752
  }
753
+ // Checked out in a managed worktree, the branch a remote declares its
754
+ // default would stay locked away from the project folder.
755
+ if (!create && (await remoteDefaultBranches(repo.projectPath)).includes(branch)) {
756
+ throw worktreeError('WORKTREE_DEFAULT_BRANCH', undefined, { branch });
757
+ }
760
758
  const entry = await createManagedWorktree({
761
759
  projectPath,
762
760
  sessionId,
@@ -770,10 +768,6 @@ export async function resolveBranchWorkspace({
770
768
  confirmLarge,
771
769
  signal,
772
770
  });
773
- const record = await getRecord(entry.id);
774
- record.mergeTarget = repo.currentBranch;
775
- await putRecord(record);
776
- entry.mergeTarget = repo.currentBranch;
777
771
  return { path: entry.path, branch, entry, created: true, repoCommonDir: repo.repoCommonDir };
778
772
  });
779
773
  }
@@ -976,6 +970,174 @@ async function snapshotHolderLive(record, live) {
976
970
  return !!lease && lease.pid !== process.pid && leaseProcessAlive(lease);
977
971
  }
978
972
 
973
+ /** The project folder's uncommitted changes under the requested `carryChanges` mode; `ask` refuses while there are any. */
974
+ async function judgePendingChanges(repo, projectSubdir, carryChanges) {
975
+ // A carry is judged by the same status read that counts the changes.
976
+ let pendingChanges = [];
977
+ if (carryChanges === 'carry') pendingChanges = await assertCarryable(repo.topLevel, projectSubdir);
978
+ else if (carryChanges) pendingChanges = await uncommittedChanges(repo.topLevel, projectSubdir);
979
+ if (pendingChanges.length && carryChanges === 'ask') {
980
+ throw worktreeError('WORKTREE_DIRTY_CHOICE', undefined, {
981
+ count: pendingChanges.length,
982
+ paths: pendingChanges.slice(0, DIRTY_CHOICE_PREVIEW),
983
+ });
984
+ }
985
+ return pendingChanges;
986
+ }
987
+
988
+ /** The commit a new worktree starts from and the branch a merge targets by default. */
989
+ async function resolveStartPoint(repo, { baseBranch, startCommit, signal }) {
990
+ let baseCommit = repo.headCommit;
991
+ let mergeTarget = repo.currentBranch;
992
+ if (baseBranch) {
993
+ baseCommit = await branchCommit(repo.projectPath, baseBranch, { signal });
994
+ if (!baseCommit) {
995
+ throw worktreeError('WORKTREE_UNSUPPORTED_REPO', `Base branch ${baseBranch} does not exist.`, { baseBranch });
996
+ }
997
+ mergeTarget = baseBranch;
998
+ }
999
+ // A new branch at an explicit start point (`git worktree add -b <b> <path> <commit-ish>`).
1000
+ if (startCommit) baseCommit = await resolveCommit(repo.projectPath, startCommit, signal);
1001
+ return { baseCommit, mergeTarget };
1002
+ }
1003
+
1004
+ /** The record a creation reserves before git is asked to add the checkout. */
1005
+ function newCreationRecord({
1006
+ slug,
1007
+ branch,
1008
+ repo,
1009
+ owner,
1010
+ txId,
1011
+ baseCommit,
1012
+ mergeTarget,
1013
+ existingBranch,
1014
+ exactBranch,
1015
+ tracked,
1016
+ includePlan,
1017
+ }) {
1018
+ return {
1019
+ id: slug,
1020
+ txId,
1021
+ repoCommonDir: repo.repoCommonDir,
1022
+ projectPath: repo.projectPath,
1023
+ projectSubdir: projectSubdirOf(repo.topLevel, repo.projectPath),
1024
+ path: managedWorktreePath(repo.repoCommonDir, slug),
1025
+ branch,
1026
+ baseCommit,
1027
+ // An existing branch has no base it branched from: it merges where a
1028
+ // merge first takes it (recorded then), and until that its own work is
1029
+ // what it gained here since baseCommit.
1030
+ mergeTarget: existingBranch ? null : mergeTarget,
1031
+ createdAt: Date.now(),
1032
+ ownerSessionId: owner.sessionId,
1033
+ existingBranch,
1034
+ exactBranch,
1035
+ state: 'creating',
1036
+ disposable: false,
1037
+ warnings: [...(tracked.submodules ? ['submodules'] : []), ...includePlan.warnings],
1038
+ resources: { worktree: null, lock: null, owner: null, includes: [] },
1039
+ deleting: null,
1040
+ recovery: null,
1041
+ };
1042
+ }
1043
+
1044
+ /**
1045
+ * Locks the fresh checkout, binds its owner lease, moves or leaves the
1046
+ * project folder's changes, applies the includes and links dependencies.
1047
+ * `carry.moved` is set as soon as changes were carried, so a later failure
1048
+ * can put them back.
1049
+ */
1050
+ async function populateCheckout({
1051
+ record,
1052
+ owner,
1053
+ repo,
1054
+ projectSubdir,
1055
+ signal,
1056
+ pendingChanges,
1057
+ carryChanges,
1058
+ baseCommit,
1059
+ includePlan,
1060
+ carry,
1061
+ }) {
1062
+ await setResource(record, 'worktree', 'created');
1063
+ throwIfAborted(signal);
1064
+ await setResource(record, 'lock', 'pending');
1065
+ await runGit(repo.projectPath, ['worktree', 'lock', '--reason', `mixdog session=${owner.sessionId}`, record.path]);
1066
+ await setResource(record, 'lock', 'created');
1067
+ await setResource(record, 'owner', 'pending');
1068
+ await writeOwnerLease(record, owner);
1069
+ await setResource(record, 'owner', 'created');
1070
+ // Carried before the include entries are copied, so an include never
1071
+ // stands in the way of a carried file; the status is read again here,
1072
+ // right before acting.
1073
+ let changes = pendingChanges.length ? { mode: 'left', count: pendingChanges.length } : null;
1074
+ if (carryChanges === 'carry') {
1075
+ carry.moved = await carryUncommittedChanges({
1076
+ topLevel: repo.topLevel,
1077
+ projectSubdir,
1078
+ worktreePath: record.path,
1079
+ baseCommit,
1080
+ label: record.id,
1081
+ });
1082
+ // The recovery ref stays until the caller has committed the move
1083
+ // (dropCarryRecoveryRef) or put the changes back (restoreCarriedChanges).
1084
+ changes = carry.moved.count
1085
+ ? { mode: 'carried', count: carry.moved.count, recoveryRef: carry.moved.recoveryRef }
1086
+ : null;
1087
+ }
1088
+ const applied = await applyIncludes(includePlan, record.path, (ledger) => recordInclude(record, ledger));
1089
+ throwIfAborted(signal);
1090
+ // After the includes: one that already brought a node_modules wins.
1091
+ const linkedDependencies = await linkWorktreeDependencies({
1092
+ mainDir: repo.projectPath,
1093
+ worktreeDir: projectSubdir ? join(record.path, ...projectSubdir.split('/')) : record.path,
1094
+ worktreeRel: projectSubdir,
1095
+ signal,
1096
+ record: (ledger) => recordInclude(record, ledger),
1097
+ });
1098
+ throwIfAborted(signal);
1099
+ record.warnings = [...record.warnings, ...applied.warnings];
1100
+ const made = (record.resources.includes || []).filter((item) => item.status === 'created');
1101
+ const rels = (predicate) => made.filter(predicate).map((item) => item.rel);
1102
+ // What creation did, for the agent's note at the first turn there (transitions.mjs).
1103
+ const prepared = {
1104
+ root: repo.topLevel,
1105
+ copied: rels((item) => item.mode === 'copy'),
1106
+ linked: rels((item) => item.mode === 'link' && !item.dependency),
1107
+ dependencies: linkedDependencies,
1108
+ skipped: [...includePlan.warnings, ...applied.warnings],
1109
+ };
1110
+ // Whichever path made it (a worktree task, a branch selection, `git
1111
+ // worktree add`), the first turn a session runs here prepares its
1112
+ // dependencies (claimWorktreeSetup).
1113
+ record.setup = { pending: true, prepared };
1114
+ record.state = 'ready';
1115
+ await putRecord(record);
1116
+ return { ...entryView(record), prepared, ...(changes ? { changes } : {}) };
1117
+ }
1118
+
1119
+ /** The error a failed creation throws, after its carried changes and partial checkout are undone. */
1120
+ async function failCreation(error, { record, carried, repo, projectSubdir, needed, root }) {
1121
+ // Carried already: the changes go back to the project folder before the
1122
+ // worktree that holds them is rolled back (the recovery ref keeps them
1123
+ // either way).
1124
+ let carryRestore = null;
1125
+ if (carried?.recoveryRef) {
1126
+ carryRestore = await restoreFromRecoveryRef(repo.topLevel, projectSubdir, carried.recoveryRef)
1127
+ .then(() => ({ restored: true, recoveryRef: carried.recoveryRef }))
1128
+ .catch((restoreError) => ({
1129
+ restored: false,
1130
+ recoveryRef: carried.recoveryRef,
1131
+ error: String(restoreError?.message || restoreError),
1132
+ }));
1133
+ }
1134
+ const rollback = await rollbackCreation(record, error);
1135
+ const failure = isDiskFullError(error) ? await diskFullFailure(error, { needed, root }) : error;
1136
+ if (!rollback.complete) failure.rollback = rollback;
1137
+ if (carryRestore) failure.carryRestore = carryRestore;
1138
+ return failure;
1139
+ }
1140
+
979
1141
  /**
980
1142
  * `carryChanges` decides the project folder's uncommitted changes (tracked
981
1143
  * and untracked, ignored excluded), judged under the repository lock:
@@ -1031,29 +1193,10 @@ export async function createManagedWorktree({
1031
1193
  throwIfAborted(signal);
1032
1194
 
1033
1195
  const projectSubdir = projectSubdirOf(repo.topLevel, repo.projectPath);
1034
- // A carry is judged by the same status read that counts the changes.
1035
- let pendingChanges = [];
1036
- if (carryChanges === 'carry') pendingChanges = await assertCarryable(repo.topLevel, projectSubdir);
1037
- else if (carryChanges) pendingChanges = await uncommittedChanges(repo.topLevel, projectSubdir);
1038
- if (pendingChanges.length && carryChanges === 'ask') {
1039
- throw worktreeError('WORKTREE_DIRTY_CHOICE', undefined, {
1040
- count: pendingChanges.length,
1041
- paths: pendingChanges.slice(0, DIRTY_CHOICE_PREVIEW),
1042
- });
1043
- }
1196
+ const pendingChanges = await judgePendingChanges(repo, projectSubdir, carryChanges);
1044
1197
 
1045
1198
  const settings = await currentWorktreeSettings();
1046
- let baseCommit = repo.headCommit;
1047
- let mergeTarget = repo.currentBranch;
1048
- if (baseBranch) {
1049
- baseCommit = await branchCommit(repo.projectPath, baseBranch, { signal });
1050
- if (!baseCommit) {
1051
- throw worktreeError('WORKTREE_UNSUPPORTED_REPO', `Base branch ${baseBranch} does not exist.`, { baseBranch });
1052
- }
1053
- mergeTarget = baseBranch;
1054
- }
1055
- // A new branch at an explicit start point (`git worktree add -b <b> <path> <commit-ish>`).
1056
- if (startCommit) baseCommit = await resolveCommit(repo.projectPath, startCommit, signal);
1199
+ const { baseCommit, mergeTarget } = await resolveStartPoint(repo, { baseBranch, startCommit, signal });
1057
1200
 
1058
1201
  // The main checkout's local env files come along on their own;
1059
1202
  // `.worktreeinclude` applies on top.
@@ -1096,7 +1239,7 @@ export async function createManagedWorktree({
1096
1239
  }
1097
1240
  );
1098
1241
  let record = await reserve();
1099
- let carried = null;
1242
+ const carry = { moved: null };
1100
1243
 
1101
1244
  try {
1102
1245
  await mkdir(root, { recursive: true });
@@ -1117,84 +1260,20 @@ export async function createManagedWorktree({
1117
1260
  await setResource(record, 'worktree', 'pending');
1118
1261
  await addCheckout(record);
1119
1262
  }
1120
- await setResource(record, 'worktree', 'created');
1121
- throwIfAborted(signal);
1122
- await setResource(record, 'lock', 'pending');
1123
- await runGit(repo.projectPath, [
1124
- 'worktree',
1125
- 'lock',
1126
- '--reason',
1127
- `mixdog session=${owner.sessionId}`,
1128
- record.path,
1129
- ]);
1130
- await setResource(record, 'lock', 'created');
1131
- await setResource(record, 'owner', 'pending');
1132
- await writeOwnerLease(record, owner);
1133
- await setResource(record, 'owner', 'created');
1134
- // Carried before the include entries are copied, so an include never
1135
- // stands in the way of a carried file; the status is read again here,
1136
- // right before acting.
1137
- let changes = pendingChanges.length ? { mode: 'left', count: pendingChanges.length } : null;
1138
- if (carryChanges === 'carry') {
1139
- carried = await carryUncommittedChanges({
1140
- topLevel: repo.topLevel,
1141
- projectSubdir,
1142
- worktreePath: record.path,
1143
- baseCommit,
1144
- label: record.id,
1145
- });
1146
- // The recovery ref stays until the caller has committed the move
1147
- // (dropCarryRecoveryRef) or put the changes back (restoreCarriedChanges).
1148
- changes = carried.count ? { mode: 'carried', count: carried.count, recoveryRef: carried.recoveryRef } : null;
1149
- }
1150
- const applied = await applyIncludes(includePlan, record.path, (ledger) => recordInclude(record, ledger));
1151
- throwIfAborted(signal);
1152
- // After the includes: one that already brought a node_modules wins.
1153
- const linkedDependencies = await linkWorktreeDependencies({
1154
- mainDir: repo.projectPath,
1155
- worktreeDir: projectSubdir ? join(record.path, ...projectSubdir.split('/')) : record.path,
1156
- worktreeRel: projectSubdir,
1263
+ return await populateCheckout({
1264
+ record,
1265
+ owner,
1266
+ repo,
1267
+ projectSubdir,
1157
1268
  signal,
1158
- record: (ledger) => recordInclude(record, ledger),
1269
+ pendingChanges,
1270
+ carryChanges,
1271
+ baseCommit,
1272
+ includePlan,
1273
+ carry,
1159
1274
  });
1160
- throwIfAborted(signal);
1161
- record.warnings = [...record.warnings, ...applied.warnings];
1162
- const made = (record.resources.includes || []).filter((item) => item.status === 'created');
1163
- const rels = (predicate) => made.filter(predicate).map((item) => item.rel);
1164
- // What creation did, for the agent's note at the first turn there (transitions.mjs).
1165
- const prepared = {
1166
- root: repo.topLevel,
1167
- copied: rels((item) => item.mode === 'copy'),
1168
- linked: rels((item) => item.mode === 'link' && !item.dependency),
1169
- dependencies: linkedDependencies,
1170
- skipped: [...includePlan.warnings, ...applied.warnings],
1171
- };
1172
- // Whichever path made it (a worktree task, a branch selection, `git
1173
- // worktree add`), the first turn a session runs here prepares its
1174
- // dependencies (claimWorktreeSetup).
1175
- record.setup = { pending: true, prepared };
1176
- record.state = 'ready';
1177
- await putRecord(record);
1178
- return { ...entryView(record), prepared, ...(changes ? { changes } : {}) };
1179
1275
  } catch (error) {
1180
- // Carried already: the changes go back to the project folder before the
1181
- // worktree that holds them is rolled back (the recovery ref keeps them
1182
- // either way).
1183
- let carryRestore = null;
1184
- if (carried?.recoveryRef) {
1185
- carryRestore = await restoreFromRecoveryRef(repo.topLevel, projectSubdir, carried.recoveryRef)
1186
- .then(() => ({ restored: true, recoveryRef: carried.recoveryRef }))
1187
- .catch((restoreError) => ({
1188
- restored: false,
1189
- recoveryRef: carried.recoveryRef,
1190
- error: String(restoreError?.message || restoreError),
1191
- }));
1192
- }
1193
- const rollback = await rollbackCreation(record, error);
1194
- const failure = isDiskFullError(error) ? await diskFullFailure(error, { needed, root }) : error;
1195
- if (!rollback.complete) failure.rollback = rollback;
1196
- if (carryRestore) failure.carryRestore = carryRestore;
1197
- throw failure;
1276
+ throw await failCreation(error, { record, carried: carry.moved, repo, projectSubdir, needed, root });
1198
1277
  }
1199
1278
 
1200
1279
  async function reserveName() {
@@ -1210,27 +1289,19 @@ export async function createManagedWorktree({
1210
1289
  if (!(await validBranchName(repo.projectPath, branch))) {
1211
1290
  throw worktreeError('WORKTREE_UNSUPPORTED_REPO', `Branch name ${branch} is not valid.`, { branch });
1212
1291
  }
1213
- const candidate = {
1214
- id: slug,
1215
- txId,
1216
- repoCommonDir: repo.repoCommonDir,
1217
- projectPath: repo.projectPath,
1218
- projectSubdir: projectSubdirOf(repo.topLevel, repo.projectPath),
1219
- path: managedWorktreePath(repo.repoCommonDir, slug),
1292
+ const candidate = newCreationRecord({
1293
+ slug,
1220
1294
  branch,
1295
+ repo,
1296
+ owner,
1297
+ txId,
1221
1298
  baseCommit,
1222
1299
  mergeTarget,
1223
- createdAt: Date.now(),
1224
- ownerSessionId: owner.sessionId,
1225
1300
  existingBranch,
1226
1301
  exactBranch: requestedBranch !== null,
1227
- state: 'creating',
1228
- disposable: false,
1229
- warnings: [...(tracked.submodules ? ['submodules'] : []), ...includePlan.warnings],
1230
- resources: { worktree: null, lock: null, owner: null, includes: [] },
1231
- deleting: null,
1232
- recovery: null,
1233
- };
1302
+ tracked,
1303
+ includePlan,
1304
+ });
1234
1305
  return (await insertRecord(candidate)) ? candidate : null;
1235
1306
  }
1236
1307
  });
@@ -1356,9 +1427,12 @@ export async function createSnapshotWorktree({
1356
1427
  * one is admitted there until the returned release. A folder no longer a
1357
1428
  * checkout admits no consumer (activity-gate tracks git checkouts only).
1358
1429
  */
1359
- function holdSnapshotFolder(record) {
1430
+ async function holdSnapshotFolder(record) {
1360
1431
  if (!existsSync(join(record.path, '.git'))) return () => {};
1361
- return holdWorkspaceActivity([record.path]);
1432
+ const release = await holdWorkspaceActivityAsync([record.path]);
1433
+ // Settles once the removal was attempted. It fails only when workspace
1434
+ // admission stopped (reported there), which keeps the folder held.
1435
+ return () => release().catch(() => {});
1362
1436
  }
1363
1437
 
1364
1438
  /** A refusal that only says "something still runs there" (retry once it ends). */
@@ -1400,9 +1474,7 @@ export async function removeSessionSnapshots(sessionId, { txIds = null } = {}) {
1400
1474
  const only = txIds ? new Set(txIds) : null;
1401
1475
  const held = Object.values((await readRegistry()).entries).filter(
1402
1476
  (record) =>
1403
- record.kind === WORKTREE_SNAPSHOT_KIND &&
1404
- record.holderSessionId === sessionId &&
1405
- (!only || only.has(record.txId))
1477
+ record.kind === WORKTREE_SNAPSHOT_KIND && record.holderSessionId === sessionId && (!only || only.has(record.txId))
1406
1478
  );
1407
1479
  for (const record of held) {
1408
1480
  const row = { id: record.id, txId: record.txId };
@@ -1854,19 +1926,59 @@ export async function removeManagedWorktree({
1854
1926
  if (!current && !expected) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
1855
1927
  return skipped;
1856
1928
  }
1857
- assertNotShared(current, sessionId);
1858
- if (current.state === 'creating' || current.state === 'recovery') {
1859
- const rollback = await rollbackCreation(current);
1860
- return rollback.complete ? { removed: true } : { removed: false, retryable: true, remaining: rollback.remaining };
1929
+ return removeLocked(current, { force, sessionId, preserveBranch, safeOnly });
1930
+ });
1931
+ }
1932
+
1933
+ /** The removal of `current`, under its repository lock. */
1934
+ async function removeLocked(current, { force, sessionId, preserveBranch = false, safeOnly = false }) {
1935
+ assertNotShared(current, sessionId);
1936
+ if (current.state === 'creating' || current.state === 'recovery') {
1937
+ const rollback = await rollbackCreation(current);
1938
+ return rollback.complete ? { removed: true } : { removed: false, retryable: true, remaining: rollback.remaining };
1939
+ }
1940
+ // Every deletion attempt of a snapshot, a resumed one included, waits
1941
+ // for (refuses on) its consumers.
1942
+ const release = current.kind === WORKTREE_SNAPSHOT_KIND ? await holdSnapshotFolder(current) : () => {};
1943
+ try {
1944
+ return await decideAndFinishDeletion(current, { force, preserveBranch, safeOnly });
1945
+ } finally {
1946
+ await release();
1947
+ }
1948
+ }
1949
+
1950
+ /**
1951
+ * Remove a worktree whose owner is gone, on an explicit request: under the
1952
+ * repository lock its retention is read again right before anything moves,
1953
+ * so an owner that came back (a live session, a running lease holder) or a
1954
+ * session the store still keeps it for refuses (WORKTREE_BUSY_JOBS). Then
1955
+ * the ordinary removal guards apply (dirty or unmerged work needs `force`).
1956
+ * @param {{ entryId: string, force?: boolean, liveSessionIds?: string[], retainedSessionIds?: string[] }} input
1957
+ */
1958
+ export async function removeOrphanedWorktree({
1959
+ entryId,
1960
+ force = false,
1961
+ liveSessionIds = [],
1962
+ retainedSessionIds = [],
1963
+ } = {}) {
1964
+ const record = await getRecord(entryId);
1965
+ if (!record) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
1966
+ return withRepoLock(record.repoCommonDir, async () => {
1967
+ const current = await getRecord(entryId);
1968
+ if (!current || current.kind === WORKTREE_SNAPSHOT_KIND) {
1969
+ throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
1861
1970
  }
1862
- // Every deletion attempt of a snapshot, a resumed one included, waits
1863
- // for (refuses on) its consumers.
1864
- const release = current.kind === WORKTREE_SNAPSHOT_KIND ? holdSnapshotFolder(current) : () => {};
1865
- try {
1866
- return await decideAndFinishDeletion(current, { force, preserveBranch, safeOnly });
1867
- } finally {
1868
- release();
1971
+ const { ownerLive, removable } = await retentionOf(current, new Set(liveSessionIds), new Set(retainedSessionIds));
1972
+ if (ownerLive) throw worktreeRefusal('workspace-lease', { entryId });
1973
+ if (!removable) {
1974
+ // Retained recovery data names itself; otherwise sessions still keep it.
1975
+ await assertRecoveryStoresClear(current);
1976
+ throw worktreeRefusal('workspace-retained', {
1977
+ entryId,
1978
+ sessions: [current.ownerSessionId, ...(current.sharedSessionIds ?? [])].filter(Boolean),
1979
+ });
1869
1980
  }
1981
+ return removeLocked(current, { force });
1870
1982
  });
1871
1983
  }
1872
1984
 
@@ -1900,25 +2012,7 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
1900
2012
  const retained = new Set(retainedSessionIds);
1901
2013
  const rows = [];
1902
2014
  for (const record of Object.values((await readRegistry()).entries)) {
1903
- const snapshot = record.kind === WORKTREE_SNAPSHOT_KIND;
1904
- const ownerLive = snapshot
1905
- ? await snapshotHolderLive(record, live)
1906
- : (!!record.ownerSessionId && live.has(record.ownerSessionId)) ||
1907
- leaseProcessAlive(await readOwnerLease(record));
1908
- const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
1909
- // A snapshot outlives no holder: the prune removes it, changes and all.
1910
- let removable = snapshot
1911
- ? !ownerLive
1912
- : !record.sharedSessionIds?.length &&
1913
- (record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
1914
- if (removable) {
1915
- try {
1916
- await assertRecoveryStoresClear(record);
1917
- } catch (error) {
1918
- if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
1919
- removable = false;
1920
- }
1921
- }
2015
+ const { ownerLive, retained: isRetained, removable } = await retentionOf(record, live, retained);
1922
2016
  rows.push({
1923
2017
  ...entryView(record),
1924
2018
  projectPath: record.projectPath,
@@ -1930,6 +2024,29 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
1930
2024
  return rows;
1931
2025
  }
1932
2026
 
2027
+ /** Who keeps `record` (listManagedWorktrees): `live` and `retained` are session id sets. */
2028
+ async function retentionOf(record, live, retained) {
2029
+ const snapshot = record.kind === WORKTREE_SNAPSHOT_KIND;
2030
+ const ownerLive = snapshot
2031
+ ? await snapshotHolderLive(record, live)
2032
+ : (!!record.ownerSessionId && live.has(record.ownerSessionId)) || leaseProcessAlive(await readOwnerLease(record));
2033
+ const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
2034
+ // A snapshot outlives no holder: the prune removes it, changes and all.
2035
+ let removable = snapshot
2036
+ ? !ownerLive
2037
+ : !record.sharedSessionIds?.length &&
2038
+ (record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
2039
+ if (removable) {
2040
+ try {
2041
+ await assertRecoveryStoresClear(record);
2042
+ } catch (error) {
2043
+ if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
2044
+ removable = false;
2045
+ }
2046
+ }
2047
+ return { ownerLive, retained: isRetained, removable };
2048
+ }
2049
+
1933
2050
  /**
1934
2051
  * Conservative reconcile (daemon startup, and the manual prune). Always:
1935
2052
  * resumes interrupted deletions, rolls back interrupted creations of no
@@ -1995,7 +2112,7 @@ export async function reconcileManagedWorktrees({
1995
2112
  // surviving folder since still keeps it.
1996
2113
  let release;
1997
2114
  try {
1998
- release = holdSnapshotFolder(record);
2115
+ release = await holdSnapshotFolder(record);
1999
2116
  } catch (error) {
2000
2117
  if (!snapshotInUse(error)) throw error;
2001
2118
  report.kept.push({ id: record.id, reason: 'snapshot-in-use' });
@@ -2004,7 +2121,7 @@ export async function reconcileManagedWorktrees({
2004
2121
  try {
2005
2122
  reportDeletion(record, await finishDeletion(record));
2006
2123
  } finally {
2007
- release();
2124
+ await release();
2008
2125
  }
2009
2126
  continue;
2010
2127
  }
@@ -2020,7 +2137,7 @@ export async function reconcileManagedWorktrees({
2020
2137
  let release = null;
2021
2138
  if (!(await snapshotHolderLive(record, live))) {
2022
2139
  try {
2023
- release = holdSnapshotFolder(record);
2140
+ release = await holdSnapshotFolder(record);
2024
2141
  } catch (error) {
2025
2142
  if (!snapshotInUse(error)) throw error;
2026
2143
  }
@@ -2036,7 +2153,7 @@ export async function reconcileManagedWorktrees({
2036
2153
  await putRecord(record);
2037
2154
  reportDeletion(record, await finishDeletion(record));
2038
2155
  } finally {
2039
- release();
2156
+ await release();
2040
2157
  }
2041
2158
  continue;
2042
2159
  }
@@ -1,26 +1,22 @@
1
1
  // Temporary git repositories and data dirs for the worktree suites.
2
2
  import '../git-direct.test-support.mjs';
3
3
  import { execFileSync } from 'node:child_process';
4
- import { appendFileSync, chmodSync, cpSync, existsSync, mkdtempSync, rmSync, writeFileSync, mkdirSync } from 'node:fs';
5
- import { tmpdir } from 'node:os';
4
+ import { appendFileSync, chmodSync, cpSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
6
5
  import { dirname, join } from 'node:path';
6
+ import { makeTempDirSync, removeTempDirSync } from '../../../../scripts/lib/scoped-temp.mjs';
7
7
 
8
8
  const created = [];
9
9
 
10
+ // A suite that never calls cleanupTempDirs still has its directories removed
11
+ // when the process exits.
10
12
  export function tempDir(prefix = 'mixdog-wt-') {
11
- const dir = mkdtempSync(join(tmpdir(), prefix));
13
+ const dir = makeTempDirSync(prefix);
12
14
  created.push(dir);
13
15
  return dir;
14
16
  }
15
17
 
16
18
  export function cleanupTempDirs() {
17
- for (const dir of created.splice(0)) {
18
- try {
19
- rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
20
- } catch {
21
- /* best effort */
22
- }
23
- }
19
+ for (const dir of created.splice(0)) removeTempDirSync(dir);
24
20
  }
25
21
 
26
22
  const GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: '0', GIT_EDITOR: 'true' };