mixdog 1.4.1 → 1.4.3

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 (630) hide show
  1. package/package.json +4 -3
  2. package/scripts/build-shipped-history.mjs +125 -33
  3. package/scripts/gate-local.mjs +220 -63
  4. package/scripts/graph-parity.mjs +8 -3
  5. package/scripts/lib/gate-scheduler.mjs +139 -32
  6. package/scripts/lib/gate-timing-reporter.mjs +16 -0
  7. package/scripts/lib/run-node-tests.mjs +71 -34
  8. package/scripts/lib/scoped-temp.mjs +1 -0
  9. package/scripts/lib/test-failure-records.mjs +14 -1
  10. package/scripts/lib/test-failure-summary.mjs +9 -4
  11. package/scripts/lib/test-spawn-ledger.mjs +43 -3
  12. package/scripts/post-release-check.mjs +26 -16
  13. package/scripts/pptx-kit-index.mjs +5 -6
  14. package/scripts/provider-pingpong-live.mjs +1 -1
  15. package/scripts/prune-embedding-runtime.mjs +3 -1
  16. package/scripts/release-paths.mjs +7 -1
  17. package/scripts/suite-health.mjs +110 -28
  18. package/scripts/test.mjs +9 -14
  19. package/src/agents/advisor/AGENT.md +4 -4
  20. package/src/agents/advisor/agent.json +1 -1
  21. package/src/agents/explore/AGENT.md +22 -0
  22. package/src/agents/explore/agent.json +6 -0
  23. package/src/cli.mjs +7 -0
  24. package/src/defaults/agents.json +7 -0
  25. package/src/defaults/shipped-history.json +38 -2
  26. package/src/defaults/skills/browser-use/SKILL.md +4 -1
  27. package/src/defaults/skills/code-tidy/SKILL.md +71 -102
  28. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
  29. package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
  30. package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
  31. package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
  32. package/src/defaults/skills/computer-use/SKILL.md +12 -2
  33. package/src/defaults/skills/setup/SKILL.md +2 -2
  34. package/src/defaults/skills/setup/references/actions.md +28 -9
  35. package/src/defaults/skills/setup/references/surfaces.md +5 -2
  36. package/src/defaults/skills/setup-guide/SKILL.md +11 -3
  37. package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
  38. package/src/defaults/skills/skill-creator/SKILL.md +85 -190
  39. package/src/defaults/skills/skill-creator/references/design.md +70 -162
  40. package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
  41. package/src/defaults/skills/test-suite/SKILL.md +194 -0
  42. package/src/defaults/skills/test-suite/references/case-management.md +51 -0
  43. package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
  44. package/src/defaults/skills/test-suite/references/reliability.md +49 -0
  45. package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
  46. package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
  47. package/src/defaults/skills/visualize/SKILL.md +6 -2
  48. package/src/lib/instruction-text.cjs +36 -0
  49. package/src/lib/rules-builder.cjs +40 -50
  50. package/src/orchestration/balanced.md +23 -0
  51. package/src/orchestration/focused.md +22 -0
  52. package/src/orchestration/none.md +5 -0
  53. package/src/orchestration/swarm.md +24 -0
  54. package/src/rules/agent-mode/AGENT_MODE.md +3 -1
  55. package/src/rules/agent-mode/MIXY.md +2 -2
  56. package/src/rules/lead/LEAD.md +3 -3
  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/60-verification.md +10 -9
  60. package/src/rules/shared/70-delivery.md +4 -3
  61. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
  62. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +3 -3
  63. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -2
  64. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +132 -21
  65. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -9
  66. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +2 -2
  67. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +67 -0
  69. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
  70. package/src/runtime/agent/orchestrator/config.mjs +12 -7
  71. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +7 -7
  72. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -30
  73. package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
  74. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +124 -12
  75. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +204 -49
  76. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +16 -7
  77. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +157 -57
  78. package/src/runtime/agent/orchestrator/mcp/client.mjs +54 -23
  79. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +8 -2
  81. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +83 -52
  82. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +1 -1
  83. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +14 -0
  84. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +43 -27
  85. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +43 -8
  86. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +30 -28
  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-sse-turn/turn-events/content-block-stop.mjs +3 -3
  90. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
  91. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
  92. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  93. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
  94. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
  95. package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
  96. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
  97. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
  98. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
  99. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
  100. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +2 -2
  102. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +48 -31
  103. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
  104. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
  105. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
  106. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
  107. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
  109. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +4 -6
  110. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2784 -2872
  111. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +5 -8
  112. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +26 -28
  113. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +288 -300
  114. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +3 -1
  115. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +1 -0
  116. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
  117. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
  118. package/src/runtime/agent/orchestrator/providers/registry.mjs +33 -2
  119. package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
  120. package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
  121. package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
  122. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +576 -0
  123. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +10 -30
  124. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +32 -0
  125. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +0 -11
  126. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +8 -0
  127. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +17 -3
  128. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +47 -27
  129. package/src/runtime/agent/orchestrator/runtime-core/goal-deadlines.mjs +141 -10
  130. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +26 -63
  131. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +28 -3
  132. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +36 -11
  133. package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +88 -56
  134. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +4 -1
  135. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +51 -32
  136. package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +45 -145
  137. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +15 -98
  138. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +32 -99
  139. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +23 -78
  140. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +69 -47
  141. package/src/runtime/agent/orchestrator/runtime-core/todo-list.mjs +367 -0
  142. package/src/runtime/agent/orchestrator/runtime-core/todo-tool-defs.mjs +47 -0
  143. package/src/runtime/agent/orchestrator/runtime-core/tool-availability.mjs +155 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +12 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +119 -35
  146. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +4 -1
  147. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +15 -6
  148. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
  149. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +28 -22
  150. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +30 -0
  151. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
  152. package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
  153. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +1 -1
  154. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +94 -10
  155. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -2
  156. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +1 -1
  157. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -1
  158. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +3 -0
  159. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +1 -1
  160. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -12
  161. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +4 -4
  162. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +11 -6
  163. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +6 -6
  164. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +7 -3
  165. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +11 -1
  166. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
  167. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +37 -8
  169. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +1 -1
  170. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +11 -1
  172. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +1 -1
  173. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +5 -3
  174. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
  175. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/todo-check.mjs +196 -0
  176. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +116 -50
  177. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +8 -1
  178. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +1 -1
  179. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +1 -1
  180. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -1
  181. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +5 -6
  182. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +27 -3
  183. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +18 -2
  184. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
  185. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
  186. package/src/runtime/agent/orchestrator/session/loop/turn-report.mjs +35 -0
  187. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +1 -1
  188. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +103 -50
  189. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +9 -7
  190. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +21 -3
  191. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +27 -11
  192. package/src/runtime/agent/orchestrator/session/manager/ask-turn-open.mjs +37 -34
  193. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +15 -0
  194. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +25 -15
  195. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +79 -24
  196. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +3 -0
  197. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +12 -1
  198. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
  199. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +6 -1
  200. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +9 -1
  201. package/src/runtime/agent/orchestrator/session/manager/pending-spool-path.mjs +2 -2
  202. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +1 -1
  203. package/src/runtime/agent/orchestrator/session/manager/prompt-settings.mjs +598 -0
  204. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +20 -0
  205. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -14
  206. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +2 -0
  207. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +12 -0
  208. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +1 -1
  210. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +56 -14
  211. package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +31 -0
  212. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +59 -20
  213. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +2 -0
  214. package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
  215. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
  216. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +18 -4
  217. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +8 -9
  218. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +339 -88
  219. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +135 -11
  220. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +377 -104
  221. package/src/runtime/agent/orchestrator/session/manager/turn-durability.mjs +144 -0
  222. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +48 -30
  223. package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
  224. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +4 -0
  225. package/src/runtime/agent/orchestrator/session/manager.mjs +6 -0
  226. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +12 -6
  227. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +8 -1
  228. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +1 -1
  229. package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +5 -1
  230. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +1 -1
  231. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +2 -2
  232. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +23 -2
  233. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +3 -3
  234. package/src/runtime/agent/orchestrator/session/store/transcript-durability.mjs +88 -0
  235. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +5 -0
  236. package/src/runtime/agent/orchestrator/session/store-summary-log.mjs +1 -1
  237. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +243 -38
  238. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
  239. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +177 -8
  240. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
  241. package/src/runtime/agent/orchestrator/session/store.mjs +5 -0
  242. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +7 -1
  243. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +9 -1
  244. package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
  245. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -1
  246. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +2 -2
  247. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -5
  248. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -1
  249. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
  250. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +21 -3
  251. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  252. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/worktree-add-guard.mjs +77 -0
  253. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -1
  254. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +42 -28
  255. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +30 -14
  256. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +2 -2
  257. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
  258. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +1 -1
  259. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +0 -1
  260. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
  261. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +0 -10
  262. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +95 -20
  263. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
  264. package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -24
  265. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary/child-kill.mjs +4 -3
  266. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +1 -2
  267. package/src/runtime/agent/orchestrator/tools/code-graph/modes/calls.mjs +1 -1
  268. package/src/runtime/agent/orchestrator/tools/code-graph/modes/symbols.mjs +2 -2
  269. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +4 -5
  270. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +3 -4
  271. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4 -22
  272. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  273. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
  274. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
  275. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +105 -15
  276. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
  277. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
  278. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
  279. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +35 -11
  280. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +2 -0
  281. package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
  282. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -6
  283. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +0 -1
  284. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  285. package/src/runtime/attachments/attachment-reference.mjs +1 -1
  286. package/src/runtime/attachments/pdf-extract.mjs +1 -1
  287. package/src/runtime/attachments/store.d.mts +1 -0
  288. package/src/runtime/attachments/store.mjs +2 -2
  289. package/src/runtime/channels/lib/config-reload-watch.mjs +42 -0
  290. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +29 -9
  291. package/src/runtime/channels/lib/scheduler.mjs +33 -0
  292. package/src/runtime/channels/lib/schedules-db.mjs +11 -4
  293. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +4 -1
  294. package/src/runtime/channels/lib/webhooks-db.mjs +9 -3
  295. package/src/runtime/channels/lib/whisper-port.mjs +19 -10
  296. package/src/runtime/channels/lib/whisper-server.mjs +22 -13
  297. package/src/runtime/channels/lib/worker-main.mjs +9 -31
  298. package/src/runtime/computer-bridge/linux-readiness.mjs +10 -14
  299. package/src/runtime/connectors/connector-accounts-mcp.mjs +372 -103
  300. package/src/runtime/connectors/gmail-app-password.mjs +4 -4
  301. package/src/runtime/connectors/google-mcp.mjs +1 -1
  302. package/src/runtime/effort-judge/judge-client.mjs +2 -2
  303. package/src/runtime/effort-judge/judge-input.mjs +4 -4
  304. package/src/runtime/explore/explorer.mjs +88 -0
  305. package/src/runtime/explore/tool-defs.mjs +35 -0
  306. package/src/runtime/explore/tool.mjs +123 -0
  307. package/src/runtime/local-provider/hardware.mjs +1 -1
  308. package/src/runtime/media/adapters/codex-image.mjs +3 -3
  309. package/src/runtime/media/adapters/gemini-video.mjs +1 -1
  310. package/src/runtime/media/media-usage.mjs +1 -1
  311. package/src/runtime/media/store.mjs +1 -1
  312. package/src/runtime/memory/index.mjs +15 -1
  313. package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
  314. package/src/runtime/memory/lib/embedding-reindex.mjs +27 -0
  315. package/src/runtime/memory/lib/embedding-worker.mjs +4 -0
  316. package/src/runtime/memory/lib/memory-embed.mjs +83 -14
  317. package/src/runtime/memory/lib/memory-process-lock.mjs +159 -36
  318. package/src/runtime/memory/lib/memory-text-utils.mjs +6 -1
  319. package/src/runtime/memory/lib/memory.mjs +17 -0
  320. package/src/runtime/memory/lib/pg/process.mjs +1 -1
  321. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -96
  322. package/src/runtime/memory/lib/recall-hybrid/hybrid-sql.mjs +12 -3
  323. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  324. package/src/runtime/office/authoring/pptx-author-action.mjs +1 -1
  325. package/src/runtime/office/authoring/xlsx-html-build.mjs +1 -1
  326. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  327. package/src/runtime/office/capabilities.mjs +1 -1
  328. package/src/runtime/office/core/office-core.mjs +1 -1
  329. package/src/runtime/office/design/content-model.mjs +3 -3
  330. package/src/runtime/office/design/docx/design-docx/section.mjs +6 -6
  331. package/src/runtime/office/design/xlsx/design-xlsx-components.mjs +1 -1
  332. package/src/runtime/office/design/xlsx/design-xlsx.mjs +1 -1
  333. package/src/runtime/office/pdf/ocr-engine.mjs +1 -1
  334. package/src/runtime/office/pdf/pdf-writer.mjs +4 -4
  335. package/src/runtime/office/portable/portable-docx-operations.mjs +2 -2
  336. package/src/runtime/office/portable/portable-soffice.mjs +8 -6
  337. package/src/runtime/office/portable/xlsx-contract.mjs +1 -1
  338. package/src/runtime/office/quality/assurance-structure-docx.mjs +1 -1
  339. package/src/runtime/shared/agent-route-config.mjs +17 -2
  340. package/src/runtime/shared/atomic-file.d.mts +8 -0
  341. package/src/runtime/shared/atomic-file.mjs +103 -2
  342. package/src/runtime/shared/background-tasks.mjs +37 -10
  343. package/src/runtime/shared/background-wait.mjs +66 -0
  344. package/src/runtime/shared/child-guardian.mjs +17 -7
  345. package/src/runtime/shared/config.mjs +313 -16
  346. package/src/runtime/shared/connector-accounts.mjs +5 -5
  347. package/src/runtime/shared/connector-catalog.d.mts +14 -8
  348. package/src/runtime/shared/connector-catalog.mjs +70 -52
  349. package/src/runtime/shared/custom-provider-keys.mjs +20 -0
  350. package/src/runtime/shared/file-has-data.mjs +26 -2
  351. package/src/runtime/shared/file-lock.mjs +21 -18
  352. package/src/runtime/shared/git-launch.d.mts +9 -0
  353. package/src/runtime/shared/git-launch.mjs +213 -0
  354. package/src/runtime/shared/git-runner-worker.mjs +2 -1
  355. package/src/runtime/shared/git-runner.mjs +7 -2
  356. package/src/runtime/shared/idle-gc.mjs +30 -7
  357. package/src/runtime/shared/llm/cost.mjs +6 -1
  358. package/src/runtime/shared/llm/http-agent.mjs +316 -29
  359. package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
  360. package/src/runtime/shared/llm/model-catalog.mjs +46 -6
  361. package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
  362. package/src/runtime/shared/llm/system-proxy.mjs +453 -0
  363. package/src/runtime/shared/llm/usage-ledger-quota.mjs +31 -12
  364. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +84 -8
  365. package/src/runtime/shared/llm/usage-ledger.mjs +3 -0
  366. package/src/runtime/shared/llm/usage-rollup.mjs +48 -0
  367. package/src/runtime/shared/maintenance-schedule.mjs +109 -0
  368. package/src/runtime/shared/process-runner.mjs +8 -4
  369. package/src/runtime/shared/provider-accounts.mjs +52 -2
  370. package/src/runtime/shared/routine-trigger.d.mts +13 -0
  371. package/src/runtime/shared/routine-trigger.mjs +34 -0
  372. package/src/runtime/shared/run-child.d.mts +2 -1
  373. package/src/runtime/shared/run-child.mjs +70 -18
  374. package/src/runtime/shared/session-scratch.mjs +14 -2
  375. package/src/runtime/shared/shipped-definitions.mjs +7 -1
  376. package/src/runtime/shared/staged-install-worker.mjs +5 -0
  377. package/src/runtime/shared/staged-update.mjs +47 -2
  378. package/src/runtime/shared/tool-card-model.golden.json +3 -12
  379. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  380. package/src/runtime/shared/tool-surface.mjs +110 -36
  381. package/src/runtime/shared/tool-work-units.mjs +35 -6
  382. package/src/runtime/shared/turn-snapshot.mjs +26 -4
  383. package/src/runtime/shared/turn-worktree-snapshot.mjs +409 -54
  384. package/src/runtime/shared/worker-requests.mjs +17 -3
  385. package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
  386. package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
  387. package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
  388. package/src/runtime/shared/worktrees/branch-management.mjs +5 -3
  389. package/src/runtime/shared/worktrees/contract.mjs +16 -6
  390. package/src/runtime/shared/worktrees/dependencies.mjs +127 -89
  391. package/src/runtime/shared/worktrees/disk.mjs +79 -2
  392. package/src/runtime/shared/worktrees/git.mjs +97 -7
  393. package/src/runtime/shared/worktrees/include.mjs +6 -4
  394. package/src/runtime/shared/worktrees/maintenance.mjs +422 -30
  395. package/src/runtime/shared/worktrees/manager.mjs +962 -197
  396. package/src/runtime/shared/worktrees/settings.mjs +33 -7
  397. package/src/runtime/shared/worktrees/test-support.mjs +5 -1
  398. package/src/runtime/shared/worktrees/worker-snapshots.mjs +82 -0
  399. package/src/runtime/tidy/install.mjs +95 -15
  400. package/src/runtime/tidy/languages.mjs +17 -15
  401. package/src/runtime/tidy/process.mjs +9 -5
  402. package/src/runtime/tidy/resolve.mjs +19 -16
  403. package/src/runtime/tidy/runners/biome.mjs +3 -3
  404. package/src/runtime/tidy/tool.mjs +1 -1
  405. package/src/runtime/tidy/worktree.mjs +10 -6
  406. package/src/runtime/visualize-bridge/client.mjs +4 -1
  407. package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
  408. package/src/runtime/web-search/index.mjs +4 -23
  409. package/src/runtime/web-search/lib/web-tools.mjs +2 -2
  410. package/src/runtime/web-search/tool-defs.mjs +17 -26
  411. package/src/session-runtime/agent-profile-changes.mjs +55 -4
  412. package/src/session-runtime/agent-task-sessions.mjs +410 -353
  413. package/src/session-runtime/boot/apis.mjs +27 -4
  414. package/src/session-runtime/boot/begin.mjs +2 -0
  415. package/src/session-runtime/boot/config.mjs +10 -1
  416. package/src/session-runtime/boot/facade.mjs +1 -0
  417. package/src/session-runtime/boot/providers.mjs +70 -3
  418. package/src/session-runtime/boot/session.mjs +2 -0
  419. package/src/session-runtime/boot/tools.mjs +71 -25
  420. package/src/session-runtime/bot-status.mjs +103 -103
  421. package/src/session-runtime/channel-config-api.mjs +1 -0
  422. package/src/session-runtime/config-change-effects.mjs +179 -0
  423. package/src/session-runtime/config-lifecycle/config-writers.mjs +1 -0
  424. package/src/session-runtime/config-lifecycle.mjs +160 -24
  425. package/src/session-runtime/connector-merge-migration.mjs +18 -15
  426. package/src/session-runtime/conversation-import/discovery.mjs +245 -47
  427. package/src/session-runtime/conversation-import/service.mjs +12 -5
  428. package/src/session-runtime/goal-facade-api.mjs +49 -3
  429. package/src/session-runtime/handoff-attachments.mjs +1 -1
  430. package/src/session-runtime/held-requests.mjs +3 -1
  431. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +3 -0
  432. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -2
  433. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -11
  434. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
  435. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +161 -120
  436. package/src/session-runtime/internal-tool-executor.mjs +12 -19
  437. package/src/session-runtime/lifecycle/cold-heir.mjs +7 -0
  438. package/src/session-runtime/lifecycle/memory-ingest.mjs +3 -3
  439. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +53 -5
  440. package/src/session-runtime/lifecycle/session-switch.mjs +13 -2
  441. package/src/session-runtime/lifecycle/teardown/session-close.mjs +10 -5
  442. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  443. package/src/session-runtime/lifecycle-api.mjs +1 -0
  444. package/src/session-runtime/mcp-glue/server-catalog.mjs +27 -10
  445. package/src/session-runtime/mcp-glue/server-connection.mjs +34 -8
  446. package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
  447. package/src/session-runtime/mixy-heartbeat.mjs +1 -1
  448. package/src/session-runtime/model-route/set-route.mjs +40 -7
  449. package/src/session-runtime/native-web-search/routes.mjs +3 -3
  450. package/src/session-runtime/provider-auth/login.mjs +2 -2
  451. package/src/session-runtime/provider-auth/refresh.mjs +6 -3
  452. package/src/session-runtime/provider-auth/setup.mjs +1 -1
  453. package/src/session-runtime/provider-readiness.mjs +53 -4
  454. package/src/session-runtime/resource-api.mjs +1 -1
  455. package/src/session-runtime/resource-extension-sync.mjs +4 -8
  456. package/src/session-runtime/resource-mcp-api.mjs +98 -35
  457. package/src/session-runtime/resource-mcp-connector-accounts.mjs +49 -32
  458. package/src/session-runtime/resource-mcp-secrets.mjs +27 -10
  459. package/src/session-runtime/resource-mcp-servers.mjs +5 -4
  460. package/src/session-runtime/resource-plugins-api.mjs +4 -0
  461. package/src/session-runtime/routine-executor.mjs +152 -0
  462. package/src/session-runtime/routine-home-turn.mjs +46 -5
  463. package/src/session-runtime/runtime-facade.mjs +5 -0
  464. package/src/session-runtime/runtime-feature-gates.mjs +2 -11
  465. package/src/session-runtime/schedule-session-run.mjs +1 -0
  466. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +6 -1
  467. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +7 -0
  468. package/src/session-runtime/services/agent-tool/send-flow.mjs +120 -8
  469. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +12 -0
  470. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +5 -0
  471. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
  472. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +28 -7
  473. package/src/session-runtime/services/agent-tool.mjs +51 -1
  474. package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
  475. package/src/session-runtime/services/channel-admin.mjs +18 -0
  476. package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
  477. package/src/session-runtime/services/daemon-candidate.mjs +4 -1
  478. package/src/session-runtime/services/hook-bus/command-handler.mjs +7 -11
  479. package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
  480. package/src/session-runtime/services/plugin-admin.mjs +14 -6
  481. package/src/session-runtime/services/provider-admin.mjs +281 -10
  482. package/src/session-runtime/services/seeds.mjs +7 -0
  483. package/src/session-runtime/services/usage-stats-model.mjs +32 -11
  484. package/src/session-runtime/session-create/materialize.mjs +4 -2
  485. package/src/session-runtime/session-create/session-options.mjs +2 -0
  486. package/src/session-runtime/session-turn-api.mjs +2 -0
  487. package/src/session-runtime/settings-builtin-tools-api.mjs +5 -10
  488. package/src/session-runtime/settings-system-api.mjs +1 -1
  489. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
  490. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
  491. package/src/session-runtime/setup-tool/executor.mjs +14 -3
  492. package/src/session-runtime/setup-tool/extended-actions.mjs +2 -0
  493. package/src/session-runtime/setup-tool/settings-contract.mjs +28 -0
  494. package/src/session-runtime/setup-tool/tool-defs.mjs +28 -2
  495. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +40 -43
  496. package/src/session-runtime/tool-policy/mode-switch.mjs +1 -1
  497. package/src/session-runtime/tool-policy/policy-stage.mjs +106 -8
  498. package/src/session-runtime/tool-policy/workflow-overlay.mjs +2 -1
  499. package/src/session-runtime/tool-policy-refresh.mjs +182 -5
  500. package/src/session-runtime/tool-surface.mjs +38 -1
  501. package/src/session-runtime/turn/agent-ops.mjs +33 -2
  502. package/src/session-runtime/turn/session-ops.mjs +2 -0
  503. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +5 -0
  504. package/src/session-runtime/turn/turn-run.mjs +1 -1
  505. package/src/session-runtime/webhook-session-run.mjs +2 -0
  506. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +46 -11
  507. package/src/session-runtime/workflow-agents-api/agent-route.mjs +2 -0
  508. package/src/session-runtime/workflow-agents-api/instruction-files.mjs +165 -0
  509. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +5 -4
  510. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +2 -3
  511. package/src/session-runtime/workflow-agents-api.mjs +2 -0
  512. package/src/session-runtime/workspace/activity-guards.mjs +176 -0
  513. package/src/session-runtime/workspace/project-branches.mjs +1 -1
  514. package/src/session-runtime/workspace/session-view.mjs +149 -0
  515. package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
  516. package/src/session-runtime/workspace/transition-runner.mjs +188 -0
  517. package/src/session-runtime/workspace/transitions.mjs +128 -1070
  518. package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
  519. package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
  520. package/src/session-runtime/workspace/worktree-maintenance.mjs +200 -0
  521. package/src/session-runtime/workspace/worktree-setup.mjs +97 -0
  522. package/src/session-runtime/workspace/worktree-tool.mjs +70 -54
  523. package/src/standalone/daemon-agent-control.mjs +25 -8
  524. package/src/standalone/daemon-desktop-runtime.mjs +8 -2
  525. package/src/standalone/daemon-lag-profiler.mjs +7 -7
  526. package/src/standalone/daemon-session-control.mjs +151 -136
  527. package/src/standalone/daemon.mjs +61 -2
  528. package/src/standalone/desktop-service-registry.mjs +9 -0
  529. package/src/standalone/local-session-runtime.mjs +21 -1
  530. package/src/standalone/session-client/daemon-unavailable.mjs +4 -1
  531. package/src/standalone/session-client.mjs +5 -1
  532. package/src/standalone/session-frame-stream.mjs +83 -11
  533. package/src/standalone/session-protocol.mjs +15 -0
  534. package/src/standalone/session-service/agent-route-follow.mjs +23 -20
  535. package/src/standalone/session-service/agent-tree/agent-turns.mjs +18 -6
  536. package/src/standalone/session-service/agent-tree.mjs +45 -9
  537. package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
  538. package/src/standalone/session-service/quota-resume.mjs +9 -0
  539. package/src/standalone/session-service/session-calls/session-action.mjs +51 -1
  540. package/src/standalone/session-service/session-calls/session-turns.mjs +37 -18
  541. package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
  542. package/src/standalone/session-service/session-calls/turn-gate.mjs +34 -0
  543. package/src/standalone/session-service/session-calls.mjs +2 -1
  544. package/src/standalone/session-service/stored-reader.mjs +127 -40
  545. package/src/tui/App.jsx +162 -164
  546. package/src/tui/app/app-view/floating-panel.jsx +3 -0
  547. package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
  548. package/src/tui/app/clipboard.mjs +22 -11
  549. package/src/tui/app/create-app-pickers.mjs +2 -0
  550. package/src/tui/app/doctor.mjs +2 -2
  551. package/src/tui/app/panel-signature.mjs +1 -1
  552. package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
  553. package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
  554. package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
  555. package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
  556. package/src/tui/app/provider-setup/oauth-actions.mjs +25 -6
  557. package/src/tui/app/provider-setup-picker.mjs +20 -13
  558. package/src/tui/app/settings-picker.mjs +53 -8
  559. package/src/tui/app/shell-layout/row-budgets.mjs +14 -12
  560. package/src/tui/app/slash-commands.mjs +2 -1
  561. package/src/tui/app/slash-dispatch/route-commands.mjs +1 -1
  562. package/src/tui/app/slash-dispatch/session-commands.mjs +47 -1
  563. package/src/tui/app/slash-dispatch.mjs +1 -1
  564. package/src/tui/app/use-btw-panel.mjs +29 -0
  565. package/src/tui/app/use-context-panel-refresh.mjs +31 -0
  566. package/src/tui/app/use-model-catalog-cache.mjs +13 -10
  567. package/src/tui/app/use-mouse-input.mjs +11 -0
  568. package/src/tui/app/use-onboarding-start.mjs +8 -3
  569. package/src/tui/app/use-panel-transition.mjs +10 -1
  570. package/src/tui/app/use-pasted-buffers.mjs +28 -20
  571. package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
  572. package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
  573. package/src/tui/app/use-prompt-queue-history.mjs +5 -4
  574. package/src/tui/app/use-selection-focus.mjs +11 -2
  575. package/src/tui/app/use-selection-geometry.mjs +18 -9
  576. package/src/tui/app/use-selection-paint.mjs +4 -4
  577. package/src/tui/app/use-selection-stitch.mjs +3 -3
  578. package/src/tui/app/use-slash-palette.mjs +62 -0
  579. package/src/tui/app/use-terminal-chrome.mjs +2 -2
  580. package/src/tui/app/use-transcript-activity.mjs +48 -33
  581. package/src/tui/app/use-transcript-follow.mjs +12 -4
  582. package/src/tui/app/use-transcript-scroll.mjs +46 -17
  583. package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
  584. package/src/tui/app/use-transcript-window/geometry.mjs +20 -6
  585. package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
  586. package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
  587. package/src/tui/app/use-transcript-window.mjs +21 -11
  588. package/src/tui/app/use-tui-ready.mjs +18 -0
  589. package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
  590. package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
  591. package/src/tui/components/Picker.jsx +27 -3
  592. package/src/tui/components/SignInUrl.jsx +68 -0
  593. package/src/tui/components/TextEntryPanel.jsx +76 -46
  594. package/src/tui/components/prompt-input/escape-policy.d.mts +0 -1
  595. package/src/tui/components/prompt-input/escape-policy.mjs +1 -1
  596. package/src/tui/components/question-panel-model.mjs +4 -4
  597. package/src/tui/components/sign-in-url-layout.mjs +24 -0
  598. package/src/tui/components/tool-execution/standard-card.jsx +3 -4
  599. package/src/tui/components/user-message-skills.mjs +1 -1
  600. package/src/tui/dist/index.mjs +2205 -1371
  601. package/src/tui/markdown/render-ansi.mjs +1 -1
  602. package/src/tui/session/agent-job-feed/notification-router.mjs +10 -0
  603. package/src/tui/session/agent-job-feed.mjs +2 -0
  604. package/src/tui/session/context-state.mjs +3 -0
  605. package/src/tui/session/goal-turn-state.mjs +6 -2
  606. package/src/tui/session/quota-resume.mjs +1 -1
  607. package/src/tui/session/session-api/controls.mjs +4 -0
  608. package/src/tui/session/session-api/extensions.mjs +8 -0
  609. package/src/tui/session/session-api/intake/abort.mjs +2 -1
  610. package/src/tui/session/session-api/intake.mjs +2 -0
  611. package/src/tui/session/session-api/integrations.mjs +2 -2
  612. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  613. package/src/tui/session/session-api/lifecycle/session-reset.mjs +7 -0
  614. package/src/tui/session/session-api/routes-agent-definitions.mjs +6 -0
  615. package/src/tui/session/session-api/settings.mjs +2 -2
  616. package/src/tui/session/session-api/worktree.mjs +13 -1
  617. package/src/tui/session/session-flow/drain.mjs +11 -14
  618. package/src/tui/session/tool-card-results/grouped-result.mjs +2 -2
  619. package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
  620. package/src/tui/session/transcript-spill.mjs +92 -4
  621. package/src/tui/session/transcript-store.mjs +2 -0
  622. package/src/tui/session/turn-quiet.mjs +1 -1
  623. package/src/tui/session/turn.mjs +3 -0
  624. package/src/tui/session/worktree-setup-notice.mjs +1 -1
  625. package/src/tui/spinner-meta.mjs +3 -3
  626. package/src/tui/spinner-verbs.mjs +2 -2
  627. package/src/defaults/skills/goal-management/SKILL.md +0 -169
  628. package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
  629. package/src/runtime/agent/orchestrator/runtime-core/goal-tasks.mjs +0 -156
  630. package/src/session-runtime/goal-tasks.mjs +0 -1
