mixdog 1.1.2 → 1.2.1

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 (424) hide show
  1. package/README.md +8 -5
  2. package/package.json +2 -1
  3. package/scripts/lib/run-node-tests.mjs +9 -0
  4. package/scripts/prune-desktop-runtime.mjs +3 -0
  5. package/scripts/test-direct.mjs +4 -2
  6. package/src/defaults/shipped-history.json +10 -0
  7. package/src/defaults/skills/pptx/SKILL.md +6 -6
  8. package/src/defaults/skills/pptx/references/review.md +6 -4
  9. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  10. package/src/defaults/skills/setup/references/actions.md +18 -5
  11. package/src/defaults/skills/visualize/SKILL.md +160 -0
  12. package/src/defaults/skills/visualize/references/craft.md +88 -0
  13. package/src/headless-command.mjs +56 -3
  14. package/src/headless-exec.mjs +17 -1
  15. package/src/help.mjs +2 -0
  16. package/src/rules/shared/60-verification.md +3 -1
  17. package/src/rules/shared/70-delivery.md +4 -2
  18. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  19. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
  21. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  22. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  23. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
  24. package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +19 -5
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +133 -15
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +55 -8
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +86 -8
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +474 -164
  33. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  34. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  35. package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
  36. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
  37. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  38. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
  39. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
  40. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -12
  41. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
  42. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  43. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  44. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  45. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
  46. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
  47. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  50. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +21 -6
  51. package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
  52. package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
  53. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  54. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  55. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  56. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
  57. package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
  58. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
  59. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
  60. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  61. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +82 -0
  62. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +556 -0
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
  64. package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
  65. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
  66. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +15 -0
  67. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  68. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  70. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
  72. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +15 -4
  73. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
  74. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
  77. package/src/runtime/agent/orchestrator/providers/registry.mjs +47 -7
  78. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
  79. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
  80. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -11
  81. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  82. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  83. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +278 -84
  85. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  86. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  87. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  88. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -3
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
  90. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
  91. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
  92. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  93. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
  94. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  95. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  96. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
  97. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +24 -13
  98. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
  99. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
  100. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
  101. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  102. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  103. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  104. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  105. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  106. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  107. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  108. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  109. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
  111. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
  112. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
  113. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
  114. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +5 -3
  115. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -4
  116. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +21 -10
  117. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  118. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
  119. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
  120. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -3
  121. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +22 -12
  122. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
  123. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +9 -3
  124. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
  125. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
  126. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
  127. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
  128. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
  129. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
  130. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
  131. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
  132. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
  133. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  136. package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
  137. package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
  138. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +33 -22
  139. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  140. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
  141. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  142. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
  143. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
  144. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
  145. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +36 -0
  146. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +23 -12
  147. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  148. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +202 -374
  149. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
  150. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  151. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  152. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +48 -9
  153. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +161 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  155. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  156. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
  157. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
  158. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
  159. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  160. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  161. package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
  162. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +203 -33
  163. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
  164. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  165. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
  166. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
  167. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +83 -68
  168. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
  169. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +20 -3
  170. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
  171. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
  172. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
  173. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
  174. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
  175. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
  176. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  177. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  179. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
  180. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
  181. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  182. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  183. package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
  184. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  185. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  186. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  187. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  188. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  189. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  190. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
  191. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
  192. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  193. package/src/runtime/attachments/store.d.mts +3 -0
  194. package/src/runtime/attachments/store.mjs +38 -0
  195. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  196. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  197. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  198. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  199. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  200. package/src/runtime/memory/lib/memory.mjs +1 -1
  201. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  202. package/src/runtime/shared/atomic-file.mjs +33 -6
  203. package/src/runtime/shared/best-effort-stderr.mjs +8 -0
  204. package/src/runtime/shared/code-graph-state.mjs +12 -0
  205. package/src/runtime/shared/defaults-separation.mjs +2 -0
  206. package/src/runtime/shared/extension-scopes.mjs +5 -3
  207. package/src/runtime/shared/file-lock.mjs +37 -11
  208. package/src/runtime/shared/git-runner-worker.mjs +3 -2
  209. package/src/runtime/shared/git-runner.mjs +4 -3
  210. package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
  211. package/src/runtime/shared/llm/default-context-window.mjs +6 -0
  212. package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
  213. package/src/runtime/shared/llm/model-catalog.mjs +240 -130
  214. package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
  215. package/src/runtime/shared/llm/provider-catalog-registry.mjs +162 -0
  216. package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
  217. package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
  218. package/src/runtime/shared/model-proxy-mode.mjs +19 -0
  219. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  220. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  221. package/src/runtime/shared/pristine-execution.mjs +28 -4
  222. package/src/runtime/shared/provider-accounts.mjs +125 -21
  223. package/src/runtime/shared/provider-api-key.mjs +33 -1
  224. package/src/runtime/shared/schedule-model-ref.mjs +11 -2
  225. package/src/runtime/shared/session-usage-totals.mjs +19 -0
  226. package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
  227. package/src/runtime/shared/shell-display.mjs +9 -3
  228. package/src/runtime/shared/singleton-owner.mjs +36 -6
  229. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  230. package/src/runtime/shared/skill-mentions.mjs +133 -0
  231. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  232. package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
  233. package/src/runtime/shared/tool-primitives.mjs +35 -2
  234. package/src/runtime/shared/tool-surface.mjs +7 -0
  235. package/src/runtime/shared/tool-work-units.mjs +14 -0
  236. package/src/runtime/shared/transcript-metadata.mjs +17 -1
  237. package/src/runtime/shared/turn-changes.mjs +791 -0
  238. package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
  239. package/src/runtime/shared/turn-snapshot.mjs +690 -81
  240. package/src/runtime/shared/turn-worktree-snapshot.mjs +185 -15
  241. package/src/runtime/shared/worker-requests.mjs +15 -2
  242. package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
  243. package/src/runtime/shared/worktrees/contract.mjs +551 -0
  244. package/src/runtime/shared/worktrees/disk.mjs +57 -0
  245. package/src/runtime/shared/worktrees/git.mjs +247 -0
  246. package/src/runtime/shared/worktrees/include.mjs +480 -0
  247. package/src/runtime/shared/worktrees/lock.mjs +46 -0
  248. package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
  249. package/src/runtime/shared/worktrees/manager.mjs +1215 -0
  250. package/src/runtime/shared/worktrees/merge.mjs +182 -0
  251. package/src/runtime/shared/worktrees/owner.mjs +46 -0
  252. package/src/runtime/shared/worktrees/paths.mjs +62 -0
  253. package/src/runtime/shared/worktrees/registry.mjs +110 -0
  254. package/src/runtime/shared/worktrees/settings.mjs +84 -0
  255. package/src/runtime/shared/worktrees/slug.mjs +62 -0
  256. package/src/runtime/shared/worktrees/test-support.mjs +96 -0
  257. package/src/runtime/visualize-bridge/client.mjs +181 -0
  258. package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
  259. package/src/session-runtime/automation-agents.mjs +8 -2
  260. package/src/session-runtime/boot/apis.mjs +90 -0
  261. package/src/session-runtime/boot/config.mjs +7 -2
  262. package/src/session-runtime/boot/facade.mjs +21 -0
  263. package/src/session-runtime/boot/infrastructure.mjs +30 -18
  264. package/src/session-runtime/boot/session.mjs +1 -0
  265. package/src/session-runtime/boot/tools.mjs +4 -0
  266. package/src/session-runtime/config-lifecycle.mjs +10 -1
  267. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  268. package/src/session-runtime/conversation-import/service.mjs +369 -0
  269. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +21 -6
  270. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  271. package/src/session-runtime/global-extensions.mjs +2 -2
  272. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
  273. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
  274. package/src/session-runtime/internal-tool-executor.mjs +9 -1
  275. package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
  276. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
  277. package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
  278. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
  279. package/src/session-runtime/mcp-glue/connect.mjs +68 -16
  280. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  281. package/src/session-runtime/mcp-glue/server-catalog.mjs +122 -33
  282. package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
  283. package/src/session-runtime/mcp-glue.mjs +22 -2
  284. package/src/session-runtime/model-route/route-persist.mjs +3 -0
  285. package/src/session-runtime/model-route/set-route.mjs +15 -2
  286. package/src/session-runtime/new-session-config.mjs +3 -2
  287. package/src/session-runtime/notification-bus.mjs +18 -3
  288. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  289. package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
  290. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  291. package/src/session-runtime/provider-readiness.mjs +16 -10
  292. package/src/session-runtime/resource-extension-sync.mjs +45 -7
  293. package/src/session-runtime/resource-mcp-api.mjs +121 -84
  294. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  295. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  296. package/src/session-runtime/resource-skills-api.mjs +23 -2
  297. package/src/session-runtime/route-resolution.mjs +10 -1
  298. package/src/session-runtime/route-state.mjs +16 -2
  299. package/src/session-runtime/runtime-core.mjs +5 -0
  300. package/src/session-runtime/runtime-facade.mjs +8 -0
  301. package/src/session-runtime/runtime-review-api.mjs +9 -0
  302. package/src/session-runtime/schedule-session-run.mjs +1 -1
  303. package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
  304. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
  305. package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
  306. package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
  307. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
  308. package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
  310. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
  311. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  312. package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
  313. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
  314. package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
  315. package/src/session-runtime/services/agent-tool.mjs +1 -0
  316. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  317. package/src/session-runtime/services/daemon-candidate.mjs +3 -2
  318. package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
  319. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  320. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  321. package/src/session-runtime/services/provider-admin.mjs +64 -18
  322. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  323. package/src/session-runtime/session-create/session-options.mjs +10 -1
  324. package/src/session-runtime/session-turn-api.mjs +1 -0
  325. package/src/session-runtime/settings-api.mjs +4 -2
  326. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
  327. package/src/session-runtime/settings-worktree-api.mjs +17 -0
  328. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  329. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  330. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -1
  331. package/src/session-runtime/setup-tool/tool-defs.mjs +38 -4
  332. package/src/session-runtime/skills-api.mjs +7 -3
  333. package/src/session-runtime/turn/agent-ops.mjs +12 -1
  334. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +14 -3
  335. package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
  336. package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
  337. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
  338. package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
  339. package/src/session-runtime/turn/turn-run.mjs +6 -7
  340. package/src/session-runtime/webhook-session-run.mjs +16 -4
  341. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
  342. package/src/session-runtime/workspace/admission-gate.mjs +197 -0
  343. package/src/session-runtime/workspace/project-branches.mjs +136 -0
  344. package/src/session-runtime/workspace/transition-steps.mjs +364 -0
  345. package/src/session-runtime/workspace/transitions.mjs +651 -0
  346. package/src/session-runtime/workspace/workspace-state.mjs +112 -0
  347. package/src/skill-script-entry.mjs +36 -0
  348. package/src/standalone/channel-transport/http-routes.mjs +17 -0
  349. package/src/standalone/channel-transport.mjs +13 -1
  350. package/src/standalone/daemon-desktop-runtime.mjs +1 -0
  351. package/src/standalone/daemon-owner.mjs +372 -0
  352. package/src/standalone/daemon-stored-session-views.mjs +15 -4
  353. package/src/standalone/daemon.mjs +179 -8
  354. package/src/standalone/desktop-service-registry.mjs +20 -0
  355. package/src/standalone/local-session-runtime.mjs +11 -0
  356. package/src/standalone/session-client/attachment-calls.mjs +3 -1
  357. package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
  358. package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
  359. package/src/standalone/session-client.mjs +104 -13
  360. package/src/standalone/session-protocol.mjs +21 -0
  361. package/src/standalone/session-proxy.mjs +3 -0
  362. package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
  363. package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
  364. package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
  365. package/src/standalone/session-service/projection/revisions.mjs +2 -0
  366. package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
  367. package/src/standalone/session-service/projection/workspace.mjs +14 -0
  368. package/src/standalone/session-service/session-calls/session-action.mjs +17 -4
  369. package/src/standalone/session-transport/call-route.mjs +13 -0
  370. package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
  371. package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
  372. package/src/standalone/session-transport/client-registry.mjs +20 -3
  373. package/src/standalone/session-transport/routes.mjs +79 -2
  374. package/src/standalone/session-transport/stack.mjs +2 -0
  375. package/src/standalone/session-transport.mjs +24 -1
  376. package/src/tui/App.jsx +9 -1
  377. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  378. package/src/tui/app/app-view.jsx +6 -0
  379. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  380. package/src/tui/app/message-selector.mjs +2 -1
  381. package/src/tui/app/model-options.mjs +37 -5
  382. package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
  383. package/src/tui/app/model-picker.mjs +4 -2
  384. package/src/tui/app/skill-mention-palette.mjs +88 -0
  385. package/src/tui/app/slash-palette.mjs +23 -7
  386. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  387. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  388. package/src/tui/app/use-prompt-state.mjs +5 -0
  389. package/src/tui/components/Message.jsx +22 -1
  390. package/src/tui/components/PromptInput.jsx +21 -3
  391. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  392. package/src/tui/components/TranscriptItem.jsx +9 -1
  393. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  394. package/src/tui/components/user-message-skills.mjs +38 -0
  395. package/src/tui/dist/index.mjs +839 -207
  396. package/src/tui/index.jsx +10 -2
  397. package/src/tui/session/compaction-view.mjs +147 -0
  398. package/src/tui/session/context-state.mjs +6 -0
  399. package/src/tui/session/initial-state.mjs +3 -0
  400. package/src/tui/session/queue-helpers.mjs +7 -2
  401. package/src/tui/session/quota-resume.mjs +2 -1
  402. package/src/tui/session/session-api/commands.mjs +10 -2
  403. package/src/tui/session/session-api/controls.mjs +4 -0
  404. package/src/tui/session/session-api/extensions.mjs +4 -2
  405. package/src/tui/session/session-api/intake/rewind.mjs +2 -1
  406. package/src/tui/session/session-api/integrations.mjs +17 -0
  407. package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
  408. package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
  409. package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
  410. package/src/tui/session/session-api/routes.mjs +10 -1
  411. package/src/tui/session/session-api/settings.mjs +9 -0
  412. package/src/tui/session/session-api/worktree.mjs +60 -0
  413. package/src/tui/session/session-api.mjs +2 -0
  414. package/src/tui/session/session-flow/auto-clear.mjs +31 -12
  415. package/src/tui/session/session-flow/drain.mjs +27 -3
  416. package/src/tui/session/session-flow/session-reset.mjs +4 -3
  417. package/src/tui/session/session-flow.mjs +2 -0
  418. package/src/tui/session/transcript-intake.mjs +14 -5
  419. package/src/tui/session/tui-steering-persist.mjs +25 -9
  420. package/src/tui/session/turn-stream.mjs +32 -4
  421. package/src/tui/session/turn-tool-cards.mjs +10 -2
  422. package/src/tui/session/turn.mjs +56 -10
  423. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  424. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Loopback client for the desktop app's visualize bridge. The desktop app
