mixdog 1.2.5 → 1.3.0

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 (493) hide show
  1. package/LICENSES/simple-icons-CC0-1.0.txt +30 -0
  2. package/NOTICE.md +19 -0
  3. package/package.json +4 -1
  4. package/scripts/check-model-recommendations.mjs +89 -0
  5. package/scripts/gate-local.mjs +7 -0
  6. package/scripts/lib/gate-scheduler.mjs +2 -2
  7. package/scripts/lib/isolated-test-env.mjs +16 -0
  8. package/scripts/lib/run-node-tests.mjs +5 -14
  9. package/scripts/provider-pingpong-live.mjs +9 -9
  10. package/src/agents/advisor/AGENT.md +4 -4
  11. package/src/agents/advisor/agent.json +1 -1
  12. package/src/agents/reviewer/AGENT.md +5 -4
  13. package/src/agents/reviewer/agent.json +1 -1
  14. package/src/defaults/shipped-history.json +17 -0
  15. package/src/defaults/skills/browser-use/SKILL.md +7 -1
  16. package/src/defaults/skills/computer-use/SKILL.md +3 -1
  17. package/src/defaults/skills/memory-management/SKILL.md +4 -1
  18. package/src/defaults/skills/setup/references/actions.md +11 -4
  19. package/src/defaults/skills/setup-guide/SKILL.md +175 -0
  20. package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
  21. package/src/defaults/skills/visualize/SKILL.md +3 -2
  22. package/src/lib/rules-builder.cjs +56 -7
  23. package/src/output-styles/common.md +22 -6
  24. package/src/output-styles/detailed.md +7 -5
  25. package/src/output-styles/minimal.md +7 -3
  26. package/src/output-styles/simple.md +2 -3
  27. package/src/rules/agent/AGENT.md +7 -1
  28. package/src/rules/agent-mode/AGENT_MODE.md +24 -0
  29. package/src/rules/agent-mode/MIXY.md +21 -0
  30. package/src/rules/agent-mode/ROUTINE.md +6 -0
  31. package/src/rules/lead/LEAD.md +9 -4
  32. package/src/rules/shared/10-tool-workflow.md +2 -1
  33. package/src/rules/shared/60-verification.md +4 -5
  34. package/src/rules/shared/70-delivery.md +3 -0
  35. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
  36. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
  37. package/src/runtime/agent/orchestrator/config.mjs +6 -0
  38. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
  39. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
  40. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +5 -3
  41. package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
  42. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
  43. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +58 -64
  44. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
  45. package/src/runtime/agent/orchestrator/mcp/client.mjs +122 -15
  46. package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
  47. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
  48. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
  49. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
  50. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
  51. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
  52. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
  53. package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
  54. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +41 -19
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
  58. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
  59. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
  62. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +11 -5
  64. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
  65. package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
  66. package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
  69. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
  70. package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
  71. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
  72. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
  80. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  81. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
  82. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  83. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
  84. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
  86. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
  88. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
  92. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
  94. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
  95. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
  96. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
  97. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
  98. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
  99. package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
  100. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +98 -4
  101. package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
  102. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
  103. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +15 -8
  104. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
  109. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
  110. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
  111. package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
  112. package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
  113. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
  114. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
  115. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
  116. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
  117. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
  118. package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
  119. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
  120. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
  121. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
  122. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
  123. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
  124. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
  125. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
  126. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
  127. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
  128. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
  129. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
  130. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
  131. package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
  132. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
  133. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
  134. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
  135. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
  136. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +82 -33
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +11 -4
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
  140. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +6 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
  146. package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
  147. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
  148. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
  149. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
  150. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
  151. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
  152. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
  153. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
  154. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
  155. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
  156. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
  157. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
  158. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
  159. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
  161. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
  163. package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
  166. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
  167. package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
  168. package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
  169. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
  171. package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
  173. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
  174. package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
  175. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
  176. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +325 -0
  177. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +84 -21
  178. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
  179. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
  180. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
  181. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
  182. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
  183. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
  184. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
  185. package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
  186. package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
  189. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
  190. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
  191. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
  197. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
  198. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
  199. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
  200. package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
  201. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
  203. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
  207. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
  208. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
  209. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
  210. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
  211. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
  212. package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
  213. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
  214. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
  215. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
  216. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
  217. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
  218. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
  219. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
  220. package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
  221. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +123 -32
  222. package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
  224. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
  225. package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
  226. package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
  227. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
  228. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
  229. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
  230. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  231. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
  232. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +64 -2
  233. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +10 -2
  234. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
  235. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +8 -0
  236. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -1
  237. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
  238. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +104 -55
  239. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
  240. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
  241. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
  242. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  243. package/src/runtime/attachments/office-extract.mjs +11 -9
  244. package/src/runtime/browser-bridge/client.mjs +24 -0
  245. package/src/runtime/channels/lib/scheduler.mjs +40 -12
  246. package/src/runtime/channels/lib/schedules-db.mjs +71 -12
  247. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
  248. package/src/runtime/channels/lib/webhook.mjs +0 -1
  249. package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
  250. package/src/runtime/channels/lib/worker-main.mjs +17 -20
  251. package/src/runtime/computer-bridge/client.mjs +28 -1
  252. package/src/runtime/connectors/gmail-app-password.mjs +690 -0
  253. package/src/runtime/connectors/google-mcp.mjs +446 -0
  254. package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
  255. package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
  256. package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
  257. package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
  258. package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
  259. package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
  260. package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
  261. package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
  262. package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
  263. package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
  264. package/src/runtime/memory/lib/memory.mjs +7 -1
  265. package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
  266. package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
  267. package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
  268. package/src/runtime/memory/lib/tool-call-handler.mjs +9 -5
  269. package/src/runtime/memory/tool-defs.mjs +5 -0
  270. package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
  271. package/src/runtime/office/core/tabular.mjs +1 -1
  272. package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
  273. package/src/runtime/office/portable/docx-formatting.mjs +1 -1
  274. package/src/runtime/office/portable/docx-runs.mjs +1 -1
  275. package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
  276. package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
  277. package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
  278. package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
  279. package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
  280. package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
  281. package/src/runtime/office/portable/portable-opc.mjs +27 -13
  282. package/src/runtime/office/portable/portable-pivot.mjs +3 -3
  283. package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
  284. package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
  285. package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
  286. package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
  287. package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
  288. package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
  289. package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
  290. package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
  291. package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
  292. package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
  293. package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
  294. package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
  295. package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
  296. package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
  297. package/src/runtime/office/portable/portable-xml.mjs +1 -1
  298. package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
  299. package/src/runtime/shared/agent-avatar.d.mts +64 -0
  300. package/src/runtime/shared/agent-avatar.mjs +320 -0
  301. package/src/runtime/shared/agent-route-config.d.mts +3 -0
  302. package/src/runtime/shared/agent-route-config.mjs +16 -0
  303. package/src/runtime/shared/atomic-file.mjs +36 -14
  304. package/src/runtime/shared/background-tasks.mjs +60 -20
  305. package/src/runtime/shared/child-spawn-gate.mjs +26 -16
  306. package/src/runtime/shared/config.mjs +8 -11
  307. package/src/runtime/shared/connector-accounts.mjs +15 -0
  308. package/src/runtime/shared/connector-catalog.d.mts +52 -0
  309. package/src/runtime/shared/connector-catalog.mjs +230 -0
  310. package/src/runtime/shared/connector-triggers.d.mts +3 -0
  311. package/src/runtime/shared/connector-triggers.mjs +43 -0
  312. package/src/runtime/shared/file-lock.mjs +7 -1
  313. package/src/runtime/shared/file-permissions-worker.mjs +38 -0
  314. package/src/runtime/shared/file-permissions.d.mts +19 -4
  315. package/src/runtime/shared/file-permissions.mjs +310 -4
  316. package/src/runtime/shared/git-runner-worker.mjs +6 -78
  317. package/src/runtime/shared/google-oauth-client.mjs +24 -0
  318. package/src/runtime/shared/held-request-host.d.mts +12 -0
  319. package/src/runtime/shared/held-request-host.mjs +71 -0
  320. package/src/runtime/shared/llm/http-agent.mjs +7 -3
  321. package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
  322. package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
  323. package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
  324. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
  325. package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
  326. package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
  327. package/src/runtime/shared/memory-snapshot.mjs +5 -1
  328. package/src/runtime/shared/notify-trace.mjs +8 -1
  329. package/src/runtime/shared/plain-preview.d.mts +1 -0
  330. package/src/runtime/shared/plain-preview.mjs +28 -0
  331. package/src/runtime/shared/pristine-execution-contract.json +5 -1
  332. package/src/runtime/shared/process-runner-worker.mjs +7 -0
  333. package/src/runtime/shared/process-runner.mjs +38 -0
  334. package/src/runtime/shared/provider-accounts.mjs +2 -1
  335. package/src/runtime/shared/provider-api-key.mjs +0 -1
  336. package/src/runtime/shared/read-row-numbers.mjs +1 -1
  337. package/src/runtime/shared/resource-admission.mjs +60 -18
  338. package/src/runtime/shared/routine-limits.d.mts +11 -0
  339. package/src/runtime/shared/routine-limits.mjs +21 -0
  340. package/src/runtime/shared/routine-trigger.d.mts +10 -0
  341. package/src/runtime/shared/routine-trigger.mjs +44 -0
  342. package/src/runtime/shared/run-child.mjs +84 -0
  343. package/src/runtime/shared/schedule-model-ref.mjs +9 -10
  344. package/src/runtime/shared/session-activity-signal.mjs +23 -0
  345. package/src/runtime/shared/shell-output-summary.mjs +23 -0
  346. package/src/runtime/shared/singleton-owner.mjs +126 -42
  347. package/src/runtime/shared/slow-span.mjs +4 -12
  348. package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
  349. package/src/runtime/shared/tool-output-limit.mjs +4 -2
  350. package/src/runtime/shared/tool-output-marker.mjs +58 -0
  351. package/src/runtime/shared/transcript-metadata.mjs +10 -0
  352. package/src/runtime/shared/turn-changes.mjs +0 -8
  353. package/src/runtime/shared/usage-readout-totals.mjs +56 -0
  354. package/src/runtime/shared/user-data-guard.mjs +131 -34
  355. package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
  356. package/src/runtime/shared/worktrees/git-head.mjs +20 -2
  357. package/src/runtime/shared/worktrees/lock.mjs +3 -2
  358. package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
  359. package/src/runtime/tidy/runners/biome.mjs +3 -1
  360. package/src/runtime/tidy/shadow.mjs +2 -1
  361. package/src/runtime/web-search/index.mjs +5 -7
  362. package/src/runtime/web-search/lib/formatter.mjs +42 -6
  363. package/src/runtime/web-search/tool-defs.mjs +6 -1
  364. package/src/session-runtime/agent-home-delivery.mjs +459 -0
  365. package/src/session-runtime/agent-profile-changes.mjs +21 -0
  366. package/src/session-runtime/agent-room-delivery.mjs +92 -0
  367. package/src/session-runtime/agent-task-sessions.mjs +200 -0
  368. package/src/session-runtime/boot/apis.mjs +50 -18
  369. package/src/session-runtime/boot/facade.mjs +5 -8
  370. package/src/session-runtime/boot/infrastructure.mjs +28 -17
  371. package/src/session-runtime/boot/tools.mjs +3 -0
  372. package/src/session-runtime/channel-config-api.mjs +53 -5
  373. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
  374. package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
  375. package/src/session-runtime/held-requests.mjs +228 -0
  376. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
  377. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
  378. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
  379. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
  380. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  381. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
  382. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
  383. package/src/session-runtime/lifecycle/session-switch/resume.mjs +11 -4
  384. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
  385. package/src/session-runtime/lifecycle/shared.mjs +25 -2
  386. package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
  387. package/src/session-runtime/lifecycle/teardown.mjs +5 -2
  388. package/src/session-runtime/lifecycle-api.mjs +3 -1
  389. package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
  390. package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
  391. package/src/session-runtime/mcp-oauth-login.mjs +112 -15
  392. package/src/session-runtime/model-route/set-route.mjs +14 -3
  393. package/src/session-runtime/owned-automation-run.mjs +229 -0
  394. package/src/session-runtime/provider-auth/login.mjs +10 -6
  395. package/src/session-runtime/provider-auth/setup.mjs +19 -2
  396. package/src/session-runtime/provider-catalog-cache.mjs +101 -25
  397. package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
  398. package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
  399. package/src/session-runtime/provider-models.mjs +76 -10
  400. package/src/session-runtime/provider-readiness.mjs +4 -0
  401. package/src/session-runtime/resource-api.mjs +5 -0
  402. package/src/session-runtime/resource-mcp-api.mjs +107 -13
  403. package/src/session-runtime/resource-skills-api.mjs +12 -0
  404. package/src/session-runtime/room-member-gate.mjs +48 -0
  405. package/src/session-runtime/routine-home-turn.mjs +156 -0
  406. package/src/session-runtime/routine-owner.mjs +48 -0
  407. package/src/session-runtime/schedule-session-run.mjs +30 -64
  408. package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
  409. package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
  410. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
  411. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
  412. package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
  413. package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
  414. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
  415. package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
  416. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
  417. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
  418. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
  419. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
  420. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
  421. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
  422. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
  423. package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
  424. package/src/session-runtime/services/agent-tool.mjs +20 -0
  425. package/src/session-runtime/services/channel-admin.mjs +93 -24
  426. package/src/session-runtime/services/memory-access.mjs +37 -0
  427. package/src/session-runtime/services/provider-admin.mjs +166 -59
  428. package/src/session-runtime/services/schedule-access.mjs +91 -0
  429. package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
  430. package/src/session-runtime/services/usage-dashboard.mjs +27 -69
  431. package/src/session-runtime/session-create/session-options.mjs +34 -7
  432. package/src/session-runtime/session-hooks.mjs +16 -8
  433. package/src/session-runtime/setup-tool/executor.mjs +68 -6
  434. package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
  435. package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
  436. package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
  437. package/src/session-runtime/skills-api.mjs +16 -1
  438. package/src/session-runtime/tool-policy-refresh.mjs +238 -29
  439. package/src/session-runtime/turn/session-ops.mjs +10 -3
  440. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +11 -2
  441. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
  442. package/src/session-runtime/usage-stats-api.mjs +6 -1
  443. package/src/session-runtime/webhook-session-run.mjs +49 -67
  444. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
  445. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
  446. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
  447. package/src/session-runtime/workflow-agents-api.mjs +4 -1
  448. package/src/standalone/channel-transport/http-routes.mjs +10 -9
  449. package/src/standalone/daemon-agent-control.mjs +1 -8
  450. package/src/standalone/daemon-desktop-runtime.mjs +20 -7
  451. package/src/standalone/daemon-owner.mjs +117 -25
  452. package/src/standalone/daemon-session-control.mjs +11 -2
  453. package/src/standalone/daemon.mjs +61 -17
  454. package/src/standalone/session-call-cache.mjs +6 -0
  455. package/src/standalone/session-protocol.mjs +28 -1
  456. package/src/standalone/session-service/retention/busy.mjs +7 -2
  457. package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
  458. package/src/standalone/session-service.mjs +19 -0
  459. package/src/standalone/session-transport/routes.mjs +7 -6
  460. package/src/tui/app/model-options.mjs +39 -2
  461. package/src/tui/app/model-picker.mjs +16 -2
  462. package/src/tui/app/provider-setup-picker.mjs +1 -2
  463. package/src/tui/app/slash-commands.mjs +20 -0
  464. package/src/tui/dist/index.mjs +487 -128
  465. package/src/tui/session/context-state.mjs +6 -1
  466. package/src/tui/session/notice-surface.mjs +35 -4
  467. package/src/tui/session/notice-text.mjs +0 -1
  468. package/src/tui/session/queue-helpers.mjs +2 -1
  469. package/src/tui/session/session-api/extensions.mjs +4 -0
  470. package/src/tui/session/session-api/intake/submission.mjs +12 -13
  471. package/src/tui/session/session-api/integrations.mjs +9 -5
  472. package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
  473. package/src/tui/session/session-api/lifecycle.mjs +17 -1
  474. package/src/tui/session/session-api/routes.mjs +48 -3
  475. package/src/tui/session/session-flow/drain.mjs +20 -3
  476. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
  477. package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
  478. package/src/tui/session/session-flow/steering.mjs +104 -24
  479. package/src/tui/session/session-flow.mjs +2 -0
  480. package/src/tui/session/tool-approval.mjs +26 -5
  481. package/src/tui/session/transcript-intake.mjs +6 -2
  482. package/src/tui/session/transcript-spill.mjs +5 -1
  483. package/src/tui/session/tui-steering-persist.mjs +65 -42
  484. package/src/tui/session/turn-live-call.mjs +56 -0
  485. package/src/tui/session/turn-stream.mjs +33 -0
  486. package/src/tui/session/turn.mjs +50 -7
  487. package/src/ui/statusline.mjs +1 -6
  488. package/src/ui/streaming-markdown-heal.mjs +24 -7
  489. package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
  490. package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
  491. package/src/workflows/default/WORKFLOW.md +9 -13
  492. package/src/session-runtime/automation-agents.mjs +0 -94
  493. package/src/session-runtime/automation-workflow.mjs +0 -59
