mixdog 1.2.2 → 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 (415) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/provider-pingpong-live.mjs +509 -0
  4. package/src/agents/advisor/AGENT.md +1 -1
  5. package/src/agents/advisor/agent.json +1 -1
  6. package/src/defaults/shipped-history.json +5 -0
  7. package/src/defaults/skills/setup/SKILL.md +6 -1
  8. package/src/defaults/skills/setup/references/actions.md +44 -22
  9. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  10. package/src/headless-exec.mjs +15 -8
  11. package/src/lib/keychain-cjs.cjs +7 -4
  12. package/src/output-styles/common.md +11 -10
  13. package/src/rules/agent/AGENT.md +5 -5
  14. package/src/rules/lead/LEAD.md +5 -5
  15. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  16. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  17. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  18. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  19. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  21. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  22. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  23. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +2 -0
  24. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
  25. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +7 -6
  26. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +29 -10
  28. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  30. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  31. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  32. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  33. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  34. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  35. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -0
  36. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  37. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +6 -0
  38. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +58 -7
  39. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
  40. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +16 -3
  41. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  42. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +12 -6
  43. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +114 -72
  45. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  46. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +37 -5
  47. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +1 -0
  49. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  50. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +3 -0
  51. package/src/runtime/agent/orchestrator/providers/cursor.mjs +9 -2
  52. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  53. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  54. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  55. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  56. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  57. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  59. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +25 -8
  60. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +87 -5
  61. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  62. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +13 -13
  63. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +355 -37
  64. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
  65. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +93 -47
  66. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +55 -10
  67. package/src/runtime/agent/orchestrator/providers/gemini.mjs +26 -8
  68. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
  70. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  71. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  72. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  73. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  74. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  75. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  76. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  77. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  78. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  80. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  81. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  82. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  83. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  84. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  85. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  86. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +121 -61
  89. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  90. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +5 -2
  91. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  92. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  93. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +1 -1
  94. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  95. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  96. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  97. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  98. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +42 -24
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +53 -5
  103. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
  108. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
  109. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
  110. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  111. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +25 -4
  112. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  113. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  114. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +4 -0
  115. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
  116. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  117. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
  119. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
  120. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
  121. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +71 -24
  122. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  123. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  124. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  125. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  126. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  127. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  128. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  129. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  130. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +11 -3
  131. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  132. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  133. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  134. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +147 -8
  135. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  136. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +5 -0
  137. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  138. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  139. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  140. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  141. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  142. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  143. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  146. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  147. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  148. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  149. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  150. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  151. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  152. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  153. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  154. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  155. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -1
  156. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  157. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  158. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  159. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  160. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  161. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  162. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  163. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  164. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  165. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  167. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  168. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  169. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  170. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  171. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  172. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +63 -20
  173. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +2 -1
  174. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  175. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  176. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  177. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  178. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  179. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +4 -1
  180. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  181. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  182. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +16 -0
  183. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  184. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  185. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  186. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  187. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  188. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +15 -3
  189. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  190. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  191. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  192. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  193. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  195. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  196. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +13 -0
  197. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  198. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  199. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  200. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  201. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  202. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  203. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  204. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  205. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  206. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  207. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
  208. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
  209. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -1
  210. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  211. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  212. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  213. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  214. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  215. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  216. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  217. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  218. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  219. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  221. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  222. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  223. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  224. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  225. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  226. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  227. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  228. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  229. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  230. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  231. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  232. package/src/runtime/github/tool.mjs +92 -2
  233. package/src/runtime/memory/index.mjs +1 -0
  234. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  235. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  236. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  237. package/src/runtime/memory/lib/pg/process.mjs +31 -26
  238. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  239. package/src/runtime/memory/lib/pg/supervisor.mjs +108 -3
  240. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  241. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  242. package/src/runtime/office/README.md +1 -1
  243. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  244. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  245. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  246. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  247. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  248. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  249. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  250. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  251. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  252. package/src/runtime/office/core/office-sessions.mjs +5 -0
  253. package/src/runtime/office/core/office-transactions.mjs +3 -0
  254. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  255. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  256. package/src/runtime/office/index.mjs +30 -0
  257. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  258. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  259. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  260. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  261. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  262. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  263. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  264. package/src/runtime/shared/buffered-appender.mjs +18 -0
  265. package/src/runtime/shared/config.mjs +78 -18
  266. package/src/runtime/shared/err-text.mjs +6 -0
  267. package/src/runtime/shared/file-permissions.d.mts +6 -1
  268. package/src/runtime/shared/file-permissions.mjs +54 -6
  269. package/src/runtime/shared/llm/anthropic-effort.mjs +6 -0
  270. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  271. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  272. package/src/runtime/shared/loopback-listener.mjs +9 -0
  273. package/src/runtime/shared/provider-api-key.mjs +2 -0
  274. package/src/runtime/shared/review-diff.mjs +52 -0
  275. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  276. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  277. package/src/runtime/shared/slow-span.mjs +114 -0
  278. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  279. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  280. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  281. package/src/runtime/shared/tool-card-model.mjs +5 -2
  282. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  283. package/src/runtime/shared/tool-primitives.mjs +13 -0
  284. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  285. package/src/runtime/shared/tool-surface.mjs +18 -3
  286. package/src/runtime/shared/tool-work-units.mjs +40 -4
  287. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  288. package/src/runtime/shared/transcript-writer.mjs +10 -2
  289. package/src/runtime/shared/turn-changes.mjs +268 -100
  290. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  291. package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
  292. package/src/runtime/shared/turn-snapshot.mjs +857 -683
  293. package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
  294. package/src/runtime/shared/user-data-guard.mjs +262 -49
  295. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  296. package/src/runtime/shared/worktrees/contract.mjs +34 -0
  297. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  298. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  299. package/src/runtime/shared/worktrees/git.mjs +8 -3
  300. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  301. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  302. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  303. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  304. package/src/runtime/terminal-bridge/client.mjs +44 -11
  305. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  306. package/src/runtime/tidy/apply.mjs +47 -2
  307. package/src/runtime/tidy/run-engines.mjs +11 -5
  308. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  309. package/src/session-runtime/boot/apis.mjs +13 -5
  310. package/src/session-runtime/boot/facade.mjs +1 -0
  311. package/src/session-runtime/boot/infrastructure.mjs +6 -1
  312. package/src/session-runtime/boot/session.mjs +0 -1
  313. package/src/session-runtime/boot/tools.mjs +4 -1
  314. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  315. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  316. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  317. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  318. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  319. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  320. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  321. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  322. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -3
  323. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  324. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  325. package/src/session-runtime/lifecycle/teardown.mjs +72 -7
  326. package/src/session-runtime/lifecycle-api.mjs +1 -0
  327. package/src/session-runtime/mcp-glue/connect.mjs +17 -5
  328. package/src/session-runtime/model-route/set-route.mjs +2 -2
  329. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  330. package/src/session-runtime/native-web-search.mjs +10 -1
  331. package/src/session-runtime/new-session-config.mjs +4 -2
  332. package/src/session-runtime/provider-auth/login.mjs +4 -0
  333. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  334. package/src/session-runtime/runtime-review-api.mjs +8 -2
  335. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  336. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  337. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  338. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  339. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  340. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  341. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  342. package/src/session-runtime/services/agent-tool.mjs +3 -0
  343. package/src/session-runtime/services/channel-admin.mjs +19 -3
  344. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  345. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  346. package/src/session-runtime/services/provider-admin.mjs +81 -15
  347. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  348. package/src/session-runtime/session-turn-api.mjs +14 -5
  349. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  350. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  351. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  352. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  353. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  354. package/src/session-runtime/skills-api.mjs +3 -5
  355. package/src/session-runtime/tool-surface.mjs +5 -1
  356. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  357. package/src/session-runtime/turn/session-ops.mjs +7 -5
  358. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  359. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  360. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  361. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  362. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  363. package/src/session-runtime/turn/turn-run.mjs +25 -9
  364. package/src/session-runtime/usage-stats-api.mjs +43 -11
  365. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  366. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  367. package/src/session-runtime/workspace/transitions.mjs +190 -15
  368. package/src/standalone/daemon-agent-control.mjs +9 -1
  369. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  370. package/src/standalone/daemon-owner.mjs +17 -4
  371. package/src/standalone/daemon-pg-stop.mjs +51 -0
  372. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  373. package/src/standalone/daemon-stop-budget.mjs +18 -0
  374. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  375. package/src/standalone/daemon-telemetry.mjs +19 -0
  376. package/src/standalone/daemon.mjs +61 -1
  377. package/src/standalone/desktop-service-registry.mjs +5 -0
  378. package/src/standalone/local-session-runtime.mjs +70 -19
  379. package/src/standalone/session-client.mjs +42 -0
  380. package/src/standalone/session-protocol.mjs +7 -0
  381. package/src/standalone/session-proxy/projection.mjs +41 -4
  382. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  383. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  384. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  385. package/src/standalone/session-service-api.mjs +6 -1
  386. package/src/standalone/session-state-patch.d.mts +2 -1
  387. package/src/standalone/session-state-patch.mjs +41 -1
  388. package/src/tui/App.jsx +25 -0
  389. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  390. package/src/tui/app/btw-controller.mjs +118 -0
  391. package/src/tui/app/create-app-pickers.mjs +2 -0
  392. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  393. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  394. package/src/tui/app/slash-commands.mjs +13 -3
  395. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  396. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  397. package/src/tui/app/use-global-key-input.mjs +5 -12
  398. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  399. package/src/tui/components/BtwPanel.jsx +53 -0
  400. package/src/tui/components/QuestionPanel.jsx +275 -0
  401. package/src/tui/components/question-panel-model.mjs +156 -0
  402. package/src/tui/dist/index.mjs +2413 -1465
  403. package/src/tui/session/context-state.mjs +4 -2
  404. package/src/tui/session/session-api/commands.mjs +10 -0
  405. package/src/tui/session/session-api/controls.mjs +2 -2
  406. package/src/tui/session/session-api/integrations.mjs +9 -2
  407. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  408. package/src/tui/session/session-api/lifecycle.mjs +2 -1
  409. package/src/tui/session/session-api/settings.mjs +6 -0
  410. package/src/tui/session/session-api.mjs +1 -0
  411. package/src/tui/session/tool-approval.mjs +10 -7
  412. package/src/tui/session/transcript-spill.mjs +14 -7
  413. package/src/tui/session/turn-stream.mjs +174 -31
  414. package/src/tui/session/turn.mjs +12 -5
  415. package/src/workflows/default/WORKFLOW.md +3 -1
