mixdog 1.2.0 → 1.2.2

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 (386) hide show
  1. package/README.md +7 -5
  2. package/package.json +1 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/src/agents/reviewer/AGENT.md +3 -3
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +5 -0
  8. package/src/defaults/skills/pptx/SKILL.md +6 -6
  9. package/src/defaults/skills/pptx/references/review.md +6 -4
  10. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  11. package/src/defaults/skills/setup/references/actions.md +13 -3
  12. package/src/defaults/skills/visualize/SKILL.md +12 -9
  13. package/src/repl/slash-commands.mjs +16 -1
  14. package/src/rules/shared/60-verification.md +3 -1
  15. package/src/rules/shared/70-delivery.md +4 -2
  16. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  17. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  18. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  19. package/src/runtime/agent/orchestrator/config.mjs +10 -4
  20. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  21. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  22. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  23. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +122 -15
  24. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +54 -11
  25. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +104 -9
  26. package/src/runtime/agent/orchestrator/mcp/client.mjs +358 -140
  27. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  28. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  29. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  30. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  31. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  32. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  33. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  36. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  37. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +294 -44
  38. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  39. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  40. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -0
  41. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  42. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +25 -21
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
  45. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  46. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  49. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  50. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  51. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +73 -35
  53. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  54. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  55. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +8 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +53 -18
  57. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  58. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  59. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +30 -14
  60. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
  61. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
  62. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
  63. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  64. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  65. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  66. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +447 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
  68. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  70. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +102 -23
  71. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
  73. package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
  74. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  75. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +86 -19
  76. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
  78. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -0
  79. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  80. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  81. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  82. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  83. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +21 -82
  84. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
  85. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
  86. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
  87. package/src/runtime/agent/orchestrator/providers/gemini.mjs +97 -51
  88. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  89. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
  90. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  91. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  92. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  93. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  94. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
  95. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
  96. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  97. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
  98. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +5 -3
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  103. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  108. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
  109. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  110. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  111. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -1
  112. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
  113. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +6 -3
  114. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
  115. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +26 -6
  116. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
  117. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  119. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +18 -11
  120. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -2
  121. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  122. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +2 -3
  123. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  125. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +34 -3
  126. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
  127. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  128. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
  129. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
  130. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  132. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  133. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  134. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  135. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +35 -24
  136. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
  137. package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
  138. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  139. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -219
  140. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  141. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  142. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  143. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  146. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  147. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  148. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  149. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  150. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +268 -181
  151. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  152. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  153. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  154. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  155. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +270 -0
  156. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  157. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  158. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
  159. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  160. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  161. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  162. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  163. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  164. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  165. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  166. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  167. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
  169. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -4
  170. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
  171. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
  172. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  173. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
  174. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +42 -5
  175. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +14 -3
  176. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
  177. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +50 -23
  178. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
  179. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +22 -14
  180. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
  181. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  182. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  183. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
  184. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
  185. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  186. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  187. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  188. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  189. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  190. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +819 -0
  191. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +12 -0
  192. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +22 -12
  193. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  194. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
  195. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  196. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  197. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +41 -3
  198. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
  199. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  200. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  201. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  202. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  203. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  205. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  206. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  208. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
  209. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
  210. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  211. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  212. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  213. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  214. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  215. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  216. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  217. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  218. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  219. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  220. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  221. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  222. package/src/runtime/attachments/store.d.mts +3 -0
  223. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  224. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  225. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  226. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  227. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  228. package/src/runtime/memory/lib/memory.mjs +1 -1
  229. package/src/runtime/memory/lib/pg/process.mjs +34 -24
  230. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
  231. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  232. package/src/runtime/office/README.md +1 -1
  233. package/src/runtime/office/shared/values.mjs +0 -5
  234. package/src/runtime/shared/atomic-file.mjs +25 -4
  235. package/src/runtime/shared/background-tasks.mjs +92 -14
  236. package/src/runtime/shared/err-text.mjs +25 -0
  237. package/src/runtime/shared/error-presentation.mjs +159 -19
  238. package/src/runtime/shared/extension-scopes.mjs +5 -3
  239. package/src/runtime/shared/file-lock.mjs +37 -11
  240. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  241. package/src/runtime/shared/llm/anthropic-effort.mjs +134 -131
  242. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  243. package/src/runtime/shared/llm/model-catalog.mjs +53 -52
  244. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  245. package/src/runtime/shared/llm/provider-catalog-registry.mjs +17 -0
  246. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  247. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  248. package/src/runtime/shared/model-display.mjs +13 -0
  249. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  250. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  251. package/src/runtime/shared/pristine-execution.mjs +28 -4
  252. package/src/runtime/shared/provider-accounts.mjs +124 -20
  253. package/src/runtime/shared/provider-api-key.mjs +12 -0
  254. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  255. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  256. package/src/runtime/shared/shell-display.mjs +9 -3
  257. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  258. package/src/runtime/shared/skill-mentions.mjs +133 -0
  259. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  260. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  261. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  262. package/src/runtime/shared/tool-primitives.mjs +35 -2
  263. package/src/runtime/shared/turn-changes.mjs +447 -219
  264. package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
  265. package/src/runtime/shared/turn-snapshot.mjs +170 -48
  266. package/src/runtime/shared/turn-worktree-snapshot.mjs +160 -51
  267. package/src/runtime/shared/worker-requests.mjs +15 -2
  268. package/src/runtime/shared/worktrees/contract.mjs +0 -24
  269. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  270. package/src/session-runtime/automation-agents.mjs +8 -2
  271. package/src/session-runtime/boot/apis.mjs +61 -0
  272. package/src/session-runtime/boot/config.mjs +5 -2
  273. package/src/session-runtime/boot/facade.mjs +1 -0
  274. package/src/session-runtime/boot/infrastructure.mjs +35 -18
  275. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  276. package/src/session-runtime/conversation-import/service.mjs +369 -0
  277. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
  278. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  279. package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
  280. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  281. package/src/session-runtime/mcp-glue/connect.mjs +83 -16
  282. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  283. package/src/session-runtime/mcp-glue/server-catalog.mjs +135 -33
  284. package/src/session-runtime/mcp-glue.mjs +25 -2
  285. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  286. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  287. package/src/session-runtime/model-route/set-route.mjs +83 -15
  288. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  289. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  290. package/src/session-runtime/new-session-config.mjs +3 -2
  291. package/src/session-runtime/notification-bus.mjs +9 -2
  292. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  293. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  294. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  295. package/src/session-runtime/provider-readiness.mjs +16 -10
  296. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  297. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  298. package/src/session-runtime/resource-extension-sync.mjs +24 -5
  299. package/src/session-runtime/resource-mcp-api.mjs +198 -78
  300. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  301. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  302. package/src/session-runtime/resource-skills-api.mjs +23 -2
  303. package/src/session-runtime/runtime-review-api.mjs +13 -0
  304. package/src/session-runtime/schedule-session-run.mjs +1 -1
  305. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  306. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  307. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  308. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  310. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  311. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  312. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  313. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  314. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  315. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  316. package/src/session-runtime/services/provider-admin.mjs +64 -18
  317. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  318. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  319. package/src/session-runtime/setup-tool/executor.mjs +12 -1
  320. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  321. package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
  322. package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
  323. package/src/session-runtime/skills-api.mjs +7 -3
  324. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  325. package/src/session-runtime/webhook-session-run.mjs +16 -4
  326. package/src/skill-script-entry.mjs +36 -0
  327. package/src/standalone/daemon-drain-policy.mjs +8 -0
  328. package/src/standalone/daemon-stored-session-views.mjs +11 -3
  329. package/src/standalone/daemon-telemetry.mjs +55 -0
  330. package/src/standalone/daemon.mjs +44 -11
  331. package/src/standalone/session-protocol.mjs +12 -0
  332. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  333. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  334. package/src/standalone/session-service/agent-tree.mjs +12 -0
  335. package/src/standalone/session-service/quota-resume.mjs +8 -0
  336. package/src/standalone/session-service/retention/busy.mjs +15 -1
  337. package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
  338. package/src/standalone/session-service-api.mjs +5 -0
  339. package/src/standalone/session-service.mjs +1 -0
  340. package/src/tui/App.jsx +9 -1
  341. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  342. package/src/tui/app/app-view.jsx +7 -0
  343. package/src/tui/app/create-app-pickers.mjs +4 -0
  344. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  345. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  346. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  347. package/src/tui/app/extension-pickers.mjs +2 -1
  348. package/src/tui/app/model-options.mjs +13 -16
  349. package/src/tui/app/skill-mention-palette.mjs +88 -0
  350. package/src/tui/app/slash-commands.mjs +7 -2
  351. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  352. package/src/tui/app/slash-palette.mjs +23 -7
  353. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  354. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  355. package/src/tui/app/use-prompt-state.mjs +5 -0
  356. package/src/tui/components/Message.jsx +22 -1
  357. package/src/tui/components/PromptInput.jsx +21 -3
  358. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  359. package/src/tui/components/StatusLine.jsx +2 -0
  360. package/src/tui/components/TranscriptItem.jsx +9 -1
  361. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  362. package/src/tui/components/status-line/local-line.mjs +5 -2
  363. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  364. package/src/tui/components/user-message-skills.mjs +38 -0
  365. package/src/tui/dist/index.mjs +1323 -214
  366. package/src/tui/session/queue-helpers.mjs +7 -2
  367. package/src/tui/session/quota-resume.mjs +46 -14
  368. package/src/tui/session/session-api/commands.mjs +33 -24
  369. package/src/tui/session/session-api/extensions.mjs +26 -2
  370. package/src/tui/session/session-api/integrations.mjs +7 -0
  371. package/src/tui/session/session-api/lifecycle.mjs +5 -1
  372. package/src/tui/session/session-api/routes.mjs +71 -7
  373. package/src/tui/session/session-api/settings.mjs +12 -14
  374. package/src/tui/session/session-flow/drain.mjs +21 -5
  375. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  376. package/src/tui/session/tui-steering-persist.mjs +25 -9
  377. package/src/tui/session/turn.mjs +55 -15
  378. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  379. package/src/ui/statusline-agents.mjs +15 -4
  380. package/src/ui/statusline.mjs +7 -3
  381. package/src/ui/streaming-markdown-heal.mjs +34 -3
  382. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  383. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  384. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
  385. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  386. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -6,7 +6,7 @@ import { resolve as pathResolve, relative as pathRelative, isAbsolute } from 'no
