mixdog 1.2.4 → 1.2.6

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 (292) hide show
  1. package/package.json +1 -1
  2. package/scripts/lib/gate-scheduler.mjs +2 -2
  3. package/scripts/lib/run-node-tests.mjs +5 -14
  4. package/scripts/mobile-release.mjs +5 -4
  5. package/scripts/provider-pingpong-live.mjs +9 -9
  6. package/src/agents/advisor/AGENT.md +4 -4
  7. package/src/agents/advisor/agent.json +1 -1
  8. package/src/agents/reviewer/AGENT.md +2 -3
  9. package/src/agents/reviewer/agent.json +1 -1
  10. package/src/defaults/shipped-history.json +11 -0
  11. package/src/defaults/skills/browser-use/SKILL.md +2 -1
  12. package/src/defaults/skills/computer-use/SKILL.md +3 -1
  13. package/src/defaults/skills/visualize/SKILL.md +3 -2
  14. package/src/lib/rules-builder.cjs +1 -1
  15. package/src/output-styles/common.md +22 -5
  16. package/src/output-styles/detailed.md +7 -5
  17. package/src/output-styles/minimal.md +7 -3
  18. package/src/output-styles/simple.md +2 -3
  19. package/src/rules/agent/AGENT.md +3 -1
  20. package/src/rules/lead/LEAD.md +10 -7
  21. package/src/rules/shared/10-tool-workflow.md +2 -1
  22. package/src/rules/shared/60-verification.md +4 -5
  23. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
  24. package/src/runtime/agent/orchestrator/config.mjs +6 -0
  25. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +1 -1
  26. package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
  27. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +53 -60
  28. package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
  29. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
  30. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
  31. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +40 -19
  32. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
  33. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
  34. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
  35. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
  36. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
  37. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
  38. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +1 -2
  39. package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
  40. package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
  41. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
  42. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
  43. package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
  44. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
  45. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
  46. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  47. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
  48. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  49. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  50. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
  51. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
  52. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
  53. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  54. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
  55. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  56. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
  57. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
  58. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
  59. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
  60. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
  61. package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
  62. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
  63. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
  64. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
  65. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
  66. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
  67. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
  68. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
  69. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
  70. package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
  71. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +2 -3
  72. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +3 -8
  73. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
  74. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
  75. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
  76. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
  77. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
  78. package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
  79. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
  80. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +9 -19
  81. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -3
  82. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -0
  83. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
  84. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
  85. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
  86. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
  87. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
  88. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
  89. package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
  90. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
  91. package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
  92. package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
  93. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
  94. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
  95. package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
  96. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
  97. package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
  98. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +255 -32
  99. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +306 -0
  100. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +70 -21
  101. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
  102. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
  103. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
  104. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
  105. package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
  106. package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
  107. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
  108. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
  109. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
  110. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
  111. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
  112. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
  113. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
  114. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
  115. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
  116. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
  118. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
  119. package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
  120. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
  121. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
  122. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
  123. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
  124. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
  125. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
  126. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
  127. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
  128. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
  129. package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
  130. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
  131. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
  132. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
  133. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
  134. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
  135. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
  136. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
  137. package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
  138. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +119 -32
  139. package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
  140. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
  141. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
  142. package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
  143. package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
  144. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
  145. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
  146. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
  147. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  148. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
  149. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +40 -2
  150. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -2
  151. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
  152. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +2 -0
  153. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +3 -1
  154. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
  155. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +35 -4
  156. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
  157. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
  158. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
  159. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  160. package/src/runtime/attachments/office-extract.mjs +11 -9
  161. package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
  162. package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
  163. package/src/runtime/memory/lib/tool-call-handler.mjs +7 -5
  164. package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
  165. package/src/runtime/office/core/tabular.mjs +1 -1
  166. package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
  167. package/src/runtime/office/portable/docx-formatting.mjs +1 -1
  168. package/src/runtime/office/portable/docx-runs.mjs +1 -1
  169. package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
  170. package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
  171. package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
  172. package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
  173. package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
  174. package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
  175. package/src/runtime/office/portable/portable-opc.mjs +27 -13
  176. package/src/runtime/office/portable/portable-pivot.mjs +3 -3
  177. package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
  178. package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
  179. package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
  180. package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
  181. package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
  182. package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
  183. package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
  184. package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
  185. package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
  186. package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
  187. package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
  188. package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
  189. package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
  190. package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
  191. package/src/runtime/office/portable/portable-xml.mjs +1 -1
  192. package/src/runtime/shared/atomic-file.mjs +22 -13
  193. package/src/runtime/shared/background-tasks.mjs +60 -20
  194. package/src/runtime/shared/child-spawn-gate.mjs +26 -16
  195. package/src/runtime/shared/config.mjs +0 -10
  196. package/src/runtime/shared/file-lock.mjs +7 -1
  197. package/src/runtime/shared/file-permissions-worker.mjs +38 -0
  198. package/src/runtime/shared/file-permissions.d.mts +19 -4
  199. package/src/runtime/shared/file-permissions.mjs +310 -4
  200. package/src/runtime/shared/git-runner-worker.mjs +6 -78
  201. package/src/runtime/shared/llm/http-agent.mjs +7 -3
  202. package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
  203. package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
  204. package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
  205. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
  206. package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
  207. package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
  208. package/src/runtime/shared/memory-snapshot.mjs +5 -1
  209. package/src/runtime/shared/notify-trace.mjs +8 -1
  210. package/src/runtime/shared/pristine-execution-contract.json +5 -1
  211. package/src/runtime/shared/process-runner-worker.mjs +7 -0
  212. package/src/runtime/shared/process-runner.mjs +38 -0
  213. package/src/runtime/shared/provider-accounts.mjs +2 -1
  214. package/src/runtime/shared/provider-api-key.mjs +0 -1
  215. package/src/runtime/shared/read-row-numbers.mjs +1 -1
  216. package/src/runtime/shared/resource-admission.mjs +60 -18
  217. package/src/runtime/shared/run-child.mjs +84 -0
  218. package/src/runtime/shared/session-activity-signal.mjs +23 -0
  219. package/src/runtime/shared/shell-output-summary.mjs +23 -0
  220. package/src/runtime/shared/singleton-owner.mjs +126 -42
  221. package/src/runtime/shared/tool-output-limit.mjs +4 -2
  222. package/src/runtime/shared/tool-output-marker.mjs +58 -0
  223. package/src/runtime/shared/user-data-guard.mjs +28 -9
  224. package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
  225. package/src/runtime/shared/worktrees/git-head.mjs +20 -2
  226. package/src/runtime/shared/worktrees/lock.mjs +3 -2
  227. package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
  228. package/src/runtime/tidy/runners/biome.mjs +3 -1
  229. package/src/runtime/tidy/shadow.mjs +2 -1
  230. package/src/runtime/web-search/index.mjs +5 -7
  231. package/src/runtime/web-search/lib/formatter.mjs +42 -6
  232. package/src/runtime/web-search/tool-defs.mjs +6 -1
  233. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
  234. package/src/session-runtime/lifecycle/session-switch/resume.mjs +7 -4
  235. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
  236. package/src/session-runtime/lifecycle/shared.mjs +19 -2
  237. package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
  238. package/src/session-runtime/lifecycle/teardown.mjs +5 -2
  239. package/src/session-runtime/lifecycle-api.mjs +3 -1
  240. package/src/session-runtime/provider-auth/login.mjs +10 -6
  241. package/src/session-runtime/provider-auth/setup.mjs +19 -2
  242. package/src/session-runtime/provider-catalog-cache.mjs +101 -25
  243. package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
  244. package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
  245. package/src/session-runtime/provider-models.mjs +76 -10
  246. package/src/session-runtime/provider-readiness.mjs +4 -0
  247. package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
  248. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
  249. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
  250. package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
  251. package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
  252. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
  253. package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
  254. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
  255. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
  256. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
  257. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
  258. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
  259. package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
  260. package/src/session-runtime/services/agent-tool.mjs +20 -0
  261. package/src/session-runtime/services/provider-admin.mjs +92 -20
  262. package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
  263. package/src/session-runtime/services/usage-dashboard.mjs +27 -69
  264. package/src/session-runtime/turn/session-ops.mjs +2 -2
  265. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  266. package/src/session-runtime/usage-stats-api.mjs +6 -1
  267. package/src/standalone/channel-transport/http-routes.mjs +10 -9
  268. package/src/standalone/daemon-desktop-runtime.mjs +20 -7
  269. package/src/standalone/daemon-owner.mjs +117 -25
  270. package/src/standalone/daemon.mjs +43 -13
  271. package/src/standalone/desktop-service-registry.mjs +32 -5
  272. package/src/standalone/session-call-cache.mjs +6 -0
  273. package/src/standalone/session-protocol.mjs +1 -1
  274. package/src/standalone/session-service/retention/busy.mjs +7 -2
  275. package/src/standalone/session-transport/routes.mjs +7 -6
  276. package/src/tui/app/model-options.mjs +39 -2
  277. package/src/tui/app/model-picker.mjs +16 -2
  278. package/src/tui/app/provider-setup-picker.mjs +1 -2
  279. package/src/tui/dist/index.mjs +436 -123
  280. package/src/tui/session/notice-text.mjs +0 -1
  281. package/src/tui/session/session-api/intake/submission.mjs +7 -13
  282. package/src/tui/session/session-api/integrations.mjs +1 -5
  283. package/src/tui/session/session-flow/drain.mjs +8 -0
  284. package/src/tui/session/session-flow/steering.mjs +46 -0
  285. package/src/tui/session/session-flow.mjs +2 -0
  286. package/src/tui/session/turn-stream.mjs +33 -0
  287. package/src/tui/session/turn.mjs +30 -3
  288. package/src/ui/statusline.mjs +1 -6
  289. package/src/ui/streaming-markdown-heal.mjs +94 -25
  290. package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
  291. package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
  292. package/src/workflows/default/WORKFLOW.md +9 -13
