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
@@ -8,6 +8,7 @@ import { currentProviderAccountId } from '../provider-auth-binding.mjs';
8
8
  // fallback, catalog retry) runs its own accounting and its result or error
9
9
  // then returns through the enclosing send, which must not write it again.
10
10
  const recorded = new WeakSet();
11
+ const UNMEASURED_USAGE = Object.freeze({ inputTokens: null, inputTokensKnown: false });
11
12
  const hasTokens = (usage) =>
12
13
  ['inputTokens', 'outputTokens', 'cachedTokens', 'cacheWriteTokens'].some((key) => Number(usage?.[key]) > 0);
13
14
  // One rule for every reported usage object: tokens, or a provider-reported
@@ -51,7 +52,9 @@ export async function accountProviderSend(provider, instance, send, model, opts
51
52
  // abandoned attempt or a failure shares that clock with the final attempt,
52
53
  // so timing it too would count the same seconds twice and understate speed.
53
54
  const record = async (result, id, owner, timed) => {
54
- if (!result?.usage) return;
55
+ // A completed call that reported no usage is still a call: it is recorded
56
+ // as unmeasured (unknown input, unpriced) instead of vanishing from totals.
57
+ if (!result?.usage && !(timed && result && typeof result === 'object')) return;
55
58
  // A nested send (e.g. a fallback model re-send) already stamped its own
56
59
  // final attempt's tier; the outer context only saw the abandoned attempt.
57
60
  result.requestServiceTier ??= identity.requestServiceTier || '';
@@ -59,7 +62,7 @@ export async function accountProviderSend(provider, instance, send, model, opts
59
62
  if (openingError) throw openingError;
60
63
  if (!ledger) return;
61
64
  recorded.add(owner);
62
- const usage = result.usage;
65
+ const usage = result.usage || UNMEASURED_USAGE;
63
66
  const row = makeUsageRecord({
64
67
  id: result.responseId ? undefined : id,
65
68
  ts: Date.now(),
@@ -61,6 +61,8 @@ const add = (target, row) => {
61
61
  costBilled: row.cost_source === 'provider' ? row.cost_usd : 0,
62
62
  costEstimated: row.cost_source === 'provider' ? 0 : row.cost_usd,
63
63
  });
64
+ // A call recorded without provider usage is unmeasured whatever its provider.
65
+ if (row.unmeasured && !usage.unmeasuredTurns) usage.unmeasuredTurns = usage.turns || 0;
64
66
  for (const field of [
65
67
  'turns',
66
68
  'input',
@@ -311,6 +313,7 @@ export function readSessionUsage(db, sessionIds) {
311
313
  json_extract(r.signature,'$[1]') AS model,
312
314
  json_extract(r.signature,'$[4]') AS cost_source,
313
315
  json_extract(r.signature,'$[7]') AS rank,
316
+ COALESCE(json_extract(json_extract(r.signature,'$[5]'),'$.inputTokensKnown'),1)=0 AS unmeasured,
314
317
  m.turns,m.input,m.output,m.cache_read,m.cache_write,m.cost_usd,m.duration_ms,
315
318
  m.speed_output,m.speed_ms
316
319
  FROM mine m JOIN usage_routes r ON r.id=m.route
@@ -9,6 +9,15 @@ export function createLoopbackListener({
9
9
  let current = null;
10
10
  let closing = null;
11
11
 
12
+ // close() drops only the keep-alive sockets idle at that moment; one whose
13
+ // in-flight response ends later would hold the close for the server's whole
14
+ // keepAliveTimeout (~5 s). Drop each as its response settles while stopping.
15
+ server.on('request', (_req, res) => {
16
+ res.once('close', () => {
17
+ if (closing) server.closeIdleConnections();
18
+ });
19
+ });
20
+
12
21
  function start() {
13
22
  if (closing) return Promise.reject(new Error('HTTP listener is stopping'));
14
23
  if (current) return current.promise;
@@ -72,12 +72,14 @@ export function getAgentApiKey(provider) {
72
72
  /** The one API-key resolver for key-based providers: an explicit config key
73
73
  * wins, otherwise the environment/keychain (getAgentApiKey). */
74
74
  export function resolveProviderApiKey(provider, config) {
75
+ if (config?.apiKeyEnv) return process.env[config.apiKeyEnv] || '';
75
76
  return config?.apiKey || getAgentApiKey(provider) || '';
76
77
  }
77
78
 
78
79
  /** Auth-error reload: the stored/environment key is re-read first so a
79
80
  * rotated key beats the stale one captured in config. */
80
81
  export function reloadProviderApiKey(provider, config) {
82
+ if (config?.apiKeyEnv) return process.env[config.apiKeyEnv] || '';
81
83
  return getAgentApiKey(provider) || config?.apiKey || '';
82
84
  }
83
85
 
@@ -1,5 +1,57 @@
1
1
  const TRUNCATED = '… [diff truncated for display]';
2
2
 
3
+ // Review replies always list every changed file with its counts. Patch text
4
+ // is carried per file within these caps (UTF-8 bytes); a file past either one
5
+ // is listed `patchOmitted` with reason PATCH_TOO_LARGE and is read on its own,
6
+ // up to the larger "show anyway" cap, when it is opened.
7
+ /** Largest single-file patch a review reply carries inline. */
8
+ export const REVIEW_FILE_PATCH_MAX_BYTES = 1024 * 1024;
9
+ /** Largest total patch text a review reply carries. */
10
+ export const REVIEW_PATCH_MAX_BYTES = 2 * 1024 * 1024;
11
+ /** Largest single-file patch a file-patch read returns. */
12
+ export const REVIEW_FILE_PATCH_SHOW_MAX_BYTES = 8 * 1024 * 1024;
13
+ export const PATCH_TOO_LARGE = 'too_large';
14
+
15
+ /** A reply file listed with its counts but without its patch, for size. */
16
+ export function patchOmittedFile(file) {
17
+ return { ...file, patchOmitted: true, reason: PATCH_TOO_LARGE };
18
+ }
19
+
20
+ /** A `diff --git` section (string or Buffer) whose hunks boundReviewPatch cut. */
21
+ export function reviewSectionTruncated(section) {
22
+ return section.includes(TRUNCATED);
23
+ }
24
+
25
+ /** Nothing of the reply's patch fit: no patch text, a file omitted for size. */
26
+ export function reviewDiffTooLarge(files, patch) {
27
+ return !patch && (files || []).some((file) => file?.patchOmitted === true && file.reason === PATCH_TOO_LARGE);
28
+ }
29
+
30
+ /** The per-file and total caps of one reply. `admit(bytes)` takes a patch of
31
+ * that size from the remaining total, or refuses it. */
32
+ export function createReviewPatchBudget(total = REVIEW_PATCH_MAX_BYTES) {
33
+ let remaining = total;
34
+ return {
35
+ get remaining() {
36
+ return remaining;
37
+ },
38
+ admit(bytes) {
39
+ if (bytes > REVIEW_FILE_PATCH_MAX_BYTES || bytes > remaining) return false;
40
+ remaining -= bytes;
41
+ return true;
42
+ },
43
+ };
44
+ }
45
+
46
+ /** One file-patch read's reply: its patch, or none when past `maxBytes`. */
47
+ export function filePatchReply(path, patch, maxBytes = REVIEW_FILE_PATCH_SHOW_MAX_BYTES) {
48
+ const text = typeof patch === 'string' ? patch : '';
49
+ if (Buffer.byteLength(text, 'utf8') > maxBytes) {
50
+ return { supported: true, path, patch: '', patchOmitted: true, reason: PATCH_TOO_LARGE };
51
+ }
52
+ return { supported: true, path, patch: text };
53
+ }
54
+
3
55
  /** Bound hunk bodies, never the inventory of changed files. Headers are kept
4
56
  * even when the inventory itself exceeds the display budget. */
5
57
  export function boundReviewPatch(patch, maxChars) {
@@ -0,0 +1,4 @@
1
+ export type SessionSidebarChange = { favorite: boolean } | { archived: boolean };
2
+ export type SessionSidebarHost = (sessionId: unknown, change: unknown) => unknown;
3
+ export function registerSessionSidebarHost(host: SessionSidebarHost): () => void;
4
+ export function applySessionSidebarChange(sessionId: string, change: SessionSidebarChange): Promise<void>;
@@ -0,0 +1,38 @@
1
+ // Runtime → desktop request channel for a session's sidebar metadata
2
+ // (favorite, archive). That metadata belongs to the desktop
3
+ // service hosted in this daemon: it registers a host here, and the Lead's
4
+ // `session` tool applies a change through it, so the sidebar republishes live.
5
+ //
6
+ // Deliberately dependency-free: the desktop service bundle imports this file
7
+ // too, and both copies share one registry through a global symbol.
8
+
9
+ const HOSTS_KEY = Symbol.for('mixdog.sessionSidebarHosts.v1');
10
+
11
+ function hosts() {
12
+ globalThis[HOSTS_KEY] ??= [];
13
+ return globalThis[HOSTS_KEY];
14
+ }
15
+
16
+ /**
17
+ * Register a desktop host. `host(sessionId, change)` applies one change:
18
+ * `{ favorite: boolean }` or `{ archived: boolean }`.
19
+ * @returns {() => void} Unregister.
20
+ */
21
+ export function registerSessionSidebarHost(host) {
22
+ const entry = { host };
23
+ hosts().push(entry);
24
+ return () => {
25
+ const list = hosts();
26
+ const index = list.indexOf(entry);
27
+ if (index >= 0) list.splice(index, 1);
28
+ };
29
+ }
30
+
31
+ /** Apply one change through exactly one host: the most recently registered
32
+ * (active) desktop service. Never broadcast — each service writes the shared
33
+ * metadata file, so a second write would be redundant at best. */
34
+ export async function applySessionSidebarChange(sessionId, change) {
35
+ const active = hosts().at(-1);
36
+ if (!active) throw new Error('no desktop app is attached to this runtime');
37
+ await active.host(sessionId, change);
38
+ }
@@ -0,0 +1,114 @@
1
+ // slow-span.mjs
2
+ // Passive per-request timing spans. Every traced call is timed on the same
3
+ // monotonic clock the owner heartbeat uses (performance.now), completed spans
4
+ // over `minMs` land in a bounded ring, and spans over `slowMs` are logged as
5
+ // `[slow-op] <label> <ms>`. When the event loop stalls, `describe(from, to)`
6
+ // names the spans that overlapped the stall window. Spans carry labels, phase
7
+ // durations and sizes only — never payloads.
8
+
9
+ import { AsyncLocalStorage } from 'node:async_hooks';
10
+ import { performance } from 'node:perf_hooks';
11
+
12
+ export const SPAN_RING_MIN_MS = 25;
13
+ export const SPAN_SLOW_MS = 1000;
14
+ export const SPAN_RING_CAPACITY = 64;
15
+
16
+ const current = new AsyncLocalStorage();
17
+
18
+ /** Short, log-safe id of a session id. */
19
+ export function shortId(id) {
20
+ const text = String(id ?? '');
21
+ return text ? text.slice(0, 8) : '';
22
+ }
23
+
24
+ /** Appends detail (e.g. the action name) to the label of the span the caller runs in. */
25
+ export function annotateSpan(detail) {
26
+ const span = current.getStore();
27
+ if (span && detail) span.label += `:${detail}`;
28
+ }
29
+
30
+ /** Closes the running phase of the caller's span at `now`, under `name`. */
31
+ export function markPhase(name) {
32
+ const span = current.getStore();
33
+ if (!span) return;
34
+ const t = span.now();
35
+ span.phases.push([name, t - span.mark]);
36
+ span.mark = t;
37
+ }
38
+
39
+ /** Records a size (count/bytes) on the caller's span. */
40
+ export function noteSpanSize(size) {
41
+ const span = current.getStore();
42
+ if (span && Number.isFinite(size)) span.size = size;
43
+ }
44
+
45
+ const round = (ms) => Math.round(ms);
46
+
47
+ function formatSpan(span) {
48
+ const phases = span.phases.map(([name, ms]) => `${name}=${round(ms)}`).join(' ');
49
+ const size = span.size === undefined ? '' : ` size=${span.size}`;
50
+ return `${span.label} ${round(span.ms)}ms${phases ? ` ${phases}` : ''}${size}`;
51
+ }
52
+
53
+ export function createSlowSpans({
54
+ now = () => performance.now(),
55
+ capacity = SPAN_RING_CAPACITY,
56
+ minMs = SPAN_RING_MIN_MS,
57
+ slowMs = SPAN_SLOW_MS,
58
+ log = () => {},
59
+ } = {}) {
60
+ const ring = [];
61
+ let sink = log;
62
+
63
+ function complete(span) {
64
+ span.end = now();
65
+ span.ms = span.end - span.start;
66
+ if (span.ms >= minMs) {
67
+ ring.push({ label: span.label, start: span.start, end: span.end, ms: span.ms, phases: span.phases, size: span.size });
68
+ if (ring.length > capacity) ring.shift();
69
+ }
70
+ if (span.ms >= slowMs) {
71
+ try {
72
+ sink(`[slow-op] ${formatSpan(span)}`);
73
+ } catch {
74
+ /* logging must not fail the call */
75
+ }
76
+ }
77
+ }
78
+
79
+ return {
80
+ setLog(next) {
81
+ sink = typeof next === 'function' ? next : () => {};
82
+ },
83
+ /** Runs `fn` inside a span; markPhase/annotateSpan inside it attach to this span. */
84
+ async trace(label, fn) {
85
+ const start = now();
86
+ const span = { label: String(label), start, mark: start, now, phases: [], size: undefined };
87
+ try {
88
+ return await current.run(span, fn);
89
+ } finally {
90
+ complete(span);
91
+ }
92
+ },
93
+ /** Completed spans overlapping [from, to], longest overlap first. */
94
+ overlapping(from, to, limit = 3) {
95
+ return ring
96
+ .map((span) => ({ span, overlap: Math.min(span.end, to) - Math.max(span.start, from) }))
97
+ .filter((row) => row.overlap > 0)
98
+ .sort((a, b) => b.overlap - a.overlap || b.span.end - a.span.end)
99
+ .slice(0, limit)
100
+ .map((row) => row.span);
101
+ },
102
+ /** One-line description of the spans overlapping a stall window ('' when none). */
103
+ describe(from, to, limit = 3) {
104
+ const spans = this.overlapping(from, to, limit);
105
+ return spans.length ? `spans: ${spans.map((span) => formatSpan({ ...span })).join('; ')}` : '';
106
+ },
107
+ get recent() {
108
+ return ring.slice();
109
+ },
110
+ };
111
+ }
112
+
113
+ /** Process-wide recorder; the daemon points its log at daemon.log. */
114
+ export const slowSpans = createSlowSpans();
@@ -76,9 +76,32 @@ export function shellJobsStatus({ clientHostPid, sessionId } = {}) {
76
76
  _shellJobsRefreshInFlight.delete(ownerPid);
77
77
  });
78
78
  }
79
- const value = cached?.value || EMPTY_SHELL_JOBS;
80
- if (!scoped) return value;
81
- return (scope && value.sessions?.[scope]) || EMPTY_SHELL_JOBS_SESSION;
79
+ const own = cached?.value || EMPTY_SHELL_JOBS;
80
+ // Session buckets are not pid-scoped, so they come from the freshest scan of
81
+ // ANY owner. Reading them from this owner's own slot made the list follow
82
+ // that slot's age: an owner polled again after its entry was evicted (or
83
+ // went stale) answered with "no sessions", and the finished shells vanished
84
+ // until the next poll brought them back.
85
+ const sessions = freshestShellJobsSessions() ?? own.sessions;
86
+ if (!scoped) return sessions === own.sessions ? own : { ...own, sessions };
87
+ return (scope && sessions?.[scope]) || EMPTY_SHELL_JOBS_SESSION;
88
+ }
89
+
90
+ // Awaited fresh scan for pollers that own their cadence (desktop): the result
91
+ // reflects the disk at call time instead of the previous poll. The CLI render
92
+ // path keeps using the cache-only shellJobsStatus.
93
+ export async function shellJobsStatusFresh({ clientHostPid } = {}) {
94
+ const ownerPid = positiveInt(clientHostPid);
95
+ if (!ownerPid) return EMPTY_SHELL_JOBS;
96
+ return refreshShellJobsStatus(ownerPid);
97
+ }
98
+
99
+ function freshestShellJobsSessions() {
100
+ let freshest = null;
101
+ for (const entry of _shellJobsSegmentCache.values()) {
102
+ if (!freshest || entry.at >= freshest.at) freshest = entry;
103
+ }
104
+ return freshest?.value.sessions;
82
105
  }
83
106
 
84
107
  // Memory cycle L2 segment source. The daemon-hosted memory runtime writes
@@ -142,7 +165,7 @@ async function refreshShellJobsStatus(ownerPid) {
142
165
  names = await readdir(dir);
143
166
  } catch {
144
167
  rememberShellJobs(ownerPid, value);
145
- return;
168
+ return value;
146
169
  }
147
170
  const { ids, ownerByJob, doneIds } = listOpenShellJobs(names);
148
171
  let count = 0;
@@ -225,6 +248,7 @@ async function refreshShellJobsStatus(ownerPid) {
225
248
  value = EMPTY_SHELL_JOBS;
226
249
  }
227
250
  rememberShellJobs(ownerPid, value);
251
+ return value;
228
252
  }
229
253
 
230
254
  // Newest-first, capped ids of job records with no `.done` marker, plus the
@@ -5,7 +5,8 @@
5
5
  import { formatToolActionHeader, toolLoadingTargets } from '../tool-surface.mjs';
6
6
  import { agentActionSummary, agentActionTitle, agentResponseTitle, isAgentTool } from './agent-surface.mjs';
7
7
  import { backgroundTaskActionTitle, backgroundTaskResultTitle, taskControlTitle } from './background-task.mjs';
8
- import { toolSearchLoadedSummary } from './generic-detail.mjs';
8
+ import { bridgeDescribedToolNames, toolSearchLoadedSummary } from './generic-detail.mjs';
9
+ import { displayToolSearchTarget } from '../tool-primitives.mjs';
9
10
  import { safeInlineText } from './inline-text.mjs';
10
11
  import { shellHeader } from './shell-surface.mjs';
11
12
 
@@ -20,6 +21,10 @@ function headerLabel(base, surface, display, status, detail) {
20
21
  }
21
22
  if (display.isBackgroundMetadataResult) return backgroundTaskActionTitle(normalizedName, display.backgroundMeta);
22
23
  if (isShellSurface) return shellHeader(status.shellStatus, groupCount, parsedArgs?.verifyShell === true);
24
+ // Bridge load_tool describes definitions; it never loads a tool.
25
+ const described =
26
+ normalizedName === 'load_tool' && !headerPending ? bridgeDescribedToolNames(display.displayedResultText) : null;
27
+ if (described) return described.length ? `Described ${described.map(displayToolSearchTarget).join(', ')}` : 'Described';
23
28
  return (
24
29
  (isAgentTool(normalizedName) ? agentActionTitle(parsedArgs, display.displayedResultText) : '') ||
25
30
  formatToolActionHeader(name, args, {
@@ -51,6 +51,34 @@ export function genericCompletedDetail({ normalizedName, label, hasResult, first
51
51
  return '';
52
52
  }
53
53
 
54
+ const uniqueToolNames = (names) => [
55
+ ...new Set((Array.isArray(names) ? names : []).map((name) => String(name || '').trim()).filter(Boolean)),
56
+ ];
57
+
58
+ /**
59
+ * What a bridge load_tool result described, missed and blocked; null for a
60
+ * loader result (or anything that is not a describe result).
61
+ */
62
+ export function bridgeDescribeResult(resultText) {
63
+ let parsed;
64
+ try {
65
+ parsed = JSON.parse(String(resultText || ''));
66
+ } catch {
67
+ return null;
68
+ }
69
+ if (!Array.isArray(parsed?.entries)) return null;
70
+ return {
71
+ described: uniqueToolNames(parsed.entries.map((entry) => entry?.name)),
72
+ missing: uniqueToolNames(parsed.missing),
73
+ blocked: uniqueToolNames((Array.isArray(parsed.blocked) ? parsed.blocked : []).map((entry) => entry?.name)),
74
+ };
75
+ }
76
+
77
+ /** Names a bridge load_tool result described, or null for a loader result. */
78
+ export function bridgeDescribedToolNames(resultText) {
79
+ return bridgeDescribeResult(resultText)?.described ?? null;
80
+ }
81
+
54
82
  export function toolSearchLoadedSummary(resultText) {
55
83
  let parsed;
56
84
  try {
@@ -61,13 +89,19 @@ export function toolSearchLoadedSummary(resultText) {
61
89
  const already = /^Already active:\s*(.+)$/m.exec(text)?.[1] || '';
62
90
  return [...(loaded ? [`Loaded: ${loaded}`] : []), ...(already ? [`Already active: ${already}`] : [])].join(' · ');
63
91
  }
92
+ // Bridge describe result: nothing was loaded; report what was not described.
93
+ const describe = bridgeDescribeResult(resultText);
94
+ if (describe) {
95
+ const { missing, blocked } = describe;
96
+ return [
97
+ ...(missing.length ? [`Missing: ${missing.join(', ')}`] : []),
98
+ ...(blocked.length ? [`Blocked: ${blocked.join(', ')}`] : []),
99
+ ].join(' · ');
100
+ }
64
101
  const tools = parsed?.selected?.tools;
65
102
  if (!tools || typeof tools !== 'object') return '';
66
- const uniqueNames = (names) => [
67
- ...new Set((Array.isArray(names) ? names : []).map((name) => String(name || '').trim()).filter(Boolean)),
68
- ];
69
- const loaded = uniqueNames(tools.added);
70
- const already = uniqueNames(tools.already);
103
+ const loaded = uniqueToolNames(tools.added);
104
+ const already = uniqueToolNames(tools.already);
71
105
  return [
72
106
  ...(loaded.length ? [`Loaded: ${loaded.join(', ')}`] : []),
73
107
  ...(already.length ? [`Already active: ${already.join(', ')}`] : []),
@@ -23,7 +23,7 @@
23
23
  * tool-card-model/card-header.mjs — header label + arg summary
24
24
  */
25
25
  import { formatToolSurface } from './tool-surface.mjs';
26
- import { pluralize } from './tool-primitives.mjs';
26
+ import { pluralize, toolCallDisplayIdentity } from './tool-primitives.mjs';
27
27
  import { deriveAggregateCardModel } from './tool-card-model/aggregate-card.mjs';
28
28
  import { isShellTool } from './tool-card-model/shell-surface.mjs';
29
29
  import { SKILL_SURFACE_NAMES } from './tool-card-model/agent-surface.mjs';
@@ -77,6 +77,7 @@ export {
77
77
  resolveBackgroundTaskMeta,
78
78
  } from './tool-card-model/background-task.mjs';
79
79
  export {
80
+ bridgeDescribeResult,
80
81
  genericCompletedDetail,
81
82
  shouldPrefixSyncElapsed,
82
83
  toolSearchLoadedSummary,
@@ -95,7 +96,8 @@ export { pluralize as plural };
95
96
  * @param {object} options { truncate(text,width), maxResultChars }.
96
97
  */
97
98
  export function deriveToolCardModel(input = {}, options = {}) {
98
- const base = readCardInput(input, options);
99
+ const identity = toolCallDisplayIdentity(input.name, input.args);
100
+ const base = readCardInput({ ...input, name: identity.name, args: identity.args }, options);
99
101
  if (base.aggregate) return deriveAggregateCardModel(base);
100
102
 
101
103
  const { label, summary, normalizedName, args: parsedArgs } = formatToolSurface(base.name, base.args);
@@ -115,6 +117,7 @@ export function deriveToolCardModel(input = {}, options = {}) {
115
117
  return {
116
118
  aggregate: false,
117
119
  ...commonCardFields(base, status.terminalStatus),
120
+ ...(identity.via ? { via: identity.via } : {}),
118
121
  labelText: header.labelText,
119
122
  summaryText: header.summaryText,
120
123
  headerFailureText: status.headerFailureText,
@@ -22,6 +22,10 @@ export const RECALL_OUTPUT_MAX_BYTES = positiveEnvInt('MIXDOG_RECALL_OUTPUT_MAX_
22
22
  // github results after field reduction; the full response stays in a raw
23
23
  // artifact. Provisional: reduced pr.list/run.list pages measured ~2k tokens.
24
24
  export const GITHUB_OUTPUT_MAX_BYTES = positiveEnvInt('MIXDOG_GITHUB_OUTPUT_MAX_BYTES', 10 * 1024);
25
+ // setup results are compact JSON (a provider index, a 25-row model page, minimal
26
+ // status rows). The same figure is the setup inline-offload threshold, so one
27
+ // result can no longer sit just under the 50KB default (a 34-model catalog did).
28
+ export const SETUP_OUTPUT_MAX_BYTES = positiveEnvInt('MIXDOG_SETUP_OUTPUT_MAX_BYTES', 20 * 1024);
25
29
 
26
30
  function _prefixByBytes(value, maxBytes) {
27
31
  const text = String(value || '');
@@ -133,6 +133,19 @@ export function parseToolArgs(args) {
133
133
  return { value: args };
134
134
  }
135
135
 
136
+ /**
137
+ * Display identity of a tool call. A call_tool bridge request shows the tool
138
+ * it runs, with `via: 'call_tool'`; the transcript keeps the wire call.
139
+ */
140
+ export function toolCallDisplayIdentity(name, args) {
141
+ if (rawToolName(name) !== 'call_tool') return { name, args };
142
+ const parsed = parseToolArgs(args);
143
+ const target = typeof parsed?.name === 'string' ? parsed.name.trim() : '';
144
+ if (!target) return { name, args };
145
+ const targetArgs = parsed.arguments && typeof parsed.arguments === 'object' ? parsed.arguments : {};
146
+ return { name: target, args: targetArgs, via: 'call_tool' };
147
+ }
148
+
136
149
  export function displayToolPath(path) {
137
150
  const text = String(path ?? '');
138
151
  return text.replace(/\\/g, '/').split('/').filter(Boolean).at(-1) || text;
@@ -640,8 +640,14 @@ function summarizeAgentResult({ text, trimmed, translate }) {
640
640
 
641
641
  const summarizeGeneric = ({ text, translate }) => summarizeGenericResult(text, translate);
642
642
 
643
+ const summarizeAskUserResult = ({ text }) => {
644
+ const answers = /^User has answered your questions:\s*(.*?)(?:\s*You can now continue with these answers in mind\.)?$/s.exec(String(text ?? '').trim());
645
+ return truncateSingleLine(answers ? answers[1] : String(text ?? '').trim(), AGENT_SURFACE_BRIEF_MAX) || null;
646
+ };
647
+
643
648
  const TOOL_RESULT_SUMMARIZERS = new Map(
644
649
  [
650
+ [['ask_user'], summarizeAskUserResult],
645
651
  [['read', 'view_image', 'read_mcp_resource'], summarizeReadResult],
646
652
  [['apply_patch'], summarizePatchResult],
647
653
  [['grep'], summarizeGrepResult],
@@ -662,7 +668,8 @@ const TOOL_RESULT_SUMMARIZERS = new Map(
662
668
  'update_memory',
663
669
  'request_user_input',
664
670
  'update_plan',
665
- 'cwd',
671
+ 'cwd', // legacy: old transcripts
672
+ 'session',
666
673
  'list_mcp_resources',
667
674
  'list_mcp_resource_templates',
668
675
  ],
@@ -144,11 +144,14 @@ export function displayToolName(name, args = {}) {
144
144
  return 'Visualize';
145
145
  case 'list_mcp_resources':
146
146
  case 'list_mcp_resource_templates':
147
- case 'cwd':
147
+ case 'cwd': // legacy: old transcripts
148
+ case 'session':
148
149
  case 'setup':
149
150
  return 'Setup';
150
151
  case 'request_user_input':
151
152
  return 'Ask User';
153
+ case 'ask_user':
154
+ return 'Question';
152
155
  case 'update_plan':
153
156
  return 'Plan';
154
157
  case 'memory':
@@ -236,6 +239,14 @@ export function summarizeToolArgs(name, args, { max = DEFAULT_SUMMARY_MAX } = {}
236
239
  return summarizeGithub(a, max);
237
240
  case 'goal':
238
241
  return compactParts([String(a.action || ''), truncateToolText(a.objective, max)]);
242
+ case 'ask_user':
243
+ return truncateToolText(
244
+ (Array.isArray(a.questions) ? a.questions : [])
245
+ .map((q) => String(q?.header || q?.question || '').trim())
246
+ .filter(Boolean)
247
+ .join(', '),
248
+ max
249
+ );
239
250
  case 'list':
240
251
  case 'ls':
241
252
  if (Array.isArray(a.path) || Array.isArray(a.dir) || Array.isArray(a.cwd)) {
@@ -333,8 +344,12 @@ export function summarizeToolArgs(name, args, { max = DEFAULT_SUMMARY_MAX } = {}
333
344
  case 'list_mcp_resources':
334
345
  case 'list_mcp_resource_templates':
335
346
  return a.server ? `server "${truncateToolText(a.server, max)}"` : 'all servers';
336
- case 'cwd':
337
- return compactParts([String(a.action || a.type || ''), truncateToolText(firstText(a.path, a.cwd, a.dir), max)]);
347
+ case 'cwd': // legacy: old transcripts
348
+ case 'session':
349
+ return compactParts([
350
+ String(a.action || a.type || ''),
351
+ truncateToolText(firstText(a.title, a.path, a.cwd, a.dir), max),
352
+ ]);
338
353
  case 'setup':
339
354
  return compactParts([
340
355
  String(a.action || ''),
@@ -85,10 +85,12 @@ const TOOL_CATEGORY = new Map([
85
85
  ['visualize', 'Visualize'],
86
86
  ['list_mcp_resources', 'Setup'],
87
87
  ['list_mcp_resource_templates', 'Setup'],
88
- ['cwd', 'Setup'],
88
+ ['cwd', 'Setup'], // legacy: old transcripts
89
+ ['session', 'Setup'],
89
90
  ['setup', 'Setup'],
90
91
  ['goal', 'Setup'],
91
92
  ['request_user_input', 'Setup'],
93
+ ['ask_user', 'Setup'],
92
94
  ['update_plan', 'Setup'],
93
95
  ['skill', 'Skill'],
94
96
  ['skill_execute', 'Skill'],
@@ -568,7 +570,7 @@ function gitStageUnit(a) {
568
570
  function cwdUnit(a) {
569
571
  const action = String(a.action || a.type || '').toLowerCase();
570
572
  // A bare `path` selects that Project even when action is omitted.
571
- if (action === 'set' || (!action && a.path)) {
573
+ if (action === 'set' || action === 'set-project' || (!action && a.path)) {
572
574
  return unitDescriptor('Setup', {
573
575
  active: 'Selecting',
574
576
  done: 'Selected',
@@ -576,9 +578,41 @@ function cwdUnit(a) {
576
578
  effect: true,
577
579
  });
578
580
  }
579
- if (action === 'list') {
581
+ if (action === 'list' || action === 'list-projects') {
580
582
  return unitDescriptor('Setup', { active: 'Listing', done: 'Listed', noun: 'project' });
581
583
  }
584
+ if (action === 'rename') {
585
+ return unitDescriptor('Setup', { active: 'Renaming', done: 'Renamed', noun: 'session', effect: true });
586
+ }
587
+ if (action === 'compact') {
588
+ return unitDescriptor('Setup', { active: 'Scheduling', done: 'Scheduled', noun: 'compaction', effect: true });
589
+ }
590
+ if (action === 'fork') {
591
+ return unitDescriptor('Setup', { active: 'Forking', done: 'Forked', noun: 'session', effect: true });
592
+ }
593
+ if (action === 'favorite' || action === 'archive') {
594
+ const off = a.value === false;
595
+ const [active, done] =
596
+ action === 'favorite'
597
+ ? off
598
+ ? ['Unfavoriting', 'Unfavorited']
599
+ : ['Favoriting', 'Favorited']
600
+ : off
601
+ ? ['Unarchiving', 'Unarchived']
602
+ : ['Archiving', 'Archived'];
603
+ return unitDescriptor('Setup', { active, done, noun: 'session', effect: true });
604
+ }
605
+ if (action.endsWith('-worktree') || action.endsWith('-worktrees')) {
606
+ return unitDescriptor('Setup', {
607
+ active: 'Managing',
608
+ done: 'Managed',
609
+ noun: 'worktree',
610
+ effect: !action.startsWith('list'),
611
+ });
612
+ }
613
+ if (action === 'status') {
614
+ return unitDescriptor('Setup', { active: 'Checking', done: 'Checked', noun: 'session' });
615
+ }
582
616
  return unitDescriptor('Setup', { active: 'Checking', done: 'Checked', noun: 'working directory', pluralNoun: 'working directories' });
583
617
  }
584
618
 
@@ -689,13 +723,15 @@ const TOOL_UNITS = new Map([
689
723
  ['use_skill', skillUnit],
690
724
  ['code_graph', codeGraphUnit],
691
725
  ['request_user_input', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
726
+ ['ask_user', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
692
727
  ['update_plan', () => unitDescriptor('Setup', { active: 'Updating', done: 'Updated', noun: 'plan' })],
693
728
  ['list_mcp_resources', () => unitDescriptor('Setup', { active: 'Listing', done: 'Listed', noun: 'MCP resource' })],
694
729
  [
695
730
  'list_mcp_resource_templates',
696
731
  () => unitDescriptor('Setup', { active: 'Listing', done: 'Listed', noun: 'MCP resource template' }),
697
732
  ],
698
- ['cwd', cwdUnit],
733
+ ['cwd', cwdUnit], // legacy: old transcripts
734
+ ['session', cwdUnit],
699
735
  ]);
700
736
 
701
737
  function mcpUnit(name, a) {