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
@@ -135,7 +135,12 @@ export function createContextState({
135
135
  const ctx = runtime.contextStatus?.() || null;
136
136
  if (!ctx) return null;
137
137
  syncContextDisplayFields(ctx);
138
- const stats = { ...getState().stats, ...contextMeasurementStats(ctx) };
138
+ const stats = {
139
+ ...getState().stats,
140
+ ...contextMeasurementStats(ctx),
141
+ // The persisted session totals behind the composer's usage readout.
142
+ usageReadout: ctx.usage?.usageReadout ?? null,
143
+ };
139
144
  updateState({ stats });
140
145
  return ctx;
141
146
  };
@@ -31,12 +31,43 @@ export function createNoticeSurface({ getState, set, isDisposed, pushItem, repla
31
31
  return id;
32
32
  };
33
33
  const pushNotice = (text, tone = 'info', options = {}) => {
34
- const value = polishNoticeText(text);
35
- if (!value) return null;
34
+ // A routine result is a finished sentence, never a raw error to polish;
35
+ // a group-room row is someone's words, kept verbatim (a pass has none).
36
+ const value =
37
+ options.routine || options.room || options.heldRequest ? String(text ?? '').trim() : polishNoticeText(text);
38
+ if (!value && !options.room) return null;
36
39
  const forceTranscript = options.transcript === true;
37
40
  if (!forceTranscript) return pushToast(value, tone, options.ttlMs, options);
38
- const id = nextId();
39
- pushItem({ kind: 'notice', id, text: value, tone });
41
+ const userRow = options.room?.kind === 'user';
42
+ // A room user row keeps its message id (the sender's submission id), as a
43
+ // turn's own prompt row keeps its submission id.
44
+ const id = (userRow && options.messageId) || nextId();
45
+ // One row per messageId: a routine's live-only run row (running, delivery
46
+ // failed) gives way to the row that follows it (routine-result.mjs).
47
+ if (options.messageId) {
48
+ const current = getState().items;
49
+ const items = current.filter((it) => !(it?.kind === 'notice' && it?.messageId === options.messageId));
50
+ if (items.length !== current.length) set({ items: replaceItems(items, { preserveStreamingTail: true }) });
51
+ }
52
+ pushItem({
53
+ // A group-room row (agent-room.mjs): the user's own words are their
54
+ // bubble; every member row is a notice the app renders from `room`.
55
+ kind: userRow ? 'user' : 'notice',
56
+ id,
57
+ text: value,
58
+ ...(userRow ? {} : { tone }),
59
+ // A schedule result posted into a home thread (routine-result.mjs).
60
+ ...(options.routine ? { routine: options.routine } : {}),
61
+ ...(options.room ? { room: options.room } : {}),
62
+ // A room user row's files, in the fields a prompt row draws them from.
63
+ ...(userRow && Array.isArray(options.attachments) && options.attachments.length
64
+ ? { attachments: options.attachments }
65
+ : {}),
66
+ ...(userRow && Array.isArray(options.images) && options.images.length ? { images: options.images } : {}),
67
+ // A held request of an unattended run (human-gate/held-message.mjs).
68
+ ...(options.heldRequest ? { heldRequest: options.heldRequest } : {}),
69
+ ...(options.messageId ? { messageId: options.messageId } : {}),
70
+ });
40
71
  return id;
41
72
  };
42
73
  // Remove a transcript notice previously created via pushNotice(...,
@@ -35,7 +35,6 @@ const FAILED_NOTICE_ACTIONS = new Map([
35
35
  ['oauth login', 'start OAuth login'],
36
36
  ['output style switch', 'switch output style'],
37
37
  ['openai usage auth save', 'save OpenAI usage auth'],
38
- ['opencode go usage auth save', 'save OpenCode Go usage auth'],
39
38
  ['plugin add', 'add plugin'],
40
39
  ['plugin mcp enable', 'enable plugin MCP'],
41
40
  ['plugin uninstall', 'uninstall plugin'],
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { agentJobResultText, parseAgentJob, parseSyntheticAgentMessage } from './agent-envelope.mjs';
7
7
  import { attachmentTextForPart, isAttachmentReference } from '../../runtime/attachments/store.mjs';
8
+ import { recognisedSlashToken } from '../app/slash-commands.mjs';
8
9
 
9
10
  const QUEUE_PRIORITY = { now: 0, next: 1, later: 2 };
10
11
 
@@ -52,7 +53,7 @@ export function isQueuedEntryVisible(entry) {
52
53
  export function isSlashQueuedEntry(entry) {
53
54
  if (entry?.skipSlashCommands) return false;
54
55
  const text = promptContentText(entry?.content ?? entry?.text ?? '');
55
- return text.trim().startsWith('/');
56
+ return recognisedSlashToken(text) !== null;
56
57
  }
57
58
 
58
59
  function firstQueueLine(text) {
@@ -121,6 +121,10 @@ export function createSessionExtensionsApi(bag) {
121
121
  (input) => runtime.saveSkill?.(input),
122
122
  (result, input) => [`skill saved: ${result?.skill?.name || input?.name || 'skill'}`]
123
123
  ),
124
+ removeSkill: lockedChange(
125
+ (input) => runtime.removeSkill?.(input),
126
+ (result, input) => [`skill removed: ${result?.skill?.name || input?.name || 'skill'}`]
127
+ ),
124
128
  reloadSkills: lockedChange(
125
129
  () => runtime.reloadSkills?.(),
126
130
  (status) => [`skills reload: ${status?.count || 0} available`]
@@ -4,7 +4,7 @@
4
4
  import { promptDisplayText } from '../../queue-helpers.mjs';
5
5
 
6
6
  export function createSubmissionIntake(bag) {
7
- const { runtime, nextId, flags, getState, enqueue, autoClearBeforeSubmit } = bag;
7
+ const { nextId, flags, getState, enqueue, autoClearBeforeSubmit } = bag;
8
8
 
9
9
  const submission = (text, options = {}) => {
10
10
  const displayText = promptDisplayText(text, options);
@@ -14,6 +14,11 @@ export function createSubmissionIntake(bag) {
14
14
  text,
15
15
  queueOptions: {
16
16
  ...options,
17
+ // A kickoff (a new agent's greeting turn) reaches the model only: no
18
+ // user bubble, no queue row, never restored into the composer.
19
+ ...(options.kickoff === true
20
+ ? { isMeta: true, suppressDisplay: true, skipSlashCommands: true, restorable: false }
21
+ : {}),
17
22
  // Always mint a submission id so daemon retries / dual-path intake
18
23
  // can dedupe instead of booking the same prompt twice.
19
24
  id: String(options.id || '').trim() || nextId(),
@@ -25,19 +30,13 @@ export function createSubmissionIntake(bag) {
25
30
  };
26
31
 
27
32
  const enqueueSubmission = (intake) => {
33
+ // The queue itself wakes a passive `task wait` or shell hold for typed
34
+ // input (not for slash commands, which run after the turn); see enqueue.
28
35
  const accepted = enqueue(intake.text, intake.queueOptions);
29
- // User input wakes a passive `task wait` without cancelling either the
30
- // turn or the background task. The returned running snapshot creates the
31
- // normal post-tool boundary, where this queued prompt is injected.
32
- if (accepted !== false) {
33
- if ((intake.queueOptions.mode || 'prompt') === 'prompt') {
34
- bag.cancelQuotaResumeOnUserInput?.();
35
- bag.cancelQueuedGoalContinuations?.();
36
- bag.archiveCompletedGoalOnUserInput?.();
37
- }
38
- try {
39
- runtime.interruptTaskWait?.('user-message');
40
- } catch {}
36
+ if (accepted !== false && (intake.queueOptions.mode || 'prompt') === 'prompt') {
37
+ bag.cancelQuotaResumeOnUserInput?.();
38
+ bag.cancelQueuedGoalContinuations?.();
39
+ bag.archiveCompletedGoalOnUserInput?.();
41
40
  }
42
41
  return accepted;
43
42
  };
@@ -139,6 +139,7 @@ export function createSessionIntegrationsApi(bag, { oauthFlows }) {
139
139
  (result) => `custom provider saved: ${result.id}`
140
140
  ),
141
141
  updateCustomProviderModel: (id, modelId, patch) => runtime.updateCustomProviderModel(id, modelId, patch),
142
+ setModelPreferences: (provider, changes) => runtime.setModelPreferences(provider, changes),
142
143
  removeCustomProvider: async (id) => {
143
144
  const result = await runtime.removeCustomProvider(id);
144
145
  refreshRouteStats();
@@ -148,11 +149,6 @@ export function createSessionIntegrationsApi(bag, { oauthFlows }) {
148
149
  testCustomProvider: (input) => runtime.testCustomProvider(input),
149
150
  checkCustomProviderKeyEnv: (name) => runtime.checkCustomProviderKeyEnv(name),
150
151
  discoverCustomProviderModels: (input) => runtime.discoverCustomProviderModels(input),
151
- saveOpenCodeGoUsageAuth: async (opts) => {
152
- await runtime.saveOpenCodeGoUsageAuth(opts);
153
- pushNotice('OpenCode Go usage auth saved', 'info');
154
- return true;
155
- },
156
152
  saveOpenAIUsageSessionKey: async (secret) => {
157
153
  await runtime.saveOpenAIUsageSessionKey(secret);
158
154
  pushNotice('OpenAI usage auth saved', 'info');
@@ -195,6 +191,14 @@ export function createSessionIntegrationsApi(bag, { oauthFlows }) {
195
191
  (name) => runtime.runScheduleNow(name),
196
192
  (_result, name) => `schedule ran: ${name}`
197
193
  ),
194
+ runWebhookNow: announced(
195
+ (name) => runtime.runWebhookNow(name),
196
+ (_result, name) => `webhook ran: ${name}`
197
+ ),
198
+ retryRoutineDelivery: announced(
199
+ (kind, name) => runtime.retryRoutineDelivery(kind, name),
200
+ (_result, kind, name) => `${kind} result delivered: ${name}`
201
+ ),
198
202
  saveWebhook: announced(
199
203
  (entry) => runtime.saveWebhook(entry),
200
204
  (result) => `webhook saved: ${result.name}`
@@ -78,18 +78,28 @@ export function createSessionResetActions(bag) {
78
78
  };
79
79
 
80
80
  return {
81
- clear: () =>
81
+ // `archiveAs`: the id the outgoing transcript is kept under (an agent
82
+ // home's fresh start); the clear fails rather than wipe without it.
83
+ // `rebuildPrompt` / `fork: false`: an agent chat's reset (session-ops clear).
84
+ clear: (options = {}) =>
82
85
  withResetLock(async () => {
86
+ const archiveAs = typeof options?.archiveAs === 'string' ? options.archiveAs : '';
87
+ const reset = {
88
+ ...(options?.rebuildPrompt === true ? { rebuildPrompt: true } : {}),
89
+ ...(options?.fork === false ? { fork: false } : {}),
90
+ };
83
91
  const clearedId = getState().sessionId;
84
92
  // A cleared session has no failed turn left to resume.
85
93
  bag.supersedeQuotaResume?.(clearedId);
86
94
  const rollbackSnapshot = beginTuiReset();
87
95
  set(blankSessionPatch());
88
96
  try {
89
- await runtime.clear({ recoverAgent: true });
97
+ const result = await runtime.clear({ recoverAgent: true, ...(archiveAs ? { archiveAs } : {}), ...reset });
98
+ if (result === false && (archiveAs || reset.rebuildPrompt))
99
+ throw new Error('The conversation could not be cleared.');
90
100
  commitEmptySession(rollbackSnapshot);
91
101
  flags.lastUserActivityAt = Date.now();
92
- return true;
102
+ return reset.rebuildPrompt ? result : true;
93
103
  } catch (error) {
94
104
  restoreTuiAfterFailedSessionReset(rollbackSnapshot);
95
105
  throw error;
@@ -9,6 +9,17 @@ import { createInheritanceActions } from './lifecycle/inheritance.mjs';
9
9
  import { createResumeAction } from './lifecycle/resume.mjs';
10
10
  import { createDisposeAction } from './lifecycle/dispose.mjs';
11
11
  import { publishModelSwitch } from './routes.mjs';
12
+ import { resolveHeldRequest } from '../../../runtime/shared/held-request-host.mjs';
13
+
14
+ /** The human-response fields of a decision (never a value), or null. */
15
+ function humanDecisionFields(decision) {
16
+ if (!decision || typeof decision !== 'object') return null;
17
+ const fields = {};
18
+ for (const key of ['response', 'editedArgs', 'remember', 'scope']) {
19
+ if (decision[key] !== undefined) fields[key] = decision[key];
20
+ }
21
+ return Object.keys(fields).length ? fields : null;
22
+ }
12
23
 
13
24
  export function createSessionLifecycleApi(bag, { restoreTranscriptItems, oauthFlows }) {
14
25
  const { runtime, pushNotice, removeNotice, setProgressHint, finishToolApproval } = bag;
@@ -52,14 +63,19 @@ export function createSessionLifecycleApi(bag, { restoreTranscriptItems, oauthFl
52
63
  return {
53
64
  isSessionTerminal: () => bag.flags?.admission === 'terminal' || runtime.isSessionTerminal?.() === true,
54
65
  resolveToolApproval: (id, decision = {}) => {
66
+ // A held request of an unattended run is answered from its owner's home
67
+ // thread, wherever the run itself lives (session-runtime/held-requests.mjs).
68
+ if (resolveHeldRequest(id, decision)) return true;
55
69
  const approved = decision === true || decision?.approved === true;
70
+ const extra = humanDecisionFields(decision);
56
71
  return finishToolApproval(
57
72
  id,
58
73
  approved,
59
74
  decision?.reason || (approved ? 'approved by user' : 'denied by user'),
60
75
  typeof decision?.device === 'string' ? decision.device : '',
61
76
  decision?.answers,
62
- typeof decision?.reply === 'string' ? decision.reply : undefined
77
+ typeof decision?.reply === 'string' ? decision.reply : undefined,
78
+ ...(extra ? [extra] : [])
63
79
  );
64
80
  },
65
81
  pushNotice,
@@ -3,7 +3,10 @@
3
3
  * the serialized optimistic setRoute, web-search route, workflows, agent
4
4
  * definitions, output style and orchestration mode.
5
5
  */
6
- import { modelSwitchItem } from '../../../runtime/agent/orchestrator/session/transcript-restore/restore.mjs';
6
+ import {
7
+ modelSwitchItem,
8
+ workflowSwitchItem,
9
+ } from '../../../runtime/agent/orchestrator/session/transcript-restore/restore.mjs';
7
10
  import { selectedModel } from '../../../session-runtime/model-route/model-switch-target.mjs';
8
11
  import { createApiHelpers } from './shared.mjs';
9
12
 
@@ -272,8 +275,48 @@ export function createSessionRouteApi(bag) {
272
275
  createWorkflow: async (payload) => runtime.createWorkflow?.(payload) ?? null,
273
276
  deleteWorkflow: async (workflowId) => runtime.deleteWorkflow?.(workflowId) ?? null,
274
277
  getAgentDefinition: (agentId) => runtime.getAgentDefinition?.(agentId) ?? null,
278
+ getAgentAvatarImage: (agentId) => runtime.getAgentAvatarImage?.(agentId) ?? null,
279
+ getAgentConnectors: (agentId) => runtime.getAgentConnectors?.(agentId) ?? [],
280
+ listConnectors: () => runtime.listConnectors?.() ?? [],
281
+ listConnectorTools: (connectorId) => runtime.listConnectorTools?.(connectorId) ?? [],
282
+ setAgentConnectors: async (agentId, connectors) => runtime.setAgentConnectors?.(agentId, connectors) ?? null,
283
+ setAgentConnectorEnabled: async (agentId, connectorId, enabled) =>
284
+ runtime.setAgentConnectorEnabled?.(agentId, connectorId, enabled) ?? [],
285
+ getProjectConnectors: (projectPath) => runtime.getProjectConnectors?.(projectPath) ?? [],
286
+ setProjectConnectorEnabled: async (projectPath, connectorId, enabled) =>
287
+ runtime.setProjectConnectorEnabled?.(projectPath, connectorId, enabled) ?? [],
288
+ setAgentConnectorToolPermission: async (agentId, connectorId, toolName, permission) =>
289
+ runtime.setAgentConnectorToolPermission?.(agentId, connectorId, toolName, permission) ?? null,
290
+ // Per-agent action-kind permissions (ask / allow / block) for the profile.
291
+ getAgentPermissions: async (agentId) =>
292
+ (await import('../../../runtime/agent/orchestrator/session/human-gate/store.mjs')).agentPermissions(agentId),
293
+ setAgentPermission: async (agentId, action, mode) =>
294
+ (await import('../../../runtime/agent/orchestrator/session/human-gate/store.mjs')).setAgentPermission(
295
+ agentId,
296
+ action,
297
+ mode
298
+ ),
299
+ getLeadPersona: () => runtime.getLeadPersona?.() ?? '',
300
+ saveLeadPersona: async (text) => runtime.saveLeadPersona?.(text) ?? '',
301
+ getLeadAgentBody: () => runtime.getLeadAgentBody?.() ?? '',
302
+ saveLeadAgentBody: async (text) => runtime.saveLeadAgentBody?.(text) ?? '',
303
+ getLeadStatus: () => runtime.getLeadStatus?.() ?? { created: null, name: '', avatar: null },
304
+ saveLeadIdentity: async (payload) => runtime.saveLeadIdentity?.(payload) ?? null,
305
+ setLeadCreated: async (created, description) => runtime.setLeadCreated?.(created, description) ?? null,
275
306
  saveAgentDefinition: async (payload) => runtime.saveAgentDefinition?.(payload) ?? null,
276
307
  deleteAgentDefinition: async (agentId) => runtime.deleteAgentDefinition?.(agentId) ?? null,
308
+ agentDefinitionPresence: (agentIds) => runtime.agentDefinitionPresence?.(agentIds) ?? null,
309
+ restoreAgentDefinition: async (agentId) => runtime.restoreAgentDefinition?.(agentId) ?? null,
310
+ purgeAgentDefinition: async (agentId) => runtime.purgeAgentDefinition?.(agentId) ?? null,
311
+ archivedAgentIdentities: (agentIds) => runtime.archivedAgentIdentities?.(agentIds) ?? null,
312
+ // Group-room rows posted by the desktop host into a room's log session.
313
+ appendRoomRows: async (sessionId, rows) =>
314
+ (await import('../../../session-runtime/agent-room-delivery.mjs')).appendRoomRows(sessionId, rows),
315
+ // One group-room supervisor step on the Maintainer route.
316
+ decideRoomTurn: async (input) =>
317
+ (await import('../../../runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs')).decideRoomTurn(
318
+ input
319
+ ),
277
320
  getOutputStyle: () => {
278
321
  return runtime.getOutputStyle?.() || runtime.listOutputStyles?.() || null;
279
322
  },
@@ -291,8 +334,10 @@ export function createSessionRouteApi(bag) {
291
334
  deferStatsRefresh();
292
335
  return result;
293
336
  }),
294
- setWorkflow: withCommandLock(async (workflowId) => {
295
- const result = await runtime.setWorkflow?.(workflowId);
337
+ setWorkflow: withCommandLock(async (workflowId, options) => {
338
+ const result = await runtime.setWorkflow?.(workflowId, options);
339
+ // A switch of this conversation leaves a divider (restored from message meta).
340
+ if (result?.workflowSwitch) bag.pushItem(workflowSwitchItem(bag.nextId(), result.workflowSwitch));
296
341
  publishRoute();
297
342
  return result;
298
343
  }),
@@ -52,6 +52,13 @@ function renderBatchItems(batch, pushUserOrSyntheticItem) {
52
52
  }
53
53
  continue;
54
54
  }
55
+ // A routine fire paints as the routine's marker row, not a user bubble.
56
+ if (entry.mode === 'routine') {
57
+ pushUserOrSyntheticItem(entry.text, entry.id, 'routine', {
58
+ routineTrigger: entry.transcriptMeta?.routineTrigger,
59
+ });
60
+ continue;
61
+ }
55
62
  const sender = String(entry.transcriptMeta?.sender || '')
56
63
  .trim()
57
64
  .toLowerCase();
@@ -106,6 +113,10 @@ export function turnOptionsForBatch(batch, steering) {
106
113
  Array.isArray(entry?.resumeCompletionKeys) ? entry.resumeCompletionKeys : []
107
114
  ),
108
115
  transcriptMeta: batch[0]?.transcriptMeta || null,
116
+ // Only a routine turn names its selection text (never its payload).
117
+ ...(batch[0]?.mode === 'routine' && typeof batch[0].skillSelection === 'string'
118
+ ? { skillSelection: batch[0].skillSelection }
119
+ : {}),
109
120
  context:
110
121
  batch
111
122
  .map((entry) => String(entry.context || '').trim())
@@ -191,9 +202,7 @@ export function createDrainLoop(
191
202
  clearBlockedDrainRetry();
192
203
  if (entries.length === 0) return;
193
204
  queue.removeQueuedEntries(entries);
194
- const mirrored = entries.filter(
195
- (entry) => steering.shouldMirrorSteeringEntry(entry) && !entry.steeringPersistRestored
196
- );
205
+ const mirrored = entries.filter((entry) => steering.shouldMirrorSteeringEntry(entry) && entry.steeringPersistId);
197
206
  if (mirrored.length > 0) {
198
207
  void Promise.resolve(dropTuiSteeringPersist(steering.leadSessionId(), mirrored)).catch(() => {});
199
208
  }
@@ -332,6 +341,14 @@ export function createDrainLoop(
332
341
  }
333
342
  submissions.remember(submissionId);
334
343
  pending.push(entry);
344
+ // Typed input or a deliverable notification ends a passive task wait or
345
+ // shell hold so the next boundary hands it to the model now.
346
+ const wake = steering.taskWaitWakeForEntry(entry);
347
+ if (wake) {
348
+ try {
349
+ bag.runtime?.interruptTaskWait?.(wake, wake === 'notification' ? entry.execution?.id || null : null);
350
+ } catch {}
351
+ }
335
352
  const needsDurableSteering =
336
353
  (getState().busy || getState().commandBusy || flags.autoClearRunning || flags.quotaResumePending) &&
337
354
  steering.shouldMirrorSteeringEntry(entry);
@@ -43,8 +43,9 @@ export function makeQueueEntry(text, options = {}, nextId) {
43
43
  ? options.resumeCompletionKeys.filter((key) => key != null && String(key).trim())
44
44
  : [],
45
45
  steeringPersistId: options.steeringPersistId || null,
46
- steeringPersistRestored: options.steeringPersistRestored === true,
47
46
  isMeta: options.isMeta === true,
47
+ // A routine turn's trusted skill-selection text (its instructions only).
48
+ skillSelection: typeof options.skillSelection === 'string' ? options.skillSelection : null,
48
49
  goalId: options.goalId || null,
49
50
  // Retry of a failed turn: the transcript and the session rewind the
50
51
  // failed turn's unanswered prompt before this entry runs.
@@ -43,7 +43,8 @@ export function createTakeEntriesOps({ pending, pendingNotificationKeys, removeQ
43
43
  batch.push(entry);
44
44
  pending.splice(i, 1);
45
45
  if (entry.mode === 'task-notification' && entry.key) pendingNotificationKeys.delete(entry.key);
46
- if (entry.retryTurnId || batch.length >= limit) break;
46
+ // A routine fire is a turn of its own, never merged with another.
47
+ if (entry.retryTurnId || entry.mode === 'routine' || batch.length >= limit) break;
47
48
  } else {
48
49
  i += 1;
49
50
  }
@@ -73,7 +74,7 @@ export function createTakeEntriesOps({ pending, pendingNotificationKeys, removeQ
73
74
  // A reclaimed prompt goes back to the draft, so its durable steering
74
75
  // mirror goes with it; otherwise the next runtime restore re-queues a
75
76
  // prompt the user already took back.
76
- const mirrored = queued.filter((entry) => entry.steeringPersistId && !entry.steeringPersistRestored);
77
+ const mirrored = queued.filter((entry) => entry.steeringPersistId);
77
78
  if (mirrored.length > 0) void dropTuiSteeringPersist(leadSessionId(), mirrored);
78
79
  const queuedText = queued
79
80
  .map((item) => item.text)
@@ -12,10 +12,13 @@ import {
12
12
  callCommitCallbacks,
13
13
  STEERING_SUPPRESSED_DISPLAY,
14
14
  } from '../queue-helpers.mjs';
15
- import { dropTuiSteeringPersist, drainTuiSteeringPersist } from '../tui-steering-persist.mjs';
15
+ import { dropTuiSteeringPersist, readTuiSteeringPersist } from '../tui-steering-persist.mjs';
16
16
  import { getBackgroundTask } from '../../../runtime/shared/background-tasks.mjs';
17
17
 
18
18
  const RESTORE_DEDUP_WINDOW = 80;
19
+ // An older build's process-local item counter: a later process issues the
20
+ // same ids again, so such an id proves nothing about delivery.
21
+ const PROCESS_LOCAL_ITEM_ID = /^it_\d+$/;
19
22
 
20
23
  // Mid-chain drain converts queued prompt/task notification entries into
21
24
  // model-visible "queued_command" style steering only at provider continuation
@@ -65,8 +68,28 @@ function steeringMessageFromEntry(entry) {
65
68
  return String(content ?? '').trim().length > 0 ? { ...meta, text: displayText, content } : null;
66
69
  }
67
70
 
68
- // Recent user message bodies define "already delivered" for restore dedup;
69
- // substring (not equality) because steering delivery may wrap the raw text.
71
+ // The submissions the transcript holds: a turn's prompt (`checkpointId`, plus
72
+ // `submissionIds` for a merged batch) and a steered message's `submissionIds`.
73
+ function deliveredSubmissionIds(session) {
74
+ const out = new Set();
75
+ for (const message of Array.isArray(session?.messages) ? session.messages : []) {
76
+ if (message?.role !== 'user') continue;
77
+ const meta = message.meta || {};
78
+ const transcript = meta.transcript || {};
79
+ for (const id of [
80
+ transcript.checkpointId,
81
+ ...(Array.isArray(transcript.submissionIds) ? transcript.submissionIds : []),
82
+ ...(Array.isArray(meta.submissionIds) ? meta.submissionIds : []),
83
+ ]) {
84
+ if (typeof id === 'string' && id) out.add(id);
85
+ }
86
+ }
87
+ return out;
88
+ }
89
+
90
+ // Rows of an older build carry no stable submission id; only their text can
91
+ // tell them delivered: substring (not equality) because steering delivery may
92
+ // wrap the raw text.
70
93
  function recentUserTexts(session, window) {
71
94
  const messages = Array.isArray(session?.messages) ? session.messages : [];
72
95
  const out = [];
@@ -107,7 +130,7 @@ export function createSteeringOps(bag, { queue, submissions }) {
107
130
  function commitSteeringQueueEntries(entries) {
108
131
  callCommitCallbacks(entries);
109
132
  const mirrored = (Array.isArray(entries) ? entries : []).filter(
110
- (entry) => shouldMirrorSteeringEntry(entry) && !entry.steeringPersistRestored
133
+ (entry) => shouldMirrorSteeringEntry(entry) && entry.steeringPersistId
111
134
  );
112
135
  if (mirrored.length > 0) dropTuiSteeringPersist(leadSessionId(), mirrored);
113
136
  }
@@ -131,6 +154,47 @@ export function createSteeringOps(bag, { queue, submissions }) {
131
154
  );
132
155
  }
133
156
 
157
+ // Queued input the user typed (editable prompts), not runtime notices.
158
+ function hasPendingUserInput() {
159
+ if (!admissionOpen()) return false;
160
+ return pending.some((entry) => isQueuedEntryEditable(entry) && !isSlashQueuedEntry(entry));
161
+ }
162
+
163
+ // A notification the next boundary will deliver: a task notification (one
164
+ // the agent already received through task wait/read is not deliverable) or
165
+ // the Goal closeout. `later` entries (scheduled and channel injects) wait
166
+ // for the turn to end, so they are not deliverable mid-turn.
167
+ function isDeliverableNotification(entry) {
168
+ const mode = entry?.mode;
169
+ return (
170
+ admissionOpen() &&
171
+ (mode === 'task-notification' || mode === 'goal-closeout') &&
172
+ queuePriorityValue(entry.priority) <= queuePriorityValue('next') &&
173
+ canDeliverSteeringEntry(entry) &&
174
+ steeringMessageFromEntry(entry) !== null
175
+ );
176
+ }
177
+
178
+ function hasPendingNotification() {
179
+ return pending.some(isDeliverableNotification);
180
+ }
181
+
182
+ // What one queued entry should wake a passive wait or shell hold for: typed
183
+ // input, a deliverable notification, or nothing (slash commands and
184
+ // informational meta prompts run or ride along without ending a wait).
185
+ function taskWaitWakeForEntry(entry) {
186
+ if (!admissionOpen()) return false;
187
+ if (isQueuedEntryEditable(entry) && !isSlashQueuedEntry(entry)) return 'user-message';
188
+ return isDeliverableNotification(entry) ? 'notification' : false;
189
+ }
190
+
191
+ // What a passive wait or shell hold should wake for right now: user input
192
+ // first, else a deliverable notification.
193
+ function pendingTaskWaitWake() {
194
+ if (hasPendingUserInput()) return 'user-message';
195
+ return hasPendingNotification() ? 'notification' : false;
196
+ }
197
+
134
198
  // `later` notifications (scheduled tasks) are skipped unless the runtime
135
199
  // explicitly asks for a later flush.
136
200
  function drainPendingSteering(_sessionIdOrOptions = null, maybeOptions = null) {
@@ -164,46 +228,57 @@ export function createSteeringOps(bag, { queue, submissions }) {
164
228
  async function restoreLeadSteeringFromDisk() {
165
229
  // A closed/closing conversation never gets queue work restored into it.
166
230
  if (!admissionOpen()) return;
167
- const rows = await drainTuiSteeringPersist(leadSessionId());
231
+ const rows = await readTuiSteeringPersist(leadSessionId());
168
232
  if (!rows.length) return;
169
233
  const livePersistIds = new Set(pending.map((entry) => entry?.steeringPersistId).filter(Boolean));
170
- // Crash-consumed dedup: a row whose text already landed in the session
171
- // transcript was consumed before the restart — only its disk drop was
172
- // lost (drop is an async fire-and-forget write). Re-queuing it silently
173
- // re-injects a stale prompt into the next turn (user report: surprise
174
- // self-injection after a process restart).
175
- const delivered = recentUserTexts(runtime.session, RESTORE_DEDUP_WINDOW);
176
- const alreadyDelivered = (text) => delivered.some((body) => body.includes(text));
234
+ // Crash-consumed dedup: a row whose submission already landed in the
235
+ // session transcript was consumed before the restart — only its disk drop
236
+ // was lost (drop is an async fire-and-forget write). Re-queuing it
237
+ // silently re-injects a stale prompt into the next turn (user report:
238
+ // surprise self-injection after a process restart). Identity, never text:
239
+ // the same words can be a new submission.
240
+ const delivered = deliveredSubmissionIds(runtime.session);
241
+ let legacyTexts = null;
242
+ const alreadyDelivered = (row, text) => {
243
+ if (row.submissionId && !PROCESS_LOCAL_ITEM_ID.test(row.submissionId)) return delivered.has(row.submissionId);
244
+ legacyTexts ??= recentUserTexts(runtime.session, RESTORE_DEDUP_WINDOW);
245
+ return legacyTexts.some((body) => body.includes(text));
246
+ };
177
247
  const restored = [];
178
- let droppedDelivered = 0;
248
+ const consumed = [];
179
249
  for (const row of rows) {
180
250
  const text = String(row?.text || '').trim();
181
251
  if (!text) continue;
182
252
  // Live enqueue already holds this row (id assigned before the async
183
253
  // disk write). Replaying it is the classic double-booked queue.
184
254
  if (row.steeringPersistId && livePersistIds.has(row.steeringPersistId)) continue;
185
- if (alreadyDelivered(text)) {
186
- droppedDelivered += 1;
255
+ if (alreadyDelivered(row, text)) {
256
+ consumed.push(row);
187
257
  continue;
188
258
  }
189
- const entry = queue.makeQueueEntry(row.text, {
190
- id: row.submissionId || undefined,
191
- submittedAt: row.submittedAt || undefined,
192
- steeringPersistRestored: true,
193
- steeringPersistId: row.steeringPersistId || undefined,
259
+ // The row keeps its executable content and attachment links; a row
260
+ // of an older build has only its text.
261
+ const { content, text: displayText, submissionId, submittedAt, ...options } = row;
262
+ const entry = queue.makeQueueEntry(content ?? displayText, {
263
+ ...options,
264
+ id: submissionId || undefined,
265
+ submittedAt: submittedAt || undefined,
266
+ displayText,
194
267
  });
195
268
  pending.push(entry);
196
- if (row.submissionId) submissions.remember(row.submissionId);
197
- if (entry.steeringPersistId) livePersistIds.add(entry.steeringPersistId);
269
+ if (submissionId) submissions.remember(submissionId);
270
+ livePersistIds.add(entry.steeringPersistId);
198
271
  if (isQueuedEntryVisible(entry)) restored.push(entry);
199
272
  }
200
273
  if (restored.length > 0) set({ queued: [...getState().queued, ...restored] });
274
+ // Reading keeps rows durable; a delivered row's lost drop is completed here.
275
+ if (consumed.length > 0) await dropTuiSteeringPersist(leadSessionId(), consumed);
201
276
  // The conversation closed while the rows were being read: settle them
202
277
  // explicitly (rejected + durable mirror released), never leave them parked.
203
278
  if (bag.flags?.admission === 'terminal') bag.settleClosedQueue?.();
204
- if (droppedDelivered > 0) {
279
+ if (consumed.length > 0) {
205
280
  try {
206
- process.stderr.write(`[tui] skipped ${droppedDelivered} already-delivered steering row(s) on restore\n`);
281
+ process.stderr.write(`[tui] skipped ${consumed.length} already-delivered steering row(s) on restore\n`);
207
282
  } catch {
208
283
  /* best effort */
209
284
  }
@@ -219,6 +294,11 @@ export function createSteeringOps(bag, { queue, submissions }) {
219
294
  commitSteeringQueueEntries,
220
295
  settleSteeredSubmissions,
221
296
  hasPendingSteering,
297
+ hasPendingUserInput,
298
+ isDeliverableNotification,
299
+ hasPendingNotification,
300
+ taskWaitWakeForEntry,
301
+ pendingTaskWaitWake,
222
302
  drainPendingSteering,
223
303
  restoreLeadSteeringFromDisk,
224
304
  };
@@ -39,6 +39,8 @@ export function createSessionFlow(bag) {
39
39
  enqueue: loop.enqueue,
40
40
  settleClosedQueue: loop.settleClosedQueue,
41
41
  hasPendingSteering: steering.hasPendingSteering,
42
+ hasPendingUserInput: steering.hasPendingUserInput,
43
+ pendingTaskWaitWake: steering.pendingTaskWaitWake,
42
44
  drainPendingSteering: steering.drainPendingSteering,
43
45
  restoreLeadSteeringFromDisk: steering.restoreLeadSteeringFromDisk,
44
46
  autoClearBeforeSubmit: autoClear.autoClearBeforeSubmit,