mixdog 1.2.5 → 1.3.0

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/LICENSES/simple-icons-CC0-1.0.txt +30 -0
  2. package/NOTICE.md +19 -0
  3. package/package.json +4 -1
  4. package/scripts/check-model-recommendations.mjs +89 -0
  5. package/scripts/gate-local.mjs +7 -0
  6. package/scripts/lib/gate-scheduler.mjs +2 -2
  7. package/scripts/lib/isolated-test-env.mjs +16 -0
  8. package/scripts/lib/run-node-tests.mjs +5 -14
  9. package/scripts/provider-pingpong-live.mjs +9 -9
  10. package/src/agents/advisor/AGENT.md +4 -4
  11. package/src/agents/advisor/agent.json +1 -1
  12. package/src/agents/reviewer/AGENT.md +5 -4
  13. package/src/agents/reviewer/agent.json +1 -1
  14. package/src/defaults/shipped-history.json +17 -0
  15. package/src/defaults/skills/browser-use/SKILL.md +7 -1
  16. package/src/defaults/skills/computer-use/SKILL.md +3 -1
  17. package/src/defaults/skills/memory-management/SKILL.md +4 -1
  18. package/src/defaults/skills/setup/references/actions.md +11 -4
  19. package/src/defaults/skills/setup-guide/SKILL.md +175 -0
  20. package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
  21. package/src/defaults/skills/visualize/SKILL.md +3 -2
  22. package/src/lib/rules-builder.cjs +56 -7
  23. package/src/output-styles/common.md +22 -6
  24. package/src/output-styles/detailed.md +7 -5
  25. package/src/output-styles/minimal.md +7 -3
  26. package/src/output-styles/simple.md +2 -3
  27. package/src/rules/agent/AGENT.md +7 -1
  28. package/src/rules/agent-mode/AGENT_MODE.md +24 -0
  29. package/src/rules/agent-mode/MIXY.md +21 -0
  30. package/src/rules/agent-mode/ROUTINE.md +6 -0
  31. package/src/rules/lead/LEAD.md +9 -4
  32. package/src/rules/shared/10-tool-workflow.md +2 -1
  33. package/src/rules/shared/60-verification.md +4 -5
  34. package/src/rules/shared/70-delivery.md +3 -0
  35. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
  36. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
  37. package/src/runtime/agent/orchestrator/config.mjs +6 -0
  38. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
  39. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
  40. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +5 -3
  41. package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
  42. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
  43. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +58 -64
  44. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
  45. package/src/runtime/agent/orchestrator/mcp/client.mjs +122 -15
  46. package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
  47. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
  48. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
  49. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
  50. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
  51. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
  52. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
  53. package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
  54. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +41 -19
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
  58. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
  59. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
  62. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +11 -5
  64. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
  65. package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
  66. package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
  69. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
  70. package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
  71. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
  72. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
  80. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  81. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
  82. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  83. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
  84. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
  86. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
  88. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
  92. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
  94. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
  95. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
  96. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
  97. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
  98. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
  99. package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
  100. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +98 -4
  101. package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
  102. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
  103. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +15 -8
  104. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
  109. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
  110. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
  111. package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
  112. package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
  113. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
  114. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
  115. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
  116. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
  117. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
  118. package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
  119. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
  120. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
  121. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
  122. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
  123. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
  124. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
  125. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
  126. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
  127. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
  128. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
  129. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
  130. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
  131. package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
  132. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
  133. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
  134. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
  135. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
  136. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +82 -33
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +11 -4
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
  140. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +6 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
  146. package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
  147. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
  148. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
  149. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
  150. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
  151. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
  152. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
  153. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
  154. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
  155. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
  156. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
  157. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
  158. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
  159. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
  161. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
  163. package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
  166. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
  167. package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
  168. package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
  169. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
  171. package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
  173. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
  174. package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
  175. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
  176. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +325 -0
  177. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +84 -21
  178. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
  179. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
  180. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
  181. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
  182. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
  183. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
  184. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
  185. package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
  186. package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
  189. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
  190. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
  191. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
  197. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
  198. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
  199. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
  200. package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
  201. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
  203. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
  207. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
  208. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
  209. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
  210. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
  211. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
  212. package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
  213. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
  214. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
  215. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
  216. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
  217. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
  218. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
  219. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
  220. package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
  221. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +123 -32
  222. package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
  224. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
  225. package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
  226. package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
  227. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
  228. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
  229. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
  230. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  231. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
  232. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +64 -2
  233. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +10 -2
  234. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
  235. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +8 -0
  236. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -1
  237. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
  238. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +104 -55
  239. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
  240. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
  241. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
  242. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  243. package/src/runtime/attachments/office-extract.mjs +11 -9
  244. package/src/runtime/browser-bridge/client.mjs +24 -0
  245. package/src/runtime/channels/lib/scheduler.mjs +40 -12
  246. package/src/runtime/channels/lib/schedules-db.mjs +71 -12
  247. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
  248. package/src/runtime/channels/lib/webhook.mjs +0 -1
  249. package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
  250. package/src/runtime/channels/lib/worker-main.mjs +17 -20
  251. package/src/runtime/computer-bridge/client.mjs +28 -1
  252. package/src/runtime/connectors/gmail-app-password.mjs +690 -0
  253. package/src/runtime/connectors/google-mcp.mjs +446 -0
  254. package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
  255. package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
  256. package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
  257. package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
  258. package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
  259. package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
  260. package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
  261. package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
  262. package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
  263. package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
  264. package/src/runtime/memory/lib/memory.mjs +7 -1
  265. package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
  266. package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
  267. package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
  268. package/src/runtime/memory/lib/tool-call-handler.mjs +9 -5
  269. package/src/runtime/memory/tool-defs.mjs +5 -0
  270. package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
  271. package/src/runtime/office/core/tabular.mjs +1 -1
  272. package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
  273. package/src/runtime/office/portable/docx-formatting.mjs +1 -1
  274. package/src/runtime/office/portable/docx-runs.mjs +1 -1
  275. package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
  276. package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
  277. package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
  278. package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
  279. package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
  280. package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
  281. package/src/runtime/office/portable/portable-opc.mjs +27 -13
  282. package/src/runtime/office/portable/portable-pivot.mjs +3 -3
  283. package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
  284. package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
  285. package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
  286. package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
  287. package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
  288. package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
  289. package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
  290. package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
  291. package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
  292. package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
  293. package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
  294. package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
  295. package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
  296. package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
  297. package/src/runtime/office/portable/portable-xml.mjs +1 -1
  298. package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
  299. package/src/runtime/shared/agent-avatar.d.mts +64 -0
  300. package/src/runtime/shared/agent-avatar.mjs +320 -0
  301. package/src/runtime/shared/agent-route-config.d.mts +3 -0
  302. package/src/runtime/shared/agent-route-config.mjs +16 -0
  303. package/src/runtime/shared/atomic-file.mjs +36 -14
  304. package/src/runtime/shared/background-tasks.mjs +60 -20
  305. package/src/runtime/shared/child-spawn-gate.mjs +26 -16
  306. package/src/runtime/shared/config.mjs +8 -11
  307. package/src/runtime/shared/connector-accounts.mjs +15 -0
  308. package/src/runtime/shared/connector-catalog.d.mts +52 -0
  309. package/src/runtime/shared/connector-catalog.mjs +230 -0
  310. package/src/runtime/shared/connector-triggers.d.mts +3 -0
  311. package/src/runtime/shared/connector-triggers.mjs +43 -0
  312. package/src/runtime/shared/file-lock.mjs +7 -1
  313. package/src/runtime/shared/file-permissions-worker.mjs +38 -0
  314. package/src/runtime/shared/file-permissions.d.mts +19 -4
  315. package/src/runtime/shared/file-permissions.mjs +310 -4
  316. package/src/runtime/shared/git-runner-worker.mjs +6 -78
  317. package/src/runtime/shared/google-oauth-client.mjs +24 -0
  318. package/src/runtime/shared/held-request-host.d.mts +12 -0
  319. package/src/runtime/shared/held-request-host.mjs +71 -0
  320. package/src/runtime/shared/llm/http-agent.mjs +7 -3
  321. package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
  322. package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
  323. package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
  324. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
  325. package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
  326. package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
  327. package/src/runtime/shared/memory-snapshot.mjs +5 -1
  328. package/src/runtime/shared/notify-trace.mjs +8 -1
  329. package/src/runtime/shared/plain-preview.d.mts +1 -0
  330. package/src/runtime/shared/plain-preview.mjs +28 -0
  331. package/src/runtime/shared/pristine-execution-contract.json +5 -1
  332. package/src/runtime/shared/process-runner-worker.mjs +7 -0
  333. package/src/runtime/shared/process-runner.mjs +38 -0
  334. package/src/runtime/shared/provider-accounts.mjs +2 -1
  335. package/src/runtime/shared/provider-api-key.mjs +0 -1
  336. package/src/runtime/shared/read-row-numbers.mjs +1 -1
  337. package/src/runtime/shared/resource-admission.mjs +60 -18
  338. package/src/runtime/shared/routine-limits.d.mts +11 -0
  339. package/src/runtime/shared/routine-limits.mjs +21 -0
  340. package/src/runtime/shared/routine-trigger.d.mts +10 -0
  341. package/src/runtime/shared/routine-trigger.mjs +44 -0
  342. package/src/runtime/shared/run-child.mjs +84 -0
  343. package/src/runtime/shared/schedule-model-ref.mjs +9 -10
  344. package/src/runtime/shared/session-activity-signal.mjs +23 -0
  345. package/src/runtime/shared/shell-output-summary.mjs +23 -0
  346. package/src/runtime/shared/singleton-owner.mjs +126 -42
  347. package/src/runtime/shared/slow-span.mjs +4 -12
  348. package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
  349. package/src/runtime/shared/tool-output-limit.mjs +4 -2
  350. package/src/runtime/shared/tool-output-marker.mjs +58 -0
  351. package/src/runtime/shared/transcript-metadata.mjs +10 -0
  352. package/src/runtime/shared/turn-changes.mjs +0 -8
  353. package/src/runtime/shared/usage-readout-totals.mjs +56 -0
  354. package/src/runtime/shared/user-data-guard.mjs +131 -34
  355. package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
  356. package/src/runtime/shared/worktrees/git-head.mjs +20 -2
  357. package/src/runtime/shared/worktrees/lock.mjs +3 -2
  358. package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
  359. package/src/runtime/tidy/runners/biome.mjs +3 -1
  360. package/src/runtime/tidy/shadow.mjs +2 -1
  361. package/src/runtime/web-search/index.mjs +5 -7
  362. package/src/runtime/web-search/lib/formatter.mjs +42 -6
  363. package/src/runtime/web-search/tool-defs.mjs +6 -1
  364. package/src/session-runtime/agent-home-delivery.mjs +459 -0
  365. package/src/session-runtime/agent-profile-changes.mjs +21 -0
  366. package/src/session-runtime/agent-room-delivery.mjs +92 -0
  367. package/src/session-runtime/agent-task-sessions.mjs +200 -0
  368. package/src/session-runtime/boot/apis.mjs +50 -18
  369. package/src/session-runtime/boot/facade.mjs +5 -8
  370. package/src/session-runtime/boot/infrastructure.mjs +28 -17
  371. package/src/session-runtime/boot/tools.mjs +3 -0
  372. package/src/session-runtime/channel-config-api.mjs +53 -5
  373. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
  374. package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
  375. package/src/session-runtime/held-requests.mjs +228 -0
  376. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
  377. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
  378. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
  379. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
  380. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  381. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
  382. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
  383. package/src/session-runtime/lifecycle/session-switch/resume.mjs +11 -4
  384. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
  385. package/src/session-runtime/lifecycle/shared.mjs +25 -2
  386. package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
  387. package/src/session-runtime/lifecycle/teardown.mjs +5 -2
  388. package/src/session-runtime/lifecycle-api.mjs +3 -1
  389. package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
  390. package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
  391. package/src/session-runtime/mcp-oauth-login.mjs +112 -15
  392. package/src/session-runtime/model-route/set-route.mjs +14 -3
  393. package/src/session-runtime/owned-automation-run.mjs +229 -0
  394. package/src/session-runtime/provider-auth/login.mjs +10 -6
  395. package/src/session-runtime/provider-auth/setup.mjs +19 -2
  396. package/src/session-runtime/provider-catalog-cache.mjs +101 -25
  397. package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
  398. package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
  399. package/src/session-runtime/provider-models.mjs +76 -10
  400. package/src/session-runtime/provider-readiness.mjs +4 -0
  401. package/src/session-runtime/resource-api.mjs +5 -0
  402. package/src/session-runtime/resource-mcp-api.mjs +107 -13
  403. package/src/session-runtime/resource-skills-api.mjs +12 -0
  404. package/src/session-runtime/room-member-gate.mjs +48 -0
  405. package/src/session-runtime/routine-home-turn.mjs +156 -0
  406. package/src/session-runtime/routine-owner.mjs +48 -0
  407. package/src/session-runtime/schedule-session-run.mjs +30 -64
  408. package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
  409. package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
  410. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
  411. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
  412. package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
  413. package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
  414. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
  415. package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
  416. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
  417. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
  418. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
  419. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
  420. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
  421. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
  422. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
  423. package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
  424. package/src/session-runtime/services/agent-tool.mjs +20 -0
  425. package/src/session-runtime/services/channel-admin.mjs +93 -24
  426. package/src/session-runtime/services/memory-access.mjs +37 -0
  427. package/src/session-runtime/services/provider-admin.mjs +166 -59
  428. package/src/session-runtime/services/schedule-access.mjs +91 -0
  429. package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
  430. package/src/session-runtime/services/usage-dashboard.mjs +27 -69
  431. package/src/session-runtime/session-create/session-options.mjs +34 -7
  432. package/src/session-runtime/session-hooks.mjs +16 -8
  433. package/src/session-runtime/setup-tool/executor.mjs +68 -6
  434. package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
  435. package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
  436. package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
  437. package/src/session-runtime/skills-api.mjs +16 -1
  438. package/src/session-runtime/tool-policy-refresh.mjs +238 -29
  439. package/src/session-runtime/turn/session-ops.mjs +10 -3
  440. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +11 -2
  441. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
  442. package/src/session-runtime/usage-stats-api.mjs +6 -1
  443. package/src/session-runtime/webhook-session-run.mjs +49 -67
  444. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
  445. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
  446. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
  447. package/src/session-runtime/workflow-agents-api.mjs +4 -1
  448. package/src/standalone/channel-transport/http-routes.mjs +10 -9
  449. package/src/standalone/daemon-agent-control.mjs +1 -8
  450. package/src/standalone/daemon-desktop-runtime.mjs +20 -7
  451. package/src/standalone/daemon-owner.mjs +117 -25
  452. package/src/standalone/daemon-session-control.mjs +11 -2
  453. package/src/standalone/daemon.mjs +61 -17
  454. package/src/standalone/session-call-cache.mjs +6 -0
  455. package/src/standalone/session-protocol.mjs +28 -1
  456. package/src/standalone/session-service/retention/busy.mjs +7 -2
  457. package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
  458. package/src/standalone/session-service.mjs +19 -0
  459. package/src/standalone/session-transport/routes.mjs +7 -6
  460. package/src/tui/app/model-options.mjs +39 -2
  461. package/src/tui/app/model-picker.mjs +16 -2
  462. package/src/tui/app/provider-setup-picker.mjs +1 -2
  463. package/src/tui/app/slash-commands.mjs +20 -0
  464. package/src/tui/dist/index.mjs +487 -128
  465. package/src/tui/session/context-state.mjs +6 -1
  466. package/src/tui/session/notice-surface.mjs +35 -4
  467. package/src/tui/session/notice-text.mjs +0 -1
  468. package/src/tui/session/queue-helpers.mjs +2 -1
  469. package/src/tui/session/session-api/extensions.mjs +4 -0
  470. package/src/tui/session/session-api/intake/submission.mjs +12 -13
  471. package/src/tui/session/session-api/integrations.mjs +9 -5
  472. package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
  473. package/src/tui/session/session-api/lifecycle.mjs +17 -1
  474. package/src/tui/session/session-api/routes.mjs +48 -3
  475. package/src/tui/session/session-flow/drain.mjs +20 -3
  476. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
  477. package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
  478. package/src/tui/session/session-flow/steering.mjs +104 -24
  479. package/src/tui/session/session-flow.mjs +2 -0
  480. package/src/tui/session/tool-approval.mjs +26 -5
  481. package/src/tui/session/transcript-intake.mjs +6 -2
  482. package/src/tui/session/transcript-spill.mjs +5 -1
  483. package/src/tui/session/tui-steering-persist.mjs +65 -42
  484. package/src/tui/session/turn-live-call.mjs +56 -0
  485. package/src/tui/session/turn-stream.mjs +33 -0
  486. package/src/tui/session/turn.mjs +50 -7
  487. package/src/ui/statusline.mjs +1 -6
  488. package/src/ui/streaming-markdown-heal.mjs +24 -7
  489. package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
  490. package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
  491. package/src/workflows/default/WORKFLOW.md +9 -13
  492. package/src/session-runtime/automation-agents.mjs +0 -94
  493. package/src/session-runtime/automation-workflow.mjs +0 -59
