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
@@ -1,3 +1,40 @@
1
+ // In-process write lock for git work on one repository.
2
+ //
3
+ // Why it exists: Mixdog runs several sessions and sub-agents against one
4
+ // repository at once, and some of its own git work is a multi-step transaction
5
+ // that git's lock files cannot make atomic:
6
+ // - a managed worktree mutation (worktrees/lock.mjs: create, checkout,
7
+ // merge, remove, reconcile) inspects state, verifies it is clean or free,
8
+ // then mutates refs, worktrees and the registry; an agent commit, checkout
9
+ // or `worktree add` landing between the check and the mutation would be
10
+ // lost or contradict it;
11
+ // - `git action:stage` re-runs the diff, verifies it against the snapshot,
12
+ // then applies the selection to the index; another write to that index in
13
+ // between would stage a patch built from a stale view;
14
+ // - two writes to one worktree (checkout + commit) must not interleave.
15
+ // The previous repository-wide read/write lock covered these by making every
16
+ // git tool call, reads included, queue on one lock, so one long read
17
+ // (`git log -S`) held back a writer and that queued writer held back every
18
+ // later read in every worktree of the repository.
19
+ //
20
+ // Policy:
21
+ // - Reads take no lock. Git publishes the index and refs by atomic rename,
22
+ // so a read always sees a consistent index and ref state; the git tool runs
23
+ // reads with optional locks off, so `git status` never takes index.lock
24
+ // beside a write (`git diff` may still refresh it briefly, which the write
25
+ // retry absorbs). A read during a same-worktree write sees git's state at
26
+ // that instant, as any second terminal (or the shell tool) does.
27
+ // - A write names the worktrees it touches (the cwd's worktree, or the
28
+ // target paths of `worktree add/remove/move`). Writes conflict only when
29
+ // those sets intersect; a whole-repository write (managed mutations,
30
+ // object pruning, init/clone, an unresolved worktree target) conflicts
31
+ // with every write of the repository.
32
+ // - Fair FIFO without convoys: a waiting write is granted once it conflicts
33
+ // with no running write and no earlier waiting write. A later write never
34
+ // overtakes an earlier one it conflicts with, so no write starves; a later
35
+ // write that conflicts with nothing ahead of it runs at once.
36
+ // - Git's own lock files still guard index, refs and config against other
37
+ // processes; the git tool retries a write that git refused on one of them.
1
38
  import { pathKey } from '../../../../shared/worktrees/paths.mjs';
2
39
 
3
40
  const states = new Map();
@@ -10,52 +47,45 @@ export function gitRepoLockKey(repo) {
10
47
  return pathKey(String(repo || '.'));
11
48
  }
12
49
 
13
- function keyFor(repo) {
14
- return gitRepoLockKey(repo);
15
- }
16
-
17
50
  function stateFor(key) {
18
51
  let state = states.get(key);
19
52
  if (!state) {
20
- state = { readers: 0, writer: false, queue: [] };
53
+ state = { running: new Set(), queue: [] };
21
54
  states.set(key, state);
22
55
  }
23
56
  return state;
24
57
  }
25
58
 
