mixdog 1.4.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/package.json +2 -2
  2. package/scripts/build-shipped-history.mjs +15 -5
  3. package/scripts/gate-local.mjs +65 -19
  4. package/scripts/graph-parity.mjs +8 -3
  5. package/scripts/lib/gate-scheduler.mjs +2 -1
  6. package/scripts/lib/run-node-tests.mjs +17 -5
  7. package/scripts/lib/test-failure-summary.mjs +1 -8
  8. package/scripts/lib/test-spawn-ledger.mjs +33 -2
  9. package/scripts/post-release-check.mjs +26 -16
  10. package/scripts/provider-pingpong-live.mjs +1 -1
  11. package/scripts/prune-embedding-runtime.mjs +3 -1
  12. package/scripts/release-paths.mjs +7 -1
  13. package/src/defaults/shipped-history.json +20 -0
  14. package/src/defaults/skills/setup/SKILL.md +2 -2
  15. package/src/defaults/skills/setup/references/actions.md +16 -3
  16. package/src/defaults/skills/setup/references/surfaces.md +3 -0
  17. package/src/defaults/skills/setup-guide/SKILL.md +6 -1
  18. package/src/lib/instruction-text.cjs +36 -0
  19. package/src/lib/rules-builder.cjs +34 -20
  20. package/src/orchestration/balanced.md +23 -0
  21. package/src/orchestration/focused.md +22 -0
  22. package/src/orchestration/none.md +5 -0
  23. package/src/orchestration/swarm.md +24 -0
  24. package/src/rules/agent-mode/AGENT_MODE.md +3 -1
  25. package/src/rules/agent-mode/MIXY.md +2 -2
  26. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +3 -3
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +0 -1
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +4 -2
  29. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +0 -9
  30. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +2 -2
  31. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +67 -0
  32. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
  33. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +4 -4
  34. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -1
  35. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +199 -46
  36. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +3 -5
  37. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +9 -3
  38. package/src/runtime/agent/orchestrator/mcp/client.mjs +3 -5
  39. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +1 -1
  40. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +8 -2
  41. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +1 -1
  42. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +14 -0
  43. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  45. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-stop.mjs +3 -3
  46. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  47. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +2 -2
  48. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +4 -6
  49. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2784 -2872
  50. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +5 -8
  51. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +288 -300
  52. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +10 -1
  53. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +10 -30
  54. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +30 -0
  55. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +0 -11
  56. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +8 -0
  57. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +17 -3
  58. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +47 -27
  59. package/src/runtime/agent/orchestrator/runtime-core/goal-deadlines.mjs +141 -10
  60. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +26 -63
  61. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +28 -3
  62. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +36 -11
  63. package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +88 -56
  64. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +4 -1
  65. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +51 -32
  66. package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +45 -145
  67. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +15 -98
  68. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +32 -99
  69. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +23 -78
  70. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +69 -48
  71. package/src/runtime/agent/orchestrator/runtime-core/todo-list.mjs +367 -0
  72. package/src/runtime/agent/orchestrator/runtime-core/todo-tool-defs.mjs +47 -0
  73. package/src/runtime/agent/orchestrator/runtime-core/tool-availability.mjs +155 -0
  74. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +9 -0
  75. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +119 -35
  76. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +28 -22
  79. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +30 -0
  80. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +1 -1
  81. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +2 -2
  82. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -2
  83. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +1 -1
  84. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -1
  85. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +3 -0
  86. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +1 -1
  87. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -12
  88. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +1 -1
  89. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +1 -1
  90. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +7 -3
  92. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +1 -1
  93. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +1 -2
  94. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +1 -1
  95. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +11 -1
  97. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +1 -1
  98. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
  99. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/todo-check.mjs +196 -0
  100. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +116 -50
  101. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +8 -1
  102. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +1 -1
  103. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +1 -1
  104. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -1
  105. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +5 -6
  106. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +6 -1
  107. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  108. package/src/runtime/agent/orchestrator/session/loop/turn-report.mjs +35 -0
  109. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +57 -26
  111. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +9 -7
  112. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +21 -3
  113. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +27 -11
  114. package/src/runtime/agent/orchestrator/session/manager/ask-turn-open.mjs +37 -34
  115. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +15 -0
  116. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +25 -15
  117. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +79 -24
  118. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +3 -0
  119. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +12 -1
  120. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
  121. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +6 -1
  122. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +9 -1
  123. package/src/runtime/agent/orchestrator/session/manager/pending-spool-path.mjs +2 -2
  124. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +1 -1
  125. package/src/runtime/agent/orchestrator/session/manager/prompt-settings.mjs +598 -0
  126. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +19 -0
  127. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +19 -10
  128. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +5 -0
  129. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +1 -1
  130. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +31 -0
  131. package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +31 -0
  132. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +42 -6
  133. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +2 -0
  134. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +11 -1
  135. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +8 -9
  136. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +339 -88
  137. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +135 -11
  138. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +377 -104
  139. package/src/runtime/agent/orchestrator/session/manager/turn-durability.mjs +144 -0
  140. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +1 -1
  141. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +4 -0
  142. package/src/runtime/agent/orchestrator/session/manager.mjs +6 -0
  143. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +8 -1
  145. package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +5 -1
  146. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +2 -2
  148. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +23 -2
  149. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +3 -3
  150. package/src/runtime/agent/orchestrator/session/store/transcript-durability.mjs +88 -0
  151. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +5 -0
  152. package/src/runtime/agent/orchestrator/session/store-summary-log.mjs +1 -1
  153. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +14 -5
  154. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +2 -2
  155. package/src/runtime/agent/orchestrator/session/store.mjs +5 -0
  156. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +7 -1
  157. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +9 -1
  158. package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
  159. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -1
  160. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +2 -2
  161. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -5
  162. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -1
  163. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +21 -3
  164. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  165. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/worktree-add-guard.mjs +77 -0
  166. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -1
  167. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +7 -3
  168. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +27 -9
  169. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +2 -2
  170. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +0 -1
  172. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +0 -10
  173. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +1 -2
  174. package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -24
  175. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary/child-kill.mjs +4 -3
  176. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +1 -2
  177. package/src/runtime/agent/orchestrator/tools/code-graph/modes/calls.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/tools/code-graph/modes/symbols.mjs +2 -2
  179. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +4 -5
  180. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +3 -4
  181. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4 -22
  182. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +2 -2
  183. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +1 -1
  184. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +0 -4
  185. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +0 -1
  186. package/src/runtime/attachments/attachment-reference.mjs +1 -1
  187. package/src/runtime/attachments/pdf-extract.mjs +1 -1
  188. package/src/runtime/attachments/store.d.mts +1 -0
  189. package/src/runtime/attachments/store.mjs +2 -2
  190. package/src/runtime/channels/lib/config-reload-watch.mjs +42 -0
  191. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +29 -9
  192. package/src/runtime/channels/lib/scheduler.mjs +33 -0
  193. package/src/runtime/channels/lib/schedules-db.mjs +11 -4
  194. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +4 -1
  195. package/src/runtime/channels/lib/webhooks-db.mjs +9 -3
  196. package/src/runtime/channels/lib/whisper-server.mjs +12 -12
  197. package/src/runtime/channels/lib/worker-main.mjs +9 -31
  198. package/src/runtime/computer-bridge/linux-readiness.mjs +10 -14
  199. package/src/runtime/connectors/connector-accounts-mcp.mjs +169 -33
  200. package/src/runtime/connectors/gmail-app-password.mjs +2 -2
  201. package/src/runtime/connectors/google-mcp.mjs +1 -1
  202. package/src/runtime/effort-judge/judge-client.mjs +2 -2
  203. package/src/runtime/effort-judge/judge-input.mjs +4 -4
  204. package/src/runtime/explore/explorer.mjs +0 -5
  205. package/src/runtime/explore/tool.mjs +3 -3
  206. package/src/runtime/local-provider/hardware.mjs +1 -1
  207. package/src/runtime/media/adapters/codex-image.mjs +3 -3
  208. package/src/runtime/media/adapters/gemini-video.mjs +1 -1
  209. package/src/runtime/media/media-usage.mjs +1 -1
  210. package/src/runtime/media/store.mjs +1 -1
  211. package/src/runtime/memory/index.mjs +11 -1
  212. package/src/runtime/memory/lib/embedding-reindex.mjs +27 -0
  213. package/src/runtime/memory/lib/memory-embed.mjs +83 -14
  214. package/src/runtime/memory/lib/memory-process-lock.mjs +159 -36
  215. package/src/runtime/memory/lib/memory-text-utils.mjs +6 -1
  216. package/src/runtime/memory/lib/memory.mjs +17 -0
  217. package/src/runtime/memory/lib/pg/process.mjs +1 -1
  218. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -96
  219. package/src/runtime/memory/lib/recall-hybrid/hybrid-sql.mjs +12 -3
  220. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  221. package/src/runtime/office/authoring/pptx-author-action.mjs +1 -1
  222. package/src/runtime/office/authoring/xlsx-html-build.mjs +1 -1
  223. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  224. package/src/runtime/office/capabilities.mjs +1 -1
  225. package/src/runtime/office/core/office-core.mjs +1 -1
  226. package/src/runtime/office/design/content-model.mjs +3 -3
  227. package/src/runtime/office/design/docx/design-docx/section.mjs +6 -6
  228. package/src/runtime/office/design/xlsx/design-xlsx-components.mjs +1 -1
  229. package/src/runtime/office/design/xlsx/design-xlsx.mjs +1 -1
  230. package/src/runtime/office/pdf/ocr-engine.mjs +1 -1
  231. package/src/runtime/office/pdf/pdf-writer.mjs +4 -4
  232. package/src/runtime/office/portable/portable-docx-operations.mjs +2 -2
  233. package/src/runtime/office/portable/portable-soffice.mjs +8 -6
  234. package/src/runtime/office/portable/xlsx-contract.mjs +1 -1
  235. package/src/runtime/shared/atomic-file.d.mts +8 -0
  236. package/src/runtime/shared/background-tasks.mjs +22 -4
  237. package/src/runtime/shared/background-wait.mjs +66 -0
  238. package/src/runtime/shared/child-guardian.mjs +17 -7
  239. package/src/runtime/shared/config.mjs +313 -16
  240. package/src/runtime/shared/connector-catalog.d.mts +4 -5
  241. package/src/runtime/shared/connector-catalog.mjs +11 -1
  242. package/src/runtime/shared/file-lock.mjs +8 -3
  243. package/src/runtime/shared/git-runner.mjs +7 -2
  244. package/src/runtime/shared/idle-gc.mjs +30 -7
  245. package/src/runtime/shared/llm/http-agent.mjs +8 -5
  246. package/src/runtime/shared/llm/system-proxy.mjs +2 -1
  247. package/src/runtime/shared/llm/usage-ledger-quota.mjs +31 -12
  248. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +84 -8
  249. package/src/runtime/shared/llm/usage-ledger.mjs +3 -0
  250. package/src/runtime/shared/llm/usage-rollup.mjs +48 -0
  251. package/src/runtime/shared/maintenance-schedule.mjs +109 -0
  252. package/src/runtime/shared/process-runner.mjs +8 -4
  253. package/src/runtime/shared/routine-trigger.d.mts +13 -0
  254. package/src/runtime/shared/routine-trigger.mjs +34 -0
  255. package/src/runtime/shared/run-child.d.mts +2 -1
  256. package/src/runtime/shared/run-child.mjs +70 -18
  257. package/src/runtime/shared/session-scratch.mjs +14 -2
  258. package/src/runtime/shared/shipped-definitions.mjs +7 -1
  259. package/src/runtime/shared/tool-card-model.golden.json +3 -12
  260. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  261. package/src/runtime/shared/tool-work-units.mjs +31 -6
  262. package/src/runtime/shared/turn-snapshot.mjs +26 -4
  263. package/src/runtime/shared/turn-worktree-snapshot.mjs +6 -11
  264. package/src/runtime/shared/worker-requests.mjs +17 -3
  265. package/src/runtime/shared/worktrees/branch-management.mjs +1 -5
  266. package/src/runtime/shared/worktrees/contract.mjs +16 -6
  267. package/src/runtime/shared/worktrees/dependencies.mjs +127 -89
  268. package/src/runtime/shared/worktrees/disk.mjs +79 -2
  269. package/src/runtime/shared/worktrees/git.mjs +44 -11
  270. package/src/runtime/shared/worktrees/include.mjs +6 -4
  271. package/src/runtime/shared/worktrees/maintenance.mjs +422 -30
  272. package/src/runtime/shared/worktrees/manager.mjs +772 -75
  273. package/src/runtime/shared/worktrees/settings.mjs +33 -7
  274. package/src/runtime/shared/worktrees/test-support.mjs +5 -1
  275. package/src/runtime/shared/worktrees/worker-snapshots.mjs +82 -0
  276. package/src/runtime/tidy/process.mjs +2 -1
  277. package/src/runtime/web-search/index.mjs +3 -22
  278. package/src/runtime/web-search/lib/web-tools.mjs +2 -2
  279. package/src/runtime/web-search/tool-defs.mjs +17 -26
  280. package/src/session-runtime/agent-profile-changes.mjs +55 -4
  281. package/src/session-runtime/boot/apis.mjs +27 -4
  282. package/src/session-runtime/boot/begin.mjs +2 -0
  283. package/src/session-runtime/boot/config.mjs +10 -1
  284. package/src/session-runtime/boot/facade.mjs +1 -0
  285. package/src/session-runtime/boot/providers.mjs +70 -3
  286. package/src/session-runtime/boot/session.mjs +2 -0
  287. package/src/session-runtime/boot/tools.mjs +69 -25
  288. package/src/session-runtime/channel-config-api.mjs +1 -0
  289. package/src/session-runtime/config-change-effects.mjs +179 -0
  290. package/src/session-runtime/config-lifecycle/config-writers.mjs +1 -0
  291. package/src/session-runtime/config-lifecycle.mjs +160 -24
  292. package/src/session-runtime/conversation-import/discovery.mjs +86 -7
  293. package/src/session-runtime/conversation-import/service.mjs +3 -2
  294. package/src/session-runtime/goal-facade-api.mjs +49 -3
  295. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +3 -0
  296. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -2
  297. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +3 -11
  298. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +18 -4
  299. package/src/session-runtime/internal-tool-executor.mjs +12 -19
  300. package/src/session-runtime/lifecycle/cold-heir.mjs +7 -0
  301. package/src/session-runtime/lifecycle/memory-ingest.mjs +3 -3
  302. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +53 -5
  303. package/src/session-runtime/lifecycle/session-switch.mjs +13 -2
  304. package/src/session-runtime/lifecycle/teardown/session-close.mjs +4 -4
  305. package/src/session-runtime/lifecycle-api.mjs +1 -0
  306. package/src/session-runtime/mcp-glue/server-catalog.mjs +14 -3
  307. package/src/session-runtime/mcp-glue/server-connection.mjs +34 -8
  308. package/src/session-runtime/model-route/set-route.mjs +40 -7
  309. package/src/session-runtime/native-web-search/routes.mjs +3 -3
  310. package/src/session-runtime/provider-auth/refresh.mjs +6 -3
  311. package/src/session-runtime/provider-auth/setup.mjs +1 -1
  312. package/src/session-runtime/provider-readiness.mjs +53 -4
  313. package/src/session-runtime/resource-api.mjs +1 -1
  314. package/src/session-runtime/resource-extension-sync.mjs +4 -8
  315. package/src/session-runtime/resource-mcp-connector-accounts.mjs +5 -1
  316. package/src/session-runtime/resource-mcp-secrets.mjs +3 -3
  317. package/src/session-runtime/resource-plugins-api.mjs +4 -0
  318. package/src/session-runtime/routine-executor.mjs +152 -0
  319. package/src/session-runtime/routine-home-turn.mjs +46 -5
  320. package/src/session-runtime/runtime-facade.mjs +5 -0
  321. package/src/session-runtime/runtime-feature-gates.mjs +2 -11
  322. package/src/session-runtime/schedule-session-run.mjs +1 -0
  323. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +6 -1
  324. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +7 -0
  325. package/src/session-runtime/services/agent-tool/send-flow.mjs +110 -6
  326. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +12 -0
  327. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +5 -0
  328. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +24 -6
  329. package/src/session-runtime/services/agent-tool.mjs +51 -1
  330. package/src/session-runtime/services/channel-admin.mjs +18 -0
  331. package/src/session-runtime/services/hook-bus/command-handler.mjs +7 -11
  332. package/src/session-runtime/services/plugin-admin.mjs +4 -0
  333. package/src/session-runtime/services/seeds.mjs +7 -0
  334. package/src/session-runtime/services/usage-stats-model.mjs +32 -11
  335. package/src/session-runtime/session-create/materialize.mjs +4 -2
  336. package/src/session-runtime/session-create/session-options.mjs +2 -0
  337. package/src/session-runtime/settings-builtin-tools-api.mjs +1 -9
  338. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +1 -1
  339. package/src/session-runtime/setup-tool/executor.mjs +8 -1
  340. package/src/session-runtime/setup-tool/extended-actions.mjs +2 -0
  341. package/src/session-runtime/setup-tool/settings-contract.mjs +28 -0
  342. package/src/session-runtime/setup-tool/tool-defs.mjs +26 -1
  343. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +40 -43
  344. package/src/session-runtime/tool-policy/mode-switch.mjs +1 -1
  345. package/src/session-runtime/tool-policy/policy-stage.mjs +106 -8
  346. package/src/session-runtime/tool-policy/workflow-overlay.mjs +2 -1
  347. package/src/session-runtime/tool-policy-refresh.mjs +182 -5
  348. package/src/session-runtime/tool-surface.mjs +38 -1
  349. package/src/session-runtime/turn/agent-ops.mjs +10 -2
  350. package/src/session-runtime/turn/session-ops.mjs +2 -0
  351. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +5 -0
  352. package/src/session-runtime/turn/turn-run.mjs +1 -1
  353. package/src/session-runtime/webhook-session-run.mjs +2 -0
  354. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +1 -4
  355. package/src/session-runtime/workflow-agents-api/agent-route.mjs +3 -10
  356. package/src/session-runtime/workflow-agents-api/instruction-files.mjs +165 -0
  357. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +5 -4
  358. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +2 -3
  359. package/src/session-runtime/workflow-agents-api.mjs +2 -0
  360. package/src/session-runtime/workspace/project-branches.mjs +1 -1
  361. package/src/session-runtime/workspace/session-view.mjs +1 -1
  362. package/src/session-runtime/workspace/transitions.mjs +20 -4
  363. package/src/session-runtime/workspace/worktree-maintenance.mjs +126 -6
  364. package/src/session-runtime/workspace/worktree-setup.mjs +13 -1
  365. package/src/session-runtime/workspace/worktree-tool.mjs +16 -0
  366. package/src/standalone/daemon-agent-control.mjs +25 -8
  367. package/src/standalone/daemon-desktop-runtime.mjs +6 -2
  368. package/src/standalone/daemon-lag-profiler.mjs +7 -7
  369. package/src/standalone/daemon.mjs +54 -2
  370. package/src/standalone/local-session-runtime.mjs +16 -0
  371. package/src/standalone/session-client/daemon-unavailable.mjs +1 -1
  372. package/src/standalone/session-protocol.mjs +11 -0
  373. package/src/standalone/session-service/agent-route-follow.mjs +23 -20
  374. package/src/standalone/session-service/agent-tree/agent-turns.mjs +18 -6
  375. package/src/standalone/session-service/quota-resume.mjs +9 -0
  376. package/src/standalone/session-service/session-calls/session-action.mjs +51 -1
  377. package/src/standalone/session-service/session-calls/session-turns.mjs +37 -18
  378. package/src/standalone/session-service/session-calls/turn-gate.mjs +34 -0
  379. package/src/standalone/session-service/session-calls.mjs +2 -1
  380. package/src/tui/App.jsx +8 -0
  381. package/src/tui/app/clipboard.mjs +1 -1
  382. package/src/tui/app/create-app-pickers.mjs +2 -0
  383. package/src/tui/app/doctor.mjs +2 -2
  384. package/src/tui/app/panel-signature.mjs +1 -1
  385. package/src/tui/app/settings-picker.mjs +53 -8
  386. package/src/tui/app/shell-layout/row-budgets.mjs +2 -2
  387. package/src/tui/app/slash-commands.mjs +1 -1
  388. package/src/tui/app/slash-dispatch/route-commands.mjs +1 -1
  389. package/src/tui/app/slash-dispatch/session-commands.mjs +1 -1
  390. package/src/tui/app/use-prompt-queue-history.mjs +2 -2
  391. package/src/tui/app/use-transcript-activity.mjs +1 -1
  392. package/src/tui/app/use-transcript-window/geometry.mjs +1 -1
  393. package/src/tui/components/prompt-input/escape-policy.d.mts +0 -1
  394. package/src/tui/components/prompt-input/escape-policy.mjs +1 -1
  395. package/src/tui/components/question-panel-model.mjs +4 -4
  396. package/src/tui/components/tool-execution/standard-card.jsx +3 -4
  397. package/src/tui/components/user-message-skills.mjs +1 -1
  398. package/src/tui/dist/index.mjs +309 -30
  399. package/src/tui/markdown/render-ansi.mjs +1 -1
  400. package/src/tui/session/agent-job-feed/notification-router.mjs +10 -0
  401. package/src/tui/session/agent-job-feed.mjs +2 -0
  402. package/src/tui/session/context-state.mjs +3 -0
  403. package/src/tui/session/quota-resume.mjs +1 -1
  404. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  405. package/src/tui/session/session-api/lifecycle/session-reset.mjs +7 -0
  406. package/src/tui/session/session-api/routes-agent-definitions.mjs +5 -0
  407. package/src/tui/session/session-api/worktree.mjs +13 -1
  408. package/src/tui/session/session-flow/drain.mjs +11 -14
  409. package/src/tui/session/tool-card-results/grouped-result.mjs +2 -2
  410. package/src/tui/session/turn-quiet.mjs +1 -1
  411. package/src/tui/session/turn.mjs +3 -0
  412. package/src/tui/session/worktree-setup-notice.mjs +1 -1
  413. package/src/tui/spinner-meta.mjs +3 -3
  414. package/src/tui/spinner-verbs.mjs +2 -2
  415. package/src/defaults/skills/goal-management/SKILL.md +0 -169
  416. package/src/runtime/agent/orchestrator/runtime-core/goal-tasks.mjs +0 -156
  417. package/src/session-runtime/goal-tasks.mjs +0 -1
