mixdog 1.2.5 → 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 (290) 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/provider-pingpong-live.mjs +9 -9
  5. package/src/agents/advisor/AGENT.md +4 -4
  6. package/src/agents/advisor/agent.json +1 -1
  7. package/src/agents/reviewer/AGENT.md +2 -3
  8. package/src/agents/reviewer/agent.json +1 -1
  9. package/src/defaults/shipped-history.json +10 -0
  10. package/src/defaults/skills/browser-use/SKILL.md +2 -1
  11. package/src/defaults/skills/computer-use/SKILL.md +3 -1
  12. package/src/defaults/skills/visualize/SKILL.md +3 -2
  13. package/src/lib/rules-builder.cjs +1 -1
  14. package/src/output-styles/common.md +22 -6
  15. package/src/output-styles/detailed.md +7 -5
  16. package/src/output-styles/minimal.md +7 -3
  17. package/src/output-styles/simple.md +2 -3
  18. package/src/rules/agent/AGENT.md +3 -1
  19. package/src/rules/lead/LEAD.md +4 -3
  20. package/src/rules/shared/10-tool-workflow.md +2 -1
  21. package/src/rules/shared/60-verification.md +4 -5
  22. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
  23. package/src/runtime/agent/orchestrator/config.mjs +6 -0
  24. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +1 -1
  25. package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
  26. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +53 -60
  27. package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
  28. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
  29. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +40 -19
  31. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
  32. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
  33. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
  34. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
  35. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
  36. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
  37. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +1 -2
  38. package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
  39. package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
  40. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
  41. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
  42. package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
  43. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
  44. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
  45. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  46. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
  47. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  48. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  49. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
  50. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
  51. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
  52. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  53. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
  54. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  55. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
  56. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
  57. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
  58. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
  59. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
  60. package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
  61. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
  62. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
  63. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
  64. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
  65. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
  66. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
  67. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
  68. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
  69. package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
  70. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +2 -3
  71. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +3 -8
  72. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
  73. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
  74. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
  75. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
  76. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
  77. package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
  78. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
  79. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +9 -19
  80. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -3
  81. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -0
  82. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
  83. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
  84. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
  85. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
  86. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
  87. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
  88. package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
  89. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
  90. package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
  91. package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
  92. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
  93. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
  94. package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
  95. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
  96. package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
  97. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
  98. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +306 -0
  99. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +70 -21
  100. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
  101. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
  102. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
  103. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
  104. package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
  105. package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
  106. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
  107. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
  108. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
  109. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
  111. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
  112. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
  113. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
  114. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
  115. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
  116. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
  117. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
  118. package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
  119. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
  120. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
  121. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
  122. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
  123. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
  124. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
  125. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
  126. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
  127. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
  128. package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
  129. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
  130. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
  131. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
  132. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
  133. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
  134. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
  135. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
  136. package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
  137. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +119 -32
  138. package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
  139. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
  140. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
  141. package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
  142. package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
  143. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
  144. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
  145. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
  146. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  147. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
  148. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +40 -2
  149. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -2
  150. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
  151. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +3 -1
  153. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
  154. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +35 -4
  155. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
  156. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
  157. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
  158. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  159. package/src/runtime/attachments/office-extract.mjs +11 -9
  160. package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
  161. package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
  162. package/src/runtime/memory/lib/tool-call-handler.mjs +7 -5
  163. package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
  164. package/src/runtime/office/core/tabular.mjs +1 -1
  165. package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
  166. package/src/runtime/office/portable/docx-formatting.mjs +1 -1
  167. package/src/runtime/office/portable/docx-runs.mjs +1 -1
  168. package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
  169. package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
  170. package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
  171. package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
  172. package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
  173. package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
  174. package/src/runtime/office/portable/portable-opc.mjs +27 -13
  175. package/src/runtime/office/portable/portable-pivot.mjs +3 -3
  176. package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
  177. package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
  178. package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
  179. package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
  180. package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
  181. package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
  182. package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
  183. package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
  184. package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
  185. package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
  186. package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
  187. package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
  188. package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
  189. package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
  190. package/src/runtime/office/portable/portable-xml.mjs +1 -1
  191. package/src/runtime/shared/atomic-file.mjs +22 -13
  192. package/src/runtime/shared/background-tasks.mjs +60 -20
  193. package/src/runtime/shared/child-spawn-gate.mjs +26 -16
  194. package/src/runtime/shared/config.mjs +0 -10
  195. package/src/runtime/shared/file-lock.mjs +7 -1
  196. package/src/runtime/shared/file-permissions-worker.mjs +38 -0
  197. package/src/runtime/shared/file-permissions.d.mts +19 -4
  198. package/src/runtime/shared/file-permissions.mjs +310 -4
  199. package/src/runtime/shared/git-runner-worker.mjs +6 -78
  200. package/src/runtime/shared/llm/http-agent.mjs +7 -3
  201. package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
  202. package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
  203. package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
  204. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
  205. package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
  206. package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
  207. package/src/runtime/shared/memory-snapshot.mjs +5 -1
  208. package/src/runtime/shared/notify-trace.mjs +8 -1
  209. package/src/runtime/shared/pristine-execution-contract.json +5 -1
  210. package/src/runtime/shared/process-runner-worker.mjs +7 -0
  211. package/src/runtime/shared/process-runner.mjs +38 -0
  212. package/src/runtime/shared/provider-accounts.mjs +2 -1
  213. package/src/runtime/shared/provider-api-key.mjs +0 -1
  214. package/src/runtime/shared/read-row-numbers.mjs +1 -1
  215. package/src/runtime/shared/resource-admission.mjs +60 -18
  216. package/src/runtime/shared/run-child.mjs +84 -0
  217. package/src/runtime/shared/session-activity-signal.mjs +23 -0
  218. package/src/runtime/shared/shell-output-summary.mjs +23 -0
  219. package/src/runtime/shared/singleton-owner.mjs +126 -42
  220. package/src/runtime/shared/tool-output-limit.mjs +4 -2
  221. package/src/runtime/shared/tool-output-marker.mjs +58 -0
  222. package/src/runtime/shared/user-data-guard.mjs +28 -9
  223. package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
  224. package/src/runtime/shared/worktrees/git-head.mjs +20 -2
  225. package/src/runtime/shared/worktrees/lock.mjs +3 -2
  226. package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
  227. package/src/runtime/tidy/runners/biome.mjs +3 -1
  228. package/src/runtime/tidy/shadow.mjs +2 -1
  229. package/src/runtime/web-search/index.mjs +5 -7
  230. package/src/runtime/web-search/lib/formatter.mjs +42 -6
  231. package/src/runtime/web-search/tool-defs.mjs +6 -1
  232. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
  233. package/src/session-runtime/lifecycle/session-switch/resume.mjs +7 -4
  234. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
  235. package/src/session-runtime/lifecycle/shared.mjs +19 -2
  236. package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
  237. package/src/session-runtime/lifecycle/teardown.mjs +5 -2
  238. package/src/session-runtime/lifecycle-api.mjs +3 -1
  239. package/src/session-runtime/provider-auth/login.mjs +10 -6
  240. package/src/session-runtime/provider-auth/setup.mjs +19 -2
  241. package/src/session-runtime/provider-catalog-cache.mjs +101 -25
  242. package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
  243. package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
  244. package/src/session-runtime/provider-models.mjs +76 -10
  245. package/src/session-runtime/provider-readiness.mjs +4 -0
  246. package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
  247. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
  248. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
  249. package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
  250. package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
  251. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
  252. package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
  253. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
  254. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
  255. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
  256. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
  257. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
  258. package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
  259. package/src/session-runtime/services/agent-tool.mjs +20 -0
  260. package/src/session-runtime/services/provider-admin.mjs +92 -20
  261. package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
  262. package/src/session-runtime/services/usage-dashboard.mjs +27 -69
  263. package/src/session-runtime/turn/session-ops.mjs +2 -2
  264. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  265. package/src/session-runtime/usage-stats-api.mjs +6 -1
  266. package/src/standalone/channel-transport/http-routes.mjs +10 -9
  267. package/src/standalone/daemon-desktop-runtime.mjs +20 -7
  268. package/src/standalone/daemon-owner.mjs +117 -25
  269. package/src/standalone/daemon.mjs +43 -13
  270. package/src/standalone/session-call-cache.mjs +6 -0
  271. package/src/standalone/session-protocol.mjs +1 -1
  272. package/src/standalone/session-service/retention/busy.mjs +7 -2
  273. package/src/standalone/session-transport/routes.mjs +7 -6
  274. package/src/tui/app/model-options.mjs +39 -2
  275. package/src/tui/app/model-picker.mjs +16 -2
  276. package/src/tui/app/provider-setup-picker.mjs +1 -2
  277. package/src/tui/dist/index.mjs +385 -104
  278. package/src/tui/session/notice-text.mjs +0 -1
  279. package/src/tui/session/session-api/intake/submission.mjs +7 -13
  280. package/src/tui/session/session-api/integrations.mjs +1 -5
  281. package/src/tui/session/session-flow/drain.mjs +8 -0
  282. package/src/tui/session/session-flow/steering.mjs +46 -0
  283. package/src/tui/session/session-flow.mjs +2 -0
  284. package/src/tui/session/turn-stream.mjs +33 -0
  285. package/src/tui/session/turn.mjs +30 -3
  286. package/src/ui/statusline.mjs +1 -6
  287. package/src/ui/streaming-markdown-heal.mjs +24 -7
  288. package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
  289. package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
  290. package/src/workflows/default/WORKFLOW.md +9 -13