26
- function drain(key, state) {
27
- if (state.writer) return;
28
- if (state.readers > 0 && state.queue[0]?.mode === 'write') return;
29
- if (state.queue.length === 0) {
30
- if (state.readers === 0) states.delete(key);
31
- return;
32
- }
33
- if (state.readers === 0 && state.queue[0].mode === 'write') {
34
- const entry = state.queue.shift();
35
- state.writer = true;
36
- entry.granted = true;
37
- entry.signal?.removeEventListener?.('abort', entry.onAbort);
38
- entry.resolve(releaseFor(key, state, 'write'));
39
- return;
40
- }
41
- while (state.queue[0]?.mode === 'read' && !state.writer) {
42
- const entry = state.queue.shift();
43
- state.readers++;
44
- entry.granted = true;
45
- entry.signal?.removeEventListener?.('abort', entry.onAbort);
46
- entry.resolve(releaseFor(key, state, 'read'));
47
- }
59
+ // `scopes` null is the whole repository.
60
+ function conflicts(left, right) {
61
+ if (!left.scopes || !right.scopes) return true;
62
+ return left.scopes.some((scope) => right.scopes.includes(scope));
48
63
  }
49
64
 
50
- function releaseFor(key, state, mode) {
65
+ function grant(key, state, entry) {
66
+ entry.granted = true;
67
+ entry.signal?.removeEventListener?.('abort', entry.onAbort);
68
+ state.running.add(entry);
51
69
  let released = false;
52
- return () => {
70
+ entry.resolve(() => {
53
71
  if (released) return;
54
72
  released = true;
55
- if (mode === 'write') state.writer = false;
56
- else state.readers = Math.max(0, state.readers - 1);
73
+ state.running.delete(entry);
57
74
  drain(key, state);
58
- };
75
+ });
76
+ }
77
+
78
+ function drain(key, state) {
79
+ const waiting = [];
80
+ for (const entry of state.queue) {
81
+ const blocked =
82
+ [...state.running].some((running) => conflicts(running, entry)) ||
83
+ waiting.some((earlier) => conflicts(earlier, entry));
84
+ if (blocked) waiting.push(entry);
85
+ else grant(key, state, entry);
86
+ }
87
+ state.queue = waiting;
88
+ if (state.running.size === 0 && waiting.length === 0) states.delete(key);
59
89
  }
60
90
 
61
91
  function abortError(signal) {
@@ -63,12 +93,12 @@ function abortError(signal) {
63
93
  return Object.assign(new Error('git repository lock aborted'), { name: 'AbortError', code: 'ABORT_ERR' });
64
94
  }
65
95
 
66
- function acquire(repo, mode, signal) {
96
+ function acquire(repo, scopes, signal) {
67
97
  if (signal?.aborted) return Promise.reject(abortError(signal));
68
- const key = keyFor(repo);
98
+ const key = gitRepoLockKey(repo);
69
99
  const state = stateFor(key);
70
100
  return new Promise((resolveLock, rejectLock) => {
71
- const entry = { mode, resolve: resolveLock, reject: rejectLock, signal, onAbort: null, granted: false };
101
+ const entry = { scopes, resolve: resolveLock, signal, onAbort: null, granted: false };
72
102
  entry.onAbort = () => {
73
103
  if (entry.granted) return;
74
104
  const index = state.queue.indexOf(entry);
@@ -83,9 +113,9 @@ function acquire(repo, mode, signal) {
83
113
  });
84
114
  }
85
115
 
86
- async function withLock(repo, mode, fn, options = {}) {
116
+ async function withLock(repo, scopes, fn, options = {}) {
87
117
  const signal = options?.signal || null;
88
- const release = await acquire(repo, mode, signal);
118
+ const release = await acquire(repo, scopes, signal);
89
119
  try {
90
120
  if (signal?.aborted) throw abortError(signal);
91
121
  return await fn();
@@ -94,10 +124,29 @@ async function withLock(repo, mode, fn, options = {}) {
94
124
  }
95
125
  }
96
126
 
97
- export function withGitRepoReadLock(repo, fn, options = {}) {
98
- return withLock(repo, 'read', fn, options);
127
+ /**
128
+ * Run `fn` holding the write lock of the whole repository.
129
+ * @template T
130
+ * @param {string} repo canonical common git dir (or the path being created)
131
+ * @param {() => Promise<T>|T} fn
132
+ * @param {{ signal?: AbortSignal }} [options]
133
+ * @returns {Promise<T>}
134
+ */
135
+ export function withGitRepoWriteLock(repo, fn, options = {}) {
136
+ return withLock(repo, null, fn, options);
99
137
  }
100
138
 
101
- export function withGitRepoWriteLock(repo, fn, options = {}) {
102
- return withLock(repo, 'write', fn, options);
139
+ /**
140
+ * Run `fn` holding the write lock of the named worktrees only; no (or no
141
+ * non-empty) worktree list holds the whole repository.
142
+ * @template T
143
+ * @param {string} repo canonical common git dir
144
+ * @param {string[]|null} worktrees worktree roots (or target paths) the write touches
145
+ * @param {() => Promise<T>|T} fn
146
+ * @param {{ signal?: AbortSignal }} [options]
147
+ * @returns {Promise<T>}
148
+ */
149
+ export function withGitWorktreeWriteLock(repo, worktrees, fn, options = {}) {
150
+ const scopes = [...new Set((worktrees || []).filter(Boolean).map((path) => gitRepoLockKey(path)))];
151
+ return withLock(repo, scopes.length ? scopes : null, fn, options);
103
152
  }
@@ -4,6 +4,7 @@ import { normalizeErrorMessage } from '../path-diagnostics.mjs';
4
4
  import { isBinaryBuffer } from '../binary-file.mjs';
5
5
  import { isUncPath, isWindowsDevicePath, hasUnsafeWin32Component } from '../device-paths.mjs';
6
6
  import { normalizeOutputPath, resolveAgainstCwd } from '../path-utils.mjs';
7
+ import { windowMarker } from '../tool-output-limit.mjs';
7
8
 
8
9
  /** Report the requested path's result; suggestions never retarget the operation. */
9
10
  export async function readFamilyPathEnoentOrError(workDir, fullPath, inputPath, err) {
@@ -52,8 +53,23 @@ export function guardedWalkRoot(inputPath, workDir) {
52
53
  return { fullPath };
53
54
  }
54
55
 
56
+ // Code-unit path order: the tiebreak that makes a size/mtime sort total, so
57
+ // equal keys cannot reorder with the walk (and shift across offset pages).
58
+ export function comparePathsStable(a, b) {
59
+ const x = String(a);
60
+ const y = String(b);
61
+ if (x === y) return 0;
62
+ return x < y ? -1 : 1;
63
+ }
64
+
55
65
  export function pageContinuationLine(offset, shown, total) {
56
- return `... [entries ${offset + 1}-${offset + shown} of ${total}; pass offset:${offset + shown} to continue]`;
66
+ return windowMarker({
67
+ unit: 'entries',
68
+ from: offset + 1,
69
+ to: offset + shown,
70
+ total,
71
+ nextOffset: offset + shown,
72
+ });
57
73
  }
58
74
 
59
75
  const LINE_COUNT_MAX_BYTES = 2 * 1024 * 1024;
@@ -0,0 +1,199 @@
1
+ // One shape for every piece of shell output handed to an agent — a foreground
2
+ // result, a background move, task wait/read and a completion notice:
3
+ // 1. ANSI stripped, then `\r` progress frames folded to their last frame
4
+ // (before anything is counted or cut);
5
+ // 2. a line longer than DELIVERY_LINE_MAX_CHARS is cut: `… [N chars cut]`;
6
+ // 3. DELIVERY_FULL_CHARS or less goes whole; otherwise a head of at most
7
+ // DELIVERY_HEAD_LINES lines (≤ DELIVERY_HEAD_MAX_CHARS), the marker, and
8
+ // the last ~DELIVERY_TAIL_CHARS;
9
+ // 4. the marker is the same everywhere and always ends with the full log:
10
+ // `[… N lines, X KB omitted — read with offset/limit or grep, full log: <path>]`;
11
+ // 5. anything shaped like a harness/system tag is escaped.
12
+ // MIXDOG_SHELL_DELIVERY_MAX_CHARS is the one knob (the whole-delivery cap); the
13
+ // head and tail sizes are fixed. It is separate from the 50 KB
14
+ // MIXDOG_TOOL_OUTPUT_MAX_BYTES that the other tools use.
15
+ import { randomBytes } from 'node:crypto';
16
+ import { mkdirSync, writeFileSync } from 'node:fs';
17
+ import { join } from 'node:path';
18
+ import { getPluginData } from '../../../config.mjs';
19
+ import { stripAnsi } from '../../shell-exec-output.mjs';
20
+ import { createCarriageReturnFolder } from '../shell-lossless-compact.mjs';
21
+ import { positiveEnvInt } from '../../../../../shared/tool-output-limit.mjs';
22
+ import { escapeHarnessTags } from '../../../../../shared/shell-output-summary.mjs';
23
+
24
+ export const DELIVERY_FULL_CHARS = positiveEnvInt('MIXDOG_SHELL_DELIVERY_MAX_CHARS', 6_000);
25
+ const DELIVERY_HEAD_LINES = 10;
26
+ const DELIVERY_HEAD_MAX_CHARS = 1_000;
27
+ const DELIVERY_TAIL_CHARS = 2_000;
28
+ export const DELIVERY_LINE_MAX_CHARS = 2_000;
29
+
30
+ export { createCarriageReturnFolder };
31
+
32
+ const newlines = (text) => {
33
+ let count = 0;
34
+ for (let i = text.indexOf('\n'); i >= 0; i = text.indexOf('\n', i + 1)) count += 1;
35
+ return count;
36
+ };
37
+
38
+ export function formatKb(bytes) {
39
+ return `${(Math.max(0, bytes) / 1024).toFixed(1)} KB`;
40
+ }
41
+
42
+ /** The omission marker — identical on every delivery path, path last. */
43
+ export function omissionMarker({ lines, bytes, path }) {
44
+ return `[… ${lines} lines, ${formatKb(bytes)} omitted — read with offset/limit or grep, full log: ${path}]`;
45
+ }
46
+
47
+ // `cut` is the number of chars removed from over-long lines.
48
+ function cutLongLines(text) {
49
+ if (text.length <= DELIVERY_LINE_MAX_CHARS) return { text, cut: 0 };
50
+ let cut = 0;
51
+ const cutText = text
52
+ .split('\n')
53
+ .map((line) => {
54
+ if (line.length <= DELIVERY_LINE_MAX_CHARS) return line;
55
+ cut += line.length - DELIVERY_LINE_MAX_CHARS;
56
+ return `${line.slice(0, DELIVERY_LINE_MAX_CHARS)} … [${line.length - DELIVERY_LINE_MAX_CHARS} chars cut]`;
57
+ })
58
+ .join('\n');
59
+ return { text: cutText, cut };
60
+ }
61
+
62
+ /** Step 1 for one chunk (the cut of step 2 is made where the text is
63
+ * delivered, so the uncut text can be archived). `fold` carries `\r` state
64
+ * across chunks of the same stream; omitted, the chunk is folded on its own. */
65
+ export function prepareShellText(text, fold = createCarriageReturnFolder()) {
66
+ return fold(stripAnsi(String(text ?? '')));
67
+ }
68
+
69
+ // `scale` is the share of the delivery budget a stream was given.
70
+ function headOf(text, scale = 1) {
71
+ let end = 0;
72
+ for (let line = 0; line < DELIVERY_HEAD_LINES && end < text.length; line += 1) {
73
+ const newline = text.indexOf('\n', end);
74
+ end = newline < 0 ? text.length : newline + 1;
75
+ }
76
+ return text.slice(0, Math.min(end, Math.floor(DELIVERY_HEAD_MAX_CHARS * scale)));
77
+ }
78
+
79
+ function tailOf(text, floor = 0, scale = 1) {
80
+ const start = Math.max(floor, text.length - Math.floor(DELIVERY_TAIL_CHARS * scale));
81
+ if (start === floor) return text.slice(start);
82
+ // Start on a line boundary when one is near.
83
+ const newline = text.indexOf('\n', start);
84
+ return newline >= 0 && newline - start < 200 && newline + 1 < text.length
85
+ ? text.slice(newline + 1)
86
+ : text.slice(start);
87
+ }
88
+
89
+ /** head + marker + tail; `omitted` counts what lies between them. */
90
+ function joinHeadTail(head, tail, omitted) {
91
+ const gap = head && !head.endsWith('\n') ? '\n' : '';
92
+ return `${head}${gap}${omissionMarker(omitted)}\n${tail}`;
93
+ }
94
+
95
+ // One stream's delivery: `natural` is the length it would have whole (escaped,
96
+ // markers included; Infinity when it can only be shown at its ends) and
97
+ // `render(budget)` the text within `budget` chars. Streams share one budget.
98
+ export const EMPTY_PIECE = { natural: 0, render: () => '' };
99
+
100
+ /** Step 3 when only the two ends of a long range were read: `total` is the
101
+ * whole range's bytes and lines. */
102
+ export function edgesPiece(headText, tailText, { totalBytes, totalLines, path }) {
103
+ return {
104
+ natural: Number.POSITIVE_INFINITY,
105
+ render: (budget) => {
106
+ const scale = budget / DELIVERY_FULL_CHARS;
107
+ const head = headOf(escapeHarnessTags(headText), scale);
108
+ const tail = tailOf(escapeHarnessTags(tailText), 0, scale);
109
+ return joinHeadTail(head, tail, {
110
+ lines: Math.max(0, totalLines - newlines(head) - newlines(tail)),
111
+ bytes: Math.max(0, totalBytes - Buffer.byteLength(head) - Buffer.byteLength(tail)),
112
+ path,
113
+ });
114
+ },
115
+ };
116
+ }
117
+
118
+ export { newlines as countNewlines };
119
+
120
+ /** Steps 2, 3 and 5 on prepared text. `path` names where the whole (uncut)
121
+ * text can be read; it is resolved only when something is removed. */
122
+ export function textPiece(text, { path }) {
123
+ let archive;
124
+ const where = () => (archive ??= typeof path === 'function' ? path() : path);
125
+ const { text: cutText, cut } = cutLongLines(text);
126
+ const shown = escapeHarnessTags(cutText);
127
+ // Cut long lines are removed content too: the whole text carries the marker.
128
+ const whole = cut
129
+ ? `${shown}${shown.endsWith('\n') ? '' : '\n'}${omissionMarker({ lines: 0, bytes: cut, path: where() })}\n`
130
+ : shown;
131
+ return {
132
+ natural: whole.length,
133
+ render: (budget) => {
134
+ if (whole.length <= budget) return whole;
135
+ const scale = budget / DELIVERY_FULL_CHARS;
136
+ const head = headOf(shown, scale);
137
+ const tail = tailOf(shown, head.length, scale);
138
+ const middle = shown.slice(head.length, shown.length - tail.length);
139
+ return joinHeadTail(head, tail, { lines: newlines(middle), bytes: Buffer.byteLength(middle), path: where() });
140
+ },
141
+ };
142
+ }
143
+
144
+ /** Max-min fair split of `budget` over the streams' natural lengths: a stream
145
+ * that fits its fair share is given exactly what it needs, the rest share
146
+ * what remains. */
147
+ function shareBudget(lengths, budget) {
148
+ const shares = lengths.map(() => 0);
149
+ let open = lengths.map((_, index) => index);
150
+ let left = Math.max(0, budget);
151
+ while (open.length) {
152
+ const fair = left / open.length;
153
+ const fits = open.filter((index) => lengths[index] <= fair);
154
+ if (!fits.length) {
155
+ for (const index of open) shares[index] = fair;
156
+ break;
157
+ }
158
+ for (const index of fits) {
159
+ shares[index] = lengths[index];
160
+ left -= lengths[index];
161
+ }
162
+ open = open.filter((index) => !fits.includes(index));
163
+ }
164
+ return shares;
165
+ }
166
+
167
+ /** Deliver streams within one shared budget (default: the whole-delivery cap),
168
+ * each escaped; the caller deducts what it adds around them. */
169
+ export function fitPieces(pieces, budget = DELIVERY_FULL_CHARS) {
170
+ const shares = shareBudget(
171
+ pieces.map((piece) => piece.natural),
172
+ budget
173
+ );
174
+ return pieces.map((piece, index) => escapeHarnessTags(piece.render(shares[index])));
175
+ }
176
+
177
+ /** Text that has no log of its own is kept where the marker can name it:
178
+ * the shell-output folder, swept with the spill files. */
179
+ export function persistDeliveryLog(text, label = 'output') {
180
+ const dir = join(getPluginData(), 'shell-output');
181
+ mkdirSync(dir, { recursive: true });
182
+ const file = join(dir, `delivered_${Date.now().toString(36)}_${randomBytes(4).toString('hex')}.${label}`);
183
+ writeFileSync(file, text);
184
+ return file;
185
+ }
186
+
187
+ /** Steps 1–5 for a whole string, as a piece. Without `path`, the original
188
+ * (uncut) text is saved when anything is removed, so the marker can name it. */
189
+ export function shellTextPiece(text, { path = null, label = 'output', fold } = {}) {
190
+ const prepared = prepareShellText(text, fold);
191
+ return textPiece(prepared, { path: path || (() => persistDeliveryLog(prepared, label)) });
192
+ }
193
+
194
+ export function deliverShellText(text, options) {
195
+ return fitPieces([shellTextPiece(text, options)])[0];
196
+ }
197
+
198
+ /** Step 5 alone, for text the caller already capped. */
199
+ export { escapeHarnessTags };
@@ -339,11 +339,23 @@ export function releaseShellJobWorkspace(jobId) {
339
339
  if (workspaceLeases.get(key) === leave) workspaceLeases.delete(key);
340
340
  }
341
341
 
342
+ /** True once `sessionId` closed in this runtime. */
343
+ export function isShellOwnerSessionClosed(sessionId) {
344
+ return closedOwnerSessions.has(String(sessionId || '').trim());
345
+ }
346
+
342
347
  /** Flag a still-open job record as "termination unconfirmed" for the readouts. */
343
348
  export function markShellJobTerminationUnconfirmed(jobId) {
344
349
  return patchRunningShellJobRecord(jobId, { terminationUnconfirmed: true });
345
350
  }
346
351
 
352
+ /** Record the pids a held job's termination watch last found alive, so a
353
+ * reader in another process can tell a live hold from a stale one. */
354
+ export function noteShellJobSurvivors(jobId, pids) {
355
+ const survivorPids = (pids || []).map(Number).filter((pid) => Number.isInteger(pid) && pid > 0);
356
+ return patchRunningShellJobRecord(jobId, { survivorPids });
357
+ }
358
+
347
359
  function patchRunningShellJobRecord(jobId, patch) {
348
360
  const key = validJobId(jobId);
349
361
  if (!key) return Promise.resolve(false);