3
+ * advertises { port, token } through `visualize-bridge.json`; this runtime
4
+ * half is the sync availability probe and the executor behind tool calls.
5
+ * Request: POST /command { sessionId, cwd, action, input }.
6
+ * Response: { ok:true, text, tabs?, path? } | { ok:false, error }.
7
+ */
8
+ import { bridgeDiscoveryChanged, readBridgeDiscovery, readBridgeDiscoveryDetail } from '../bridge-discovery.mjs';
9
+
10
+ const DISCOVERY_FILE = 'visualize-bridge.json';
11
+ const REQUEST_TIMEOUT_MS = 30_000;
12
+ /** `export` renders a page and writes a file; the desktop host's own deadline
13
+ * for it (45 s) is shorter, so a timeout is reported by the host, which then
14
+ * writes nothing, rather than raced by this client. */
15
+ const EXPORT_REQUEST_TIMEOUT_MS = 60_000;
16
+ const MAX_RESPONSE_BYTES = 1024 * 1024;
17
+ const ACTIONS = new Set(['open', 'close', 'annotate', 'capture', 'export', 'check', 'inspect']);
18
+ const INLINE_KINDS = ['mermaid', 'svg', 'chart', 'html', 'markdown'];
19
+ const MAX_INLINE_BYTES = 512 * 1024;
20
+ const BRIDGE_UNAVAILABLE_MESSAGE = 'visualize is unavailable; the Mixdog desktop app must be running';
21
+
22
+ export function visualizeBridgeAvailableSync() {
23
+ return readBridgeDiscovery(DISCOVERY_FILE) !== null;
24
+ }
25
+
26
+ function toolError(message) {
27
+ return { content: [{ type: 'text', text: `Error: ${message}` }], isError: true };
28
+ }
29
+
30
+ function unavailableMessage() {
31
+ const { reason } = readBridgeDiscoveryDetail(DISCOVERY_FILE);
32
+ return reason && reason !== 'missing'
33
+ ? `${BRIDGE_UNAVAILABLE_MESSAGE} (discovery ${reason})`
34
+ : BRIDGE_UNAVAILABLE_MESSAGE;
35
+ }
36
+
37
+ export function validateVisualizeArgs(args) {
38
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
39
+ return { ok: false, error: 'visualize arguments must be an object' };
40
+ }
41
+ if (!ACTIONS.has(args.action)) return { ok: false, error: 'action must be open, close, annotate, capture, export, check, or inspect' };
42
+ const input = args.input ?? {};
43
+ if (typeof input !== 'object' || Array.isArray(input)) return { ok: false, error: 'input must be an object' };
44
+ if (args.action === 'open' && input.content != null) {
45
+ const content = input.content;
46
+ if (input.targets != null) return { ok: false, error: 'open takes either input.targets or input.content, not both' };
47
+ if (typeof content !== 'object' || Array.isArray(content)) {
48
+ return { ok: false, error: 'open input.content must be { kind, source, title? }' };
49
+ }
50
+ if (!INLINE_KINDS.includes(content.kind)) {
51
+ return { ok: false, error: `open input.content.kind must be one of ${INLINE_KINDS.join(', ')}` };
52
+ }
53
+ if (typeof content.source !== 'string' || !content.source.trim()) {
54
+ return { ok: false, error: 'open input.content.source must be a non-empty string' };
55
+ }
56
+ if (Buffer.byteLength(content.source) > MAX_INLINE_BYTES) {
57
+ return { ok: false, error: `open input.content.source must be at most ${MAX_INLINE_BYTES / 1024} KiB` };
58
+ }
59
+ if (content.title != null && typeof content.title !== 'string') {
60
+ return { ok: false, error: 'open input.content.title must be a string' };
61
+ }
62
+ if (input.version != null && !(Number.isInteger(input.version) && input.version >= 1)) {
63
+ return { ok: false, error: 'open input.version must be a positive integer (a kept version number)' };
64
+ }
65
+ } else if (args.action === 'open') {
66
+ const targets = input.targets;
67
+ if (
68
+ !Array.isArray(targets) ||
69
+ targets.length < 1 ||
70
+ targets.length > 3 ||
71
+ targets.some((target) => typeof target !== 'string' || !target.trim())
72
+ ) {
73
+ return { ok: false, error: 'open requires input.targets: 1-3 non-empty strings' };
74
+ }
75
+ if (targets.some((target) => /^https?:\/\//i.test(target.trim())) && targets.length > 1) {
76
+ return { ok: false, error: 'a web URL must be the only target; do not mix it with files or other URLs' };
77
+ }
78
+ if (input.version != null && !(Number.isInteger(input.version) && input.version >= 1)) {
79
+ return { ok: false, error: 'open input.version must be a positive integer (a kept version number)' };
80
+ }
81
+ }
82
+ if (['annotate', 'capture', 'export', 'check', 'inspect'].includes(args.action) && (typeof input.tab !== 'string' || !input.tab)) {
83
+ return { ok: false, error: `${args.action} requires input.tab` };
84
+ }
85
+ if (args.action === 'inspect') {
86
+ const { viewport, selector } = input;
87
+ if (viewport != null) {
88
+ const sized = (value, min, max) => Number.isInteger(value) && value >= min && value <= max;
89
+ if (
90
+ typeof viewport !== 'object' ||
91
+ Array.isArray(viewport) ||
92
+ !sized(viewport.width, 200, 3000) ||
93
+ (viewport.height != null && !sized(viewport.height, 200, 4000))
94
+ ) {
95
+ return { ok: false, error: 'inspect input.viewport must be { width: 200-3000, height?: 200-4000 } in whole pixels' };
96
+ }
97
+ }
98
+ if (selector != null && (typeof selector !== 'string' || !selector.trim() || selector.length > 500)) {
99
+ return { ok: false, error: 'inspect input.selector must be a non-empty CSS selector of at most 500 characters' };
100
+ }
101
+ }
102
+ if (args.action === 'capture' && !(typeof input.output === 'string' && /\.png$/i.test(input.output.trim()))) {
103
+ return { ok: false, error: 'capture requires input.output ending in .png' };
104
+ }
105
+ if (args.action === 'export') {
106
+ if (input.format !== 'png' && input.format !== 'pdf') return { ok: false, error: 'export requires input.format png or pdf' };
107
+ if (typeof input.output !== 'string' || !new RegExp('\\.' + input.format + '$', 'i').test(input.output.trim())) {
108
+ return { ok: false, error: `export requires input.output ending in .${input.format}` };
109
+ }
110
+ if (input.version != null && !(Number.isInteger(input.version) && input.version >= 1)) {
111
+ return { ok: false, error: 'export input.version must be a positive integer (a kept version number)' };
112
+ }
113
+ if (input.overwrite != null && typeof input.overwrite !== 'boolean') {
114
+ return { ok: false, error: 'export input.overwrite must be a boolean' };
115
+ }
116
+ }
117
+ return { ok: true, action: args.action, input };
118
+ }
119
+
120
+ async function requestBridge(discovery, payload, signal) {
121
+ const response = await fetch(`http://127.0.0.1:${discovery.port}/command`, {
122
+ method: 'POST',
123
+ headers: { 'content-type': 'application/json', authorization: `Bearer ${discovery.token}` },
124
+ body: JSON.stringify(payload),
125
+ signal,
126
+ });
127
+ try {
128
+ const text = await response.text();
129
+ if (text.length > MAX_RESPONSE_BYTES) throw new Error('too large');
130
+ return { body: JSON.parse(text), status: response.status };
131
+ } catch {
132
+ throw new Error(`visualize bridge returned an invalid response (HTTP ${response.status})`);
133
+ }
134
+ }
135
+
136
+ function formatSuccess(body) {
137
+ const lines = [String(body.text ?? '')];
138
+ if (Array.isArray(body.tabs) && body.tabs.length) {
139
+ lines.push(...body.tabs.map((tab) => `${tab.id} ${tab.kind} ${tab.label} → ${tab.target}`));
140
+ }
141
+ if (typeof body.path === 'string' && body.path) lines.push(`path: ${body.path}`);
142
+ return lines.filter(Boolean).join('\n');
143
+ }
144
+
145
+ /** Execute one `visualize` tool call. */
146
+ export async function executeVisualizeTool(args, options = {}) {
147
+ const validated = validateVisualizeArgs(args);
148
+ if (!validated.ok) return toolError(validated.error);
149
+ const sessionId = String(options.sessionId || '').trim();
150
+ if (!sessionId) return toolError('visualize session context is unavailable');
151
+ const payload = {
152
+ sessionId,
153
+ cwd: options.cwd || process.cwd(),
154
+ action: validated.action,
155
+ input: validated.input,
156
+ };
157
+ let discovery = readBridgeDiscovery(DISCOVERY_FILE);
158
+ if (!discovery) return toolError(unavailableMessage());
159
+ let result;
160
+ for (let attempt = 0; attempt < 2; attempt += 1) {
161
+ const timeout = AbortSignal.timeout(validated.action === 'export' ? EXPORT_REQUEST_TIMEOUT_MS : REQUEST_TIMEOUT_MS);
162
+ try {
163
+ result = await requestBridge(discovery, payload, options.signal ? AbortSignal.any([timeout, options.signal]) : timeout);
164
+ break;
165
+ } catch (error) {
166
+ if (error?.name === 'TimeoutError') return toolError('visualize bridge timed out');
167
+ if (options.signal?.aborted) return toolError('visualize command cancelled');
168
+ const replacement = readBridgeDiscovery(DISCOVERY_FILE);
169
+ if (attempt === 0 && bridgeDiscoveryChanged(discovery, replacement)) {
170
+ discovery = replacement;
171
+ continue;
172
+ }
173
+ return toolError(error?.message?.startsWith('visualize bridge') ? error.message : unavailableMessage());
174
+ }
175
+ }
176
+ const { body, status } = result;
177
+ if (!body?.ok) {
178
+ return toolError(String(body?.error || `visualize bridge request failed (HTTP ${status})`).replace(/^Error:\s*/, ''));
179
+ }
180
+ return { content: [{ type: 'text', text: formatSuccess(body) }] };
181
+ }
@@ -0,0 +1,97 @@
1
+ import { TOOL_SYNC_EXECUTION_CONTRACT } from '../shared/tool-execution-contract.mjs';
2
+
3
+ /**
4
+ * `visualize` shows produced artifacts in the Mixdog desktop app's side panel
5
+ * over a loopback bridge. Deferred, and present only while the desktop
6
+ * Visualize bridge is up and the feature is on.
7
+ */
8
+ export const TOOL_DEFS = [
9
+ {
10
+ name: 'visualize',
11
+ title: 'Mixdog Visualize',
12
+ description:
13
+ "Show the user any artifact you produced or changed (mockups, docs, decks, sheets, PDFs, images, video, local dev pages) in the desktop side panel beside the chat. Panel tabs auto-reload when a file changes, so re-opening after edits is unnecessary. " +
14
+ 'open: input.targets (1-3 file paths, 2-3 = side-by-side comparison; or a single http(s) URL alone, never mixed with files or other URLs), optional label, optional version (show that kept version of a file tab read-only; each open/reload that changes the files keeps a version). close: optional tab (omit = all). ' +
15
+ 'annotate: tab + add [{selector,label?}] | remove [selector] | clear; HTML pages only, never edits the file. capture: tab + output (.png path). ' +
16
+ 'export: tab + format (png|pdf) + output (project-relative path ending .png/.pdf) + optional version (a kept version of the tab) + optional overwrite (true replaces an existing file, only under design/; otherwise an existing file is refused). Writes a record of the approved page inside the project and returns its project-relative path, size/dimensions and the page problems seen while rendering. A single HTML page (file, or inline html/chart) is rendered whole in a hidden window, so the tab need not be on screen (PDF: HTML pages only; PNG has a pixel cap, over it export pdf or shorten the page); any other tab exports as capture does (the displayed tab, PNG only). Same project containment as capture: links and paths outside the working directory are refused. ' +
17
+ 'check: tab; HTML pages only; waits briefly for the page to settle and returns only its runtime problems (uncaught errors, unhandled rejections, CSP violations, console errors/warnings, missing local assets). ' +
18
+ 'inspect: tab + optional viewport {width,height} (e.g. 375x812 to look at a mobile layout) + optional selector (scope); HTML pages with scripts/styles only (not static mermaid/svg/markdown). Returns a compact text read-out of the rendered page without a screenshot: viewport, landmarks and headings, interactive elements (role, accessible name, selector, x/y/w/h), and layout findings (horizontal overflow, clipped text, overlapping or tiny tap targets, low text contrast, images without alt, unlabeled inputs). Run it (desktop width and, for responsive designs, a mobile width) and fix the findings before reporting; `check` also says when findings exist. Secret field values are never included. ' +
19
+ 'Any result about a tab ends with a "Page problems" section when the page has problems: fix them in the file and re-check before reporting; never report a page with unresolved problems as done. ' +
20
+ 'HTML pages run their scripts, but outside network (CDNs, web fonts, APIs, any other http(s)/ws address) is blocked unless the user allows it for the tab, so mockups must be self-contained; a blocked request appears as a "blocked-network" page problem on open/check. ' +
21
+ 'Direct renderers: instead of targets, open takes input.content {kind: mermaid|svg|chart|html|markdown, source, title?} (max 512 KiB; chart = an ECharts option as JSON) and shows it with no file written. ' +
22
+ 'Prefer inline content for diagrams, charts and quick sketches; write a file for real mockups that need iteration, scripts or versioning on disk. ' +
23
+ 'mermaid, svg and markdown render as static, sanitized output (no scripts, no network). chart (ECharts option JSON, interactive: tooltips, zoom) and html (scripts run) open as in-memory pages with the same protections as HTML file pages (outside network blocked, page problems captured); html content must be self-contained. Re-open with the same title to add a version. A render error (Mermaid parse error, bad chart JSON) is returned as a page problem: fix the source and open again. ' +
24
+ 'Tweaks: an HTML page (file or inline html/chart) can declare adjustable parameters in <script type="application/json" id="mx-tweaks">[{id,label,type:color|range|select|toggle,var:"--name" or attr:"data-name",min,max,step,unit,options:[{value,label}],default}] (max 16, keep it to a few meaningful ones). The panel shows a Tweaks drawer and applies changes live to the page root (CSS variables / data attributes your CSS and script read); the chosen values come back with their next message under tweaks: to bake into the file. A malformed block is a "tweaks: <reason>" page problem. ' +
25
+ 'Does not replace browser for clicking/typing. ' +
26
+ TOOL_SYNC_EXECUTION_CONTRACT,
27
+ inputSchema: {
28
+ type: 'object',
29
+ properties: {
30
+ action: { type: 'string', enum: ['open', 'close', 'annotate', 'capture', 'export', 'check', 'inspect'] },
31
+ input: {
32
+ type: 'object',
33
+ properties: {
34
+ targets: {
35
+ type: 'array',
36
+ items: { type: 'string' },
37
+ minItems: 1,
38
+ maxItems: 3,
39
+ description: 'open: 1-3 project-relative/absolute file paths (side by side), or exactly one http(s) URL as the only target.',
40
+ },
41
+ content: {
42
+ type: 'object',
43
+ properties: {
44
+ kind: { type: 'string', enum: ['mermaid', 'svg', 'chart', 'html', 'markdown'] },
45
+ source: {
46
+ type: 'string',
47
+ maxLength: 524288,
48
+ description: 'Diagram text, SVG/HTML/Markdown source, or an ECharts option as JSON (chart).',
49
+ },
50
+ title: { type: 'string', description: 'Tab title; re-opening the same title adds a version.' },
51
+ },
52
+ required: ['kind', 'source'],
53
+ additionalProperties: false,
54
+ description: 'open: render this directly instead of files. Exclusive with targets.',
55
+ },
56
+ label: { type: 'string', description: 'open: tab label.' },
57
+ version: {
58
+ type: 'integer',
59
+ minimum: 1,
60
+ description: 'open (file tabs): kept version number to show read-only instead of the live files. export: kept version number to render instead of the live page.',
61
+ },
62
+ tab: { type: 'string', description: 'Tab id from open (close: omit for all).' },
63
+ add: {
64
+ type: 'array',
65
+ items: {
66
+ type: 'object',
67
+ properties: { selector: { type: 'string' }, label: { type: 'string' } },
68
+ required: ['selector'],
69
+ additionalProperties: false,
70
+ },
71
+ description: 'annotate: CSS selectors to outline.',
72
+ },
73
+ remove: { type: 'array', items: { type: 'string' }, description: 'annotate: selectors to un-outline.' },
74
+ clear: { type: 'boolean', description: 'annotate: remove all outlines.' },
75
+ output: { type: 'string', description: 'capture: project path ending .png. export: project path ending .png or .pdf (matching format).' },
76
+ format: { type: 'string', enum: ['png', 'pdf'], description: 'export: file format.' },
77
+ overwrite: { type: 'boolean', description: 'export: replace an existing output file; honored only for paths under design/.' },
78
+ viewport: {
79
+ type: 'object',
80
+ properties: {
81
+ width: { type: 'integer', minimum: 200, maximum: 3000 },
82
+ height: { type: 'integer', minimum: 200, maximum: 4000 },
83
+ },
84
+ required: ['width'],
85
+ additionalProperties: false,
86
+ description: 'inspect: size to lay the page out at (height defaults to 800); omit for the panel\'s current size.',
87
+ },
88
+ selector: { type: 'string', maxLength: 500, description: 'inspect: CSS selector scoping the read-out to one subtree.' },
89
+ },
90
+ additionalProperties: false,
91
+ },
92
+ },
93
+ required: ['action'],
94
+ additionalProperties: false,
95
+ },
96
+ },
97
+ ];
@@ -57,10 +57,16 @@ export function deliverAutomationCompletion(sessionId, text, meta = {}) {
57
57
  return true;
58
58
  }