@@ -180,7 +180,7 @@ async function appendComment(zip, comments, op, text, thread = {}) {
180
180
  const stamps = commentStamps();
181
181
  zip.file(
182
182
  comments.part,
183
- comments.xml.replace('</w:comments>', `${commentEntryXml(id, op, text, stamps.local)}</w:comments>`)
183
+ comments.xml.replace('</w:comments>', () => `${commentEntryXml(id, op, text, stamps.local)}</w:comments>`)
184
184
  );
185
185
  await registerCommentThread(zip, { commentId: id, ...thread });
186
186
  await registerCommentIdentity(zip, { commentId: id, date: stamps.utc });
@@ -363,7 +363,7 @@ export async function setDocxParagraphStyle(zip, op) {
363
363
  let nextParagraph = paragraph.xml;
364
364
  if (/<w:pPr(?:\s[^>]*)?>/.test(nextParagraph)) {
365
365
  if (/<w:pStyle\b[^>]*\/>/.test(nextParagraph)) {
366
- nextParagraph = nextParagraph.replace(/<w:pStyle\b[^>]*\/>/, `<w:pStyle w:val="${style}"/>`);
366
+ nextParagraph = nextParagraph.replace(/<w:pStyle\b[^>]*\/>/, () => `<w:pStyle w:val="${style}"/>`);
367
367
  } else {
368
368
  nextParagraph = nextParagraph.replace(/<w:pPr(?:\s[^>]*)?>/, (open) => `${open}<w:pStyle w:val="${style}"/>`);
369
369
  }
@@ -412,17 +412,18 @@ export async function setDocxTableCell(zip, op, { tracking }) {
412
412
  if (first) {
413
413
  nextCell = cell[0].replace(
414
414
  '</w:tc>',
415
- `<w:p><w:ins ${revisionAttributes(id, op.author)}><w:r>` +
415
+ () =>
416
+ `<w:p><w:ins ${revisionAttributes(id, op.author)}><w:r>` +
416
417
  `${wordTextContent(op.text, { preserve: true })}</w:r></w:ins></w:p></w:tc>`
417
418
  );
418
419
  }
419
420
  } else if (textNodes(cell[0], 'w:t').length) {
420
421
  nextCell = withFirstRunText(cell[0], op.text);
421
422
  } else {
422
- nextCell = cell[0].replace('</w:tc>', `<w:p><w:r>${wordTextContent(op.text)}</w:r></w:p></w:tc>`);
423
+ nextCell = cell[0].replace('</w:tc>', () => `<w:p><w:r>${wordTextContent(op.text)}</w:r></w:p></w:tc>`);
423
424
  }
424
- const nextRow = row[0].replace(cell[0], nextCell);
425
- const nextTable = table[0].replace(row[0], nextRow);
425
+ const nextRow = row[0].replace(cell[0], () => nextCell);
426
+ const nextTable = table[0].replace(row[0], () => nextRow);
426
427
  zip.file(
427
428
  DOCUMENT_PART,
428
429
  `${current.slice(0, table.index)}${nextTable}${current.slice(table.index + table[0].length)}`
@@ -548,7 +549,7 @@ export async function editDocxTableRowsOrColumns(zip, op) {
548
549
  const blank = blankTableCells(template[0]);
549
550
  nextTable =
550
551
  position > rows.length
551
- ? table[0].replace(/<\/w:tbl>$/, `${blank}</w:tbl>`)
552
+ ? table[0].replace(/<\/w:tbl>$/, () => `${blank}</w:tbl>`)
552
553
  : `${table[0].slice(0, template.index)}${blank}${table[0].slice(template.index)}`;
553
554
  }
554
555
  } else {
@@ -633,7 +634,7 @@ export async function addDocxHyperlink(zip, op) {
633
634
  } else if (op.paragraph) {
634
635
  const model = docxBodyModel(current);
635
636
  const paragraph = bodyParagraphAt(model, op.paragraph);
636
- const nextParagraph = paragraph.xml.replace(/<\/w:p>$/, `${link}</w:p>`);
637
+ const nextParagraph = paragraph.xml.replace(/<\/w:p>$/, () => `${link}</w:p>`);
637
638
  current = replaceBodyParagraph(current, model, paragraph, nextParagraph);
638
639
  anchor = 'paragraph';
639
640
  } else {
@@ -788,7 +789,7 @@ export async function addDocxBookmark(zip, op) {
788
789
  const opening = /^<w:p(?:\s[^>]*)?>(?:<w:pPr(?:\s[^>]*)?>[\s\S]*?<\/w:pPr>)?/.exec(paragraph.xml)?.[0] || '<w:p>';
789
790
  const marked =
790
791
  `${opening}<w:bookmarkStart w:id="${id}" w:name="${xmlEncode(name)}"/>` +
791
- `${paragraph.xml.slice(opening.length)}`.replace(/<\/w:p>$/, `<w:bookmarkEnd w:id="${id}"/></w:p>`);
792
+ `${paragraph.xml.slice(opening.length)}`.replace(/<\/w:p>$/, () => `<w:bookmarkEnd w:id="${id}"/></w:p>`);
792
793
  zip.file(DOCUMENT_PART, replaceBodyParagraph(current, model, paragraph, marked));
793
794
  return { op: op.op, changed: true, name, bookmark: id };
794
795
  }
@@ -837,7 +838,7 @@ export async function setDocxHeaderFooter(zip, op) {
837
838
 
838
839
  // A separator says the number stands against the total ("3 / 12"): asked for with separator:' / ' and no
839
840
  // includeTotal, the footer printed "3" alone. includeTotal:false still keeps the number alone.
840
- export function pageNumbersIncludeTotal(op) {
841
+ function pageNumbersIncludeTotal(op) {
841
842
  return op.includeTotal === true || (op.includeTotal !== false && Boolean(String(op.separator ?? '').trim()));
842
843
  }
843
844
 
@@ -82,15 +82,15 @@ const PARAGRAPH_MARK_ID_OFFSET = 900;
82
82
  // place ahead of the deletion that rejects it.
83
83
  function withParagraphMarkRevision(paragraphXml, mark) {
84
84
  if (!/<w:pPr(?:\s[^>]*)?>/.test(paragraphXml)) {
85
- return paragraphXml.replace(/^(<w:p(?:\s[^>]*)?>)/, `$1<w:pPr><w:rPr>${mark}</w:rPr></w:pPr>`);
85
+ return paragraphXml.replace(/^(<w:p(?:\s[^>]*)?>)/, (__m, __1) => `${__1}<w:pPr><w:rPr>${mark}</w:rPr></w:pPr>`);
86
86
  }
87
87
  if (/<w:rPr(?:\s[^>]*)?>[\s\S]*?<\/w:rPr>\s*<\/w:pPr>/.test(paragraphXml)) {
88
88
  return paragraphXml.replace(
89
89
  /(<w:rPr(?:\s[^>]*)?>)((?:<w:ins\b[^>]*\/>|<w:ins\b[^>]*>[\s\S]*?<\/w:ins>)?)/,
90
- `$1$2${mark}`
90
+ (__m, __1, __2) => `${__1}${__2}${mark}`
91
91
  );
92
92
  }
93
- return paragraphXml.replace(/<\/w:pPr>/, `<w:rPr>${mark}</w:rPr></w:pPr>`);
93
+ return paragraphXml.replace(/<\/w:pPr>/, () => `<w:rPr>${mark}</w:rPr></w:pPr>`);
94
94
  }
95
95
 
96
96
  export function docxTocEntries(documentXml, lower, upper, headingLevels = new Map()) {
@@ -328,7 +328,10 @@ export async function addDocxNote(zip, op) {
328
328
  `<w:r><w:rPr><w:rStyle w:val="${definition.style}"/>${faces}<w:vertAlign w:val="superscript"/></w:rPr>` +
329
329
  `<w:${definition.reference === 'w:footnoteReference' ? 'footnoteRef' : 'endnoteRef'}/></w:r>` +
330
330
  `<w:r>${noteRun}<w:t xml:space="preserve"> ${xmlEncode(text)}</w:t></w:r></w:p></${definition.tag}>`;
331
- zip.file(definition.part, definition.xml.replace(`</${definition.root}>`, `${entry}</${definition.root}>`));
331
+ zip.file(
332
+ definition.part,
333
+ definition.xml.replace(`</${definition.root}>`, () => `${entry}</${definition.root}>`)
334
+ );
332
335
  // The mark belongs right after the phrase it cites; a phrase split across
333
336
  // a tab, field, or drawing falls back to the end of its paragraph.
334
337
  const mark =
@@ -336,7 +339,7 @@ export async function addDocxNote(zip, op) {
336
339
  `<${definition.reference} w:id="${id}"/></w:r>`;
337
340
  const cited = find ? wholeWordPhrase(paragraphTexts(paragraph.xml, 'w:t').join(''), find) : '';
338
341
  const phrase = cited ? anchorPhraseInParagraph(paragraph.xml, cited, id, { start: '', end: mark }) : null;
339
- const anchored = phrase || paragraph.xml.replace(/<\/w:p>$/, `${mark}</w:p>`);
342
+ const anchored = phrase || paragraph.xml.replace(/<\/w:p>$/, () => `${mark}</w:p>`);
340
343
  const nextInner = `${model.body.inner.slice(0, paragraph.start)}${anchored}${model.body.inner.slice(paragraph.end)}`;
341
344
  current = `${current.slice(0, model.body.start)}${nextInner}${current.slice(model.body.end)}`;
342
345
  zip.file('word/document.xml', current);
@@ -388,7 +391,7 @@ export async function setDocxDocumentFont(zip, op) {
388
391
  }
389
392
 
390
393
  // The fields one style takes in define_styles: its face, size, weight, ink, and its paragraph's flow.
391
- export const DOCX_STYLE_FIELDS = Object.freeze([
394
+ const DOCX_STYLE_FIELDS = Object.freeze([
392
395
  'name',
393
396
  'nameEastAsia',
394
397
  'size',
@@ -608,7 +611,7 @@ export async function fitDocxTable(zip, op) {
608
611
  let nextTable = grid
609
612
  ? table[0].replace(
610
613
  grid[0],
611
- `<w:tblGrid>${widths.map((width) => `<w:gridCol w:w="${width}"/>`).join('')}</w:tblGrid>`
614
+ () => `<w:tblGrid>${widths.map((width) => `<w:gridCol w:w="${width}"/>`).join('')}</w:tblGrid>`
612
615
  )
613
616
  : table[0];
614
617
  const declared = `<w:tblW w:w="${usable}" w:type="dxa"/>`;
@@ -616,9 +619,9 @@ export async function fitDocxTable(zip, op) {
616
619
  ? wordTableProperties(op.properties)
617
620
  : /<w:tblPr>([\s\S]*?)<\/w:tblPr>/.exec(nextTable)?.[1] || '';
618
621
  if (/<w:tblW\b[^>]*\/>/.test(tableProperties)) {
619
- tableProperties = tableProperties.replace(/<w:tblW\b[^>]*\/>/, declared);
622
+ tableProperties = tableProperties.replace(/<w:tblW\b[^>]*\/>/, () => declared);
620
623
  } else if (/<w:tblStyle\b[^>]*\/>/.test(tableProperties)) {
621
- tableProperties = tableProperties.replace(/(<w:tblStyle\b[^>]*\/>)/, `$1${declared}`);
624
+ tableProperties = tableProperties.replace(/(<w:tblStyle\b[^>]*\/>)/, (__m, __1) => `${__1}${declared}`);
622
625
  } else {
623
626
  tableProperties = `${declared}${tableProperties}`;
624
627
  }
@@ -640,7 +643,10 @@ function controlFilledWith(control, contentInner, text) {
640
643
  ? `${/^<w:p(?:\s[^>]*)?>(?:<w:pPr(?:\s[^>]*)?>[\s\S]*?<\/w:pPr>)?/.exec(firstParagraph)?.[0] || '<w:p>'}${run}</w:p>`
641
644
  : run;
642
645
  const cleaned = control.replace(/<w:showingPlcHdr\b[^>]*\/>/g, '');
643
- return cleaned.replace(/<w:sdtContent\b[^>]*>[\s\S]*?<\/w:sdtContent>/, `<w:sdtContent>${paragraph}</w:sdtContent>`);
646
+ return cleaned.replace(
647
+ /<w:sdtContent\b[^>]*>[\s\S]*?<\/w:sdtContent>/,
648
+ () => `<w:sdtContent>${paragraph}</w:sdtContent>`
649
+ );
644
650
  }
645
651
 
646
652
  /** Fills one named or numbered content control, in the body, a header, or a footer. */
@@ -712,8 +718,8 @@ function paragraphWithText(paragraph, op) {
712
718
  if (!nodes.length) {
713
719
  if (op.op === 'set_run_text') throw new Error(`DOCX paragraph ${op.paragraph} has no editable text`);
714
720
  const run = `<w:r>${wordTextContent(op.text, { preserve: true })}</w:r>`;
715
- if (/<\/w:p>\s*$/.test(paragraph.xml)) return paragraph.xml.replace(/<\/w:p>\s*$/, `${run}</w:p>`);
716
- if (/\/>\s*$/.test(paragraph.xml)) return paragraph.xml.replace(/\/>\s*$/, `>${run}</w:p>`);
721
+ if (/<\/w:p>\s*$/.test(paragraph.xml)) return paragraph.xml.replace(/<\/w:p>\s*$/, () => `${run}</w:p>`);
722
+ if (/\/>\s*$/.test(paragraph.xml)) return paragraph.xml.replace(/\/>\s*$/, () => `>${run}</w:p>`);
717
723
  throw new Error(`DOCX paragraph ${op.paragraph} is malformed`);
718
724
  }
719
725
  if (op.op === 'set_run_text') {
@@ -852,8 +858,7 @@ function mergedDocxTable({ table, rows, row, cells }, op) {
852
858
  );
853
859
  return `${rowXml.slice(0, joined[0].index)}${merged}${rowXml.slice(end)}`;
854
860
  };
855
- let nextTable = table[0].replace(
856
- row[0],
861
+ let nextTable = table[0].replace(row[0], () =>
857
862
  mergeRow(row[0], cells, `${gridSpan}${rowSpan > 1 ? '<w:vMerge w:val="restart"/>' : ''}`)
858
863
  );
859
864
  if (rowSpan > 1) {
@@ -862,8 +867,7 @@ function mergedDocxTable({ table, rows, row, cells }, op) {
862
867
  if (!continuationRow) break;
863
868
  const continuationCells = rowCellMatches(continuationRow[0]);
864
869
  if (!continuationCells[first]) continue;
865
- nextTable = nextTable.replace(
866
- continuationRow[0],
870
+ nextTable = nextTable.replace(continuationRow[0], () =>
867
871
  mergeRow(continuationRow[0], continuationCells, `${gridSpan}<w:vMerge/>`)
868
872
  );
869
873
  }
@@ -883,7 +887,7 @@ export async function styleOrMergeDocxTableCell(zip, op) {
883
887
  if (!cell) throw missingDocxCellError(op, cells);
884
888
  const nextTable =
885
889
  op.op === 'set_table_cell_style'
886
- ? table[0].replace(cell[0], styledDocxCell(cell[0], op))
890
+ ? table[0].replace(cell[0], () => styledDocxCell(cell[0], op))
887
891
  : mergedDocxTable({ table, rows, row, cells }, op);
888
892
  current = replaceDocxTable(current, table, nextTable);
889
893
  zip.file('word/document.xml', current);
@@ -121,7 +121,7 @@ const sectionChildRank = (tag) => SECTION_CHILD_ORDER.indexOf(tag === 'footerRef
121
121
  /** Replaces the section's own tag element, or writes it ahead of the first child the schema places after it. */
122
122
  export function upsertSectionChild(sectionXml, tag, element) {
123
123
  const pattern = new RegExp(`<w:${tag}\\b[^>]*\\/>`);
124
- if (pattern.test(sectionXml)) return sectionXml.replace(pattern, element);
124
+ if (pattern.test(sectionXml)) return sectionXml.replace(pattern, () => element);
125
125
  const rank = sectionChildRank(tag);
126
126
  const children = /<w:(\w+)\b/g;
127
127
  children.lastIndex = sectionXml.indexOf('>') + 1;
@@ -257,7 +257,11 @@ async function ensureNoteStyles(zip, definition) {
257
257
  : `<w:style w:type="character" w:styleId="${definition.style}"><w:name w:val="${markName}"/><w:uiPriority w:val="99"/><w:unhideWhenUsed/>` +
258
258
  '<w:rPr><w:vertAlign w:val="superscript"/></w:rPr></w:style>',
259
259
  ].join('');
260
- if (additions) zip.file(part, styles.replace('</w:styles>', `${additions}</w:styles>`));
260
+ if (additions)
261
+ zip.file(
262
+ part,
263
+ styles.replace('</w:styles>', () => `${additions}</w:styles>`)
264
+ );
261
265
  }
262
266
 
263
267
  // Word reads the separator notes (ids -1 and 0) before any real note: without
@@ -313,8 +317,8 @@ export async function registerCommentThread(zip, { commentId, parentId = 0, done
313
317
  `${parentId ? ` w15:paraIdParent="${commentParagraphId(parentId)}"` : ''}` +
314
318
  ` w15:done="${done ? 1 : 0}"/>`;
315
319
  const next = pattern.test(extended.xml)
316
- ? extended.xml.replace(pattern, entry)
317
- : extended.xml.replace('</w15:commentsEx>', `${entry}</w15:commentsEx>`);
320
+ ? extended.xml.replace(pattern, () => entry)
321
+ : extended.xml.replace('</w15:commentsEx>', () => `${entry}</w15:commentsEx>`);
318
322
  zip.file(extended.part, next);
319
323
  return paraId;
320
324
  }
@@ -381,7 +385,8 @@ export async function registerCommentIdentity(zip, { commentId, date }) {
381
385
  ids.part,
382
386
  ids.xml.replace(
383
387
  `</${COMMENT_SIDECARS.ids.root}>`,
384
- `<w16cid:commentId w16cid:paraId="${paraId}" w16cid:durableId="${durableId}"/></${COMMENT_SIDECARS.ids.root}>`
388
+ () =>
389
+ `<w16cid:commentId w16cid:paraId="${paraId}" w16cid:durableId="${durableId}"/></${COMMENT_SIDECARS.ids.root}>`
385
390
  )
386
391
  );
387
392
  }
@@ -391,7 +396,8 @@ export async function registerCommentIdentity(zip, { commentId, date }) {
391
396
  extensible.part,
392
397
  extensible.xml.replace(
393
398
  `</${COMMENT_SIDECARS.extensible.root}>`,
394
- `<w16cex:commentExtensible w16cex:durableId="${durableId}" w16cex:dateUtc="${xmlEncode(date)}"/></${COMMENT_SIDECARS.extensible.root}>`
399
+ () =>
400
+ `<w16cex:commentExtensible w16cex:durableId="${durableId}" w16cex:dateUtc="${xmlEncode(date)}"/></${COMMENT_SIDECARS.extensible.root}>`
395
401
  )
396
402
  );
397
403
  }
@@ -435,7 +441,7 @@ export function anchorDocxComment(paragraphXml, id) {
435
441
  const body = paragraphXml.slice(opening.length);
436
442
  return `${opening}<w:commentRangeStart w:id="${id}"/>${body}`.replace(
437
443
  /<\/w:p>$/,
438
- `<w:commentRangeEnd w:id="${id}"/><w:r><w:commentReference w:id="${id}"/></w:r></w:p>`
444
+ () => `<w:commentRangeEnd w:id="${id}"/><w:r><w:commentReference w:id="${id}"/></w:r></w:p>`
439
445
  );
440
446
  }
441
447
 
@@ -511,7 +517,7 @@ export async function ensureDocxUpdateFields(zip) {
511
517
  export function upsertSectionReference(sectionXml, tag, kind, relationshipId) {
512
518
  const element = `<w:${tag} w:type="${kind}" r:id="${relationshipId}"/>`;
513
519
  const pattern = new RegExp(`<w:${tag}\\b[^>]*\\bw:type="${kind}"[^>]*\\/>`);
514
- if (pattern.test(sectionXml)) return sectionXml.replace(pattern, element);
520
+ if (pattern.test(sectionXml)) return sectionXml.replace(pattern, () => element);
515
521
  const position = sectionXml.indexOf('>') + 1;
516
522
  return `${sectionXml.slice(0, position)}${element}${sectionXml.slice(position)}`;
517
523
  }
@@ -704,7 +710,7 @@ export async function ensureNumbering(zip, kind, { restart = false } = {}) {
704
710
  : xml.indexOf('>', xml.indexOf('<w:numbering')) + 1;
705
711
  next = `${xml.slice(0, position)}${numberingDefinition(abstractId, kind)}${xml.slice(position)}`;
706
712
  }
707
- next = next.replace('</w:numbering>', `${definition}</w:numbering>`);
713
+ next = next.replace('</w:numbering>', () => `${definition}</w:numbering>`);
708
714
  zip.file(part, next);
709
715
  return { xml: next, numId, created: true };
710
716
  }
@@ -62,6 +62,9 @@ export async function documentStyleId(zip, requested, type = 'paragraph') {
62
62
  return local ? `${open}${local.id}${close}` : whole;
63
63
  }
64
64
  );
65
- zip.file(STYLES_PART, styles.replace('</w:styles>', `${definition}</w:styles>`));
65
+ zip.file(
66
+ STYLES_PART,
67
+ styles.replace('</w:styles>', () => `${definition}</w:styles>`)
68
+ );
66
69
  return { id: borrowed.id, found: true };
67
70
  }
@@ -188,8 +188,8 @@ export function justifyWordParagraphs(cellXml, justification) {
188
188
  return cellXml.replace(/<w:p(?:\s[^>]*)?>[\s\S]*?<\/w:p>/g, (paragraph) => {
189
189
  const stripped = paragraph.replace(/<w:jc\b[^>]*\/>/g, '');
190
190
  return /<w:pPr(?:\s[^>]*)?>/.test(stripped)
191
- ? stripped.replace(/<\/w:pPr>/, `<w:jc w:val="${justification}"/></w:pPr>`)
192
- : stripped.replace(/^(<w:p(?:\s[^>]*)?>)/, `$1<w:pPr><w:jc w:val="${justification}"/></w:pPr>`);
191
+ ? stripped.replace(/<\/w:pPr>/, () => `<w:jc w:val="${justification}"/></w:pPr>`)
192
+ : stripped.replace(/^(<w:p(?:\s[^>]*)?>)/, (__m, __1) => `${__1}<w:pPr><w:jc w:val="${justification}"/></w:pPr>`);
193
193
  });
194
194
  }
195
195
 
@@ -202,9 +202,9 @@ export function alignWordTableColumns(tableXml, columnAlignments = []) {
202
202
  let nextRow = row[0];
203
203
  rowCellMatches(row[0]).forEach((cell, column) => {
204
204
  if (!justifications[column]) return;
205
- nextRow = nextRow.replace(cell[0], justifyWordParagraphs(cell[0], justifications[column]));
205
+ nextRow = nextRow.replace(cell[0], () => justifyWordParagraphs(cell[0], justifications[column]));
206
206
  });
207
- next = next.replace(row[0], nextRow);
207
+ next = next.replace(row[0], () => nextRow);
208
208
  }
209
209
  return next;
210
210
  }
@@ -302,7 +302,7 @@ function tableRowStyle(properties, row) {
302
302
  // The last row is the total when totalRow is set: bold over a rule, so it reads as the sum of the rows above it and
303
303
  // not as one more of them.
304
304
  const isTotalRow = (properties, row, rows) => properties?.totalRow === true && rows > 1 && row === rows - 1;
305
- export const TOTAL_ROW_RULE = Object.freeze({ size: 8, color: '374151' });
305
+ const TOTAL_ROW_RULE = Object.freeze({ size: 8, color: '374151' });
306
306
 
307
307
  // A row's weight: its own rowStyles bold when given, else the header's or the total's.
308
308
  function rowBold(properties, row, rows, header) {
@@ -520,9 +520,9 @@ export function applyWordRunFormat(xml, runFormat) {
520
520
  const opened = /<w:rPr(?:\s[^>]*)?>([\s\S]*?)<\/w:rPr>/.exec(run);
521
521
  if (opened) {
522
522
  const merged = mergeWordPropertyElements(opened[1], runFormat, RUN_PROPERTY_ORDER);
523
- return run.replace(opened[0], `<w:rPr>${merged}</w:rPr>`);
523
+ return run.replace(opened[0], () => `<w:rPr>${merged}</w:rPr>`);
524
524
  }
525
- if (selfClosed) return run.replace(selfClosed[0], `<w:rPr>${runFormat}</w:rPr>`);
525
+ if (selfClosed) return run.replace(selfClosed[0], () => `<w:rPr>${runFormat}</w:rPr>`);
526
526
  return run.replace(/<w:r(?:\s[^>]*)?>/, (open) => `${open}<w:rPr>${runFormat}</w:rPr>`);
527
527
  });
528
528
  }
@@ -598,7 +598,7 @@ export function rewriteTableColumns(tableXml, columnIndex, mode) {
598
598
  } else {
599
599
  columns.splice(columnIndex - 1, 0, columns[columnIndex - 1] || columns.at(-1) || '<w:gridCol/>');
600
600
  }
601
- next = next.replace(grid[0], `<w:tblGrid>${columns.join('')}</w:tblGrid>`);
601
+ next = next.replace(grid[0], () => `<w:tblGrid>${columns.join('')}</w:tblGrid>`);
602
602
  }
603
603
  return mapTableRows(next, (row) => {
604
604
  const cells = tableRowCells(row);
@@ -749,7 +749,7 @@ export function replaceDocxTable(current, table, nextTable) {
749
749
 
750
750
  export function replaceWordProperties(xml, owner, propertyTag, value) {
751
751
  const pattern = new RegExp(`<w:${propertyTag}(?:\\s[^>]*)?>[\\s\\S]*?<\\/w:${propertyTag}>`);
752
- if (pattern.test(xml)) return xml.replace(pattern, `<w:${propertyTag}>${value}</w:${propertyTag}>`);
752
+ if (pattern.test(xml)) return xml.replace(pattern, () => `<w:${propertyTag}>${value}</w:${propertyTag}>`);
753
753
  return xml.replace(
754
754
  new RegExp(`<w:${owner}(?:\\s[^>]*)?>`),
755
755
  (open) => `${open}<w:${propertyTag}>${value}</w:${propertyTag}>`
@@ -206,7 +206,10 @@ export async function ensureContentTypeOverride(zip, part, type) {
206
206
  const path = '[Content_Types].xml';
207
207
  const xml = await zipText(zip, path);
208
208
  if (xml.includes(`PartName="${part}"`)) return;
209
- zip.file(path, xml.replace('</Types>', `<Override PartName="${part}" ContentType="${type}"/></Types>`));
209
+ zip.file(
210
+ path,
211
+ xml.replace('</Types>', () => `<Override PartName="${part}" ContentType="${type}"/></Types>`)
212
+ );
210
213
  }
211
214
 
212
215
  export async function removeContentTypeOverride(zip, part) {
@@ -219,7 +222,10 @@ export async function ensureDefaultContentType(zip, extension, type) {
219
222
  const path = '[Content_Types].xml';
220
223
  const xml = await zipText(zip, path);
221
224
  if (new RegExp(`<Default\\b[^>]*\\bExtension="${extension}"`, 'i').test(xml)) return;
222
- zip.file(path, xml.replace(/<Types\b[^>]*>/, `$&<Default Extension="${extension}" ContentType="${type}"/>`));
225
+ zip.file(
226
+ path,
227
+ xml.replace(/<Types\b[^>]*>/, (__m) => `${__m}<Default Extension="${extension}" ContentType="${type}"/>`)
228
+ );
223
229
  }
224
230
 
225
231
  export async function addPackageRelationship(zip, relsPath, type, target, mode = '') {
@@ -237,7 +243,10 @@ export async function addPackageRelationship(zip, relsPath, type, target, mode =
237
243
  const relationship =
238
244
  `<Relationship Id="${id}" Type="${type}" Target="${xmlEncode(target)}"` +
239
245
  `${mode ? ` TargetMode="${mode}"` : ''}/>`;
240
- zip.file(relsPath, xml.replace('</Relationships>', `${relationship}</Relationships>`));
246
+ zip.file(
247
+ relsPath,
248
+ xml.replace('</Relationships>', () => `${relationship}</Relationships>`)
249
+ );
241
250
  return id;
242
251
  }
243
252
 
@@ -417,7 +426,9 @@ async function clonePartTree(zip, sourcePath, cache = new Map()) {
417
426
  const cloned = await clonePartTree(zip, partFromTarget(directory, target), cache);
418
427
  if (!cloned) continue;
419
428
  const rewrittenTarget = absolute ? `/${cloned}` : posix.relative(posix.dirname(targetPath), cloned);
420
- output = output.replace(block, block.replace(`Target="${raw}"`, `Target="${xmlEncode(rewrittenTarget)}"`));
429
+ output = output.replace(block, () =>
430
+ block.replace(`Target="${raw}"`, () => `Target="${xmlEncode(rewrittenTarget)}"`)
431
+ );
421
432
  }
422
433
  zip.file(partRelationshipPath(targetPath), output);
423
434
  return targetPath;
@@ -446,7 +457,9 @@ export async function cloneOwnedSlideParts(zip, relationshipsPath) {
446
457
  if (!cloned) continue;
447
458
  copied.push(cloned);
448
459
  const rewrittenTarget = absolute ? `/${cloned}` : posix.relative(owner, cloned);
449
- output = output.replace(block, block.replace(`Target="${raw}"`, `Target="${xmlEncode(rewrittenTarget)}"`));
460
+ output = output.replace(block, () =>
461
+ block.replace(`Target="${raw}"`, () => `Target="${xmlEncode(rewrittenTarget)}"`)
462
+ );
450
463
  }
451
464
  if (copied.length) zip.file(relationshipsPath, output);
452
465
  return copied;
@@ -468,9 +481,11 @@ async function remapLayoutRelationships(source, zip, { layoutPath, targetPath, m
468
481
  ? master
469
482
  : await importPartTree(source, zip, resolved, cache);
470
483
  if (!mapped) continue;
471
- output = output.replace(
472
- block,
473
- block.replace(/\bTarget="[^"]*"/, `Target="${xmlEncode(posix.relative(posix.dirname(targetPath), mapped))}"`)
484
+ output = output.replace(block, () =>
485
+ block.replace(
486
+ /\bTarget="[^"]*"/,
487
+ () => `Target="${xmlEncode(posix.relative(posix.dirname(targetPath), mapped))}"`
488
+ )
474
489
  );
475
490
  }
476
491
  zip.file(partRelationshipPath(targetPath), output);
@@ -490,8 +505,8 @@ async function registerLayoutOnMaster(zip, master, targetPath) {
490
505
  zip.file(
491
506
  master,
492
507
  masterXml.includes('</p:sldLayoutIdLst>')
493
- ? masterXml.replace('</p:sldLayoutIdLst>', `${entry}</p:sldLayoutIdLst>`)
494
- : masterXml.replace(/(<p:clrMap\b[^>]*\/>)/, `$1<p:sldLayoutIdLst>${entry}</p:sldLayoutIdLst>`)
508
+ ? masterXml.replace('</p:sldLayoutIdLst>', () => `${entry}</p:sldLayoutIdLst>`)
509
+ : masterXml.replace(/(<p:clrMap\b[^>]*\/>)/, (__m, __1) => `${__1}<p:sldLayoutIdLst>${entry}</p:sldLayoutIdLst>`)
495
510
  );
496
511
  }
497
512
 
@@ -548,9 +563,8 @@ export async function rewriteImportedRelationships(source, zip, sourceOwner, tar
548
563
  } else {
549
564
  mapped = await importPartTree(source, zip, resolved, cache);
550
565
  }
551
- output = output.replace(
552
- block,
553
- block.replace(/\bTarget="[^"]*"/, `Target="${xmlEncode(posix.relative(targetDirectory, mapped))}"`)
566
+ output = output.replace(block, () =>
567
+ block.replace(/\bTarget="[^"]*"/, () => `Target="${xmlEncode(posix.relative(targetDirectory, mapped))}"`)
554
568
  );
555
569
  }
556
570
  return output;
@@ -321,12 +321,12 @@ export async function writePivotTable(
321
321
  const cacheId = (workbook.match(/<pivotCache\b/g) || []).length + 1;
322
322
  const entry = `<pivotCache cacheId="${cacheId}" r:id="${workbookRelationshipId}"/>`;
323
323
  if (/<pivotCaches>/.test(workbook)) {
324
- workbook = workbook.replace('</pivotCaches>', `${entry}</pivotCaches>`);
324
+ workbook = workbook.replace('</pivotCaches>', () => `${entry}</pivotCaches>`);
325
325
  } else {
326
326
  const block = `<pivotCaches>${entry}</pivotCaches>`;
327
327
  workbook = /<calcPr\b[^>]*\/>/.test(workbook)
328
- ? workbook.replace(/(<calcPr\b[^>]*\/>)/, `$1${block}`)
329
- : workbook.replace('</sheets>', `</sheets>${block}`);
328
+ ? workbook.replace(/(<calcPr\b[^>]*\/>)/, (__m, __1) => `${__1}${block}`)
329
+ : workbook.replace('</sheets>', () => `</sheets>${block}`);
330
330
  }
331
331
  zip.file('xl/workbook.xml', workbook);
332
332
 
@@ -185,9 +185,9 @@ export async function writePresentationChart(zip, { chartPart, embeddingPart, ch
185
185
  const id = /\bId="([^"]+)"/.exec(previous)?.[1] || `rId${Math.max(0, ...taken) + 1}`;
186
186
  const relationship = `<Relationship Id="${id}" Type="${OFFICE_RELATIONSHIP_BASE}/package" Target="${target}"/>`;
187
187
  let relationships = `${XML_HEADER}<Relationships xmlns="${PACKAGE_RELATIONSHIP_NS}">${relationship}</Relationships>`;
188
- if (previous) relationships = existing.replace(previous, relationship);
188
+ if (previous) relationships = existing.replace(previous, () => relationship);
189
189
  else if (existing.includes('</Relationships>'))
190
- relationships = existing.replace('</Relationships>', `${relationship}</Relationships>`);
190
+ relationships = existing.replace('</Relationships>', () => `${relationship}</Relationships>`);
191
191
  zip.file(relationshipsPath, relationships);
192
192
  zip.file(chartPart, citeChartWorkbook(chart, id));
193
193
  await ensureContentTypeOverride(zip, `/${chartPart}`, CHART_CONTENT_TYPE);
@@ -197,7 +197,7 @@ export async function writePresentationChart(zip, { chartPart, embeddingPart, ch
197
197
  function citeChartWorkbook(chart, id) {
198
198
  const text = String(chart);
199
199
  if (/<c:externalData\b[^>]*\br:id="/.test(text)) {
200
- return text.replace(/(<c:externalData\b[^>]*\br:id=")[^"]*(")/, `$1${id}$2`);
200
+ return text.replace(/(<c:externalData\b[^>]*\br:id=")[^"]*(")/, (__m, __1, __2) => `${__1}${id}${__2}`);
201
201
  }
202
202
  const cited = `<c:externalData r:id="${id}"><c:autoUpdate val="0"/></c:externalData>`;
203
203
  const before = /<c:(?:printSettings|userShapes|extLst)\b|<\/c:chartSpace>/.exec(text);
@@ -103,9 +103,9 @@ function accentOnLastPoint(series, count) {
103
103
  if (count !== previousCount && accents.length === 1 && pointAt(accents[0]) === previousCount - 1) {
104
104
  // The accent and the point now last trade places; one past the new end is dropped by the caller.
105
105
  const displaced = points.find((point) => pointAt(point) === count - 1);
106
- const moved = (point, to) => point.replace(/<c:idx val="\d+"\/>/, `<c:idx val="${to}"/>`);
107
- block = block.replace(accents[0], moved(accents[0], count - 1));
108
- if (displaced) block = block.replace(displaced, moved(displaced, previousCount - 1));
106
+ const moved = (point, to) => point.replace(/<c:idx val="\d+"\/>/, () => `<c:idx val="${to}"/>`);
107
+ block = block.replace(accents[0], () => moved(accents[0], count - 1));
108
+ if (displaced) block = block.replace(displaced, () => moved(displaced, previousCount - 1));
109
109
  }
110
110
  return block;
111
111
  }
@@ -132,7 +132,7 @@ function refreshChartDataInPlace(xml, categories, series, op) {
132
132
  block = /<c:tx>\s*<c:v>/.test(block)
133
133
  ? block.replace(
134
134
  /<c:tx>\s*<c:v>[\s\S]*?<\/c:v>\s*<\/c:tx>/,
135
- `<c:tx><c:v>${xmlEncode(String(entry.name))}</c:v></c:tx>`
135
+ () => `<c:tx><c:v>${xmlEncode(String(entry.name))}</c:v></c:tx>`
136
136
  )
137
137
  : block.replace(
138
138
  /(<c:tx>\s*<c:strRef>[\s\S]*?<c:strCache>)[\s\S]*?(<\/c:strCache>)/,
@@ -251,20 +251,20 @@ function withCategoryOrientation(xml, orientation) {
251
251
  const element = `<c:orientation val="${orientation}"/>`;
252
252
  let oriented;
253
253
  if (/<c:orientation val="[^"]*"\/>/.test(categoryAxis)) {
254
- oriented = categoryAxis.replace(/<c:orientation val="[^"]*"\/>/, element);
254
+ oriented = categoryAxis.replace(/<c:orientation val="[^"]*"\/>/, () => element);
255
255
  } else if (categoryAxis.includes('<c:scaling/>')) {
256
- oriented = categoryAxis.replace('<c:scaling/>', `<c:scaling>${element}</c:scaling>`);
256
+ oriented = categoryAxis.replace('<c:scaling/>', () => `<c:scaling>${element}</c:scaling>`);
257
257
  } else {
258
- oriented = categoryAxis.replace('<c:scaling>', `<c:scaling>${element}`);
258
+ oriented = categoryAxis.replace('<c:scaling>', () => `<c:scaling>${element}`);
259
259
  }
260
260
  const crosses = orientation === 'maxMin' ? 'max' : 'autoZero';
261
261
  let crossed = valueAxis;
262
262
  if (/<c:crosses val="[^"]*"\/>/.test(valueAxis)) {
263
- crossed = valueAxis.replace(/<c:crosses val="[^"]*"\/>/, `<c:crosses val="${crosses}"/>`);
263
+ crossed = valueAxis.replace(/<c:crosses val="[^"]*"\/>/, () => `<c:crosses val="${crosses}"/>`);
264
264
  } else if (!/<c:crossesAt\b/.test(valueAxis)) {
265
- crossed = valueAxis.replace(/(<c:crossAx val="[^"]*"\/>)/, `$1<c:crosses val="${crosses}"/>`);
265
+ crossed = valueAxis.replace(/(<c:crossAx val="[^"]*"\/>)/, (__m, __1) => `${__1}<c:crosses val="${crosses}"/>`);
266
266
  }
267
- return xml.replace(categoryAxis, oriented).replace(valueAxis, crossed);
267
+ return xml.replace(categoryAxis, () => oriented).replace(valueAxis, () => crossed);
268
268
  }
269
269
 
270
270
  // The new series carrying the colours the chart already had.
@@ -420,7 +420,7 @@ export async function handleSetChartAxis(context, op) {
420
420
  const bounds =
421
421
  `${op.maximum != null ? `<c:max val="${Number(op.maximum)}"/>` : ''}` +
422
422
  `${op.minimum != null ? `<c:min val="${Number(op.minimum)}"/>` : ''}`;
423
- return cleaned.replace('</c:scaling>', `${bounds}</c:scaling>`);
423
+ return cleaned.replace('</c:scaling>', () => `${bounds}</c:scaling>`);
424
424
  });
425
425
  }
426
426
  if (op.numberFormat != null) {
@@ -471,7 +471,7 @@ export async function handleSetChartSeries(context, op) {
471
471
  if (op.name != null) {
472
472
  updated = updated.replace(
473
473
  /(<c:tx>[\s\S]*?<c:strCache>[\s\S]*?<c:pt idx="0"><c:v>)[\s\S]*?(<\/c:v>)/,
474
- `$1${xmlEncode(String(op.name))}$2`
474
+ (__m, __1, __2) => `${__1}${xmlEncode(String(op.name))}${__2}`
475
475
  );
476
476
  }
477
477
  if (Array.isArray(op.categories) && op.categories.length) {
@@ -482,9 +482,12 @@ export async function handleSetChartSeries(context, op) {
482
482
  block
483
483
  .replace(
484
484
  /<c:strCache>[\s\S]*?<\/c:strCache>/,
485
- `<c:strCache><c:ptCount val="${op.categories.length}"/>${points}</c:strCache>`
485
+ () => `<c:strCache><c:ptCount val="${op.categories.length}"/>${points}</c:strCache>`
486
+ )
487
+ .replace(
488
+ /(<c:f>[^<]*\$[A-Z]+\$\d+:\$[A-Z]+\$)\d+(<\/c:f>)/,
489
+ (__m, __1, __2) => `${__1}${op.categories.length + 1}${__2}`
486
490
  )
487
- .replace(/(<c:f>[^<]*\$[A-Z]+\$\d+:\$[A-Z]+\$)\d+(<\/c:f>)/, `$1${op.categories.length + 1}$2`)
488
491
  );
489
492
  }
490
493
  if (Array.isArray(op.values) && op.values.length) {
@@ -499,10 +502,13 @@ export async function handleSetChartSeries(context, op) {
499
502
  .replace(/<c:numCache>[\s\S]*?<\/c:numCache>/, (cache) =>
500
503
  cache.replace(
501
504
  /<c:ptCount val="\d+"\/>[\s\S]*?(?=<\/c:numCache>)/,
502
- `<c:ptCount val="${op.values.length}"/>${points}`
505
+ () => `<c:ptCount val="${op.values.length}"/>${points}`
503
506
  )
504
507
  )
505
- .replace(/(<c:f>[^<]*\$[A-Z]+\$\d+:\$[A-Z]+\$)\d+(<\/c:f>)/, `$1${op.values.length + 1}$2`)
508
+ .replace(
509
+ /(<c:f>[^<]*\$[A-Z]+\$\d+:\$[A-Z]+\$)\d+(<\/c:f>)/,
510
+ (__m, __1, __2) => `${__1}${op.values.length + 1}${__2}`
511
+ )
506
512
  );
507
513
  }
508
514
  return updated;
@@ -575,7 +581,7 @@ export async function handleSetChartTrendlineOrSetChartErrorBars(context, op) {
575
581
  const anchor = /<c:cat>/.exec(cleaned) || /<c:val>/.exec(cleaned);
576
582
  return anchor
577
583
  ? `${cleaned.slice(0, anchor.index)}${element}${cleaned.slice(anchor.index)}`
578
- : cleaned.replace('</c:ser>', `${element}</c:ser>`);
584
+ : cleaned.replace('</c:ser>', () => `${element}</c:ser>`);
579
585
  });
580
586
  if (!changed) throw new Error(`Chart has no series ${op.series ?? ''}`.trim());
581
587
  zip.file(chart.part, next);
@@ -610,7 +616,7 @@ export async function handleSetChartDataLabels(context, op) {
610
616
  const anchor = /<c:cat>/.exec(cleaned);
611
617
  return anchor
612
618
  ? `${cleaned.slice(0, anchor.index)}${labels}${cleaned.slice(anchor.index)}`
613
- : cleaned.replace('</c:ser>', `${labels}</c:ser>`);
619
+ : cleaned.replace('</c:ser>', () => `${labels}</c:ser>`);
614
620
  });
615
621
  if (!changed) throw new Error(`Chart has no series ${op.series ?? ''}`.trim());
616
622
  zip.file(chart.part, next);
@@ -264,11 +264,11 @@ function setTableCellText(cell, text) {
264
264
  `<a:t${/^\s|\s$/.test(value) ? ' xml:space="preserve"' : ''}>${xmlEncode(value)}</a:t></a:r>`;
265
265
  const paragraph = /<a:p(?:\s[^>]*)?>[\s\S]*?<\/a:p>/.exec(cell);
266
266
  if (paragraph) {
267
- const replaced = paragraph[0].replace(/<\/a:p>$/, `${run}</a:p>`);
267
+ const replaced = paragraph[0].replace(/<\/a:p>$/, () => `${run}</a:p>`);
268
268
  return `${cell.slice(0, paragraph.index)}${replaced}${cell.slice(paragraph.index + paragraph[0].length)}`;
269
269
  }
270
270
  if (!/<\/a:txBody>/.test(cell)) throw new Error('PPTX table cell has no text body');
271
- return cell.replace('</a:txBody>', `<a:p>${run}</a:p></a:txBody>`);
271
+ return cell.replace('</a:txBody>', () => `<a:p>${run}</a:p></a:txBody>`);
272
272
  }
273
273
 
274
274
  export function setTableValues(shapeXml, values) {
@@ -399,7 +399,7 @@ export function writeShapeTree(slideXml, tree, shapes) {
399
399
 
400
400
  export function appendSlideShape(xml, shape) {
401
401
  if (!/<\/p:spTree>/.test(xml)) throw new Error('PPTX slide shape tree is missing');
402
- return xml.replace('</p:spTree>', `${shape}</p:spTree>`);
402
+ return xml.replace('</p:spTree>', () => `${shape}</p:spTree>`);
403
403
  }
404
404
 
405
405
  export function setSlideBackground(xml, color) {
@@ -444,8 +444,8 @@ export function updateShapeGeometry(shape, properties) {
444
444
  `<a:ext cx="${properties.width != null ? toEmu(properties.width) : Number(extent?.[1] || 1)}"` +
445
445
  ` cy="${properties.height != null ? toEmu(properties.height) : Number(extent?.[2] || 1)}"/></${frameTag}>`;
446
446
  if (current) next = `${next.slice(0, current.index)}${frame}${next.slice(current.index + current[0].length)}`;
447
- else if (frameTag === 'p:xfrm') next = next.replace('</p:nvGraphicFramePr>', `$&${frame}`);
448
- else next = next.replace(/<p:spPr(?:\s[^>]*)?>/, `$&${frame}`);
447
+ else if (frameTag === 'p:xfrm') next = next.replace('</p:nvGraphicFramePr>', (__m) => `${__m}${frame}`);
448
+ else next = next.replace(/<p:spPr(?:\s[^>]*)?>/, (__m) => `${__m}${frame}`);
449
449
  }
450
450
  // A transparency alone keeps the fill's colour, as the Office backend's Fill.Transparency does; it was dropped here.
451
451
  const fillColor =