@@ -104,9 +104,10 @@ async function runGit(
104
104
  maxBytes = COMMAND_MAX_BYTES,
105
105
  allowFailure = false,
106
106
  stdoutEncoding = 'utf8',
107
+ env = null,
107
108
  } = {}
108
109
  ) {
109
- const result = await runGitOffThread(args, { cwd, input, timeoutMs, maxBytes, stdoutEncoding });
110
+ const result = await runGitOffThread(args, { cwd, input, env, timeoutMs, maxBytes, stdoutEncoding });
110
111
  if (result.code !== 0 && !allowFailure) throw commandError(args, result.stderr, result.code);
111
112
  return result;
112
113
  }
@@ -142,6 +143,7 @@ function stateForRoot(root) {
142
143
  gitDir,
143
144
  initialized: false,
144
145
  sourceIndexPath: null,
146
+ sourcePaths: null,
145
147
  sourceIndexIdentity: null,
146
148
  sourceTracked: new Set(),
147
149
  lineEndingArgs: [],
@@ -233,7 +235,7 @@ function assertStateLive(state) {
233
235
  throw error;
234
236
  }
235
237
 
236
- function shadowArgs(state, args) {
238
+ function shadowArgs(state, args, workTree = state.root) {
237
239
  assertStateLive(state);
238
240
  return [
239
241
  ...state.lineEndingArgs,
@@ -245,7 +247,7 @@ function shadowArgs(state, args) {
245
247
  '--git-dir',
246
248
  state.gitDir,
247
249
  '--work-tree',
248
- state.root,
250
+ workTree,
249
251
  ...args,
250
252
  ];
251
253
  }
@@ -259,21 +261,54 @@ async function sourceGitPath(root, suffix) {
259
261
  return result.code === 0 && value ? resolve(root, value) : null;
260
262
  }
261
263
 
262
- async function syncSourceExclude(state) {
263
- const source = await sourceGitPath(state.root, 'info/exclude');
264
- if (!source || !(await exists(source))) return;
265
- const target = join(state.gitDir, 'info', 'exclude');
266
- await mkdir(dirname(target), { recursive: true });
267
- await copyFile(source, target).catch(() => {});
264
+ /** The source repository's info/exclude, index and common directory paths
265
+ * from one `rev-parse`, kept for the state's lifetime once answered (the
266
+ * index path already was). An unanswered or unexpected reply falls back to
267
+ * the per-path reads, uncached, so a failure is retried as before. */
268
+ async function sourceGitPaths(state) {
269
+ if (state.sourcePaths) return state.sourcePaths;
270
+ const result = await runGit(
271
+ ['rev-parse', '--path-format=absolute', '--git-path', 'info/exclude', '--git-path', 'index', '--git-common-dir'],
272
+ { cwd: state.root, allowFailure: true }
273
+ );
274
+ const lines = String(result.stdout || '')
275
+ .split(/\r?\n/)
276
+ .filter((line) => line !== '');
277
+ if (result.code === 0 && lines.length === 3 && lines.every((line) => clean(line))) {
278
+ const [exclude, index, commonDir] = lines.map((line) => clean(line));
279
+ state.sourcePaths = {
280
+ exclude: resolve(state.root, exclude),
281
+ index: resolve(state.root, index),
282
+ commonDir,
283
+ };
284
+ return state.sourcePaths;
285
+ }
286
+ const [exclude, index, commonDir] = await Promise.all([
287
+ sourceGitPath(state.root, 'info/exclude'),
288
+ sourceGitPath(state.root, 'index'),
289
+ sourceCommonDir(state.root),
290
+ ]);
291
+ return { exclude, index, commonDir };
268
292
  }
269
293
 
270
- async function syncAlternates(state) {
294
+ async function sourceCommonDir(root) {
271
295
  const result = await runGit(['rev-parse', '--path-format=absolute', '--git-common-dir'], {
272
- cwd: state.root,
296
+ cwd: root,
273
297
  allowFailure: true,
274
298
  });
275
299
  const commonDir = clean(result.stdout);
276
- if (result.code !== 0 || !commonDir) return;
300
+ return result.code === 0 && commonDir ? commonDir : null;
301
+ }
302
+
303
+ async function syncSourceExclude(state, source) {
304
+ if (!source || !(await exists(source))) return;
305
+ const target = join(state.gitDir, 'info', 'exclude');
306
+ await mkdir(dirname(target), { recursive: true });
307
+ await copyFile(source, target).catch(() => {});
308
+ }
309
+
310
+ async function syncAlternates(state, commonDir) {
311
+ if (!commonDir) return;
277
312
  const sourceObjects = join(resolve(state.root, commonDir), 'objects');
278
313
  if (!(await exists(sourceObjects))) return;
279
314
  const alternates = [sourceObjects];
@@ -294,7 +329,7 @@ async function syncAlternates(state) {
294
329
  }
295
330
 
296
331
  async function sourceIndexIdentity(state) {
297
- state.sourceIndexPath ??= await sourceGitPath(state.root, 'index');
332
+ state.sourceIndexPath ??= (await sourceGitPaths(state)).index;
298
333
  if (!state.sourceIndexPath) return 'missing';
299
334
  try {
300
335
  const stat = await lstat(state.sourceIndexPath);
@@ -349,10 +384,14 @@ async function ensureState(state) {
349
384
  'utf8'
350
385
  );
351
386
  }
387
+ // One layout read serves both syncs below. Every (re)initialisation reads the
388
+ // source layout afresh, so a changed `.git` indirection is never served stale.
389
+ state.sourcePaths = null;
390
+ const paths = await sourceGitPaths(state);
352
391
  const [lineEndingArgs] = await Promise.all([
353
392
  sourceLineEndingArgs(state.root),
354
- syncSourceExclude(state),
355
- syncAlternates(state),
393
+ syncSourceExclude(state, paths.exclude),
394
+ syncAlternates(state, paths.commonDir),
356
395
  ]);
357
396
  state.lineEndingArgs = lineEndingArgs;
358
397
  // Seed once per process, then keep this index synchronized with the live
@@ -366,7 +405,7 @@ async function ensureState(state) {
366
405
 
367
406
  async function resetShadowIndex(state) {
368
407
  state.lastCapture = null;
369
- state.sourceIndexPath ??= await sourceGitPath(state.root, 'index');
408
+ state.sourceIndexPath ??= (await sourceGitPaths(state)).index;
370
409
  const sourceIndex = state.sourceIndexPath;
371
410
  const target = join(state.gitDir, 'index');
372
411
  if (sourceIndex && (await exists(sourceIndex))) {
@@ -545,7 +584,9 @@ function withOmittedBaselines(snapshot, review) {
545
584
  return { ...review, files, patch, diffTooLarge: reviewDiffTooLarge(files, patch) };
546
585
  }
547
586
 
548
- async function applyBaselineFilesUnlocked(state, tree, allEntries) {
587
+ /** `tree` with `allEntries` (recorded first states) applied. `absent`: keys of
588
+ * paths known not to be in `tree`, whose removal is a no-op and runs no git. */
589
+ async function applyBaselineFilesUnlocked(state, tree, allEntries, { absent = null } = {}) {
549
590
  // Omitted baselines change no tree: they are carried as metadata only.
550
591
  const files = allEntries
551
592
  .filter((entry) => entry?.omitted === true)
@@ -555,37 +596,260 @@ async function applyBaselineFilesUnlocked(state, tree, allEntries) {
555
596
  omitted: true,
556
597
  size: Number(entry.size) || 0,
557
598
  }));
558
- const entries = allEntries.filter((entry) => entry?.omitted !== true);
559
- if (entries.length === 0) return { tree, files };
560
- const saved = clean((await runGit(shadowArgs(state, ['write-tree']), { cwd: state.root })).stdout);
561
- try {
562
- await runGit(shadowArgs(state, ['read-tree', tree]), { cwd: state.root });
563
- for (const entry of entries) {
599
+ const entries = allEntries
600
+ .filter((entry) => entry?.omitted !== true)
601
+ .map((entry) => {
564
602
  const path = safeRelativePath(state.root, entry.path);
565
- let oid = entry.oid || null;
566
- if (entry.content !== undefined && entry.content !== null) {
567
- oid = clean(
568
- (
569
- await runGit(shadowArgs(state, ['hash-object', '-w', '--stdin', '--path', path]), {
570
- cwd: state.root,
571
- input: entry.content,
572
- })
573
- ).stdout
574
- );
603
+ const content = entry.content !== undefined && entry.content !== null ? entry.content : null;
604
+ const noop = content === null && !entry.oid && Boolean(absent?.has(pathKey(path)));
605
+ return { path, content, oid: entry.oid || null, noop };
606
+ });
607
+ if (entries.every((entry) => entry.noop)) {
608
+ return { tree, files: [...files, ...entries.map(({ path }) => ({ path, oid: null }))] };
609
+ }
610
+ try {
611
+ return await applyInIndex(state, tree, entries, files, temporaryIndexEnv(state), { batch: true });
612
+ } catch {
613
+ // The original sequence in the shadow index: it fails, if at all, as before.
614
+ return await applyInShadowIndex(state, tree, entries, files);
615
+ }
616
+ }
617
+
618
+ let temporaryIndexSeq = 0;
619
+
620
+ /** An environment whose git index is a fresh file in the shadow repository. */
621
+ function temporaryIndexEnv(state) {
622
+ const index = join(state.gitDir, `index.baseline-${process.pid}-${++temporaryIndexSeq}`);
623
+ return { ...process.env, GIT_INDEX_FILE: index };
624
+ }
625
+
626
+ /** `content` written as a blob, converted as the file at `path` would be. */
627
+ async function hashBlob(state, path, content, env) {
628
+ const result = await runGit(shadowArgs(state, ['hash-object', '-w', '--stdin', '--path', path]), {
629
+ cwd: state.root,
630
+ input: content,
631
+ env,
632
+ });
633
+ return clean(result.stdout);
634
+ }
635
+
636
+ let blobWorkSeq = 0;
637
+ // A path component a scratch worktree file could not carry unchanged: a
638
+ // character or name the platform rewrites (Windows device names, trailing dots
639
+ // and spaces, 8.3 aliases) or git treats specially (`.git`, `.gitattributes`).
640
+ const UNBATCHABLE_COMPONENT =
641
+ /[\u0000-\u001f"*:<>?|\\]|[. ]$|~\d|^(?:con|prn|aux|nul|(?:com|lpt)[0-9\u00b9\u00b2\u00b3])(?:\..*)?$|^\.(?:git|gitattributes)$/i;
642
+ // Longest scratch file path written: below the classic Windows MAX_PATH.
643
+ const MAX_BATCH_PATH = 240;
644
+
645
+ function batchKey(path) {
646
+ return path.normalize('NFC').toLowerCase();
647
+ }
648
+
649
+ /** Blob ids of `items` (`{ path, content }`) as `hash-object --stdin --path`
650
+ * gives them, in a constant number of git processes. hash-object takes its
651
+ * attributes, `core.autocrlf` and eol conversion from the file's path, so the
652
+ * contents are written to a scratch worktree at the same relative paths, with
653
+ * the real worktree's `.gitattributes` files beside them, and hashed there by
654
+ * one `hash-object --stdin-paths`: the same attribute stack, the same
655
+ * conversion code. A path with a `filter=` attribute (a clean driver may read
656
+ * the worktree) and a path the scratch worktree cannot represent exactly are
657
+ * hashed one by one as before. Any failure throws and the caller falls back. */
658
+ async function hashBlobs(state, items, env) {
659
+ const ids = new Map();
660
+ const batched = [];
661
+ const single = [];
662
+ const keys = new Set();
663
+ const scratch = join(state.gitDir, `baseline-work-${process.pid}-${++blobWorkSeq}`);
664
+ for (const item of items) {
665
+ const key = batchKey(item.path);
666
+ const fits =
667
+ !keys.has(key) &&
668
+ scratch.length + 1 + item.path.length <= MAX_BATCH_PATH &&
669
+ !item.path.split('/').some((part) => UNBATCHABLE_COMPONENT.test(part));
670
+ if (fits) {
671
+ keys.add(key);
672
+ batched.push(item);
673
+ } else {
674
+ single.push(item);
675
+ }
676
+ }
677
+ if (batched.length > 0) {
678
+ try {
679
+ const directories = new Set(['']);
680
+ for (const { path } of batched) {
681
+ for (let dir = dirname(path); dir !== '.'; dir = dirname(dir)) directories.add(dir);
682
+ }
683
+ await mkdir(scratch, { recursive: true });
684
+ await Promise.all([...directories].map((dir) => mkdir(join(scratch, dir), { recursive: true })));
685
+ await Promise.all([
686
+ ...batched.map(({ path, content }) => writeFile(join(scratch, path), content)),
687
+ // git ignores a symbolic-link .gitattributes, so only a regular file is carried over.
688
+ ...[...directories].map(async (dir) => {
689
+ const source = join(state.root, dir, '.gitattributes');
690
+ if ((await lstat(source).catch(() => null))?.isFile())
691
+ await copyFile(source, join(scratch, dir, '.gitattributes'));
692
+ }),
693
+ ]);
694
+ const options = { cwd: scratch, env };
695
+ const filtered = await runGit(shadowArgs(state, ['check-attr', '-z', '--stdin', 'filter'], scratch), {
696
+ ...options,
697
+ input: `${batched.map(({ path }) => path).join('\0')}\0`,
698
+ });
699
+ const fields = filtered.stdout.split('\0');
700
+ const driven = new Set();
701
+ for (let index = 0; index + 2 < fields.length; index += 3) {
702
+ if (fields[index + 2] !== 'unspecified') driven.add(fields[index]);
703
+ }
704
+ const plain = batched.filter((item) => {
705
+ if (!driven.has(item.path)) return true;
706
+ single.push(item);
707
+ return false;
708
+ });
709
+ if (plain.length > 0) {
710
+ const hashed = await runGit(shadowArgs(state, ['hash-object', '-w', '--stdin-paths'], scratch), {
711
+ ...options,
712
+ input: `${plain.map(({ path }) => path).join('\n')}\n`,
713
+ });
714
+ const oids = hashed.stdout.split('\n').filter(Boolean);
715
+ if (oids.length !== plain.length) throw new Error('hash-object answered a different number of blobs');
716
+ plain.forEach((item, index) => {
717
+ ids.set(item, oids[index].trim());
718
+ });
719
+ }
720
+ } finally {
721
+ await rm(scratch, { recursive: true, force: true }).catch(() => {});
722
+ }
723
+ }
724
+ for (const item of single) ids.set(item, await hashBlob(state, item.path, item.content, env));
725
+ return ids;
726
+ }
727
+
728
+ // Longest ls-tree command line the directory/file probe sends.
729
+ const MAX_PROBE_CHARS = 24_000;
730
+
731
+ /** Every proper parent directory of `path`, outermost last. */
732
+ function parentDirectories(path) {
733
+ const parents = [];
734
+ for (let dir = dirname(path); dir !== '.' && dir !== '/'; dir = dirname(dir)) parents.push(dir);
735
+ return parents;
736
+ }
737
+
738
+ /** Could `update-index --index-info` take `addPaths` on top of `tree` without
739
+ * replacing anything? Unlike `--cacheinfo`, it replaces a file by a directory
740
+ * of the same name and the reverse; the per-file sequence refuses both and
741
+ * the caller must see that refusal. False for a pair of added paths where one
742
+ * is a directory of the other, or an added path whose parent is a file (or
743
+ * submodule) in `tree`, or that is a directory in `tree`. A path the probe
744
+ * cannot ask about exactly (a leading ':' is pathspec magic) or too many to
745
+ * ask at once counts as unsafe, so the caller runs the per-file sequence. */
746
+ async function addsReplaceNothing(state, tree, addPaths, env) {
747
+ if (addPaths.length === 0) return true;
748
+ if (addPaths.some((path) => path.startsWith(':'))) return false;
749
+ const added = new Set(addPaths);
750
+ const parents = new Set(addPaths.flatMap(parentDirectories));
751
+ if ([...parents].some((dir) => added.has(dir))) return false;
752
+ const asked = [...new Set([...added, ...parents])];
753
+ if (asked.reduce((total, path) => total + path.length + 1, 0) > MAX_PROBE_CHARS) return false;
754
+ const listed = await runGit(shadowArgs(state, ['ls-tree', '-z', tree, '--', ...asked]), {
755
+ cwd: state.root,
756
+ env,
757
+ });
758
+ for (const record of listed.stdout.split('\0')) {
759
+ const tab = record.indexOf('\t');
760
+ if (tab < 0) continue;
761
+ const isTree = record.slice(0, tab).split(' ')[1] === 'tree';
762
+ const path = record.slice(tab + 1);
763
+ if (isTree ? added.has(path) : parents.has(path)) return false;
764
+ }
765
+ return true;
766
+ }
767
+
768
+ /** The entries applied on top of `tree` in an index of their own, removed
769
+ * afterwards: the shadow index is never touched, so it needs no save and
770
+ * restore. Every command (hash-object's attribute lookup included) sees the
771
+ * same index content the original sequence does: `tree` plus the entries so
772
+ * far. Null `env`: the shadow index itself (the caller saves and restores).
773
+ * `batch`: when it spawns fewer git processes and no entry swaps a file for a
774
+ * directory (addsReplaceNothing), every blob is hashed together (hashBlobs)
775
+ * and every add and removal is one `update-index --index-info`, instead of a
776
+ * `hash-object` and an `update-index` per entry. */
777
+ async function applyInIndex(state, tree, entries, baseFiles, env, { batch = false } = {}) {
778
+ const files = [...baseFiles];
779
+ try {
780
+ const live = entries.filter(({ noop }) => !noop);
781
+ const contents = live.filter(({ content }) => content !== null).length;
782
+ const adds = live.filter(({ content, oid }) => content !== null || oid).map(({ path }) => path);
783
+ // Per entry: a hash (content) plus an update-index, or an update-index. In
784
+ // batch: check-attr and hash-object for all contents, an ls-tree probe
785
+ // when anything is added, and one update-index.
786
+ const worthBatching =
787
+ batch && (contents > 0 ? 2 : 0) + 1 + (adds.length > 0 ? 1 : 0) < 2 * contents + (live.length - contents);
788
+ const [, replacesNothing] = await Promise.all([
789
+ runGit(shadowArgs(state, ['read-tree', tree]), { cwd: state.root, env }),
790
+ worthBatching ? addsReplaceNothing(state, tree, adds, env) : false,
791
+ ]);
792
+ if (replacesNothing) {
793
+ const hashed = await hashBlobs(
794
+ state,
795
+ live.filter(({ content }) => content !== null),
796
+ env
797
+ );
798
+ const nullOid = '0'.repeat(tree.length);
799
+ let info = '';
800
+ for (const entry of entries) {
801
+ if (entry.noop) {
802
+ files.push({ path: entry.path, oid: null });
803
+ continue;
804
+ }
805
+ const oid = entry.content !== null ? hashed.get(entry) : entry.oid;
806
+ // Mode 0 removes the path, as `update-index --force-remove` did.
807
+ info += oid ? `100644 ${oid}\t${entry.path}\0` : `0 ${nullOid}\t${entry.path}\0`;
808
+ files.push({ path: entry.path, oid });
809
+ }
810
+ await runGit(shadowArgs(state, ['update-index', '-z', '--index-info']), {
811
+ cwd: state.root,
812
+ env,
813
+ input: info,
814
+ });
815
+ entries = [];
816
+ }
817
+ for (const { path, content, oid: recorded, noop } of entries) {
818
+ if (noop) {
819
+ files.push({ path, oid: null });
820
+ continue;
821
+ }
822
+ let oid = recorded;
823
+ if (content !== null) {
824
+ oid = await hashBlob(state, path, content, env);
575
825
  }
576
826
  if (oid) {
577
827
  await runGit(shadowArgs(state, ['update-index', '--add', '--cacheinfo', '100644', oid, path]), {
578
828
  cwd: state.root,
829
+ env,
579
830
  });
580
831
  } else {
581
- await runGit(shadowArgs(state, ['update-index', '--force-remove', '--', path]), { cwd: state.root });
832
+ await runGit(shadowArgs(state, ['update-index', '--force-remove', '--', path]), { cwd: state.root, env });
582
833
  }
583
834
  files.push({ path, oid });
584
835
  }
585
836
  return {
586
- tree: clean((await runGit(shadowArgs(state, ['write-tree']), { cwd: state.root })).stdout),
837
+ tree: clean((await runGit(shadowArgs(state, ['write-tree']), { cwd: state.root, env })).stdout),
587
838
  files,
588
839
  };
840
+ } finally {
841
+ if (env) {
842
+ await rm(env.GIT_INDEX_FILE, { force: true }).catch(() => {});
843
+ await rm(`${env.GIT_INDEX_FILE}.lock`, { force: true }).catch(() => {});
844
+ }
845
+ }
846
+ }
847
+
848
+ /** The original sequence: the shadow index saved as a tree, used, restored. */
849
+ async function applyInShadowIndex(state, tree, entries, files) {
850
+ const saved = clean((await runGit(shadowArgs(state, ['write-tree']), { cwd: state.root })).stdout);
851
+ try {
852
+ return await applyInIndex(state, tree, entries, files, null);
589
853
  } finally {
590
854
  await runGit(shadowArgs(state, ['read-tree', saved]), { cwd: state.root });
591
855
  }
@@ -603,13 +867,26 @@ async function materializeToolBaselines(snapshot) {
603
867
  }
604
868
  );
605
869
  const present = new Set(splitNulList(listed.stdout).map(pathKey));
606
- const ignoredResult = await runGit(['check-ignore', '--no-index', '-z', '--stdin'], {
607
- cwd: state.root,
608
- input: `${paths.join('\0')}\0`,
609
- allowFailure: true,
610
- });
611
- if (ignoredResult.code > 1) throw commandError(['check-ignore'], ignoredResult.stderr, ignoredResult.code);
612
- const ignored = new Set(splitNulList(ignoredResult.stdout).map(pathKey));
870
+ // A leading ':' is pathspec magic to ls-tree and check-ignore: such a path
871
+ // may not have been read literally, so every read below runs as before.
872
+ const literal = paths.every((path) => !path.startsWith(':'));
873
+ // The ignore answer is only consulted for bytes kept for a path that is
874
+ // neither in the baseline tree nor tracked, and small enough to keep.
875
+ const asksIgnored = ([path, content]) =>
876
+ Buffer.isBuffer(content) &&
877
+ !present.has(pathKey(path)) &&
878
+ !state.sourceTracked.has(pathKey(path)) &&
879
+ content.length <= MAX_UNTRACKED_FILE_BYTES;
880
+ let ignored = new Set();
881
+ if (!literal || pending.some(asksIgnored)) {
882
+ const ignoredResult = await runGit(['check-ignore', '--no-index', '-z', '--stdin'], {
883
+ cwd: state.root,
884
+ input: `${paths.join('\0')}\0`,
885
+ allowFailure: true,
886
+ });
887
+ if (ignoredResult.code > 1) throw commandError(['check-ignore'], ignoredResult.stderr, ignoredResult.code);
888
+ ignored = new Set(splitNulList(ignoredResult.stdout).map(pathKey));
889
+ }
613
890
  const missing = pending
614
891
  .filter(
615
892
  ([path, content]) =>
@@ -624,7 +901,9 @@ async function materializeToolBaselines(snapshot) {
624
901
  .map(([path, content]) =>
625
902
  isOmittedBaseline(content) ? { path, omitted: true, size: content.size } : { path, content }
626
903
  );
627
- const applied = await applyBaselineFilesUnlocked(state, snapshot.baselineTree, missing);
904
+ // A path ls-tree read literally and did not list is not in the tree.
905
+ const absent = literal ? new Set(paths.map(pathKey).filter((key) => !present.has(key))) : null;
906
+ const applied = await applyBaselineFilesUnlocked(state, snapshot.baselineTree, missing, { absent });
628
907
  snapshot.baselineTree = applied.tree;
629
908
  for (const entry of applied.files) snapshot.baselineFiles.set(pathKey(entry.path), entry);
630
909
  for (const [path] of pending) snapshot.pendingBaselines.delete(path);
@@ -710,14 +989,68 @@ async function patchSectionsByPath(state, baselineTree, currentTree, pathspec, m
710
989
  if (error?.code === 'EMAXBUFFER') return null;
711
990
  throw error;
712
991
  }
992
+ return sectionsByPath(result.stdout);
993
+ }
994
+
995
+ function sectionsByPath(patchText) {
713
996
  const sections = new Map();
714
- for (const section of splitPatchSections(Buffer.from(result.stdout, 'utf8'))) {
997
+ for (const section of splitPatchSections(Buffer.from(patchText, 'utf8'))) {
715
998
  const path = section.newPath ?? section.oldPath;
716
999
  if (path) sections.set(pathKey(path), section.patch);
717
1000
  }
718
1001
  return sections;
719
1002
  }
720
1003
 
1004
+ /** A range's name-status, numstat and whole patch from one `git diff`
1005
+ * (`--raw --numstat --patch -z`: raw records, numstat records, a NUL, then
1006
+ * the same patch bytes a patch-only read prints). Null when that read fails
1007
+ * or passes the patch read's byte cap, or its output is not that shape: the
1008
+ * caller then takes the separate reads, which fail or bound exactly as
1009
+ * before. */
1010
+ async function combinedTreeDiff(state, rangeArgs) {
1011
+ let result;
1012
+ try {
1013
+ result = await runGit(
1014
+ shadowArgs(state, ['diff', '--raw', '--numstat', '--patch', '--no-ext-diff', '--unified=3', '-z', ...rangeArgs]),
1015
+ { cwd: state.root, maxBytes: COMMAND_MAX_BYTES + PATCH_OUTPUT_SLACK_BYTES, allowFailure: true }
1016
+ );
1017
+ } catch (error) {
1018
+ if (error?.code === 'EMAXBUFFER') return null;
1019
+ throw error;
1020
+ }
1021
+ if (result.code !== 0) return null;
1022
+ const text = String(result.stdout || '');
1023
+ if (!text) return { statuses: new Map(), stats: new Map(), sections: new Map() };
1024
+ // Raw records (each starts with ':') re-shaped as name-status tokens.
1025
+ const nameStatus = [];
1026
+ let cursor = 0;
1027
+ const token = () => {
1028
+ const end = text.indexOf('\0', cursor);
1029
+ if (end < 0) return null;
1030
+ const value = text.slice(cursor, end);
1031
+ cursor = end + 1;
1032
+ return value;
1033
+ };
1034
+ while (text[cursor] === ':') {
1035
+ const header = token();
1036
+ const status = header?.slice(header.lastIndexOf(' ') + 1);
1037
+ if (!status) return null;
1038
+ const paths = [token()];
1039
+ if (status[0] === 'R' || status[0] === 'C') paths.push(token());
1040
+ if (paths.some((path) => !path)) return null;
1041
+ nameStatus.push(status, ...paths);
1042
+ }
1043
+ // Numstat records never hold an empty token after a NUL, so the first NUL
1044
+ // pair ends them; the separator NUL follows.
1045
+ const numstatEnd = text[cursor] === '\0' ? cursor : text.indexOf('\0\0', cursor) + 1;
1046
+ if (numstatEnd <= 0) return null;
1047
+ return {
1048
+ statuses: parseNameStatus(`${nameStatus.join('\0')}\0`),
1049
+ stats: parseNumstat(text.slice(cursor, numstatEnd)),
1050
+ sections: sectionsByPath(text.slice(numstatEnd + 1)),
1051
+ };
1052
+ }
1053
+
721
1054
  /** After the whole range overflowed: patches read in path batches, the
722
1055
  * smallest changes first, until the reply's total is spent. A batch that
723
1056
  * overflows is halved; a single file that does is too large. */
@@ -761,6 +1094,12 @@ async function boundedTreePatch(state, baselineTree, currentTree, pathspec, file
761
1094
  sections = new Map();
762
1095
  await batchedPatchSections(state, baselineTree, currentTree, files, sections);
763
1096
  }
1097
+ return boundedTreePatchFromSections(files, sections, whole);
1098
+ }
1099
+
1100
+ /** `files` with the patch `sections` that fit the reply caps; `whole`: the
1101
+ * sections are a complete read, so a file without one has no patch. */
1102
+ function boundedTreePatchFromSections(files, sections, whole) {
764
1103
  const budget = createReviewPatchBudget();
765
1104
  const kept = [];
766
1105
  const bounded = files.map((file) => {
@@ -783,12 +1122,35 @@ async function diffTreesUnlocked(state, baselineTree, currentTree, paths = null)
783
1122
  // baseline describes the whole worktree, concurrent sessions included.
784
1123
  const pathspec = Array.isArray(paths) && paths.length > 0 ? paths : ['.'];
785
1124
  const rangeArgs = ['--find-renames', baselineTree, currentTree, '--', ...pathspec];
1125
+ const combined = await combinedTreeDiff(state, rangeArgs);
1126
+ if (combined) {
1127
+ const files = reviewFiles(combined.statuses, combined.stats);
1128
+ const bounded = boundedTreePatchFromSections(files, combined.sections, true);
1129
+ return {
1130
+ patch: bounded.patch,
1131
+ files: bounded.files,
1132
+ patchTruncated: false,
1133
+ diffTooLarge: reviewDiffTooLarge(bounded.files, bounded.patch),
1134
+ currentTree,
1135
+ };
1136
+ }
786
1137
  const [nameStatus, numstat] = await Promise.all([
787
1138
  runGit(shadowArgs(state, ['diff', '--name-status', '-z', ...rangeArgs]), { cwd: state.root }),
788
1139
  runGit(shadowArgs(state, ['diff', '--numstat', '-z', ...rangeArgs]), { cwd: state.root }),
789
1140
  ]);
790
- const statuses = parseNameStatus(nameStatus.stdout);
791
- const stats = parseNumstat(numstat.stdout);
1141
+ const files = reviewFiles(parseNameStatus(nameStatus.stdout), parseNumstat(numstat.stdout));
1142
+ const bounded = await boundedTreePatch(state, baselineTree, currentTree, pathspec, files);
1143
+ return {
1144
+ patch: bounded.patch,
1145
+ files: bounded.files,
1146
+ patchTruncated: false,
1147
+ diffTooLarge: reviewDiffTooLarge(bounded.files, bounded.patch),
1148
+ currentTree,
1149
+ };
1150
+ }
1151
+
1152
+ /** Review rows from the name-status and numstat reads of one range. */
1153
+ function reviewFiles(statuses, stats) {
792
1154
  const keys = [...new Set([...statuses.keys(), ...stats.keys()])];
793
1155
  const files = keys
794
1156
  .map((key) => {
@@ -804,14 +1166,7 @@ async function diffTreesUnlocked(state, baselineTree, currentTree, paths = null)
804
1166
  };
805
1167
  })
806
1168
  .sort((left, right) => left.path.localeCompare(right.path));
807
- const bounded = await boundedTreePatch(state, baselineTree, currentTree, pathspec, files);
808
- return {
809
- patch: bounded.patch,
810
- files: bounded.files,
811
- patchTruncated: false,
812
- diffTooLarge: reviewDiffTooLarge(bounded.files, bounded.patch),
813
- currentTree,
814
- };
1169
+ return files;
815
1170
  }
816
1171
 
817
1172
  /** One file's patch between two trees (a rename read with its old path), up
@@ -67,8 +67,15 @@ export function createWorkerRequestClient(url, { idleExitMs = 0, onEvent = null,
67
67
  created.unref();
68
68
  if (worker === created) armIdleTimer(created);
69
69
  }
70
- if (error) entry.reject(Object.assign(new Error(error.message), { code: error.code }));
71
- else entry.resolve(result);
70
+ if (error) {
71
+ entry.reject(
72
+ Object.assign(
73
+ new Error(error.message),
74
+ { code: error.code },
75
+ typeof error.childExited === 'boolean' ? { childExited: error.childExited, pid: error.pid } : {}
76
+ )
77
+ );
78
+ } else entry.resolve(result);
72
79
  });
73
80
  created.on('error', (error) => {
74
81
  if (worker === created) {
@@ -132,7 +139,14 @@ export function serveWorkerRequests(handler) {
132
139
  (error) =>
133
140
  parentPort.postMessage({
134
141
  id,
135
- error: { message: String(error?.message || error), code: error?.code ?? null },
142
+ error: {
143
+ message: String(error?.message || error),
144
+ code: error?.code ?? null,
145
+ // A timed-out child's fate (run-child.mjs waitForExitMs).
146
+ ...(typeof error?.childExited === 'boolean'
147
+ ? { childExited: error.childExited, pid: error.pid ?? null }
148
+ : {}),
149
+ },
136
150
  })
137
151
  );
138
152
  });