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
@@ -15,11 +15,14 @@ import { join } from 'node:path';
15
15
  // Leaf helpers only: the three-way present/absent/unreadable classification
16
16
  // and the strict record parser the authoritative store uses, so the catalog
17
17
  // cannot disagree with it.
18
- import { probePath, readTextFile, PROBE_PRESENT, PROBE_ABSENT } from './store/fs-probe.mjs';
19
- import { readTopLevelLifecycleRecord, isLifecycleUnreadable } from './lifecycle-scan.mjs';
18
+ import { probePath, readBytesFile, readTextFile, PROBE_PRESENT, PROBE_ABSENT } from './store/fs-probe.mjs';
19
+ import { isLifecycleUnreadable } from './lifecycle-scan.mjs';
20
+ import { readStrictRecordFields } from './store-record-strict-scan.mjs';
20
21
  import { isAgentOnlySession, isRootLeadSession, sessionVisibility } from './store-summary-visibility.mjs';
21
22
  import { applySummaryLogText, summaryLogPath } from './store-summary-log.mjs';
22
23
  import { dataDir } from './store-summary-locations.mjs';
24
+ import { normalizeRoutineProvenance } from './routine-result.mjs';
25
+ import { lastMessageLine, lastMessageSummary } from './store-summary-last-message.mjs';
23
26
  import {
24
27
  desktopSession,
25
28
  importKey,
@@ -30,6 +33,7 @@ import {
30
33
  workspaceSummary,
31
34
  } from './store-summary-fields.mjs';
32
35
  import { isRealTurnMessage } from './compact/user-message-kind.mjs';
36
+ import { sessionModeOf } from './agent-mode.mjs';
33
37
  import { byActivityThenId } from './catalog-db/schema.mjs';
34
38
  import {
35
39
  sessionStampOf,
@@ -43,7 +47,7 @@ export const STAMP_ABSENT_CODES = new Set(['ENOENT', 'ENOTDIR']);
43
47
  /** The one catalog order of every listing path (JSON and DB): newest
44
48
  * conversation activity first (see normalizedRow's lastUsedAt note), ties by
45
49
  * id, so a fallback and the DB never disagree on equal activity times. */
46
- export const byCatalogOrder = byActivityThenId;
50
+ const byCatalogOrder = byActivityThenId;
47
51
 
48
52
  // ── Stamp-keyed strict derivations ──────────────────────────────────────────
49
53
  // Session metadata and catalog rows are small values derived from a strict
@@ -52,8 +56,20 @@ export const byCatalogOrder = byActivityThenId;
52
56
  // proven to come from (stat → read → stat) and that stamp is past the racy
53
57
  // window. Any other file — changed, replaced by another writer, unreadable —
54
58
  // is read and strictly parsed again.
59
+ // Bounded by count and by serialized size: nothing tells this map a session
60
+ // file went away, so a churning host fills it with dead paths until LRU
61
+ // eviction (`delete` + `set` on a hit keeps Map order least recent first).
55
62
  const STAMPED_DERIVATION_LIMIT = 2048;
56
- const stampedDerivations = new Map(); // `${kind}|${path}` → { stamp, value }
63
+ const STAMPED_DERIVATION_MAX_BYTES = 8 * 1024 * 1024;
64
+ const stampedDerivations = new Map(); // `${kind}|${path}` → { stamp, value, bytes }
65
+ let stampedDerivationBytes = 0;
66
+
67
+ function dropStampedDerivation(key) {
68
+ const entry = stampedDerivations.get(key);
69
+ if (!entry) return;
70
+ stampedDerivations.delete(key);
71
+ stampedDerivationBytes -= entry.bytes;
72
+ }
57
73
 
58
74
  export function observeStamp(path) {
59
75
  try {
@@ -64,24 +80,35 @@ export function observeStamp(path) {
64
80
  }
65
81
 
66
82
  /** `{ state, value }`: `derive(text)` for the record at `path`, or its cached
67
- * result while the file is provably unchanged. */
68
- export function stampedDerivation(kind, path, derive) {
83
+ * result while the file is provably unchanged. `bytes`: `derive` gets the
84
+ * raw Buffer instead of text. `stamp`: the caller's own stat of `path`,
85
+ * taken just before, stands for the pre-read stat (one stat fewer). */
86
+ export function stampedDerivation(kind, path, derive, { bytes = false, stamp } = {}) {
69
87
  const key = `${kind}|${path}`;
70
- const before = observeStamp(path);
88
+ const before = stamp === undefined ? observeStamp(path) : stamp;
71
89
  const cached = stampedDerivations.get(key);
72
90
  if (before && cached && sameSessionStamp(cached.stamp, before)) {
73
91
  stampedDerivations.delete(key);
74
92
  stampedDerivations.set(key, cached);
75
93
  return { state: PROBE_PRESENT, value: cached.value };
76
94
  }
77
- stampedDerivations.delete(key);
78
- const read = readTextFile(path);
95
+ dropStampedDerivation(key);
96
+ const read = bytes ? readBytesFile(path) : readTextFile(path);
79
97
  if (read.state !== PROBE_PRESENT) return { state: read.state, value: null };
80
- const value = derive(read.text);
98
+ const value = derive(bytes ? read.bytes : read.text);
81
99
  if (isSettledSessionStamp(before) && sameSessionStamp(before, observeStamp(path))) {
82
- stampedDerivations.set(key, { stamp: before, value });
83
- if (stampedDerivations.size > STAMPED_DERIVATION_LIMIT) {
84
- stampedDerivations.delete(stampedDerivations.keys().next().value);
100
+ // UTF-16 code units of the key and the serialized value approximate the
101
+ // retained bytes; the strict parse just above dwarfs this stringify.
102
+ const size = 2 * (key.length + (JSON.stringify(value)?.length ?? 0));
103
+ if (size <= STAMPED_DERIVATION_MAX_BYTES) {
104
+ stampedDerivations.set(key, { stamp: before, value, bytes: size });
105
+ stampedDerivationBytes += size;
106
+ while (
107
+ stampedDerivations.size > STAMPED_DERIVATION_LIMIT ||
108
+ stampedDerivationBytes > STAMPED_DERIVATION_MAX_BYTES
109
+ ) {
110
+ dropStampedDerivation(stampedDerivations.keys().next().value);
111
+ }
85
112
  }
86
113
  }
87
114
  return { state: PROBE_PRESENT, value };
@@ -167,6 +194,7 @@ export function normalizedRow(row) {
167
194
  status: String(row.status || (row.closed === true ? 'closed' : 'idle')),
168
195
  owner: row.owner || 'user',
169
196
  agent: row.agent || null,
197
+ sessionMode: sessionModeOf(row),
170
198
  sourceType: row.sourceType || null,
171
199
  sourceName: row.sourceName || null,
172
200
  scopeKey: row.scopeKey || null,
@@ -186,6 +214,10 @@ export function normalizedRow(row) {
186
214
  realTurnCount: realTurnCount(row),
187
215
  title: cleanText(row.title, 100),
188
216
  preview: cleanText(row.preview),
217
+ lastMessagePreview: cleanText(row.lastMessagePreview),
218
+ // Null for any line that is not a routine result, and on rows written
219
+ // before the marker existed (they show their plain text).
220
+ lastMessageRoutine: normalizeRoutineProvenance(row.lastMessageRoutine),
189
221
  generation: typeof row.generation === 'number' ? row.generation : 0,
190
222
  storageMtimeMs: positiveNumber(row.storageMtimeMs, 0),
191
223
  storageSize: positiveNumber(row.storageSize, 0),
@@ -199,6 +231,26 @@ function leadRows(rows) {
199
231
  return rows.filter((row) => row && isLeadVisibleRow(row));
200
232
  }
201
233
 
234
+ // What a row derivation decodes of a record (store-record-strict-scan.mjs):
235
+ // rowFromSession reads its user messages whole, the newest messages back to
236
+ // the one with a last-message line whole too, only the role of the rest, and
237
+ // never these top-level fields — together ~10% of a record, mostly tool
238
+ // catalogs. Every other top-level field is decoded, so a field a row starts
239
+ // to read is there without touching this list.
240
+ const CATALOG_RECORD_READ = {
241
+ skip: new Set([
242
+ 'tools',
243
+ 'deferredToolCatalog',
244
+ 'deferredLateToolCatalog',
245
+ 'bp3CoreContext',
246
+ 'bp3EnvironmentContext',
247
+ 'compaction',
248
+ 'pendingDeferredToolDelta',
249
+ ]),
250
+ fullMessageRoles: new Set(['user']),
251
+ fullTailUntil: (message) => Boolean(lastMessageLine(message)),
252
+ };
253
+
202
254
  function rowFromSession(session) {
203
255
  const messages = Array.isArray(session?.messages) ? session.messages : [];
204
256
  const preview =
@@ -214,11 +266,15 @@ function rowFromSession(session) {
214
266
  )
215
267
  .map((message) => cleanText(messageText(message.content)))
216
268
  .find(Boolean) || '';
269
+ // The last-message line comes from the transcript like the summary index
270
+ // derives it; without it a session saved after the index was written lost
271
+ // its contact-row preview whenever its row came from this file read.
217
272
  return normalizedRow({
218
273
  ...session,
219
274
  messageCount: messages.filter((message) => message?.role === 'user' || message?.role === 'assistant').length,
220
275
  realTurnCount: messages.filter(isRealTurnMessage).length,
221
276
  preview,
277
+ ...lastMessageSummary(messages),
222
278
  });
223
279
  }
224
280
 
@@ -259,14 +315,21 @@ function reconcileSessionFile(directory, storageId, retained, forceRead) {
259
315
  return { kind: 'indexed', ...fingerprint };
260
316
  }
261
317
  // A file the index does not describe (never saved by the store, or
262
- // saved after the index was written) is parsed once per full stamp.
263
- const read = stampedDerivation('row', path, (text) => {
264
- // Same strict authority as the store: a duplicate/ambiguous top-level
265
- // record or a foreign identity is not this file's session.
266
- const record = readTopLevelLifecycleRecord(text);
267
- if (isLifecycleUnreadable(record) || record.id !== storageId) return null;
268
- return rowFromSession(record.doc);
269
- });
318
+ // saved after the index was written) is read once per full stamp; the
319
+ // stat above is the read's pre-read stat.
320
+ const read = stampedDerivation(
321
+ 'row',
322
+ path,
323
+ (bytes) => {
324
+ // Same strict authority as the store: a duplicate/ambiguous top-level
325
+ // record or a foreign identity is not this file's session. Only what a
326
+ // row is made of is decoded (see CATALOG_RECORD_READ).
327
+ const record = readStrictRecordFields(bytes, CATALOG_RECORD_READ);
328
+ if (isLifecycleUnreadable(record) || record.id !== storageId) return null;
329
+ return rowFromSession(record.doc);
330
+ },
331
+ { bytes: true, stamp }
332
+ );
270
333
  if (read.state === PROBE_ABSENT) return null;
271
334
  // Exists and could not be read (EACCES/EIO): retain the last known row
272
335
  // rather than let a transient IO error delete it from view.
@@ -16,8 +16,9 @@ import {
16
16
  writeJsonAtomicSync,
17
17
  } from '../../../shared/atomic-file.mjs';
18
18
  import { applySummaryLogText, encodeSummaryOps, summaryLogPath } from './store-summary-log.mjs';
19
- import { cleanSessionPreview, isSessionPreviewNoise, sessionMessageText } from '../runtime-core/session-text.mjs';
19
+ import { isSessionPreviewNoise, sessionMessageText } from '../runtime-core/session-text.mjs';
20
20
  import { sessionVisibility } from './store-summary-visibility.mjs';
21
+ import { sessionModeOf } from './agent-mode.mjs';
21
22
  import {
22
23
  importKey,
23
24
  inheritedFromSessionId,
@@ -27,6 +28,8 @@ import {
27
28
  workspaceSummary,
28
29
  } from './store-summary-fields.mjs';
29
30
  import { isRealTurnMessage } from './compact/user-message-kind.mjs';
31
+ import { isRoutineResultMessage, normalizeRoutineProvenance, routineProvenance } from './routine-result.mjs';
32
+ import { LAST_MESSAGE_PREVIEW_MAX, cleanSummaryPreview, lastMessageRawText } from './store-summary-last-message.mjs';
30
33
 
31
34
  export const SESSION_SUMMARY_INDEX_VERSION = 2;
32
35
 
@@ -37,15 +40,7 @@ export function summaryIndexPath() {
37
40
  return join(getPluginData(), 'session-summaries.json');
38
41
  }
39
42
 
40
- function _computeCleanPreview(text, max) {
41
- const value = cleanSessionPreview(text, max);
42
- return value.length > max
43
- ? value
44
- .slice(0, max)
45
- .replace(/\s+\S*$/, '')
46
- .trim()
47
- : value;
48
- }
43
+ const _computeCleanPreview = cleanSummaryPreview;
49
44
 
50
45
  // Every index flush re-normalizes EVERY row's stored title and preview, and
51
46
  // cleaning runs a chain of regex replaces that each allocate a copy. Those
@@ -79,8 +74,13 @@ const sessionMessageProjectionMemo = new WeakMap();
79
74
  // re-cleaned.
80
75
  const messagePreviewMemo = new WeakMap();
81
76
 
77
+ // Routine results (a schedule's output in its owner's home thread) follow ONE
78
+ // rule here: each is exactly one message of `messageCount` (so a thread's
79
+ // unread count, messageCount minus the read cursor, rises by one per result),
80
+ // never a real turn (`realTurnCount`), never the first-prompt `preview` the
81
+ // title falls back to, and shown as its notice line in `lastMessagePreview`.
82
82
  function _previewFromMessage(message) {
83
- if (message?.role !== 'user') return '';
83
+ if (message?.role !== 'user' || isRoutineResultMessage(message)) return '';
84
84
  const raw = sessionMessageText(message.content);
85
85
  const memo = messagePreviewMemo.get(message);
86
86
  if (memo && memo.raw === raw) return memo.preview;
@@ -89,6 +89,20 @@ function _previewFromMessage(message) {
89
89
  return preview;
90
90
  }
91
91
 
92
+ // message → { raw, preview } for the LAST conversational message, user or
93
+ // assistant alike (a messenger row's last-message line).
94
+ const lastMessagePreviewMemo = new WeakMap();
95
+
96
+ function _lastPreviewFromMessage(message) {
97
+ const raw = lastMessageRawText(message);
98
+ if (raw === null) return '';
99
+ const memo = lastMessagePreviewMemo.get(message);
100
+ if (memo && memo.raw === raw) return memo.preview;
101
+ const preview = isSessionPreviewNoise(raw) ? '' : _cleanPreview(raw, LAST_MESSAGE_PREVIEW_MAX);
102
+ lastMessagePreviewMemo.set(message, { raw, preview });
103
+ return preview;
104
+ }
105
+
92
106
  function _sessionMessageProjection(session) {
93
107
  const messages = Array.isArray(session?.messages) ? session.messages : [];
94
108
  const cached = session && typeof session === 'object' ? sessionMessageProjectionMemo.get(session) : null;
@@ -134,6 +148,17 @@ function _sessionMessageProjection(session) {
134
148
  }
135
149
  }
136
150
  }
151
+ // The newest line, read back from the tail every time: a streamed reply
152
+ // fills its message in place. Tool-only and synthetic rows are skipped, and
153
+ // each message's text is memoized, so this stays a few lookups per save.
154
+ // The line's routine provenance rides along, so a client labels a routine
155
+ // result by this marker and never by the line's wording.
156
+ let last = '';
157
+ let lastRoutine = null;
158
+ for (let index = messages.length - 1; index >= 0 && !last; index -= 1) {
159
+ last = _lastPreviewFromMessage(messages[index]);
160
+ if (last) lastRoutine = routineProvenance(messages[index]);
161
+ }
137
162
  if (session && typeof session === 'object') {
138
163
  sessionMessageProjectionMemo.set(session, {
139
164
  length: messages.length,
@@ -144,7 +169,7 @@ function _sessionMessageProjection(session) {
144
169
  previewMessage,
145
170
  });
146
171
  }
147
- return { count, real, preview };
172
+ return { count, real, preview, last, lastRoutine };
148
173
  }
149
174
 
150
175
  function _desktopSessionSummary(value, cwd = null) {
@@ -178,6 +203,8 @@ export function _sessionSummary(session) {
178
203
  status: String(session.status || (session.closed === true ? 'closed' : 'idle')),
179
204
  owner: session.owner || 'user',
180
205
  agent: session.agent || null,
206
+ // 'agent' | 'coding' (agent-mode.mjs); older records resolve it.
207
+ sessionMode: sessionModeOf(session),
181
208
  sourceType: session.sourceType || null,
182
209
  sourceName: session.sourceName || null,
183
210
  scopeKey: session.scopeKey || null,
@@ -209,6 +236,8 @@ export function _sessionSummary(session) {
209
236
  realTurnCount: messageProjection.real,
210
237
  title: _cleanPreview(session.title || '', 100),
211
238
  preview: messageProjection.preview,
239
+ lastMessagePreview: messageProjection.last,
240
+ lastMessageRoutine: messageProjection.lastRoutine,
212
241
  generation: typeof session.generation === 'number' ? session.generation : 0,
213
242
  storageMtimeMs: _positiveNumber(session.storageMtimeMs, 0),
214
243
  storageSize: _positiveNumber(session.storageSize, 0),
@@ -234,6 +263,7 @@ function _normalizeSummaryRow(row) {
234
263
  status: String(row.status || (row.closed === true ? 'closed' : 'idle')),
235
264
  owner: row.owner || 'user',
236
265
  agent: row.agent || null,
266
+ sessionMode: sessionModeOf(row),
237
267
  sourceType: row.sourceType || null,
238
268
  sourceName: row.sourceName || null,
239
269
  scopeKey: row.scopeKey || null,
@@ -264,6 +294,8 @@ function _normalizeSummaryRow(row) {
264
294
  realTurnCount: realTurnCount(row),
265
295
  title: _cleanPreview(row.title || '', 100),
266
296
  preview: _cleanPreview(row.preview || ''),
297
+ lastMessagePreview: _cleanPreview(row.lastMessagePreview || '', 160),
298
+ lastMessageRoutine: normalizeRoutineProvenance(row.lastMessageRoutine),
267
299
  generation: typeof row.generation === 'number' ? row.generation : 0,
268
300
  storageMtimeMs: _positiveNumber(row.storageMtimeMs, 0),
269
301
  storageSize: _positiveNumber(row.storageSize, 0),
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The summary's last-message line (a messenger row's preview): the newest
3
+ * user or assistant message with displayable text, and that line's routine
4
+ * provenance. Leaf module, shared by the summary index (store saves) and the
5
+ * catalog's strict file scan so both derive the same line.
6
+ */
7
+ import { cleanSessionPreview, isSessionPreviewNoise, sessionMessageText } from '../runtime-core/session-text.mjs';
8
+ import { plainPreviewText } from '../../../shared/plain-preview.mjs';
9
+ import { isRoutineResultMessage, routineProvenance, routineResultNotice } from './routine-result.mjs';
10
+
11
+ export const LAST_MESSAGE_PREVIEW_MAX = 160;
12
+
13
+ /** cleanSessionPreview cut back to a word boundary within `max`. */
14
+ export function cleanSummaryPreview(text, max) {
15
+ const value = cleanSessionPreview(text, max);
16
+ return value.length > max
17
+ ? value
18
+ .slice(0, max)
19
+ .replace(/\s+\S*$/, '')
20
+ .trim()
21
+ : value;
22
+ }
23
+
24
+ /** The raw text a conversational message contributes as the last line (a
25
+ * routine result: its notice line); null for any other message. */
26
+ export function lastMessageRawText(message) {
27
+ if (message?.role !== 'user' && message?.role !== 'assistant') return null;
28
+ return isRoutineResultMessage(message) ? routineResultNotice(message).text : sessionMessageText(message.content);
29
+ }
30
+
31
+ /** The message's last-message line, '' when it has none (tool-only, synthetic). */
32
+ export function lastMessageLine(message) {
33
+ const raw = lastMessageRawText(message);
34
+ if (raw === null || isSessionPreviewNoise(raw)) return '';
35
+ return cleanSummaryPreview(plainPreviewText(raw), LAST_MESSAGE_PREVIEW_MAX);
36
+ }
37
+
38
+ /** `{ lastMessagePreview, lastMessageRoutine }` of a transcript. */
39
+ export function lastMessageSummary(messages) {
40
+ const list = Array.isArray(messages) ? messages : [];
41
+ for (let index = list.length - 1; index >= 0; index -= 1) {
42
+ const line = lastMessageLine(list[index]);
43
+ if (line) return { lastMessagePreview: line, lastMessageRoutine: routineProvenance(list[index]) };
44
+ }
45
+ return { lastMessagePreview: '', lastMessageRoutine: null };
46
+ }
@@ -24,6 +24,7 @@ import {
24
24
  } from './store-summary-catalog.mjs';
25
25
  import { createStoredTranscriptCache, nextProjectionStamp } from './store-transcript-cache.mjs';
26
26
  import {
27
+ forgetStoredTranscriptOffThread,
27
28
  OFFLOAD_MIN_CHARS,
28
29
  projectStoredTranscriptOffThread,
29
30
  storedTranscriptWorkerRunning,
@@ -35,6 +36,7 @@ import { readArchivedAgentResult } from './store-summary-archived-agent.mjs';
35
36
  import { compactionArchivePath, readCompactionArchivePage } from './compaction-archive.mjs';
36
37
  import { currentSessionCatalogDb, onSessionCatalogDbChange, sessionCatalogDb } from './catalog-db/index.mjs';
37
38
  import { decodeCatalogCursor, encodeCatalogCursor, isAfterCursor } from './catalog-db/schema.mjs';
39
+ import { onSessionActivityChange } from '../../../shared/session-activity-signal.mjs';
38
40
  import {
39
41
  readCanonicalSessionRecord as readCanonicalLifecycle,
40
42
  offerStrictSessionRecord,
@@ -45,7 +47,11 @@ import {
45
47
  // Worker-pool row projection (child + Lead indexes, live-work evidence) lives
46
48
  // in store-agent-worker-rows.mjs; re-exported so prior importers of this
47
49
  // module stay unchanged.
48
- export { listStoredAgentWorkerLinks, listStoredAgentWorkers } from './store-agent-worker-rows.mjs';
50
+ export {
51
+ listStoredAgentWorkerLinks,
52
+ listStoredAgentWorkers,
53
+ listStoredAgentWorkersAsync,
54
+ } from './store-agent-worker-rows.mjs';
49
55
  export { storedAgentWorkerIndexPath } from './store-summary-locations.mjs';
50
56
 
51
57
  // One cache per process: the daemon serves every cold pane read from it, and
@@ -59,7 +65,9 @@ export function clearStoredTranscriptCache() {
59
65
 
60
66
  /** Drop one session's cold projections: it went live, or its last view left. */
61
67
  export function forgetStoredSessionTranscript(sessionId) {
62
- storedTranscriptCache.forget(`${String(sessionId || '').trim()}|`);
68
+ const id = String(sessionId || '').trim();
69
+ storedTranscriptCache.forget(`${id}|`);
70
+ if (id) forgetStoredTranscriptOffThread(id);
63
71
  }
64
72
 
65
73
  /** Its last view left: keep the cold projections for a revisit, within the
@@ -82,18 +90,22 @@ export function storedTranscriptCacheStats() {
82
90
  const ordinaryCatalog = createOrdinaryCatalog();
83
91
  const catalogListeners = new Set();
84
92
 
85
- function notifyCatalogListeners() {
93
+ function notifyCatalogListeners(kind = 'catalog') {
86
94
  for (const listener of catalogListeners) {
87
95
  try {
88
- listener();
96
+ listener(kind);
89
97
  } catch {
90
98
  /* a listener's failure is its own */
91
99
  }
92
100
  }
93
101
  }
94
102
 
95
- ordinaryCatalog.subscribe(notifyCatalogListeners);
96
- onSessionCatalogDbChange(notifyCatalogListeners);
103
+ ordinaryCatalog.subscribe(() => notifyCatalogListeners());
104
+ onSessionCatalogDbChange(() => notifyCatalogListeners());
105
+ // Runtime activity transitions (turn start/settle, task wait, background
106
+ // hand-off/finish) change only the Agents pool projection: `agent-activity`
107
+ // lets the reader refresh just that, at once.
108
+ onSessionActivityChange(() => notifyCatalogListeners('agent-activity'));
97
109
 
98
110
  /** `listener()` runs when a background pass finds a session file that changed
99
111
  * without a directory or index change, i.e. when an ordinary listing would
@@ -292,29 +304,32 @@ export function storedSessionTranscriptStamp(id) {
292
304
  return archive ? `${record}|${checkpoint}|${archive}` : null;
293
305
  }
294
306
 
307
+ /** A large record with no checkpoint sidecar is read, digested, parsed and
308
+ * projected on a worker thread: the same pipeline, off the daemon event
309
+ * loop. It hands no parse to the load cache (a later resume reads the file
310
+ * itself). The answer is the cache's `project` contract; a worker failure
311
+ * rejects and the cache runs the in-process pipeline instead. */
312
+ async function projectStoredTranscriptElsewhere(known, context) {
313
+ const { sessionId, recordPath, itemLimit, timing } = context;
314
+ timing.worker = storedTranscriptWorkerRunning(sessionId) ? 'warm' : 'cold';
315
+ const workerStartedAt = performance.now();
316
+ const answer = await projectStoredTranscriptOffThread({ sessionId, recordPath, itemLimit, known });
317
+ timing.workerMs = performance.now() - workerStartedAt;
318
+ Object.assign(timing, answer.timing);
319
+ context.readState = answer.state;
320
+ if (answer.state !== PROBE_PRESENT) return null;
321
+ if (answer.same) return answer;
322
+ if (answer.unreadable) return { ...answer, value: null };
323
+ if (answer.stamp) readCanonicalLifecycle.rememberStrictVerdict(recordPath, answer.stamp, answer.lifecycle);
324
+ // Stamps are process-unique per module realm; re-issue in this one.
325
+ answer.value.projectionStamp = nextProjectionStamp();
326
+ return answer;
327
+ }
328
+
295
329
  /** Projects the strictly parsed record `text` (read at full stamp `stamp`, or
296
330
  * null when not provably stable) into the cached transcript value. */
297
331
  async function produceStoredTranscript(text, stamp, context) {
298
- const { sessionId, recordPath, itemLimit, includeMessages, mode, offloadable, checkpointAbsent, timing } = context;
299
- // A large record with no checkpoint sidecar parses and projects on a
300
- // worker thread: the same pipeline, off the daemon event loop. It hands
301
- // no parse to the load cache (a later resume reads the file itself).
302
- if (offloadable && text.length >= OFFLOAD_MIN_CHARS) {
303
- try {
304
- timing.worker = storedTranscriptWorkerRunning() ? 'warm' : 'cold';
305
- const workerStartedAt = performance.now();
306
- const answer = await projectStoredTranscriptOffThread({ sessionId, text, itemLimit });
307
- timing.workerMs = performance.now() - workerStartedAt;
308
- Object.assign(timing, answer.timing);
309
- if (answer.unreadable) return null;
310
- if (stamp) readCanonicalLifecycle.rememberStrictVerdict(recordPath, stamp, answer.lifecycle);
311
- // Stamps are process-unique per module realm; re-issue in this one.
312
- answer.value.projectionStamp = nextProjectionStamp();
313
- return answer.value;
314
- } catch {
315
- // Worker unavailable: fall through to the in-process pipeline.
316
- }
317
- }
332
+ const { sessionId, recordPath, itemLimit, includeMessages, mode, checkpointAbsent, timing } = context;
318
333
  const parseStartedAt = performance.now();
319
334
  const record = readTopLevelLifecycleRecord(text);
320
335
  timing.parseMs = performance.now() - parseStartedAt;
@@ -388,7 +403,6 @@ export async function readStoredSessionTranscript(id, options = {}) {
388
403
  const archive = probePath(archivePath);
389
404
  const requestedLimit = Number(options.transcriptItemLimit);
390
405
  const itemLimit = Number.isFinite(requestedLimit) && requestedLimit > 0 ? requestedLimit : Number.POSITIVE_INFINITY;
391
- let readState = PROBE_PRESENT;
392
406
  // Full stamp the loaded text provably came from (unchanged around the
393
407
  // read), or null. Only such a parse may serve other readers.
394
408
  let readStamp = null;
@@ -405,9 +419,10 @@ export async function readStoredSessionTranscript(id, options = {}) {
405
419
  itemLimit,
406
420
  includeMessages,
407
421
  mode,
408
- offloadable,
409
422
  checkpointAbsent,
410
423
  timing,
424
+ // How the record read went (the worker's read or loadText below).
425
+ readState: PROBE_PRESENT,
411
426
  };
412
427
  const { value, hit, read } = await storedTranscriptCache.read({
413
428
  key: `${sessionId}|${itemLimit}|${mode}`,
@@ -425,6 +440,7 @@ export async function readStoredSessionTranscript(id, options = {}) {
425
440
  archive.size,
426
441
  ].join(':'),
427
442
  fileStat: recordStat,
443
+ project: offloadable ? (known) => projectStoredTranscriptElsewhere(known, produceContext) : null,
428
444
  loadText: async () => {
429
445
  const readStartedAt = performance.now();
430
446
  const before = observeStamp(recordPath);
@@ -440,7 +456,7 @@ export async function readStoredSessionTranscript(id, options = {}) {
440
456
  }
441
457
  body ||= readTextFile(recordPath);
442
458
  timing.readMs = performance.now() - readStartedAt;
443
- readState = body.state;
459
+ produceContext.readState = body.state;
444
460
  if (body.state !== PROBE_PRESENT) return null;
445
461
  readStamp = before && sameSessionStamp(before, observeStamp(recordPath)) ? before : null;
446
462
  return body.text;
@@ -448,7 +464,7 @@ export async function readStoredSessionTranscript(id, options = {}) {
448
464
  produce: (text) => produceStoredTranscript(text, readStamp, produceContext),
449
465
  });
450
466
  // The record vanished between stat and read: same answer as an absent probe.
451
- if (readState === PROBE_ABSENT) return readVanishedSessionTranscript(sessionId);
467
+ if (produceContext.readState === PROBE_ABSENT) return readVanishedSessionTranscript(sessionId);
452
468
  if (typeof options.trace === 'function') {
453
469
  options.trace({
454
470
  sessionId,
@@ -49,7 +49,3 @@ export function sessionVisibility(value) {
49
49
  export function isAgentOnlySession(value) {
50
50
  return sessionVisibility(value) === SESSION_VISIBILITY_AGENT_ONLY;
51
51
  }
52
-
53
- export function isOrdinarySession(value) {
54
- return !isAgentOnlySession(value);
55
- }