@@ -108,6 +108,11 @@ function gitActionOf(operation, args) {
108
108
  return first || DEFAULT_GIT_ACTIONS.get(operation) || 'list';
109
109
  }
110
110
 
111
+ const GIT_BRANCH_WRITE_FLAGS =
112
+ /^(?:-[dDmMcCfu]|--(?:delete|move|copy|force|set-upstream-to(?:=.*)?|unset-upstream|edit-description|track|no-track|create-reflog))$/;
113
+ const GIT_TAG_WRITE_FLAGS =
114
+ /^(?:-[adfsumFe]|--(?:annotate|delete|force|sign|local-user(?:=.*)?|message(?:=.*)?|file(?:=.*)?|edit))$/;
115
+
111
116
  const GIT_CONFIG_MUTATION_FLAGS = new Set([
112
117
  '--add',
113
118
  '--edit',
@@ -140,9 +145,13 @@ export function gitPlanIsReadOnly(plan) {
140
145
  }
141
146
  if (operation === 'hash-object') return !args.includes('-w') && !args.includes('--stdin-paths');
142
147
  if (operation === 'branch' || operation === 'tag') {
143
- return (
144
- args.length === 0 || args.some((value) => ['--list', '-l', '-a', '--all', '-r', '--remotes'].includes(value))
145
- );
148
+ // A listing flag does not make the call read-only when another flag writes:
149
+ // `branch -a -D x` deletes and `tag -a v1` creates (there `-a` is
150
+ // --annotate, not --all).
151
+ const writes = operation === 'tag' ? GIT_TAG_WRITE_FLAGS : GIT_BRANCH_WRITE_FLAGS;
152
+ if (args.some((value) => writes.test(value))) return false;
153
+ const listFlags = operation === 'tag' ? ['--list', '-l'] : ['--list', '-l', '-a', '--all', '-r', '--remotes'];
154
+ return args.length === 0 || args.some((value) => listFlags.includes(value));
146
155
  }
147
156
  if (operation === 'config') {
148
157
  if (args.some((value) => GIT_CONFIG_MUTATION_FLAGS.has(value))) return false;
@@ -6,8 +6,11 @@ import { tokenizeDirectArgv } from './shell-direct-exe.mjs';
6
6
  import { GIT_DIFF_EXIT_SIGNAL_FLAGS } from './bash-tool/benign-exit.mjs';
7
7
  import { withBuiltinPathLocks } from './path-locks.mjs';
8
8
  import { withAdvisoryLocks } from './advisory-lock.mjs';
9
- import { gitRepoLockKey, withGitRepoReadLock, withGitRepoWriteLock } from './git-repo-rw-lock.mjs';
9
+ import { gitRepoLockKey, withGitWorktreeWriteLock } from './git-repo-rw-lock.mjs';
10
10
  import { invalidateBuiltinResultCache } from './cache-layers.mjs';
11
+ import { runAbortable } from '../../../../shared/abort-race.mjs';
12
+ import { sleep } from '../../../../shared/sleep.mjs';
13
+ import { capMarker } from '../../../../shared/tool-output-marker.mjs';
11
14
  import { drainCodeGraphCache } from '../code-graph-state.mjs';
12
15
  import { ensureNativeSpawnServer, tryNativeSpawn } from '../lib/native-spawn-client.mjs';
13
16
  import {
@@ -26,7 +29,14 @@ import {
26
29
 
27
30
  const DEFAULT_TIMEOUT_MS = 120_000;
28
31
  const MAX_CAPTURE_BYTES = 128 * 1024 * 1024;
29
- const GIT_OUTPUT_LIMIT_MAX = 200;
32
+ // Sized from 3 days of real calls (2.9k diff/show/log/status results): diff and
33
+ // show p50 ~125 lines / 6K chars, p90 ~460-510 lines / 21-23K chars, p95 ~700
34
+ // lines / 30-36K chars. 500 lines / 40K chars fits ~91% of them (was ~65% at
35
+ // 50 lines / 12K) and 1000 covers the p97 tail; 1981 of 2010 calls that set
36
+ // output_limit asked for the old max of 200.
37
+ const GIT_OUTPUT_LIMIT_MAX = 1000;
38
+ const GIT_OUTPUT_LINES_DEFAULT = 500;
39
+ const GIT_LOG_LINES_DEFAULT = 100;
30
40
  // Matches the other batch tools' 10-entry fan-out; a 6-command survey used to
31
41
  // be refused outright, costing the model a round trip.
32
42
  const GIT_COMMAND_ARRAY_LIMIT = 10;
@@ -95,7 +105,8 @@ export const GIT_TOOL_DEF = {
95
105
  type: 'integer',
96
106
  minimum: 1,
97
107
  maximum: GIT_OUTPUT_LIMIT_MAX,
98
- description: 'Body line cap; staging IDs are not capped. Default 50; git log defaults to 10.',
108
+ description:
109
+ 'Body line cap, max 1000; staging IDs are not capped. Default 500; git log defaults to 100. A cut ends with [output capped …] naming how to continue.',
99
110
  },
100
111
  include_stage_ids: {
101
112
  type: 'boolean',
@@ -145,10 +156,10 @@ function outputLines(value) {
145
156
  // A line cap alone lets a few very long lines (minified files, lockfiles)
146
157
  // through, so each command also gets a character budget, and a command array
147
158
  // shares one. A cut always states what was omitted and how to page.
148
- const COMMAND_CHAR_BUDGET = 12_000;
149
- const ARRAY_CHAR_BUDGET = 24_000;
159
+ const COMMAND_CHAR_BUDGET = 40_000;
160
+ const ARRAY_CHAR_BUDGET = 60_000;
150
161
  const MIN_COMMAND_CHARS = 1_000;
151
- const LARGE_DIFF_LINES = 200;
162
+ const LARGE_DIFF_LINES = GIT_OUTPUT_LINES_DEFAULT;
152
163
  const LARGE_DIFF_HINT =
153
164
  'hint: large diff - run with --stat first for per-file sizes, add -U1 for less context, and page by file with -- <path>';
154
165
 
@@ -185,7 +196,11 @@ function capOutput(text, cap) {
185
196
  text: lineCut
186
197
  ? appendText(
187
198
  kept,
188
- `... [${lines.length - cap.lines} more lines omitted; raise output_limit or narrow the command]`
199
+ capMarker({
200
+ limit: `${cap.lines} lines`,
201
+ shown: `${lines.length - cap.lines} more lines omitted`,
202
+ narrow: `raise output_limit (max ${GIT_OUTPUT_LIMIT_MAX}) or narrow the command (-- <path>, -n/--skip)`,
203
+ })
189
204
  )
190
205
  : text,
191
206
  truncated: lineCut,
@@ -198,7 +213,11 @@ function capOutput(text, cap) {
198
213
  return {
199
214
  text: appendText(
200
215
  kept.slice(0, cut),
201
- `... [${lines.length - shown} more lines (${text.length - cut} chars) omitted; output limited to ${cap.chars} chars - narrow the command (-- <path>, -n/--skip) to page]`
216
+ capMarker({
217
+ limit: `${cap.chars} chars`,
218
+ shown: `${lines.length - shown} more lines (${text.length - cut} chars) omitted`,
219
+ narrow: 'narrow the command (-- <path>, -n/--skip) to page',
220
+ })
202
221
  ),
203
222
  truncated: true,
204
223
  totalLines: lines.length,
@@ -355,7 +374,7 @@ function parseCommand(rawCommand, workDir) {
355
374
  return { command: String(command), cwd, globalArgs, operation, args };
356
375
  }
357
376
 
358
- async function runProcess(program, argv, { cwd, signal, maxBytes = MAX_CAPTURE_BYTES } = {}) {
377
+ async function runProcess(program, argv, { cwd, signal, maxBytes = MAX_CAPTURE_BYTES, optionalLocks = true } = {}) {
359
378
  let child;
360
379
  try {
361
380
  await ensureNativeSpawnServer();
@@ -371,6 +390,12 @@ async function runProcess(program, argv, { cwd, signal, maxBytes = MAX_CAPTURE_B
371
390
  GIT_EDITOR: 'true',
372
391
  GIT_SEQUENCE_EDITOR: 'true',
373
392
  LC_ALL: 'C',
393
+ // Reads run beside writes without a lock (git-repo-rw-lock.mjs).
394
+ // With optional locks off `git status` never takes index.lock to
395
+ // write back a refreshed index, so it cannot fail a concurrent
396
+ // write on that lock. (`git diff` ignores the setting and may still
397
+ // refresh the index briefly; the write retry absorbs that.)
398
+ ...(optionalLocks ? {} : { GIT_OPTIONAL_LOCKS: '0' }),
374
399
  },
375
400
  outputLimit: maxBytes,
376
401
  },
@@ -477,12 +502,48 @@ function gitFailureReason(plan, result) {
477
502
  return `git ${plan.operation} exited ${result.exitCode}`;
478
503
  }
479
504
 
480
- function commandFailure(plan, result, limit = 50) {
505
+ function commandFailure(plan, result, limit = GIT_OUTPUT_LINES_DEFAULT) {
481
506
  return commandResult(plan, result, limit).text;
482
507
  }
483
508
 
484
509
  function runGit(plan, argv, options = {}) {
485
- return runProcess('git', [...plan.globalArgs, ...argv], { cwd: plan.cwd, signal: options.signal });
510
+ return runProcess('git', [...plan.globalArgs, ...argv], {
511
+ cwd: plan.cwd,
512
+ signal: options.signal,
513
+ optionalLocks: !options.readOnly,
514
+ });
515
+ }
516
+
517
+ // Another process (an editor, a terminal, an IDE) holding one of git's lock
518
+ // files makes git refuse a write: index.lock, a ref or packed-refs lock,
519
+ // config.lock. Commands take that lock before changing anything, so a brief
520
+ // retry with backoff turns the collision into a short wait; a command that had
521
+ // already done part of its work reports its own state on the retry.
522
+ const GIT_LOCK_CONTENTION_RE =
523
+ /Unable to create '[^'\n]*\.lock': File exists|could not lock config file [^\n]*: File exists/;
524
+ const GIT_LOCK_RETRY_DELAYS_MS = [100, 200, 400, 800, 1600];
525
+
526
+ async function runGitWrite(plan, argv, { signal } = {}) {
527
+ let retryMs = 0;
528
+ for (let retries = 0; ; retries += 1) {
529
+ const result = Object.assign(await runGit(plan, argv, { signal }), { retries, retryMs });
530
+ const delay = GIT_LOCK_RETRY_DELAYS_MS[retries];
531
+ if (succeeded(result) || delay === undefined || !GIT_LOCK_CONTENTION_RE.test(String(result.stderr))) return result;
532
+ await runAbortable(signal, () => sleep(delay)).catch(() => {});
533
+ if (signal?.aborted) return result;
534
+ retryMs += delay;
535
+ }
536
+ }
537
+
538
+ const LOCK_WAIT_REPORT_MS = 1000;
539
+
540
+ // Waiting is reported once it exceeds a second, so a slow answer is never
541
+ // mistaken for slow git work.
542
+ function lockWaitNote(waitedMs, result = null) {
543
+ const total = waitedMs + (result?.retryMs || 0);
544
+ if (total <= LOCK_WAIT_REPORT_MS) return '';
545
+ const retried = result?.retries ? ` (git lock file busy; retried ${result.retries}x)` : '';
546
+ return `note: waited ${(total / 1000).toFixed(1)}s for concurrent git writes${retried}`;
486
547
  }
487
548
 
488
549
  function prepare(plan) {
@@ -501,7 +562,7 @@ function prepare(plan) {
501
562
  }
502
563
 
503
564
  async function runStageableDiff(plan, argv, repo, signal) {
504
- const result = await runGit(plan, argv, { signal });
565
+ const result = await runGit(plan, argv, { signal, readOnly: true });
505
566
  if (!succeeded(result)) return result;
506
567
  result.stdout = String(result.stdout);
507
568
  result.stderr = String(result.stderr);
@@ -509,7 +570,7 @@ async function runStageableDiff(plan, argv, repo, signal) {
509
570
  const untracked = await runGit(
510
571
  plan,
511
572
  ['ls-files', '--others', '--exclude-standard', '--full-name', '-z', '--', ...paths],
512
- { signal }
573
+ { signal, readOnly: true }
513
574
  );
514
575
  if (!succeeded(untracked)) return untracked;
515
576
  for (const path of String(untracked.stdout).split('\0').filter(Boolean)) {
@@ -528,7 +589,7 @@ async function runStageableDiff(plan, argv, repo, signal) {
528
589
  '/dev/null',
529
590
  path,
530
591
  ],
531
- { signal }
592
+ { signal, readOnly: true }
532
593
  );
533
594
  // --no-index uses exit 1 for a successfully produced patch.
534
595
  if (!succeeded({ ...added, exitCode: added.exitCode === 1 ? 0 : added.exitCode })) return added;
@@ -589,8 +650,8 @@ function rememberRepoRoot(key, hit) {
589
650
 
590
651
  // `lockKey` is the repository's canonical common git dir: the main checkout
591
652
  // and its linked worktrees share one object store and ref namespace, so their
592
- // git calls serialize on one repository lock (managed worktree mutations take
593
- // the same key).
653
+ // writes share one repository lock state, scoped per worktree (managed
654
+ // worktree mutations take the same key for the whole repository).
594
655
  async function resolveRepo(plan, signal) {
595
656
  const key = repoRootCacheKey(plan);
596
657
  const hit = cachedRepoRoot(key, plan);
@@ -619,6 +680,8 @@ async function resolveRepo(plan, signal) {
619
680
  return { root: null, lockKey: null, probe: result };
620
681
  }
621
682
 
683
+ const CONFIG_SUBCOMMANDS = new Set(['get', 'set', 'unset', 'list', 'rename-section', 'remove-section', 'edit']);
684
+
622
685
  function localizeConfigPlan(plan) {
623
686
  if (plan.operation !== 'config') return plan;
624
687
  const external = plan.args.find(
@@ -629,6 +692,11 @@ function localizeConfigPlan(plan) {
629
692
  );
630
693
  if (external) throw new Error(`git config ${external} is outside the local repository scope`);
631
694
  if (plan.args.some((value) => value === '--local' || value === '--worktree')) return plan;
695
+ // `git config get|set|list …` takes its scope option after the subcommand
696
+ // (`--local get k` reads `get` as a key name); the legacy form takes it first.
697
+ if (CONFIG_SUBCOMMANDS.has(plan.args[0])) {
698
+ return { ...plan, args: [plan.args[0], '--local', ...plan.args.slice(1)] };
699
+ }
632
700
  return { ...plan, args: ['--local', ...plan.args] };
633
701
  }
634
702
 
@@ -660,7 +728,7 @@ const CREATION_VALUE_FLAGS = new Set([
660
728
  '--initial-branch',
661
729
  ]);
662
730
 
663
- function optionFreePositionals(args) {
731
+ function optionFreePositionals(args, valueFlags = CREATION_VALUE_FLAGS) {
664
732
  const out = [];
665
733
  for (let index = 0; index < args.length; index++) {
666
734
  const value = args[index];
@@ -668,7 +736,7 @@ function optionFreePositionals(args) {
668
736
  out.push(...args.slice(index + 1));
669
737
  break;
670
738
  }
671
- if (CREATION_VALUE_FLAGS.has(value)) {
739
+ if (valueFlags.has(value)) {
672
740
  index++;
673
741
  continue;
674
742
  }
@@ -690,10 +758,50 @@ function creationTarget(plan) {
690
758
  return resolve(plan.cwd, leaf);
691
759
  }
692
760
 
761
+ // Pruning or repacking deletes unreachable objects, including ones a write in
762
+ // any worktree has just created and not yet referenced (git gc documents
763
+ // --prune=now as unsafe beside a concurrent writer), so these hold the whole
764
+ // repository.
765
+ const REPO_WIDE_OPERATIONS = new Set(['gc', 'maintenance', 'prune', 'prune-packed', 'repack']);
766
+ const WORKTREE_VALUE_FLAGS = new Set(['-b', '-B', '--reason']);
767
+
768
+ // The worktrees a mutating plan touches; null holds the whole repository. A
769
+ // write changes its cwd's worktree, except that `git worktree add/remove/move`
770
+ // change the target worktree (plus the shared admin dir, which git itself
771
+ // guards), so writes on different worktrees never wait for each other.
772
+ function writeScopes(plan, root) {
773
+ if (REPO_WIDE_OPERATIONS.has(plan.operation)) return null;
774
+ if (plan.operation !== 'worktree') return [root];
775
+ const [action, ...paths] = optionFreePositionals(plan.args, WORKTREE_VALUE_FLAGS);
776
+ const target = (path) => resolve(plan.cwd, path);
777
+ // git also names a worktree by a unique path suffix, which no cwd-relative
778
+ // path resolves; an argument that is not a worktree here holds the whole
779
+ // repository instead of guessing (so do prune and an argument-less repair).
780
+ const existing = (path) => (existsSync(join(target(path), '.git')) ? target(path) : null);
781
+ let scopes = null;
782
+ if (action === 'add') scopes = paths.slice(0, 1).map(target);
783
+ else if (action === 'move' && paths.length === 2) scopes = [existing(paths[0]), target(paths[1])];
784
+ else if (['remove', 'lock', 'unlock', 'repair'].includes(action)) scopes = paths.map(existing);
785
+ return scopes?.length && scopes.every(Boolean) ? scopes : null;
786
+ }
787
+
693
788
  // A mutating git call holds the in-process and cross-process locks on its
694
- // path, and drops the result caches it may have invalidated.
695
- function withGitMutationLocks(path, callback) {
696
- return withBuiltinPathLocks([path], () => withAdvisoryLocks([path], callback));
789
+ // paths, and drops the result caches it may have invalidated.
790
+ function withGitMutationLocks(paths, callback) {
791
+ return withBuiltinPathLocks(paths, () => withAdvisoryLocks(paths, callback));
792
+ }
793
+
794
+ // A write holds Mixdog's repository lock on the worktrees it touches (the
795
+ // whole repository when `scopes` is null), then the path and cross-process
796
+ // locks on the same paths; `callback` learns how long acquiring them took.
797
+ function withGitWriteLocks(lockKey, scopes, root, signal, callback) {
798
+ const started = Date.now();
799
+ return withGitWorktreeWriteLock(
800
+ lockKey,
801
+ scopes,
802
+ () => withGitMutationLocks(scopes || [root], () => callback(Date.now() - started)),
803
+ { signal }
804
+ );
697
805
  }
698
806
 
699
807
  function invalidateAfterGitMutation() {
@@ -709,14 +817,6 @@ function abortSignalOf(options) {
709
817
  return options?.signal || options?.abortSignal || null;
710
818
  }
711
819
 
712
- async function executeCreation(plan, target, limit, signal) {
713
- return withGitMutationLocks(target, async () => {
714
- const result = await runGit(plan, [plan.operation, ...plan.args], { signal });
715
- invalidateAfterGitMutation();
716
- return commandResult(plan, result, limit);
717
- });
718
- }
719
-
720
820
  function stageRequest(value) {
721
821
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
722
822
  return { error: 'git stage must be an object' };
@@ -759,46 +859,48 @@ async function executeGitStage(input, workDir, options = {}) {
759
859
  hint: 'Run git diff with include_stage_ids:true in the current Project and use its diff_id/change_ids.',
760
860
  });
761
861
  }
762
- const limit = outputLimit(input?.output_limit, 50);
862
+ const limit = outputLimit(input?.output_limit, GIT_OUTPUT_LINES_DEFAULT);
763
863
  const signal = abortSignalOf(options);
764
864
  const repo = snapshot.repo;
765
865
  const { lockKey } = await resolveRepo({ ...snapshot.plan, cwd: repo }, signal);
766
- return withGitRepoWriteLock(
767
- lockKey || repo,
768
- () =>
769
- withGitMutationLocks(repo, async () => {
770
- const current = await runStageableDiff(snapshot.plan, snapshot.argv, repo, signal);
771
- if (!succeeded(current)) return commandFailure(snapshot.plan, current, limit);
772
- const raw = current.stdout;
773
- if (!diffSnapshotMatches(snapshot, raw)) {
774
- return ok({
775
- staged: false,
776
- reason: 'stale_diff',
777
- hint: 'The working diff changed. Run git diff with include_stage_ids:true again and select current change_ids.',
778
- });
779
- }
780
- const built = buildSelectedStagePatch(raw, request.changeIds);
781
- if (built.missing.length || !built.patch) {
782
- return fail(
783
- `git stage change_ids are not present in the diff: ${built.missing.join(', ') || '(none selected)'}`
784
- );
785
- }
786
- return withStagePatchFile(built.patch, async (patchPath) => {
787
- const applyArgs = ['apply', '--cached', '--unidiff-zero', patchPath];
788
- const applyPlan = { ...snapshot.plan, cwd: repo, operation: 'apply', args: applyArgs.slice(1) };
789
- const check = await runGit(applyPlan, ['apply', '--cached', '--check', '--unidiff-zero', patchPath], {
790
- signal,
791
- });
792
- if (!succeeded(check)) return commandFailure(applyPlan, check, limit);
793
- const applied = await runGit(applyPlan, applyArgs, { signal });
794
- if (!succeeded(applied)) return commandFailure(applyPlan, applied, limit);
795
- deleteDiffSnapshot(request.diffId);
796
- invalidateAfterGitMutation();
797
- return ok({ staged: true, ...stagedSummary(built.changes) });
798
- });
799
- }),
800
- { signal }
801
- );
866
+ // The diff check and the index apply form one transaction on this
867
+ // worktree's index, so the stage holds its worktree for both.
868
+ return withGitWriteLocks(lockKey || repo, [repo], repo, signal, async (waitedMs) => {
869
+ const noted = (text, result) => appendText(text, lockWaitNote(waitedMs, result));
870
+ const answer = (data, result) => {
871
+ const note = lockWaitNote(waitedMs, result);
872
+ return ok(note ? { ...data, note } : data);
873
+ };
874
+ const current = await runStageableDiff(snapshot.plan, snapshot.argv, repo, signal);
875
+ if (!succeeded(current)) return noted(commandFailure(snapshot.plan, current, limit));
876
+ const raw = current.stdout;
877
+ if (!diffSnapshotMatches(snapshot, raw)) {
878
+ return answer({
879
+ staged: false,
880
+ reason: 'stale_diff',
881
+ hint: 'The working diff changed. Run git diff with include_stage_ids:true again and select current change_ids.',
882
+ });
883
+ }
884
+ const built = buildSelectedStagePatch(raw, request.changeIds);
885
+ if (built.missing.length || !built.patch) {
886
+ return noted(
887
+ fail(`git stage change_ids are not present in the diff: ${built.missing.join(', ') || '(none selected)'}`)
888
+ );
889
+ }
890
+ return withStagePatchFile(built.patch, async (patchPath) => {
891
+ const applyArgs = ['apply', '--cached', '--unidiff-zero', patchPath];
892
+ const applyPlan = { ...snapshot.plan, cwd: repo, operation: 'apply', args: applyArgs.slice(1) };
893
+ const check = await runGit(applyPlan, ['apply', '--cached', '--check', '--unidiff-zero', patchPath], {
894
+ signal,
895
+ });
896
+ if (!succeeded(check)) return noted(commandFailure(applyPlan, check, limit));
897
+ const applied = await runGitWrite(applyPlan, applyArgs, { signal });
898
+ if (!succeeded(applied)) return noted(commandFailure(applyPlan, applied, limit), applied);
899
+ deleteDiffSnapshot(request.diffId);
900
+ invalidateAfterGitMutation();
901
+ return answer({ staged: true, ...stagedSummary(built.changes) }, applied);
902
+ });
903
+ });
802
904
  }
803
905
 
804
906
  async function executeSingleGitTool(input, workDir, options = {}) {
@@ -823,7 +925,7 @@ async function executeSingleGitTool(input, workDir, options = {}) {
823
925
  ) {
824
926
  return rejected('git archive requires -o/--output; binary stdout is not returned');
825
927
  }
826
- const limitDefault = plan.operation === 'log' ? 10 : 50;
928
+ const limitDefault = plan.operation === 'log' ? GIT_LOG_LINES_DEFAULT : GIT_OUTPUT_LINES_DEFAULT;
827
929
  const limit = {
828
930
  lines: outputLimit(input.output_limit, limitDefault),
829
931
  chars: options.charBudget ?? COMMAND_CHAR_BUDGET,
@@ -831,7 +933,13 @@ async function executeSingleGitTool(input, workDir, options = {}) {
831
933
  const signal = abortSignalOf(options);
832
934
  if (plan.operation === 'init' || plan.operation === 'clone') {
833
935
  const target = creationTarget(plan);
834
- return withGitRepoWriteLock(target, () => executeCreation(plan, target, limit, signal), { signal });
936
+ return withGitWriteLocks(target, null, target, signal, async (waitedMs) => {
937
+ const result = await runGit(plan, [plan.operation, ...plan.args], { signal });
938
+ invalidateAfterGitMutation();
939
+ const rendered = commandResult(plan, result, limit);
940
+ rendered.text = appendText(rendered.text, lockWaitNote(waitedMs));
941
+ return rendered;
942
+ });
835
943
  }
836
944
  if (REPO_FREE_OPERATIONS.has(plan.operation)) {
837
945
  const result = await runGit(plan, [plan.operation, ...plan.args], { signal });
@@ -849,39 +957,32 @@ async function executeSingleGitTool(input, workDir, options = {}) {
849
957
  const prepared = prepare(plan);
850
958
  const stageableRequest = plan.operation === 'diff' && (plan.args.length === 0 || plan.args[0] === '--');
851
959
  if (stageableRequest) prepared.argv.splice(1, 0, '--no-textconv', '--src-prefix=a/', '--dst-prefix=b/');
960
+ // A read takes no lock, so it never waits behind another read, a long
961
+ // `git log -S`, or a write (git-repo-rw-lock.mjs explains why that is safe).
852
962
  if (isReadOnly(plan)) {
853
- return withGitRepoReadLock(
854
- lockKey,
855
- async () => {
856
- const result = stageableRequest
857
- ? await runStageableDiff(plan, prepared.argv, repo, signal)
858
- : await runGit(plan, prepared.argv, { signal });
859
- if (!succeeded(result)) return commandResult(plan, result, limit);
860
- if (stageableRequest && input.include_stage_ids === true) {
861
- const snapshot = createDiffSnapshot({
862
- repo,
863
- scope: resolve(workDir || process.cwd()),
864
- plan,
865
- argv: prepared.argv,
866
- raw: result.stdout,
867
- });
868
- return stageableDiffResult(plan, result, snapshot, limit);
869
- }
870
- return commandResult(plan, result, limit);
871
- },
872
- { signal }
873
- );
963
+ const result = stageableRequest
964
+ ? await runStageableDiff(plan, prepared.argv, repo, signal)
965
+ : await runGit(plan, prepared.argv, { signal, readOnly: true });
966
+ if (!succeeded(result)) return commandResult(plan, result, limit);
967
+ if (stageableRequest && input.include_stage_ids === true) {
968
+ const snapshot = createDiffSnapshot({
969
+ repo,
970
+ scope: resolve(workDir || process.cwd()),
971
+ plan,
972
+ argv: prepared.argv,
973
+ raw: result.stdout,
974
+ });
975
+ return stageableDiffResult(plan, result, snapshot, limit);
976
+ }
977
+ return commandResult(plan, result, limit);
874
978
  }
875
- return withGitRepoWriteLock(
876
- lockKey,
877
- () =>
878
- withGitMutationLocks(repo, async () => {
879
- const result = await runGit(plan, prepared.argv, { signal });
880
- invalidateAfterGitMutation();
881
- return commandResult(plan, result, limit);
882
- }),
883
- { signal }
884
- );
979
+ return withGitWriteLocks(lockKey, writeScopes(plan, repo), repo, signal, async (waitedMs) => {
980
+ const result = await runGitWrite(plan, prepared.argv, { signal });
981
+ invalidateAfterGitMutation();
982
+ const rendered = commandResult(plan, result, limit);
983
+ rendered.text = appendText(rendered.text, lockWaitNote(waitedMs, result));
984
+ return rendered;
985
+ });
885
986
  }
886
987
 
887
988
  // `git a && git b` written as one string means exactly what the command array
@@ -996,8 +1097,8 @@ export async function executeGitTool(rawInput, workDir, options = {}) {
996
1097
  // Ordered execution with fail-fast: a mutation sequence (`reflog expire`
997
1098
  // then `gc`) must not run its later steps on a state the earlier step did
998
1099
  // not produce. Every command is parsed above before any runs, so a typo in
999
- // command 3 never leaves commands 1-2 half applied. Each command still
1000
- // acquires its own repository lock inside executeSingleGitTool.
1100
+ // command 3 never leaves commands 1-2 half applied. Each write still
1101
+ // acquires its own worktree lock inside executeSingleGitTool.
1001
1102
  // Headers name the position and subcommand only: echoing the argument list
1002
1103
  // (a 22-path `add`) cost more than the result it labelled.
1003
1104
  const results = [];
@@ -1027,4 +1128,5 @@ export const _gitCommandInternals = {
1027
1128
  parseCommand,
1028
1129
  prepare,
1029
1130
  resolveRepo,
1131
+ writeScopes,
1030
1132
  };