mixdog 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. package/README.md +8 -4
  2. package/package.json +8 -8
  3. package/scripts/native-release-status.mjs +238 -0
  4. package/scripts/verify-runtime-dependency-versions.mjs +158 -0
  5. package/src/agents/reviewer/AGENT.md +5 -7
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +9 -1
  8. package/src/defaults/skills/browser-use/SKILL.md +6 -3
  9. package/src/defaults/skills/local-provider/SKILL.md +33 -6
  10. package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
  11. package/src/defaults/skills/setup/SKILL.md +23 -1
  12. package/src/defaults/skills/setup/references/actions.md +50 -3
  13. package/src/defaults/skills/setup/references/surfaces.md +23 -3
  14. package/src/defaults/skills/setup-guide/SKILL.md +7 -3
  15. package/src/defaults/skills/visualize/SKILL.md +9 -6
  16. package/src/defaults/skills/visualize/references/craft.md +8 -1
  17. package/src/help.mjs +1 -1
  18. package/src/lib/keychain-cjs.cjs +4 -1
  19. package/src/lib/rules-builder.cjs +14 -7
  20. package/src/rules/agent-mode/AGENT_MODE.md +8 -5
  21. package/src/rules/agent-mode/MIXY.md +6 -8
  22. package/src/rules/lead/LEAD.md +7 -10
  23. package/src/rules/shared/10-tool-workflow.md +4 -0
  24. package/src/rules/shared/20-research.md +2 -0
  25. package/src/rules/shared/45-destructive.md +5 -1
  26. package/src/rules/shared/60-verification.md +6 -4
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
  29. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
  30. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
  31. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
  32. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
  33. package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
  34. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
  35. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  36. package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
  37. package/src/runtime/agent/orchestrator/config.mjs +11 -0
  38. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
  39. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
  40. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
  41. package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +84 -32
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
  45. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
  46. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +84 -42
  48. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
  49. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
  50. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
  51. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
  52. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
  54. package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
  55. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
  56. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
  57. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
  59. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
  60. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
  61. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
  62. package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
  64. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
  65. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
  66. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
  67. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
  68. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
  69. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
  70. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
  72. package/src/runtime/agent/orchestrator/providers/registry.mjs +19 -0
  73. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
  74. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
  75. package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
  76. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
  78. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
  79. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
  81. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
  82. package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
  83. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +52 -6
  85. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +35 -13
  86. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
  87. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +8 -3
  90. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
  92. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
  93. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
  94. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -2
  95. package/src/runtime/agent/orchestrator/session/agent-room.mjs +196 -45
  96. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
  97. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  98. package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
  99. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +45 -19
  100. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
  101. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
  102. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +185 -37
  103. package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +6 -2
  107. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +4 -1
  108. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  109. package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
  110. package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +240 -0
  111. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +102 -35
  112. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
  113. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +19 -9
  114. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
  115. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
  116. package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
  117. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
  118. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +199 -109
  119. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
  120. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
  121. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
  123. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
  124. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
  125. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
  126. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -0
  127. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
  128. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +33 -8
  129. package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
  130. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +27 -0
  131. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
  132. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
  133. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
  134. package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
  135. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
  136. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
  137. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
  138. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +27 -14
  139. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +14 -0
  140. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
  143. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
  144. package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +115 -0
  145. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
  146. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
  147. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
  148. package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
  149. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
  150. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
  151. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
  155. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
  156. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +4 -9
  157. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +14 -1
  158. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
  160. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
  161. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +52 -11
  163. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +126 -12
  166. package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
  167. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +16 -3
  168. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
  169. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
  170. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
  171. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
  172. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
  173. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
  174. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +15 -5
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +49 -1
  178. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +80 -1
  179. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
  180. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
  181. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
  182. package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
  183. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
  184. package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
  185. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
  186. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
  189. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
  190. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +47 -14
  191. package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +6 -3
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
  196. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
  199. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +10 -12
  200. package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
  201. package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
  202. package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
  203. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
  204. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
  205. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +42 -23
  206. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
  207. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
  208. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
  209. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
  210. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
  211. package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
  212. package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
  213. package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
  214. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
  215. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
  216. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
  217. package/src/runtime/attachments/attachment-reference.mjs +155 -0
  218. package/src/runtime/attachments/legacy-office.mjs +110 -0
  219. package/src/runtime/attachments/limits.mjs +5 -1
  220. package/src/runtime/attachments/office-extract.mjs +3 -6
  221. package/src/runtime/attachments/pdf-extract.mjs +84 -10
  222. package/src/runtime/attachments/prompt-restore.mjs +70 -0
  223. package/src/runtime/attachments/store.mjs +109 -33
  224. package/src/runtime/browser-bridge/client.mjs +73 -20
  225. package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
  226. package/src/runtime/channels/lib/scheduler.mjs +14 -7
  227. package/src/runtime/channels/lib/state-file.mjs +15 -15
  228. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
  229. package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
  230. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
  231. package/src/runtime/channels/lib/worker-main.mjs +3 -2
  232. package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
  233. package/src/runtime/effort-judge/judge-client.mjs +66 -16
  234. package/src/runtime/effort-judge/model-install.mjs +47 -7
  235. package/src/runtime/local-provider/asset-installer.mjs +10 -4
  236. package/src/runtime/local-provider/catalog.mjs +5 -2
  237. package/src/runtime/local-provider/registered-models.mjs +64 -27
  238. package/src/runtime/local-provider/server.mjs +2 -3
  239. package/src/runtime/media/adapters/image-api.mjs +89 -0
  240. package/src/runtime/media/auth.mjs +64 -1
  241. package/src/runtime/media/catalog.mjs +66 -4
  242. package/src/runtime/media/jobs.mjs +4 -0
  243. package/src/runtime/media/lanes.mjs +46 -5
  244. package/src/runtime/media/media-usage.mjs +17 -0
  245. package/src/runtime/media/renditions.mjs +15 -15
  246. package/src/runtime/media/store.mjs +36 -35
  247. package/src/runtime/media/tool.mjs +8 -1
  248. package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
  249. package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
  250. package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
  251. package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
  252. package/src/runtime/memory/lib/pg/process.mjs +8 -4
  253. package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
  254. package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
  255. package/src/runtime/office/core/journal.mjs +7 -14
  256. package/src/runtime/office/design/library/design-library-core.mjs +4 -16
  257. package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
  258. package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
  259. package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
  260. package/src/runtime/office/pdf/pdf-render.mjs +30 -18
  261. package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
  262. package/src/runtime/office/portable/portable-soffice.mjs +135 -29
  263. package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
  264. package/src/runtime/shared/agent-avatar.mjs +3 -2
  265. package/src/runtime/shared/agent-kind-migration.mjs +200 -0
  266. package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
  267. package/src/runtime/shared/agent-message-envelope.mjs +44 -0
  268. package/src/runtime/shared/agent-reap-state.d.mts +4 -0
  269. package/src/runtime/shared/agent-room-host.d.mts +31 -0
  270. package/src/runtime/shared/agent-room-host.mjs +58 -0
  271. package/src/runtime/shared/agent-store.mjs +24 -7
  272. package/src/runtime/shared/agent-task-starts.mjs +27 -0
  273. package/src/runtime/shared/atomic-file.d.mts +50 -0
  274. package/src/runtime/shared/atomic-file.mjs +394 -132
  275. package/src/runtime/shared/background-tasks.mjs +7 -4
  276. package/src/runtime/shared/bot-hops.mjs +35 -0
  277. package/src/runtime/shared/bot-split-migration.mjs +1 -1
  278. package/src/runtime/shared/bounded-download.mjs +4 -2
  279. package/src/runtime/shared/config.mjs +39 -9
  280. package/src/runtime/shared/defaults-separation.mjs +6 -2
  281. package/src/runtime/shared/delegated-approval-host.mjs +74 -0
  282. package/src/runtime/shared/err-text.mjs +4 -0
  283. package/src/runtime/shared/error-presentation.mjs +22 -4
  284. package/src/runtime/shared/file-has-data.mjs +28 -0
  285. package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
  286. package/src/runtime/shared/pending-agent-work.mjs +54 -0
  287. package/src/runtime/shared/process-lifecycle.mjs +8 -12
  288. package/src/runtime/shared/projects.mjs +50 -41
  289. package/src/runtime/shared/provider-accounts.mjs +17 -12
  290. package/src/runtime/shared/redact-directories.mjs +18 -0
  291. package/src/runtime/shared/remove-directory.mjs +28 -0
  292. package/src/runtime/shared/routine-trigger.d.mts +6 -1
  293. package/src/runtime/shared/routine-trigger.mjs +14 -6
  294. package/src/runtime/shared/run-child.d.mts +3 -0
  295. package/src/runtime/shared/run-child.mjs +24 -3
  296. package/src/runtime/shared/session-baseline-store.mjs +8 -2
  297. package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
  298. package/src/runtime/shared/session-sidebar-host.mjs +16 -3
  299. package/src/runtime/shared/singleton-owner.mjs +7 -6
  300. package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
  301. package/src/runtime/shared/staged-update.mjs +4 -2
  302. package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
  303. package/src/runtime/shared/tool-execution-contract.mjs +10 -0
  304. package/src/runtime/shared/tool-work-units.mjs +12 -9
  305. package/src/runtime/shared/transcript-metadata.mjs +28 -3
  306. package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
  307. package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
  308. package/src/runtime/shared/turn-snapshot.mjs +277 -124
  309. package/src/runtime/shared/user-cwd.mjs +9 -4
  310. package/src/runtime/shared/user-data-guard.mjs +92 -61
  311. package/src/runtime/shared/utf8-cut.mjs +10 -0
  312. package/src/runtime/shared/worktrees/activity-gate.mjs +251 -61
  313. package/src/runtime/shared/worktrees/contract.mjs +11 -3
  314. package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
  315. package/src/runtime/shared/worktrees/manager.mjs +419 -52
  316. package/src/runtime/shared/worktrees/registry.mjs +29 -27
  317. package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
  318. package/src/runtime/tidy/core-install.mjs +26 -4
  319. package/src/runtime/tidy/install.mjs +91 -23
  320. package/src/runtime/tidy/process.mjs +41 -8
  321. package/src/runtime/tidy/resolve.mjs +10 -7
  322. package/src/runtime/web-search/lib/config.mjs +4 -16
  323. package/src/session-runtime/agent-home-delivery.mjs +542 -204
  324. package/src/session-runtime/agent-profile-changes.mjs +16 -0
  325. package/src/session-runtime/agent-room-delivery.mjs +81 -35
  326. package/src/session-runtime/agent-task-sessions.mjs +811 -179
  327. package/src/session-runtime/agent-tool-routing.mjs +1 -0
  328. package/src/session-runtime/boot/apis.mjs +48 -24
  329. package/src/session-runtime/boot/config.mjs +1 -0
  330. package/src/session-runtime/boot/facade.mjs +16 -7
  331. package/src/session-runtime/boot/infrastructure.mjs +14 -2
  332. package/src/session-runtime/boot/providers.mjs +2 -2
  333. package/src/session-runtime/boot/shared.mjs +12 -6
  334. package/src/session-runtime/boot/tools.mjs +23 -3
  335. package/src/session-runtime/bot-status.mjs +432 -0
  336. package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
  337. package/src/session-runtime/config-lifecycle.mjs +60 -55
  338. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
  339. package/src/session-runtime/held-requests.mjs +31 -33
  340. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
  341. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
  342. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +24 -26
  343. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  344. package/src/session-runtime/lifecycle/teardown.mjs +11 -3
  345. package/src/session-runtime/mcp-glue/connect.mjs +100 -186
  346. package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
  347. package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
  348. package/src/session-runtime/media-api.mjs +5 -2
  349. package/src/session-runtime/model-recency.mjs +1 -0
  350. package/src/session-runtime/model-route/route-tuning.mjs +4 -1
  351. package/src/session-runtime/model-route/set-route.mjs +61 -1
  352. package/src/session-runtime/owned-automation-run.mjs +8 -1
  353. package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
  354. package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
  355. package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
  356. package/src/session-runtime/route-resolution.mjs +16 -8
  357. package/src/session-runtime/route-state.mjs +1 -59
  358. package/src/session-runtime/routine-home-turn.mjs +5 -3
  359. package/src/session-runtime/runtime-bootstrap.mjs +5 -3
  360. package/src/session-runtime/runtime-paths.mjs +11 -5
  361. package/src/session-runtime/runtime-review-api.mjs +4 -1
  362. package/src/session-runtime/runtime-tunables.mjs +6 -0
  363. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
  364. package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
  365. package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
  366. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
  367. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +34 -19
  368. package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
  369. package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
  370. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +7 -0
  371. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
  372. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
  373. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
  374. package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
  375. package/src/session-runtime/services/agent-tool.mjs +6 -0
  376. package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
  377. package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
  378. package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
  379. package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
  380. package/src/session-runtime/services/plugin-admin.mjs +26 -26
  381. package/src/session-runtime/services/provider-admin.mjs +26 -6
  382. package/src/session-runtime/services/schedule-access.mjs +33 -4
  383. package/src/session-runtime/services/seeds.mjs +4 -3
  384. package/src/session-runtime/services/usage-dashboard.mjs +1 -1
  385. package/src/session-runtime/services/usage-stats-model.mjs +2 -1
  386. package/src/session-runtime/services/worktree-access.mjs +27 -0
  387. package/src/session-runtime/session-create/materialize.mjs +2 -3
  388. package/src/session-runtime/session-create/session-options.mjs +15 -2
  389. package/src/session-runtime/session-hooks.mjs +9 -17
  390. package/src/session-runtime/settings-builtin-tools-api.mjs +65 -1
  391. package/src/session-runtime/settings-compaction-api.mjs +86 -39
  392. package/src/session-runtime/setup-tool/executor.mjs +12 -2
  393. package/src/session-runtime/setup-tool/settings-contract.mjs +34 -1
  394. package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
  395. package/src/session-runtime/skills-api.mjs +12 -5
  396. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +349 -0
  397. package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
  398. package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
  399. package/src/session-runtime/tool-policy/policy-stage.mjs +183 -0
  400. package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
  401. package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
  402. package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
  403. package/src/session-runtime/tool-policy-refresh.mjs +48 -369
  404. package/src/session-runtime/tool-surface.mjs +10 -4
  405. package/src/session-runtime/turn/session-ops.mjs +8 -0
  406. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
  407. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  408. package/src/session-runtime/turn/turn-run.mjs +7 -2
  409. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
  410. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +527 -333
  411. package/src/session-runtime/workflow-agents-api/agent-route.mjs +85 -63
  412. package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
  413. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
  414. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
  415. package/src/session-runtime/workspace/transition-steps.mjs +1 -18
  416. package/src/session-runtime/workspace/transitions.mjs +279 -67
  417. package/src/session-runtime/workspace/workspace-state.mjs +7 -6
  418. package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
  419. package/src/standalone/daemon-agent-control.mjs +4 -1
  420. package/src/standalone/daemon-lag-profiler.mjs +3 -1
  421. package/src/standalone/daemon-session-control.mjs +173 -15
  422. package/src/standalone/daemon-telemetry.mjs +9 -0
  423. package/src/standalone/daemon.mjs +33 -10
  424. package/src/standalone/local-session-runtime.mjs +33 -16
  425. package/src/standalone/session-client.mjs +7 -2
  426. package/src/standalone/session-protocol.mjs +8 -0
  427. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
  428. package/src/standalone/session-service/agent-route-follow.mjs +69 -0
  429. package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
  430. package/src/standalone/session-service.mjs +21 -0
  431. package/src/standalone/session-state-projection.mjs +19 -9
  432. package/src/standalone/session-tool-output.mjs +36 -9
  433. package/src/standalone/staged-import.mjs +47 -0
  434. package/src/tui/App.jsx +2 -0
  435. package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
  436. package/src/tui/app/message-selector.mjs +15 -2
  437. package/src/tui/app/model-options.mjs +16 -2
  438. package/src/tui/app/model-picker.mjs +2 -1
  439. package/src/tui/app/route-pickers.mjs +3 -1
  440. package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
  441. package/src/tui/app/slash-commands.mjs +1 -1
  442. package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
  443. package/src/tui/dist/index.mjs +617 -369
  444. package/src/tui/paste-attachments.mjs +0 -1
  445. package/src/tui/paste-text-policy.mjs +4 -5
  446. package/src/tui/prompt-history-store.mjs +16 -21
  447. package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
  448. package/src/tui/session/context-state.mjs +4 -0
  449. package/src/tui/session/notice-surface.mjs +3 -0
  450. package/src/tui/session/session-api/intake/abort.mjs +52 -18
  451. package/src/tui/session/session-api/intake/rewind.mjs +39 -4
  452. package/src/tui/session/session-api/media.mjs +2 -1
  453. package/src/tui/session/session-api/routes-agent-definitions.mjs +76 -0
  454. package/src/tui/session/session-api/routes-write.mjs +203 -0
  455. package/src/tui/session/session-api/routes.mjs +23 -247
  456. package/src/tui/session/session-api/settings.mjs +14 -1
  457. package/src/tui/session/session-flow/drain.mjs +28 -3
  458. package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
  459. package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
  460. package/src/tui/session/session-flow/steering.mjs +8 -3
  461. package/src/tui/session/tool-approval.mjs +142 -14
  462. package/src/tui/session/transcript-intake.mjs +2 -0
  463. package/src/tui/session/turn.mjs +23 -14
  464. package/src/tui/transcript-tool-failures.mjs +8 -2
  465. package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
  466. package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
  467. package/src/rules/agent-mode/ROUTINE.md +0 -6
  468. package/src/session-runtime/room-member-gate.mjs +0 -48