@@ -7,13 +7,17 @@
7
7
  * `label`, `agent`, `provider`, `model`, `effort`, `fast`, `finished`) and the
8
8
  * "\n\nResult:\n" marker are the wire format the notification writer emits;
9
9
  * they are matched verbatim.
10
+ *
11
+ * Only the parent(s) named by metadata are read — never the sessions
12
+ * directory: every vanished id reaches this path (deleted Lead records too),
13
+ * and a synchronous scan of every session file froze the daemon loop.
10
14
  */
11
- import { readFileSync, readdirSync } from 'node:fs';
15
+ import { readFile } from 'node:fs/promises';
12
16
  import { join } from 'node:path';
13
- import { probePath, PROBE_PRESENT } from './store/fs-probe.mjs';
14
17
  import { readTopLevelLifecycleRecord, isLifecycleUnreadable } from './lifecycle-scan.mjs';
15
18
  import { dataDir } from './store-summary-locations.mjs';
16
- import { cleanValue, desktopSession, positiveNumber } from './store-summary-fields.mjs';
19
+ import { listStoredAgentWorkerLinks } from './store-agent-worker-rows.mjs';
20
+ import { cleanValue, desktopSession, isStoredSessionId, positiveNumber } from './store-summary-fields.mjs';
17
21
 