6
6
  import { findBySuffixStrip, findFileByBasename } from '../builtin/path-diagnostics.mjs';
7
7
  import { resolveEntryPath, resolveV4AEntryPath, classifyEntry, pathKey } from './paths.mjs';
8
8
 
9
- function uniqueExistingPatchTarget(basePath, requestedFullPath) {
9
+ async function uniqueExistingPatchTarget(basePath, requestedFullPath) {
10
10
  // Auto-relocation is only valid for a missing target lexically inside the
11
11
  // patch root. An explicit outside-root path must never be pulled back into
12
12
  // the project merely because a basename happens to match.
@@ -23,14 +23,14 @@ function uniqueExistingPatchTarget(basePath, requestedFullPath) {
23
23
  };
24
24
  const suffix = asFile(findBySuffixStrip(basePath, requestedFullPath));
25
25
  if (suffix) return suffix;
26
- const basenameHits = findFileByBasename(basePath, requestedFullPath, { limit: 2 });
26
+ const basenameHits = await findFileByBasename(basePath, requestedFullPath, { limit: 2 });
27
27
  return basenameHits.length === 1 ? asFile(basenameHits[0]) : null;
28
28
  }
29
29
 
30
- function redirectedPatchPath(requestedFullPath, basePath) {
30
+ async function redirectedPatchPath(requestedFullPath, basePath) {
31
31
  // An existing requested path always wins over relocation.
32
32
  if (!requestedFullPath || existsSync(requestedFullPath)) return requestedFullPath;
33
- return uniqueExistingPatchTarget(basePath, requestedFullPath) || requestedFullPath;
33
+ return (await uniqueExistingPatchTarget(basePath, requestedFullPath)) || requestedFullPath;
34
34
  }
35
35
 
36
36
  export function patchHeaderPathForResolved(basePath, fullPath) {
@@ -41,33 +41,37 @@ export function patchHeaderPathForResolved(basePath, fullPath) {
41
41
  return fullPath;
42
42
  }
43
43
 
44
- export function rewriteV4AReadRedirects(sections, basePath) {
45
- return (sections || []).map((section) => {
46
- if (!section || section.kind === 'add' || !section.path) return section;
47
- const requested = resolveV4AEntryPath(basePath, section.path);
48
- const redirected = redirectedPatchPath(requested, basePath);
49
- if (pathKey(redirected) === pathKey(requested)) return section;
50
- return { ...section, path: patchHeaderPathForResolved(basePath, redirected) };
51
- });
44
+ export async function rewriteV4AReadRedirects(sections, basePath) {
45
+ return Promise.all(
46
+ (sections || []).map(async (section) => {
47
+ if (!section || section.kind === 'add' || !section.path) return section;
48
+ const requested = resolveV4AEntryPath(basePath, section.path);
49
+ const redirected = await redirectedPatchPath(requested, basePath);
50
+ if (pathKey(redirected) === pathKey(requested)) return section;
51
+ return { ...section, path: patchHeaderPathForResolved(basePath, redirected) };
52
+ })
53
+ );
52
54
  }
53
55
 
54
- export function rewriteParsedReadRedirects(parsed, basePath) {
55
- return (parsed || []).map((entry) => {
56
- const kind = classifyEntry(entry);
57
- if (kind === 'create' || !entry?.oldFileName) return entry;
58
- const requested = resolveEntryPath(basePath, entry.oldFileName);
59
- const redirected = redirectedPatchPath(requested, basePath);
60
- if (pathKey(redirected) === pathKey(requested)) return entry;
61
- const rewritten = {
62
- ...entry,
63
- oldFileName: patchHeaderPathForResolved(basePath, redirected),
64
- };
65
- if (kind === 'modify' && entry.newFileName) {
66
- const newRequested = resolveEntryPath(basePath, entry.newFileName);
67
- if (pathKey(newRequested) === pathKey(requested)) {
68
- rewritten.newFileName = rewritten.oldFileName;
56
+ export async function rewriteParsedReadRedirects(parsed, basePath) {
57
+ return Promise.all(
58
+ (parsed || []).map(async (entry) => {
59
+ const kind = classifyEntry(entry);
60
+ if (kind === 'create' || !entry?.oldFileName) return entry;
61
+ const requested = resolveEntryPath(basePath, entry.oldFileName);
62
+ const redirected = await redirectedPatchPath(requested, basePath);
63
+ if (pathKey(redirected) === pathKey(requested)) return entry;
64
+ const rewritten = {
65
+ ...entry,
66
+ oldFileName: patchHeaderPathForResolved(basePath, redirected),
67
+ };
68
+ if (kind === 'modify' && entry.newFileName) {
69
+ const newRequested = resolveEntryPath(basePath, entry.newFileName);
70
+ if (pathKey(newRequested) === pathKey(requested)) {
71
+ rewritten.newFileName = rewritten.oldFileName;
72
+ }
69
73
  }
70
- }
71
- return rewritten;
72
- });
74
+ return rewritten;
75
+ })
76
+ );
73
77
  }
@@ -84,10 +84,10 @@ function parsedEntryUnit(entry, basePath) {
84
84
  // Parse the patch body into V4A-style sections (V4A envelope, bare-@@ hunks,
85
85
  // or counted-unified salvaged as V4A), or into parsed unified entries for a
86
86
  // plain unified diff.
87
- function parsePatchSections(patchStr, requestedFormat, basePath, { coalesceByFile }) {
87
+ async function parsePatchSections(patchStr, requestedFormat, basePath, { coalesceByFile }) {
88
88
  if (isV4APatchInput(patchStr, requestedFormat)) {
89
89
  try {
90
- const parsedSections = rewriteV4AReadRedirects(parseV4APatch(patchStr), basePath);
90
+ const parsedSections = await rewriteV4AReadRedirects(parseV4APatch(patchStr), basePath);
91
91
  return { sections: coalesceByFile ? coalesceCompatibleV4ASections(parsedSections, basePath) : parsedSections };
92
92
  } catch (err) {
93
93
  throw new Error(`apply_patch: V4A parse failed — ${err?.message || String(err)}`);
@@ -98,7 +98,7 @@ function parsePatchSections(patchStr, requestedFormat, basePath, { coalesceByFil
98
98
  // section's conversion into its own unit (ordered-stop preserved) rather
99
99
  // than converting the whole patch up front.
100
100
  try {
101
- return { sections: rewriteV4AReadRedirects(parseUnifiedBareV4APatch(patchStr), basePath) };
101
+ return { sections: await rewriteV4AReadRedirects(parseUnifiedBareV4APatch(patchStr), basePath) };
102
102
  } catch (err) {
103
103
  throw new Error(`apply_patch: bare @@ parse failed — ${err?.message || String(err)}`);
104
104
  }
@@ -116,18 +116,18 @@ function parsePatchSections(patchStr, requestedFormat, basePath, { coalesceByFil
116
116
  // V4A-style sections and defer per-section conversion — same ordered-stop
117
117
  // guarantee as the V4A path (no whole-patch up-front convert).
118
118
  try {
119
- return { sections: rewriteV4AReadRedirects(parseUnifiedCountedAsV4APatch(patchStr), basePath) };
119
+ return { sections: await rewriteV4AReadRedirects(parseUnifiedCountedAsV4APatch(patchStr), basePath) };
120
120
  } catch (fallbackErr) {
121
121
  throw new Error(
122
122
  `apply_patch: parse failed — ${err?.message || String(err)}; V4A fallback failed — ${fallbackErr?.message || String(fallbackErr)}`
123
123
  );
124
124
  }
125
125
  }
126
- return { parsed: rewriteParsedReadRedirects(parsed, basePath) };
126
+ return { parsed: await rewriteParsedReadRedirects(parsed, basePath) };
127
127
  }
128
128
 
129
- export function buildPatchUnits(patchStr, requestedFormat, basePath, ctx) {
130
- const { sections, parsed } = parsePatchSections(patchStr, requestedFormat, basePath, ctx);
129
+ export async function buildPatchUnits(patchStr, requestedFormat, basePath, ctx) {
130
+ const { sections, parsed } = await parsePatchSections(patchStr, requestedFormat, basePath, ctx);
131
131
  if (sections) return sections.map((section) => sectionUnit(section, basePath, ctx));
132
132
  return (parsed || []).map((entry) => parsedEntryUnit(entry, basePath));
133
133
  }
@@ -30,7 +30,7 @@ export async function applyPatchSequence(patchStr, requestedFormat, basePath, ct
30
30
  coalesceByFile = false,
31
31
  } = ctx;
32
32
 
33
- const units = buildPatchUnits(patchStr, requestedFormat, basePath, {
33
+ const units = await buildPatchUnits(patchStr, requestedFormat, basePath, {
34
34
  v4aConvertOpts,
35
35
  dryRun,
36
36
  readStateScope,
@@ -18,6 +18,7 @@ import { randomUUID } from 'node:crypto';
18
18
  import { getPluginData } from '../config.mjs';
19
19
  import { scrubLoaderVars, scrubProviderSecrets, scrubRuntimeRootVars } from './env-scrub.mjs';
20
20
  import { spawnShellWithRetry } from './lib/shell-spawn-retry.mjs';
21
+ import { ensureSkillLauncherDir } from '../../../shared/skill-script-runtime.mjs';
21
22
 
22
23
  const SNAPSHOT_TIMEOUT_MS = 10_000;
23
24
 
@@ -146,6 +147,9 @@ echo "# Shell options" >> "$SNAPSHOT_FILE"
146
147
  ${optDump}
147
148
  echo "# Aliases" >> "$SNAPSHOT_FILE"
148
149
  ${aliasDump}
150
+ # The sourced PATH replaces the model shell's own, so it carries the
151
+ # skill-launcher entry buildShellSpawnEnv prepends (mixdog-skill-node).
152
+ PATH=${_shellQuote(ensureSkillLauncherDir())}:"$PATH"
149
153
  # PATH may contain $, backticks, or quotes that would re-expand if we
150
154
  # emitted it inside double quotes. Emit a shell-safe single-quoted PATH
151
155
  # export line via printf %q-style escaping inside the dump shell.
@@ -0,0 +1,3 @@
1
+ export function readAttachmentBuffer(value: string | { attachmentRef?: string }): Buffer;
2
+ export function isPermanentAttachmentError(error: unknown): boolean;
3
+ export function isAttachmentReference(value: unknown): boolean;
@@ -97,7 +97,7 @@ export function createOwnedStarter({
97
97
  state.automationRunning = true;
98
98
  }
99
99
  // DEGRADED MODE: a messaging connect failure — packaged runtime without
100
- // discord.js, bad token, gateway outage — must not take schedules/webhooks
100
+ // the provider library, bad token, gateway outage — must not take schedules/webhooks
101
101
  // down with it. Sends stay dead (connected=false) but session runs, the
102
102
  // webhook server and the relay tunnel keep working.
103
103
  async function degradeToAutomation() {
@@ -27,6 +27,14 @@ ${payload}
27
27
  <<<${_UNTRUSTED}_END>>>`;
28
28
  }
29
29
 
30
+ /** The run's model-visible prompt (endpoint instructions + fenced external
31
+ * payload) and its trusted skill-selection input: the endpoint-authored
32
+ * instructions alone, so nothing in the payload or headers selects a skill. */
33
+ function webhookRunPrompt(instructions, body, headers) {
34
+ const trusted = String(instructions ?? '');
35
+ return { prompt: `${trusted}\n\n${buildFencedPayload(body, headers)}`, skillSelection: trusted };
36
+ }
37
+
30
38
  function trackDispatch({ name, deliveryId, dispatchP, controller }) {
31
39
  let settled = false;
32
40
  const timeoutHandle = setTimeout(
@@ -89,6 +97,10 @@ function createWebhookSessionDispatcher({ getConfig, getBridgeDispatch }) {
89
97
  workflow: extra.workflow || null,
90
98
  attachments: extra.attachments || null,
91
99
  delivery: extra.delivery || null,
100
+ // Trusted skill-selection input: only the endpoint-authored
101
+ // instructions, never the fenced external body/headers that share
102
+ // the model-visible prompt.
103
+ skillSelection: String(extra.skillSelection ?? ''),
92
104
  context: {
93
105
  source: 'webhook',
94
106
  endpoint: name,
@@ -105,14 +117,14 @@ function createWebhookSessionDispatcher({ getConfig, getBridgeDispatch }) {
105
117
  async function dispatchEndpoint({ name, body, headers, res, deliveryId, endpoint }) {
106
118
  try {
107
119
  const { model, instructions, cwd, workflow, attachments, delivery } = endpoint;
108
- const payloadContent = buildFencedPayload(body, headers);
120
+ const run = webhookRunPrompt(instructions, body, headers);
109
121
  if (!getBridgeDispatch()) throw new Error(`[webhook] session dispatch requires bridgeDispatch`);
110
- const fullPrompt = `${instructions}\n\n${payloadContent}`;
111
- await dispatchSessionRun(name, model || null, fullPrompt, headers, deliveryId, res, {
122
+ await dispatchSessionRun(name, model || null, run.prompt, headers, deliveryId, res, {
112
123
  cwd: cwd || null,
113
124
  workflow: workflow || null,
114
125
  attachments: attachments || null,
115
126
  delivery: delivery || null,
127
+ skillSelection: run.skillSelection,
116
128
  });
117
129
  return true;
118
130
  } catch (err) {
@@ -125,4 +137,4 @@ function createWebhookSessionDispatcher({ getConfig, getBridgeDispatch }) {
125
137
  return { dispatchEndpoint };
126
138
  }
127
139
 
128
- export { buildFencedPayload, createWebhookSessionDispatcher };
140
+ export { buildFencedPayload, createWebhookSessionDispatcher, webhookRunPrompt };
@@ -218,20 +218,23 @@ function wireWebhookHandlers() {
218
218
  webhookServer.setEventPipeline(eventPipeline);
219
219
  // Webhook fires run as sessions (schedules parity); the Automations
220
220
  // session row is the only surface (channel relay retired).
221
- webhookServer.setBridgeDispatch(async ({ prompt, model, cwd, workflow, attachments, context, signal }) => {
222
- const { runWebhookSession } = await import('../../../session-runtime/webhook-session-run.mjs');
223
- const run = await runWebhookSession({
224
- name: context?.endpoint || 'webhook',
225
- model: model || null,
226
- cwd: cwd || null,
227
- workflow: workflow || null,
228
- attachments: attachments || null,
229
- // Dispatch-timeout cancellation only works if the signal reaches the run.
230
- signal: signal || null,
231
- prompt,
232
- });
233
- return run;
234
- });
221
+ webhookServer.setBridgeDispatch(
222
+ async ({ prompt, skillSelection, model, cwd, workflow, attachments, context, signal }) => {
223
+ const { runWebhookSession } = await import('../../../session-runtime/webhook-session-run.mjs');
224
+ const run = await runWebhookSession({
225
+ name: context?.endpoint || 'webhook',
226
+ model: model || null,
227
+ cwd: cwd || null,
228
+ workflow: workflow || null,
229
+ attachments: attachments || null,
230
+ // Dispatch-timeout cancellation only works if the signal reaches the run.
231
+ signal: signal || null,
232
+ prompt,
233
+ skillSelection,
234
+ });
235
+ return run;
236
+ }
237
+ );
235
238
  }
236
239
  function wireEventQueueHandlers(eventQueue) {
237
240
  if (!eventQueue) return;
@@ -17,8 +17,6 @@ export const INPUT_GROUP_SECURITY_NOTE =
17
17
  export const GNOME_EXTENSION_UUID = 'mixdog-windows@mixdog.io';
18
18
  /** The oldest helper interface this app can use (2 added Screenshot and StopRequested, 3 the in-shell indicator). */
19
19
  export const MIN_WINDOW_HELPER_VERSION = 3;
20
- export const WINDOW_CONTROL_HINT =
21
- 'wayland_window_control_unavailable: this compositor offers no window control to other programs; on GNOME the Mixdog Windows extension (mixdog-windows@mixdog.io) provides it and must be enabled and loaded';
22
20
  export const WINDOW_HELPER_RELOGIN_HINT =
23
21
  'wayland_window_control_unavailable: the Mixdog Windows GNOME extension is installed and enabled but GNOME Shell has not loaded it yet; the user must sign out and sign in again once';
24
22
  export const WINDOW_HELPER_ENABLE_HINT =
@@ -20,12 +20,19 @@ const MODEL_FILES = ['model.onnx', 'tokenizer.json'];
20
20
  // The worker runs one judgment at a time, so requests are sent one by one:
21
21
  // each answer's deadline starts when it is sent, and the wait for earlier
22
22
  // requests is bounded separately so a burst of turns queues instead of
23
- // timing out behind each other.
23
+ // timing out behind each other. The next request is sent only once the worker
24
+ // has answered the previous one: an answer that missed its deadline still
25
+ // occupies the worker, and sending into it would start the next deadline
26
+ // while the worker is busy, failing it too.
27
+ // 500 ms covers the 18-layer judge's tail while parallel agents share the CPU.
24
28
  // MIXDOG_EFFORT_JUDGE_TIMEOUT_MS raises it on a host whose CPUs are shared
25
29
  // with heavy work (parallel benchmark containers).
26
30
  const WARM_TIMEOUT_MS =
27
- Number(process.env.MIXDOG_EFFORT_JUDGE_TIMEOUT_MS) > 0 ? Number(process.env.MIXDOG_EFFORT_JUDGE_TIMEOUT_MS) : 400;
31
+ Number(process.env.MIXDOG_EFFORT_JUDGE_TIMEOUT_MS) > 0 ? Number(process.env.MIXDOG_EFFORT_JUDGE_TIMEOUT_MS) : 500;
28
32
  const QUEUE_WAIT_MS = 1000;
33
+ // A worker that has not answered for this long is stuck; it is replaced so
34
+ // the queue does not stay blocked behind it.
35
+ const STUCK_MS = 10_000;
29
36
  let queueTail = Promise.resolve();
30
37
  // A turn that arrives while the judge is still loading (its first use, or the
31
38
  // first turn after a model update) waits at most this long; loading takes about 2 s on a desktop CPU.
@@ -107,7 +114,7 @@ function settle(id, fn) {
107
114
  const entry = pending.get(id);
108
115
  if (!entry) return;
109
116
  pending.delete(id);
110
- clearTimeout(entry.timer);
117
+ entry.done();
111
118
  fn(entry);
112
119
  }
113
120
 
@@ -151,11 +158,27 @@ function ensureWorker(dir) {
151
158
  return created;
152
159
  }
153
160
 
161
+ // `answer` settles with the probabilities or fails at the deadline; `done`
162
+ // resolves once the worker has answered (or exited), when it can take the next request.
154
163
  function request(target, { request: text, prev, prevRequest, step }) {
155
164
  const id = ++msgId;
156
- return new Promise((resolve, reject) => {
157
- const timer = setTimeout(() => settle(id, (entry) => entry.reject(new Error('timeout'))), WARM_TIMEOUT_MS);
158
- pending.set(id, { resolve, reject, timer });
165
+ let finish;
166
+ const done = new Promise((resolve) => {
167
+ finish = resolve;
168
+ });
169
+ const answer = new Promise((resolve, reject) => {
170
+ const timer = setTimeout(() => reject(new Error('timeout')), WARM_TIMEOUT_MS);
171
+ const stuck = setTimeout(() => void target.terminate().catch(() => {}), STUCK_MS);
172
+ stuck.unref();
173
+ pending.set(id, {
174
+ resolve,
175
+ reject,
176
+ done: () => {
177
+ clearTimeout(timer);
178
+ clearTimeout(stuck);
179
+ finish();
180
+ },
181
+ });
159
182
  // The worker formats the text the way its model was trained.
160
183
  target.postMessage({
161
184
  action: 'judge',
@@ -169,6 +192,9 @@ function request(target, { request: text, prev, prevRequest, step }) {
169
192
  ...(step ? { step } : {}),
170
193
  });
171
194
  });
195
+ // A caller that gave up while queued never reads its answer.
196
+ answer.catch(() => {});
197
+ return { answer, done };
172
198
  }
173
199
 
174
200
  // One install at a time (the settings install and the boot refresh can overlap).
@@ -257,19 +283,31 @@ export async function judgeTurn(input) {
257
283
  if (!ready && !(await waitReady(COLD_WAIT_MS))) {
258
284
  return { skipped: lastLoadError ? `load-error: ${lastLoadError}` : 'warming' };
259
285
  }
260
- const queuedAt = Date.now();
261
- const run = queueTail.then(async () => {
262
- if (worker !== target || !ready) return { skipped: 'effort judge exited' };
263
- if (Date.now() - queuedAt > QUEUE_WAIT_MS) return { skipped: 'busy' };
264
- const startedAt = Date.now();
265
- try {
266
- return { probs: await request(target, input), ms: Date.now() - startedAt };
267
- } catch (error) {
268
- return { skipped: String(error?.message || error) };
269
- }
286
+ let abandoned = false;
287
+ const turn = queueTail.then(() => {
288
+ if (abandoned) return null;
289
+ if (worker !== target || !ready) return { exited: true };
290
+ return { startedAt: Date.now(), ...request(target, input) };
270
291
  });
271
- queueTail = run;
272
- return run;
292
+ queueTail = turn.then((sent) => sent?.done);
293
+ let timer;
294
+ const sent = await Promise.race([
295
+ turn,
296
+ new Promise((resolve) => {
297
+ timer = setTimeout(resolve, QUEUE_WAIT_MS, null);
298
+ }),
299
+ ]);
300
+ clearTimeout(timer);
301
+ if (!sent) {
302
+ abandoned = true;
303
+ return { skipped: 'busy' };
304
+ }
305
+ if (sent.exited) return { skipped: 'effort judge exited' };
306
+ try {
307
+ return { probs: await sent.answer, ms: Date.now() - sent.startedAt };
308
+ } catch (error) {
309
+ return { skipped: String(error?.message || error) };
310
+ }
273
311
  }
274
312
 
275
313
  // MIXDOG_EFFORT_DECISIONS_LOG redirects the log, e.g. for benchmark runs whose
@@ -161,7 +161,7 @@ async function _migrateRecallIndexesIfStale(db) {
161
161
  }
162
162
 
163
163
  // One-time cleanup: attachment-only placeholder rows ('(attachment)' user
164
- // content, e.g. Discord provider discord.mjs:724) predate the
164
+ // content from the former channel provider) predate the
165
165
  // shouldExcludeIngestMessage() ingest-time filter (session-ingest.mjs).
166
166
  // Delete any already-persisted rows so they stop polluting recall/cycle1.
167
167
  // Idempotent (no-op once cleaned); best-effort so a failure never blocks boot.
@@ -12,17 +12,16 @@ import {
12
12
  existsSync,
13
13
  mkdirSync,
14
14
  mkdtempSync,
15
- readdirSync,
16
15
  readFileSync,
17
16
  rmdirSync,
18
17
  rmSync,
19
- statSync,
20
18
  symlinkSync,
21
19
  unlinkSync,
22
20
  writeFileSync,
23
21
  } from 'node:fs';
22
+ import { readdir, readFile, rm, stat } from 'node:fs/promises';
24
23
  import { join } from 'node:path';
25
- import { spawn, spawnSync } from 'node:child_process';
24
+ import { execFile, spawn, spawnSync } from 'node:child_process';
26
25
  import { createConnection, createServer } from 'node:net';
27
26
  import { isPidAlive } from '../../../shared/pid-liveness.mjs';
28
27
 
@@ -607,22 +606,36 @@ export function classifyOrphanTempPostmaster({
607
606
  return Number(uptimeSec) >= Math.max(60, Number(minUptimeSec) || ORPHAN_TEMP_PG_MIN_UPTIME_SEC);
608
607
  }
609
608
 
610
- function tempPostmasterOwnerAlive(args) {
609
+ async function tempPostmasterOwnerAlive(args) {
611
610
  const rawDataDir = pgDataDirFromArgs(args);
612
611
  if (!rawDataDir) return false;
613
612
  const dataRoot = join(rawDataDir, '..');
614
613
  for (const name of ['memory-runtime-owner.json', 'daemon-owner.json']) {
615
614
  try {
616
- const owner = JSON.parse(readFileSync(join(dataRoot, name), 'utf8'));
615
+ const owner = JSON.parse(await readFile(join(dataRoot, name), 'utf8'));
617
616
  if (Number(owner?.pid) > 0 && isPidAlive(Number(owner.pid))) return true;
618
617
  } catch {}
619
618
  }
620
619
  return false;
621
620
  }
622
621
 
623
- function listPostmasterRows() {
622
+ // Async child run: stdout on exit 0, null on any failure/timeout (the old
623
+ // spawnSync `status !== 0` contract). Never blocks the event loop.
624
+ function execFileText(file, args, options) {
625
+ return new Promise((resolve) => {
626
+ try {
627
+ execFile(file, args, { encoding: 'utf8', ...options }, (error, stdout) => {
628
+ resolve(error ? null : String(stdout || ''));
629
+ });
630
+ } catch {
631
+ resolve(null);
632
+ }
633
+ });
634
+ }
635
+
636
+ async function listPostmasterRows() {
624
637
  if (process.platform === 'win32') {
625
- const result = spawnSync(
638
+ const stdout = await execFileText(
626
639
  'powershell',
627
640
  [
628
641
  '-NoProfile',
@@ -632,10 +645,10 @@ function listPostmasterRows() {
632
645
  'started = [int](New-TimeSpan -Start $_.CreationDate -End (Get-Date)).TotalSeconds; ' +
633
646
  'args = $_.CommandLine } }',
634
647
  ],
635
- { encoding: 'utf8', timeout: 15_000, windowsHide: true }
648
+ { timeout: 15_000, windowsHide: true }
636
649
  );
637
- if (result.status !== 0) return [];
638
- return String(result.stdout || '')
650
+ if (stdout === null) return [];
651
+ return stdout
639
652
  .split(/\r?\n/)
640
653
  .filter(Boolean)
641
654
  .flatMap((line) => {
@@ -647,12 +660,9 @@ function listPostmasterRows() {
647
660
  }
648
661
  });
649
662
  }
650
- const result = spawnSync('ps', ['-eo', 'pid=,etimes=,args='], {
651
- encoding: 'utf8',
652
- timeout: 15_000,
653
- });
654
- if (result.status !== 0) return [];
655
- return String(result.stdout || '')
663
+ const stdout = await execFileText('ps', ['-eo', 'pid=,etimes=,args='], { timeout: 15_000 });
664
+ if (stdout === null) return [];
665
+ return stdout
656
666
  .split(/\r?\n/)
657
667
  .flatMap((line) => {
658
668
  const match = line.match(/^\s*(\d+)\s+(\d+)\s+(.*postgres.*)$/);
@@ -679,11 +689,11 @@ function pristineRootForArgs(args, tempRoot) {
679
689
  // (observed: 87 roots, 6.1GB, alongside 57 live postmasters). Roots a live
680
690
  // postmaster still owns are kept, and the same uptime margin that protects a
681
691
  // running harness from the process sweep protects its directory here.
682
- function sweepAbandonedPristineRoots(tempRoot, liveRoots, minAgeMs) {
692
+ async function sweepAbandonedPristineRoots(tempRoot, liveRoots, minAgeMs) {
683
693
  let removed = 0;
684
694
  let entries;
685
695
  try {
686
- entries = readdirSync(tempRoot, { withFileTypes: true });
696
+ entries = await readdir(tempRoot, { withFileTypes: true });
687
697
  } catch {
688
698
  return 0;
689
699
  }
@@ -693,12 +703,12 @@ function sweepAbandonedPristineRoots(tempRoot, liveRoots, minAgeMs) {
693
703
  const full = join(tempRoot, entry.name);
694
704
  if (liveRoots.has(normalizePathForMatch(full))) continue;
695
705
  try {
696
- if (statSync(full).mtimeMs > cutoff) continue;
706
+ if ((await stat(full)).mtimeMs > cutoff) continue;
697
707
  } catch {
698
708
  continue;
699
709
  }
700
710
  try {
701
- rmSync(full, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
711
+ await rm(full, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
702
712
  removed += 1;
703
713
  } catch {
704
714
  /* a process this sweep did not reap still holds it */
@@ -709,18 +719,18 @@ function sweepAbandonedPristineRoots(tempRoot, liveRoots, minAgeMs) {
709
719
 
710
720
  /** Best-effort machine hygiene: reap orphan temp postmasters, then drop the
711
721
  * throwaway roots no live postmaster owns. Runs periodically, not once. */
712
- export function sweepOrphanTempPostmasters({ tempRoot, minUptimeSec } = {}) {
722
+ export async function sweepOrphanTempPostmasters({ tempRoot, minUptimeSec } = {}) {
713
723
  let reaped = 0;
714
724
  try {
715
725
  const root = tempRoot || process.env.TMPDIR || process.env.TEMP || process.env.TMP || '/tmp';
716
726
  const liveRoots = new Set();
717
- for (const row of listPostmasterRows()) {
727
+ for (const row of await listPostmasterRows()) {
718
728
  if (!row.pid || row.pid === process.pid) continue;
719
729
  if (
720
730
  !classifyOrphanTempPostmaster({
721
731
  ...row,
722
732
  tempRoot: root,
723
- ownerAlive: tempPostmasterOwnerAlive(row.args),
733
+ ownerAlive: await tempPostmasterOwnerAlive(row.args),
724
734
  minUptimeSec,
725
735
  })
726
736
  ) {
@@ -737,7 +747,7 @@ export function sweepOrphanTempPostmasters({ tempRoot, minUptimeSec } = {}) {
737
747
  }
738
748
  }
739
749
  const minAgeMs = Math.max(60, Number(minUptimeSec) || ORPHAN_TEMP_PG_MIN_UPTIME_SEC) * 1000;
740
- const removed = sweepAbandonedPristineRoots(root, liveRoots, minAgeMs);
750
+ const removed = await sweepAbandonedPristineRoots(root, liveRoots, minAgeMs);
741
751
  if (removed > 0) __mixdogMemoryLog(`[pg-process] removed ${removed} abandoned pristine root(s)\n`);
742
752
  } catch {
743
753
  /* hygiene is best-effort */
@@ -372,6 +372,16 @@ function readPostmasterInfo(pgdata) {
372
372
  }
373
373
  }
374
374
 
375
+ // Async child run (never blocks the daemon loop): stdout on exit 0, else null.
376
+ async function _execFileText(file, args) {
377
+ const { execFile } = await import('node:child_process');
378
+ return new Promise((resolveText) => {
379
+ execFile(file, args, { encoding: 'utf8', windowsHide: true, timeout: 15_000 }, (error, stdout) => {
380
+ resolveText(error ? null : String(stdout || ''));
381
+ });
382
+ });
383
+ }
384
+
375
385
  /**
376
386
  * Best-effort process-name check: confirms the pid's comm name contains 'postgres'.
377
387
  * Falls back to true (alive) when the name cannot be determined.
@@ -383,19 +393,12 @@ async function isPostgresPid(pid) {
383
393
  return comm.includes('postgres');
384
394
  }
385
395
  if (process.platform === 'darwin') {
386
- const { spawnSync } = await import('node:child_process');
387
- const r = spawnSync('ps', ['-o', 'comm=', '-p', String(pid)], { encoding: 'utf8', windowsHide: true });
388
- if (r.status === 0) return (r.stdout || '').trim().includes('postgres');
389
- return true;
396
+ const out = await _execFileText('ps', ['-o', 'comm=', '-p', String(pid)]);
397
+ return out === null ? true : out.trim().includes('postgres');
390
398
  }
391
399
  if (process.platform === 'win32') {
392
- const { spawnSync } = await import('node:child_process');
393
- const r = spawnSync('tasklist', ['/FI', `PID eq ${pid}`, '/FO', 'CSV', '/NH'], {
394
- encoding: 'utf8',
395
- windowsHide: true,
396
- });
397
- if (r.status === 0) return (r.stdout || '').toLowerCase().includes('postgres');
398
- return true;
400
+ const out = await _execFileText('tasklist', ['/FI', `PID eq ${pid}`, '/FO', 'CSV', '/NH']);
401
+ return out === null ? true : out.toLowerCase().includes('postgres');
399
402
  }
400
403
  } catch {
401
404
  /* cannot read — fall back to alive */
@@ -463,8 +466,8 @@ function scheduleOrphanTempPostmasterSweep() {
463
466
  _orphanSweepStarted = true;
464
467
  const runSweep = () => {
465
468
  void _getPgProc()
466
- .then(({ sweepOrphanTempPostmasters }) => {
467
- const reaped = sweepOrphanTempPostmasters?.() || 0;
469
+ .then(async ({ sweepOrphanTempPostmasters }) => {
470
+ const reaped = (await sweepOrphanTempPostmasters?.()) || 0;
468
471
  if (reaped > 0) __mixdogMemoryLog(`[supervisor-pg] orphan sweep reaped ${reaped} temp postmaster(s)\n`);
469
472
  })
470
473
  .catch(() => {
@@ -201,8 +201,8 @@ function isExcludedUserIngestText(m, text) {
201
201
  if (metaSource === 'task-notification') return true;
202
202
  // `Reference files:` synthetic user rows (manager.mjs isReferenceFilesMessage).
203
203
  if (/^Reference files:\s*/i.test(trimmedStart)) return true;
204
- // Attachment-only placeholder rows (e.g. Discord provider discord.mjs:724
205
- // `"(attachment)"` fallback when a message carries no text, only files).
204
+ // Attachment-only placeholder rows (`"(attachment)"` fallback written by the
205
+ // former channel provider when a message carried no text, only files).
206
206
  if (text.trim() === '(attachment)') return true;
207
207
  // Compaction summary user rows (compact.mjs isSummaryMessage / SUMMARY_PREFIX).
208
208
  if (metaSource === 'compact-summary') return true;
@@ -17,7 +17,7 @@ Microsoft Office installed.
17
17
  | `design/` | Design tokens, content model, composition, creative direction for the Word and Excel composers (`compose_document`, `compose_sheet`); `design-discipline.mjs` owns the safe typeface list, palette repair (tinted dark fields, WCAG contrast, paired accent tints), and the brief rules; `docx/`, `xlsx/` format compilers; `library/` template library with the bundled `templates/`. Decks are never composed here — a slide is authored by the model as a script (`authoring/`), and `compose_slide` is refused with that route. |
18
18
  | `quality/` | Reviews and gates: `assurance-*.mjs` (trust, structure, rendered pages, checklist), aesthetics, design review, scoring, visual diff. |
19
19
  | `bench/` | Benchmarks behind `npm run bench:office*`; `bench-support.mjs` holds the shared tool-call helpers. |
20
- | `shared/` | Tiny helpers used across folders: `values.mjs` (`plainObject`, `clone`, `stableValue`, `sha256`, `clamp`, `compact`, `imageBuffer`), `page-sizes.mjs` (the paper sizes PDF create and Word `set_page` share), `column-widths.mjs` (the widths a Word or PDF table given none takes from its text), and `asar-path.mjs`. |
20
+ | `shared/` | Tiny helpers used across folders: `values.mjs` (`plainObject`, `clone`, `stableValue`, `sha256`, `clamp`, `compact`), `page-sizes.mjs` (the paper sizes PDF create and Word `set_page` share), `column-widths.mjs` (the widths a Word or PDF table given none takes from its text), and `asar-path.mjs`. |
21
21
 
22
22
  ## Dependency direction
23
23
 
@@ -32,8 +32,3 @@ export function compact(value, maximum = 120) {
32
32
  .replace(/\s+/g, ' ')
33
33
  .slice(0, maximum);
34
34
  }
35
-
36
- export function imageBuffer(image) {
37
- if (Buffer.isBuffer(image?.data)) return image.data;
38
- return Buffer.from(String(image?.data || ''), 'base64');
39
- }