mixdog 1.2.1 → 1.2.3

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 (557) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/scripts/provider-pingpong-live.mjs +509 -0
  6. package/src/agents/advisor/AGENT.md +1 -1
  7. package/src/agents/advisor/agent.json +1 -1
  8. package/src/agents/reviewer/AGENT.md +3 -3
  9. package/src/agents/reviewer/agent.json +1 -1
  10. package/src/defaults/shipped-history.json +6 -0
  11. package/src/defaults/skills/setup/SKILL.md +6 -1
  12. package/src/defaults/skills/setup/references/actions.md +44 -22
  13. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  14. package/src/headless-exec.mjs +15 -8
  15. package/src/lib/keychain-cjs.cjs +7 -4
  16. package/src/output-styles/common.md +11 -10
  17. package/src/repl/slash-commands.mjs +16 -1
  18. package/src/rules/agent/AGENT.md +5 -5
  19. package/src/rules/lead/LEAD.md +5 -5
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  22. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  23. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  24. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
  33. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  36. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  37. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  38. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  39. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  40. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  41. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  43. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  44. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  45. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
  46. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  47. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  48. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
  49. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
  50. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  51. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  54. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
  58. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  59. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  63. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  65. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  66. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
  70. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  71. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  72. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
  73. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
  74. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
  75. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  76. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
  77. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  79. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  80. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
  81. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  83. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
  84. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  85. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  86. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
  87. package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
  88. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  89. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  90. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  91. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  92. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  93. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
  94. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
  96. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
  97. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  99. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  100. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  102. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
  103. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
  105. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
  106. package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
  107. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  109. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
  110. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  113. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  114. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  115. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  116. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  117. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  118. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  119. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  120. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  121. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  122. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  123. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  124. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  125. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  126. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  127. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  128. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  129. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  138. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  140. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  141. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  142. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
  143. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
  144. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  145. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  147. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
  148. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  150. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
  151. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
  153. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
  154. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
  155. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
  156. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
  157. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  158. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  159. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  160. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
  161. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  163. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
  164. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  165. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
  166. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  167. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  168. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  169. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  170. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
  171. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
  172. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  173. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
  174. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
  175. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  176. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  177. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  178. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  179. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  180. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  181. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  182. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  183. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  184. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  185. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  186. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  187. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  188. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
  189. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  190. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  191. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  192. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
  193. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  195. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
  196. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  197. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  198. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  199. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  200. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  201. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  202. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  203. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  204. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  205. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  206. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  207. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  208. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  210. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  211. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  212. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
  213. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  214. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  215. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  216. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  217. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  218. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  219. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  220. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  221. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  222. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
  223. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  224. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  225. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  226. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  227. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  228. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  229. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  230. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  231. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  232. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  233. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  234. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  235. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  236. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  237. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  238. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  239. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  240. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
  241. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  242. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  243. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  244. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  245. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  246. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
  248. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
  249. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  250. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  251. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
  252. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  253. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  254. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  255. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  256. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
  257. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  258. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
  259. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  260. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  261. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  262. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  263. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  264. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  265. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  266. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  267. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
  268. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  269. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  270. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  271. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  272. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  273. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  274. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  275. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  276. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  277. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  278. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  279. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  280. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  281. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
  282. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
  283. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
  284. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  285. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  286. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  287. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  288. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  289. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  290. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  291. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  292. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
  293. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  294. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  295. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  296. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  297. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  298. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  299. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  300. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  301. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  302. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  303. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  304. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  305. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  306. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  307. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  308. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  309. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  310. package/src/runtime/github/tool.mjs +92 -2
  311. package/src/runtime/memory/index.mjs +1 -0
  312. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  313. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  314. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  315. package/src/runtime/memory/lib/pg/process.mjs +65 -50
  316. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  317. package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
  318. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  319. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  320. package/src/runtime/office/README.md +2 -2
  321. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  322. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  323. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  324. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  325. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  326. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  327. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  328. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  329. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  330. package/src/runtime/office/core/office-sessions.mjs +5 -0
  331. package/src/runtime/office/core/office-transactions.mjs +3 -0
  332. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  333. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  334. package/src/runtime/office/index.mjs +30 -0
  335. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  336. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  337. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  338. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  339. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  340. package/src/runtime/office/shared/values.mjs +0 -5
  341. package/src/runtime/shared/background-tasks.mjs +92 -14
  342. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  343. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  344. package/src/runtime/shared/buffered-appender.mjs +18 -0
  345. package/src/runtime/shared/config.mjs +78 -18
  346. package/src/runtime/shared/err-text.mjs +31 -0
  347. package/src/runtime/shared/error-presentation.mjs +159 -19
  348. package/src/runtime/shared/file-permissions.d.mts +6 -1
  349. package/src/runtime/shared/file-permissions.mjs +54 -6
  350. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  351. package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
  352. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  353. package/src/runtime/shared/llm/model-catalog.mjs +53 -40
  354. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  355. package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
  356. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  357. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  358. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  359. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  360. package/src/runtime/shared/loopback-listener.mjs +9 -0
  361. package/src/runtime/shared/model-display.mjs +13 -0
  362. package/src/runtime/shared/provider-api-key.mjs +2 -0
  363. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  364. package/src/runtime/shared/review-diff.mjs +52 -0
  365. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  366. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  367. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  368. package/src/runtime/shared/slow-span.mjs +114 -0
  369. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  370. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  371. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  372. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  373. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  374. package/src/runtime/shared/tool-card-model.mjs +5 -2
  375. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  376. package/src/runtime/shared/tool-primitives.mjs +13 -0
  377. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  378. package/src/runtime/shared/tool-surface.mjs +18 -3
  379. package/src/runtime/shared/tool-work-units.mjs +40 -4
  380. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  381. package/src/runtime/shared/transcript-writer.mjs +10 -2
  382. package/src/runtime/shared/turn-changes.mjs +670 -274
  383. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  384. package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
  385. package/src/runtime/shared/turn-snapshot.mjs +986 -690
  386. package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
  387. package/src/runtime/shared/user-data-guard.mjs +262 -49
  388. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  389. package/src/runtime/shared/worktrees/contract.mjs +34 -24
  390. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  391. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  392. package/src/runtime/shared/worktrees/git.mjs +8 -3
  393. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  394. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  395. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  396. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  397. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  398. package/src/runtime/terminal-bridge/client.mjs +44 -11
  399. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  400. package/src/runtime/tidy/apply.mjs +47 -2
  401. package/src/runtime/tidy/run-engines.mjs +11 -5
  402. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  403. package/src/session-runtime/boot/apis.mjs +19 -5
  404. package/src/session-runtime/boot/facade.mjs +1 -0
  405. package/src/session-runtime/boot/infrastructure.mjs +12 -1
  406. package/src/session-runtime/boot/session.mjs +0 -1
  407. package/src/session-runtime/boot/tools.mjs +4 -1
  408. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  409. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  410. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  411. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  412. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  413. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  414. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  415. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  416. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
  417. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  418. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  419. package/src/session-runtime/lifecycle/teardown.mjs +73 -8
  420. package/src/session-runtime/lifecycle-api.mjs +1 -0
  421. package/src/session-runtime/mcp-glue/connect.mjs +46 -14
  422. package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
  423. package/src/session-runtime/mcp-glue.mjs +3 -0
  424. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  425. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  426. package/src/session-runtime/model-route/set-route.mjs +85 -17
  427. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  428. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  429. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  430. package/src/session-runtime/native-web-search.mjs +10 -1
  431. package/src/session-runtime/new-session-config.mjs +4 -2
  432. package/src/session-runtime/provider-auth/login.mjs +4 -0
  433. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  434. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  435. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  436. package/src/session-runtime/resource-extension-sync.mjs +4 -0
  437. package/src/session-runtime/resource-mcp-api.mjs +98 -2
  438. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  439. package/src/session-runtime/runtime-review-api.mjs +21 -2
  440. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  441. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  442. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  443. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  444. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  445. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  446. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  447. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  448. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  449. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  450. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  451. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  452. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  453. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  454. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  455. package/src/session-runtime/services/agent-tool.mjs +3 -0
  456. package/src/session-runtime/services/channel-admin.mjs +19 -3
  457. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  458. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  459. package/src/session-runtime/services/provider-admin.mjs +81 -15
  460. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  461. package/src/session-runtime/session-turn-api.mjs +14 -5
  462. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  463. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  464. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  465. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  466. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  467. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  468. package/src/session-runtime/skills-api.mjs +3 -5
  469. package/src/session-runtime/tool-surface.mjs +5 -1
  470. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  471. package/src/session-runtime/turn/session-ops.mjs +7 -5
  472. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  473. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  474. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  475. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  476. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  477. package/src/session-runtime/turn/turn-run.mjs +25 -9
  478. package/src/session-runtime/usage-stats-api.mjs +43 -11
  479. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  480. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  481. package/src/session-runtime/workspace/transitions.mjs +190 -15
  482. package/src/standalone/daemon-agent-control.mjs +9 -1
  483. package/src/standalone/daemon-drain-policy.mjs +8 -0
  484. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  485. package/src/standalone/daemon-owner.mjs +17 -4
  486. package/src/standalone/daemon-pg-stop.mjs +51 -0
  487. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  488. package/src/standalone/daemon-stop-budget.mjs +18 -0
  489. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  490. package/src/standalone/daemon-telemetry.mjs +74 -0
  491. package/src/standalone/daemon.mjs +64 -8
  492. package/src/standalone/desktop-service-registry.mjs +5 -0
  493. package/src/standalone/local-session-runtime.mjs +70 -19
  494. package/src/standalone/session-client.mjs +42 -0
  495. package/src/standalone/session-protocol.mjs +14 -0
  496. package/src/standalone/session-proxy/projection.mjs +41 -4
  497. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  498. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  499. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  500. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  501. package/src/standalone/session-service/agent-tree.mjs +12 -0
  502. package/src/standalone/session-service/quota-resume.mjs +8 -0
  503. package/src/standalone/session-service/retention/busy.mjs +15 -1
  504. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  505. package/src/standalone/session-service-api.mjs +11 -1
  506. package/src/standalone/session-service.mjs +1 -0
  507. package/src/standalone/session-state-patch.d.mts +2 -1
  508. package/src/standalone/session-state-patch.mjs +41 -1
  509. package/src/tui/App.jsx +25 -0
  510. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  511. package/src/tui/app/app-view.jsx +1 -0
  512. package/src/tui/app/btw-controller.mjs +118 -0
  513. package/src/tui/app/create-app-pickers.mjs +6 -0
  514. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  515. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  516. package/src/tui/app/extension-pickers.mjs +2 -1
  517. package/src/tui/app/model-options.mjs +11 -16
  518. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  519. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  520. package/src/tui/app/slash-commands.mjs +20 -5
  521. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  522. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  523. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  524. package/src/tui/app/use-global-key-input.mjs +5 -12
  525. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  526. package/src/tui/components/BtwPanel.jsx +53 -0
  527. package/src/tui/components/QuestionPanel.jsx +275 -0
  528. package/src/tui/components/StatusLine.jsx +2 -0
  529. package/src/tui/components/question-panel-model.mjs +156 -0
  530. package/src/tui/components/status-line/local-line.mjs +5 -2
  531. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  532. package/src/tui/dist/index.mjs +3221 -1500
  533. package/src/tui/session/context-state.mjs +4 -2
  534. package/src/tui/session/quota-resume.mjs +46 -14
  535. package/src/tui/session/session-api/commands.mjs +43 -24
  536. package/src/tui/session/session-api/controls.mjs +2 -2
  537. package/src/tui/session/session-api/extensions.mjs +22 -0
  538. package/src/tui/session/session-api/integrations.mjs +16 -2
  539. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  540. package/src/tui/session/session-api/lifecycle.mjs +7 -2
  541. package/src/tui/session/session-api/routes.mjs +71 -7
  542. package/src/tui/session/session-api/settings.mjs +11 -14
  543. package/src/tui/session/session-api.mjs +1 -0
  544. package/src/tui/session/session-flow/drain.mjs +7 -1
  545. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  546. package/src/tui/session/tool-approval.mjs +10 -7
  547. package/src/tui/session/transcript-spill.mjs +14 -7
  548. package/src/tui/session/turn-stream.mjs +174 -31
  549. package/src/tui/session/turn.mjs +46 -16
  550. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  551. package/src/ui/statusline-agents.mjs +15 -4
  552. package/src/ui/statusline.mjs +7 -3
  553. package/src/ui/streaming-markdown-heal.mjs +34 -3
  554. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  555. package/src/workflows/default/WORKFLOW.md +3 -1
  556. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  557. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -10,14 +10,14 @@ Microsoft Office installed.