@@ -148,12 +148,12 @@ function request({
148
148
  }
149
149
  );
150
150
  req.on('timeout', () => {
151
- req.destroy(new Error(`session timeout: ${method} ${urlPath}`));
151
+ req.destroy(sessionTimeoutError(method, urlPath));
152
152
  });
153
153
  req.on('error', reject);
154
154
  if (deadlineMs > 0) {
155
155
  deadlineTimer = setTimeout(() => {
156
- const error = new Error(`session timeout: ${method} ${urlPath}`);
156
+ const error = sessionTimeoutError(method, urlPath);
157
157
  reject(error);
158
158
  req.destroy(error);
159
159
  }, deadlineMs);
@@ -163,6 +163,11 @@ function request({
163
163
  });
164
164
  }
165
165
 
166
+ /** No answer within the request's bound: the daemon may be busy with it, not gone. */
167
+ function sessionTimeoutError(method, urlPath) {
168
+ return Object.assign(new Error(`session timeout: ${method} ${urlPath}`), { code: 'ESESSIONTIMEOUT' });
169
+ }
170
+
166
171
  /** /health within `timeoutMs` of total duration; null when it does not answer. */
167
172
  export async function probeSessionHealth({ port, token, timeoutMs = 800 } = {}) {
168
173
  try {
@@ -15,12 +15,14 @@ export const SESSION_READ_ACTIONS = Object.freeze([
15
15
  'getAgentAvatarImage',
16
16
  'getAgentConnectors',
17
17
  'getProjectConnectors',
18
+ 'getAgentAlwaysAllowedTools',
18
19
  'getAgentPermissions',
19
20
  'listConnectors',
20
21
  'listConnectorTools',
21
22
  'getLeadPersona',
22
23
  'getLeadAgentBody',
23
24
  'getLeadStatus',
25
+ 'getLeadHomeRoute',
24
26
  'getAutoClear',
25
27
  'getChannelSettings',
26
28
  'getChannelSetup',
@@ -45,6 +47,8 @@ export const SESSION_READ_ACTIONS = Object.freeze([
45
47
  'getQuotaHistory',
46
48
  'getRecapSettings',
47
49
  'getSessionTitleSettings',
50
+ 'getLeadAppearance',
51
+ 'getBotOrder',
48
52
  'getWebSearchRoute',
49
53
  'getSettingsSnapshot',
50
54
  'getSystemShell',
@@ -188,6 +192,7 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
188
192
  'setAgentConnectorToolPermission',
189
193
  'setProjectConnectorEnabled',
190
194
  'setAgentPermission',
195
+ 'recordAgentApprovalAudit',
191
196
  'saveLeadPersona',
192
197
  'saveLeadAgentBody',
193
198
  'setLeadCreated',
@@ -233,6 +238,8 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
233
238
  'setProgressHint',
234
239
  'setRecapEnabled',
235
240
  'setAiSessionTitles',
241
+ 'setLeadAppearance',
242
+ 'setBotOrder',
236
243
  'setRoute',
237
244
  'setScheduleEnabled',
238
245
  'setWebSearchRoute',
@@ -241,6 +248,7 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
241
248
  'setToolMode',
242
249
  'setWebSearchEnabled',
243
250
  'setInstructionFiles',
251
+ 'setAutoEffortBase',
244
252
  'setWebhookConfig',
245
253
  'setWebhookEnabled',
246
254
  'setWorkflow',
@@ -57,6 +57,8 @@ export function createInlineBootLoaders({
57
57
  if (isClosed()) return false;
58
58
  try {
59
59
  const module = await loadLocalModule();
60
+ // A loop turn between the two graph loads: one piece held the loop.
61
+ await new Promise((resolve) => setImmediate(resolve));
60
62
  if (isClosed()) return false;
61
63
  return (await module.warmLocalSessionRuntime?.()) !== false;
62
64
  } catch {
@@ -0,0 +1,69 @@
1
+ // A bot's saved model route reaches the chats it already has: its home thread
2
+ // and its group-room member sessions, from their next turn (the session route
3
+ // API's deferred pick, the one every model picker uses: a running turn finishes
4
+ // on the model it started on). The latest saved route wins. A thread no
5
+ // runtime hosts keeps its model until it is opened (the desktop refreshes it
6
+ // then, agent-home-sessions.ts).
7
+ import { subscribeAgentRouteChanges } from '../../session-runtime/agent-profile-changes.mjs';
8
+ import { agentHomeSessionId } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
9
+ import { roomMemberOfSession } from '../../runtime/agent/orchestrator/session/agent-room.mjs';
10
+
11
+ const ROUTE_KEYS = [
12
+ 'provider',
13
+ 'model',
14
+ 'effort',
15
+ 'fast',
16
+ 'autoEffort',
17
+ 'modelParameters',
18
+ 'contextPercent',
19
+ 'contextTokens',
20
+ ];
21
+
22
+ /** The pick the session route API takes for a saved route. */
23
+ function sessionRoutePick(route) {
24
+ const pick = { sessionOnly: true };
25
+ for (const key of ROUTE_KEYS) if (route?.[key] !== undefined && route[key] !== null) pick[key] = route[key];
26
+ return pick;
27
+ }
28
+
29
+ export function createAgentRouteFollow({ sessionsById, sessionOwner, advance, publishStep, log }) {
30
+ // Each chat takes its updates one at a time, in the order they were
31
+ // published: a slow chat never lets an older route land after a newer one.
32
+ const tails = new Map(); // sessionId -> Promise of its last queued update
33
+
34
+ function apply(sessionId, pick) {
35
+ const entry = sessionOwner(sessionId);
36
+ if (typeof entry?.runtime?.setRoute !== 'function') return Promise.resolve();
37
+ return Promise.resolve()
38
+ .then(async () => {
39
+ await entry.runtime.setRoute(pick);
40
+ const step = advance(entry);
41
+ if (step.changed) publishStep(entry, step);
42
+ })
43
+ .catch((error) => {
44
+ // A route the runtime refuses (provider signed out) leaves the chat on its model.
45
+ log(`agent route change not applied to ${sessionId}: ${error?.message || error}`);
46
+ });
47
+ }
48
+
49
+ function enqueue(sessionId, pick) {
50
+ const queued = (tails.get(sessionId) || Promise.resolve()).then(() => apply(sessionId, pick));
51
+ tails.set(sessionId, queued);
52
+ queued.then(() => {
53
+ if (tails.get(sessionId) === queued) tails.delete(sessionId);
54
+ });
55
+ return queued;
56
+ }
57
+
58
+ // Every matching chat is queued before the first await: publications queue in order.
59
+ function follow(agentId, route) {
60
+ const home = agentHomeSessionId(agentId);
61
+ if (!home || !route?.provider || !route?.model) return Promise.resolve();
62
+ const pick = sessionRoutePick(route);
63
+ const queued = [...sessionsById.keys()]
64
+ .filter((sessionId) => sessionId === home || roomMemberOfSession(sessionId)?.agentId === agentId)
65
+ .map((sessionId) => enqueue(sessionId, pick));
66
+ return Promise.all(queued);
67
+ }
68
+ return subscribeAgentRouteChanges(follow);
69
+ }
@@ -62,15 +62,43 @@ export function createSessionTurnCalls(ctx) {
62
62
  return step;
63
63
  };
64
64
 
65
- async function submitSession({ sessionId, prompt, options = {}, open: openHints = {}, baseRevision = null } = {}) {
65
+ // Intakes in flight per session: an abort of the session also cancels an
66
+ // attachment conversion that has not yet become a turn.
67
+ const intakeAborts = new Map();
68
+
69
+ async function submitSession({
70
+ sessionId,
71
+ prompt,
72
+ options = {},
73
+ open: openHints = {},
74
+ baseRevision = null,
75
+ signal = null,
76
+ } = {}) {
66
77
  const id = String(sessionId || '');
67
78
  if (!id) throw new TypeError('sessionId is required');
68
79
  const entry = await entryForSession(id, openHints || {});
69
80
  const target = entry.runtime.submitAsync;
70
81
  if (typeof target !== 'function') throw new TypeError('session runtime must implement submitAsync');
71
- const intake = await preparePromptSubmissionForProvider(materializePromptSubmission(prompt, options || {}), {
72
- nativePdf: providerNativePdf(entry.runtime.provider || entry.runtime.session?.provider || ''),
73
- });
82
+ const intakeAbort = new AbortController();
83
+ const forwardAbort = () => intakeAbort.abort(signal.reason);
84
+ if (signal?.aborted) forwardAbort();
85
+ else signal?.addEventListener?.('abort', forwardAbort, { once: true });
86
+ if (!intakeAborts.has(id)) intakeAborts.set(id, new Set());
87
+ intakeAborts.get(id).add(intakeAbort);
88
+ let intake;
89
+ try {
90
+ intake = await preparePromptSubmissionForProvider(
91
+ materializePromptSubmission(prompt, options || {}),
92
+ { nativePdf: providerNativePdf(entry.runtime.provider || entry.runtime.session?.provider || '') },
93
+ { signal: intakeAbort.signal }
94
+ );
95
+ } finally {
96
+ signal?.removeEventListener?.('abort', forwardAbort);
97
+ intakeAborts.get(id)?.delete(intakeAbort);
98
+ if (!intakeAborts.get(id)?.size) intakeAborts.delete(id);
99
+ }
100
+ // A cancel that landed after the last conversion step must not submit.
101
+ intakeAbort.signal.throwIfAborted();
74
102
  // Await intake only: submitAsync resolves once the prompt is represented by
75
103
  // the queue/user row, while provider execution remains daemon-owned and
76
104
  // detached.
@@ -131,6 +159,7 @@ export function createSessionTurnCalls(ctx) {
131
159
  async function abortSession({ sessionId, open: openHints = {}, options = {}, baseRevision = null } = {}) {
132
160
  const id = String(sessionId || '');
133
161
  if (!id) throw new TypeError('sessionId is required');
162
+ for (const intakeAbort of intakeAborts.get(id) ?? []) intakeAbort.abort();
134
163
  const entry = await entryForSession(id, openHints || {});
135
164
  const target = entry.runtime.abort;
136
165
  if (typeof target !== 'function') throw new TypeError('session action abort is unavailable');
@@ -23,6 +23,8 @@ import { createViewerRegistry } from './session-service/viewers.mjs';
23
23
  import { createSessionEntries } from './session-service/entries.mjs';
24
24
  import { createSessionCalls } from './session-service/session-calls.mjs';
25
25
  import { createQuotaResumeScheduler } from './session-service/quota-resume.mjs';
26
+ import { createAgentRouteFollow } from './session-service/agent-route-follow.mjs';
27
+ import { registerDelegatedApprovalOpener } from '../runtime/shared/delegated-approval-host.mjs';
26
28
 
27
29
  const EXTERNAL_SESSION_ACTIONS = new Set([
28
30
  ...SESSION_READ_ACTION_SET,
@@ -205,6 +207,17 @@ export function createSessionService({
205
207
  retainUnwatched: retention.retainUnwatched,
206
208
  createSession: calls.createSession,
207
209
  });
210
+ // A sub-agent's approval shows in its top-level chat; one not loaded is
211
+ // brought up so the copy (and its notifications) appear there.
212
+ const unregisterApprovalOpener = registerDelegatedApprovalOpener((sessionId) => calls.materializeSession(sessionId));
213
+ // A bot's saved route reaches its hosted home and room-member chats from their next turn.
214
+ const agentRouteFollow = createAgentRouteFollow({
215
+ sessionsById,
216
+ sessionOwner: projection.sessionOwner,
217
+ advance: projection.advance,
218
+ publishStep: projection.publishStep,
219
+ log,
220
+ });
208
221
  const quotaUsableReader = typeof readQuotaUsable === 'function' ? readQuotaUsable : async () => false;
209
222
  const quotaResume = quotaResumeStore
210
223
  ? createQuotaResumeScheduler({
@@ -219,6 +232,8 @@ export function createSessionService({
219
232
  function stop(reason = 'service stop') {
220
233
  if (stopPromise) return stopPromise;
221
234
  closed = true;
235
+ unregisterApprovalOpener();
236
+ agentRouteFollow.unsubscribe();
222
237
  quotaResume?.stop();
223
238
  stopPromise = Promise.resolve().then(async () => {
224
239
  try {
@@ -243,6 +258,11 @@ export function createSessionService({
243
258
  return Boolean(owner) && retention.stateBusy(owner.runtime?.getState?.());
244
259
  }
245
260
 
261
+ /** Whether the runtime hosting `sessionId` shows an approval card waiting on the user. */
262
+ function liveSessionAwaitingApproval(sessionId) {
263
+ return Boolean(projection.sessionOwner(sessionId)?.runtime?.getState?.()?.toolApproval);
264
+ }
265
+
246
266
  /** Show a transcript notice in the hosted runtime of `sessionId` (no turn)
247
267
  * and publish it to its views; false when no runtime hosts it. */
248
268
  function pushLiveSessionNotice(sessionId, { text, tone = 'info', ...options } = {}) {
@@ -300,6 +320,7 @@ export function createSessionService({
300
320
  methods: {
301
321
  ...calls,
302
322
  liveSessionBusy,
323
+ liveSessionAwaitingApproval,
303
324
  pushLiveSessionNotice,
304
325
  stop,
305
326
  startQuotaResume: () => quotaResume?.start(),
@@ -1,4 +1,6 @@
1
1
  import { sanitizeForWire } from './session-wire-values.mjs';
2
+ import { stripAgentMessageEnvelope } from '../runtime/shared/agent-message-envelope.mjs';
3
+ import { transcriptSourceFields } from '../runtime/shared/transcript-metadata.mjs';
2
4
 
3
5
  /** Immutable source fields keep their wire identity until they actually change.
4
6
  * In particular, a live tail must not rebuild the settled transcript or resend
@@ -29,15 +31,23 @@ export function projectSessionState(entry, raw) {
29
31
  }
30
32
  let cloned;
31
33
  if (key === 'queued' && Array.isArray(value)) {
32
- cloned = value.map((item) => ({
33
- id: item?.id,
34
- submittedAt: item?.submittedAt,
35
- text: String(item?.displayText ?? item?.text ?? '').slice(0, 2_000),
36
- displayText: String(item?.displayText ?? item?.text ?? '').slice(0, 2_000),
37
- mode: item?.mode || 'prompt',
38
- priority: item?.priority || 'next',
39
- ...(Array.isArray(item?.images) && item.images.length ? { images: item.images } : {}),
40
- }));
34
+ cloned = value.map((item) => {
35
+ // A queued bot message reads like its delivered row: the sender tag
36
+ // and the message without its envelope.
37
+ const source = transcriptSourceFields(item?.transcriptMeta);
38
+ const queuedText = String(item?.displayText ?? item?.text ?? '');
39
+ const text = (source.fromAgent ? stripAgentMessageEnvelope(queuedText) : queuedText).slice(0, 2_000);
40
+ return {
41
+ id: item?.id,
42
+ submittedAt: item?.submittedAt,
43
+ text,
44
+ displayText: text,
45
+ mode: item?.mode || 'prompt',
46
+ priority: item?.priority || 'next',
47
+ ...source,
48
+ ...(Array.isArray(item?.images) && item.images.length ? { images: item.images } : {}),
49
+ };
50
+ });
41
51
  } else if (key === 'items' && Array.isArray(value)) {
42
52
  const items = entry.itemCache;
43
53
  const nextItems = new Map();
@@ -1,4 +1,6 @@
1
1
  import { encodeCatalogCursor } from '../runtime/agent/orchestrator/session/catalog-db/schema.mjs';
2
+ import { UNTRUSTED_NOTE, sessionBotOf } from '../session-runtime/bot-status.mjs';
3
+ import { escapeHarnessTags } from '../runtime/shared/shell-output-summary.mjs';
2
4
  import { truncateToolText } from '../runtime/shared/tool-primitives.mjs';
3
5
  import { summarizeToolResult } from '../runtime/shared/tool-result-summary.mjs';
4
6
 
@@ -6,18 +8,43 @@ import { TOOL_OUTPUT_PAGE_BYTES, TOOL_OUTPUT_TAIL_BYTES } from '../runtime/share
6
8
 
7
9
  export const SESSION_TOOL_OUTPUT_BYTES = TOOL_OUTPUT_TAIL_BYTES;
8
10
  const MESSAGE_TEXT_LIMIT = 2000;
11
+ const LIST_PREVIEW_LIMIT = 100;
9
12
  const outputBytes = (value) => Buffer.byteLength(JSON.stringify(value), 'utf8');
10
13
 
11
- /** Keep catalog paging authoritative even when the output budget shortens a page. */
12
- export function sessionListOutput(page, limit) {
14
+ /** Keep catalog paging authoritative even when the output budget shortens a page.
15
+ * `rich` adds the owning bot, last activity, latest line and working state
16
+ * (never for a background caller: bot-status.mjs scopedBot). */
17
+ export function sessionListOutput(page, limit, { rich = true } = {}) {
13
18
  const raw = page.sessions;
14
- const sessions = raw.slice(0, limit).map((row) => ({
15
- id: row.id,
16
- ...(row.title || row.preview ? { title: truncateToolText(row.title || row.preview, 160) } : {}),
17
- ...(row.status ? { status: row.status } : {}),
18
- ...(row.cwd ? { cwd: row.cwd } : {}),
19
- }));
20
- const result = { sessions, nextCursor: page.nextCursor ?? null };
19
+ const sessions = raw.slice(0, limit).map((row) => {
20
+ const base = {
21
+ id: row.id,
22
+ ...(row.title || row.preview
23
+ ? { title: escapeHarnessTags(truncateToolText(row.title || row.preview, 160)) }
24
+ : {}),
25
+ ...(row.status ? { status: row.status } : {}),
26
+ ...(row.cwd ? { cwd: row.cwd } : {}),
27
+ ...(row.archived === true ? { archived: true } : {}),
28
+ };
29
+ if (!rich) return base;
30
+ // The bot it belongs to: its chat, room seat or the task's creator.
31
+ const bot = sessionBotOf(row);
32
+ const lastUsedAt = Number(row.lastUsedAt) || 0;
33
+ const preview = String(row.lastMessagePreview || '').replace(/\s+/g, ' ');
34
+ return {
35
+ ...base,
36
+ ...(bot ? { bot } : {}),
37
+ ...(lastUsedAt ? { lastUsedAt: new Date(lastUsedAt).toISOString() } : {}),
38
+ // The latest user or assistant line, quoted data.
39
+ ...(preview.trim() ? { preview: escapeHarnessTags(truncateToolText(preview, LIST_PREVIEW_LIMIT)) } : {}),
40
+ ...(row.working === true || row.agentWorking === true ? { working: true } : {}),
41
+ };
42
+ });
43
+ const result = {
44
+ sessions,
45
+ nextCursor: page.nextCursor ?? null,
46
+ ...(sessions.some((row) => row.preview) ? { note: UNTRUSTED_NOTE } : {}),
47
+ };
21
48
  for (;;) {
22
49
  if (sessions.length < raw.length && sessions.length) {
23
50
  result.nextCursor = encodeCatalogCursor(raw[sessions.length - 1]);
@@ -0,0 +1,47 @@
1
+ // Staged dynamic import of a large module graph. Loading a graph (file reads,
2
+ // compilation, evaluation) runs synchronously inside one import() call, so the
3
+ // daemon's session-runtime warm-up held the event loop for ~0.5 s in one
4
+ // piece right after `daemon-ready`. Importing the graph's top-level stages one
5
+ // loop turn apart splits that block without changing what is loaded.
6
+ import { readFileSync } from 'node:fs';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ // A static `import … from './x'`, `export … from './x'` or bare `import './x'`
10
+ // at the start of a line, in source order.
11
+ const STATIC_RELATIVE_IMPORT =
12
+ /^(?:import|export)\b[^;]*?\bfrom\s*['"](\.{1,2}\/[^'"]+)['"]|^import\s*['"](\.{1,2}\/[^'"]+)['"]/gm;
13
+
14
+ /** The relative static imports of the module at `url`, resolved, in source order. */
15
+ export function staticRelativeImports(url) {
16
+ const source = readFileSync(fileURLToPath(url), 'utf8');
17
+ return [...source.matchAll(STATIC_RELATIVE_IMPORT)].map((match) => new URL(match[1] || match[2], url).href);
18
+ }
19
+
20
+ const nextTurn = () => new Promise((resolve) => setImmediate(resolve));
21
+
22
+ /**
23
+ * import(url), after importing each static relative dependency of `stagesOf`
24
+ * (in its source order, one loop turn apart). Module evaluation order is the
25
+ * one a single import gives — dependencies depth-first in source order — as
26
+ * long as no module of a stage's graph imports `stagesOf` or an importer of it
27
+ * back. Staging stops at the first stage that fails, so no later stage
28
+ * evaluates; the final import then reports the failure as a single import
29
+ * would.
30
+ */
31
+ export async function importInStages(url, stagesOf) {
32
+ let stages = [];
33
+ try {
34
+ stages = staticRelativeImports(stagesOf);
35
+ } catch {
36
+ // Unreadable source: one import, as before.
37
+ }
38
+ for (const stage of stages) {
39
+ try {
40
+ await import(stage);
41
+ } catch {
42
+ break;
43
+ }
44
+ await nextTurn();
45
+ }
46
+ return import(url);
47
+ }
package/src/tui/App.jsx CHANGED
@@ -516,6 +516,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
516
516
  syncPromptLayoutRows,
517
517
  showPromptHint,
518
518
  clearPromptHint,
519
+ installPastedImages,
520
+ installPastedTexts,
519
521
  });
520
522
 
521
523
  // PROMPT HANDLER cluster extracted to app/use-prompt-handlers.mjs.
@@ -3,10 +3,14 @@
3
3
  // the Advanced list of provider default idle windows edited as text.
4
4
 
5
5
  // Lead BP4 messages cache TTL follows autoClear (cache-strategy.mjs
6
- // resolveLeadMessagesTtl): off or idle>=1h -> 1h, shorter idle -> 5m.
6
+ // resolveLeadMessagesTtl): off or idle>=1h (incl. unlimited) -> 1h, shorter
7
+ // idle -> 5m.
7
8
  const HOUR_MS = 60 * 60 * 1000;
9
+ // Typed (and shown) for "never auto-clear"; the runtime stores it as 0.
10
+ const UNLIMITED_INPUT = 'unlimited';
8
11
 
9
- const formatDurationInput = (ms) => {
12
+ const formatDurationInput = (ms, unlimited = false) => {
13
+ if (unlimited) return UNLIMITED_INPUT;
10
14
  const value = Math.max(0, Math.round(Number(ms) || 0));
11
15
  if (value > 0 && value % HOUR_MS === 0) return `${value / HOUR_MS}h`;
12
16
  if (value > 0 && value % 60_000 === 0) return `${value / 60_000}m`;
@@ -39,7 +43,7 @@ export function createAutoClearPicker({
39
43
  label: entry.provider,
40
44
  marker: entry.provider === provider ? '✓' : '',
41
45
  markerColor: theme.success,
42
- meta: `${formatDuration(entry.idleMs)}${entry.custom ? ' custom' : ''}`,
46
+ meta: `${entry.unlimited ? 'Unlimited' : formatDuration(entry.idleMs)}${entry.custom ? ' custom' : ''}`,
43
47
  description: `Default idle window for ${entry.provider}. Enter to edit as text.`,
44
48
  _action: 'provider-default',
45
49
  _entry: entry,
@@ -66,10 +70,10 @@ export function createAutoClearPicker({
66
70
  store.pushNotice('autoclear unavailable', 'warn');
67
71
  return;
68
72
  }
69
- store.pushNotice(
70
- next.enabled ? `autoclear on · idle ${formatDuration(next.idleMs)}` : 'autoclear off',
71
- 'info'
72
- );
73
+ let notice = 'autoclear off';
74
+ if (next.enabled)
75
+ notice = next.unlimited ? 'autoclear on · unlimited' : `autoclear on · idle ${formatDuration(next.idleMs)}`;
76
+ store.pushNotice(notice, 'info');
73
77
  })
74
78
  .catch((e) => store.pushNotice(`autoclear failed: ${e?.message || e}`, 'error'))
75
79
  .finally(settled);
@@ -80,8 +84,8 @@ export function createAutoClearPicker({
80
84
  setSettingsPrompt({
81
85
  kind: 'autoclear-provider',
82
86
  label: `Auto-clear · ${entry.provider}`,
83
- hint: `Type a duration like 10m, 1h, or 24h. Empty resets to built-in ${formatDurationInput(entry.builtInMs)}.`,
84
- initialValue: formatDurationInput(entry.idleMs),
87
+ hint: `Type a duration like 10m, 1h, or 24h, or ${UNLIMITED_INPUT} to never auto-clear. Empty resets to built-in ${formatDurationInput(entry.builtInMs, entry.builtInUnlimited)}.`,
88
+ initialValue: formatDurationInput(entry.idleMs, entry.unlimited),
85
89
  provider: entry.provider,
86
90
  builtInMs: entry.builtInMs,
87
91
  returnTo,
@@ -109,18 +113,20 @@ export function createAutoClearPicker({
109
113
  const current = await readCurrent();
110
114
  const enabled = current?.enabled !== false;
111
115
  const idleMs = Number(current?.idleMs || HOUR_MS);
116
+ const unlimited = current?.unlimited === true;
112
117
  const cacheTtlLabel = !enabled || idleMs >= HOUR_MS ? '1h' : '5m';
113
118
  let sourceLabel = `${current?.provider || 'default'} default`;
114
119
  if (current?.providerCustom) sourceLabel = `${current.provider} override`;
115
120
  else if (current?.custom) sourceLabel = 'global';
121
+ const clearText = unlimited
122
+ ? `Never clear idle sessions (${sourceLabel})`
123
+ : `Clear idle sessions after ${formatDuration(idleMs)} (${sourceLabel})`;
116
124
  const items = [
117
125
  {
118
126
  value: 'toggle',
119
127
  label: 'Auto-clear',
120
128
  meta: enabled ? 'On' : 'Off',
121
- description: enabled
122
- ? `Clear idle sessions after ${formatDuration(idleMs)} (${sourceLabel}) · lead cache TTL ${cacheTtlLabel}.`
123
- : 'Idle auto-clear disabled.',
129
+ description: enabled ? `${clearText} · lead cache TTL ${cacheTtlLabel}.` : 'Idle auto-clear disabled.',
124
130
  _action: 'toggle',
125
131
  },
126
132
  {
@@ -132,7 +138,7 @@ export function createAutoClearPicker({
132
138
  ];
133
139
  own.paint({
134
140
  title: 'Auto-clear',
135
- description: `Clear idle context after ${enabled ? `${formatDuration(idleMs)} (${sourceLabel})` : 'never'} · lead cache TTL ${cacheTtlLabel}.`,
141
+ description: `Clear idle context after ${enabled && !unlimited ? `${formatDuration(idleMs)} (${sourceLabel})` : 'never'} · lead cache TTL ${cacheTtlLabel}.`,
136
142
  help: '↑/↓ Select · ←/→ Toggle On/Off · Enter Open/Toggle · Esc Close',
137
143
  indexMode: 'always',
138
144
  labelWidth: 10,
@@ -45,6 +45,8 @@ export function useMessageSelector({
45
45
  syncPromptLayoutRows,
46
46
  showPromptHint,
47
47
  clearPromptHint,
48
+ installPastedImages,
49
+ installPastedTexts,
48
50
  }) {
49
51
  // Cheap enough to recompute only when the transcript array identity changes;
50
52
  // the prompt asks for this on every Escape, never per keystroke.
@@ -64,11 +66,22 @@ export function useMessageSelector({
64
66
  return false;
65
67
  }
66
68
  clearPromptHint();
69
+ // The prompt's pasted blocks return with it, so its tokens still expand.
70
+ if (restored.pastedImages) installPastedImages?.(restored.pastedImages, { merge: true });
71
+ if (restored.pastedTexts) installPastedTexts?.(restored.pastedTexts, { merge: true });
67
72
  syncPromptLayoutRows(text);
68
73
  setPromptDraftOverride({ id: Date.now(), value: text });
74
+ if (restored.notice) showPromptHint(restored.notice, 'error');
69
75
  return true;
70
76
  },
71
- [clearPromptHint, syncPromptLayoutRows, setPromptDraftOverride, showPromptHint]
77
+ [
78
+ clearPromptHint,
79
+ syncPromptLayoutRows,
80
+ setPromptDraftOverride,
81
+ showPromptHint,
82
+ installPastedImages,
83
+ installPastedTexts,
84
+ ]
72
85
  );
73
86
 
74
87
  const openMessageSelector = useCallback(() => {
@@ -89,7 +102,7 @@ export function useMessageSelector({
89
102
  own.close();
90
103
  let restored;
91
104
  try {
92
- restored = store.rewindToItem?.(value);
105
+ restored = store.rewindToItem?.(value, { restoreFiles: false });
93
106
  } catch (error) {
94
107
  showPromptHint(`rewind failed: ${error?.message || error}`, 'error');
95
108
  return;
@@ -221,6 +221,18 @@ export const loadProviderDisplayNames = async (store) => {
221
221
  return names;
222
222
  };
223
223
 
224
+ /** Provider names for the picker: custom rows' own `providerName` first, then
225
+ * setup names over them (setup wins). Works when setup is missing or failed. */
226
+ export const catalogProviderDisplayNames = (models, setupNames = null) => {
227
+ const names = {};
228
+ for (const model of Array.isArray(models) ? models : []) {
229
+ const provider = String(model?.provider || '').trim();
230
+ const name = String(model?.providerName || '').trim();
231
+ if (provider.startsWith('custom-') && name) names[provider] = name;
232
+ }
233
+ return { ...names, ...setupNames };
234
+ };
235
+
224
236
  /** `{ id, text }` for each provider whose model list failed, with the reason
225
237
  * (the setup row's `catalogError`) and what to do about it. */
226
238
  export const loadProviderCatalogFailures = async (store) => {
@@ -368,9 +380,11 @@ const routeModelDetails = (route) =>
368
380
  .filter(Boolean)
369
381
  .join(' · ');
370
382
 
371
- export const routeLabel = (route) => {
383
+ export const routeLabel = (route, providerNames = null) => {
372
384
  if (!route?.provider || !route?.model) return '(unset)';
373
- return [providerDisplayName(route.provider), routeModelDetails(route)].filter(Boolean).join(' · ');
385
+ return [resolveProviderDisplayName(route.provider, providerNames), routeModelDetails(route)]
386
+ .filter(Boolean)
387
+ .join(' · ');
374
388
  };
375
389
 
376
390
  export const routeModelLabel = (route) => (route?.model ? routeModelDetails(route) : '(unset)');
@@ -14,6 +14,7 @@ import {
14
14
  normalizeModelOptions,
15
15
  buildCatalogFailureItems,
16
16
  buildModelProviderItems,
17
+ catalogProviderDisplayNames,
17
18
  loadProviderCatalogFailures,
18
19
  loadProviderDisplayNames,
19
20
  } from './model-options.mjs';
@@ -83,7 +84,7 @@ export function createModelPicker({
83
84
  }
84
85
 
85
86
  const models = normalizeModelOptions(providerModels);
86
- const providerNames = await loadProviderDisplayNames(store);
87
+ const providerNames = catalogProviderDisplayNames(models, await loadProviderDisplayNames(store));
87
88
  const catalogFailures = await loadProviderCatalogFailures(store);
88
89
  const activeRoute = options.currentRoute || {
89
90
  provider: state.provider,
@@ -7,6 +7,7 @@
7
7
  * openers (openModelPicker) thread as lazy getter wrappers so they resolve the
8
8
  * live binding at call time.
9
9
  */
10
+ import { loadProviderDisplayNames } from './model-options.mjs';
10
11
  import { createAgentsPicker } from './route-pickers/agents-picker.mjs';
11
12
  import { createOutputStylePicker } from './route-pickers/output-style-picker.mjs';
12
13
  import { createWorkflowPicker } from './route-pickers/workflow-picker.mjs';
@@ -59,7 +60,8 @@ export function createRoutePickers({
59
60
  store.pushNotice('Web-search model save is already running.', 'warn');
60
61
  return;
61
62
  }
62
- store.pushNotice(`Web-search model set to ${routeLabel(result)}`, 'info');
63
+ const providerNames = await loadProviderDisplayNames(store);
64
+ store.pushNotice(`Web-search model set to ${routeLabel(result, providerNames)}`, 'info');
63
65
  return result;
64
66
  },
65
67
  onAfterSelect: null,
@@ -139,9 +139,9 @@ export function buildSettingsItems({
139
139
  {
140
140
  value: 'autoclear',
141
141
  label: 'Auto-clear',
142
- meta: autoClearEnabled ? `On (${formatDuration(autoClear.idleMs)})` : 'Off',
142
+ meta: autoClearEnabled ? `On (${autoClear.unlimited ? 'Unlimited' : formatDuration(autoClear.idleMs)})` : 'Off',
143
143
  description: autoClearEnabled
144
- ? `Clear idle sessions after ${formatDuration(autoClear.idleMs)}${autoClearSource}. Enter for options.`
144
+ ? `${autoClear.unlimited ? 'Never clear idle sessions' : `Clear idle sessions after ${formatDuration(autoClear.idleMs)}`}${autoClearSource}. Enter for options.`
145
145
  : 'Idle auto-clear disabled. Enter for options.',
146
146
  _action: 'autoclear',
147
147
  },
@@ -30,7 +30,7 @@ export const SLASH_COMMANDS = [
30
30
  {
31
31
  name: 'autoclear',
32
32
  usage: '/autoclear',
33
- params: '[on|off|duration]',
33
+ params: '[on|off|duration|unlimited]',
34
34
  description: 'Reduce cache-miss cost after long idle gaps',
35
35
  },
36
36
  { name: 'resume', usage: '/resume', params: '[id]', description: 'Resume a saved chat' },