@@ -1,8 +1,10 @@
1
1
  // Deferred-tool catalog: measured-usage ordering, kind/bucket classification,
2
2
  // tool_search ranking + auto-selection, and the session tool-surface
3
3
  // application/selection logic. Pure module (session objects passed in).
4
+ import { createHash } from 'node:crypto';
4
5
  import { clean } from './session-text.mjs';
5
- import { mergePendingDeferredToolDelta } from './deferred-tool-delta.mjs';
6
+ import { dropPendingDeferredToolAdds, mergePendingDeferredToolDelta } from './deferred-tool-delta.mjs';
7
+ import { isAgentOwner } from '../agent-owner.mjs';
6
8
  import { applyInitialDeferredToolManifestToBp2 } from '../context/collect.mjs';
7
9
  import {
8
10
  listedDeferredToolNames,
@@ -12,7 +14,11 @@ import {
12
14
  import { parseMcpToolName } from '../../../shared/tool-primitives.mjs';
13
15
  import { getMcpServerInstructionsMap, getMcpTools, getMcpToolGeneration } from '../mcp/client.mjs';
14
16
  import { filterMcpToolsForSession } from './extension-scopes.mjs';
15
- import { isDeferredToolAvailable, isToolPermittedBySessionPolicy } from './deferred-tool-availability.mjs';
17
+ import {
18
+ isDeferredToolAvailable,
19
+ isToolPermittedBySessionPolicy,
20
+ sessionFeatureDenies,
21
+ } from './deferred-tool-availability.mjs';
16
22
  import { routeToolExclusionReason } from '../session/loop/provider-tool-exclusions.mjs';
17
23
  import { isResponsesFreeformTool, toResponsesCustomTool } from '../providers/custom-tool-wire.mjs';
18
24
  import {
@@ -46,21 +52,8 @@ import {
46
52
  toolExposureModeForProvider,
47
53
  } from './tool-exposure.mjs';
48
54
  import { TOOL_BRIDGE_TOOLS } from './tool-defs.mjs';
49
- export {
50
- toolKind,
51
- toolSchemaBucket,
52
- estimateToolSchemaBreakdown,
53
- measuredToolUsage,
54
- parseToolSelection,
55
- sortedCatalogByMeasuredUsage,
56
- } from './tool-catalog-schema.mjs';
55
+ export { estimateToolSchemaBreakdown } from './tool-catalog-schema.mjs';
57
56
  export { snapshotProviderRequestTools } from './provider-request-snapshot.mjs';
58
- export {
59
- DEFERRED_DEFAULT_FULL_TOOLS,
60
- DEFERRED_DEFAULT_LEAD_TOOLS,
61
- DEFERRED_DEFAULT_READONLY_TOOLS,
62
- MEASURED_TOOL_USAGE,
63
- } from './tool-catalog-data.mjs';
64
57
 
65
58
  // Provider modes without native tool search. Their bridge-v1 sessions
66
59
  // (tool-exposure.mjs) get the native roster and late delta notices; only a
@@ -548,24 +541,30 @@ export function rebuildDeferredToolSurfaceForProvider(session, provider) {
548
541
  // <available-deferred-tools> manifest IN PLACE and pre-mark names announced;
549
542
  // bridge-v1 sessions do the same (roster + bridge guidance). Only a fixed
550
543
  // surface not yet on the bridge updates its scoped catalog alone. Fully sync
551
- // and idempotent: no genuinely-new MCP name => no-op / no mutation.
544
+ // and idempotent: no MCP name added or gone => no-op / no mutation.
552
545
  export function refreshInitialDeferredMcpSurface(session, liveMcpTools) {
553
546
  if (!session || !Array.isArray(session.messages)) return false;
554
547
  if (session.deferredProviderMode === 'full') return false;
555
548
  const live = filterDisallowedTools(Array.isArray(liveMcpTools) ? liveMcpTools : [], session.disallowedTools);
549
+ const liveNames = new Set(live.map((tool) => clean(tool?.name)).filter(isMcpToolName));
556
550
  const byName = new Map();
551
+ // Nothing was sent yet: a server gone since create leaves the initial surface.
552
+ let changed = false;
557
553
  for (const tool of Array.isArray(session.deferredToolCatalog) ? session.deferredToolCatalog : []) {
558
554
  const name = clean(tool?.name);
555
+ if (isMcpToolName(name) && !liveNames.has(name)) {
556
+ changed = true;
557
+ continue;
558
+ }
559
559
  if (name && !byName.has(name)) byName.set(name, tool);
560
560
  }
561
- let added = false;
562
561
  for (const tool of live) {
563
562
  const name = clean(tool?.name);
564
563
  if (!name || !isMcpToolName(name) || byName.has(name)) continue;
565
564
  byName.set(name, activeToolForSurface(tool));
566
- added = true;
565
+ changed = true;
567
566
  }
568
- if (!added) return false;
567
+ if (!changed) return false;
569
568
  session.deferredToolCatalog = sortedCatalogByMeasuredUsage([...byName.values()]);
570
569
  if (fixedSurfaceSession(session)) {
571
570
  session.updatedAt = Date.now();
@@ -720,10 +719,12 @@ function reconcileDeferredMcpToolCatalogUncached(session, liveMcpTools) {
720
719
  // connected OR the tool is already loaded, including native history-only
721
720
  // discoveries. Availability is determined by deferredMcpToolNames, not this pool.
722
721
  const nextByName = new Map();
722
+ // A built-in a settings gate opened (tool-availability.mjs) is no MCP tool:
723
+ // its availability is the session's deny set, so it stays.
723
724
  for (const tool of lateCatalog) {
724
725
  const name = clean(tool?.name);
725
726
  if (!name || nextByName.has(name)) continue;
726
- if (!liveMcpByName.has(name) && !active.has(name)) continue;
727
+ if (isMcpToolName(name) && !liveMcpByName.has(name) && !active.has(name)) continue;
727
728
  nextByName.set(name, tool);
728
729
  }
729
730
  for (const [name, tool] of liveMcpByName) nextByName.set(name, tool);
@@ -773,28 +774,84 @@ function reconcileDeferredMcpToolCatalogUncached(session, liveMcpTools) {
773
774
  * connected tool the boot manifest never listed and the session has not loaded
774
775
  * or discovered rides the next real prompt as one more delta, acknowledged
775
776
  * only once the provider accepts that turn.
777
+ * Only a session whose prompt is never rebuilt at a cold point (a delegated
778
+ * worker, or a prompt without a recorded identity) is re-armed, by name; any
779
+ * other session folds its late tools into the rebuilt manifest instead
780
+ * (foldLateDeferredTools).
776
781
  * Returns the re-armed names, or null when there are none.
777
782
  */
778
783
  export function rearmLateDeferredTools(session) {
779
784
  // The compaction also drops the load results that carried a server's
780
- // instruction text, so the next load of its tools delivers it again.
781
- if (session) delete session.mcpInstructionsAnnounced;
785
+ // instruction text (the account and configuration guidance, which no prompt
786
+ // manifest carries), so the next load of its tools delivers it again. It
787
+ // rides a tool result, never the cached prefix, and ordinary turns still
788
+ // send it once.
789
+ if (session) {
790
+ delete session.mcpInstructionsAnnounced;
791
+ delete session.mcpInstructionHashes;
792
+ }
782
793
  if (!session || !Array.isArray(session.tools) || fixedSurfaceSession(session)) return null;
783
- if (!Array.isArray(session.deferredMcpToolNames) || !Array.isArray(session.deferredAnnouncedTools)) return null;
794
+ if (session.promptIdentity && !isAgentOwner(session)) return null;
795
+ if (!Array.isArray(session.deferredAnnouncedTools)) return null;
784
796
  // Listed in the boot manifest, or already loaded/discovered: still visible.
785
797
  const listed = new Set([...session.deferredAnnouncedTools, ...persistentToolSurfaceNames(session)]);
786
- const connected = new Set(session.deferredMcpToolNames);
798
+ const connected = new Set(Array.isArray(session.deferredMcpToolNames) ? session.deferredMcpToolNames : []);
787
799
  const added = [];
788
800
  for (const tool of Array.isArray(session.deferredLateToolCatalog) ? session.deferredLateToolCatalog : []) {
789
801
  const name = clean(tool?.name);
790
- if (!name || !connected.has(name) || listed.has(name) || !rosterPermits(session, tool)) continue;
791
- added.push({ name, description: lateAnnouncementDescription(tool?.description) });
802
+ if (!name || listed.has(name) || !rosterPermits(session, tool)) continue;
803
+ // MCP tools while connected; a built-in a settings gate opened while permitted.
804
+ if (isMcpToolName(name) ? !connected.has(name) : !isToolPermittedBySessionPolicy(session, name)) continue;
805
+ // Names only: the model was told the description before.
806
+ added.push({ name, description: '' });
792
807
  }
793
808
  if (!added.length) return null;
794
809
  mergePendingDeferredToolDelta(session, { added });
795
810
  return added.map((entry) => entry.name);
796
811
  }
797
812
 
813
+ /**
814
+ * A cold point (a compaction, a rebuilt prompt): the late tools join the boot
815
+ * catalog and the rebuilt BP2 manifest lists them, so nothing about them rides
816
+ * a notice. Pending
817
+ * announcements the manifest now carries are dropped. Returns the folded names.
818
+ */
819
+ export function foldLateDeferredTools(session) {
820
+ if (!session || !Array.isArray(session.tools) || fixedSurfaceSession(session)) return [];
821
+ const late = Array.isArray(session.deferredLateToolCatalog) ? session.deferredLateToolCatalog : [];
822
+ const connected = new Set(Array.isArray(session.deferredMcpToolNames) ? session.deferredMcpToolNames : []);
823
+ const byName = new Map();
824
+ for (const tool of Array.isArray(session.deferredToolCatalog) ? session.deferredToolCatalog : []) {
825
+ const name = clean(tool?.name);
826
+ if (name && !byName.has(name)) byName.set(name, tool);
827
+ }
828
+ const folded = [];
829
+ for (const tool of late) {
830
+ const name = clean(tool?.name);
831
+ if (!name || byName.has(name) || !rosterPermits(session, tool)) continue;
832
+ if (isMcpToolName(name) ? !connected.has(name) : !isToolPermittedBySessionPolicy(session, name)) continue;
833
+ byName.set(name, activeToolForSurface(tool));
834
+ folded.push(name);
835
+ }
836
+ session.deferredToolCatalog = sortedCatalogByMeasuredUsage([...byName.values()]);
837
+ // Whatever the boot catalog holds now (folded here, or by the rebuilt surface) leaves the late pool.
838
+ session.deferredLateToolCatalog = late.filter((tool) => !byName.has(clean(tool?.name)));
839
+ session.mcpServerInstructions = getMcpServerInstructionsMap(session.mcpScopeId);
840
+ if (Array.isArray(session.messages) && session.messages.some((m) => m?.role === 'system')) {
841
+ applyInitialDeferredToolManifestToBp2(session, deferredPoolToolNames(session), { rebuild: true });
842
+ session.deferredAnnouncedTools = listedDeferredToolNames(
843
+ session,
844
+ deferredPoolToolNames(session),
845
+ renderedDeferredManifest(session)
846
+ );
847
+ }
848
+ // The manifest lists only short triggers, never a server's instruction text:
849
+ // what a load has told stays as recorded (a compaction clears it).
850
+ const listed = new Set(Array.isArray(session.deferredAnnouncedTools) ? session.deferredAnnouncedTools : []);
851
+ dropPendingDeferredToolAdds(session, listed);
852
+ return folded;
853
+ }
854
+
798
855
  export function scopedMcpToolsFor(session, config = null) {
799
856
  return filterMcpToolsForSession(getMcpTools(session?.mcpScopeId), session?.cwd || null, config);
800
857
  }
@@ -916,24 +973,41 @@ function resolvableCatalog(session) {
916
973
  return filterSessionToolPolicy(tools, session);
917
974
  }
918
975
 
976
+ const instructionHash = (text) =>
977
+ createHash('sha256')
978
+ .update(String(text || ''))
979
+ .digest('hex')
980
+ .slice(0, 16);
981
+
919
982
  // A server's instruction text rides the first load_tool naming any of its
920
- // tools (loaded now, already active, or described on the bridge), once until
921
- // compaction (`mcpInstructionsAnnounced`; rearmLateDeferredTools clears it with
922
- // the transcript that held the text): `## <server>` + body, sanitized and
923
- // capped like the BP2 block it replaces. No text, nothing sent or recorded.
983
+ // tools (loaded now, already active, or described on the bridge), once per
984
+ // text (`mcpInstructionsAnnounced`, `mcpInstructionHashes`: a connector whose
985
+ // accounts changed sends its new text again; a compaction clears the record,
986
+ // rearmLateDeferredTools): `## <server>` + body,
987
+ // sanitized and capped (sanitizeMcpInstructionText, well under 4 KB). No
988
+ // text, nothing sent or recorded.
924
989
  function pendingMcpInstructions(session, catalog, names) {
925
990
  const map = session?.mcpServerInstructions;
926
991
  if (!map || typeof map !== 'object' || !names.length) return [];
927
992
  const byName = new Map(catalog.map((tool) => [clean(tool?.name), tool]));
928
993
  const announced = new Set(Array.isArray(session.mcpInstructionsAnnounced) ? session.mcpInstructionsAnnounced : []);
994
+ const hashes =
995
+ session.mcpInstructionHashes && typeof session.mcpInstructionHashes === 'object'
996
+ ? session.mcpInstructionHashes
997
+ : {};
998
+ const seen = new Set();
929
999
  const pending = [];
930
1000
  for (const name of names) {
931
1001
  const server = parseMcpToolName(byName.get(name) || name)?.server;
932
- if (!server || announced.has(server) || !mcpServerManifestLabel(server)) continue;
1002
+ if (!server || seen.has(server) || !mcpServerManifestLabel(server)) continue;
933
1003
  const text = sanitizeMcpInstructionText(map[server]);
934
1004
  if (!text) continue;
935
- announced.add(server);
936
- pending.push({ server, block: `## ${server}\n${text}` });
1005
+ const hash = instructionHash(text);
1006
+ // Told already, and the text is the one told. A record from before hashes
1007
+ // were kept cannot tell which text it carried: sent once more, and hashed.
1008
+ if (announced.has(server) && hashes[server] === hash) continue;
1009
+ seen.add(server);
1010
+ pending.push({ server, hash, block: `## ${server}\n${text}` });
937
1011
  }
938
1012
  return pending;
939
1013
  }
@@ -943,6 +1017,10 @@ function announceMcpServers(session, pending) {
943
1017
  session.mcpInstructionsAnnounced = [
944
1018
  ...new Set([...(session.mcpInstructionsAnnounced || []), ...pending.map((entry) => entry.server)]),
945
1019
  ];
1020
+ session.mcpInstructionHashes = {
1021
+ ...(session.mcpInstructionHashes || {}),
1022
+ ...Object.fromEntries(pending.map((entry) => [entry.server, entry.hash])),
1023
+ };
946
1024
  }
947
1025
 
948
1026
  function claimMcpServerInstructions(session, catalog, names) {
@@ -1016,7 +1094,9 @@ export function renderToolSearch(args = {}, session, mode = 'full', options = {}
1016
1094
  ]);
1017
1095
  const loaded = toolSelection.added || [];
1018
1096
  const alreadyActive = toolSelection.already || [];
1019
- const missing = toolSelection.missing || [];
1097
+ // A tool a settings gate closed is named as such, not as unknown.
1098
+ const disabledInSettings = (toolSelection.missing || []).filter((name) => sessionFeatureDenies(session, name));
1099
+ const missing = (toolSelection.missing || []).filter((name) => !disabledInSettings.includes(name));
1020
1100
  const blocked = toolSelection.blocked || [];
1021
1101
  // Native discovery is history-driven: an explicit re-selection must emit
1022
1102
  // the tool reference/spec again even when the callable registry already has
@@ -1040,6 +1120,9 @@ export function renderToolSearch(args = {}, session, mode = 'full', options = {}
1040
1120
  ? { ...nativeToolSearchBase, summary: nativeSummary || nativeToolSearchBase.summary }
1041
1121
  : null;
1042
1122
  const notes = [];
1123
+ if (disabledInSettings.length) {
1124
+ notes.push(`Disabled in settings: ${disabledInSettings.join(', ')}. Do not retry unless the user turns it on.`);
1125
+ }
1043
1126
  if (missing.length && pendingMcpServers.length) {
1044
1127
  notes.push('Some requested names may belong to an MCP server still connecting — retry next turn.');
1045
1128
  }
@@ -1059,6 +1142,7 @@ export function renderToolSearch(args = {}, session, mode = 'full', options = {}
1059
1142
  alreadyActive,
1060
1143
  ...(alreadyActiveSchemas.length ? { alreadyActiveSchemas } : {}),
1061
1144
  missing,
1145
+ ...(disabledInSettings.length ? { disabledInSettings } : {}),
1062
1146
  ...(blocked.length ? { blocked } : {}),
1063
1147
  ...mcpFields,
1064
1148
  activeTools: sortedNamesByMeasuredUsage(
@@ -101,7 +101,7 @@ export const SESSION_TOOL = {
101
101
  'suggest',
102
102
  ],
103
103
  description:
104
- 'status defaults to current; list pages sessions, without sub-agent or archived ones unless include_agents/include_archived; bots shows each bot’s activity, work, approvals, routines and attention flags, or with session_id (a bot id or its chat) its routines and recent sessions; read returns latest items; send queues prompt (reportsBack: the turn result reports back here); cancel stops the turn; delete removes the session. create (bot conversations) starts a visible agent task session from brief (started, not done yet); unknown Project: list-projects first, still ambiguous: ask the user. compact runs after this turn; fork copies it without switching. suggest (Mixy’s chat only) records a proposal made to the user under key; value false records that the user declined it.',
104
+ 'status defaults to current; list pages sessions, without sub-agent or archived ones unless include_agents/include_archived; bots shows each bot’s activity, work, approvals, routines and attention flags, or with session_id (a bot id or its chat) its routines and recent sessions; read returns latest items; send queues prompt (reportsBack: the turn result reports back here); cancel stops the turn; delete removes the session. create (bot conversations; only for a big multi-step plan, smaller work goes to agent) starts a visible agent task session from brief (started, not done yet); unknown Project: list-projects first, still ambiguous: ask the user. compact runs after this turn; fork copies it without switching. suggest (Mixy’s chat only) records a proposal made to the user under key; value false records that the user declined it.',
105
105
  },
106
106
  title: {
107
107
  type: 'string',
@@ -32,7 +32,7 @@ export function createWorkflowContext({ packs, agents }) {
32
32
  function workflowContextBlockFromPack(pack) {
33
33
  if (!pack) return '';
34
34
  // The pack body opens with its own `# <name>` title, so header + description
35
- // + body used to repeat the workflow name three times in the prompt. Emit one
35
+ // + body would repeat the workflow name three times in the prompt. Emit one
36
36
  // header line and drop the body's duplicate title (only when it matches).
37
37
  const rawBody = String(pack.body || '');
38
38
  const firstBreak = rawBody.indexOf('\n');
@@ -14,6 +14,7 @@ import { clearReactionTargets } from '../runtime-core/reaction-tool-defs.mjs';
14
14
  import { applyRetryAction, beginIteration, sendProviderRequest, settleSendResult } from './loop/send-phase.mjs';
15
15
  import { runToolPhase } from './loop/tool-phase.mjs';
16
16
  import { endedWithoutReply } from './loop/turn-limits.mjs';
17
+ import { carryReportOnError } from './loop/turn-report.mjs';
17
18
 
18
19
  // Facade re-exports: these symbols live in ./loop/ modules and are part of
19
20
  // loop.mjs's public surface (imported by scripts/tests and other runtime
@@ -62,29 +63,34 @@ async function runAgentLoop(provider, messages, model, tools, onToolCall, cwd, s
62
63
  resetAccountProbePacing();
63
64
  const state = createLoopState({ provider, messages, model, tools, cwd, sendOpts });
64
65
  // Completion, cancellation, and terminal failures end execution.
65
- while (true) {
66
- const round = await beginIteration(state);
67
- const sent = await sendProviderRequest(state, round);
68
- if (applyRetryAction(state, sent.result)) continue;
69
- settleSendResult(state, round, sent);
70
- // A turn without client tool calls is not automatically the final answer:
71
- // the provider may have hit its output ceiling, been cut by a safety
72
- // classifier, declared the turn unfinished, or returned nothing. Each case
73
- // owns a bounded recovery ladder in ./loop/no-tool-turn.mjs, which either
74
- // appended a recovery turn ('continue') or produced the terminal response.
75
- if (!state.response.toolCalls?.length) {
76
- const outcome = await state.noToolTurn.resolve(state.response, state.iterations);
77
- state.response = outcome.response;
78
- if (outcome.action === 'continue') continue;
79
- break;
80
- }
81
- await runToolPhase(state, round, sent, onToolCall);
82
- // A capped turn that kept calling tools after it was told to reply ends
83
- // here with no reply (./loop/turn-limits.mjs).
84
- if (state.turnLimitEnded) {
85
- state.response = endedWithoutReply(state.response);
86
- break;
66
+ try {
67
+ while (true) {
68
+ const round = await beginIteration(state);
69
+ const sent = await sendProviderRequest(state, round);
70
+ if (applyRetryAction(state, sent.result)) continue;
71
+ settleSendResult(state, round, sent);
72
+ // A turn without client tool calls is not automatically the final answer:
73
+ // the provider may have hit its output ceiling, been cut by a safety
74
+ // classifier, declared the turn unfinished, or returned nothing. Each case
75
+ // owns a bounded recovery ladder in ./loop/no-tool-turn.mjs, which either
76
+ // appended a recovery turn ('continue') or produced the terminal response.
77
+ if (!state.response.toolCalls?.length) {
78
+ const outcome = await state.noToolTurn.resolve(state.response, state.iterations);
79
+ state.response = outcome.response;
80
+ if (outcome.action === 'continue') continue;
81
+ break;
82
+ }
83
+ await runToolPhase(state, round, sent, onToolCall);
84
+ // A capped turn that kept calling tools after it was told to reply ends
85
+ // here with no reply (./loop/turn-limits.mjs), keeping the answers it
86
+ // went past.
87
+ if (state.turnLimitEnded) {
88
+ state.response = state.noToolTurn.finalize(endedWithoutReply(state.response));
89
+ break;
90
+ }
87
91
  }
92
+ } catch (error) {
93
+ throw carryReportOnError(error, state.noToolTurn.endedReport());
88
94
  }
89
95
  return finishLoop(state);
90
96
  }
@@ -4,6 +4,36 @@
4
4
  // only — nothing here reads or changes the watchdog's abort policy.
5
5
  import { displayProgressStage, lastProgressAt } from '../../../shared/quiet-progress.mjs';
6
6
  import { resolveAgentStallThresholds } from '../stall-policy.mjs';
7
+ import { todoProgress } from '../runtime-core/todo-list.mjs';
8
+ import { sessionUsageTotals } from '../../../shared/session-usage-totals.mjs';
9
+
10
+ /** `rows` with each agent's todo progress taken from its live session when
11
+ * this process holds one: the list changes before the session is saved, and
12
+ * the stored copy lags. A live session is authoritative, so one without a
13
+ * list (cleared) drops the row's stored `todo`; rows with no live session
14
+ * keep the stored one. */
15
+ export function withLiveTodo(rows, liveSession) {
16
+ return rows.map((row) => {
17
+ const live = row?.sessionId ? liveSession(row.sessionId) : null;
18
+ if (!live) return row;
19
+ const { todo: _stored, ...rest } = row;
20
+ const todo = todoProgress(live);
21
+ return todo ? { ...rest, todo } : rest;
22
+ });
23
+ }
24
+
25
+ /** `rows` with each agent's running token and tool-call totals taken from its
26
+ * live session when this process holds one: the counters advance with every
27
+ * model response, while the stored copy follows a throttled save. A total the
28
+ * live session does not know keeps the stored one. */
29
+ export function withLiveUsage(rows, liveSession) {
30
+ return rows.map((row) => {
31
+ const live = row?.sessionId ? liveSession(row.sessionId) : null;
32
+ if (!live) return row;
33
+ const { usage, toolCalls } = sessionUsageTotals(live);
34
+ return { ...row, ...(usage ? { usage } : {}), ...(toolCalls === null ? {} : { toolCalls }) };
35
+ });
36
+ }
7
37
 
8
38
  /** `rows` with progress fields on every row `runtimeEntry(sessionId)` reports
9
39
  * in flight. `awaitingTask` marks a row whose agent waits on its background
@@ -11,7 +11,7 @@ import { imagePartAllowance, pdfPartAllowance } from './context-utils.mjs';
11
11
  // over the transcript. The rest stays for the conversation, tool results and
12
12
  // the answer; above it the read-what-you-need path costs far less than the
13
13
  // whole files.
14
- export const ATTACHMENT_INLINE_SHARE = 0.25;
14
+ const ATTACHMENT_INLINE_SHARE = 0.25;
15
15
 
16
16
  /** The inline-attachment budget of a model window (0 when unknown). */
17
17
  export function attachmentInlineBudget(contextWindow) {
@@ -141,7 +141,7 @@ export function sessionReturnChance(gaps, elapsedMs, withinMs) {
141
141
 
142
142
  // A write below this many tokens is prompt growth, never a rewrite: 4096 is
143
143
  // the largest minimum cacheable prompt length of the supported models.
144
- export const CACHE_WARM_REWRITE_FLOOR_TOKENS = 4096;
144
+ const CACHE_WARM_REWRITE_FLOOR_TOKENS = 4096;
145
145
 
146
146
  /** Whether a warm's `usage` shows a substantial rewrite with poor read
147
147
  * coverage: the write reaches the floor and the read covers less than half
@@ -155,7 +155,7 @@ export function warmRewrote(usage) {
155
155
  /** Whether an entry last used at `touchAt` and living `ttlMs` will have
156
156
  * expired by the time a warm sent at `now` reaches the provider (`latencyMs`
157
157
  * later): a warm into an expired entry rewrites the whole prompt. */
158
- export function cacheEntryLapsed(touchAt, ttlMs, now, latencyMs = null) {
158
+ function cacheEntryLapsed(touchAt, ttlMs, now, latencyMs = null) {
159
159
  return touchAt + ttlMs - now <= (Number(latencyMs) || 0);
160
160
  }
161
161
 
@@ -26,7 +26,7 @@ export const SESSION_CATALOG_DB_FILE = 'session-catalog.sqlite';
26
26
  * path (an off-switch); absent or true uses the DB whenever it can. */
27
27
  export const SESSION_STORE_CONFIG_DEFAULTS = Object.freeze({ sqliteCatalog: true });
28
28
  /** Stable prefix of every daemon.log line of the catalog DB. */
29
- export const SESSION_CATALOG_LOG_PREFIX = '[session-catalog-db]';
29
+ const SESSION_CATALOG_LOG_PREFIX = '[session-catalog-db]';
30
30
 
31
31
  // A worker that keeps dying is given up on for a while.
32
32
  const CRASH_WINDOW_MS = 10 * 60_000;
@@ -93,7 +93,7 @@ function workerSettings() {
93
93
  * worker threads are not the main thread, and a daemon started by the CLI
94
94
  * under system Node stays on JSON.
95
95
  */
96
- export function isSessionCatalogDbWriter() {
96
+ function isSessionCatalogDbWriter() {
97
97
  if (testOptions && 'writer' in testOptions) return testOptions.writer === true;
98
98
  return (
99
99
  isMainThread &&
@@ -127,7 +127,7 @@ export function byActivityThenId(left, right) {
127
127
  }
128
128
 
129
129
  /** Title normalized once at write: what a title lookup or sort compares. */
130
- export function normalizedTitle(row) {
130
+ function normalizedTitle(row) {
131
131
  return String(row.title || row.preview || '')
132
132
  .normalize('NFKC')
133
133
  .toLowerCase()
@@ -18,7 +18,7 @@ export const EXECUTION_RECOVERY_SOURCE = 'compact-execution-recovery';
18
18
  const TOOL_HISTORY_CONTEXT_RATIO = 0.05;
19
19
  // The working set of recent execution evidence does not grow with the window:
20
20
  // above 800k, 5% kept a large block of old tool output after every Compact.
21
- export const TOOL_HISTORY_MAX_TOKENS = 40_000;
21
+ const TOOL_HISTORY_MAX_TOKENS = 40_000;
22
22
  const ARCHIVE_THRESHOLD_TOKENS = 512;
23
23
  // Only the newest reminder survives a Compact; it names the dumps it replaced
24
24
  // (each dump holds the reminder that preceded it, so older ones stay reachable).
@@ -421,6 +421,9 @@ function prependLatestUserContext(message, prefix) {
421
421
  if (replacesGoalState) {
422
422
  suffix = suffix.replace(/<system-reminder>\s*<goal_state>[\s\S]*?<\/goal_state>\s*<\/system-reminder>\s*/gi, '');
423
423
  }
424
+ if (text.includes('<todo_state>')) {
425
+ suffix = suffix.replace(/<system-reminder>\s*<todo_state>[\s\S]*?<\/todo_state>\s*<\/system-reminder>\s*/gi, '');
426
+ }
424
427
  // The kept suffix still carries the turn's agent list reminder: it stays told.
425
428
  const told = bare !== message && message.meta.agentListing ? { agentListing: message.meta.agentListing } : null;
426
429
  return withRuntimeUserContext(told ? { ...bare, meta: { ...bare.meta, ...told } } : bare, {
@@ -64,7 +64,7 @@ const LIGHTER_FAMILY = Object.freeze({
64
64
  },
65
65
  'openai-oauth': {
66
66
  catalog: loadSavedCodexCatalog,
67
- matches: (row, id) => id.includes('-luna') && gptVersion(id) !== null,
67
+ matches: (_row, id) => id.includes('-luna') && gptVersion(id) !== null,
68
68
  compare: compareGptVersion,
69
69
  },
70
70
  });
@@ -55,14 +55,10 @@ export {
55
55
  // deployment recalibrate without a code change; values are clamped to a
56
56
  // plausible band.
57
57
  //
58
- // The Anthropic factor was 1.9 while opaque replay blobs were projected as a
59
- // fixed marker — that is, while a transcript's entire reasoning stream (15-35%
60
- // of it) was priced at zero, and the multiplier was silently covering the gap.
61
- // Now that those blobs carry their measured cost, the ratio was re-measured
62
- // against the provider's own token counter on twenty real transcripts:
63
- // 1.23-1.40, median 1.32 (previously 1.72-2.48 — a fifth of the spread, since
64
- // the multiplier no longer has to absorb a variable amount of reasoning).
65
- // 1.4 covers the measured maximum without double counting.
58
+ // Opaque replay blobs carry their measured cost, so the Anthropic ratio does
59
+ // not have to absorb a variable amount of reasoning. Measured against the
60
+ // provider's own token counter on twenty real transcripts: 1.23-1.40, median
61
+ // 1.32. 1.4 covers the measured maximum without double counting.
66
62
  //
67
63
  // Only Anthropic-style providers can be calibrated against reported usage at
68
64
  // all, because only they resend the whole transcript every turn. OpenAI/xAI
@@ -96,10 +92,10 @@ export { estimateRequestReserveTokens, estimateToolSchemaTokens, toolSchemaSigna
96
92
 
97
93
  // Opaque replay payloads (Anthropic thinking signatures, OpenAI encrypted
98
94
  // reasoning blobs, redacted data) are long base64-ish strings that ARE billed
99
- // proportionally to their serialized length — see the measurement below. They
100
- // were previously replaced with a fixed marker, which priced a provider's
101
- // entire reasoning stream at nearly zero. Project them at their measured cost
102
- // instead. Projection is KEY-SCOPED: only fields that structurally carry
95
+ // proportionally to their serialized length — see the measurement below. A
96
+ // fixed marker would price a provider's entire reasoning stream at nearly zero,
97
+ // so they are projected at their measured cost. Projection is KEY-SCOPED: only
98
+ // fields that structurally carry
103
99
  // opaque replay
104
100
  // material (signatures / encrypted / redacted / raw data blobs) are eligible,
105
101
  // so genuine long model text (e.g. Gemini thought text) keeps its real cost.
@@ -79,7 +79,7 @@ export function unwrapClaudePastes(text) {
79
79
  return unwrapped.trim() ? unwrapped : text;
80
80
  }
81
81
 
82
- export function isClaudeEnvelopeText(text) {
82
+ function isClaudeEnvelopeText(text) {
83
83
  const trimmed = String(text || '').trim();
84
84
  if (!trimmed) return true;
85
85
  return (
@@ -28,7 +28,7 @@ const CODEX_ENVELOPE_TAGS = [
28
28
  ];
29
29
  const TOOL_CALL_TYPES = new Set(['function_call', 'custom_tool_call', 'local_shell_call']);
30
30
 
31
- export function isCodexEnvelopeText(text) {
31
+ function isCodexEnvelopeText(text) {
32
32
  const trimmed = String(text || '').trim();
33
33
  if (!trimmed) return true;
34
34
  if (/^# AGENTS\.md instructions\b/.test(trimmed) && trimmed.includes('<INSTRUCTIONS>')) return true;
@@ -14,7 +14,7 @@ import {
14
14
  normalizeTurns,
15
15
  } from './turns.mjs';
16
16
 
17
- export const IMPORT_SOURCES = Object.freeze(['codex', 'claude']);
17
+ const IMPORT_SOURCES = Object.freeze(['codex', 'claude', 'cowork']);
18
18
  /** A line or converted transcript beyond the import limits fails the file. */
19
19
  export const IMPORT_ERROR_TOO_LARGE = 'tooLarge';
20
20
  export const IMPORT_MAX_LINE_BYTES = 32 * 1024 * 1024;
@@ -12,11 +12,15 @@ import { writeStderrBestEffort } from '../../../../shared/best-effort-stderr.mjs
12
12
  import { IMPORTED_MESSAGE_SOURCE } from '../imported-message.mjs';
13
13
  import { ingestSessionTurn } from '../../../../session-search/session-search-ingest.mjs';
14
14
 
15
- export const IMPORT_ORIGIN_VERSION = 1;
15
+ const IMPORT_ORIGIN_VERSION = 1;
16
16
 
17
- /** Dedupe identity: the foreign session id, else the canonical source path. */
17
+ /**
18
+ * Dedupe identity: the foreign session id, else the canonical source path.
19
+ * Cowork transcripts are Claude Code transcripts, so both share the `claude` namespace.
20
+ */
18
21
  export function importOriginKey(source, foreignSessionId, canonicalPath) {
19
- return foreignSessionId ? `${source}:${foreignSessionId}` : `${source}:path:${canonicalPath}`;
22
+ const namespace = source === 'cowork' ? 'claude' : source;
23
+ return foreignSessionId ? `${namespace}:${foreignSessionId}` : `${namespace}:path:${canonicalPath}`;
20
24
  }
21
25
 
22
26
  export function buildImportOrigin({ source, sourcePath, foreignSessionId = null, sourceCwd = null, importedAt }) {
@@ -7,7 +7,7 @@
7
7
  // user's words; the structured `heldRequest` payload is for the UI only.
8
8
  import { escapeHarnessTags } from '../../../../shared/shell-output-summary.mjs';
9
9
 
10
- export const HELD_REQUEST_SOURCE = 'held-request';
10
+ const HELD_REQUEST_SOURCE = 'held-request';
11
11
  const STATUSES = new Set(['pending', 'approved', 'denied', 'expired']);
12
12
 
13
13
  const clean = (value, limit = 200) =>
@@ -12,7 +12,7 @@
12
12
  // own: the card names the tool, its current level and the one
13
13
  // asked for, and the person picks the level (`scope`: one of
14
14
  // `choices`) or denies. Answered once, never remembered.
15
- // A response is one of HUMAN_RESPONSES plus a `remember` scope; a policy lists
15
+ // A response is one of RESPONSES_BY_KIND for its kind plus a `remember` scope; a policy lists
16
16
  // the scopes it allows and can leave out `always`. Nothing here ever carries a
17
17
  // secret value: a decision that names one is stripped to its verdict.
18
18
 
@@ -20,7 +20,6 @@ const HUMAN_REQUEST_KINDS = Object.freeze(['approval', 'outbound', 'secret', 'ta
20
20
  /** The levels a connector card may raise a tool to. */
21
21
  export const CONNECTOR_WIDEN_LEVELS = Object.freeze(['needs_approval', 'auto']);
22
22
  const CONNECTOR_LEVELS = ['disabled', ...CONNECTOR_WIDEN_LEVELS];
23
- const HUMAN_RESPONSES = Object.freeze(['approve', 'deny', 'edit-and-approve', 'provide-secret', 'skip', 'done']);
24
23
  const REMEMBER_SCOPES = Object.freeze(['once', 'agent', 'always']);
25
24
  export const SECRET_REQUEST_TIMEOUT_MS = 120_000;
26
25
  /** What a secret's bound field is: a sign-in form (아이디 + 비밀번호), a lone
@@ -20,7 +20,7 @@ export const AUTOMATION_GRANT_REASON =
20
20
  export const isGrantedRun = (run) => Boolean(run) && run.kind !== 'room';
21
21
 
22
22
  /** Whether an outbound request is a payment or permanent delete. */
23
- export function isForbiddenInRun(request) {
23
+ function isForbiddenInRun(request) {
24
24
  const category = request?.kind === 'outbound' ? request.outbound?.category : '';
25
25
  return ACTION_KINDS.includes(category) && !isRememberableAction(category);
26
26
  }
@@ -151,7 +151,7 @@ export function persistsConfirmedImageRejection(err, strip) {
151
151
  return strip.uniqueImages === 1;
152
152
  }
153
153
 
154
- export const PREPARATION_FAILED_CODE = 'anthropic_image_preparation_failed';
154
+ const PREPARATION_FAILED_CODE = 'anthropic_image_preparation_failed';
155
155
 
156
156
  /** True for prepareAnthropicImages' local "this image is invalid" rejection. */
157
157
  export function isImagePreparationFailed(err) {