10
10
  | --- | --- |
11
11
  | `(root)` | Public surface only: `index.mjs` (tool executor), `tool-defs.mjs`, `capabilities.mjs`. Test suites and `office-test-support.mjs` also live here. |
12
12
  | `authoring/` | The `author` action — the only way a deck is made: `pptx-script-contract.mjs` (what a script may require and how long it may run; the model-facing guide is the built-in `pptx` skill in `src/defaults/skills/pptx`), `pptx-script-runner.mjs` (runs a pptxgenjs script in-process with a scoped `require`, injecting `MEASURE` and `ICON`), `pptx-script-normalize.mjs` (paragraph properties, hanging punctuation, accent-series merge), `pptx-html-runner.mjs` + `pptx-html-measure.mjs` + `pptx-html-build.mjs` (the HTML input: a local Chrome/Edge lays the slides out, the measurement becomes native text boxes, shapes, tables, charts, and pictures, and the browser's pages are kept for the HTML-beside-PPTX comparison), `pptx-author-action.mjs` (writes the deck, opens an `authored` session, renders, returns the composition receipt and contact sheet), `pptx-receipt.mjs`, `pptx-contact-sheet.mjs`, `pptx-icons.mjs` + `pptx-icons.json` (offline Lucide subset built by `npm run office:icons`), `pptx-brief.mjs`. Sits beside the root and imports `core`. |
13
- | `core/` | Sessions, transactions, journal, snapshot pagination, tabular sessions, and the action pipeline (`office-actions-*.mjs`). |
13
+ | `core/` | Sessions, transactions, journal, snapshot pagination, tabular sessions, the action pipeline (`office-actions-*.mjs`), and the write ledger (`office-write-ledger.mjs`: every route that writes a workspace file reports it with `noteOfficeWrite` before writing; `index.mjs` records the reported files that changed in the session's turn review as its own changes). |
14
14
  | `com/` | Windows-native path: `com-adapter.mjs` plus the PowerShell hosts `office-com-host.ps1` and `office-com-session-host.ps1`. |
15
15
  | `portable/` | OOXML read/write without Office, package validation, XLSX contracts, the backend-neutral XLSX audits shared by portable `issues`, Excel's `issues` merge, and the quality review (`xlsx-audit-support.mjs` cell reading and the capped issue list, `xlsx-sheet-hygiene.mjs` every-profile hygiene and layout information, `xlsx-formula-audit.mjs` the financial-model discipline and the orchestration), the workbook conventions summary a snapshot carries (`xlsx-conventions.mjs`), LibreOffice recalculation with its error summary (`portable-soffice.mjs` holds one private user profile for the life of the process, runs conversions one at a time behind it, and drops the profile after a failed run; `xlsx-recalculate.mjs` asks LibreOffice first and falls back to `xlsx-formula-engine.mjs`, which evaluates the formulas in this process and refuses — never guesses — the ones it cannot read; `portable-shared-formulas.mjs` gives every cell a shared or array formula covers the formula it actually holds, so a filled-down column is never read as pasted numbers), the sheet content audits (`portable-sheet-audits.mjs`: percent scale, column fit, protected inputs, unreadable ink, a hardcode inside a row of formulas), the leftover scan (`placeholder-scan.mjs`: template wording and tools' citation markers, read on slides, a document's body, headers and footers, and PDF pages), `convertLegacyOffice` in `portable-soffice.mjs` (a `.doc`/`.xls`/`.ppt` saved once as its package beside the original when `open` meets one), text and image metrics. |
16
16
  | `pdf/` | `pdf-adapter.mjs` (session surface: snapshot, batch — including the marks `highlight`, `add_link`, `preview_fields` — validate, issues; re-exports `createPdf`), `pdf-writer.mjs` (blocks → pages, tables, page numbers), `pdf-forms.mjs` (field lint, add, describe, fill), `pdf-draw.mjs` (colors, page sizes, wrapping, images), `pdf-fonts.mjs` (system Unicode font fallback shared by create, marks, forms, and OCR), `pdf-analysis.mjs` (text layout with rules, boxes, and links, ruled and aligned tables, images, OCR), `pdf-search.mjs` (text search over a layout: lines from runs, glyph-width placement, whole words), `pdf-safety.mjs` (active-content report: JavaScript, Launch, non-web links), `pdf-render.mjs`, `pdf-security.mjs` (qpdf), `document-preview.mjs`. |
17
17
  | `design/` | Design tokens, content model, composition, creative direction for the Word and Excel composers (`compose_document`, `compose_sheet`); `design-discipline.mjs` owns the safe typeface list, palette repair (tinted dark fields, WCAG contrast, paired accent tints), and the brief rules; `docx/`, `xlsx/` format compilers; `library/` template library with the bundled `templates/`. Decks are never composed here — a slide is authored by the model as a script (`authoring/`), and `compose_slide` is refused with that route. |
18
18
  | `quality/` | Reviews and gates: `assurance-*.mjs` (trust, structure, rendered pages, checklist), aesthetics, design review, scoring, visual diff. |
19
19
  | `bench/` | Benchmarks behind `npm run bench:office*`; `bench-support.mjs` holds the shared tool-call helpers. |
20
- | `shared/` | Tiny helpers used across folders: `values.mjs` (`plainObject`, `clone`, `stableValue`, `sha256`, `clamp`, `compact`, `imageBuffer`), `page-sizes.mjs` (the paper sizes PDF create and Word `set_page` share), `column-widths.mjs` (the widths a Word or PDF table given none takes from its text), and `asar-path.mjs`. |
20
+ | `shared/` | Tiny helpers used across folders: `values.mjs` (`plainObject`, `clone`, `stableValue`, `sha256`, `clamp`, `compact`), `page-sizes.mjs` (the paper sizes PDF create and Word `set_page` share), `column-widths.mjs` (the widths a Word or PDF table given none takes from its text), and `asar-path.mjs`. |
21
21
 
22
22
  ## Dependency direction
23
23
 
@@ -8,6 +8,7 @@ import { render } from '../core/office-actions.mjs';
8
8
  import { documentFormat, officeSessionForDocument } from '../core/office-core.mjs';
9
9
  import { createAuthoredSession, exists, fullPath, validatePptxAuthorMode } from '../core/office-sessions.mjs';
10
10
  import { inlineOfficeAudit } from '../quality/inline-audit.mjs';
11
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
11
12
  import { parseAuthoringBrief } from './pptx-brief.mjs';
12
13
  import { htmlBriefScript } from './pptx-html-runner.mjs';
13
14
  import {
@@ -68,6 +69,7 @@ async function writeComparisons(target, htmlPages, officePages) {
68
69
  (await scaled(officePages.find((image) => image.page === page && (image.pages?.length || 1) === 1))) ||
69
70
  (await blank(left.width));
70
71
  const path = `${target}.mixdog-compare-page-${page}.png`;
72
+ noteOfficeWrite(path);
71
73
  await sharp({ create: { width: left.width + right.width + gap, height, channels: 3, background: '#808080' } })
72
74
  .composite([
73
75
  { input: left.data, left: 0, top: 0 },
@@ -7,6 +7,7 @@
7
7
  import { writeFile } from 'node:fs/promises';
8
8
  import { basename, dirname, extname, join } from 'node:path';
9
9
  import { createCanvas, loadImage } from '@napi-rs/canvas';
10
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
10
11
 
11
12
  function pageImages(images = []) {
12
13
  const pages = [];
@@ -51,6 +52,7 @@ export async function writeContactSheet(images, output, { width = 1600 } = {}) {
51
52
  const data = sheet.toBuffer('image/png');
52
53
  const stem = basename(output, extname(output));
53
54
  const path = join(dirname(output), `${stem}.mixdog-contact.png`);
55
+ noteOfficeWrite(path);
54
56
  await writeFile(path, data);
55
57
  return {
56
58
  path,
@@ -9,6 +9,7 @@ import { createRequire } from 'node:module';
9
9
  import { pathToFileURL } from 'node:url';
10
10
 
11
11
  import { launchHtmlBrowser, runInBrowser } from './html-browser.mjs';
12
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
12
13
  import { iconGlobal } from './pptx-icons.mjs';
13
14
  import { GEOMETRY_TOLERANCE_PX, NEAR_MISS_PX, readGeometry } from './pptx-html-geometry.mjs';
14
15
 
@@ -598,6 +599,7 @@ export async function measureHtmlDeck(
598
599
  );
599
600
  }
600
601
  const shot = shotPath(index + 1);
602
+ noteOfficeWrite(shot);
601
603
  await element.screenshot({ path: shot });
602
604
  shots.push(shot);
603
605
  const measured = await page.evaluate(extractSlide, index);
@@ -6,6 +6,7 @@ import { dirname } from 'node:path';
6
6
  import { createRequire } from 'node:module';
7
7
 
8
8
  import { HTML_CANVAS, measureHtmlDeck } from './pptx-html-measure.mjs';
9
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
9
10
  import { buildPptxFromMeasure } from './pptx-html-build.mjs';
10
11
  import { normalizeAuthoredPptx } from './pptx-script-normalize.mjs';
11
12
 
@@ -312,6 +313,7 @@ export async function writeHtmlComparisons(target, htmlShots, renderedImages) {
312
313
  const left = await sharp(html).resize(width, height, { fit: 'fill' }).png().toBuffer();
313
314
  const right = await sharp(image.path).resize(width, height, { fit: 'fill' }).png().toBuffer();
314
315
  const path = artifacts.compare(image.page);
316
+ noteOfficeWrite(path);
315
317
  await sharp({ create: { width: width * 2 + gap, height, channels: 3, background: '#808080' } })
316
318
  .composite([
317
319
  { input: left, left: 0, top: 0 },
@@ -6,6 +6,7 @@ import { dirname, join } from 'node:path';
6
6
  import { pathToFileURL } from 'node:url';
7
7
 
8
8
  import { htmlFailure, launchHtmlBrowser, photographCaptures, runInBrowser } from './html-browser.mjs';
9
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
9
10
  import { iconTable, injectIcons } from './pptx-html-measure.mjs';
10
11
  import { extractXlsxSheets } from './xlsx-html-measure.mjs';
11
12
  import { drawDataCharts } from './pdf-html-charts.mjs';
@@ -106,6 +107,7 @@ export async function runXlsxHtmlAuthoring(html, output, { target, signal = null
106
107
  const htmlPages = [];
107
108
  for (const [index, clip] of extents.entries()) {
108
109
  const path = artifacts.shot(index + 1);
110
+ noteOfficeWrite(path);
109
111
  await page.screenshot({ path, clip, captureBeyondViewport: true });
110
112
  htmlPages.push({ page: index + 1, path });
111
113
  }
@@ -2,6 +2,7 @@ import { mkdir, writeFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { extractPdfImages, extractPdfTextLayout, findPdfText, inferPdfTables } from '../pdf/pdf-analysis.mjs';
4
4
  import { findByDocumentPath, fullPath, queryObject, snapshot, snapshotSelectionForTarget } from './office-sessions.mjs';
5
+ import { noteOfficeWrite } from './office-write-ledger.mjs';
5
6
 
6
7
  /** RFC 4180 quoting so a table cell that contains a comma or quote round-trips. */
7
8
  export function csvCell(text) {
@@ -94,6 +95,7 @@ async function queryPdfTables(session, args, cwd, signal) {
94
95
  const ordinal = (counters.get(table.page) || 0) + 1;
95
96
  counters.set(table.page, ordinal);
96
97
  const file = join(directory, `page-${table.page}-table-${ordinal}.csv`);
98
+ noteOfficeWrite(file);
97
99
  await writeFile(
98
100
  file,
99
101
  `${table.rows.map((row) => row.map((cell) => csvCell(String(cell ?? ''))).join(',')).join('\r\n')}\r\n`,
@@ -115,6 +117,7 @@ async function queryPdfImages(session, args, cwd, signal) {
115
117
  const written = [];
116
118
  for (const image of extracted._images) {
117
119
  const file = join(directory, `page-${image.page}-image-${image.index}.png`);
120
+ noteOfficeWrite(file);
118
121
  await writeFile(file, Buffer.from(image.data, 'base64'));
119
122
  written.push(file);
120
123
  }
@@ -8,6 +8,7 @@ import { resolveOfficeRenderOutput } from '../quality/quality-pipeline.mjs';
8
8
  import { defaultRenderOutput, exists, fullPath } from './office-sessions.mjs';
9
9
  import { completePageCoverage, pptxPageSignatures, reusablePptxPages } from './pptx-page-cache.mjs';
10
10
  import { numberDocxTableOfContents } from './docx-toc-pages.mjs';
11
+ import { noteOfficeWrite } from './office-write-ledger.mjs';
11
12
 
12
13
  function request(session, args, cwd) {
13
14
  return {
@@ -136,6 +137,7 @@ export async function renderOfficePreview(
136
137
  const exportKey = `${session.target}\0${Number(session.snapshotVersion || 0)}\0${requested.output}`;
137
138
  if (!incremental || session.previewExportKey !== exportKey || !(await exists(requested.output))) {
138
139
  session.previewExportKey = null;
140
+ noteOfficeWrite(requested.output);
139
141
  await exportPreview(session, requested.output);
140
142
  if (incremental) session.previewExportKey = exportKey;
141
143
  }
@@ -9,6 +9,7 @@ import { describeOfficeCapabilities } from '../capabilities.mjs';
9
9
  import { applyBatch, closeSession, finalize, issues, qa, render, save, validate } from './office-actions.mjs';
10
10
  import { getOfficeElement, queryOfficeDocument } from './office-actions-read.mjs';
11
11
  import { snapshot } from './office-sessions.mjs';
12
+ import { noteOfficeWrite } from './office-write-ledger.mjs';
12
13
  import { noteBatchAgainstHtml } from '../authoring/html-source-drift.mjs';
13
14
  import {
14
15
  assertTransactionUnchanged,
@@ -59,7 +60,13 @@ async function batchAction(session, args, cwd, signal) {
59
60
  };
60
61
  }
61
62
 
63
+ // Verbs that never write the session's document.
64
+ const READ_ACTIONS = new Set(['describe', 'begin', 'diff', 'snapshot', 'get', 'query', 'issues', 'validate']);
65
+
62
66
  export async function dispatchOfficeSessionAction({ action, session, args, cwd, signal }) {
67
+ // Write receipt: every other verb may write the session's document (an
68
+ // edit, save, rollback, autoFix, or a render that numbers its contents).
69
+ if (!READ_ACTIONS.has(action)) noteOfficeWrite(session.target);
63
70
  if (action === 'describe') {
64
71
  return describeOfficeCapabilities({
65
72
  format: session.format,
@@ -29,6 +29,7 @@ import {
29
29
  toolResult,
30
30
  } from './office-core.mjs';
31
31
  import { fullPath, selectMode } from './office-sessions.mjs';
32
+ import { noteOfficeWrite } from './office-write-ledger.mjs';
32
33
  import { pendingOfficeTransactions, recoverOfficeTransaction } from './office-transactions.mjs';
33
34
 
34
35
  async function detectAction(args, cwd, dataDir) {
@@ -102,6 +103,13 @@ async function authorAction(args, cwd, dataDir, signal, startedAt) {
102
103
  const extension = extname(String(args.path || args.output || '')).toLowerCase();
103
104
  const author =
104
105
  { '.pdf': authorPdf, '.docx': authorHtmlDocument, '.xlsx': authorHtmlDocument }[extension] || authorPptx;
106
+ // Write receipts: the authored document and the sidecars kept beside it
107
+ // (its HTML source and print); per-page images report themselves.
108
+ for (const value of [args.path, args.output]) {
109
+ if (!String(value || '').trim()) continue;
110
+ const target = fullPath(String(value).trim(), cwd);
111
+ for (const path of [target, `${target}.mixdog-source.html`, `${target}.mixdog-html.pdf`]) noteOfficeWrite(path);
112
+ }
105
113
  const authored = await author(args, { cwd, dataDir, signal });
106
114
  const images = Array.isArray(authored?._images) ? authored._images : [];
107
115
  delete authored._images;
@@ -4,6 +4,7 @@ import { basename, dirname, extname, isAbsolute, join, resolve } from 'node:path
4
4
  import { tmpdir } from 'node:os';
5
5
  import { randomUUID } from 'node:crypto';
6
6
  import { assertOfficeOperationContracts } from '../capabilities.mjs';
7
+ import { noteOfficeWrite } from './office-write-ledger.mjs';
7
8
  import {
8
9
  callMicrosoftOffice,
9
10
  detectMicrosoftOffice,
@@ -258,6 +259,7 @@ async function packageSource(path, signal) {
258
259
  `${path} is a legacy binary file and ${converted} already exists; open ${converted} directly, or move it aside to convert again.`
259
260
  );
260
261
  }
262
+ noteOfficeWrite(converted);
261
263
  await convertLegacyOffice(path, converted, { signal });
262
264
  return { source: converted, convertedFrom: path };
263
265
  }
@@ -280,6 +282,7 @@ export async function openSession(args, cwd, dataDir, { readOnly = false } = {})
280
282
  if (existing) return existing;
281
283
  if (copies) {
282
284
  await mkdir(dirname(target), { recursive: true });
285
+ noteOfficeWrite(target);
283
286
  await copyFile(source, target);
284
287
  }
285
288
  const designContext = await resolveOfficeDesignContext({
@@ -533,6 +536,7 @@ export async function createSession(args, cwd, dataDir) {
533
536
  // Whether this call brings the file into being decides what a failed create
534
537
  // may clean up afterwards: a file it wrote itself, never one already there.
535
538
  const targetExisted = await exists(target);
539
+ noteOfficeWrite(target);
536
540
  const designContext = await resolveOfficeDesignContext({ args, dataDir, target, format, created: true });
537
541
  const creation = { target, fileKind, format, dataDir, targetExisted, designContext };
538
542
  await releaseOverwrittenSession(target, args.overwrite);
@@ -645,6 +649,7 @@ export async function materializeWorkingCopy(session) {
645
649
  throw new Error('portable editing requires an output path different from the source');
646
650
  }
647
651
  await mkdir(dirname(target), { recursive: true });
652
+ noteOfficeWrite(target);
648
653
  await copyFile(session.source, target);
649
654
  if (documentSessions.get(documentSessionKey(session.target)) === session.id) {
650
655
  documentSessions.delete(documentSessionKey(session.target));
@@ -4,6 +4,7 @@ import { tmpdir } from 'node:os';
4
4
  import { randomUUID } from 'node:crypto';
5
5
  import { callMicrosoftOffice, detectMicrosoftOffice, openMicrosoftOfficeSession } from '../com/com-adapter.mjs';
6
6
  import { listOfficeJournals, readOfficeJournal, removeOfficeJournal, writeOfficeJournal } from './journal.mjs';
7
+ import { noteOfficeWrite } from './office-write-ledger.mjs';
7
8
  import {
8
9
  OfficeConflictError,
9
10
  documentFingerprint,
@@ -299,6 +300,8 @@ export async function rollbackTransaction(session) {
299
300
  transaction.diff = transactionDocumentDiff(transaction, current.document);
300
301
  transaction.phase = 'rolling_back';
301
302
  await persistOfficeTransaction(session);
303
+ // A recovered rollback restores the document outside any session verb.
304
+ noteOfficeWrite(session.target);
302
305
  if (isMicrosoftOfficeSession(session)) {
303
306
  const result = await callMicrosoftOffice(
304
307
  {
@@ -0,0 +1,98 @@
1
+ /**
2
+ * office-write-ledger.mjs — the workspace files one Office Use call wrote,
3
+ * with their exact before/after state, so the session's turn review counts
4
+ * them as its own changes and Undo can restore them.
5
+ *
6
+ * Ownership is never inferred from the folder: every route that writes a
7
+ * workspace file — the session's working copy, a created or converted
8
+ * document, a render's preview and page images, a split/extract/query output,
9
+ * an authored document and its sidecars, a secured PDF — hands the path to
10
+ * noteOfficeWrite BEFORE it writes, which captures the file's prior state.
11
+ * After the call, only noted files whose bytes changed are recorded. Scratch
12
+ * files outside the workspace (the system temp folder, the Office data
13
+ * folder) are never noted.
14
+ */
15
+ import { AsyncLocalStorage } from 'node:async_hooks';
16
+ import { statSync } from 'node:fs';
17
+ import { tmpdir } from 'node:os';
18
+ import { isAbsolute, relative, resolve } from 'node:path';
19
+ import {
20
+ PATCH_EDIT_BUDGET_BYTES,
21
+ createSnapshotBudget,
22
+ reviewFileContent,
23
+ } from '../../shared/bounded-file-read.mjs';
24
+
25
+ const ledgers = new AsyncLocalStorage();
26
+
27
+ const pathKey = (path) => (process.platform === 'win32' ? path.toLowerCase() : path);
28
+
29
+ function inside(parent, child) {
30
+ if (!parent) return false;
31
+ const rel = relative(resolve(parent), child);
32
+ return !rel || (!rel.startsWith('..') && !isAbsolute(rel));
33
+ }
34
+
35
+ function fileStamp(path) {
36
+ try {
37
+ const info = statSync(path);
38
+ return info.isFile() ? { size: info.size, mtimeMs: info.mtimeMs } : null;
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ /** Run one Office call with a ledger its write routes report into. */
45
+ export function runWithOfficeWriteLedger({ cwd, dataDir }, task) {
46
+ const ledger = {
47
+ cwd: resolve(cwd || process.cwd()),
48
+ dataDir: dataDir ? resolve(dataDir) : '',
49
+ budget: createSnapshotBudget(PATCH_EDIT_BUDGET_BYTES),
50
+ before: new Map(),
51
+ };
52
+ return { ledger, run: ledgers.run(ledger, task) };
53
+ }
54
+
55
+ /** A write receipt: the call is about to write `path`. The first receipt of a
56
+ * path captures its state before the write; a call without a ledger (no
57
+ * session to credit) and scratch paths are ignored. */
58
+ export function noteOfficeWrite(path) {
59
+ const ledger = ledgers.getStore();
60
+ const text = typeof path === 'string' ? path.trim() : '';
61
+ if (!ledger || !text) return;
62
+ const fullPath = resolve(ledger.cwd, text);
63
+ const key = pathKey(fullPath);
64
+ if (ledger.before.has(key)) return;
65
+ if (inside(ledger.dataDir, fullPath)) return;
66
+ if (inside(tmpdir(), fullPath) && !inside(ledger.cwd, fullPath)) return;
67
+ let content;
68
+ try {
69
+ content = reviewFileContent(fullPath, { budget: ledger.budget });
70
+ } catch {
71
+ return; // not a regular file: never recorded
72
+ }
73
+ ledger.before.set(key, { fullPath, content, stamp: fileStamp(fullPath) });
74
+ }
75
+
76
+ const sameBytes = (left, right) => Buffer.isBuffer(left) && Buffer.isBuffer(right) && left.equals(right);
77
+
78
+ /** Every noted file the call created, changed or removed, as
79
+ * `{ fullPath, before, after }` (null = absent). */
80
+ export function officeWriteChanges(ledger) {
81
+ const changes = [];
82
+ for (const { fullPath, content: before, stamp: priorStamp } of ledger.before.values()) {
83
+ const stamp = fileStamp(fullPath);
84
+ if (!priorStamp && !stamp) continue;
85
+ // Uncaptured bytes compare by their stamp; captured ones byte for byte.
86
+ const untouched = priorStamp && stamp && priorStamp.size === stamp.size && priorStamp.mtimeMs === stamp.mtimeMs;
87
+ if (untouched && !Buffer.isBuffer(before)) continue;
88
+ let after = null;
89
+ try {
90
+ after = stamp ? reviewFileContent(fullPath) : null;
91
+ } catch {
92
+ continue;
93
+ }
94
+ if (sameBytes(before, after)) continue;
95
+ changes.push({ fullPath, before, after });
96
+ }
97
+ return changes;
98
+ }
@@ -14,6 +14,7 @@ import {
14
14
  toolResult,
15
15
  } from './core/office-core.mjs';
16
16
  import { resolveSession } from './core/office-sessions.mjs';
17
+ import { officeWriteChanges, runWithOfficeWriteLedger } from './core/office-write-ledger.mjs';
17
18
 
18
19
  // Office work is minutes of real application time, and guessing which action carries it is how
19
20
  // tuning goes wrong. MIXDOG_OFFICE_TRACE writes one line per call so a slow run maps itself; it
@@ -27,6 +28,35 @@ const OFFICE_TRACE = process.env.MIXDOG_OFFICE_TRACE || '';
27
28
  const READ_ONLY_ACTIONS = new Set(['snapshot', 'get', 'query', 'issues', 'validate', 'describe', 'render', 'qa']);
28
29
 
29
30
  export async function executeOfficeTool(args = {}, context = {}) {
31
+ const sessionId = String(context.sessionId || '');
32
+ if (!sessionId) return await tracedOfficeTool(args, context);
33
+ const cwd = context.cwd || process.cwd();
34
+ const { ledger, run } = runWithOfficeWriteLedger(
35
+ { cwd, dataDir: context.dataDir || defaultOfficeDataDir() },
36
+ () => tracedOfficeTool(args, context)
37
+ );
38
+ try {
39
+ return await run;
40
+ } finally {
41
+ await recordOfficeWrites(ledger, sessionId, cwd);
42
+ }
43
+ }
44
+
45
+ // The files this call's write routes reported join the session's turn review
46
+ // as its own changes (counted, and undoable where their bytes were captured).
47
+ // The recorder is loaded on first use; recording never affects the result.
48
+ async function recordOfficeWrites(ledger, sessionId, cwd) {
49
+ try {
50
+ const changes = officeWriteChanges(ledger);
51
+ if (changes.length === 0) return;
52
+ const { recordToolFileChanges } = await import('../agent/orchestrator/tools/patch/ui-diff.mjs');
53
+ recordToolFileChanges({ sessionId, basePath: cwd, changes });
54
+ } catch {
55
+ /* best-effort review channel */
56
+ }
57
+ }
58
+
59
+ async function tracedOfficeTool(args, context) {
30
60
  if (!OFFICE_TRACE) return await runOfficeTool(args, context);
31
61
  const startedAt = performance.now();
32
62
  try {
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { mkdir, writeFile } from 'node:fs/promises';
7
7
  import { dirname, resolve } from 'node:path';
8
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
8
9
  import {
9
10
  PDFDocument,
10
11
  PDFArray,
@@ -130,6 +131,7 @@ export async function writeSibling(path, target, bytes) {
130
131
  if (output.toLowerCase() === resolve(path).toLowerCase())
131
132
  throw new Error('output must differ from the document being edited');
132
133
  await mkdir(dirname(output), { recursive: true });
134
+ noteOfficeWrite(output);
133
135
  await writeFile(output, bytes);
134
136
  return output;
135
137
  }
@@ -5,6 +5,7 @@ import { createCanvas, loadImage } from '@napi-rs/canvas';
5
5
  import { pdfjsStandardFontDataUrl, resolvedPdfJs } from '../../attachments/pdfjs-runtime.mjs';
6
6
  import { installPdfGlobals } from './pdf-document.mjs';
7
7
  import { workerExecArgv } from '../../shared/worker-exec-argv.mjs';
8
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
8
9
 
9
10
  const PAGE_NUMBER_PATTERN = /^\s*(?:(?:page\s*)?\d+\s*(?:of|\/)\s*\d+|페이지\s*\d+|\d+\s*페이지)\s*$/i;
10
11
 
@@ -144,8 +145,8 @@ async function runPdfRenderWorker(data, signal = null) {
144
145
  }
145
146
 
146
147
  // Many pages are reviewed as contact sheets: one labelled grid image per group
147
- // of pages, written next to the PDF.
148
- async function writeContactSheet(group, width, imagePath, renderPage) {
148
+ // of pages, for a file next to the PDF.
149
+ async function contactSheet(group, width, imagePath, renderPage) {
149
150
  const columns = group.length <= 2 ? 1 : Math.max(2, Math.ceil(Math.sqrt(group.length * 0.75)));
150
151
  const rows = Math.ceil(group.length / columns);
151
152
  const gap = 12;
@@ -182,7 +183,6 @@ async function writeContactSheet(group, width, imagePath, renderPage) {
182
183
  context.strokeRect(x, y + labelHeight, image.width, image.height);
183
184
  }
184
185
  const data = sheet.toBuffer('image/png');
185
- await writeFile(imagePath, data);
186
186
  return {
187
187
  page: group[0],
188
188
  pages: group,
@@ -204,7 +204,18 @@ async function writeContactSheet(group, width, imagePath, renderPage) {
204
204
  };
205
205
  }
206
206
 
207
- async function renderPdfPagesDirect(path, { pages = null, maxWidth = 1400, maximumScale = 2, signal = null } = {}) {
207
+ // The page images land beside the PDF, each reported as an Office write first.
208
+ async function writePageImages(images) {
209
+ for (const image of images) {
210
+ noteOfficeWrite(image.path);
211
+ await writeFile(image.path, Buffer.from(image.data, 'base64'));
212
+ }
213
+ }
214
+
215
+ async function renderPdfPagesDirect(
216
+ path,
217
+ { pages = null, maxWidth = 1400, maximumScale = 2, signal = null, writeImages = true } = {}
218
+ ) {
208
219
  if (signal?.aborted) throw new Error('PDF rendering was cancelled');
209
220
  installPdfGlobals();
210
221
  const { getDocument, VerbosityLevel } = await resolvedPdfJs();
@@ -248,7 +259,6 @@ async function renderPdfPagesDirect(path, { pages = null, maxWidth = 1400, maxim
248
259
  for (const pageNumber of selected) {
249
260
  const { canvas, data } = await renderPage(pageNumber, maxWidth);
250
261
  const imagePath = join(dirname(path), `${stem}-page-${pageNumber}.png`);
251
- await writeFile(imagePath, data);
252
262
  output.push({
253
263
  page: pageNumber,
254
264
  path: imagePath,
@@ -264,9 +274,10 @@ async function renderPdfPagesDirect(path, { pages = null, maxWidth = 1400, maxim
264
274
  for (let offset = 0; offset < selected.length; offset += pagesPerSheet) {
265
275
  const group = selected.slice(offset, offset + pagesPerSheet);
266
276
  const imagePath = join(dirname(path), `${stem}-pages-${group[0]}-${group.at(-1)}.png`);
267
- output.push(await writeContactSheet(group, width, imagePath, renderPage));
277
+ output.push(await contactSheet(group, width, imagePath, renderPage));
268
278
  }
269
279
  }
280
+ if (writeImages) await writePageImages(output);
270
281
  const reviewedPages = output.flatMap((image) => image.pages || [image.page]);
271
282
  const reviewedPageSet = new Set(reviewedPages);
272
283
  return {
@@ -293,7 +304,9 @@ export async function renderPdfPages(path, options = {}) {
293
304
  const signal = options.signal || null;
294
305
  if (signal?.aborted) throw new Error('PDF rendering was cancelled');
295
306
  if (!isMainThread) return await renderPdfPagesDirect(path, options);
296
- return await runPdfRenderWorker(
307
+ // The worker rasterizes; this thread writes the images, where the call's
308
+ // write ledger can see each one before it lands.
309
+ const rendered = await runPdfRenderWorker(
297
310
  {
298
311
  kind: PDF_RENDER_WORKER_KIND,
299
312
  path,
@@ -301,10 +314,13 @@ export async function renderPdfPages(path, options = {}) {
301
314
  pages: options.pages ?? null,
302
315
  maxWidth: options.maxWidth ?? 1400,
303
316
  maximumScale: options.maximumScale ?? 2,
317
+ writeImages: false,
304
318
  },
305
319
  },
306
320
  signal
307
321
  );
322
+ await writePageImages(rendered.images);
323
+ return rendered;
308
324
  }
309
325
 
310
326
  if (!isMainThread && [PDF_RENDER_WORKER_KIND, PDF_RENDER_PAGE_WORKER_KIND].includes(workerData?.kind)) {
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { writeFile, rm, rename } from 'node:fs/promises';
4
4
  import { dirname, join } from 'node:path';
5
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
5
6
 
6
7
  // qpdf on PATH, or wherever MIXDOG_QPDF_PATH points (the Windows installer
7
8
  // does not add itself to PATH).
@@ -89,6 +90,7 @@ export async function securePdf({ input, output, mode, password = '', ownerPassw
89
90
  ? ['--encrypt', password, ownerPassword || password, '256', '--', input, target]
90
91
  : [`--password=${password}`, '--decrypt', input, target];
91
92
  await writeFile(responsePath, `${args.join('\n')}\n`, { encoding: 'utf8', mode: 0o600 });
93
+ noteOfficeWrite(output);
92
94
  try {
93
95
  await run(QPDF, [`@${responsePath}`]);
94
96
  if (samePath) await rename(target, output);
@@ -1,6 +1,7 @@
1
1
  import { posix } from 'node:path';
2
2
  import { createHash } from 'node:crypto';
3
3
  import { readFile, writeFile } from 'node:fs/promises';
4
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
4
5
  import { koreanParticleReplacements } from '../shared/korean-particles.mjs';
5
6
  import { presetLabels } from '../shared/labels.mjs';
6
7
  import {
@@ -137,7 +138,9 @@ export async function packageBuffer(zip) {
137
138
  }
138
139
 
139
140
  export async function savePackage(zip, path) {
140
- await writeFile(path, await packageBuffer(zip));
141
+ const bytes = await packageBuffer(zip);
142
+ noteOfficeWrite(path);
143
+ await writeFile(path, bytes);
141
144
  }
142
145
 
143
146
  export function relationshipMap(xml) {
@@ -1,6 +1,7 @@
1
1
  import { writeFile } from 'node:fs/promises';
2
2
  import { dirname, extname, basename, join } from 'node:path';
3
3
  import { createCanvas, loadImage } from '@napi-rs/canvas';
4
+ import { noteOfficeWrite } from '../core/office-write-ledger.mjs';
4
5
 
5
6
  function imageByPage(images) {
6
7
  return new Map((images || []).map((image) => [Number(image.page), image]));
@@ -61,6 +62,7 @@ export async function compareRenderedPages(beforeImages, afterImages, outputPdf)
61
62
  diffContext.putImageData(diff, 0, 0);
62
63
  const data = diffCanvas.toBuffer('image/png');
63
64
  const path = join(dirname(outputPdf), `${stem}-visual-diff-page-${page}.png`);
65
+ noteOfficeWrite(path);
64
66
  await writeFile(path, data);
65
67
  const total = width * height;
66
68
  metrics.push({
@@ -32,8 +32,3 @@ export function compact(value, maximum = 120) {
32
32
  .replace(/\s+/g, ' ')
33
33
  .slice(0, maximum);
34
34
  }
35
-
36
- export function imageBuffer(image) {
37
- if (Buffer.isBuffer(image?.data)) return image.data;
38
- return Buffer.from(String(image?.data || ''), 'base64');
39
- }