mixdog 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. package/README.md +8 -4
  2. package/package.json +8 -8
  3. package/scripts/native-release-status.mjs +238 -0
  4. package/scripts/verify-runtime-dependency-versions.mjs +158 -0
  5. package/src/agents/reviewer/AGENT.md +5 -7
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +9 -1
  8. package/src/defaults/skills/browser-use/SKILL.md +6 -3
  9. package/src/defaults/skills/local-provider/SKILL.md +33 -6
  10. package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
  11. package/src/defaults/skills/setup/SKILL.md +23 -1
  12. package/src/defaults/skills/setup/references/actions.md +50 -3
  13. package/src/defaults/skills/setup/references/surfaces.md +23 -3
  14. package/src/defaults/skills/setup-guide/SKILL.md +7 -3
  15. package/src/defaults/skills/visualize/SKILL.md +9 -6
  16. package/src/defaults/skills/visualize/references/craft.md +8 -1
  17. package/src/help.mjs +1 -1
  18. package/src/lib/keychain-cjs.cjs +4 -1
  19. package/src/lib/rules-builder.cjs +14 -7
  20. package/src/rules/agent-mode/AGENT_MODE.md +8 -5
  21. package/src/rules/agent-mode/MIXY.md +6 -8
  22. package/src/rules/lead/LEAD.md +7 -10
  23. package/src/rules/shared/10-tool-workflow.md +4 -0
  24. package/src/rules/shared/20-research.md +2 -0
  25. package/src/rules/shared/45-destructive.md +5 -1
  26. package/src/rules/shared/60-verification.md +6 -4
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
  29. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
  30. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
  31. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
  32. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
  33. package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
  34. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
  35. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  36. package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
  37. package/src/runtime/agent/orchestrator/config.mjs +11 -0
  38. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
  39. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
  40. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
  41. package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +84 -32
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
  45. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
  46. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +84 -42
  48. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
  49. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
  50. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
  51. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
  52. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
  54. package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
  55. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
  56. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
  57. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
  59. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
  60. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
  61. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
  62. package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
  64. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
  65. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
  66. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
  67. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
  68. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
  69. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
  70. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
  72. package/src/runtime/agent/orchestrator/providers/registry.mjs +19 -0
  73. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
  74. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
  75. package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
  76. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
  78. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
  79. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
  81. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
  82. package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
  83. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +52 -6
  85. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +35 -13
  86. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
  87. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +8 -3
  90. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
  92. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
  93. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
  94. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -2
  95. package/src/runtime/agent/orchestrator/session/agent-room.mjs +196 -45
  96. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
  97. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  98. package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
  99. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +45 -19
  100. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
  101. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
  102. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +185 -37
  103. package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +6 -2
  107. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +4 -1
  108. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  109. package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
  110. package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +240 -0
  111. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +102 -35
  112. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
  113. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +19 -9
  114. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
  115. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
  116. package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
  117. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
  118. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +199 -109
  119. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
  120. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
  121. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
  123. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
  124. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
  125. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
  126. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -0
  127. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
  128. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +33 -8
  129. package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
  130. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +27 -0
  131. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
  132. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
  133. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
  134. package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
  135. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
  136. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
  137. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
  138. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +27 -14
  139. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +14 -0
  140. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
  143. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
  144. package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +115 -0
  145. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
  146. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
  147. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
  148. package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
  149. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
  150. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
  151. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
  155. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
  156. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +4 -9
  157. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +14 -1
  158. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
  160. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
  161. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +52 -11
  163. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +126 -12
  166. package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
  167. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +16 -3
  168. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
  169. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
  170. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
  171. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
  172. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
  173. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
  174. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +15 -5
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +49 -1
  178. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +80 -1
  179. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
  180. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
  181. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
  182. package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
  183. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
  184. package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
  185. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
  186. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
  189. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
  190. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +47 -14
  191. package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +6 -3
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
  196. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
  199. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +10 -12
  200. package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
  201. package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
  202. package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
  203. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
  204. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
  205. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +42 -23
  206. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
  207. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
  208. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
  209. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
  210. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
  211. package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
  212. package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
  213. package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
  214. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
  215. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
  216. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
  217. package/src/runtime/attachments/attachment-reference.mjs +155 -0
  218. package/src/runtime/attachments/legacy-office.mjs +110 -0
  219. package/src/runtime/attachments/limits.mjs +5 -1
  220. package/src/runtime/attachments/office-extract.mjs +3 -6
  221. package/src/runtime/attachments/pdf-extract.mjs +84 -10
  222. package/src/runtime/attachments/prompt-restore.mjs +70 -0
  223. package/src/runtime/attachments/store.mjs +109 -33
  224. package/src/runtime/browser-bridge/client.mjs +73 -20
  225. package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
  226. package/src/runtime/channels/lib/scheduler.mjs +14 -7
  227. package/src/runtime/channels/lib/state-file.mjs +15 -15
  228. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
  229. package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
  230. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
  231. package/src/runtime/channels/lib/worker-main.mjs +3 -2
  232. package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
  233. package/src/runtime/effort-judge/judge-client.mjs +66 -16
  234. package/src/runtime/effort-judge/model-install.mjs +47 -7
  235. package/src/runtime/local-provider/asset-installer.mjs +10 -4
  236. package/src/runtime/local-provider/catalog.mjs +5 -2
  237. package/src/runtime/local-provider/registered-models.mjs +64 -27
  238. package/src/runtime/local-provider/server.mjs +2 -3
  239. package/src/runtime/media/adapters/image-api.mjs +89 -0
  240. package/src/runtime/media/auth.mjs +64 -1
  241. package/src/runtime/media/catalog.mjs +66 -4
  242. package/src/runtime/media/jobs.mjs +4 -0
  243. package/src/runtime/media/lanes.mjs +46 -5
  244. package/src/runtime/media/media-usage.mjs +17 -0
  245. package/src/runtime/media/renditions.mjs +15 -15
  246. package/src/runtime/media/store.mjs +36 -35
  247. package/src/runtime/media/tool.mjs +8 -1
  248. package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
  249. package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
  250. package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
  251. package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
  252. package/src/runtime/memory/lib/pg/process.mjs +8 -4
  253. package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
  254. package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
  255. package/src/runtime/office/core/journal.mjs +7 -14
  256. package/src/runtime/office/design/library/design-library-core.mjs +4 -16
  257. package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
  258. package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
  259. package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
  260. package/src/runtime/office/pdf/pdf-render.mjs +30 -18
  261. package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
  262. package/src/runtime/office/portable/portable-soffice.mjs +135 -29
  263. package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
  264. package/src/runtime/shared/agent-avatar.mjs +3 -2
  265. package/src/runtime/shared/agent-kind-migration.mjs +200 -0
  266. package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
  267. package/src/runtime/shared/agent-message-envelope.mjs +44 -0
  268. package/src/runtime/shared/agent-reap-state.d.mts +4 -0
  269. package/src/runtime/shared/agent-room-host.d.mts +31 -0
  270. package/src/runtime/shared/agent-room-host.mjs +58 -0
  271. package/src/runtime/shared/agent-store.mjs +24 -7
  272. package/src/runtime/shared/agent-task-starts.mjs +27 -0
  273. package/src/runtime/shared/atomic-file.d.mts +50 -0
  274. package/src/runtime/shared/atomic-file.mjs +394 -132
  275. package/src/runtime/shared/background-tasks.mjs +7 -4
  276. package/src/runtime/shared/bot-hops.mjs +35 -0
  277. package/src/runtime/shared/bot-split-migration.mjs +1 -1
  278. package/src/runtime/shared/bounded-download.mjs +4 -2
  279. package/src/runtime/shared/config.mjs +39 -9
  280. package/src/runtime/shared/defaults-separation.mjs +6 -2
  281. package/src/runtime/shared/delegated-approval-host.mjs +74 -0
  282. package/src/runtime/shared/err-text.mjs +4 -0
  283. package/src/runtime/shared/error-presentation.mjs +22 -4
  284. package/src/runtime/shared/file-has-data.mjs +28 -0
  285. package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
  286. package/src/runtime/shared/pending-agent-work.mjs +54 -0
  287. package/src/runtime/shared/process-lifecycle.mjs +8 -12
  288. package/src/runtime/shared/projects.mjs +50 -41
  289. package/src/runtime/shared/provider-accounts.mjs +17 -12
  290. package/src/runtime/shared/redact-directories.mjs +18 -0
  291. package/src/runtime/shared/remove-directory.mjs +28 -0
  292. package/src/runtime/shared/routine-trigger.d.mts +6 -1
  293. package/src/runtime/shared/routine-trigger.mjs +14 -6
  294. package/src/runtime/shared/run-child.d.mts +3 -0
  295. package/src/runtime/shared/run-child.mjs +24 -3
  296. package/src/runtime/shared/session-baseline-store.mjs +8 -2
  297. package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
  298. package/src/runtime/shared/session-sidebar-host.mjs +16 -3
  299. package/src/runtime/shared/singleton-owner.mjs +7 -6
  300. package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
  301. package/src/runtime/shared/staged-update.mjs +4 -2
  302. package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
  303. package/src/runtime/shared/tool-execution-contract.mjs +10 -0
  304. package/src/runtime/shared/tool-work-units.mjs +12 -9
  305. package/src/runtime/shared/transcript-metadata.mjs +28 -3
  306. package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
  307. package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
  308. package/src/runtime/shared/turn-snapshot.mjs +277 -124
  309. package/src/runtime/shared/user-cwd.mjs +9 -4
  310. package/src/runtime/shared/user-data-guard.mjs +92 -61
  311. package/src/runtime/shared/utf8-cut.mjs +10 -0
  312. package/src/runtime/shared/worktrees/activity-gate.mjs +251 -61
  313. package/src/runtime/shared/worktrees/contract.mjs +11 -3
  314. package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
  315. package/src/runtime/shared/worktrees/manager.mjs +419 -52
  316. package/src/runtime/shared/worktrees/registry.mjs +29 -27
  317. package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
  318. package/src/runtime/tidy/core-install.mjs +26 -4
  319. package/src/runtime/tidy/install.mjs +91 -23
  320. package/src/runtime/tidy/process.mjs +41 -8
  321. package/src/runtime/tidy/resolve.mjs +10 -7
  322. package/src/runtime/web-search/lib/config.mjs +4 -16
  323. package/src/session-runtime/agent-home-delivery.mjs +542 -204
  324. package/src/session-runtime/agent-profile-changes.mjs +16 -0
  325. package/src/session-runtime/agent-room-delivery.mjs +81 -35
  326. package/src/session-runtime/agent-task-sessions.mjs +811 -179
  327. package/src/session-runtime/agent-tool-routing.mjs +1 -0
  328. package/src/session-runtime/boot/apis.mjs +48 -24
  329. package/src/session-runtime/boot/config.mjs +1 -0
  330. package/src/session-runtime/boot/facade.mjs +16 -7
  331. package/src/session-runtime/boot/infrastructure.mjs +14 -2
  332. package/src/session-runtime/boot/providers.mjs +2 -2
  333. package/src/session-runtime/boot/shared.mjs +12 -6
  334. package/src/session-runtime/boot/tools.mjs +23 -3
  335. package/src/session-runtime/bot-status.mjs +432 -0
  336. package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
  337. package/src/session-runtime/config-lifecycle.mjs +60 -55
  338. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
  339. package/src/session-runtime/held-requests.mjs +31 -33
  340. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
  341. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
  342. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +24 -26
  343. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  344. package/src/session-runtime/lifecycle/teardown.mjs +11 -3
  345. package/src/session-runtime/mcp-glue/connect.mjs +100 -186
  346. package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
  347. package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
  348. package/src/session-runtime/media-api.mjs +5 -2
  349. package/src/session-runtime/model-recency.mjs +1 -0
  350. package/src/session-runtime/model-route/route-tuning.mjs +4 -1
  351. package/src/session-runtime/model-route/set-route.mjs +61 -1
  352. package/src/session-runtime/owned-automation-run.mjs +8 -1
  353. package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
  354. package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
  355. package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
  356. package/src/session-runtime/route-resolution.mjs +16 -8
  357. package/src/session-runtime/route-state.mjs +1 -59
  358. package/src/session-runtime/routine-home-turn.mjs +5 -3
  359. package/src/session-runtime/runtime-bootstrap.mjs +5 -3
  360. package/src/session-runtime/runtime-paths.mjs +11 -5
  361. package/src/session-runtime/runtime-review-api.mjs +4 -1
  362. package/src/session-runtime/runtime-tunables.mjs +6 -0
  363. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
  364. package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
  365. package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
  366. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
  367. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +34 -19
  368. package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
  369. package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
  370. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +7 -0
  371. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
  372. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
  373. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
  374. package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
  375. package/src/session-runtime/services/agent-tool.mjs +6 -0
  376. package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
  377. package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
  378. package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
  379. package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
  380. package/src/session-runtime/services/plugin-admin.mjs +26 -26
  381. package/src/session-runtime/services/provider-admin.mjs +26 -6
  382. package/src/session-runtime/services/schedule-access.mjs +33 -4
  383. package/src/session-runtime/services/seeds.mjs +4 -3
  384. package/src/session-runtime/services/usage-dashboard.mjs +1 -1
  385. package/src/session-runtime/services/usage-stats-model.mjs +2 -1
  386. package/src/session-runtime/services/worktree-access.mjs +27 -0
  387. package/src/session-runtime/session-create/materialize.mjs +2 -3
  388. package/src/session-runtime/session-create/session-options.mjs +15 -2
  389. package/src/session-runtime/session-hooks.mjs +9 -17
  390. package/src/session-runtime/settings-builtin-tools-api.mjs +65 -1
  391. package/src/session-runtime/settings-compaction-api.mjs +86 -39
  392. package/src/session-runtime/setup-tool/executor.mjs +12 -2
  393. package/src/session-runtime/setup-tool/settings-contract.mjs +34 -1
  394. package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
  395. package/src/session-runtime/skills-api.mjs +12 -5
  396. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +349 -0
  397. package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
  398. package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
  399. package/src/session-runtime/tool-policy/policy-stage.mjs +183 -0
  400. package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
  401. package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
  402. package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
  403. package/src/session-runtime/tool-policy-refresh.mjs +48 -369
  404. package/src/session-runtime/tool-surface.mjs +10 -4
  405. package/src/session-runtime/turn/session-ops.mjs +8 -0
  406. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
  407. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  408. package/src/session-runtime/turn/turn-run.mjs +7 -2
  409. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
  410. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +527 -333
  411. package/src/session-runtime/workflow-agents-api/agent-route.mjs +85 -63
  412. package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
  413. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
  414. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
  415. package/src/session-runtime/workspace/transition-steps.mjs +1 -18
  416. package/src/session-runtime/workspace/transitions.mjs +279 -67
  417. package/src/session-runtime/workspace/workspace-state.mjs +7 -6
  418. package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
  419. package/src/standalone/daemon-agent-control.mjs +4 -1
  420. package/src/standalone/daemon-lag-profiler.mjs +3 -1
  421. package/src/standalone/daemon-session-control.mjs +173 -15
  422. package/src/standalone/daemon-telemetry.mjs +9 -0
  423. package/src/standalone/daemon.mjs +33 -10
  424. package/src/standalone/local-session-runtime.mjs +33 -16
  425. package/src/standalone/session-client.mjs +7 -2
  426. package/src/standalone/session-protocol.mjs +8 -0
  427. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
  428. package/src/standalone/session-service/agent-route-follow.mjs +69 -0
  429. package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
  430. package/src/standalone/session-service.mjs +21 -0
  431. package/src/standalone/session-state-projection.mjs +19 -9
  432. package/src/standalone/session-tool-output.mjs +36 -9
  433. package/src/standalone/staged-import.mjs +47 -0
  434. package/src/tui/App.jsx +2 -0
  435. package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
  436. package/src/tui/app/message-selector.mjs +15 -2
  437. package/src/tui/app/model-options.mjs +16 -2
  438. package/src/tui/app/model-picker.mjs +2 -1
  439. package/src/tui/app/route-pickers.mjs +3 -1
  440. package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
  441. package/src/tui/app/slash-commands.mjs +1 -1
  442. package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
  443. package/src/tui/dist/index.mjs +617 -369
  444. package/src/tui/paste-attachments.mjs +0 -1
  445. package/src/tui/paste-text-policy.mjs +4 -5
  446. package/src/tui/prompt-history-store.mjs +16 -21
  447. package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
  448. package/src/tui/session/context-state.mjs +4 -0
  449. package/src/tui/session/notice-surface.mjs +3 -0
  450. package/src/tui/session/session-api/intake/abort.mjs +52 -18
  451. package/src/tui/session/session-api/intake/rewind.mjs +39 -4
  452. package/src/tui/session/session-api/media.mjs +2 -1
  453. package/src/tui/session/session-api/routes-agent-definitions.mjs +76 -0
  454. package/src/tui/session/session-api/routes-write.mjs +203 -0
  455. package/src/tui/session/session-api/routes.mjs +23 -247
  456. package/src/tui/session/session-api/settings.mjs +14 -1
  457. package/src/tui/session/session-flow/drain.mjs +28 -3
  458. package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
  459. package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
  460. package/src/tui/session/session-flow/steering.mjs +8 -3
  461. package/src/tui/session/tool-approval.mjs +142 -14
  462. package/src/tui/session/transcript-intake.mjs +2 -0
  463. package/src/tui/session/turn.mjs +23 -14
  464. package/src/tui/transcript-tool-failures.mjs +8 -2
  465. package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
  466. package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
  467. package/src/rules/agent-mode/ROUTINE.md +0 -6
  468. package/src/session-runtime/room-member-gate.mjs +0 -48
