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
@@ -6,7 +6,10 @@ import {
6
6
  filterDisallowedTools,
7
7
  selectDeferredTools,
8
8
  } from '../runtime/agent/orchestrator/runtime-core/tool-catalog.mjs';
9
- import { AGENT_WORKER_DENIED_TOOLS } from '../runtime/agent/orchestrator/session/manager/tool-resolution.mjs';
9
+ import {
10
+ AGENT_WORKER_DENIED_TOOLS,
11
+ finalizeSessionToolList,
12
+ } from '../runtime/agent/orchestrator/session/manager/tool-resolution.mjs';
10
13
  import { LEAD_DISALLOWED_TOOLS } from '../runtime/agent/orchestrator/runtime-core/tool-defs.mjs';
11
14
  import { deferredSurfaceModeForLead, toolSpecForMode } from '../runtime/agent/orchestrator/runtime-core/effort.mjs';
12
15
  import { loadSkillToolDependencies } from '../runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs';
@@ -39,6 +42,11 @@ export function createToolSurface({
39
42
  getFeatureDisallowedTools = () => [],
40
43
  }) {
41
44
  let preSessionSurface = null;
45
+ // The inputs the cached preview was built from (setters no longer
46
+ // invalidate it; a config adopt or reload replaces the config object).
47
+ let preSessionInputs = '';
48
+ let preSessionConfig = null;
49
+ let surfaceGeneration = 0;
42
50
 
43
51
  // A coding Lead keeps `agent` whichever agents exist (the agents reach it as
44
52
  // a listing reminder); Solo still offers it (deferred) for explicit user
@@ -122,16 +130,45 @@ export function createToolSurface({
122
130
  return selectDeferredTools(session, names, surfaceMode);
123
131
  }
124
132
 
133
+ /** Definitions the current session's kind may hold — built-ins included —
134
+ * for tools a settings gate opened mid-conversation. */
135
+ function toolDefinitionsFor(names) {
136
+ const wanted = new Set((names || []).map(String));
137
+ const session = getSession();
138
+ const ownerIsAgent = isAgentOwner(session);
139
+ const previewTools =
140
+ typeof mgr.previewSessionTools === 'function'
141
+ ? mgr.previewSessionTools(toolSpecForMode(mode), [], {
142
+ mcpScopeId: getMcpScopeId(),
143
+ modelName: getRoute().model,
144
+ cwd: getCurrentCwd?.() || null,
145
+ })
146
+ : [];
147
+ const byName = new Map();
148
+ for (const tool of [...modelStandaloneTools(), ...filterModelToolsForProfile(previewTools, getToolProfile())]) {
149
+ const name = String(tool?.name || '');
150
+ if (wanted.has(name) && !byName.has(name)) byName.set(name, tool);
151
+ }
152
+ return finalizeSessionToolList([...byName.values()], { ownerIsAgent });
153
+ }
154
+
125
155
  return {
126
156
  modelStandaloneTools,
127
157
  activateTools,
158
+ toolDefinitionsFor,
159
+ surfaceGeneration: () => surfaceGeneration,
128
160
  invalidatePreSessionToolSurface() {
129
161
  preSessionSurface = null;
162
+ surfaceGeneration += 1;
130
163
  },
131
164
  /** The live session once it exists; the preview surface until then. */
132
165
  activeToolSurface() {
133
166
  const session = getSession();
134
167
  if (session) return session;
168
+ const inputs = getFeatureDisallowedTools().join(',');
169
+ if (preSessionConfig !== getConfig() || preSessionInputs !== inputs) preSessionSurface = null;
170
+ preSessionConfig = getConfig();
171
+ preSessionInputs = inputs;
135
172
  preSessionSurface ??= buildPreSessionSurface();
136
173
  return preSessionSurface;
137
174
  },
@@ -31,6 +31,7 @@ export function createAgentOps(deps) {
31
31
  subscribeRuntimeNotification,
32
32
  agentTool,
33
33
  activeToolSurface,
34
+ reconcileEmptySession,
34
35
  notificationListeners,
35
36
  getReservedSessionId,
36
37
  } = deps;
@@ -136,7 +137,14 @@ export function createAgentOps(deps) {
136
137
  return () => notificationListeners.delete(listener);
137
138
  }
138
139
 
139
- function toolsStatus(query = '') {
140
+ // An empty session has nothing cached: it is brought to the settings first
141
+ // (the turn-start reconcile), so the list is what its first turn sends.
142
+ async function toolsStatus(query = '') {
143
+ await reconcileEmptySession?.();
144
+ return toolsStatusNow(query);
145
+ }
146
+
147
+ function toolsStatusNow(query = '') {
140
148
  const surface = activeToolSurface();
141
149
  let catalog = [];
142
150
  if (Array.isArray(surface?.deferredToolCatalog)) catalog = surface.deferredToolCatalog;
@@ -161,7 +169,7 @@ export function createAgentOps(deps) {
161
169
  function selectTools(names) {
162
170
  const list = Array.isArray(names) ? names : String(names || '').split(/[,\s]+/);
163
171
  const result = selectDeferredTools(activeToolSurface(), list, getMode());
164
- return { ...result, status: toolsStatus() };
172
+ return { ...result, status: toolsStatusNow() };
165
173
  }
166
174
 
167
175
  return {
@@ -6,6 +6,7 @@ import { normalizeToolMode } from '../../runtime/agent/orchestrator/runtime-core
6
6
  import { interruptTaskWaitForSession } from '../../runtime/agent/orchestrator/session/task-wait-control.mjs';
7
7
  import { markPendingGoalReminder } from '../../runtime/agent/orchestrator/runtime-core/goal-reminder.mjs';
8
8
  import { rearmLateDeferredTools } from '../../runtime/agent/orchestrator/runtime-core/tool-catalog.mjs';
9
+ import { rearmPromptSettingsNotice } from '../../runtime/agent/orchestrator/session/manager/prompt-settings.mjs';
9
10
 
10
11
  export function createSessionOps(deps) {
11
12
  const {
@@ -101,6 +102,7 @@ export function createSessionOps(deps) {
101
102
  // The same compaction strips late MCP tool announcements from older turns.
102
103
  try {
103
104
  rearmLateDeferredTools(getSession());
105
+ rearmPromptSettingsNotice(getSession());
104
106
  } catch {
105
107
  /* best-effort: a tool reminder must never break manual compact */
106
108
  }
@@ -90,6 +90,7 @@ export function createTurnPreparation({
90
90
  applyPendingRoute,
91
91
  applyPendingAgentProfile,
92
92
  applyPendingSessionSwitches,
93
+ reconcileTurnSettings,
93
94
  }) {
94
95
  async function admitWorkspace(turn, prompt, options) {
95
96
  // Turn admission: waits while this session's workspace transitions or
@@ -149,6 +150,10 @@ export function createTurnPreparation({
149
150
  // An orchestration mode or workflow chosen while the previous turn ran
150
151
  // applies from this one (before a cold-cache fold can take it in).
151
152
  const sessionSwitches = applyPendingSessionSwitches?.();
153
+ // Settings saved since this session last ran (here or in any other
154
+ // runtime): an empty session is rebuilt, a conversation takes moved tool
155
+ // gates live — before a cold-cache fold below can take them in.
156
+ await reconcileTurnSettings?.();
152
157
  // An agent profile saved while the previous turn ran applies from this one.
153
158
  await applyPendingAgentProfile?.();
154
159
  options.onRouteApplied?.(getSession());
@@ -85,7 +85,7 @@ export function createTurnRunner(deps) {
85
85
  // The agents enabled now (coding Leads), asked for each user turn
86
86
  // the ask prepares, for its agent list reminder
87
87
  // (manager/agent-listing-notice.mjs).
88
- { ...callbacks, agentsNow: currentAgents }
88
+ { ...callbacks, agentsNow: currentAgents, agentConfig: getConfig }
89
89
  );
90
90
  } finally {
91
91
  releaseWebSearchUsage?.();
@@ -43,6 +43,7 @@ function runWebhookTurn({
43
43
  name,
44
44
  prompt,
45
45
  ownerAgentId = null,
46
+ executorAgentId = null,
46
47
  cwd = null,
47
48
  attachments = null,
48
49
  event = '',
@@ -55,6 +56,7 @@ function runWebhookTurn({
55
56
  kind: 'webhook',
56
57
  name: endpoint,
57
58
  ownerAgentId,
59
+ executorAgentId: executorAgentId || null,
58
60
  prompt,
59
61
  skillSelection: String(skillSelection ?? ''),
60
62
  attachments,
@@ -177,10 +177,7 @@ export function createAgentConnectorsApi(deps, editor) {
177
177
  return [...names].map((tool) => ({
178
178
  connector,
179
179
  tool,
180
- permission: connectorToolPermission(
181
- { off: [], tools },
182
- { mcpServerName: connector, mcpToolName: tool }
183
- ),
180
+ permission: connectorToolPermission({ off: [], tools }, { mcpServerName: connector, mcpToolName: tool }),
184
181
  explicit: connectorToolEntries(tools, group, tool).length > 0,
185
182
  }));
186
183
  });
@@ -7,7 +7,6 @@ import { ensureProviderEnabled } from '../../runtime/agent/orchestrator/runtime-
7
7
  import { resolveRouteContextState, selectionFastCapable } from '../route-state.mjs';
8
8
  import {
9
9
  canonicalizeAgentRouteStorage,
10
- EXPLORE_AGENT_ID,
11
10
  isAgentDisabled,
12
11
  withAgentDisabled,
13
12
  } from '../../runtime/shared/agent-route-config.mjs';
@@ -227,13 +226,7 @@ export function createAgentRouteApi(deps) {
227
226
  return stayOff ? { ...routeToSave, id, disabled: true } : routeToSave;
228
227
  }
229
228
 
230
- // Explore's route decides whether the explore tool exists, so the empty
231
- // session rebuilds its tool surface on any change of it.
232
- async function setAgentRouteAndRefresh(agentId, next) {
233
- const saved = await setAgentRoute(agentId, next);
234
- if (agentEditorId(agentId) === EXPLORE_AGENT_ID) await deps.refreshEmptySessionToolPolicy?.();
235
- return saved;
236
- }
237
-
238
- return { setAgentRoute: setAgentRouteAndRefresh };
229
+ // Explore's route decides whether the explore tool exists; sessions take a
230
+ // change of it at their next turn start (reconcileTurnSettings).
231
+ return { setAgentRoute };
239
232
  }
@@ -0,0 +1,165 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync, mkdirSync, rmSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { writeFileAtomicSync } from '../../runtime/shared/atomic-file.mjs';
5
+ import { normalizeText } from '../../runtime/shared/shipped-definitions.mjs';
6
+ import { decodeInstructionFile, INSTRUCTION_FILE_MAX_BYTES } from '../../lib/instruction-text.cjs';
7
+ import { outputStyleMetaFromMarkdown } from '../../lib/output-style-meta.cjs';
8
+ import {
9
+ readInstructionFile,
10
+ shippedOrchestrationPath,
11
+ userOrchestrationPath,
12
+ } from '../../runtime/agent/orchestrator/runtime-core/orchestration.mjs';
13
+ import { ORCHESTRATION_MODES } from '../../runtime/shared/orchestration.mjs';
14
+ import { publishAgentProfileChange } from '../agent-profile-changes.mjs';
15
+ import { STANDALONE_ROOT } from '../runtime-paths.mjs';
16
+ import { resolveDataDir } from './shared.mjs';
17
+
18
+ // The editable instruction texts: the four orchestration modes (delegation)
19
+ // and the four output-style depth levels. Each has a shipped .md file and a
20
+ // same-name user file in the data dir that replaces it; the set is fixed.
21
+ export const INSTRUCTION_FILE_CONFLICT = 'INSTRUCTION_FILE_CONFLICT';
22
+
23
+ const MODE_LABELS = { none: 'Solo', focused: 'Focused', balanced: 'Balanced', swarm: 'Swarm' };
24
+ const STYLES = [
25
+ ['detailed', 'Detailed'],
26
+ ['simple', 'Simple'],
27
+ ['minimal', 'Minimal'],
28
+ ['extreme-minimal', 'Extreme Minimal'],
29
+ ];
30
+ const INSTRUCTION_GROUPS = Object.freeze(['delegation', 'outputStyle']);
31
+
32
+ const FRONTMATTER = /^---[ \t]*\r?\n[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/;
33
+ const bodyOfStyle = (text) =>
34
+ String(text || '')
35
+ .replace(FRONTMATTER, '')
36
+ .trim();
37
+ const hashOf = (text) => createHash('sha256').update(String(text)).digest('hex').slice(0, 24);
38
+
39
+ // One item's files and the text <-> file mapping. The style editor shows and
40
+ // saves the file's body only: the shipped front matter (name, title,
41
+ // description) is kept, and common.md is not part of it.
42
+ function itemFor(group, id, deps) {
43
+ if (group === 'delegation') {
44
+ if (!ORCHESTRATION_MODES.includes(id))
45
+ throw new Error(`orchestration mode must be one of ${ORCHESTRATION_MODES.join(', ')}`);
46
+ return {
47
+ group,
48
+ id,
49
+ label: MODE_LABELS[id],
50
+ shipped: shippedOrchestrationPath(id),
51
+ user: userOrchestrationPath(id),
52
+ body: (text) => text,
53
+ file: (body) => `${body}\n`,
54
+ accepts: () => true,
55
+ };
56
+ }
57
+ if (group === 'outputStyle') {
58
+ const style = STYLES.find(([styleId]) => styleId === id);
59
+ if (!style) throw new Error(`output style must be one of ${STYLES.map(([styleId]) => styleId).join(', ')}`);
60
+ const shipped = join(deps.rootDir ?? STANDALONE_ROOT, 'output-styles', `${id}.md`);
61
+ return {
62
+ group,
63
+ id,
64
+ label: style[1],
65
+ shipped,
66
+ user: join(resolveDataDir(deps), 'output-styles', `${id}.md`),
67
+ body: bodyOfStyle,
68
+ file: (body, shippedText) => `${(FRONTMATTER.exec(shippedText) || [''])[0].trimEnd()}\n\n${body}\n`,
69
+ // A file whose front matter names another style defines that one instead
70
+ // (the prompt builder registers it by name): it does not replace this one.
71
+ accepts: (text) => outputStyleMetaFromMarkdown(text, `${id}.md`)?.id === id,
72
+ };
73
+ }
74
+ throw new Error(`instruction group must be one of ${INSTRUCTION_GROUPS.join(', ')}`);
75
+ }
76
+
77
+ export function createInstructionFilesApi(deps) {
78
+ function stateOf(item) {
79
+ const shipped = readInstructionFile(item.shipped);
80
+ const defaultBody = item.body(shipped?.text ?? '');
81
+ const user = readInstructionFile(item.user);
82
+ const accepted = Boolean(user?.text) && item.accepts(user.text);
83
+ const userBody = accepted ? item.body(user.text) : '';
84
+ // An existing user file that cannot serve (empty, too large, not text, a
85
+ // style under another name) is passed over by the prompt builders: the
86
+ // built-in applies.
87
+ const usable = Boolean(userBody);
88
+ const problem = user && !usable ? (user.problem ?? (accepted ? 'empty' : 'invalid')) : undefined;
89
+ const body = usable ? userBody : defaultBody;
90
+ return {
91
+ group: item.group,
92
+ id: item.id,
93
+ label: item.label,
94
+ body,
95
+ defaultBody,
96
+ userOverride: Boolean(user),
97
+ modified: usable && normalizeText(userBody) !== normalizeText(defaultBody),
98
+ ...(problem ? { problem } : {}),
99
+ ...(user ? { path: item.user } : {}),
100
+ revision: hashOf(`${usable ? 'user' : 'default'}\0${problem ?? ''}\0${body}`),
101
+ };
102
+ }
103
+
104
+ // A write or reset made against a state that has moved on is refused.
105
+ function assertCurrent(payloadRevision, before, item) {
106
+ if (payloadRevision === undefined || String(payloadRevision) === before.revision) return;
107
+ const conflict = new Error(`${INSTRUCTION_FILE_CONFLICT}: "${item.id}" changed since it was loaded`);
108
+ conflict.code = INSTRUCTION_FILE_CONFLICT;
109
+ throw conflict;
110
+ }
111
+
112
+ const get = (group, id) => stateOf(itemFor(group, id, deps));
113
+
114
+ function list() {
115
+ return [...ORCHESTRATION_MODES.map((id) => get('delegation', id)), ...STYLES.map(([id]) => get('outputStyle', id))];
116
+ }
117
+
118
+ async function announce() {
119
+ deps.invalidateContextStatusCache?.();
120
+ await publishAgentProfileChange();
121
+ }
122
+
123
+ async function save(payload = {}) {
124
+ const item = itemFor(payload.group, payload.id, deps);
125
+ const body = String(payload.body ?? '')
126
+ .replace(/\r\n/g, '\n')
127
+ .trim();
128
+ if (!body) throw new Error('instruction text must not be empty');
129
+ if (body.includes('\0')) throw new Error('instruction text must be plain text');
130
+ const before = stateOf(item);
131
+ assertCurrent(payload.expectedRevision, before, item);
132
+ if (normalizeText(body) === normalizeText(before.defaultBody)) {
133
+ // Equal to the shipped text: keep no copy, so it follows the shipped version.
134
+ rmSync(item.user, { force: true });
135
+ } else {
136
+ // The bytes that reach the disk — front matter and newline included —
137
+ // must pass the reader's check, or the saved file would be ignored.
138
+ const bytes = Buffer.from(item.file(body, readInstructionFile(item.shipped)?.text ?? ''));
139
+ if (bytes.length > INSTRUCTION_FILE_MAX_BYTES) throw new Error('instruction text is larger than 256 KB');
140
+ const problem = decodeInstructionFile(bytes).problem;
141
+ if (problem) throw new Error(`instruction text cannot be saved (${problem})`);
142
+ mkdirSync(dirname(item.user), { recursive: true });
143
+ writeFileAtomicSync(item.user, bytes, { backup: true, mode: 0o644 });
144
+ }
145
+ await announce();
146
+ return stateOf(item);
147
+ }
148
+
149
+ async function reset(group, id, expectedRevision) {
150
+ const item = itemFor(group, id, deps);
151
+ if (!existsSync(item.user)) throw new Error(`"${item.id}" has no user override to reset`);
152
+ assertCurrent(expectedRevision, stateOf(item), item);
153
+ rmSync(item.user, { force: true });
154
+ rmSync(`${item.user}.bak`, { force: true });
155
+ await announce();
156
+ return stateOf(item);
157
+ }
158
+
159
+ return {
160
+ listInstructionFiles: list,
161
+ getInstructionFile: get,
162
+ saveInstructionFile: save,
163
+ resetInstructionFile: reset,
164
+ };
165
+ }
@@ -30,7 +30,9 @@ export function createStyleAndModeApi(deps) {
30
30
  scheduleOutputStyleSave(selected.id);
31
31
  const freshStatus = { configured: selected.id, current: selected, styles: before.styles };
32
32
  seedOutputStyleStatusCache(freshStatus);
33
- const appliedToCurrentSession = !getSession()?.id;
33
+ // An empty session is rebuilt at its next turn start; a conversation is
34
+ // told then and folds the style in at its next cold point.
35
+ const appliedToCurrentSession = deps.settingsReachCurrentSession?.() ?? !getSession()?.id;
34
36
  invalidateContextStatusCache();
35
37
  return { ...freshStatus, appliedToCurrentSession };
36
38
  }
@@ -53,10 +55,9 @@ export function createStyleAndModeApi(deps) {
53
55
  }
54
56
  }
55
57
  saveConfigAndAdopt({ ...getConfig(), orchestrationMode: mode });
56
- const applied = await deps.refreshEmptySessionToolPolicy?.();
57
- deps.invalidatePreSessionToolSurface?.();
58
+ // An empty session takes it at its next turn start (reconcileTurnSettings).
58
59
  invalidateContextStatusCache();
59
- return { mode, appliedToCurrentSession: applied?.appliedToCurrentSession !== false };
60
+ return { mode, appliedToCurrentSession: deps.settingsReachCurrentSession?.() !== false };
60
61
  }
61
62
 
62
63
  return {
@@ -66,9 +66,8 @@ export function createWorkflowPacksApi(deps) {
66
66
  if (switched) return { ...switched.workflow, ...switched };
67
67
  }
68
68
  saveActiveWorkflow(id);
69
- const applied = await deps.refreshEmptySessionToolPolicy?.();
70
- deps.invalidatePreSessionToolSurface?.();
71
- return { ...workflowSummary(pack), appliedToCurrentSession: applied?.appliedToCurrentSession !== false };
69
+ // An empty session takes it at its next turn start (reconcileTurnSettings).
70
+ return { ...workflowSummary(pack), appliedToCurrentSession: deps.settingsReachCurrentSession?.() !== false };
72
71
  }
73
72
 
74
73
  function getWorkflowPack(workflowId) {
@@ -4,6 +4,7 @@ import { createAgentConnectorsApi } from './workflow-agents-api/agent-connectors
4
4
  import { createAgentRouteApi } from './workflow-agents-api/agent-route.mjs';
5
5
  import { createWorkflowPacksApi } from './workflow-agents-api/workflow-packs.mjs';
6
6
  import { createStyleAndModeApi } from './workflow-agents-api/style-and-mode.mjs';
7
+ import { createInstructionFilesApi } from './workflow-agents-api/instruction-files.mjs';
7
8
 
8
9
  // Onboarding + agents/workflows/output-style selection surface. Stateless
9
10
  // helpers are imported by the phase modules under workflow-agents-api/; the
@@ -20,5 +21,6 @@ export function createWorkflowAgentsApi(deps) {
20
21
  ...routeApi,
21
22
  ...createWorkflowPacksApi(deps),
22
23
  ...createStyleAndModeApi(deps),
24
+ ...createInstructionFilesApi(deps),
23
25
  };
24
26
  }
@@ -52,7 +52,7 @@ export function createProjectBranchOps({
52
52
  return {
53
53
  // Detached: branch null and the checked-out commit in baseCommit.
54
54
  workspace: project.currentBranch ? workspace : { ...workspace, baseCommit: project.headCommit ?? null },
55
- branches: branchMenuEntries(menu.branches, menu.occupancy),
55
+ branches: branchMenuEntries(menu.branches, menu.occupancy, menu.committedAt),
56
56
  occupancy: menu.occupancy,
57
57
  retainedWorktree: null,
58
58
  };
@@ -130,7 +130,7 @@ export function createSessionWorkspaceView({
130
130
  return {
131
131
  workspace: view,
132
132
  pendingWorktree: pendingWorktree(),
133
- branches: branchMenuEntries(menu.branches, menu.occupancy),
133
+ branches: branchMenuEntries(menu.branches, menu.occupancy, menu.committedAt),
134
134
  occupancy: menu.occupancy,
135
135
  retainedWorktree: selectedEntry ?? menu.retainedWorktree ?? null,
136
136
  // Creation notes of the retained worktree (submodules, include entries).
@@ -62,12 +62,18 @@ async function defaultRegisteredProject(path) {
62
62
  * `move` ({ from, changes }: the session left the project folder `from` for
63
63
  * a worktree) adds the uncommitted-changes and path lines to that notice.
64
64
  */
65
- export async function refreshWorkspacePrompt(session, cwd, { loadCoreMemoryContext, move = null } = {}) {
65
+ export async function refreshWorkspacePrompt(
66
+ session,
67
+ cwd,
68
+ { loadCoreMemoryContext, move = null, instructionFilesMode } = {}
69
+ ) {
66
70
  // A new checkout invalidates observed-file snapshots as well as read/search
67
71
  // results. Conversation text remains historical evidence, not a file cache.
68
72
  clearReadDedupSession(session?.id);
69
73
  resetReadStateAfterCompaction(session?.id);
70
- const { environmentContext, instructionFilesContext } = buildWorkspacePromptContext(session, cwd);
74
+ const { environmentContext, instructionFilesContext } = buildWorkspacePromptContext(session, cwd, {
75
+ instructionFilesMode,
76
+ });
71
77
  const coreMemoryContext =
72
78
  session?.owner === AGENT_OWNER || typeof loadCoreMemoryContext !== 'function'
73
79
  ? undefined
@@ -94,8 +100,13 @@ export function publicWorkspaceMethods(api) {
94
100
  requestWorktree: (input) => api.requestWorktree(input),
95
101
  mergeWorkspace: (input) => api.mergeWorkspace(input),
96
102
  removeWorktree: (input) => api.removeWorktree(input),
97
- listWorktrees: () => api.listWorktrees(),
98
- pruneWorktrees: () => api.pruneWorktrees(),
103
+ // External callers get the list with its details (Settings → Worktrees).
104
+ listWorktrees: () => api.listWorktrees({ details: true }),
105
+ pruneWorktrees: (input) => api.pruneWorktrees({ repoCommonDir: input?.repoCommonDir ?? null }),
106
+ previewWorktreeCleanup: (input) => api.previewWorktreeCleanup({ repoCommonDir: input?.repoCommonDir ?? null }),
107
+ deleteWorktree: (input) => api.deleteWorktree(input),
108
+ getSessionWorktreeWork: (input) => api.getSessionWorktreeWork(input),
109
+ setArchivedSessionWorktrees: (input) => api.setArchivedSessionWorktrees(input),
99
110
  };
100
111
  }
101
112
 
@@ -285,7 +296,12 @@ export function createWorkspaceTransitions({
285
296
  switchProject: runner.switchProject,
286
297
  listWorktrees: worktrees.listWorktrees,
287
298
  pruneWorktrees: worktrees.pruneWorktrees,
299
+ previewWorktreeCleanup: worktrees.previewWorktreeCleanup,
300
+ deleteWorktree: worktrees.deleteWorktree,
288
301
  removeOrphanWorktree: worktrees.removeOrphanWorktree,
302
+ removeOwnedWorktree: worktrees.removeOwnedWorktree,
303
+ getSessionWorktreeWork: worktrees.getSessionWorktreeWork,
304
+ setArchivedSessionWorktrees: worktrees.setArchivedSessionWorktrees,
289
305
  cleanupDeletedSession: worktrees.cleanupDeletedSession,
290
306
  onWorktreeSetup: setup.onWorktreeSetup,
291
307
  dispose: checkouts.dispose,
@@ -32,14 +32,59 @@ export function createWorktreeMaintenance({
32
32
  * snapshots (no branch) only with `includeSnapshots` (the git tool); the
33
33
  * desktop list (DesktopManagedWorktreeRow, a branch per row) never gets them.
34
34
  */
35
- async function listWorktrees({ includeSnapshots = false } = {}) {
36
- const rows = await maintenance.listWorktreesWithRetention(await maintenanceScope());
35
+ async function listWorktrees({ includeSnapshots = false, details = false } = {}) {
36
+ const rows = await maintenance.listWorktreesWithRetention({
37
+ ...(await maintenanceScope()),
38
+ details,
39
+ settings: worktreeSettings(),
40
+ });
37
41
  return includeSnapshots ? rows : rows.filter((row) => row.kind !== WORKTREE_SNAPSHOT_KIND);
38
42
  }
39
43
 
40
- /** The manual prune: clean, merged worktrees no stored or live session retains. */
44
+ /** The manual prune: clean, merged worktrees no stored or live session retains
45
+ * (plus, with autoCleanup on, what the automatic cleanup would remove). */
41
46
  async function pruneWorktrees({ repoCommonDir = null } = {}) {
42
- return maintenance.pruneWorktrees({ ...(await maintenanceScope()), repoCommonDir });
47
+ return maintenance.pruneWorktrees({
48
+ ...(await maintenanceScope()),
49
+ repoCommonDir,
50
+ settings: worktreeSettings(),
51
+ currentLiveSessionIds: () => listLiveSessions().map((candidate) => candidate?.id),
52
+ });
53
+ }
54
+
55
+ /** Whether the manual prune could act on anything (no git verification, nothing removed). */
56
+ async function previewWorktreeCleanup({ repoCommonDir = null } = {}) {
57
+ const { hasCandidates } = await maintenance.previewWorktreeCleanup({
58
+ ...(await maintenanceScope()),
59
+ repoCommonDir,
60
+ settings: worktreeSettings(),
61
+ });
62
+ return { hasCandidates };
63
+ }
64
+
65
+ /**
66
+ * Delete managed worktree `entryId` from the worktree list (Settings →
67
+ * Worktrees), whoever owns it: a session the store keeps no longer protects
68
+ * it, but a live owner or a session or background command working in the
69
+ * folder refuses (folder-in-use, folder-shell-jobs, workspace-lease), as do
70
+ * other sessions' shared references and retained recovery data. Dirty or
71
+ * unmerged work needs `force`; a forced unmerged tip stays under
72
+ * refs/mixdog/removed/<id>.
73
+ */
74
+ async function deleteWorktree({ entryId, force = false } = {}) {
75
+ const row = (await listWorktrees()).find((item) => item.id === entryId);
76
+ if (!row) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
77
+ const removed = await withManagementFolders([row.path], false, async () => {
78
+ const { liveSessionIds, listSessionIds, manager: backendApi } = await maintenanceScope();
79
+ return backendApi.removeOrphanedWorktree({
80
+ entryId,
81
+ force: force === true,
82
+ liveSessionIds,
83
+ retainedSessionIds: await listSessionIds(),
84
+ allowRetained: true,
85
+ });
86
+ });
87
+ return { removed, entryId, path: row.path };
43
88
  }
44
89
 
45
90
  /**
@@ -70,11 +115,86 @@ export function createWorktreeMaintenance({
70
115
  async function cleanupDeletedSession(sessionId) {
71
116
  // Its snapshots go with it below; no turn cleanup keeps retrying them.
72
117
  cancelSnapshotCleanups(sessionId);
118
+ const settings = worktreeSettings();
73
119
  return maintenance.cleanupDeletedSessionWorktree(sessionId, {
74
120
  manager: await backend(),
75
- autoCleanup: worktreeSettings().autoCleanup,
121
+ autoCleanup: settings.autoCleanup,
122
+ deleteBranch: settings.deleteBranch,
123
+ });
124
+ }
125
+
126
+ /**
127
+ * Remove managed worktree `entryId` this session owns but does not work in
128
+ * now, without entering it first: the session does not move, so its own
129
+ * turn and workers elsewhere never block it. The folder's consumers still
130
+ * refuse (another session or a background command in it), as do dirty or
131
+ * unmerged work without `force`, other sessions' references and retained
132
+ * recovery data (the manager's guards).
133
+ */
134
+ async function removeOwnedWorktree({ entryId, force = false } = {}) {
135
+ const session = getSession();
136
+ const row = (await listWorktrees()).find((item) => item.id === entryId);
137
+ if (!row) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
138
+ if (!session?.id || row.ownerSessionId !== session.id) {
139
+ throw worktreeError('WORKTREE_BUSY_JOBS', 'This worktree belongs to another session.', {
140
+ reason: 'workspace-shared',
141
+ sessions: [row.ownerSessionId].filter(Boolean),
142
+ });
143
+ }
144
+ if (session.workspace?.worktreeId === entryId) {
145
+ throw worktreeError('WORKTREE_BUSY_JOBS', 'The session works in this worktree; return to the project first.', {
146
+ reason: 'folder-in-use',
147
+ sessions: [session.id],
148
+ });
149
+ }
150
+ const removed = await withManagementFolders([row.path], true, async () =>
151
+ (await backend()).removeManagedWorktree({ entryId, force: force === true, sessionId: session.id })
152
+ );
153
+ return { removed, entryId, path: row.path };
154
+ }
155
+
156
+ /**
157
+ * Of `sessionIds`, the ones owning a managed worktree whose removal would be
158
+ * refused without `force` (dirty or unmerged work, another session's
159
+ * reference, retained recovery data): the desktop's auto-delete keeps those
160
+ * sessions archived. Read-only; a check that fails counts as holding work.
161
+ */
162
+ async function getSessionWorktreeWork({ sessionIds = [] } = {}) {
163
+ const wanted = new Set((Array.isArray(sessionIds) ? sessionIds : []).filter((id) => typeof id === 'string' && id));
164
+ const holding = new Set();
165
+ if (!wanted.size) return { sessionIds: [] };
166
+ const manager = await backend();
167
+ for (const row of await listWorktrees()) {
168
+ const owner = row.ownerSessionId;
169
+ if (!wanted.has(owner) || holding.has(owner)) continue;
170
+ try {
171
+ await manager.assertWorktreeRemovable({ entryId: row.id, sessionId: owner });
172
+ } catch {
173
+ holding.add(owner);
174
+ }
175
+ }
176
+ return { sessionIds: [...holding] };
177
+ }
178
+
179
+ /** Archived (or restored) sessions: autoCleanup and cleanupArchived decide whether their worktrees become disposable. */
180
+ async function setArchivedSessionWorktrees({ sessionIds = [], archived = false } = {}) {
181
+ const settings = worktreeSettings();
182
+ return maintenance.setArchivedSessionWorktrees(sessionIds, archived === true, {
183
+ manager: await backend(),
184
+ autoCleanup: settings.autoCleanup,
185
+ cleanupArchived: settings.cleanupArchived,
76
186
  });
77
187
  }
78
188
 
79
- return { listWorktrees, pruneWorktrees, removeOrphanWorktree, cleanupDeletedSession };
189
+ return {
190
+ listWorktrees,
191
+ pruneWorktrees,
192
+ previewWorktreeCleanup,
193
+ deleteWorktree,
194
+ removeOrphanWorktree,
195
+ removeOwnedWorktree,
196
+ getSessionWorktreeWork,
197
+ setArchivedSessionWorktrees,
198
+ cleanupDeletedSession,
199
+ };
80
200
  }