@@ -23,6 +23,7 @@ const POWERSHELL_RESERVED_HEADS = new Set([
23
23
  'dir',
24
24
  'echo',
25
25
  'erase',
26
+ 'fc',
26
27
  'foreach',
27
28
  'help',
28
29
  'history',
@@ -110,12 +111,19 @@ function _disabledByEnv(env) {
110
111
 
111
112
  // Quote-aware argv split for native CreateProcess. Unlike shellTokenize this
112
113
  // keeps Windows backslashes literal so `C:\foo\bar.exe` is one path token.
113
- export function tokenizeDirectArgv(command) {
114
+ // `strict` is for callers that must reproduce PowerShell's own parse (the
115
+ // direct spawn): a form where PowerShell and this splitter could disagree —
116
+ // a `\"` that PowerShell does not treat as an escape, or text glued to the
117
+ // closing quote of a string that opened its argument (PowerShell starts a new
118
+ // argument there) — returns null so the command runs through the shell
119
+ // unchanged.
120
+ export function tokenizeDirectArgv(command, { strict = false } = {}) {
114
121
  const text = String(command || '');
115
122
  const tokens = [];
116
123
  let current = '';
117
124
  let quote = null;
118
125
  let started = false;
126
+ let leading = false;
119
127
  const push = () => {
120
128
  if (started) tokens.push(current);
121
129
  current = '';
@@ -125,12 +133,20 @@ export function tokenizeDirectArgv(command) {
125
133
  const ch = text[i];
126
134
  if (quote === '"') {
127
135
  if (ch === '\\' && text[i + 1] === '"') {
136
+ if (strict) return null;
128
137
  current += '"';
129
138
  i += 1;
130
139
  continue;
131
140
  }
132
141
  if (ch === '"') {
142
+ // PowerShell: a doubled quote inside a double-quoted string is a literal quote.
143
+ if (text[i + 1] === '"') {
144
+ current += '"';
145
+ i += 1;
146
+ continue;
147
+ }
133
148
  quote = null;
149
+ if (strict && leading && i + 1 < text.length && !/\s/.test(text[i + 1])) return null;
134
150
  continue;
135
151
  }
136
152
  current += ch;
@@ -138,13 +154,24 @@ export function tokenizeDirectArgv(command) {
138
154
  }
139
155
  if (quote === "'") {
140
156
  if (ch === "'") {
157
+ // PowerShell: a doubled quote inside a single-quoted string is a literal quote.
158
+ if (text[i + 1] === "'") {
159
+ current += "'";
160
+ i += 1;
161
+ continue;
162
+ }
141
163
  quote = null;
164
+ if (strict && leading && i + 1 < text.length && !/\s/.test(text[i + 1])) return null;
142
165
  continue;
143
166
  }
144
167
  current += ch;
145
168
  continue;
146
169
  }
147
170
  if (ch === "'" || ch === '"') {
171
+ // A string that opens an argument ends it: PowerShell starts a NEW
172
+ // argument at whatever is glued behind the closing quote. A string
173
+ // opened mid-argument (`a"b c"d`) joins its neighbours.
174
+ leading = !started;
148
175
  quote = ch;
149
176
  started = true;
150
177
  continue;
@@ -185,6 +212,9 @@ export function commandNeedsShell(command) {
185
212
  continue;
186
213
  }
187
214
  if ('|&;<>()\n\r{}'.includes(ch) || ch === '`') return true;
215
+ // A bare `~` expands to the home directory and `@name` splats, both before
216
+ // the native program sees the argument.
217
+ if ((ch === '~' || ch === '@') && (i === 0 || /\s/.test(text[i - 1]))) return true;
188
218
  if ('*?[]'.includes(ch)) return true;
189
219
  if (ch === '$') return true;
190
220
  if (ch === '#' && (i === 0 || /\s/.test(text[i - 1]))) return true;
@@ -192,6 +222,14 @@ export function commandNeedsShell(command) {
192
222
  return quote != null;
193
223
  }
194
224
 
225
+ function _isFile(file) {
226
+ try {
227
+ return statSync(file).isFile();
228
+ } catch {
229
+ return false;
230
+ }
231
+ }
232
+
195
233
  function _isUsableExe(file) {
196
234
  try {
197
235
  if (!/\.exe$/i.test(file)) return false;
@@ -215,17 +253,29 @@ export function resolveDirectExe(
215
253
  const resolved = isAbsolute(name) || /^[A-Za-z]:[\\/]/.test(name) ? name : pathResolve(baseCwd, name);
216
254
  return _isUsableExe(resolved) ? resolved : null;
217
255
  }
218
- const fileName = /\.exe$/i.test(name) ? name : `${name}.exe`;
256
+ const explicitExe = /\.exe$/i.test(name);
219
257
  const seen = new Set();
220
- const dirs = [baseCwd, ...String(pathValue || '').split(pathDelimiter)];
221
- for (const dir of dirs) {
258
+ // PowerShell never looks in the current directory for a bare command name,
259
+ // so neither may this resolver: a project-local `tool.exe` is not `tool`.
260
+ for (const dir of String(pathValue || '').split(pathDelimiter)) {
222
261
  if (!dir) continue;
223
262
  const key = dir.toLowerCase();
224
263
  if (seen.has(key)) continue;
225
264
  seen.add(key);
226
- if (seen.size > maxDirectories + 1) break;
227
- const candidate = pathJoin(dir, fileName);
265
+ if (seen.size > maxDirectories) break;
266
+ if (explicitExe) {
267
+ const candidate = pathJoin(dir, name);
268
+ if (_isUsableExe(candidate)) return candidate;
269
+ continue;
270
+ }
271
+ // PowerShell takes the first directory holding ANY runnable form of the
272
+ // name, and a `.com`/`.ps1` there outranks the `.exe` while a `.cmd`/`.bat`
273
+ // shim in an earlier directory shadows a later `.exe`: all stay with the shell.
274
+ const has = (ext) => _isFile(pathJoin(dir, `${name}${ext}`));
275
+ if (has('.com') || has('.ps1')) return null;
276
+ const candidate = pathJoin(dir, `${name}.exe`);
228
277
  if (_isUsableExe(candidate)) return candidate;
278
+ if (has('.bat') || has('.cmd')) return null;
229
279
  }
230
280
  return null;
231
281
  }
@@ -244,7 +294,7 @@ export function planDirectExeSpawn(
244
294
  if (_disabledByEnv(env)) return null;
245
295
  const text = String(command || '').trim();
246
296
  if (!text || commandNeedsShell(text) || hasPowerShellOnlySyntax(text)) return null;
247
- const tokens = tokenizeDirectArgv(text);
297
+ const tokens = tokenizeDirectArgv(text, { strict: true });
248
298
  if (!tokens || tokens.length === 0) return null;
249
299
  if (tokens.includes('--%')) return null;
250
300
  const head = tokens[0];
@@ -8,7 +8,7 @@ import {
8
8
  // eval), so the static cycle through session/manager.mjs is safe — same
9
9
  // pattern as loop/tool-exec.mjs.
10
10
  import { enqueuePendingMessage, markCompletionEntry } from '../../session/manager.mjs';
11
- import { completeBackgroundTask } from '../../../../shared/background-tasks.mjs';
11
+ import { completeBackgroundTask, getBackgroundTask } from '../../../../shared/background-tasks.mjs';
12
12
  import {
13
13
  cancelNativeTask,
14
14
  getNativeTask,
@@ -28,36 +28,54 @@ import {
28
28
  adoptShellWorkspaceAdmission,
29
29
  clearTerminationHold,
30
30
  completeShellJobRecord,
31
+ isShellOwnerSessionClosed,
31
32
  listShellJobRecords,
32
33
  markShellJobTerminationUnconfirmed,
34
+ noteShellJobSurvivors,
33
35
  publishShellJobRecord,
34
36
  registerTerminationHold,
35
37
  retireShellJobRecord,
36
38
  takeReleaseRequest,
37
39
  } from './lib/shell-job-records.mjs';
38
- import { createProcessTreeTracker, killAfterSnapshot, watchTermination } from '../lib/shell-descendants.mjs';
40
+ import {
41
+ createProcessTreeTracker,
42
+ killAfterSnapshot,
43
+ PROCESS_TABLE_READ_BOUND_MS,
44
+ watchTermination,
45
+ withinBound,
46
+ } from '../lib/shell-descendants.mjs';
39
47
  import {
40
48
  flushPendingOwnerCancels,
49
+ prepareOwnedShellTreeKills,
41
50
  registerOwnedShellTree,
42
51
  unregisterOwnedShellTree,
43
52
  } from '../lib/owned-shell-trees.mjs';
44
53
 
45
- // Pre-kill snapshot of a tracked background job: the promotion baseline, or a
46
- // fresh read when that did not complete. Marks the job killed, so its settle
47
- // relies on this snapshot instead of an after-exit observation.
54
+ // Bound on how long a runtime/session shutdown waits for the sweep of what a
55
+ // cancelled job started outside its process group.
56
+ const SHUTDOWN_TREE_CONFIRM_MS = 3_000;
57
+ // Lead of the pre-deadline snapshot over a native timeout kill: one table
58
+ // read's bound plus margin.
59
+ const PRE_DEADLINE_CAPTURE_MS = PROCESS_TABLE_READ_BOUND_MS + 1_000;
60
+
61
+ // Pre-kill snapshot of a tracked background job: always a fresh read, since
62
+ // the promotion baseline predates whatever the job started since (a server,
63
+ // an npm child); the baseline still stands when the fresh read fails. Marks
64
+ // the job killed, so its settle relies on this snapshot instead of an
65
+ // after-exit observation.
48
66
  function prepareTrackedKill(entry) {
49
67
  entry.killed = true;
50
- if (entry.tracker.complete) return true;
51
- return (entry.baseline || Promise.resolve(false)).then(
52
- (complete) => complete || entry.tracker.capture().catch(() => false)
68
+ return (entry.baseline || Promise.resolve(false)).then(() =>
69
+ entry.tracker.capture().catch(() => entry.tracker.complete)
53
70
  );
54
71
  }
55
72
  import { isPidAlive } from '../../../../shared/pid-liveness.mjs';
56
73
  import {
57
74
  renderShellCompletionEnvelope,
58
- renderShellCompletionNotice,
59
75
  shellCompletionInstruction,
60
76
  } from '../../../../shared/task-notification-envelope.mjs';
77
+ import { formatDuration } from '../../../../shared/shell-output-summary.mjs';
78
+ import { readShellTaskOutput } from './lib/shell-task-output.mjs';
61
79
 
62
80
  export { shellJobPublicTaskResult } from './lib/shell-job-insights.mjs';
63
81
 
@@ -105,7 +123,17 @@ function trackShellJobRecord(task, options) {
105
123
  adoptShellWorkspaceAdmission(jobId, hold);
106
124
  }
107
125
  const tracker = task?.cwd ? createProcessTreeTracker({ pid: task.pid }) : null;
108
- const entry = { tracker, killed: false, baseline: null };
126
+ let resolveTerminated = null;
127
+ const entry = {
128
+ tracker,
129
+ killed: false,
130
+ baseline: null,
131
+ // Settles once every process of the job is confirmed gone (or the user
132
+ // force-released it): what `task cancel` waits on before it reports.
133
+ terminated: new Promise((resolve) => {
134
+ resolveTerminated = resolve;
135
+ }),
136
+ };
109
137
  if (tracker) {
110
138
  backgroundTrackers.set(jobId, entry);
111
139
  // Baseline identities while the promoted root is known to run, so a later
@@ -117,9 +145,24 @@ function trackShellJobRecord(task, options) {
117
145
  }
118
146
  let unsubscribe = null;
119
147
  let settled = false;
148
+ // The native runner enforces the job's deadline itself, with no snapshot
149
+ // from here: one is taken shortly before it, so the timeout kill has the
150
+ // identities of what the job started since its promotion.
151
+ const deadlineMs = Math.floor(Number(options?.timeoutMs) || 0);
152
+ const deadlineCapture =
153
+ tracker && deadlineMs > 0
154
+ ? setTimeout(
155
+ () => {
156
+ if (!settled) void tracker.capture().catch(() => false);
157
+ },
158
+ Math.max(0, deadlineMs - PRE_DEADLINE_CAPTURE_MS)
159
+ )
160
+ : null;
161
+ deadlineCapture?.unref?.();
120
162
  const settle = (detail) => {
121
163
  if (settled || !detail || detail.status === 'running') return;
122
164
  settled = true;
165
+ clearTimeout(deadlineCapture);
123
166
  try {
124
167
  unsubscribe?.();
125
168
  } catch {}
@@ -144,12 +187,17 @@ function trackShellJobRecord(task, options) {
144
187
  stop();
145
188
  clearTerminationHold(jobId);
146
189
  if (backgroundTrackers.get(jobId) === entry) backgroundTrackers.delete(jobId);
190
+ resolveTerminated(true);
147
191
  return completeShellJobRecord(jobId, normalized);
148
192
  };
149
193
  const stop = watchTermination({
150
194
  tracker,
195
+ // A killed job is not over while processes it started still run.
196
+ sweep: killed,
151
197
  onTerminated: finish,
152
198
  releaseRequested: () => takeReleaseRequest(jobId),
199
+ ownerClosed: () => isShellOwnerSessionClosed(options?.ownerSessionId),
200
+ onSurvivors: (pids) => void noteShellJobSurvivors(jobId, pids),
153
201
  onUnconfirmed: () => {
154
202
  void markShellJobTerminationUnconfirmed(jobId);
155
203
  registerTerminationHold(jobId, {
@@ -226,7 +274,18 @@ function shellJobFailureCause(detail) {
226
274
  return `exited with code ${exitCode}`;
227
275
  }
228
276
 
229
- export function buildShellCompletion(jobId, detail) {
277
+ function completionStreams(detail) {
278
+ return {
279
+ stdout_path: detail?.stdoutPath || null,
280
+ stderr_path: detail?.mergeStderr === true ? null : detail?.stderrPath || null,
281
+ stdout_preview: detail?.stdoutPreview || '',
282
+ stderr_preview: detail?.mergeStderr === true ? '' : detail?.stderrPreview || '',
283
+ };
284
+ }
285
+
286
+ /** `output`: the unseen output to deliver (the task cursor's remainder). By
287
+ * default the whole capture is read with a fresh cursor, consuming nothing. */
288
+ export function buildShellCompletion(jobId, detail, { output } = {}) {
230
289
  const exitCode = typeof detail?.exitCode === 'number' ? detail.exitCode : null;
231
290
  const status = detail?.status || 'unknown';
232
291
  const taskStatus = shellJobTaskStatus(detail);
@@ -234,29 +293,36 @@ export function buildShellCompletion(jobId, detail) {
234
293
  // native task has no `error` of its own.
235
294
  const failureCause = taskStatus === 'failed' ? shellJobFailureCause(detail) : null;
236
295
  const reported = failureCause && !detail?.error ? { ...detail, error: failureCause } : detail;
296
+ const startedMs = Date.parse(detail?.startedAt || '');
297
+ const finishedMs = Date.parse(detail?.finishedAt || '');
298
+ // The completion carries the result itself — exit code, duration and the
299
+ // output (whole when short, else a summary with the log path) — so the
300
+ // agent never needs a follow-up read for it.
237
301
  const body = renderShellCompletionEnvelope({
238
302
  jobId,
239
303
  status: taskStatus,
240
304
  exitCode,
241
305
  command: detail?.command,
242
- summary: detail?.summary || failureCause || null,
243
- stdoutPreview: detail?.stdoutPreview,
244
- stderrPreview: detail?.stderrPreview,
245
- mergeStderr: detail?.mergeStderr,
246
306
  outputFile: detail?.stdoutPath,
247
307
  error: failureCause,
308
+ result: [
309
+ [
310
+ exitCode !== null ? `exit code: ${exitCode}` : null,
311
+ Number.isFinite(startedMs) && Number.isFinite(finishedMs)
312
+ ? `duration: ${formatDuration(finishedMs - startedMs)}`
313
+ : null,
314
+ ]
315
+ .filter(Boolean)
316
+ .join(', ') || null,
317
+ output ?? readShellTaskOutput({ status: 'completed' }, completionStreams(detail), { terminal: true }),
318
+ ]
319
+ .filter(Boolean)
320
+ .join('\n'),
248
321
  });
249
322
  return {
250
323
  taskStatus,
251
324
  body,
252
- notification: renderShellCompletionNotice({
253
- jobId,
254
- status: taskStatus,
255
- exitCode,
256
- command: detail?.command,
257
- outputFile: detail?.stdoutPath,
258
- error: failureCause,
259
- }),
325
+ notification: body,
260
326
  instruction: shellCompletionInstruction({ jobId, status, exitCode }),
261
327
  result: shellJobPublicTaskResult(reported),
262
328
  error: failureCause,
@@ -343,6 +409,15 @@ export function killShellJob(jobId) {
343
409
  return { ...attachJobInsights(normalizeShellJobDetail(detail)), killed: wasRunning };
344
410
  }
345
411
 
412
+ /** True once every process of a tracked background job is confirmed gone,
413
+ * false while any is still alive when `timeoutMs` passes. A job without a
414
+ * process tracker (or one already finished) has nothing left to confirm. */
415
+ export async function waitShellJobTerminated(jobId, timeoutMs) {
416
+ const entry = backgroundTrackers.get(String(jobId || ''));
417
+ if (!entry) return true;
418
+ return withinBound(entry.terminated, timeoutMs, false);
419
+ }
420
+
346
421
  export function clearShellJobNotifyCtx(jobId) {
347
422
  jobNotifyCtxByJobId.delete(jobId);
348
423
  }
@@ -383,7 +458,14 @@ export function watchBackgroundShellJob(jobId, notifyCtx) {
383
458
  backgroundShellJobWatchers.delete(jobId);
384
459
  jobNotifyCtxByJobId.delete(jobId);
385
460
  const enriched = attachJobInsights(normalizeShellJobDetail(detail));
386
- const completion = buildShellCompletion(jobId, enriched);
461
+ // The notice carries only what the agent has not seen yet: the task's
462
+ // cursor remainder. Kept on the task so a wait/read that reaches the
463
+ // finished task first returns that same remainder (and suppresses the
464
+ // notice) instead of an empty read.
465
+ const task = getBackgroundTask(jobId);
466
+ const output = task ? readShellTaskOutput(task, completionStreams(enriched), { terminal: true }) : undefined;
467
+ if (task) task.completionOutput = output;
468
+ const completion = buildShellCompletion(jobId, enriched, { output });
387
469
  const completedTask = completeBackgroundTask(jobId, {
388
470
  status: completion.taskStatus,
389
471
  result: completion.result,
@@ -471,7 +553,7 @@ export async function promoteForegroundShellJob({
471
553
  }
472
554
  // Added before tracking: the record's settlement removes it again.
473
555
  promotedJobIds.add(native.jobId);
474
- trackShellJobRecord(native, { ownerSessionId, clientHostPid, startedAtMs: started });
556
+ trackShellJobRecord(native, { ownerSessionId, clientHostPid, startedAtMs: started, timeoutMs });
475
557
  return native;
476
558
  }
477
559
 
@@ -593,18 +675,26 @@ export async function shutdownShellJobs(_reason = 'runtime-close', { scope = nul
593
675
  (task) => task.status === 'running' && (!scoped || String(task.ownerSessionId || '') === ownerSessionId)
594
676
  );
595
677
  let cancelledWatchers = 0;
596
- for (const task of jobs) {
597
- if (cancelBackgroundShellJobWatch(task.jobId)) cancelledWatchers += 1;
598
- try {
599
- cancelNativeTask(task.jobId);
600
- } catch {}
601
- jobNotifyCtxByJobId.delete(task.jobId);
602
- }
678
+ // Identities first, as every other kill does: once a root dies, what it
679
+ // started outside its process group is reparented and can no longer be
680
+ // found. The cancel is sent at the snapshot bound regardless.
681
+ await killAfterSnapshot(Promise.all(prepareOwnedShellTreeKills(scoped ? ownerSessionId : null)), () => {
682
+ for (const task of jobs) {
683
+ if (cancelBackgroundShellJobWatch(task.jobId)) cancelledWatchers += 1;
684
+ try {
685
+ cancelNativeTask(task.jobId);
686
+ } catch {}
687
+ jobNotifyCtxByJobId.delete(task.jobId);
688
+ }
689
+ });
603
690
  const settled = await Promise.all(jobs.map((task) => waitNativeTask(task.jobId, 1_200).catch(() => null)));
604
691
  // A process still running after the wait is not forgotten: it keeps being
605
692
  // stopped until its exit is confirmed.
606
693
  const unconfirmed = jobs.filter((_, index) => settled[index]?.status === 'running').map((task) => task.jobId);
607
694
  for (const jobId of unconfirmed) retryShutdownSurvivor(jobId, 1);
695
+ // The roots are gone; what they started outside their group is swept by
696
+ // each job's termination watch. Shutdown waits for that, bounded.
697
+ const treesGone = await Promise.all(jobs.map((task) => waitShellJobTerminated(task.jobId, SHUTDOWN_TREE_CONFIRM_MS)));
608
698
  if (scoped) {
609
699
  // The owning session is gone: nothing can query its tasks again, so
610
700
  // drop ALL of its retained state — not only the ones that happened to
@@ -624,6 +714,7 @@ export async function shutdownShellJobs(_reason = 'runtime-close', { scope = nul
624
714
  cancelledJobs: jobs.length,
625
715
  confirmedJobs: settled.filter((task) => task && task.status !== 'running').length,
626
716
  unconfirmedJobs: unconfirmed,
717
+ treeUnconfirmedJobs: jobs.filter((_, index) => !treesGone[index]).map((task) => task.jobId),
627
718
  cancelledWatchers,
628
719
  };
629
720
  }
@@ -213,6 +213,11 @@ function buildSuccessSummary(command, stdout) {
213
213
  return null;
214
214
  }
215
215
 
216
+ // A line redrawn with `\r` shows only its last non-empty frame.
217
+ function lastVisibleFrame(frames) {
218
+ return [...frames].reverse().find((frame) => frame !== '') ?? '';
219
+ }
220
+
216
221
  export function foldCarriageReturnFrames(value) {
217
222
  const text = String(value ?? '');
218
223
  if (!/\r(?!\n)/.test(text)) return null;
@@ -223,12 +228,32 @@ export function foldCarriageReturnFrames(value) {
223
228
  const frames = line.split('\r');
224
229
  if (frames.length === 1) return line;
225
230
  omitted += frames.length - 1;
226
- return [...frames].reverse().find((frame) => frame !== '') ?? '';
231
+ return lastVisibleFrame(frames);
227
232
  });
228
233
  if (!omitted) return null;
229
234
  return `${out.join('\n')}\n... [${omitted} overwritten progress frames omitted]`;
230
235
  }
231
236
 
237
+ /** The same `\r` folding for output that arrives in chunks: the line still
238
+ * open at a chunk's end keeps its state, so a progress bar redrawn across
239
+ * deliveries shows its latest frame once, while plain continuation text of
240
+ * that line is passed through as is. */
241
+ export function createCarriageReturnFolder() {
242
+ let open = '';
243
+ return function fold(chunk) {
244
+ const lines = String(chunk ?? '')
245
+ .replace(/\r\n/g, '\n')
246
+ .split('\n');
247
+ const out = lines.map((line, index) => {
248
+ const redraw = line.includes('\r');
249
+ const visible = redraw ? lastVisibleFrame((index === 0 ? open + line : line).split('\r')) : line;
250
+ if (index === lines.length - 1) open = index === 0 && !redraw ? open + line : visible;
251
+ return visible;
252
+ });
253
+ return out.join('\n');
254
+ };
255
+ }
256
+
232
257
  function hasDiagnosticHazard(value) {
233
258
  return /\b(?:errors?|warnings?|failed|failure|panic|fatal|xpass|xfailed|cancelled|todo|skipped)\b/i.test(
234
259
  String(value ?? '')
@@ -1,5 +1,6 @@
1
1
  import { countSplitLines } from './path-utils.mjs';
2
2
  import { TOOL_OUTPUT_MAX_BYTES } from './tool-output-limit.mjs';
3
+ import { DELIVERY_FULL_CHARS, fitPieces, shellTextPiece } from './lib/shell-delivery.mjs';
3
4
 
4
5
  const SHELL_OUTPUT_MAX_BYTES = TOOL_OUTPUT_MAX_BYTES;
5
6
 
@@ -7,11 +8,6 @@ export const SMART_BASH_MAX_LINES = 400;
7
8
  export const SMART_BASH_MAX_BYTES = TOOL_OUTPUT_MAX_BYTES;
8
9
  export const SMART_BASH_HEAD_LINES = 80;
9
10
  export const SMART_BASH_TAIL_LINES = 80;
10
- export const BACKGROUND_PARTIAL_OUTPUT_MAX_BYTES = 10 * 1024;
11
- const BACKGROUND_PARTIAL_OUTPUT_HEAD_BYTES = 2 * 1024;
12
-
13
- const BACKGROUND_PARTIAL_TRUNCATION_MARKER = '\n\n... [partial output truncated; head and tail shown] ...\n\n';
14
-
15
11
  function utf8Prefix(value, maxBytes) {
16
12
  const buffer = Buffer.from(String(value ?? ''), 'utf8');
17
13
  if (buffer.length <= maxBytes) return buffer.toString('utf8');
@@ -20,31 +16,20 @@ function utf8Prefix(value, maxBytes) {
20
16
  return buffer.subarray(0, end).toString('utf8');
21
17
  }
22
18
 
23
- function utf8Suffix(value, maxBytes) {
24
- const buffer = Buffer.from(String(value ?? ''), 'utf8');
25
- if (buffer.length <= maxBytes) return buffer.toString('utf8');
26
- let start = buffer.length - maxBytes;
27
- while (start < buffer.length && (buffer[start] & 0xc0) === 0x80) start += 1;
28
- return buffer.subarray(start).toString('utf8');
29
- }
30
-
19
+ // Partial output of a promoted command that has no task record, in the shared
20
+ // delivery shape (lib/shell-delivery.mjs).
31
21
  export function renderBackgroundPartialOutput(stdout, stderr) {
32
- const sections = [];
33
- const out = String(stdout ?? '');
34
- const err = String(stderr ?? '');
35
- if (out) sections.push(`[partial stdout]\n${out}`);
36
- if (err) sections.push(`[partial stderr]\n${err}`);
37
- const merged = sections.join('\n\n');
38
- if (!merged) return '';
39
- if (Buffer.byteLength(merged, 'utf8') <= BACKGROUND_PARTIAL_OUTPUT_MAX_BYTES) return merged;
40
-
41
- const markerBytes = Buffer.byteLength(BACKGROUND_PARTIAL_TRUNCATION_MARKER, 'utf8');
42
- const tailBytes = BACKGROUND_PARTIAL_OUTPUT_MAX_BYTES - BACKGROUND_PARTIAL_OUTPUT_HEAD_BYTES - markerBytes;
43
- return (
44
- utf8Prefix(merged, BACKGROUND_PARTIAL_OUTPUT_HEAD_BYTES) +
45
- BACKGROUND_PARTIAL_TRUNCATION_MARKER +
46
- utf8Suffix(merged, tailBytes)
22
+ const streams = [
23
+ ['stdout', String(stdout ?? '')],
24
+ ['stderr', String(stderr ?? '')],
25
+ ].filter(([, text]) => text);
26
+ const headings = streams.map(([label]) => `[partial ${label}]\n`);
27
+ const fixed = headings.reduce((sum, heading) => sum + heading.length, 2 * Math.max(0, streams.length - 1));
28
+ const bodies = fitPieces(
29
+ streams.map(([label, text]) => shellTextPiece(text, { label })),
30
+ DELIVERY_FULL_CHARS - fixed
47
31
  );
32
+ return streams.map((_, index) => `${headings[index]}${bodies[index]}`).join('\n\n');
48
33
  }
49
34
 
50
35
  export function smartMiddleTruncate(content) {