@@ -0,0 +1,194 @@
1
+ /**
2
+ * The Lead's managed-worktree operations behind the `git` tool
3
+ * (`action: "worktree"` and the mapped `git worktree …` commands), over the
4
+ * same workspace authority the desktop branch menu drives:
5
+ *
6
+ * - The caller's own session runs through this runtime's workspace API with
7
+ * `ownTurn` (the calling turn is tolerated; workers, background shells and
8
+ * other sessions in an affected folder are not).
9
+ * - Another session runs through session control (the daemon's
10
+ * `session.configure` lane): no `ownTurn`, so a target with a running turn,
11
+ * workers or background shells refuses (WORKTREE_BUSY_JOBS).
12
+ *
13
+ * Every failure keeps its typed WorktreeError (code, details); interactive
14
+ * refusals (WORKTREE_DIRTY_CHOICE, WORKTREE_LARGE_REPO_CONFIRM) carry what the
15
+ * caller needs to ask the user before it calls again.
16
+ */
17
+ import { worktreeError, worktreeNameError } from '../../runtime/shared/worktrees/contract.mjs';
18
+ import { samePath } from '../../runtime/shared/worktrees/paths.mjs';
19
+ import { assertWorktreeMutationAllowed, worktreeCallerScope } from '../services/worktree-access.mjs';
20
+
21
+ const loadManager = () => import('../../runtime/shared/worktrees/manager.mjs');
22
+
23
+ /**
24
+ * @param {object} deps
25
+ * @param {() => any} deps.getSession The Lead session this runtime hosts (its trusted caller scope).
26
+ * @param {() => any} deps.getWorkspaceApi The runtime's workspace transitions (late-bound).
27
+ * @param {((args: object, context: object) => Promise<any>)|null} [deps.executeSessionControl] Cross-session lane.
28
+ * @param {object|null} [deps.manager] Managed-worktree backend override (tests).
29
+ */
30
+ export function createWorktreeToolHost({
31
+ getSession,
32
+ getWorkspaceApi,
33
+ executeSessionControl = null,
34
+ manager = null,
35
+ }) {
36
+ const backend = () => (manager ? Promise.resolve(manager) : loadManager());
37
+
38
+ function workspaceApi() {
39
+ const api = getWorkspaceApi();
40
+ if (!api) throw new Error('git worktree: managed worktrees are unavailable in this runtime');
41
+ return api;
42
+ }
43
+
44
+ /**
45
+ * The workspace lane of `sessionId`: the caller's own (null/equal) or
46
+ * another session's, which carries the caller's trusted `scope` for the
47
+ * daemon to check again.
48
+ */
49
+ function laneFor(sessionId, callerSessionId, scope) {
50
+ if (!sessionId || sessionId === callerSessionId) {
51
+ const api = workspaceApi();
52
+ return {
53
+ own: true,
54
+ menu: () => api.getBranchMenu(),
55
+ call: (method, input) => api[method](input, { ownTurn: true }),
56
+ };
57
+ }
58
+ if (typeof executeSessionControl !== 'function') {
59
+ throw new Error("git worktree: another session's workspace is unavailable in this runtime");
60
+ }
61
+ const control = (method, input) =>
62
+ executeSessionControl(
63
+ { action: 'worktree', session_id: sessionId, method, ...(input ? { input } : {}) },
64
+ { callerSessionId, callerScope: scope }
65
+ );
66
+ return { own: false, menu: () => control('getBranchMenu'), call: control };
67
+ }
68
+
69
+ async function enter(lane, request) {
70
+ if (request.branch) {
71
+ return lane.call('selectBranch', {
72
+ branch: request.branch,
73
+ create: request.create === true,
74
+ confirmLarge: request.confirmLarge === true,
75
+ txId: request.txId,
76
+ });
77
+ }
78
+ // A valid slug names the worktree; any other text is a hint the slug is made from.
79
+ const name = typeof request.name === 'string' ? request.name.trim() : '';
80
+ const slug = name && !worktreeNameError(name) ? name : null;
81
+ return lane.call('requestWorktree', {
82
+ provision: true,
83
+ name: slug,
84
+ prompt: slug ? '' : name,
85
+ ...(request.carry ? { carryChanges: request.carry } : {}),
86
+ confirmLarge: request.confirmLarge === true,
87
+ txId: request.txId,
88
+ });
89
+ }
90
+
91
+ /** Back to the project folder (the branch checked out there); the worktree stays retained. */
92
+ async function back(lane, request) {
93
+ const menu = await lane.menu();
94
+ const workspace = menu.workspace;
95
+ if (!workspace.worktreeId && samePath(workspace.cwd, workspace.projectPath)) {
96
+ return { revision: workspace.revision, workspace, unchanged: true };
97
+ }
98
+ const projectBranch = menu.occupancy.find((row) => row.kind === 'current')?.branch ?? null;
99
+ if (!projectBranch) {
100
+ throw worktreeError(
101
+ 'WORKTREE_UNSUPPORTED_REPO',
102
+ 'The project folder has no checked-out branch to return to (detached HEAD).'
103
+ );
104
+ }
105
+ return lane.call('selectBranch', { branch: projectBranch, expectedRevision: workspace.revision, txId: request.txId });
106
+ }
107
+
108
+ /** The desktop's "merge": into the confirmed merge target, then the cleanup autoCleanup allows. */
109
+ async function merge(lane) {
110
+ const { workspace } = await lane.menu();
111
+ return lane.call('mergeWorkspace', {
112
+ confirmed: true,
113
+ target: workspace.mergeTarget ?? null,
114
+ expectedRevision: workspace.revision,
115
+ cleanup: true,
116
+ });
117
+ }
118
+
119
+ /**
120
+ * `git worktree remove <path>`: the managed removal of whichever owner
121
+ * holds it — this session's snapshot, or the worktree a session retains
122
+ * (its own lane: the same guards as the desktop's removal).
123
+ */
124
+ async function removePath(request, callerSessionId, scope) {
125
+ const entry = await (await backend()).getWorktreeByPath(request.path);
126
+ if (!entry) {
127
+ throw new Error(
128
+ `git worktree remove: ${request.path} is not a Mixdog-managed worktree; unmanaged worktrees are not removed through the git tool`
129
+ );
130
+ }
131
+ if (entry.kind === 'snapshot') return workspaceApi().removeSnapshot({ path: entry.path, force: request.force });
132
+ if (!entry.ownerSessionId) {
133
+ throw new Error(
134
+ `git worktree remove: no session retains ${entry.path}; git worktree prune removes it once it is clean and merged`
135
+ );
136
+ }
137
+ const lane = laneFor(entry.ownerSessionId, callerSessionId, scope);
138
+ const menu = await lane.menu();
139
+ if (menu.retainedWorktree?.id !== entry.id) {
140
+ throw new Error(
141
+ `git worktree remove: ${entry.path} is not the current worktree of session ${entry.ownerSessionId}; enter it (worktree_action enter, branch ${entry.branch}) first, then remove it`
142
+ );
143
+ }
144
+ return lane.call('removeWorktree', { force: request.force === true, expectedRevision: menu.workspace.revision });
145
+ }
146
+
147
+ /**
148
+ * @param {{ op: string } & Record<string, any>} request
149
+ * @param {{ callerSessionId: string }} context
150
+ */
151
+ async function run(request, { callerSessionId }) {
152
+ // Trusted state of the calling Lead, never model input: every operation
153
+ // but `list` needs an attended conversation.
154
+ const scope = worktreeCallerScope(getSession());
155
+ if (request.op !== 'list') assertWorktreeMutationAllowed(scope, `git worktree ${request.op}`);
156
+ const lane = () => laneFor(request.sessionId, callerSessionId, scope);
157
+ switch (request.op) {
158
+ case 'enter':
159
+ return enter(lane(), request);
160
+ case 'return':
161
+ return back(lane(), request);
162
+ case 'merge':
163
+ return merge(lane());
164
+ case 'remove':
165
+ return lane().call('removeWorktree', { force: request.force === true });
166
+ case 'list':
167
+ return workspaceApi().listWorktrees({ includeSnapshots: true });
168
+ case 'prune':
169
+ return workspaceApi().pruneWorktrees({ repoCommonDir: request.repoCommonDir ?? null });
170
+ case 'add':
171
+ return workspaceApi().addBranchWorktree({
172
+ branch: request.branch,
173
+ create: request.create === true,
174
+ startPoint: request.startPoint ?? null,
175
+ confirmLarge: request.confirmLarge === true,
176
+ txId: request.txId,
177
+ repoCommonDir: request.repoCommonDir ?? null,
178
+ });
179
+ case 'snapshot':
180
+ return workspaceApi().createSnapshot({
181
+ commit: request.commit,
182
+ confirmLarge: request.confirmLarge === true,
183
+ txId: request.txId,
184
+ repoCommonDir: request.repoCommonDir ?? null,
185
+ });
186
+ case 'remove-path':
187
+ return removePath(request, callerSessionId, scope);
188
+ default:
189
+ throw new TypeError(`git worktree: unknown operation ${request.op}`);
190
+ }
191
+ }
192
+
193
+ return { run };
194
+ }
@@ -54,7 +54,10 @@ export function createCanonicalAgentControl({ getSessionService, getSessionRunti
54
54
  ownerSessionId: sessionService.rootOwnerSessionId(parentSessionId),
55
55
  };
56
56
  if (String(args?.type || '') === '__close_all') {
57
- await tool.closeAll?.(String(args?.reason || 'agent owner closed'), { callerSessionId: parentSessionId || null });
57
+ await tool.closeAll?.(String(args?.reason || 'agent owner closed'), {
58
+ callerSessionId: parentSessionId || null,
59
+ processExit: args?.processExit === true,
60
+ });
58
61
  await sessionService.cancelAgentDescendants(parentSessionId, String(args?.reason || 'agent owner closed'));
59
62
  return 'agent close all: ok';
60
63
  }
@@ -20,7 +20,9 @@ export const LAG_PROFILE_KEEP = 10;
20
20
  export const LAG_PROFILE_TOP = 15;
21
21
  export const LAG_PROFILE_SAMPLING_US = 1000;
22
22
  export const LAG_P99_THRESHOLD_MS = 1000;
23
- export const LAG_MAX_THRESHOLD_MS = 2000;
23
+ // The owner lease's stall threshold: any window holding one logged
24
+ // `event loop stalled` line is kept.
25
+ export const LAG_MAX_THRESHOLD_MS = 1000;
24
26
 
25
27
  const PROFILE_FILE_RE = /^daemon-lag-.+\.cpuprofile$/;
26
28
  const SRC_ROOT = fileURLToPath(new URL('..', import.meta.url));
@@ -1,19 +1,85 @@
1
1
  import { SESSION_ID_PATTERN } from '../runtime/agent/orchestrator/runtime-core/session-id.mjs';
2
2
  import { sessionListOutput, sessionReadOutput, SESSION_TOOL_OUTPUT_BYTES } from './session-tool-output.mjs';
3
3
  import { createAgentTaskSessions } from '../session-runtime/agent-task-sessions.mjs';
4
+ import { assertWorktreeMutationAllowed } from '../session-runtime/services/worktree-access.mjs';
5
+ import { createBotStatus, scanCatalog, scopedBot, sessionBotOf } from '../session-runtime/bot-status.mjs';
4
6
  import { handoffContent } from '../session-runtime/handoff-attachments.mjs';
7
+ import { BOT_HOP_LIMIT_ERROR, MAX_BOT_HOPS } from '../runtime/shared/bot-hops.mjs';
8
+ import { rebindDelegation } from '../runtime/agent/orchestrator/session/human-gate/delegation.mjs';
9
+ import { isAgentOnlySession } from '../runtime/agent/orchestrator/session/store-summary-visibility.mjs';
10
+ import { readSessionSidebarState } from '../runtime/shared/session-sidebar-host.mjs';
11
+ import { agentRoomHost } from '../runtime/shared/agent-room-host.mjs';
12
+ import {
13
+ roomIdOfSession,
14
+ roomMemberOfSession,
15
+ roomSessionId,
16
+ } from '../runtime/agent/orchestrator/session/agent-room.mjs';
5
17
 
6
18
  const TARGET_ACTIONS = new Set(['status', 'read', 'send', 'cancel', 'delete']);
7
19
  const MUTATING_ACTIONS = new Set(['send', 'cancel', 'delete']);
20
+ // The workspace methods `worktree` reaches on another session (all on the
21
+ // session protocol's read/configure allowlists).
22
+ const WORKTREE_METHODS = new Set(['getBranchMenu', 'requestWorktree', 'selectBranch', 'mergeWorkspace', 'removeWorktree']);
23
+ // Why a send from a conversation that is no bot's reports nothing back.
24
+ const NOT_BOT_REASON = 'only a bot conversation gets session results reported back; check that session for the result';
25
+
26
+ /** The member a send to room log `sessionId` addresses, through the desktop
27
+ * room host: `{ host, agentId, sessionId, text }`; throws when no desktop is
28
+ * attached or no member resolves. */
29
+ async function roomAddressee(sessionId, args) {
30
+ let host;
31
+ try {
32
+ host = agentRoomHost();
33
+ } catch (error) {
34
+ throw new Error(`session: cannot send to ${sessionId}: ${error.message}`);
35
+ }
36
+ const member = await host.member(sessionId, { to: args.to, prompt: args.prompt }).catch((error) => {
37
+ throw new Error(`session: ${error?.message || error}`);
38
+ });
39
+ return { host, ...member };
40
+ }
8
41
 
9
42
  /** Model-facing session operations over the same service used by desktop and TUI. */
10
43
  export function createSessionControl({
11
44
  getSessionService,
12
45
  agentTasks = createAgentTaskSessions({ getSessionService }),
46
+ botStatus = createBotStatus({ getSessionService }),
13
47
  }) {
48
+ /**
49
+ * Another session's workspace for the git tool's worktree operations
50
+ * (session-runtime/workspace/worktree-tool.mjs): one workspace method with
51
+ * one input, through the same configure / read lanes the desktop uses. No
52
+ * `ownTurn` ever crosses: the target must be idle. A change (anything but
53
+ * the menu read) needs the caller's trusted scope (`callerScope`, from
54
+ * worktree-access.mjs worktreeCallerScope) to be an attended conversation.
55
+ */
56
+ async function worktreeControl(args, caller, callerScope) {
57
+ const sessionId = typeof args.session_id === 'string' ? args.session_id.trim() : '';
58
+ if (!SESSION_ID_PATTERN.test(sessionId)) throw new Error('session: session_id is required for action=worktree');
59
+ if (sessionId === caller) throw new Error('session: worktree control must target another session');
60
+ if (!WORKTREE_METHODS.has(args.method)) throw new Error(`session: unsupported worktree method "${args.method}"`);
61
+ if (args.method !== 'getBranchMenu') assertWorktreeMutationAllowed(callerScope, `session: worktree ${args.method}`);
62
+ const service = getSessionService();
63
+ if (!service) throw new Error('session: session service is unavailable');
64
+ if (args.method === 'getBranchMenu') {
65
+ return (await service.readSession({ sessionId, action: 'getBranchMenu', args: [] })).value;
66
+ }
67
+ const result = await service.configureSession(
68
+ { sessionId, action: args.method, args: [args.input ?? {}] },
69
+ { revision: 1 }
70
+ );
71
+ return result.value;
72
+ }
73
+
14
74
  return async function executeSessionControl(args = {}, context = {}) {
15
75
  const action = args.action;
16
- if (action !== 'list' && action !== 'create' && !TARGET_ACTIONS.has(action)) {
76
+ if (
77
+ action !== 'list' &&
78
+ action !== 'create' &&
79
+ action !== 'bots' &&
80
+ action !== 'worktree' &&
81
+ !TARGET_ACTIONS.has(action)
82
+ ) {
17
83
  throw new Error(`session: unsupported remote action "${action}"`);
18
84
  }
19
85
  const caller = context.callerSessionId;
@@ -22,8 +88,11 @@ export function createSessionControl({
22
88
  }
23
89
  // `callerAgentId`: set only for an attended agent conversation (workspace-tools.mjs).
24
90
  if (action === 'create') return agentTasks.create(args, context);
91
+ if (action === 'worktree') return worktreeControl(args, caller, context.callerScope);
92
+ // `callerScope`: the caller's schedule-access scope (workspace-tools.mjs).
93
+ if (action === 'bots') return botStatus(args, context);
25
94
  const sessionId = typeof args.session_id === 'string' ? args.session_id.trim() : '';
26
- if (TARGET_ACTIONS.has(action) && (typeof sessionId !== 'string' || !SESSION_ID_PATTERN.test(sessionId))) {
95
+ if (TARGET_ACTIONS.has(action) && !SESSION_ID_PATTERN.test(sessionId)) {
27
96
  throw new Error(`session: session_id is required for action=${action}`);
28
97
  }
29
98
  if (MUTATING_ACTIONS.has(action) && sessionId === caller) {
@@ -45,31 +114,121 @@ export function createSessionControl({
45
114
  const service = getSessionService();
46
115
  if (!service) throw new Error('session: session service is unavailable');
47
116
  if (action === 'list') {
48
- const page = await service.listSessionCatalog({ page: { limit, cursor: args.cursor || null } });
49
- return sessionListOutput(page, limit);
117
+ for (const flag of ['include_agents', 'include_archived']) {
118
+ if (args[flag] !== undefined && typeof args[flag] !== 'boolean') {
119
+ throw new Error(`session: ${flag} must be a boolean`);
120
+ }
121
+ }
122
+ // Scoped like bots (`callerScope`, bot-status.mjs): the human's sessions
123
+ // list everything, a bot (or its unattended run) only its own sessions,
124
+ // anything else the plain rows without previews. Sub-agent sessions (a
125
+ // parent finds its own through the agent tool) and archived ones (the
126
+ // desktop's flag) only on request; the scan pages past the rows left
127
+ // out, so a page is never short while more rows match.
128
+ const own = scopedBot(context.callerScope);
129
+ const archived = (await readSessionSidebarState())?.archived ?? {};
130
+ const keep = (row) =>
131
+ (!own || sessionBotOf(row) === own) &&
132
+ (args.include_agents === true || !isAgentOnlySession(row)) &&
133
+ (args.include_archived === true || !Object.hasOwn(archived, row.id));
134
+ // Bounded: past 10000 rows scanned with fewer than `limit` matching, the
135
+ // page ends (possibly empty) with a nextCursor to continue from.
136
+ const scan = await scanCatalog(service, keep, { cursor: args.cursor || null, want: limit, maxRows: 10_000 });
137
+ const sessions = scan.rows.map((row) => (Object.hasOwn(archived, row.id) ? { ...row, archived: true } : row));
138
+ return sessionListOutput({ sessions, nextCursor: scan.nextCursor }, limit, { rich: own !== null });
50
139
  }
51
140
  if (action === 'send') {
52
141
  if (typeof args.prompt !== 'string' || !args.prompt.trim()) {
53
142
  throw new Error('session: prompt is required for action=send');
54
143
  }
144
+ // A room member's session is the room's to drive: a message goes to the
145
+ // room, naming the member.
146
+ if (roomMemberOfSession(sessionId)) {
147
+ throw new Error(
148
+ `session: ${sessionId} is a group-room member's session; send to its room (session_id ${roomSessionId(roomMemberOfSession(sessionId).roomId)}) with to: <member>`
149
+ );
150
+ }
151
+ // A send to a room's log is a message to one member there (`to`, or a
152
+ // leading @name), run by the desktop room host; the member's turn in
153
+ // its member session is the turn that answers and reports.
154
+ const room = roomIdOfSession(sessionId) ? await roomAddressee(sessionId, args) : null;
155
+ if (room?.sessionId === caller) throw new Error('session: send must target another session');
55
156
  // An agent conversation's send reports its turn back to the agent's
56
157
  // home: a task session it created by its stored origin, any other
57
158
  // session by an origin for this send only.
58
159
  // Forwarded files ride along as stored attachment parts (workspace-tools.mjs).
59
- const prompt = handoffContent(args.prompt, context.attachmentParts);
60
- const origin = await agentTasks.reportOrigin(sessionId, context.callerAgentId, caller);
160
+ const prompt = handoffContent(room ? room.text : args.prompt, context.attachmentParts);
161
+ const turnSessionId = room ? room.sessionId : sessionId;
162
+ const from = { sessionId: caller, ...(context.callerAgentId ? { agentId: context.callerAgentId } : {}) };
163
+ // The member's turn carries the send's hop (`transcriptMeta.hop`), so a
164
+ // chain through the room counts on toward MAX_BOT_HOPS.
165
+ const submit = room
166
+ ? async ({ id, onSettled, follow, transcriptMeta } = {}) => ({
167
+ accepted:
168
+ (await room.host.ask(sessionId, {
169
+ agentId: room.agentId,
170
+ prompt,
171
+ from,
172
+ ...(id ? { id } : {}),
173
+ ...(transcriptMeta?.hop > 0 ? { hop: transcriptMeta.hop } : {}),
174
+ ...(onSettled ? { onSettled } : {}),
175
+ ...(follow ? { follow } : {}),
176
+ })) === true,
177
+ })
178
+ : null;
179
+ const addressed = room ? { to: room.agentId } : {};
180
+ let origin = await agentTasks.reportOrigin(turnSessionId, context.callerAgentId, caller);
181
+ // A send made in a bot-descended turn (`callerHop` > 0), or by a bot to
182
+ // another session, extends the chain by one; a bot's own task session
183
+ // only continues it. Refused past the limit, whatever the target.
184
+ const turnHop = Number(context.callerHop) || 0;
185
+ const chained = (hop) => {
186
+ if (hop > MAX_BOT_HOPS) throw new Error(BOT_HOP_LIMIT_ERROR);
187
+ return hop;
188
+ };
61
189
  if (origin) {
62
- const { accepted, reportsBack } = await agentTasks.send(sessionId, prompt, origin);
63
- return { sessionId, accepted, reportsBack };
190
+ const hop = chained(origin.target === 'session' ? turnHop + 1 : turnHop);
191
+ if (hop > 0) origin = { ...origin, hop };
192
+ // The task session a bot created acts as the sending conversation does
193
+ // from now on (attended chat or run); another's session keeps its own.
194
+ if (origin.target !== 'session') await rebindDelegation(sessionId, caller);
195
+ const sent = await agentTasks.send(turnSessionId, prompt, origin, submit);
196
+ return { sessionId, ...addressed, ...sent, ...(hop > 0 ? { hop } : {}) };
64
197
  }
65
- const result = await service.submitSession({
198
+ const hop = turnHop > 0 ? chained(turnHop + 1) : 0;
199
+ let accepted;
200
+ if (submit) accepted = (await submit(hop > 0 ? { transcriptMeta: { hop } } : {})).accepted;
201
+ else {
202
+ // New work from this sender: a delegated target acts as the sender does.
203
+ await rebindDelegation(sessionId, caller);
204
+ const result = await service.submitSession({
205
+ sessionId,
206
+ prompt,
207
+ options: { mode: 'prompt', transcriptMeta: { sender: 'lead', ...(hop > 0 ? { hop } : {}) } },
208
+ });
209
+ accepted = result.accepted === true;
210
+ }
211
+ return {
66
212
  sessionId,
67
- prompt,
68
- options: { mode: 'prompt', transcriptMeta: { sender: 'lead' } },
69
- });
70
- return { sessionId, accepted: result.accepted === true, reportsBack: false };
213
+ ...addressed,
214
+ accepted,
215
+ reportsBack: false,
216
+ ...(accepted ? { reportsBackReason: NOT_BOT_REASON } : {}),
217
+ ...(hop > 0 ? { hop } : {}),
218
+ };
71
219
  }
72
220
  if (action === 'cancel') {
221
+ // A room's exchange is run by the desktop room host, so its stop (the UI
222
+ // stop button) ends it; the log is not a session the service can abort.
223
+ if (roomIdOfSession(sessionId)) {
224
+ let host;
225
+ try {
226
+ host = agentRoomHost();
227
+ } catch (error) {
228
+ throw new Error(`session: cannot cancel ${sessionId}: ${error.message}`);
229
+ }
230
+ return { sessionId, aborted: host.stop(sessionId) === true };
231
+ }
73
232
  const result = await service.abortSession({ sessionId });
74
233
  return { sessionId, aborted: result.aborted === true };
75
234
  }
@@ -91,7 +250,7 @@ export function createSessionControl({
91
250
  });
92
251
  const snapshot = result.full;
93
252
  if (!snapshot) throw new Error(`session: ${sessionId} is unavailable`);
94
- const status = {
253
+ return {
95
254
  sessionId,
96
255
  title: snapshot.title ?? null,
97
256
  cwd: snapshot.cwd ?? null,
@@ -100,6 +259,5 @@ export function createSessionControl({
100
259
  busy: snapshot.busy === true,
101
260
  quotaResume: snapshot.quotaResume ?? null,
102
261
  };
103
- return status;
104
262
  };
105
263
  }
@@ -184,6 +184,10 @@ export function createDaemonTelemetry({
184
184
  log = () => {},
185
185
  getWork = () => ({}),
186
186
  onInterval = null,
187
+ // Runs once when the loop starts, before its first window: a probe that
188
+ // judges each window (the lag profiler) arms here so the first one covers
189
+ // boot instead of starting only at the first tick.
190
+ onStart = null,
187
191
  now,
188
192
  pid,
189
193
  memoryUsage,
@@ -239,6 +243,11 @@ export function createDaemonTelemetry({
239
243
  }, ms);
240
244
  handle?.unref?.();
241
245
  timer = handle;
246
+ try {
247
+ onStart?.();
248
+ } catch {
249
+ /* a start probe must not stop the sample loop */
250
+ }
242
251
  return timer;
243
252
  }
244
253
 
@@ -359,6 +359,11 @@ slowSpans.setLog(log);
359
359
  daemonTelemetry = createDaemonTelemetry({
360
360
  log,
361
361
  getWork: inFlightWork,
362
+ // Arms the profiler at daemon-ready when lag-profile.on exists (a no-op
363
+ // without it), so the first window holds the startup stalls.
364
+ onStart() {
365
+ void lagProfiler.tick();
366
+ },
362
367
  onInterval() {
363
368
  // eventLoopDelay is reset at the end of every tick, so this status is the
364
369
  // lag of the 30s window that just ended — the same window the lag
@@ -928,7 +933,14 @@ async function main() {
928
933
  });
929
934
  canonicalAgentControl = agentControl;
930
935
  // Agents' cross-session sends and task sessions, and their report watches.
931
- const agentTasks = createAgentTaskSessions({ getSessionService: () => sessionService });
936
+ const agentTasks = createAgentTaskSessions({
937
+ getSessionService: () => sessionService,
938
+ // A task session re-attached after a restart takes its agents' queued
939
+ // results through the owner runtime's notification bus.
940
+ deliverCompletion: (sessionId, text, meta) =>
941
+ sessionRuntimeHost?.notifySessionCompletion?.(sessionId, text, meta) === true,
942
+ settleAgentResults: async () => (await agentControl.canonicalAgentTool()).settleRestartFailures(),
943
+ });
932
944
  const requestedRuntimeMode = String(process.env.MIXDOG_SESSION_RUNTIME_MODE || '')
933
945
  .trim()
934
946
  .toLowerCase();
@@ -990,15 +1002,26 @@ async function main() {
990
1002
  busy: (sessionId) => sessionService.liveSessionBusy(sessionId),
991
1003
  notice: (sessionId, notice) => sessionService.pushLiveSessionNotice(sessionId, notice),
992
1004
  // A task session's result (session create): the agent relays it in one
993
- // turn. Resolves whether the turn was taken.
994
- wake: async (sessionId, prompt, { id } = {}) =>
995
- (
996
- await sessionService.submitSession({
997
- sessionId,
998
- prompt,
999
- options: { mode: 'prompt', kickoff: true, ...(id ? { id } : {}) },
1000
- })
1001
- )?.accepted === true,
1005
+ // turn. Resolves false when the turn was refused, else `{ settled }`, the
1006
+ // turn's end status ('done' when it finished).
1007
+ wake: async (sessionId, prompt, { id, hop = 0 } = {}) => {
1008
+ let settle = () => {};
1009
+ const settled = new Promise((resolveSettled) => {
1010
+ settle = resolveSettled;
1011
+ });
1012
+ const result = await sessionService.submitSession({
1013
+ sessionId,
1014
+ prompt,
1015
+ options: {
1016
+ mode: 'prompt',
1017
+ kickoff: true,
1018
+ ...(id ? { id } : {}),
1019
+ ...(hop > 0 ? { transcriptMeta: { hop } } : {}),
1020
+ onSettled: (detail) => settle(String(detail?.status || 'failed')),
1021
+ },
1022
+ });
1023
+ return result?.accepted === true ? { settled } : false;
1024
+ },
1002
1025
  // A routine fire: one queued turn in its bot's thread (routine-home-turn.mjs).
1003
1026
  submit: async (sessionId, prompt, options) =>
1004
1027
  (await sessionService.submitSession({ sessionId, prompt, options }))?.accepted === true,
@@ -12,7 +12,7 @@ import { performance } from 'node:perf_hooks';
12
12
  import { isDeepStrictEqual } from 'node:util';
13
13
  import { bootProfile } from '../tui/session/boot-profile.mjs';
14
14
  import { createGoalContinuation } from '../tui/session/goal-continuation.mjs';
15
- import { createToolApproval } from '../tui/session/tool-approval.mjs';
15
+ import { createToolApproval, resolveToolApprovalTimeoutMs } from '../tui/session/tool-approval.mjs';
16
16
  import { createToolCardResults } from '../tui/session/tool-card-results.mjs';
17
17
  import { createAgentJobFeed } from '../tui/session/agent-job-feed.mjs';
18
18
  import { createWorktreeSetupNotices } from '../tui/session/worktree-setup-notice.mjs';
@@ -41,13 +41,22 @@ import {
41
41
  createTranscriptSpillBuffer,
42
42
  sweepStaleTranscriptSpillDirsOnce,
43
43
  } from '../tui/session/transcript-spill.mjs';
44
+ import { importInStages } from './staged-import.mjs';
44
45
 
45
46
  const SESSION_RUNTIME_MODULE = '../mixdog-session-runtime.mjs';
47
+ // Its one module (only mixdog-session-runtime.mjs imports it): its boot
48
+ // modules are the graph's stages.
49
+ const SESSION_RUNTIME_CORE = '../session-runtime/runtime-core.mjs';
50
+ const importSessionRuntimeInStages = () =>
51
+ importInStages(
52
+ new URL(SESSION_RUNTIME_MODULE, import.meta.url).href,
53
+ new URL(SESSION_RUNTIME_CORE, import.meta.url).href
54
+ );
46
55
 
47
56
  // Shared across create calls so concurrent session startups import the
48
57
  // runtime graph once.
49
58
  let sessionRuntimeModulePromise = null;
50
- let sessionRuntimeImporter = () => import(SESSION_RUNTIME_MODULE);
59
+ let sessionRuntimeImporter = importSessionRuntimeInStages;
51
60
  function importSessionRuntimeModule() {
52
61
  // A failed import is forgotten so the next caller retries lazily.
53
62
  sessionRuntimeModulePromise ??= Promise.resolve()
@@ -79,14 +88,13 @@ export async function warmLocalSessionRuntime() {
79
88
 
80
89
  /** Test seam: replace the dynamic import of the session-runtime module. */
81
90
  export function setSessionRuntimeImporterForTest(importer) {
82
- sessionRuntimeImporter = importer || (() => import(SESSION_RUNTIME_MODULE));
91
+ sessionRuntimeImporter = importer || importSessionRuntimeInStages;
83
92
  sessionRuntimeModulePromise = null;
84
93
  }
85
94
 
86
- const TOOL_APPROVAL_TIMEOUT_MS = (() => {
87
- const value = Number(process.env.MIXDOG_TOOL_APPROVAL_TIMEOUT_MS);
88
- return Number.isFinite(value) && value > 0 ? Math.max(1000, Math.round(value)) : 120_000;
89
- })();
95
+ // An approval waits until the user answers (Deny, Stop or a closing runtime
96
+ // settle it); MIXDOG_TOOL_APPROVAL_TIMEOUT_MS opts into a limit for tests/ops.
97
+ const TOOL_APPROVAL_TIMEOUT_MS = resolveToolApprovalTimeoutMs();
90
98
 
91
99
  export {
92
100
  cleanupStaleTranscriptSpillDirs,
@@ -306,15 +314,22 @@ export async function createLocalSessionRuntime({
306
314
  pushItem,
307
315
  replaceItems,
308
316
  });
309
- const { presentNextToolApproval, finishToolApproval, denyAllToolApprovals, requestToolApproval } = createToolApproval(
310
- {
311
- getState,
312
- set,
313
- nextId,
314
- getDisposed: () => flags.disposed,
315
- timeoutMs: TOOL_APPROVAL_TIMEOUT_MS,
316
- }
317
- );
317
+ // A sub-agent's approvals also show in the top-level chat (human-gate/gate.mjs).
318
+ const { approvalSurface } = await import('../runtime/agent/orchestrator/session/human-gate/gate.mjs');
319
+ const {
320
+ presentNextToolApproval,
321
+ finishToolApproval,
322
+ denyAllToolApprovals,
323
+ requestToolApproval,
324
+ adoptDelegatedApprovals,
325
+ } = createToolApproval({
326
+ getState,
327
+ set,
328
+ nextId,
329
+ getDisposed: () => flags.disposed,
330
+ timeoutMs: TOOL_APPROVAL_TIMEOUT_MS,
331
+ surfaceOf: approvalSurface,
332
+ });
318
333
  const runtimePulse = createRuntimePulse({
319
334
  flags,
320
335
  getState,
@@ -336,6 +351,8 @@ export async function createLocalSessionRuntime({
336
351
  lifecycle.runtimePulseTimer = setInterval(() => {
337
352
  headWatch.retarget();
338
353
  runtimePulse();
354
+ // A sub-agent's approval made before this session loaded (or bound its id).
355
+ adoptDelegatedApprovals();
339
356
  }, 2000);
340
357
  lifecycle.runtimePulseTimer.unref?.();
341
358