59
59
 
60
+ // Ask options for a follow-up turn fed by agent results: the runtime reporting
61
+ // worker output, not the user — stored as a task notification and never a
62
+ // source of explicit skill selection.
63
+ export const AUTOMATION_RESULT_TURN_OPTS = Object.freeze({ promptSource: 'task-notification' });
64
+
60
65
  /**
61
66
  * Runs an automation conversation to its end: the first turn, then one more
62
67
  * turn per batch of agent results while agents it started are still out.
63
- * Resolves with the last turn's result.
68
+ * `nextTurn(text, askOpts)` receives AUTOMATION_RESULT_TURN_OPTS as the
69
+ * results' provenance. Resolves with the last turn's result.
64
70
  */
65
71
  export async function runAutomationTurns(sessionId, firstTurn, nextTurn, { waitMs = AGENT_RESULT_WAIT_MS } = {}) {
66
72
  const run = { pending: new Set(), ready: [], wake: null };
@@ -79,7 +85,7 @@ export async function runAutomationTurns(sessionId, firstTurn, nextTurn, { waitM
79
85
  run.wake = null;
80
86
  if (!arrived) break;
81
87
  }
82
- result = await nextTurn(run.ready.splice(0).join('\n\n'));
88
+ result = await nextTurn(run.ready.splice(0).join('\n\n'), { ...AUTOMATION_RESULT_TURN_OPTS });
83
89
  }
84
90
  return result;
85
91
  } finally {
@@ -58,6 +58,12 @@ import { loadInstructionFilesContext } from '../../runtime/agent/orchestrator/co
58
58
  import { createSessionTurnApi } from '../session-turn-api.mjs';
59
59
  import { createGoalFacadeApi } from '../goal-facade-api.mjs';
60
60
  import { createRuntimeReviewApi } from '../runtime-review-api.mjs';
61
+ import { createWorkspaceTransitions, refreshWorkspacePrompt } from '../workspace/transitions.mjs';
62
+ import { saveSession } from '../../runtime/agent/orchestrator/session/store.mjs';
63
+ import { modelToolSchemaAllowlist } from '../../runtime/agent/orchestrator/runtime-core/tool-profile.mjs';
64
+ import { sessionOptions } from '../session-create/session-options.mjs';
65
+ import { createConversationImportApi } from '../conversation-import/service.mjs';
66
+ import { importError } from '../conversation-import/discovery.mjs';
61
67
  import { bootProfile } from '../boot-profile.mjs';
62
68
  import { STANDALONE_DATA_DIR } from '../runtime-paths.mjs';
63
69
  import {
@@ -86,18 +92,29 @@ export function wireApis(boot) {
86
92
  });
87
93
  boot.providerAuthApi = providerAuthApiFor(boot);
88
94
  boot.mediaApi = createMediaApi();
95
+ boot.conversationImportApi = conversationImportApiFor(boot);
89
96
  boot.sessionTitles = createSessionTitleController({
90
97
  dataRoot: () => dataDirOf(boot.cfgMod),
91
98
  promoteGeneratedTitle: (sessionId, title, stage) => boot.mgr.updateSessionGeneratedTitle(sessionId, title, stage),
92
99
  });
93
100
  boot.lifecycleApi = lifecycleApiFor(boot);
94
101
  boot.resourceApi = resourceApiFor(boot);
102
+ // Plugin MCP servers are derived live; copies an earlier enable action wrote
103
+ // into mcpServers are adopted once (an injected headless config is left as is).
104
+ if (!boot.params.initialConfig || typeof boot.params.initialConfig !== 'object') {
105
+ try {
106
+ boot.resourceApi.migratePluginMcpCopies();
107
+ } catch (error) {
108
+ bootProfile('plugin-mcp:adopt-failed', { error: error?.message || String(error) });
109
+ }
110
+ }
95
111
  boot.disposeGlobalExtensionSubscription = () => {
96
112
  boot.disposeConfigSync?.();
97
113
  boot.resourceApi.disposeGlobalExtensionSubscription?.();
98
114
  };
99
115
  boot.modelRouteApi = modelRouteApiFor(boot);
100
116
  boot.workflowAgentsApi = workflowAgentsApiFor(boot);
117
+ boot.workspaceApi = workspaceApiFor(boot);
101
118
  boot.sessionTurnApi = sessionTurnApiFor(boot);
102
119
  const getFacadeSessionId = () => boot.rt.session?.id || boot.rt.reservedSessionId || null;
103
120
  boot.runtimeReviewApi = createRuntimeReviewApi({
@@ -279,6 +296,45 @@ function settingsApiFor(boot) {
279
296
  });
280
297
  }
281
298
 
299
+ // Conversation import: imported sessions are built with the Lead options a new
300
+ // session of this runtime would get (current route, tools, workflow, memory),
301
+ // minus its reservation, profile ownership and desktop placement.
302
+ function conversationImportApiFor(boot) {
303
+ const { rt, mgr } = boot;
304
+ return createConversationImportApi({
305
+ // The async catalog (the daemon's SQLite catalog worker, else JSON),
306
+ // loaded on first use so boot does not pull in the cold reader.
307
+ listSessionSummaries: async () => {
308
+ const reader = await import('../../runtime/agent/orchestrator/session/store-summary-reader.mjs');
309
+ return reader.listStoredSessionSummariesAsync();
310
+ },
311
+ createSession: (options) => mgr.createSession(options),
312
+ prepareLeadOptions: async () => {
313
+ await boot.awaitKeychainPrewarm();
314
+ const route = rt.route?.provider && rt.route?.model ? rt.route : resolveRoute(rt.config, {});
315
+ if (!route?.provider || !route?.model) throw importError('noModelRoute');
316
+ await boot.ensureProvidersReady(rt.config.providers || {});
317
+ const coreMemoryContext = await boot.loadCoreMemoryContext();
318
+ const leadView = Object.assign(Object.create(rt), {
319
+ route,
320
+ reservedSessionId: null,
321
+ sessionProfile: null,
322
+ desktopSession: null,
323
+ });
324
+ return sessionOptions(
325
+ {
326
+ rt: leadView,
327
+ cfgMod: boot.cfgMod,
328
+ activeWorkflowContext: workflowHelpers.activeWorkflowContext,
329
+ schemaAllowedTools: modelToolSchemaAllowlist(rt.toolProfile),
330
+ featureDisallowedTools: boot.featureDisallowedTools,
331
+ },
332
+ coreMemoryContext
333
+ );
334
+ },
335
+ });
336
+ }
337
+
282
338
  function providerAuthApiFor(boot) {
283
339
  const { rt, cfgMod, reg, ensureProvidersReady } = boot;
284
340
  return createProviderAuthApi({
@@ -364,6 +420,8 @@ function lifecycleApiFor(boot) {
364
420
  invalidateContextStatusCache: boot.invalidateContextStatusCache,
365
421
  invalidatePreSessionToolSurface: boot.invalidatePreSessionToolSurface,
366
422
  applyResolvedCwd: boot.applyResolvedCwd,
423
+ // Created after the lifecycle API, so resolved at call time.
424
+ cleanupDeletedSessionWorktree: (sessionId) => boot.workspaceApi?.cleanupDeletedSession?.(sessionId),
367
425
  resolveRoute,
368
426
  applyDeferredToolSurface,
369
427
  beginRoutePreparation: (task) => routePreparation.start(task),
@@ -398,6 +456,8 @@ function resourceApiFor(boot) {
398
456
  normalizeMcpServerInput: boot.normalizeMcpServerInput,
399
457
  mcpStatus: boot.mcpStatus,
400
458
  getMcpServerConfig: boot.getMcpServerConfig,
459
+ resolveMcpCatalog: boot.resolveMcpCatalog,
460
+ pluginMcpServer: boot.pluginMcpServer,
401
461
  skillsStatus: boot.skillsStatus,
402
462
  skillContent: boot.skillContent,
403
463
  addGlobalSkill: boot.addGlobalSkill,
@@ -486,9 +546,39 @@ function workflowAgentsApiFor(boot) {
486
546
  });
487
547
  }
488
548
 
549
+ // The Lead workspace transition authority (worktree / project branch / remove)
550
+ // and the turn-start workspace gate. Facade-facing methods are spread by
551
+ // buildFacade; prepareTurnWorkspace feeds the turn runner.
552
+ function workspaceApiFor(boot) {
553
+ const { rt } = boot;
554
+ return createWorkspaceTransitions({
555
+ getSession: () => rt.session,
556
+ getReservedSessionId: () => rt.reservedSessionId,
557
+ getCurrentCwd: () => rt.currentCwd,
558
+ getDesktopSession: () => rt.desktopSession,
559
+ getConfig: () => rt.config,
560
+ createCurrentSession: (reason) => boot.createCurrentSession(reason),
561
+ applyResolvedCwd: (cwd) => boot.applyResolvedCwd(cwd),
562
+ persistSession: (session) => saveSession(session, { immediate: true }),
563
+ refreshWorkspaceContext: (session, cwd) =>
564
+ refreshWorkspacePrompt(session, cwd, { loadCoreMemoryContext: boot.loadCoreMemoryContext }),
565
+ invalidateCaches: () => {
566
+ boot.invalidateContextStatusCache();
567
+ boot.invalidatePreSessionToolSurface();
568
+ },
569
+ getActiveTurnCount: () => rt.activeTurnCount || 0,
570
+ agentStatusState: boot.agentStatusState,
571
+ updateLeadWorkerCwd: (sessionId, cwd) => boot.agentTool?.updateLeadWorkerCwd?.(sessionId, cwd),
572
+ sessionManager: boot.mgr,
573
+ initialIntent: boot.params.worktree,
574
+ });
575
+ }
576
+
489
577
  function sessionTurnApiFor(boot) {
490
578
  const { rt, tunables, remoteTranscript, routePreparation } = boot;
491
579
  return createSessionTurnApi({
580
+ prepareTurnWorkspace: boot.workspaceApi.prepareTurnWorkspace,
581
+ admitTurnWorkspace: boot.workspaceApi.admitTurnWorkspace,
492
582
  getSession: () => rt.session,
493
583
  setSession: boot.adoptSession,
494
584
  getCurrentCwd: () => rt.currentCwd,
@@ -30,8 +30,10 @@ export async function resolveConfig(boot) {
30
30
  model: params.model,
31
31
  effort: params.effort,
32
32
  fast: params.fast,
33
+ autoEffort: params.autoEffort,
33
34
  modelParameters: params.modelParameters,
34
35
  contextPercent: params.contextPercent,
36
+ contextTokens: params.contextTokens,
35
37
  selectedContextWindow: params.selectedContextWindow,
36
38
  }));
37
39
  configureLocalProviderIdleTtl(rt.config.providers?.[LOCAL_PROVIDER_ID]?.idleTtlSeconds);
@@ -85,7 +87,8 @@ function initRuntimeState(rt, params) {
85
87
  rt.activeTurnAbortControllers = new Set();
86
88
  rt.firstTurnCompleted = false;
87
89
  rt.codeGraphFirstTurnPrewarmDone = false;
88
- rt.startupProviderCatalogRefreshStarted = false;
90
+ // Last registry catalog-refresh promise this runtime attached handling to.
91
+ rt.startupProviderCatalogRefreshObserved = null;
89
92
  // True while the boot-time provider-catalog refresh is in flight: warming a
90
93
  // model cache it is about to invalidate only burns the load twice.
91
94
  rt.startupProviderCatalogRefreshPending = false;
@@ -104,7 +107,9 @@ function activeTurnControls(rt) {
104
107
  aborted = true;
105
108
  try {
106
109
  controller.abort(reason);
107
- } catch {}
110
+ } catch {
111
+ // Best-effort: one throwing abort listener must not stop the others.
112
+ }
108
113
  }
109
114
  return aborted;
110
115
  },
@@ -18,6 +18,7 @@ export function buildFacade(boot) {
18
18
  ...boot.providerAuthApi,
19
19
  ...boot.usageStatsApi,
20
20
  ...boot.mediaApi,
21
+ ...boot.conversationImportApi,
21
22
  ...boot.runtimeReviewApi,
22
23
  },
23
24
  goalApi: boot.goalFacadeApi,
@@ -27,6 +28,26 @@ export function buildFacade(boot) {
27
28
  ...boot.modelRouteApi,
28
29
  ...boot.workflowAgentsApi,
29
30
  ...boot.sessionTurnApi,
31
+ // A surface registers its idle auto-clear here; returns an unregister.
32
+ setCompletionWakeGate: (gate) => {
33
+ const next = typeof gate === 'function' ? gate : null;
34
+ boot.completionWakeGate = next;
35
+ return () => {
36
+ if (boot.completionWakeGate === next) boot.completionWakeGate = null;
37
+ };
38
+ },
39
+ applyWorkspaceTransition: boot.workspaceApi.applyWorkspaceTransition,
40
+ getWorkspace: boot.workspaceApi.getWorkspace,
41
+ getBranchMenu: boot.workspaceApi.getBranchMenu,
42
+ getProjectBranchMenu: boot.workspaceApi.getProjectBranchMenu,
43
+ selectBranch: boot.workspaceApi.selectBranch,
44
+ selectProjectBranch: boot.workspaceApi.selectProjectBranch,
45
+ mergeProjectBranch: boot.workspaceApi.mergeProjectBranch,
46
+ requestWorktree: boot.workspaceApi.requestWorktree,
47
+ mergeWorkspace: boot.workspaceApi.mergeWorkspace,
48
+ removeWorktree: boot.workspaceApi.removeWorktree,
49
+ listWorktrees: boot.workspaceApi.listWorktrees,
50
+ pruneWorktrees: boot.workspaceApi.pruneWorktrees,
30
51
  claimSetupRequest: setupTool.claimSetupRequest,
31
52
  isSetupRequestActive: setupTool.isSetupRequestActive,
32
53
  completeSetupRequest: setupTool.completeSetupRequest,
@@ -7,11 +7,7 @@ import { createStandaloneHookBus } from '../services/hook-bus.mjs';
7
7
  import { updateCurrentCwdOverride, writeLastSessionCwd } from '../../runtime/shared/user-cwd.mjs';
8
8
  import { listRegisteredPlugins, pluginAdminStatus } from '../services/plugin-admin.mjs';
9
9
  import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
10
- import {
11
- countSkillFiles,
12
- pluginManifest,
13
- pluginMcpServerName,
14
- } from '../../runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs';
10
+ import { countSkillFiles, pluginManifest } from '../../runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs';
15
11
  import { bootProfile } from '../boot-profile.mjs';
16
12
  import { createMcpGlue } from '../mcp-glue.mjs';
17
13
  import { createSelfUpdateController } from '../self-update.mjs';
@@ -41,20 +37,30 @@ function wireMcp(boot) {
41
37
  mcpConnectGeneration: 0,
42
38
  mcpConnectInFlight: null,
43
39
  };
44
- const { mcpStatus, getMcpServerConfig, connectConfiguredMcp, awaitInitialMcpConnect, normalizeMcpServerInput } =
45
- createMcpGlue({
46
- mcpClient,
47
- getConfig: () => rt.config,
48
- getCurrentCwd: () => rt.currentCwd,
49
- getMcpScopeId: () => rt.mcpScopeId,
50
- getDesktopSession: () => rt.desktopSession,
51
- setDesktopSession: (v) => {
52
- rt.desktopSession = v;
53
- },
54
- state: mcpState,
55
- });
40
+ const {
41
+ mcpStatus,
42
+ resolveMcpCatalog,
43
+ pluginMcpServer,
44
+ pluginMcpSummary,
45
+ getMcpServerConfig,
46
+ connectConfiguredMcp,
47
+ awaitInitialMcpConnect,
48
+ normalizeMcpServerInput,
49
+ } = createMcpGlue({
50
+ mcpClient,
51
+ getConfig: () => rt.config,
52
+ getCurrentCwd: () => rt.currentCwd,
53
+ getMcpScopeId: () => rt.mcpScopeId,
54
+ // Plugin-declared servers are derived from the registry on every resolve.
55
+ getPluginDataDir: () => dataDirOf(boot.cfgMod),
56
+ listPlugins: () => listRegisteredPlugins({ dataDir: boot.cfgMod.getPluginData() }),
57
+ state: mcpState,
58
+ });
56
59
  Object.assign(boot, {
57
60
  mcpStatus,
61
+ resolveMcpCatalog,
62
+ pluginMcpServer,
63
+ pluginMcpSummary,
58
64
  getMcpServerConfig,
59
65
  connectConfiguredMcp,
60
66
  awaitInitialMcpConnect,
@@ -119,6 +125,7 @@ function wireNotifications(boot) {
119
125
  getCurrentSessionId: () => rt.session?.id || rt.reservedSessionId || null,
120
126
  getTurnApi: () => boot.sessionTurnApi,
121
127
  getOwnerLifecycle: (sessionId) => ownerLifecycle(rt, sessionId),
128
+ beforeWake: (sessionId) => boot.completionWakeGate?.(sessionId),
122
129
  });
123
130
  const {
124
131
  emitRuntimeNotification,
@@ -249,7 +256,12 @@ function wireCwdPlugins(boot) {
249
256
  listRegisteredPlugins,
250
257
  pluginAdminStatus,
251
258
  pluginManifest,
252
- pluginMcpServerName,
259
+ pluginMcpSummary: boot.pluginMcpSummary,
260
+ // Plugin MCP servers without a declared cwd follow this runtime's cwd:
261
+ // reconnect just those (and refresh advertised roots) in place.
262
+ onCwdChanged: () => {
263
+ void boot.connectConfiguredMcp({ reconcile: true }).catch(() => {});
264
+ },
253
265
  countSkillFiles,
254
266
  writeLastSessionCwd,
255
267
  updateCurrentCwdOverride,
@@ -20,6 +20,7 @@ export function wireSessionLifecycle(boot) {
20
20
  params.model !== undefined ||
21
21
  params.effort !== undefined ||
22
22
  params.fast !== undefined ||
23
+ params.autoEffort !== undefined ||
23
24
  params.modelParameters !== undefined,
24
25
  invalidatePreSessionToolSurface: boot.invalidatePreSessionToolSurface,
25
26
  invalidateOutputStyleStatusCache: boot.invalidateOutputStyleStatusCache,
@@ -20,6 +20,7 @@ import { TOOL_DEFS as TERMINAL_BRIDGE_TOOL_DEFS } from '../../runtime/terminal-b
20
20
  import { TOOL_DEFS as OFFICE_TOOL_DEFS } from '../../runtime/office/tool-defs.mjs';
21
21
  import { TOOL_DEFS as MEDIA_TOOL_DEFS } from '../../runtime/media/tool-defs.mjs';
22
22
  import { TOOL_DEFS as TIDY_TOOL_DEFS } from '../../runtime/tidy/tool-defs.mjs';
23
+ import { TOOL_DEFS as VISUALIZE_BRIDGE_TOOL_DEFS } from '../../runtime/visualize-bridge/tool-defs.mjs';
23
24
  import { SETUP_TOOL_DEFS } from '../setup-tool/tool-defs.mjs';
24
25
  import { createSetupToolExecutor } from '../setup-tool/executor.mjs';
25
26
  import { bootProfile } from '../boot-profile.mjs';
@@ -156,6 +157,7 @@ function wireToolSurface(boot) {
156
157
  officeToolDefs: OFFICE_TOOL_DEFS,
157
158
  mediaToolDefs: MEDIA_TOOL_DEFS,
158
159
  tidyToolDefs: TIDY_TOOL_DEFS,
160
+ visualizeToolDefs: VISUALIZE_BRIDGE_TOOL_DEFS,
159
161
  setupToolDefs: SETUP_TOOL_DEFS,
160
162
  goalTools: goalRuntime.tools,
161
163
  agentTools: agentTool.tools,
@@ -246,6 +248,8 @@ function wireInternalTools(boot) {
246
248
  mcpStatus: boot.mcpStatus,
247
249
  applyResolvedCwd: boot.applyResolvedCwd,
248
250
  skillToolContent: boot.skillToolContent,
251
+ // Late-bound: the workspace authority is built with the API slices.
252
+ getWorkspaceApi: () => boot.workspaceApi || null,
249
253
  }),
250
254
  });
251
255
  Object.assign(boot, { setupTool, disposeInternalTools });