18
22
  function archivedAgentNotification(content, sessionId) {
19
23
  const text = typeof content === 'string' ? content : '';
@@ -52,23 +56,38 @@ function archivedAgentNotification(content, sessionId) {
52
56
  };
53
57
  }
54
58
 
59
+ /** Parent session ids metadata names for `sessionId`: its agent-workers.json
60
+ * link and its summary-catalog row (`catalogRow(id)`, optional). */
61
+ function parentSessionIds(sessionId, catalogRow) {
62
+ const parents = new Set();
63
+ for (const link of listStoredAgentWorkerLinks()) {
64
+ if (link.sessionId !== sessionId) continue;
65
+ parents.add(link.parentSessionId);
66
+ parents.add(link.ownerSessionId);
67
+ }
68
+ const row = typeof catalogRow === 'function' ? catalogRow(sessionId) : null;
69
+ if (row) {
70
+ parents.add(cleanValue(row.parentSessionId));
71
+ parents.add(cleanValue(row.ownerSessionId));
72
+ }
73
+ parents.delete(sessionId);
74
+ return [...parents].filter(isStoredSessionId);
75
+ }
76
+
55
77
  /** Legacy recovery for child transcripts already unlinked by terminal reaping.
56
- * The parent owns one canonical body-carrying completion notification, so scan
57
- * only files containing the exact child id and project the newest valid body. */
58
- export function readArchivedAgentResult(sessionId) {
78
+ * The parent owns one canonical body-carrying completion notification: read
79
+ * only the parent(s) metadata links the child to, asynchronously, and project
80
+ * the newest valid body. An id with no parent link (a deleted Lead record)
81
+ * resolves to null without touching any session file. */
82
+ export async function readArchivedAgentResult(sessionId, { catalogRow } = {}) {
83
+ const parents = parentSessionIds(sessionId, catalogRow);
84
+ if (parents.length === 0) return null;
59
85
  const dir = join(dataDir(), 'sessions');
60
- if (probePath(dir).state !== PROBE_PRESENT) return null;
61
- let files;
62
- try {
63
- files = readdirSync(dir).filter((file) => file.endsWith('.json'));
64
- } catch {
65
- return null;
66
- }
67
86
  let best = null;
68
- for (const file of files) {
87
+ for (const parentId of parents) {
69
88
  let raw;
70
89
  try {
71
- raw = readFileSync(join(dir, file), 'utf8');
90
+ raw = await readFile(join(dir, `${parentId}.json`), 'utf8');
72
91
  } catch {
73
92
  continue;
74
93
  }
@@ -24,8 +24,10 @@ import {
24
24
  inheritedFromSessionId,
25
25
  isStoredSessionId,
26
26
  positiveNumber,
27
+ realTurnCount,
27
28
  workspaceSummary,
28
29
  } from './store-summary-fields.mjs';
30
+ import { isRealTurnMessage } from './compact/user-message-kind.mjs';
29
31
  import { byActivityThenId } from './catalog-db/schema.mjs';
30
32
  import {
31
33
  sessionStampOf,
@@ -182,6 +184,7 @@ export function normalizedRow(row, heartbeatAt = 0) {
182
184
  permission: row.permission || null,
183
185
  toolPermission: row.toolPermission || null,
184
186
  messageCount: Math.max(0, Math.floor(Number(row.messageCount) || 0)),
187
+ realTurnCount: realTurnCount(row),
185
188
  title: cleanText(row.title, 100),
186
189
  preview: cleanText(row.preview),
187
190
  generation: typeof row.generation === 'number' ? row.generation : 0,
@@ -240,6 +243,7 @@ function rowFromSession(session, heartbeatAt = 0) {
240
243
  {
241
244
  ...session,
242
245
  messageCount: messages.filter((message) => message?.role === 'user' || message?.role === 'assistant').length,
246
+ realTurnCount: messages.filter(isRealTurnMessage).length,
243
247
  preview,
244
248
  },
245
249
  heartbeatAt
@@ -55,6 +55,14 @@ export function inheritedFromSessionId(value) {
55
55
  return id || null;
56
56
  }
57
57
 
58
+ /** Count of real human turns a session persisted (actual user instructions
59
+ * plus compact summaries, which stand for earlier human turns); null for a
60
+ * row written before the field existed. */
61
+ export function realTurnCount(value) {
62
+ const count = value?.realTurnCount;
63
+ return typeof count === 'number' && Number.isFinite(count) && count >= 0 ? Math.floor(count) : null;
64
+ }
65
+
58
66
  export function importKey(value) {
59
67
  const key = typeof value?.importKey === 'string' ? value.importKey : value?.importOrigin?.key;
60
68
  return typeof key === 'string' && key.trim() ? key : null;
@@ -23,8 +23,10 @@ import {
23
23
  inheritedFromSessionId,
24
24
  isStoredSessionId,
25
25
  positiveNumber as _positiveNumber,
26
+ realTurnCount,
26
27
  workspaceSummary,
27
28
  } from './store-summary-fields.mjs';
29
+ import { isRealTurnMessage } from './compact/user-message-kind.mjs';
28
30
 
29
31
  export const SESSION_SUMMARY_INDEX_VERSION = 2;
30
32
 
@@ -92,6 +94,7 @@ function _sessionMessageProjection(session) {
92
94
  const cached = session && typeof session === 'object' ? sessionMessageProjectionMemo.get(session) : null;
93
95
  let start = 0;
94
96
  let count = 0;
97
+ let real = 0;
95
98
  let preview = '';
96
99
  let previewMessage = null;
97
100
  const canAppend =
@@ -101,6 +104,7 @@ function _sessionMessageProjection(session) {
101
104
  if (canAppend) {
102
105
  start = cached.length;
103
106
  count = cached.count;
107
+ real = cached.real;
104
108
  preview = cached.preview;
105
109
  previewMessage = cached.previewMessage;
106
110
  // The first real user message is stable in normal append-only session
@@ -112,6 +116,7 @@ function _sessionMessageProjection(session) {
112
116
  else {
113
117
  start = 0;
114
118
  count = 0;
119
+ real = 0;
115
120
  preview = '';
116
121
  previewMessage = null;
117
122
  }
@@ -120,6 +125,7 @@ function _sessionMessageProjection(session) {
120
125
  for (let index = start; index < messages.length; index += 1) {
121
126
  const message = messages[index];
122
127
  if (message && (message.role === 'user' || message.role === 'assistant')) count += 1;
128
+ if (isRealTurnMessage(message)) real += 1;
123
129
  if (!preview) {
124
130
  const candidate = _previewFromMessage(message);
125
131
  if (candidate) {
@@ -133,11 +139,12 @@ function _sessionMessageProjection(session) {
133
139
  length: messages.length,
134
140
  lastMessage: messages[messages.length - 1] || null,
135
141
  count,
142
+ real,
136
143
  preview,
137
144
  previewMessage,
138
145
  });
139
146
  }
140
- return { count, preview };
147
+ return { count, real, preview };
141
148
  }
142
149
 
143
150
  function _desktopSessionSummary(value, cwd = null) {
@@ -199,6 +206,7 @@ export function _sessionSummary(session) {
199
206
  : null,
200
207
  taskType: session.taskType || null,
201
208
  messageCount: messageProjection.count,
209
+ realTurnCount: messageProjection.real,
202
210
  title: _cleanPreview(session.title || '', 100),
203
211
  preview: messageProjection.preview,
204
212
  generation: typeof session.generation === 'number' ? session.generation : 0,
@@ -253,6 +261,7 @@ function _normalizeSummaryRow(row) {
253
261
  : null,
254
262
  taskType: row.taskType || null,
255
263
  messageCount: Math.max(0, Math.floor(Number(row.messageCount) || 0)),
264
+ realTurnCount: realTurnCount(row),
256
265
  title: _cleanPreview(row.title || '', 100),
257
266
  preview: _cleanPreview(row.preview || ''),
258
267
  generation: typeof row.generation === 'number' ? row.generation : 0,
@@ -250,6 +250,14 @@ function storedSessionMetadata(sessionId, session) {
250
250
  };
251
251
  }
252
252
 
253
+ /** A record that is gone may be a reaped agent child: its parent is resolved
254
+ * from metadata only (worker link, summary-index row), never by a scan. */
255
+ function readVanishedSessionTranscript(sessionId) {
256
+ return readArchivedAgentResult(sessionId, {
257
+ catalogRow: (id) => ordinaryCatalog.loadIndex().rowsById.get(id) || null,
258
+ });
259
+ }
260
+
253
261
  /** The two files a stored transcript projection is built from. */
254
262
  function storedTranscriptInputPaths(sessionId) {
255
263
  return {
@@ -375,7 +383,7 @@ export async function readStoredSessionTranscript(id, options = {}) {
375
383
  // Phase durations of the parse this call ran (absent on a cache hit).
376
384
  const timing = {};
377
385
  const recordStat = probePath(recordPath);
378
- if (recordStat.state === PROBE_ABSENT) return readArchivedAgentResult(sessionId);
386
+ if (recordStat.state === PROBE_ABSENT) return readVanishedSessionTranscript(sessionId);
379
387
  if (recordStat.state !== PROBE_PRESENT) return null;
380
388
  const checkpoint = probePath(checkpointPath);
381
389
  const archive = probePath(archivePath);
@@ -441,7 +449,7 @@ export async function readStoredSessionTranscript(id, options = {}) {
441
449
  produce: (text) => produceStoredTranscript(text, readStamp, produceContext),
442
450
  });
443
451
  // The record vanished between stat and read: same answer as an absent probe.
444
- if (readState === PROBE_ABSENT) return readArchivedAgentResult(sessionId);
452
+ if (readState === PROBE_ABSENT) return readVanishedSessionTranscript(sessionId);
445
453
  if (typeof options.trace === 'function') {
446
454
  options.trace({
447
455
  sessionId,
@@ -3,7 +3,7 @@
3
3
  * Sessions are saved to disk so CLI and MCP server can share state,
4
4
  * and sessions survive server restarts (resume).
5
5
  */
6
- import { writeFileSync } from 'node:fs';
6
+ import { closeSync, fsyncSync, openSync, writeFileSync } from 'node:fs';
7
7
  import * as fsp from 'node:fs/promises';
8
8
  import { randomBytes } from 'node:crypto';
9
9
  import { sessionPath } from './store/paths-heartbeat.mjs';
@@ -354,7 +354,15 @@ function _doSaveSync(payload) {
354
354
  attempted = JSON.stringify(disk);
355
355
  // The lifecycle these exact bytes carry, recorded with the commit stamp.
356
356
  const lifecycle = _lifecycleOfSessionDocument(disk);
357
- writeFileSync(tmp, attempted, 'utf-8');
357
+ // fsync before the rename: without it an OS crash can publish the
358
+ // renamed file with its data blocks never written (all-NUL record).
359
+ const fd = openSync(tmp, 'w');
360
+ try {
361
+ writeFileSync(fd, attempted, 'utf-8');
362
+ fsyncSync(fd);
363
+ } finally {
364
+ closeSync(fd);
365
+ }
358
366
  if (_shouldDrop(id, opts, attempt)) {
359
367
  _discardSaveTmp(tmp);
360
368
  if (mayMutate()) _recordSaveDrop(id, epoch);
@@ -636,7 +644,14 @@ async function _doSave(payload) {
636
644
  attempted = JSON.stringify(disk);
637
645
  // Captured before the await: the lifecycle of exactly these bytes.
638
646
  const lifecycle = _lifecycleOfSessionDocument(disk);
639
- await fsp.writeFile(tmp, attempted, 'utf-8');
647
+ // fsync before the rename (see _doSaveSync).
648
+ const handle = await fsp.open(tmp, 'w');
649
+ try {
650
+ await handle.writeFile(attempted, 'utf-8');
651
+ await handle.sync();
652
+ } finally {
653
+ await handle.close();
654
+ }
640
655
  // Second check: between the temp write and the rename, closeSession()
641
656
  // may have planted a tombstone. Re-check on disk; if a newer tombstone
642
657
  // now exists, discard our temp file rather than let rename clobber it.
@@ -706,6 +721,7 @@ export { loadSession } from './store/load-session.mjs';
706
721
  // Hard delete + owned-agent enumeration live in store/session-delete.mjs;
707
722
  // re-exported here so prior importers of store.mjs stay unchanged.
708
723
  export { deleteSession, listOwnedAgentSessionIds } from './store/session-delete.mjs';
724
+ export { fenceSessionWrites } from './store/live-state.mjs';
709
725
 
710
726
  // Listing / summaries live in store/listing.mjs and the stale sweep in
711
727
  // store/sweep/stale-sweep.mjs; re-exported here so importers keep one
@@ -208,6 +208,7 @@ function invocationOptions(batch, call, exec) {
208
208
  iteration: batch.iterations,
209
209
  localSearchTelemetry: exec.localSearchTelemetry || {},
210
210
  resultTelemetry: exec.resultTelemetry,
211
+ ...(call.wireCall ? { bridgeWireCall: call.wireCall } : {}),
211
212
  };
212
213
  }
213
214
 
@@ -319,7 +319,7 @@ function stagePostProcessingFailure(batch, completed, postErr, postprocessStarte
319
319
  if (sessionRef?._scopedCacheOutcomeByCallId instanceof Map && call?.id) {
320
320
  sessionRef._scopedCacheOutcomeByCallId.delete(call.id);
321
321
  }
322
- if (call?.id) restoreToolCallBodyForId(batch.assistantTurnMsg, batch.calls, call.id);
322
+ if (call?.id) restoreToolCallBodyForId(batch.assistantTurnMsg, batch.wireCalls, call.id);
323
323
  const message = `Error: tool result post-processing failed for "${call.name}": ${postErr instanceof Error ? postErr.message : String(postErr)}`;
324
324
  traceAgentToolFailure({
325
325
  sessionId: batch.sessionId,
@@ -46,7 +46,7 @@ export async function recordCallOutcome(batch, call, exec, sigs, ctSig) {
46
46
  // otherwise hide behind a `[mixdog compacted …]` placeholder). Restored
47
47
  // immediately so an abort or post-processing throw cannot leave it
48
48
  // compacted; early-skipped calls stay compacted.
49
- if (executed && failed && call?.id) restoreToolCallBodyForId(batch.assistantTurnMsg, batch.calls, call.id);
49
+ if (executed && failed && call?.id) restoreToolCallBodyForId(batch.assistantTurnMsg, batch.wireCalls, call.id);
50
50
  if (sessionId && _stripMcpPrefix(call.name) === 'apply_patch') {
51
51
  if (exec.executeOk && exec.resultKind === 'normal') invalidateAfterPatch(sessionId, call, cwd);
52
52
  // Mutation tools invalidate even on returned-error/partial-fail — the
@@ -4,11 +4,17 @@
4
4
  // live here so processToolBatch can hand them back.
5
5
  import { executeTool } from '../loop/tool-exec.mjs';
6
6
  import { planToolBatch } from './plan.mjs';
7
+ import { bridgeClassificationTools, resolveExecutionToolCalls } from '../loop/tool-call-resolution.mjs';
7
8
 
8
9
  export function createBatchState(ctx) {
9
- const { calls, tools, assistantTurnMsg, sessionRef } = ctx;
10
+ const { assistantTurnMsg, sessionRef } = ctx;
11
+ // Bridged call_tool requests run as their targets from here on; the wire
12
+ // calls stay authoritative for the transcript and failed-argument restore.
13
+ const calls = resolveExecutionToolCalls(ctx.calls, sessionRef);
14
+ const tools = bridgeClassificationTools(ctx.tools, calls);
10
15
  return {
11
16
  calls,
17
+ wireCalls: ctx.calls,
12
18
  messages: ctx.messages,
13
19
  tools,
14
20
  cwd: ctx.cwd,
@@ -19,8 +19,10 @@ import { getPluginData } from '../config.mjs';
19
19
  import { countSplitLines, normalizeOutputPath } from '../tools/builtin/path-utils.mjs';
20
20
  import { classifyResultKind } from './result-classification.mjs';
21
21
  import { registerSessionPurgeHook } from './store.mjs';
22
+ import { SETUP_OUTPUT_MAX_BYTES } from '../../../shared/tool-output-limit.mjs';
22
23
 
23
24
  const TOOL_RESULT_OFFLOAD_THRESHOLD_CHARS = 50_000;
25
+ const TOOL_RESULT_SETUP_THRESHOLD_CHARS = SETUP_OUTPUT_MAX_BYTES;
24
26
  const TOOL_RESULT_PREVIEW_CHARS = 512;
25
27
  const TOOL_RESULT_SHELL_THRESHOLD_CHARS = 30_000;
26
28
  const TOOL_RESULT_SEARCH_THRESHOLD_CHARS = 50_000;
@@ -61,6 +63,7 @@ const INLINE_THRESHOLD_BY_TOOL = new Map([
61
63
  ['bash_session', TOOL_RESULT_SHELL_THRESHOLD_CHARS],
62
64
  ['terminal', TOOL_RESULT_SHELL_THRESHOLD_CHARS],
63
65
  ['task', TOOL_RESULT_SHELL_THRESHOLD_CHARS],
66
+ ['setup', TOOL_RESULT_SETUP_THRESHOLD_CHARS],
64
67
  ]);
65
68
 
66
69
  function getOffloadThreshold(toolName) {
@@ -554,6 +557,7 @@ export const _internals = {
554
557
  TOOL_RESULT_SHELL_THRESHOLD_CHARS,
555
558
  TOOL_RESULT_SEARCH_THRESHOLD_CHARS,
556
559
  TOOL_RESULT_GREP_THRESHOLD_CHARS,
560
+ TOOL_RESULT_SETUP_THRESHOLD_CHARS,
557
561
  getOffloadThreshold,
558
562
  TOOL_RESULT_PREVIEW_CHARS,
559
563
  TOOL_RESULT_MESSAGE_MAX_CHARS,
@@ -0,0 +1,77 @@
1
+ // A provider 400 that names one tool's input schema (Anthropic
2
+ // `tools.3.custom.input_schema`, OpenAI `Invalid schema for function 'x'` /
3
+ // `tools[3].parameters`, Gemini `function_declarations[3]`): which tool of the
4
+ // request it is, so the session can drop it instead of failing every turn.
5
+ import { providerToolExclusionReason } from './loop/provider-tool-exclusions.mjs';
6
+ import { providerNativeToolPrefixCount } from '../runtime-core/provider-request-tools.mjs';
7
+
8
+ const MAX_REASON_CHARS = 240;
9
+
10
+ const text = (value) => (typeof value === 'string' ? value : '');
11
+
12
+ // Provider-structured places a rejection names its field, best evidence first:
13
+ // OpenAI `param` (also nested under `error`), Anthropic / OpenAI `error.message`,
14
+ // Google `details[].fieldViolations[].field`, then a JSON body, then the
15
+ // error's own message.
16
+ function evidence(error) {
17
+ const nested = [error?.error, error?.providerError, error?.response?.data?.error, error?.response?.data];
18
+ const violations = [error?.details, error?.error?.details, error?.errorDetails]
19
+ .flatMap((details) => (Array.isArray(details) ? details : []))
20
+ .flatMap((detail) => (Array.isArray(detail?.fieldViolations) ? detail.fieldViolations : []))
21
+ .flatMap((violation) => [text(violation?.field), text(violation?.description)]);
22
+ const bodies = [error?.body, error?.responseBody].map((body) => {
23
+ if (typeof body !== 'string') return [];
24
+ try {
25
+ const parsed = JSON.parse(body);
26
+ return [text(parsed?.error?.param), text(parsed?.error?.message), text(parsed?.message)];
27
+ } catch {
28
+ return [body];
29
+ }
30
+ });
31
+ return [
32
+ error?.param,
33
+ ...nested.map((entry) => entry?.param),
34
+ ...nested.map((entry) => entry?.message),
35
+ ...violations,
36
+ ...bodies.flat(),
37
+ error?.message,
38
+ error?.cause?.message,
39
+ ].filter((entry) => typeof entry === 'string' && entry);
40
+ }
41
+
42
+ // One piece of evidence -> which tool: a wire index (`byIndex`, with the
43
+ // OpenAI Responses hosted-tool offset when `shifted`) or a function name.
44
+ function target(entry) {
45
+ let match = /\btools\.(\d+)\.(?:custom\.)?input_schema/.exec(entry);
46
+ if (match) return { index: Number(match[1]) };
47
+ match = /\btools(?:\[(\d+)\]|\.(\d+))\.(?:function\.)?parameters/.exec(entry);
48
+ if (match) return { index: Number(match[1] ?? match[2]), shifted: true };
49
+ match = /\b(?:function_declarations|functionDeclarations)(?:\[(\d+)\]|\.(\d+))/.exec(entry);
50
+ if (match) return { index: Number(match[1] ?? match[2]) };
51
+ match = /Invalid schema for function ['"`]([^'"`]+)['"`]/.exec(entry);
52
+ if (match) return { name: match[1] };
53
+ return null;
54
+ }
55
+
56
+ /** `{ name, pointer, reason }` of the tool a schema 400 points at, or null (any
57
+ * other error, or a tool that is not part of the request's own tools). */
58
+ export function rejectedToolSchema(error, { sendTools, sessionRef, opts }) {
59
+ if ((error?.httpStatus ?? error?.status ?? error?.statusCode) !== 400) return null;
60
+ const tools = Array.isArray(sendTools) ? sendTools : [];
61
+ const nativeCount = providerNativeToolPrefixCount(tools);
62
+ // The wire list: the request's tools minus those the wire left out.
63
+ const wire = tools.filter((tool) => !providerToolExclusionReason(sessionRef, tool?.name));
64
+ const hosted = sessionRef?.wireRoute?.wire !== 'chat' && Array.isArray(opts?.nativeTools) ? opts.nativeTools.length : 0;
65
+ const entries = evidence(error);
66
+ let name = '';
67
+ for (const entry of entries) {
68
+ const found = target(entry);
69
+ if (!found) continue;
70
+ const tool = found.name ? wire.find((t) => t?.name === found.name) : wire[found.index - (found.shifted ? hosted : 0)];
71
+ name = typeof tool?.name === 'string' ? tool.name : '';
72
+ if (name) break;
73
+ }
74
+ if (!name || tools.findIndex((t) => t?.name === name) < nativeCount) return null;
75
+ const detail = entries.join(' ').replace(/\s+/g, ' ').trim().slice(0, MAX_REASON_CHARS);
76
+ return { name, pointer: '/', reason: `the provider rejected it with HTTP 400: ${detail}` };
77
+ }
@@ -68,6 +68,12 @@ export function buildBashPolicyScanTargets(command) {
68
68
  return out;
69
69
  }
70
70
 
71
- export function checkExecPolicyMessage(command) {
72
- return formatExecPolicyBlockMessage(evaluateExecPolicyFromTargets(buildBashPolicyScanTargets(command)));
71
+ export function evaluateExecPolicy(command) {
72
+ return evaluateExecPolicyFromTargets(buildBashPolicyScanTargets(command));
73
+ }
74
+
75
+ // `elevationApproved` is runtime-supplied: the user approved this call's
76
+ // 'ask' (elevation) decision. It never lifts a deny.
77
+ export function checkExecPolicyMessage(command, { elevationApproved = false } = {}) {
78
+ return formatExecPolicyBlockMessage(evaluateExecPolicy(command), { elevationApproved });
73
79
  }
@@ -8,11 +8,11 @@ import { formatShellToolFailure } from './result-format.mjs';
8
8
  // Policy + shell-specific rewrites before any shell dispatch. Returns either
9
9
  // `{ failure }` (a formatted tool failure) or the command to run with the
10
10
  // resolved shell spec and the wmic rewrite (if any).
11
- export function prepareShellCommand(args) {
11
+ export function prepareShellCommand(args, { elevationApproved = false } = {}) {
12
12
  // Run hard-block policy before any shell dispatch.
13
13
  const rawCmd = String(args && args.command != null ? args.command : '');
14
14
  if (rawCmd) {
15
- const policyBlock = checkExecPolicyMessage(rawCmd);
15
+ const policyBlock = checkExecPolicyMessage(rawCmd, { elevationApproved });
16
16
  if (policyBlock) return { failure: formatShellToolFailure(policyBlock) };
17
17
  }
18
18
  let command = args.command;
@@ -52,7 +52,7 @@ export function prepareShellCommand(args) {
52
52
  : null;
53
53
  if (bashismRewrite) command = bashismRewrite.command;
54
54
 
55
- const execPolicyBlock = checkExecPolicyMessage(command);
55
+ const execPolicyBlock = checkExecPolicyMessage(command, { elevationApproved });
56
56
  if (execPolicyBlock) return { failure: formatShellToolFailure(execPolicyBlock) };
57
57
  return { command, analysisCommand, resolvedSpec, wmicRewrite, bashismRewrite };
58
58
  }
@@ -61,7 +61,9 @@ export async function executeBashTool(args, workDir, options = {}) {
61
61
  // Every call starts from the current Project root. A command-local `cd`
62
62
  // never creates a second session cwd authority beside the dedicated cwd tool.
63
63
  const bashWorkDir = workDir;
64
- const prepared = prepareShellCommand(args);
64
+ // Approval comes from the runtime's options, never from model-supplied args.
65
+ const elevationApproved = options?.elevationApproved === true;
66
+ const prepared = prepareShellCommand(args, { elevationApproved });
65
67
  if (prepared.failure) return prepared.failure;
66
68
  const { resolvedSpec, wmicRewrite, bashismRewrite } = prepared;
67
69
  // Effects are analyzed on the command as the caller meant it, before the
@@ -97,6 +99,7 @@ export async function executeBashTool(args, workDir, options = {}) {
97
99
  command: invocation.wrappedCommand,
98
100
  execScript: invocation.execScript,
99
101
  directArgv: invocation.directArgv,
102
+ elevationApproved,
100
103
  env: invocation.spawnEnv,
101
104
  cwd: bashWorkDir,
102
105
  timeoutMs: deadlines.timeout,
@@ -37,6 +37,7 @@ import { decodeValidUtf8OrNull, detectPatchTargetCodec, nearestPatchLineMatch }
37
37
  import { hashText } from './hash-utils.mjs';
38
38
  import { invalidateBuiltinResultCache } from './cache-layers.mjs';
39
39
  import { markCodeGraphDirtyPaths } from '../code-graph-state.mjs';
40
+ import { reviewFileContent } from '../../../../shared/bounded-file-read.mjs';
40
41
 
41
42
  const STR_REPLACE_NAMES = new Set(['edit', 'strreplace', 'str_replace', 'str_replace_editor', 'search_replace']);
42
43
  const WRITE_NAMES = new Set(['write', 'create_file', 'createfile']);
@@ -189,26 +190,27 @@ function recordEditSnapshot(fullPath, options, contentHash = null, preMutationSt
189
190
  // UI diff parity with apply_patch: register the before/after pair on the
190
191
  // shared per-call side channel so tool cards render edit results with the
191
192
  // same diff markup. Lazy import breaks the orchestrator→builtin→adapters
192
- // module cycle; failures never affect the edit result.
193
- async function recordEditUiDiff(options, workDir, fullPath, before, after, encoding) {
193
+ // module cycle; failures never affect the edit result. `sides()` yields the
194
+ // file's `{ before, after }` content (null = absent).
195
+ async function recordToolUiDiff(options, workDir, fullPath, sides) {
194
196
  const callId = options?.toolCallId;
195
197
  const sessionId = options?.sessionId || options?.readStateScope;
196
198
  if (!callId || !sessionId) return;
197
199
  try {
198
200
  const { registerEditToolUiDiff } = await import('../patch/orchestrator.mjs');
199
- registerEditToolUiDiff({
200
- callId,
201
- sessionId,
202
- basePath: workDir,
203
- fullPath,
204
- before: before === null ? null : encodeEditContent(before, encoding),
205
- after: after === null ? null : encodeEditContent(after, encoding),
206
- });
201
+ registerEditToolUiDiff({ callId, sessionId, basePath: workDir, fullPath, ...sides() });
207
202
  } catch {
208
203
  /* best-effort display channel */
209
204
  }
210
205
  }
211
206
 
207
+ async function recordEditUiDiff(options, workDir, fullPath, before, after, encoding) {
208
+ await recordToolUiDiff(options, workDir, fullPath, () => ({
209
+ before: before === null ? null : encodeEditContent(before, encoding),
210
+ after: after === null ? null : encodeEditContent(after, encoding),
211
+ }));
212
+ }
213
+
212
214
  // The 0-based line the failure excerpt centres on, or -1: the engine's
213
215
  // "nearest match" hint, else the exact old_string, else its longest tokens,
214
216
  // else the fuzzy line scorer.
@@ -828,6 +830,7 @@ async function adaptWrite(args, workDir, options) {
828
830
  if (target.error) return target.error;
829
831
  const fullPath = target.full;
830
832
  const existed = existsSync(fullPath);
833
+ const before = existed ? reviewFileContent(fullPath) : null;
831
834
  try {
832
835
  mkdirSync(dirname(fullPath), { recursive: true });
833
836
  } catch {
@@ -835,6 +838,7 @@ async function adaptWrite(args, workDir, options) {
835
838
  }
836
839
  await atomicWrite(fullPath, contents, { sessionId: editScope(options) });
837
840
  invalidateAfterWrite(fullPath);
841
+ await recordToolUiDiff(options, workDir, fullPath, () => ({ before, after: contents }));
838
842
  return `${existed ? 'Updated' : 'Created'} ${fullPath} (${Buffer.byteLength(contents, 'utf8')} bytes)`;
839
843
  }
840
844