@@ -313,7 +313,9 @@ function queueSaturatedAsTask(run, saturation, spec) {
313
313
  jobId: taskId,
314
314
  abortSignal: queuedAbort.signal,
315
315
  admissionWaitMs: 0,
316
- // The call already returned: nobody renders live progress.
316
+ // The call already returned: nobody renders live progress, and no
317
+ // hold remains for user input to end.
318
+ wakeSignal: null,
317
319
  onProgress: null,
318
320
  onOutputTail: null,
319
321
  });
@@ -465,7 +467,27 @@ const promotable = (run, backgroundOnTimeout) =>
465
467
  run.child?.exitCode == null &&
466
468
  run.child?.signalCode == null;
467
469
 
468
- function armDeadlines(run, { timeoutMs, autoBackgroundMs, backgroundOnTimeout, abortSignal }, fireAutoBackground) {
470
+ // New user input or a queued task notification during the hold moves a
471
+ // still-running command to the background at once (never a kill): the call
472
+ // returns to the agent loop, which delivers it at the next boundary.
473
+ function armInputWake(run, wakeSignal, fireAutoBackground) {
474
+ if (!wakeSignal) return;
475
+ const onWake = () => {
476
+ const reason = wakeSignal.reason === 'notification' ? 'notification' : 'input';
477
+ if (promotable(run, true)) fireAutoBackground({ reason });
478
+ };
479
+ if (wakeSignal.aborted) {
480
+ onWake();
481
+ return;
482
+ }
483
+ wakeSignal.addEventListener('abort', onWake, { once: true });
484
+ }
485
+
486
+ function armDeadlines(
487
+ run,
488
+ { timeoutMs, autoBackgroundMs, autoBackgroundReason, backgroundOnTimeout, abortSignal },
489
+ fireAutoBackground
490
+ ) {
469
491
  if (timeoutMs > 0) {
470
492
  run.timer = setTimeout(() => {
471
493
  // Promote-on-timeout: if the caller allows backgrounding and the child
@@ -490,7 +512,7 @@ function armDeadlines(run, { timeoutMs, autoBackgroundMs, backgroundOnTimeout, a
490
512
  (timeoutMs <= 0 || autoBackgroundMs < timeoutMs)
491
513
  ) {
492
514
  run.autoBgTimer = setTimeout(() => {
493
- fireAutoBackground();
515
+ fireAutoBackground({ reason: autoBackgroundReason || 'threshold' });
494
516
  }, autoBackgroundMs);
495
517
  if (run.autoBgTimer.unref) run.autoBgTimer.unref();
496
518
  }
@@ -525,7 +547,11 @@ export function execShellCommand(options) {
525
547
  cwd,
526
548
  timeoutMs,
527
549
  abortSignal,
550
+ // Aborted when new user input should end the hold (task-wait-control).
551
+ wakeSignal = null,
528
552
  autoBackgroundMs,
553
+ // 'background' for an explicit background start; the hold otherwise.
554
+ autoBackgroundReason = 'threshold',
529
555
  onProgress,
530
556
  onOutputTail,
531
557
  clientHostPid,
@@ -597,7 +623,12 @@ export function execShellCommand(options) {
597
623
  promotedTimeoutMs,
598
624
  backgroundDeadlineMs,
599
625
  });
600
- armDeadlines(run, { timeoutMs, autoBackgroundMs, backgroundOnTimeout, abortSignal }, fireAutoBackground);
626
+ armDeadlines(
627
+ run,
628
+ { timeoutMs, autoBackgroundMs, autoBackgroundReason, backgroundOnTimeout, abortSignal },
629
+ fireAutoBackground
630
+ );
631
+ armInputWake(run, wakeSignal, fireAutoBackground);
601
632
  armProgressTimers(run, { onProgress, onOutputTail });
602
633
  } catch (err) {
603
634
  settleSetupFailure(run, err);
@@ -273,6 +273,8 @@ export function isBlockedCommand(command) {
273
273
  return decoded !== null && _blockedText(decoded);
274
274
  }
275
275
 
276
+ const WMIC_PROCESS_COMMAND_RE = /^\s*(?:&\s*)?(?:cmd(?:\.exe)?\s+\/c\s+["']?)?(?:\S*[\\/])?wmic(?:\.exe)?\s+process\b/i;
277
+
276
278
  const WMIC_PROCESS_DEFAULT_FIELDS = Object.freeze([
277
279
  'ProcessId',
278
280
  'Name',
@@ -336,8 +338,11 @@ export function maybeRewriteWmicProcessCommand(command) {
336
338
  // silently drop surrounding `cd`, pipes, `&&`/`;` segments. For composite
337
339
  // commands containing wmic, return null so the caller falls back to other
338
340
  // policy handling instead of dropping context.
339
- if (/[|&;]|\$\(|`/.test(text) && /\bwmic(?:\.exe)?\s+process\b/i.test(text)) return null;
340
- if (!/\bwmic(?:\.exe)?\s+process\b/i.test(text)) return null;
341
+ // Only a command that IS a wmic call is rewritten. The words `wmic process`
342
+ // inside a search pattern, a commit message or a file being written are text:
343
+ // replacing that whole command would discard it.
344
+ if (!WMIC_PROCESS_COMMAND_RE.test(text)) return null;
345
+ if (/[|&;]|\$\(|`/.test(text)) return null;
341
346
  if (!/\bget\b/i.test(text)) {
342
347
  return {
343
348
  error:
@@ -8,6 +8,8 @@
8
8
  // `powershell -Command "<inline>"` / `pwsh -Command "<inline>"` to
9
9
  // `-EncodedCommand <utf16le-base64>` so the payload stays opaque to the
10
10
  // outer shell. Other shells / non-Windows are no-op pass-through.
11
+ import { codeMask } from './builtin/bash-tool/bashism-rewrite.mjs';
12
+
11
13
  // Match -Command "<body>" where the body may contain escaped quotes
12
14
  // (`\"` or `""`). Stops at the first unescaped closing quote so nested
13
15
  // patterns like `"... \"inner\" ..."` survive intact. Common PowerShell
@@ -16,49 +18,63 @@
16
18
  // Single-quoted -Command '<body>' is also covered.
17
19
  const _POWERSHELL_FLAGS_RE =
18
20
  /\s+-(?:NoProfile|NonInteractive|WindowStyle\s+\S+|ExecutionPolicy\s+\S+|Sta|Mta|NoLogo|NoExit)/.source;
21
+ // What may follow the closing quote: the end of the command or a shell
22
+ // operator. Anything else (`pwsh -Command "a" "b"`) is more arguments, which
23
+ // PowerShell appends to the command text and an -EncodedCommand would drop.
24
+ const _POWERSHELL_TRAILING = '(?=[ \\t]*(?:$|[\\r\\n;|&<>]|\\d+>))';
19
25
  const _POWERSHELL_DOUBLE_RE = new RegExp(
20
26
  '\\b(powershell(?:\\.exe)?|pwsh(?:\\.exe)?)((?:' +
21
27
  _POWERSHELL_FLAGS_RE +
22
- ')*)\\s+(?:-Command|-c)\\s+"((?:[^"\\\\]|\\\\.|"")+?)"(?=\\s|$|;|&&|\\|\\|)',
28
+ ')*)\\s+(?:-Command|-c)\\s+"((?:[^"\\\\]|\\\\.|"")+?)"' +
29
+ _POWERSHELL_TRAILING,
23
30
  'gi'
24
31
  );
25
32
  const _POWERSHELL_SINGLE_RE = new RegExp(
26
33
  '\\b(powershell(?:\\.exe)?|pwsh(?:\\.exe)?)((?:' +
27
34
  _POWERSHELL_FLAGS_RE +
28
- ")*)\\s+(?:-Command|-c)\\s+'((?:[^'\\\\]|\\\\.|'')+?)'(?=\\s|$|;|&&|\\|\\|)",
35
+ ")*)\\s+(?:-Command|-c)\\s+'((?:[^'\\\\]|\\\\.|'')+?)'" +
36
+ _POWERSHELL_TRAILING,
29
37
  'gi'
30
38
  );
31
39
 
32
- export function _maybeEncodePowerShellCommand(command) {
33
- if (process.platform !== 'win32') return command;
34
- if (typeof command !== 'string' || command.length === 0) return command;
35
- const replaceFn = (match, exe, flags, body) => {
40
+ // One pass of one quote style. Only an invocation the outer shell itself runs
41
+ // is rewritten: the same text inside a string, here-string or comment (a
42
+ // README being written, a commit message) is data, not a command.
43
+ function _encodePass(command, pattern, quote) {
44
+ const live = codeMask(command);
45
+ if (!live) return command;
46
+ return command.replace(pattern, (match, exe, flags, body, offset) => {
47
+ if (!live[offset]) return match;
36
48
  try {
37
- // Unescape doubled-up quotes the caller used to embed " / ' inside
38
- // the -Command literal. We're handing the body to powershell as
39
- // base64 so the outer-shell escaping is no longer needed.
40
- // Unescape both PowerShell-style doubled quotes (`""` / `''`) AND
41
- // bash-style backslash-escaped quotes (`\"` / `\'`) since POSIX
42
- // outer-shell wrappers commonly use backslash form. Without
43
- // backslash unescape, `pwsh -Command "Get-Process \"foo\""` would
44
- // base64-encode the literal backslash, breaking inside PowerShell.
45
- const unescaped = _unescapePowerShellCommandBody(body);
49
+ // Unescape the quote the caller used to embed the body: the PowerShell
50
+ // doubled form (`""` / `''`) AND the bash-style backslash form (`\"` /
51
+ // `\'`) POSIX outer-shell wrappers commonly use. Without the backslash
52
+ // unescape, `pwsh -Command "Get-Process \"foo\""` would base64-encode the
53
+ // literal backslash. The OTHER quote is the body's own syntax and stays.
54
+ const unescaped = _unescapePowerShellCommandBody(body, quote);
46
55
  const encoded = Buffer.from(unescaped, 'utf16le').toString('base64');
47
56
  const trimmedFlags = (flags || '').replace(/\s+/g, ' ').trim();
48
57
  return `${exe}${trimmedFlags ? ` ${trimmedFlags}` : ''} -EncodedCommand ${encoded}`;
49
58
  } catch {
50
59
  return match;
51
60
  }
52
- };
53
- return command.replace(_POWERSHELL_DOUBLE_RE, replaceFn).replace(_POWERSHELL_SINGLE_RE, replaceFn);
61
+ });
62
+ }
63
+
64
+ export function _maybeEncodePowerShellCommand(command) {
65
+ if (process.platform !== 'win32') return command;
66
+ if (typeof command !== 'string' || command.length === 0) return command;
67
+ return _encodePass(_encodePass(command, _POWERSHELL_DOUBLE_RE, '"'), _POWERSHELL_SINGLE_RE, "'");
54
68
  }
55
69
 
56
- function _unescapePowerShellCommandBody(body) {
57
- return String(body || '')
58
- .replace(/""/g, '"')
59
- .replace(/''/g, "'")
60
- .replace(/\\"/g, '"')
61
- .replace(/\\'/g, "'");
70
+ // `quote` names the delimiter that wrapped the body, so only its own escapes
71
+ // are removed. Without it (policy scanning, which wants every reading of the
72
+ // body) both styles are removed.
73
+ function _unescapePowerShellCommandBody(body, quote) {
74
+ let text = String(body || '');
75
+ if (quote !== "'") text = text.replace(/""/g, '"').replace(/\\"/g, '"');
76
+ if (quote !== '"') text = text.replace(/''/g, "'").replace(/\\'/g, "'");
77
+ return text;
62
78
  }
63
79
 
64
80
  // Extract inline `powershell -Command "…"` bodies for policy scan parity
@@ -126,11 +126,15 @@ function getSnapshotScript(shellPath, snapshotFilePath, configFileExists) {
126
126
  declare -f "$func" >> "$SNAPSHOT_FILE" 2>/dev/null
127
127
  done
128
128
  `;
129
+ // Options are matched on their state column: a name containing "on"
130
+ // (monitor, onecmd) must not turn an OFF option on. Job control (monitor)
131
+ // is never restored: it gives every pipeline its own process group, which
132
+ // the runner's group kill then cannot reach.
129
133
  const optDump = isZsh
130
- ? `setopt 2>/dev/null | sed 's/^/setopt /' | head -n 1000 >> "$SNAPSHOT_FILE"`
134
+ ? `setopt 2>/dev/null | grep -vxE '(no)?monitor' | sed 's/^/setopt /' | head -n 1000 >> "$SNAPSHOT_FILE"`
131
135
  : `
132
136
  shopt -p 2>/dev/null | head -n 1000 >> "$SNAPSHOT_FILE"
133
- set -o 2>/dev/null | grep "on" | awk '{print "set -o " $1}' | head -n 1000 >> "$SNAPSHOT_FILE"
137
+ set -o 2>/dev/null | awk '$2 == "on" && $1 != "monitor" {print "set -o " $1}' | head -n 1000 >> "$SNAPSHOT_FILE"
134
138
  echo "shopt -s expand_aliases" >> "$SNAPSHOT_FILE"
135
139
  `;
136
140
  const aliasDump = `
@@ -1,30 +1,30 @@
1
1
  {
2
- "version": "0.1.10",
2
+ "version": "0.1.11",
3
3
  "_comment": "Synced from immutable spawn-v release assets.",
4
4
  "assets": {
5
5
  "darwin-arm64": {
6
- "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.10/mixdog-spawn-darwin-arm64",
7
- "sha256": "8c20f4096c08a5159c62b28ada8aaed9d49d18ab21faaa1631e3eadadaadc91c"
6
+ "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.11/mixdog-spawn-darwin-arm64",
7
+ "sha256": "6f1a7e6597dcc8785d12c5a13c42388110d9f4a2e5378ca2773172adbf50de60"
8
8
  },
9
9
  "darwin-x64": {
10
- "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.10/mixdog-spawn-darwin-x64",
11
- "sha256": "a35c66bf5c0121f1202ea69cc22a5804b0587a37929ebf3b66e08ec2b18b6b86"
10
+ "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.11/mixdog-spawn-darwin-x64",
11
+ "sha256": "ff755eb9848cb3ce90f3df24136bb84a52f9ff6c67002c4d764beb6d7906e6b2"
12
12
  },
13
13
  "linux-arm64": {
14
- "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.10/mixdog-spawn-linux-arm64",
15
- "sha256": "463bc8bdb6abe49fd99fee53397365417cb6613ebabbfcd332e6b62fa3e79c37"
14
+ "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.11/mixdog-spawn-linux-arm64",
15
+ "sha256": "3bc0fccde46537046d498a2b953aa92ef4afacc95c96c563ce1d6fb92d74e593"
16
16
  },
17
17
  "linux-x64": {
18
- "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.10/mixdog-spawn-linux-x64",
19
- "sha256": "329a940ae3affc9fa5bcc9e6a48b2f7c8a783900f2de3a952de2422aa60413f5"
18
+ "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.11/mixdog-spawn-linux-x64",
19
+ "sha256": "16dc4e3bf6636335c1325c88bbb5245529731525953466e761d363897b59aac7"
20
20
  },
21
21
  "win32-arm64": {
22
- "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.10/mixdog-spawn-win32-arm64.exe",
23
- "sha256": "a1719d2ea8f87707cb515a5e8e055ed56d6b48f3b717346b0a4ee63d40e562df"
22
+ "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.11/mixdog-spawn-win32-arm64.exe",
23
+ "sha256": "c2fb5499d3d44405e27c79f8db65694299d61ddf029f466df68549fc2f2c5f5c"
24
24
  },
25
25
  "win32-x64": {
26
- "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.10/mixdog-spawn-win32-x64.exe",
27
- "sha256": "ac65bd416d03f9c4e9e65eb04c6455a948551e726f74bd73bb32acbf4bc66d93"
26
+ "url": "https://github.com/tribgames/mixdog/releases/download/spawn-v0.1.11/mixdog-spawn-win32-x64.exe",
27
+ "sha256": "50531a9f033dc22eff3ec5b2a9d10441ffdfac0e50d9acf9047e4f302e5d70d9"
28
28
  }
29
29
  }
30
30
  }
@@ -13,7 +13,10 @@ const ATTR_BOUND = 4096;
13
13
  const ATTRS = `[^<>]{0,${ATTR_BOUND}}`;
14
14
  const A = ATTRS;
15
15
  // A regex built from a raw template; the interpolations are pattern text.
16
- const re = (flags = '') => (strings, ...values) => new RegExp(String.raw(strings, ...values), flags);
16
+ const re =
17
+ (flags = '') =>
18
+ (strings, ...values) =>
19
+ new RegExp(String.raw(strings, ...values), flags);
17
20
  // The patterns the per-cell / per-run loops use are built once.
18
21
  const V_RE = re()`<v(?:\s${A})?>([^<]*)</v>`;
19
22
  const T_RUN_RE = re('g')`<t(?:\s${A})?>([^<]*)</t>`;
@@ -384,16 +387,12 @@ function relationshipList(xml) {
384
387
 
385
388
  function sharedStringTable(xml) {
386
389
  if (!xml) return [];
387
- return [...scanElements(xml, 'si')]
388
- .filter((item) => item.inner !== null)
389
- .map((item) => textRuns(item.inner));
390
+ return [...scanElements(xml, 'si')].filter((item) => item.inner !== null).map((item) => textRuns(item.inner));
390
391
  }
391
392
 
392
393
  // Concatenated <t> character data of one fragment.
393
394
  function textRuns(fragment) {
394
- return [...fragment.matchAll(T_RUN_RE)]
395
- .map(([, text]) => decodeXmlEntities(text))
396
- .join('');
395
+ return [...fragment.matchAll(T_RUN_RE)].map(([, text]) => decodeXmlEntities(text)).join('');
397
396
  }
398
397
 
399
398
  // Excel stores a date as a day count and a percentage as a fraction, so a
@@ -421,7 +420,10 @@ function cellNumberFormats(xml) {
421
420
  if (!xml) return [];
422
421
  const custom = new Map(
423
422
  [...xml.matchAll(re('g')`<numFmt\b(${A}?)/?>`)]
424
- .map(([, attributes]) => [/\bnumFmtId="(\d+)"/.exec(attributes)?.[1], /\bformatCode="([^"<>]*)"/.exec(attributes)?.[1]])
423
+ .map(([, attributes]) => [
424
+ /\bnumFmtId="(\d+)"/.exec(attributes)?.[1],
425
+ /\bformatCode="([^"<>]*)"/.exec(attributes)?.[1],
426
+ ])
425
427
  .filter(([id, code]) => id !== undefined && code !== undefined)
426
428
  .map(([id, code]) => [Number(id), decodeXmlEntities(code)])
427
429
  );
@@ -629,7 +631,7 @@ function relatedPart(target, ownerPart) {
629
631
  const base = String(ownerPart).replace(/\/[^/]+$/, '');
630
632
  const value = String(target).replace(/^\//, '');
631
633
  if (!value.startsWith('..')) return value.startsWith('xl/') ? value : `${base}/${value}`;
632
- return value.replace(/^\.\.\//, `${base.replace(/\/[^/]+$/, '')}/`);
634
+ return value.replace(/^\.\.\//, () => `${base.replace(/\/[^/]+$/, '')}/`);
633
635
  }
634
636
 
635
637
  // A sheet's chart is its message, and it lives outside the cell grid: read as
@@ -15,7 +15,10 @@ const META = '\u2581';
15
15
  // The library's stand-in for SentencePiece's precompiled charsmap.
16
16
  function precompiledNormalize(text) {
17
17
  text = text.replace(/[\u0001-\u0008\u000B\u000E-\u001F\u007F\u008F\u009F]/gm, '');
18
- text = text.replace(/[\u0009\u000A\u000C\u000D\u00A0\u1680\u2000-\u200F\u2028\u2029\u202F\u205F\u2581\u3000\uFEFF\uFFFD]/gm, ' ');
18
+ text = text.replace(
19
+ /[\u0009\u000A\u000C\u000D\u00A0\u1680\u2000-\u200F\u2028\u2029\u202F\u205F\u2581\u3000\uFEFF\uFFFD]/gm,
20
+ ' '
21
+ );
19
22
  return text.includes('\uFF5E')
20
23
  ? text
21
24
  .split('\uFF5E')
@@ -30,9 +33,10 @@ function buildNormalizer(spec) {
30
33
  if (step.type === 'Precompiled') return precompiledNormalize;
31
34
  if (step.type === 'Replace' && step.pattern?.Regex != null) {
32
35
  const re = new RegExp(step.pattern.Regex, 'gu');
33
- return (text) => text.replace(re, step.content);
36
+ return (text) => text.replace(re, () => step.content);
34
37
  }
35
- if (step.type === 'Replace' && step.pattern?.String != null) return (text) => text.replaceAll(step.pattern.String, step.content);
38
+ if (step.type === 'Replace' && step.pattern?.String != null)
39
+ return (text) => text.replaceAll(step.pattern.String, () => step.content);
36
40
  throw new UnsupportedTokenizerError(`unsupported normalizer ${step.type}`);
37
41
  });
38
42
  return (text) => fns.reduce((acc, fn) => fn(acc), text);
@@ -58,18 +62,10 @@ function splitOn(words, text) {
58
62
  return out;
59
63
  }
60
64
 
61
- /** Loads tokenizer.json; throws UnsupportedTokenizerError for any other layout. */
62
- export function loadUnigramTokenizer(tokenizerJsonPath, { maxLength = 512 } = {}) {
63
- const json = JSON.parse(readFileSync(tokenizerJsonPath, 'utf8'));
64
- const model = json.model;
65
- const pre = json.pre_tokenizer;
66
- const template = json.post_processor;
67
- if (model?.type !== 'Unigram') throw new UnsupportedTokenizerError(`unsupported model ${model?.type}`);
68
- if (pre?.type !== 'Metaspace') throw new UnsupportedTokenizerError(`unsupported pre-tokenizer ${pre?.type}`);
69
- if (template?.type !== 'TemplateProcessing') throw new UnsupportedTokenizerError(`unsupported post-processor ${template?.type}`);
70
- const normalize = buildNormalizer(json.normalizer);
71
-
72
- const n = model.vocab.length;
65
+ // Packs the vocabulary into one string pool with typed-array scores and an
66
+ // open-addressing index; `lookup(str, a, b)` returns the id of str[a, b) or -1.
67
+ function buildVocabIndex(vocab) {
68
+ const n = vocab.length;
73
69
  const scores = new Float64Array(n);
74
70
  const offsets = new Int32Array(n + 1);
75
71
  const pieces = [];
@@ -77,7 +73,7 @@ export function loadUnigramTokenizer(tokenizerJsonPath, { maxLength = 512 } = {}
77
73
  let maxChars = 1;
78
74
  let minScore = Infinity;
79
75
  for (let i = 0; i < n; i++) {
80
- const [piece, score] = model.vocab[i];
76
+ const [piece, score] = vocab[i];
81
77
  scores[i] = score;
82
78
  if (score < minScore) minScore = score;
83
79
  offsets[i] = length;
@@ -119,6 +115,21 @@ export function loadUnigramTokenizer(tokenizerJsonPath, { maxLength = 512 } = {}
119
115
  slot = (slot + 1) & mask;
120
116
  }
121
117
  };
118
+ return { scores, minScore, maxChars, lookup };
119
+ }
120
+
121
+ /** Loads tokenizer.json; throws UnsupportedTokenizerError for any other layout. */
122
+ export function loadUnigramTokenizer(tokenizerJsonPath, { maxLength = 512 } = {}) {
123
+ const json = JSON.parse(readFileSync(tokenizerJsonPath, 'utf8'));
124
+ const model = json.model;
125
+ const pre = json.pre_tokenizer;
126
+ const template = json.post_processor;
127
+ if (model?.type !== 'Unigram') throw new UnsupportedTokenizerError(`unsupported model ${model?.type}`);
128
+ if (pre?.type !== 'Metaspace') throw new UnsupportedTokenizerError(`unsupported pre-tokenizer ${pre?.type}`);
129
+ if (template?.type !== 'TemplateProcessing')
130
+ throw new UnsupportedTokenizerError(`unsupported post-processor ${template?.type}`);
131
+ const normalize = buildNormalizer(json.normalizer);
132
+ const { scores, minScore, maxChars, lookup } = buildVocabIndex(model.vocab);
122
133
  const unkId = model.unk_id;
123
134
  const unkScore = minScore - 10;
124
135
  scores[unkId] = unkScore;
@@ -229,8 +240,11 @@ export function loadUnigramTokenizer(tokenizerJsonPath, { maxLength = 512 } = {}
229
240
  return stripAround(splitOn(normalizedAdded, normalized)).flatMap((sub) => {
230
241
  if (sub.length === 0) return [];
231
242
  if (added.has(sub)) return [sub];
232
- let piece = sub.replaceAll(' ', strRep);
233
- if (!piece.startsWith(replacement) && (prependScheme === 'always' || (prependScheme === 'first' && sectionIndex === 0))) {
243
+ let piece = sub.replaceAll(' ', () => strRep);
244
+ if (
245
+ !piece.startsWith(replacement) &&
246
+ (prependScheme === 'always' || (prependScheme === 'first' && sectionIndex === 0))
247
+ ) {
234
248
  piece = strRep + piece;
235
249
  }
236
250
  return fuseUnk(viterbi(piece));
@@ -188,7 +188,7 @@ function runtimeAssetUrlCandidates(url) {
188
188
  .map((repo) => repo.trim())
189
189
  .filter(Boolean);
190
190
  for (const repo of overrides) {
191
- if (repo && repo !== releaseRepo) add(value.replace(`/github.com/${releaseRepo}/`, `/github.com/${repo}/`));
191
+ if (repo && repo !== releaseRepo) add(value.replace(`/github.com/${releaseRepo}/`, () => `/github.com/${repo}/`));
192
192
  }
193
193
  return out;
194
194
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  capLineOrientedToolOutput,
3
+ capMarker,
3
4
  RECALL_OUTPUT_MAX_BYTES,
4
5
  } from '../../agent/orchestrator/tools/builtin/tool-output-limit.mjs';
5
6
 
@@ -8,11 +9,12 @@ import {
8
9
  // footer, so a huge multi-query/grouped browse cannot flood the caller's
9
10
  // context (42KB single-call observed before the cap).
10
11
  function capRecallText(text) {
11
- return capLineOrientedToolOutput(
12
- text,
13
- RECALL_OUTPUT_MAX_BYTES,
14
- (kept, lines) =>
15
- `... [recall output capped at ${Math.round(RECALL_OUTPUT_MAX_BYTES / 1024)}KB after ${kept.length} of ${lines.length} lines; narrow query[]/category/period or page with the returned cursor]`
12
+ return capLineOrientedToolOutput(text, RECALL_OUTPUT_MAX_BYTES, (kept, lines) =>
13
+ capMarker({
14
+ limit: RECALL_OUTPUT_MAX_BYTES,
15
+ shown: `${kept.length} of ${lines.length} lines shown`,
16
+ narrow: 'narrow query[]/category/period, lower limit, or page with the cursor/offset shown in the results',
17
+ })
16
18
  );
17
19
  }
18
20
 
@@ -135,7 +135,9 @@ async function giveNotesMasterOwnTheme(zip) {
135
135
  await ensureContentTypeOverride(zip, `/${own}`, THEME_TYPE);
136
136
  zip.file(
137
137
  relsPath,
138
- rels.replace(theme.tag, theme.tag.replace(/\bTarget="[^"]+"/, `Target="../theme/${posix.basename(own)}"`))
138
+ rels.replace(theme.tag, () =>
139
+ theme.tag.replace(/\bTarget="[^"]+"/, () => `Target="../theme/${posix.basename(own)}"`)
140
+ )
139
141
  );
140
142
  return true;
141
143
  }
@@ -269,8 +271,8 @@ export function normalizeChartFonts(xml) {
269
271
  const txPr = `<c:txPr><a:bodyPr/><a:lstStyle/><a:p><a:pPr><a:defRPr><a:latin typeface="${face}"/><a:ea typeface="${face}"/><a:cs typeface="${face}"/></a:defRPr></a:pPr><a:endParaRPr lang="en-US"/></a:p></c:txPr>`;
270
272
  // Schema order after </c:chart>: c:spPr?, c:txPr?, c:externalData?, …
271
273
  if (/<\/c:chart>\s*<c:spPr>[\s\S]*?<\/c:spPr>/.test(output))
272
- output = output.replace(/(<\/c:chart>\s*<c:spPr>[\s\S]*?<\/c:spPr>)/, `$1${txPr}`);
273
- else output = output.replace('</c:chart>', `</c:chart>${txPr}`);
274
+ output = output.replace(/(<\/c:chart>\s*<c:spPr>[\s\S]*?<\/c:spPr>)/, (__m, __1) => `${__1}${txPr}`);
275
+ else output = output.replace('</c:chart>', () => `</c:chart>${txPr}`);
274
276
  changed += 1;
275
277
  }
276
278
  return { xml: output, changed, face };
@@ -323,11 +325,11 @@ export function nativeGradients(xml) {
323
325
  // Schema order inside spPr: xfrm, geometry, fill, ln, effects — the fill is swapped in place and the
324
326
  // outline becomes none, so a gradient never shows a solid rim of its first stop.
325
327
  let inner = SHAPE_FILL.test(properties)
326
- ? properties.replace(SHAPE_FILL, fill)
327
- : properties.replace(/(<\/a:prstGeom>|<a:prstGeom\b[^>]*\/>|<\/a:custGeom>)/, `$1${fill}`);
328
+ ? properties.replace(SHAPE_FILL, () => fill)
329
+ : properties.replace(/(<\/a:prstGeom>|<a:prstGeom\b[^>]*\/>|<\/a:custGeom>)/, (__m, __1) => `${__1}${fill}`);
328
330
  inner = SHAPE_LINE.test(inner)
329
331
  ? inner.replace(SHAPE_LINE, '<a:ln><a:noFill/></a:ln>')
330
- : inner.replace(fill, `${fill}<a:ln><a:noFill/></a:ln>`);
332
+ : inner.replace(fill, () => `${fill}<a:ln><a:noFill/></a:ln>`);
331
333
  return inner;
332
334
  });
333
335
  });
@@ -380,12 +382,13 @@ async function attachSvgIcons(zip, slidePart, xml) {
380
382
  const id = nextRelationshipId(relationships);
381
383
  relationships = relationships.replace(
382
384
  '</Relationships>',
383
- `<Relationship Id="${id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/${mediaName.split('/').pop()}"/></Relationships>`
385
+ () =>
386
+ `<Relationship Id="${id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/${mediaName.split('/').pop()}"/></Relationships>`
384
387
  );
385
388
  const extension = `<a:extLst><a:ext uri="${SVG_EXTENSION_URI}"><asvg:svgBlip xmlns:asvg="${SVG_NAMESPACE}" r:embed="${id}"/></a:ext></a:extLst>`;
386
389
  const withSvg = blip.endsWith('/>')
387
390
  ? `${blip.slice(0, -2)}>${extension}</a:blip>`
388
- : blip.replace('</a:blip>', `${extension}</a:blip>`);
391
+ : blip.replace('</a:blip>', () => `${extension}</a:blip>`);
389
392
  output = output.replace(picture, () =>
390
393
  picture.replace(blip, () => withSvg).replace(/(<p:cNvPr\b[^>]*\bname=)"[^"]*"/, '$1"Icon"')
391
394
  );
@@ -236,7 +236,7 @@ export async function applyTabularBatch(path, format, operations) {
236
236
  const before = String(row[column]);
237
237
  if (!find || !before.includes(find)) continue;
238
238
  count += before.split(find).length - 1;
239
- row[column] = before.replaceAll(find, String(operation.replace ?? ''));
239
+ row[column] = before.replaceAll(find, () => String(operation.replace ?? ''));
240
240
  }
241
241
  }
242
242
  results.push({ op, changed: count > 0, count });
@@ -82,7 +82,10 @@ export async function pptxSlideEntries(zip) {
82
82
 
83
83
  function xmlSetAttribute(source, name, value) {
84
84
  const escaped = String(name).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
85
- return String(source).replace(new RegExp(`(\\b${escaped}=")[^"]*(")`, 'i'), `$1${String(value)}$2`);
85
+ return String(source).replace(
86
+ new RegExp(`(\\b${escaped}=")[^"]*(")`, 'i'),
87
+ (__m, __1, __2) => `${__1}${String(value)}${__2}`
88
+ );
86
89
  }
87
90
 
88
91
  function relationshipType(block, suffix) {
@@ -93,7 +96,7 @@ function ensureContentTypeOverride(xml, partName, contentType) {
93
96
  if (!xml || new RegExp(`\\bPartName="${String(partName).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"`, 'i').test(xml)) {
94
97
  return xml;
95
98
  }
96
- return xml.replace(/<\/Types>/i, `<Override PartName="${partName}" ContentType="${contentType}"/></Types>`);
99
+ return xml.replace(/<\/Types>/i, () => `<Override PartName="${partName}" ContentType="${contentType}"/></Types>`);
97
100
  }
98
101
 
99
102
  const RELATIONSHIP_BLOCK = /<(?:\w+:)?Relationship\b[^>]*\/?>/gi;
@@ -150,7 +153,7 @@ function presentationWithSlideList(presentationXml, relationshipIds) {
150
153
  if (!slideListMatch) throw new Error('PPTX presentation slide list is missing');
151
154
  const prefix = slideListMatch[1] || '';
152
155
  const slideIds = relationshipIds.map((id, index) => `<${prefix}sldId id="${256 + index}" r:id="${id}"/>`).join('');
153
- return presentationXml.replace(slideListPattern, `<${prefix}sldIdLst>${slideIds}</${prefix}sldIdLst>`);
156
+ return presentationXml.replace(slideListPattern, () => `<${prefix}sldIdLst>${slideIds}</${prefix}sldIdLst>`);
154
157
  }
155
158
 
156
159
  function presentationRelationshipsWithSlides(relationshipsXml, relationshipIds) {
@@ -162,7 +165,7 @@ function presentationRelationshipsWithSlides(relationshipsXml, relationshipIds)
162
165
  .join('');
163
166
  return relationshipsXml
164
167
  .replace(RELATIONSHIP_BLOCK, (block) => (relationshipType(block, 'slide') ? '' : block))
165
- .replace(/<\/Relationships>/i, `${slideRelationships}</Relationships>`);
168
+ .replace(/<\/Relationships>/i, () => `${slideRelationships}</Relationships>`);
166
169
  }
167
170
 
168
171
  // Writes one selected slide (and its notes) under its new ordinal, retargeting
@@ -73,7 +73,7 @@ export function patchParagraphFormat(xml, properties, numbering = null) {
73
73
  // opened in its place first, so the patch lands inside the schema's order rather than ahead of the style's name.
74
74
  function openStyleProperties(styleXml, tag) {
75
75
  if (new RegExp(`<w:${tag}(?:\\s[^>]*)?(?:/>|>)`).test(styleXml)) {
76
- return styleXml.replace(new RegExp(`<w:${tag}(?:\\s[^>]*)?/>`), `<w:${tag}></w:${tag}>`);
76
+ return styleXml.replace(new RegExp(`<w:${tag}(?:\\s[^>]*)?/>`), () => `<w:${tag}></w:${tag}>`);
77
77
  }
78
78
  const before = tag === 'pPr' ? /<w:(?:rPr|tblPr|trPr|tcPr|tblStylePr)\b/ : /<w:(?:tblPr|trPr|tcPr|tblStylePr)\b/;
79
79
  const at = before.exec(styleXml)?.index ?? styleXml.lastIndexOf('</w:style>');
@@ -205,7 +205,7 @@ function resolveDocxRowMarks(documentXml, { resolution = 'accept', author = '' }
205
205
  continue;
206
206
  }
207
207
  const clearedProperties = properties.replace(marker('del', author), '').replace(marker('ins', author), '');
208
- xml = `${xml.slice(0, row.start)}${rowXml.replace(properties, clearedProperties)}${xml.slice(row.end)}`;
208
+ xml = `${xml.slice(0, row.start)}${rowXml.replace(properties, () => clearedProperties)}${xml.slice(row.end)}`;
209
209
  cleared += 1;
210
210
  }
211
211
  xml = xml.replace(
@@ -12,8 +12,8 @@ export function trackedParagraphRewrite(paragraphXml, text, id, author) {
12
12
  const properties = /<w:r(?:\s[^>]*)?>\s*(<w:rPr(?:\s[^>]*)?>[\s\S]*?<\/w:rPr>)/.exec(paragraphXml)?.[1] || '';
13
13
  const deleted = markRunsDeleted(paragraphXml, id, author);
14
14
  const inserted = `<w:ins ${revisionAttributes(id + runCount, author)}><w:r>${properties}${wordTextContent(text, { preserve: true })}</w:r></w:ins>`;
15
- if (/<\/w:p>\s*$/.test(deleted)) return deleted.replace(/<\/w:p>\s*$/, `${inserted}</w:p>`);
16
- if (/\/>\s*$/.test(deleted)) return deleted.replace(/\/>\s*$/, `>${inserted}</w:p>`);
15
+ if (/<\/w:p>\s*$/.test(deleted)) return deleted.replace(/<\/w:p>\s*$/, () => `${inserted}</w:p>`);
16
+ if (/\/>\s*$/.test(deleted)) return deleted.replace(/\/>\s*$/, () => `>${inserted}</w:p>`);
17
17
  throw new Error('DOCX paragraph is malformed');
18
18
  }
19
19