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
@@ -0,0 +1,23 @@
1
+ // session-activity-signal.mjs
2
+ // Process-local "a session's activity state may have changed" pulse: a turn
3
+ // started or settled, a task wait began or ended, a background task was
4
+ // handed off or finished. Status surfaces that project activity from the
5
+ // runtime map (the Agents pool) listen and re-read at once instead of waiting
6
+ // for their next store event. Import-free leaf.
7
+ const listeners = new Set();
8
+
9
+ export function onSessionActivityChange(listener) {
10
+ if (typeof listener !== 'function') return () => {};
11
+ listeners.add(listener);
12
+ return () => listeners.delete(listener);
13
+ }
14
+
15
+ export function emitSessionActivityChange(sessionId = '') {
16
+ for (const listener of [...listeners]) {
17
+ try {
18
+ listener(String(sessionId || ''));
19
+ } catch {
20
+ /* a listener's failure never affects the transition */
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,23 @@
1
+ // Formatting shared by every surface that hands shell output to an agent.
2
+ // Program output is untrusted text: anything shaped like a harness/system tag
3
+ // is escaped so it can never forge a notice, a result boundary or a reminder.
4
+ // (Capping lives in tools/builtin/lib/shell-delivery.mjs, per-job cursors in
5
+ // tools/builtin/lib/shell-task-output.mjs.)
6
+
7
+ // A tag-looking token: `<name`, `</name`, where the name is a known
8
+ // harness/system/transcript word or any hyphenated/underscored/namespaced
9
+ // name (task-notification, system-reminder, tool_result, ns:tag ...). Plain
10
+ // HTML-ish words like <div> or a comparison `a<b` stay readable.
11
+ const HARNESS_TAG =
12
+ /<(\/?)(?=(?:[a-z][\w]*[-_:][\w:-]*|system|result|results|summary|status|error|user|assistant|human|tool|function|functions|instructions|context|notification|reminder|output|invoke|parameter|thinking)\b)/gi;
13
+
14
+ export function escapeHarnessTags(text) {
15
+ return String(text ?? '').replace(HARNESS_TAG, '&lt;$1');
16
+ }
17
+
18
+ export function formatDuration(ms) {
19
+ if (!(ms >= 0)) return '';
20
+ if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
21
+ const minutes = Math.floor(ms / 60_000);
22
+ return `${minutes}m ${Math.round((ms % 60_000) / 1000)}s`;
23
+ }
@@ -1,8 +1,23 @@
1
- import { mkdirSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
1
+ import { mkdirSync, renameSync, rmdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
2
+ import { readFile, rename, rm, rmdir, stat, writeFile } from 'node:fs/promises';
2
3
  import { dirname } from 'node:path';
4
+ import { withFileLock, withFileLockSync } from './file-lock.mjs';
3
5
  import { readJsonSafe } from './json-file.mjs';
4
6
  import { isPidAlive } from './pid-liveness.mjs';
5
- import { sleepSync } from './sleep.mjs';
7
+
8
+ // Claim-lock protocol shared by the sync and async paths: `<path>.claim.lock`
9
+ // is a file-lock.mjs lock, published atomically with its holder's pid and
10
+ // token. A holder whose pid is alive is waited out however long it holds the
11
+ // lock — a holder stalled mid-refresh still owns it: reclaiming it on age let
12
+ // a successor claim the record and the stalled refresh then overwrite it. Its
13
+ // lock is reclaimed only once that pid is dead, and only the holder's own
14
+ // acquisition (pid + token) is ever released. A lock naming no holder — the
15
+ // bare directory versions before this one took the lock with — is reclaimed
16
+ // once older than CLAIM_LOCK_STALE_MS, as those versions did.
17
+ const CLAIM_LOCK_TIMEOUT_MS = 500;
18
+ const CLAIM_LOCK_STALE_MS = 5000;
19
+ const CLAIM_LOCK_OPTS = Object.freeze({ timeoutMs: CLAIM_LOCK_TIMEOUT_MS, staleMs: CLAIM_LOCK_STALE_MS });
20
+ const BUSY = Symbol('claim lock busy');
6
21
 
7
22
  function writeJsonAtomic(path, value) {
8
23
  mkdirSync(dirname(path), { recursive: true });
@@ -11,28 +26,82 @@ function writeJsonAtomic(path, value) {
11
26
  renameSync(tmp, path);
12
27
  }
13
28
 
14
- function acquireClaimLock(path) {
29
+ // Held by another live process or this one's async holder ('busy'). Any other
30
+ // failure (an unwritable data directory) is thrown, as before.
31
+ function claimLockHeld(error) {
32
+ return error?.code === 'ELOCKCONTENDED' || (error?.code === 'ELOCKTIMEOUT' && error.cause?.code === 'EEXIST');
33
+ }
34
+
35
+ function legacyLockStale(info) {
36
+ return info.isDirectory() && Date.now() - info.mtimeMs > CLAIM_LOCK_STALE_MS;
37
+ }
38
+
39
+ // An older version's stale bare lock directory is removed with rmdir alone,
40
+ // never recursive or forced: between the stat and the removal a contender may
41
+ // have replaced it with a live owner-named lock file. rmdir refuses a file
42
+ // (ENOENT on Windows, ENOTDIR elsewhere) and a non-empty directory
43
+ // (ENOTEMPTY); a missing path (ENOENT) is already gone. Any refusal (EPERM
44
+ // included) leaves the path untouched to the shared acquire loop below, which
45
+ // waits a live holder out and reclaims only a dead one's lock.
46
+
47
+ // `fn()` under the claim lock, or BUSY. file-lock creates a missing data
48
+ // directory (a first boot, e.g. a daemon an ssh bootstrap starts on a fresh
49
+ // server).
50
+ function withClaimLockSync(path, fn) {
15
51
  const lockPath = `${path}.claim.lock`;
16
- // A first boot (e.g. a daemon an ssh bootstrap starts on a fresh server)
17
- // has no data directory yet: the lock's parent must exist.
18
- mkdirSync(dirname(path), { recursive: true });
19
- for (let i = 0; i < 20; i++) {
20
- try {
21
- mkdirSync(lockPath, { recursive: false });
22
- return lockPath;
23
- } catch (error) {
24
- if (error?.code !== 'EEXIST') throw error;
25
- try {
26
- const ageMs = Date.now() - statSync(lockPath).mtimeMs;
27
- if (ageMs > 5000) {
28
- rmSync(lockPath, { recursive: true, force: true });
29
- continue;
30
- }
31
- } catch {}
32
- sleepSync(25);
33
- }
52
+ try {
53
+ if (legacyLockStale(statSync(lockPath))) rmdirSync(lockPath);
54
+ } catch {}
55
+ let entered = false;
56
+ try {
57
+ return withFileLockSync(
58
+ lockPath,
59
+ () => {
60
+ entered = true;
61
+ return fn();
62
+ },
63
+ CLAIM_LOCK_OPTS
64
+ );
65
+ } catch (error) {
66
+ if (!entered && claimLockHeld(error)) return BUSY;
67
+ throw error;
68
+ }
69
+ }
70
+
71
+ // The same lock taken without blocking the event loop: every file operation
72
+ // and every retry wait is awaited (a synchronous refresh once held the
73
+ // daemon's loop for 20 s in one rmSync under disk contention).
74
+ async function withClaimLock(path, fn) {
75
+ const lockPath = `${path}.claim.lock`;
76
+ try {
77
+ if (legacyLockStale(await stat(lockPath))) await rmdir(lockPath);
78
+ } catch {}
79
+ let entered = false;
80
+ try {
81
+ return await withFileLock(
82
+ lockPath,
83
+ () => {
84
+ entered = true;
85
+ return fn();
86
+ },
87
+ CLAIM_LOCK_OPTS
88
+ );
89
+ } catch (error) {
90
+ if (!entered && claimLockHeld(error)) return BUSY;
91
+ throw error;
92
+ }
93
+ }
94
+
95
+ function namesOtherPid(record, pid) {
96
+ return Boolean(record?.pid) && Number(record.pid) !== Number(pid);
97
+ }
98
+
99
+ async function readJsonSafeAsync(path) {
100
+ try {
101
+ return JSON.parse(await readFile(path, 'utf8'));
102
+ } catch {
103
+ return null;
34
104
  }
35
- return null;
36
105
  }
37
106
 
38
107
  // A live pid alone does not prove the record's process still owns it: the OS
@@ -64,18 +133,15 @@ export function claimSingletonOwner(path, { kind = 'runtime', pid = process.pid,
64
133
  return { owned: false, owner: current };
65
134
  }
66
135
 
67
- const lockPath = acquireClaimLock(path);
68
- if (!lockPath) return { owned: false, owner: readJsonSafe(path) };
69
- try {
136
+ const result = withClaimLockSync(path, () => {
70
137
  const lockedCurrent = readJsonSafe(path);
71
138
  if (livePeer(lockedCurrent)) {
72
139
  return { owned: false, owner: lockedCurrent };
73
140
  }
74
141
  writeJsonAtomic(path, owner);
75
142
  return { owned: true, owner };
76
- } finally {
77
- rmSync(lockPath, { recursive: true, force: true });
78
- }
143
+ });
144
+ return result === BUSY ? { owned: false, owner: readJsonSafe(path) } : result;
79
145
  }
80
146
 
81
147
  export function releaseSingletonOwner(path, pid = process.pid) {
@@ -94,16 +160,37 @@ export function releaseSingletonOwner(path, pid = process.pid) {
94
160
  // naming another pid is reported, never overwritten ('superseded'); a claim
95
161
  // lock held past its wait leaves the record alone ('busy').
96
162
  export function refreshSingletonOwner(path, owner) {
97
- const lockPath = acquireClaimLock(path);
98
- if (!lockPath) return { status: 'busy', owner: null };
99
- try {
163
+ const result = withClaimLockSync(path, () => {
100
164
  const current = readJsonSafe(path);
101
- if (current?.pid && Number(current.pid) !== Number(owner.pid)) return { status: 'superseded', owner: current };
165
+ if (namesOtherPid(current, owner.pid)) return { status: 'superseded', owner: current };
102
166
  writeJsonAtomic(path, owner);
103
167
  return { status: 'refreshed', owner };
104
- } finally {
105
- rmSync(lockPath, { recursive: true, force: true });
106
- }
168
+ });
169
+ return result === BUSY ? { status: 'busy', owner: null } : result;
170
+ }
171
+
172
+ /** refreshSingletonOwner without blocking the event loop: the same claim
173
+ * lock (mutually exclusive with the sync claim/refresh/handoff), the same
174
+ * verdicts, every file operation and retry wait awaited. Its awaited write
175
+ * may stall, so the record is read again right before it is replaced: a
176
+ * record another pid wrote meanwhile is reported, never overwritten. */
177
+ export async function refreshSingletonOwnerAsync(path, owner) {
178
+ const result = await withClaimLock(path, async () => {
179
+ const current = await readJsonSafeAsync(path);
180
+ if (namesOtherPid(current, owner.pid)) return { status: 'superseded', owner: current };
181
+ let tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
182
+ try {
183
+ await writeFile(tmp, `${JSON.stringify(owner, null, 2)}\n`);
184
+ const latest = await readJsonSafeAsync(path);
185
+ if (namesOtherPid(latest, owner.pid)) return { status: 'superseded', owner: latest };
186
+ await rename(tmp, path);
187
+ tmp = null;
188
+ return { status: 'refreshed', owner };
189
+ } finally {
190
+ if (tmp) await rm(tmp, { force: true }).catch(() => {});
191
+ }
192
+ });
193
+ return result === BUSY ? { status: 'busy', owner: null } : result;
107
194
  }
108
195
 
109
196
  // Atomic ownership handoff: replace the owner record from fromPid to toOwner
@@ -113,11 +200,9 @@ export function refreshSingletonOwner(path, owner) {
113
200
  // (someone else won), the handoff is refused (owned:false) and the caller
114
201
  // should fall back to the winner rather than overwrite it.
115
202
  export function handoffSingletonOwner(path, fromPid, toOwner = {}) {
116
- const lockPath = acquireClaimLock(path);
117
- if (!lockPath) return { owned: false, owner: readJsonSafe(path) };
118
- try {
203
+ const result = withClaimLockSync(path, () => {
119
204
  const current = readJsonSafe(path);
120
- if (current?.pid && Number(current.pid) !== Number(fromPid)) {
205
+ if (namesOtherPid(current, fromPid)) {
121
206
  return { owned: false, owner: current };
122
207
  }
123
208
  const owner = {
@@ -127,7 +212,6 @@ export function handoffSingletonOwner(path, fromPid, toOwner = {}) {
127
212
  };
128
213
  writeJsonAtomic(path, owner);
129
214
  return { owned: true, owner };
130
- } finally {
131
- rmSync(lockPath, { recursive: true, force: true });
132
- }
215
+ });
216
+ return result === BUSY ? { owned: false, owner: readJsonSafe(path) } : result;
133
217
  }
@@ -3,8 +3,8 @@
3
3
  // monotonic clock the owner heartbeat uses (performance.now), completed spans
4
4
  // over `minMs` land in a bounded ring, and spans over `slowMs` are logged as
5
5
  // `[slow-op] <label> <ms>`. When the event loop stalls, `describe(from, to)`
6
- // names the spans that overlapped the stall window. Spans carry labels, phase
7
- // durations and sizes only — never payloads.
6
+ // names the spans that overlapped the stall window. Spans carry labels and
7
+ // phase durations only — never payloads.
8
8
 
9
9
  import { AsyncLocalStorage } from 'node:async_hooks';
10
10
  import { performance } from 'node:perf_hooks';
@@ -36,18 +36,11 @@ export function markPhase(name) {
36
36
  span.mark = t;
37
37
  }
38
38
 
39
- /** Records a size (count/bytes) on the caller's span. */
40
- export function noteSpanSize(size) {
41
- const span = current.getStore();
42
- if (span && Number.isFinite(size)) span.size = size;
43
- }
44
-
45
39
  const round = (ms) => Math.round(ms);
46
40
 
47
41
  function formatSpan(span) {
48
42
  const phases = span.phases.map(([name, ms]) => `${name}=${round(ms)}`).join(' ');
49
- const size = span.size === undefined ? '' : ` size=${span.size}`;
50
- return `${span.label} ${round(span.ms)}ms${phases ? ` ${phases}` : ''}${size}`;
43
+ return `${span.label} ${round(span.ms)}ms${phases ? ` ${phases}` : ''}`;
51
44
  }
52
45
 
53
46
  export function createSlowSpans({
@@ -70,7 +63,6 @@ export function createSlowSpans({
70
63
  end: span.end,
71
64
  ms: span.ms,
72
65
  phases: span.phases,
73
- size: span.size,
74
66
  });
75
67
  if (ring.length > capacity) ring.shift();
76
68
  }
@@ -90,7 +82,7 @@ export function createSlowSpans({
90
82
  /** Runs `fn` inside a span; markPhase/annotateSpan inside it attach to this span. */
91
83
  async trace(label, fn) {
92
84
  const start = now();
93
- const span = { label: String(label), start, mark: start, now, phases: [], size: undefined };
85
+ const span = { label: String(label), start, mark: start, now, phases: [] };
94
86
  try {
95
87
  return await current.run(span, fn);
96
88
  } finally {
@@ -200,7 +200,8 @@ async function refreshShellJobsStatus(ownerPid) {
200
200
  // its owner retires the record. Its root pid may be gone while a
201
201
  // descendant lives, so the owner's liveness decides, not the root's.
202
202
  const unconfirmed = detail?.terminationUnconfirmed === true;
203
- if (unconfirmed ? !isPidAlive(ownerByJob.get(id) || 0) : !(await isShellJobAlive(detail, p, dir, id))) continue;
203
+ if (unconfirmed ? !isHeldShellJobAlive(detail, ownerByJob.get(id)) : !(await isShellJobAlive(detail, p, dir, id)))
204
+ continue;
204
205
  // A foreground command is awaited in its own tool card; listing it here
205
206
  // made every short command flash in and out of the shell list. Only
206
207
  // backgrounded jobs (including promoted ones) are background work.
@@ -326,6 +327,17 @@ function summarizeShellJobs({ count, oldestMs, jobs, bySession }) {
326
327
  return { count, elapsedLabel, jobs, sessions };
327
328
  }
328
329
 
330
+ // A held record lives while its owner process does. Once its owner session
331
+ // has closed, it also needs a process left to hold: the root or a survivor
332
+ // its termination watch last reported. Without one it is an orphan whose
333
+ // processes are gone, and it resolves instead of staying unconfirmed.
334
+ function isHeldShellJobAlive(detail, ownerPid) {
335
+ if (!isPidAlive(ownerPid || 0)) return false;
336
+ if (detail?.ownerSessionClosed !== true) return true;
337
+ const survivors = Array.isArray(detail?.survivorPids) ? detail.survivorPids : [];
338
+ return [detail?.pid, ...survivors].some((pid) => isPidAlive(positiveInt(pid)));
339
+ }
340
+
329
341
  async function isShellJobAlive(detail, detailPath, dir, id) {
330
342
  const pid = positiveInt(detail?.pid);
331
343
  if (!pid) return false;
@@ -3,6 +3,8 @@
3
3
  // context cost of any one tool call is bounded and consistent. Override with
4
4
  // MIXDOG_TOOL_OUTPUT_MAX_BYTES. Line-based sub-caps (e.g. bash max lines) stay
5
5
  // per-tool; this governs only the byte budget.
6
+ import { capMarker } from './tool-output-marker.mjs';
7
+ export { capMarker, formatCapSize, windowMarker } from './tool-output-marker.mjs';
6
8
  // A positive integer from an env var, or `fallback` when unset or invalid.
7
9
  export function positiveEnvInt(name, fallback) {
8
10
  const v = parseInt(process.env[name], 10);
@@ -53,7 +55,7 @@ export function capLineOrientedToolOutput(result, maxBytes, footerForPrefix) {
53
55
  while (lo <= hi) {
54
56
  const mid = Math.floor((lo + hi) / 2);
55
57
  const kept = lines.slice(0, mid);
56
- const footer = String(footerForPrefix?.(kept, lines) || '... [output budget reached; remainder omitted]');
58
+ const footer = String(footerForPrefix?.(kept, lines) || capMarker({ limit: cap }));
57
59
  const candidate = `${kept.join('\n')}${kept.length ? '\n' : ''}${footer}`;
58
60
  if (Buffer.byteLength(candidate, 'utf8') <= cap) {
59
61
  best = candidate;
@@ -63,5 +65,5 @@ export function capLineOrientedToolOutput(result, maxBytes, footerForPrefix) {
63
65
  }
64
66
  }
65
67
  if (best) return best;
66
- return _prefixByBytes(String(footerForPrefix?.([], lines) || '... [output budget reached; remainder omitted]'), cap);
68
+ return _prefixByBytes(String(footerForPrefix?.([], lines) || capMarker({ limit: cap })), cap);
67
69
  }
@@ -0,0 +1,58 @@
1
+ // One marker vocabulary for every non-shell tool output that is not the whole
2
+ // answer. Two shapes, never mixed:
3
+ // window `[lines a-b of N; offset:N for more]` the agent asked for this slice
4
+ // cap `[output capped at X KB; …; offset:N for more]` the tool cut it
5
+ // A cap marker always carries the continuation (offset / cursor, else narrowing
6
+ // advice) and, when the complete output was saved, `full output: <path>`.
7
+
8
+ export function formatCapSize(bytes) {
9
+ const n = Number(bytes);
10
+ if (n < 1024) return `${Math.max(0, Math.trunc(n))} bytes`;
11
+ const kb = n / 1024;
12
+ return `${Number.isInteger(kb) ? kb : kb.toFixed(1)} KB`;
13
+ }
14
+
15
+ /**
16
+ * Requested window: `[lines 5-27 of 90; offset:28 for more]` (no continuation
17
+ * at the end). `capBytes` marks a window the byte cap shortened:
18
+ * `[lines 5-27 of 90; output capped at 50 KB; offset:28 for more]`.
19
+ */
20
+ export function windowMarker({
21
+ unit = 'lines',
22
+ from,
23
+ to,
24
+ total = null,
25
+ nextOffset = null,
26
+ capBytes = null,
27
+ offsetKey = 'offset',
28
+ }) {
29
+ const of = total == null ? '' : ` of ${total}`;
30
+ const cap = capBytes == null ? '' : `; output capped at ${formatCapSize(capBytes)}`;
31
+ const more = nextOffset == null ? '' : `; ${offsetKey}:${nextOffset} for more`;
32
+ return `[${unit} ${from}-${to}${of}${cap}${more}]`;
33
+ }
34
+
35
+ /**
36
+ * Cap hit. `limit` is bytes (number) or a ready label ("500 rows"). `shown`
37
+ * says what survived. Continuation is `nextOffset`, else `cursor`, else
38
+ * `narrow` advice (a default is supplied so it is never missing).
39
+ */
40
+ export function capMarker({
41
+ limit,
42
+ shown = '',
43
+ nextOffset = null,
44
+ offsetKey = 'offset',
45
+ cursor = null,
46
+ narrow = '',
47
+ fullPath = '',
48
+ }) {
49
+ const parts = [`output capped at ${typeof limit === 'number' ? formatCapSize(limit) : limit}`];
50
+ if (shown) parts.push(shown);
51
+ if (nextOffset != null) parts.push(`${offsetKey}:${nextOffset} for more`);
52
+ else if (cursor != null) parts.push(`cursor:${cursor} for more`);
53
+ if (narrow || (nextOffset == null && cursor == null)) {
54
+ parts.push(`narrow: ${narrow || 'restrict the path, pattern or scope'}`);
55
+ }
56
+ if (fullPath) parts.push(`full output: ${fullPath}`);
57
+ return `[${parts.join('; ')}]`;
58
+ }
@@ -2,6 +2,7 @@
2
2
  // These pure helpers keep live rows, persisted messages and restored rows on
3
3
  // the same field contract without rewriting older display-only transcripts.
4
4
  import { displayModelName } from './model-display.mjs';
5
+ import { routineTriggerField } from './routine-trigger.mjs';
5
6
 
6
7
  export function transcriptRouteMetadataFields(value) {
7
8
  if (!value || typeof value !== 'object') return {};
@@ -76,10 +77,19 @@ export function persistedUserTranscriptMetadata(value) {
76
77
  // The turn's change-record key (the outer prompt id), so a restored user
77
78
  // row still addresses its turn's Undo/Reapply.
78
79
  ...(typeof value.checkpointId === 'string' && value.checkpointId ? { checkpointId: value.checkpointId } : {}),
80
+ // Every submission a merged queued batch delivered as this turn.
81
+ ...submissionIdsField(value.submissionIds),
79
82
  ...attachmentsField(value.attachments),
83
+ // A routine fire delivered as this turn (routine-trigger.mjs).
84
+ ...routineTriggerField(value),
80
85
  };
81
86
  }
82
87
 
88
+ function submissionIdsField(value) {
89
+ const ids = Array.isArray(value) ? value.filter((id) => typeof id === 'string' && id) : [];
90
+ return ids.length ? { submissionIds: ids } : {};
91
+ }
92
+
83
93
  function attachmentsField(value) {
84
94
  const attachments = normalizeMessageAttachments(value);
85
95
  return attachments.length ? { attachments } : {};
@@ -27,7 +27,6 @@ import {
27
27
  export const TURN_CHANGE_FILE_PATCH_MAX_BYTES = 8 * 1024 * 1024;
28
28
  const APPLY_TIMEOUT_MS = 60_000;
29
29
  const APPLY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
30
- const STATUSES = new Set(['A', 'M', 'D', 'R']);
31
30
  // Characters a patch header cannot carry unquoted; such a path is recorded but
32
31
  // never replayed.
33
32
  const UNSAFE_PATH_CHARACTERS = /[\t\n\r"\0]/;
@@ -37,13 +36,6 @@ export function changePathKey(value) {
37
36
  return process.platform === 'win32' ? text.toLowerCase() : text;
38
37
  }
39
38
 
40
- /** git status letter → record status (copies create a new file). */
41
- export function normalizeChangeStatus(code) {
42
- const letter = String(code || 'M').charAt(0);
43
- if (STATUSES.has(letter)) return letter;
44
- return letter === 'C' ? 'A' : 'M';
45
- }
46
-
47
39
  /** A root-relative forward-slash path that a patch may name, or ''. */
48
40
  function safeChangePath(value) {
49
41
  const text = clean(value).replace(/\\/g, '/');
@@ -0,0 +1,56 @@
1
+ // Session-cumulative figures behind the composer's usage readout, kept on the
2
+ // session record (`session.usageReadout`) so they survive restart, reload and
3
+ // compaction. One fold per model call of the session itself; calls of other
4
+ // sessions (delegated sub-agents have their own records) never enter.
5
+ //
6
+ // - cache hit = cacheRead / (input + cacheRead + cacheWrite) over every call
7
+ // whose prompt was measured. A call that could not measure its prompt
8
+ // (promptKnown === false) has unknown zeros, so it adds nothing.
9
+ // - speed = output tokens over generation ms (first visible token → end of the
10
+ // response) of the calls long enough to time. A reply too short says nothing
11
+ // about the model's speed, so each call is held to the floors below BEFORE it
12
+ // is summed.
13
+ // - total tokens = input + cacheRead + cacheWrite + output, from the same sums.
14
+ export const MIN_SPEED_OUTPUT_TOKENS = 20;
15
+ export const MIN_SPEED_MS = 500;
16
+
17
+ function num(value) {
18
+ const n = Number(value);
19
+ return Number.isFinite(n) && n > 0 ? n : 0;
20
+ }
21
+
22
+ /** The zeroed totals record. */
23
+ export function emptyUsageReadout() {
24
+ return { input: 0, cacheRead: 0, cacheWrite: 0, output: 0, speedOutputTokens: 0, speedMs: 0 };
25
+ }
26
+
27
+ /**
28
+ * Fold one `onUsageDelta` event (and the call's generation ms, 0 when it was
29
+ * not timed) into the totals; returns a new record, never mutates `totals`.
30
+ * Providers differ on whether input counts cache; the prompt total does not,
31
+ * so fresh input is the prompt less its cache read/write.
32
+ */
33
+ export function foldUsageReadout(totals, delta = {}, generationMs = 0) {
34
+ const base = totals || emptyUsageReadout();
35
+ const next = { ...base };
36
+ if (delta.promptKnown !== false) {
37
+ const cacheRead = num(delta.deltaCachedRead);
38
+ const cacheWrite = num(delta.deltaCacheWrite);
39
+ const prompt = num(delta.deltaPrompt) || num(delta.deltaInput) + cacheRead + cacheWrite;
40
+ next.input = num(base.input) + Math.max(0, prompt - cacheRead - cacheWrite);
41
+ next.cacheRead = num(base.cacheRead) + cacheRead;
42
+ next.cacheWrite = num(base.cacheWrite) + cacheWrite;
43
+ }
44
+ const output = num(delta.deltaOutput);
45
+ // Every call's output enters the session's total tokens, timed or not. A
46
+ // record saved before the field existed has no output sum to extend, and a
47
+ // partial one would pass for the whole: it stays without until the session
48
+ // starts over.
49
+ if (Number.isFinite(base.output)) next.output = base.output + output;
50
+ const ms = num(generationMs);
51
+ if (ms >= MIN_SPEED_MS && output >= MIN_SPEED_OUTPUT_TOKENS) {
52
+ next.speedOutputTokens = num(base.speedOutputTokens) + output;
53
+ next.speedMs = num(base.speedMs) + ms;
54
+ }
55
+ return next;
56
+ }