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
package/src/tui/index.jsx CHANGED
@@ -578,7 +578,7 @@ function registerStdioDeathGuards(signalCleanup) {
578
578
  return listeners;
579
579
  }
580
580
 
581
- export async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {}) {
581
+ export async function runTui({ provider, model, toolMode, remote, forceOnboarding, worktree } = {}) {
582
582
  const startedAt = performance.now();
583
583
  bootProfile('run:start', { provider, model, toolMode, remote });
584
584
  // The React/ink TUI needs a raw-mode-capable TTY (interactive input). In a
@@ -636,7 +636,15 @@ export async function runTui({ provider, model, toolMode, remote, forceOnboardin
636
636
  // Session runtime startup is independent from palette selection. Start it now and
637
637
  // overlap its runtime import/config work with the theme read, while still
638
638
  // awaiting the theme before the first React frame.
639
- const storeOutcomePromise = createSessionRuntime({ provider, model, toolMode, remote }).then(
639
+ // An interactive Lead the user starts follows the worktree settings default
640
+ // unless `--worktree [name]` / `--no-worktree` decided.
641
+ const storeOutcomePromise = createSessionRuntime({
642
+ provider,
643
+ model,
644
+ toolMode,
645
+ remote,
646
+ worktree: worktree ?? { mode: 'default' },
647
+ }).then(
640
648
  (store) => ({ store, error: null }),
641
649
  (error) => ({ store: null, error })
642
650
  );
@@ -0,0 +1,147 @@
1
+ /**
2
+ * src/tui/session/compaction-view.mjs - the visible transcript across a
3
+ * compaction. The rows the compaction took out of the model context stay in
4
+ * view, marked `archived` (display-only: greyed, no model-state actions), and
5
+ * the completion row becomes the "compacted" divider at the boundary.
6
+ *
7
+ * The model transcript itself belongs to runtime.compact / the pre-send pass;
8
+ * the durable copy of the dropped rows is the runtime's compaction archive.
9
+ */
10
+ import { COMPACTION_DIVIDER_LABEL } from '../../runtime/agent/orchestrator/session/compaction-archive.mjs';
11
+
12
+ function isCompactionDivider(item) {
13
+ return item?.kind === 'statusdone' && item.status === 'compacted';
14
+ }
15
+
16
+ function archivedItem(item) {
17
+ if (!item || typeof item !== 'object' || item.archived === true || isCompactionDivider(item)) return item;
18
+ return { ...item, archived: true };
19
+ }
20
+
21
+ /** `divider` (id, detail) as the compaction boundary row. Every path — manual,
22
+ * auto-clear, mid-turn — and the persisted archive carry the one compaction
23
+ * label; the stats stay in `detail`. */
24
+ function compactionDividerItem(item) {
25
+ return {
26
+ ...item,
27
+ kind: 'statusdone',
28
+ status: 'compacted',
29
+ label: COMPACTION_DIVIDER_LABEL,
30
+ at: item?.at ?? Date.now(),
31
+ };
32
+ }
33
+
34
+ /** Row kinds a transcript message backs (prompt, reply, tool card). */
35
+ const MESSAGE_ROW_KINDS = new Set(['user', 'assistant', 'tool']);
36
+
37
+ const idSet = (values) => new Set(Array.isArray(values) ? values.filter((value) => value != null) : []);
38
+
39
+ /** The tool calls a tool row shows: its own call, a restored aggregate's
40
+ * calls, a live aggregate's members (whose ids are their call ids). */
41
+ function toolCallIdsOfItem(item) {
42
+ if (item?.kind !== 'tool') return [];
43
+ if (item.callId) return [String(item.callId)];
44
+ if (Array.isArray(item.callIds) && item.callIds.length) return item.callIds.filter(Boolean).map(String);
45
+ if (item.aggregate === true && Array.isArray(item.toolMembers)) {
46
+ return item.toolMembers
47
+ .map((member) => member?.id)
48
+ .filter((id) => id != null)
49
+ .map(String);
50
+ }
51
+ return [];
52
+ }
53
+
54
+ /**
55
+ * Which rows a compaction took out of the model context, from the result or
56
+ * event it reported:
57
+ * - `droppedIdentities` ({ messageIds, callIds }) — whenever supplied,
58
+ * whatever `droppedMessages` says — by id membership only:
59
+ * a tool row whose calls all left (or, without call ids, whose message
60
+ * id left); any other row with a message of its own (prompt, reply,
61
+ * notification, restored marker) whose message id left — a prompt,
62
+ * reply or tool row without an id stays live. Only a row with no
63
+ * message of its own (a live completion, notice or status row) follows
64
+ * its turn's prompt;
65
+ * - no identities and `droppedMessages: 0` (a rewrite-only pass): none;
66
+ * - neither (a source that reports nothing): every row.
67
+ * Returns a predicate over the rows before the boundary, in order.
68
+ */
69
+ export function compactionArchivedRows(result) {
70
+ const identities = result?.droppedIdentities;
71
+ // Identities decide when supplied: a kept message can still have lost
72
+ // part of itself (its text, some calls) with no message fully dropped.
73
+ // The count is only the fallback for a source without identities.
74
+ if (!identities || typeof identities !== 'object') {
75
+ const count = result?.droppedMessages;
76
+ return count !== undefined && count !== null && !(Number(count) > 0) ? () => false : () => true;
77
+ }
78
+ const messageIds = idSet(identities.messageIds);
79
+ const callIds = idSet(identities.callIds);
80
+ let promptDropped = false;
81
+ const predicate = (item) => {
82
+ if (!item || typeof item !== 'object') return false;
83
+ const calls = toolCallIdsOfItem(item);
84
+ let dropped;
85
+ if (calls.length) dropped = calls.every((id) => callIds.has(id));
86
+ // A message-backed row is decided by its own id alone: one without an id
87
+ // has no display identity in the result and stays live.
88
+ else if (item.messageId || MESSAGE_ROW_KINDS.has(item.kind)) {
89
+ dropped = Boolean(item.messageId) && messageIds.has(item.messageId);
90
+ }
91
+ // Only an auxiliary row (no message of its own) follows its turn.
92
+ else return promptDropped;
93
+ if (item.kind === 'user') promptDropped = dropped;
94
+ return dropped;
95
+ };
96
+ // An aggregate row some of whose calls survive stays live, with its dropped
97
+ // members marked archived (the restart path archives exactly those calls).
98
+ predicate.markDroppedMembers = (item) => {
99
+ if (item?.kind !== 'tool' || item.aggregate !== true || !Array.isArray(item.toolMembers)) return item;
100
+ if (!item.toolMembers.some((member) => member?.id != null && callIds.has(String(member.id)))) return item;
101
+ return {
102
+ ...item,
103
+ toolMembers: item.toolMembers.map((member) =>
104
+ member?.id != null && callIds.has(String(member.id)) && member.archived !== true
105
+ ? { ...member, archived: true }
106
+ : member
107
+ ),
108
+ };
109
+ };
110
+ return predicate;
111
+ }
112
+
113
+ function classifiedRow(item, archived) {
114
+ if (archived(item)) return archivedItem(item);
115
+ return typeof archived.markDroppedMembers === 'function' ? archived.markDroppedMembers(item) : item;
116
+ }
117
+
118
+ /** Items with the rows before `boundary` (default: all) that `archived`
119
+ * selects marked archived, and the divider inserted at the boundary.
120
+ * Returns the next list and the divider's index. */
121
+ export function archiveItemsForCompaction(
122
+ items,
123
+ divider,
124
+ boundary = null,
125
+ { archived = () => true, archiveTail = false } = {}
126
+ ) {
127
+ const list = Array.isArray(items) ? items : [];
128
+ const at = Number.isInteger(boundary) ? Math.max(0, Math.min(list.length, boundary)) : list.length;
129
+ const next = list.slice(0, at).map((item) => classifiedRow(item, archived));
130
+ next.push(compactionDividerItem(divider));
131
+ // The current turn's rows after the boundary stay in place but are still
132
+ // classified by the same result: what compaction explicitly dropped from
133
+ // this turn (its tool calls) is archived, the rest stays live.
134
+ for (let index = at; index < list.length; index += 1) {
135
+ next.push(archiveTail ? classifiedRow(list[index], archived) : list[index]);
136
+ }
137
+ return { items: next, dividerIndex: at };
138
+ }
139
+
140
+ /** The runtime archive range a resumed session exposes to paged views
141
+ * (`transcriptArchive` state), or null. */
142
+ export function resumedTranscriptArchive(range) {
143
+ const after = Number(range?.after);
144
+ const before = Number(range?.before);
145
+ if (!Number.isInteger(after) || !Number.isInteger(before) || before - 1 <= after) return null;
146
+ return { after, before };
147
+ }
@@ -61,12 +61,18 @@ export function createContextState({
61
61
  effortOptions: runtime.effortOptions,
62
62
  fast: runtime.fast,
63
63
  fastCapable: runtime.fastCapable,
64
+ autoEffort: runtime.autoEffort !== false,
64
65
  modelParameters: runtime.modelParameters || {},
65
66
  contextPercent: runtime.contextPercent,
66
67
  contextWindow: runtime.contextWindow,
67
68
  rawContextWindow: runtime.rawContextWindow,
68
69
  effectiveContextWindowPercent: runtime.effectiveContextWindowPercent,
69
70
  cwd: runtime.cwd || process.cwd(),
71
+ // Lead workspace record (worktrees/contract.mjs SessionWorkspace): the
72
+ // registered Project, the execution root, the worktree binding and its
73
+ // revision. Null while the session has never left its project folder.
74
+ // Identity-stable until a transition commits.
75
+ workspace: runtime.getWorkspace?.() ?? null,
70
76
  systemShell: runtime.systemShell || { source: 'auto', command: '', effective: '' },
71
77
  webSearchRoute: runtime.getWebSearchRoute?.() || runtime.webSearchRoute || null,
72
78
  autoClear: autoClearState(),
@@ -12,6 +12,9 @@ export function createInitialSessionState({ runtime, runtimeCwd, baseRouteState
12
12
  transcriptViewRevision: 0,
13
13
  transcriptHistoryBefore: false,
14
14
  transcriptHistoryAfter: false,
15
+ // Compaction-archive segments a paged view may load above the rows held
16
+ // here ({ after, before } segment numbers), set on resume.
17
+ transcriptArchive: null,
15
18
  structureRevision: 0,
16
19
  streamingTail: null,
17
20
  toasts: [],
@@ -175,7 +175,9 @@ export function mergePastedImages(entries) {
175
175
 
176
176
  // Byte-free image metadata for the user transcript item. Prompt content carries
177
177
  // only a content-addressed attachment ref after daemon intake; transcript items
178
- // and desktop snapshots carry just name/mime/size.
178
+ // and desktop snapshots carry name/mime/size plus, for attachment-reference
179
+ // parts, the `attachmentRef` so the desktop can rebuild thumbnails from the
180
+ // stored original.
179
181
  export function promptContentImageMeta(content, pastedImages) {
180
182
  const parts = Array.isArray(content) ? content.filter((part) => part?.type === 'image') : [];
181
183
  if (parts.length === 0) return null;
@@ -190,6 +192,7 @@ export function promptContentImageMeta(content, pastedImages) {
190
192
  name: String(meta?.filename || `Image ${index + 1}`),
191
193
  mimeType: String(part.mimeType || part.mediaType || meta?.mediaType || 'image/png'),
192
194
  bytes: Number(part.sizeBytes) || data.length,
195
+ ...(isAttachmentReference(part) ? { attachmentRef: part.attachmentRef } : {}),
193
196
  };
194
197
  });
195
198
  }
@@ -202,6 +205,8 @@ export function callCommitCallbacks(entries) {
202
205
  for (const entry of entries || []) {
203
206
  try {
204
207
  entry?.onCommitted?.();
205
- } catch {}
208
+ } catch {
209
+ // A throwing commit callback must not block the remaining entries.
210
+ }
206
211
  }
207
212
  }
@@ -52,7 +52,8 @@ export function latestQuotaFailure(items) {
52
52
  const transcript = Array.isArray(items) ? items : [];
53
53
  for (let index = transcript.length - 1; index >= 0; index -= 1) {
54
54
  const item = transcript[index];
55
- if (item?.kind === 'user') return null;
55
+ // A turn a compaction archived is no longer the model's to resume.
56
+ if (item?.kind === 'user' || item?.archived === true) return null;
56
57
  if (item?.kind !== 'turndone') continue;
57
58
  const quota = item.quota;
58
59
  if (String(item.status || '').toLowerCase() !== 'failed' || !quota || typeof quota.provider !== 'string') {
@@ -4,6 +4,7 @@
4
4
  * a turn is running). Each shows a command status while it holds the lock.
5
5
  */
6
6
  import { compactEventDetail } from '../labels.mjs';
7
+ import { archiveItemsForCompaction, compactionArchivedRows } from '../compaction-view.mjs';
7
8
 
8
9
  export function createSessionCommandsApi(bag) {
9
10
  const {
@@ -108,8 +109,15 @@ export function createSessionCommandsApi(bag) {
108
109
  invalidateExact: compactChanged,
109
110
  });
110
111
  set({ ...routeState(), stats: { ...getState().stats } });
111
- if (compactChanged) set({ items: replaceItems([]) });
112
- pushItem(compactDoneItem(result, startedAt));
112
+ if (compactChanged) {
113
+ // The compacted rows stay visible (archived) above the divider.
114
+ const { items } = archiveItemsForCompaction(getState().items, compactDoneItem(result, startedAt), null, {
115
+ archived: compactionArchivedRows(result),
116
+ });
117
+ set({ items: replaceItems(items, { preserveSpill: true }) });
118
+ } else {
119
+ pushItem(compactDoneItem(result, startedAt));
120
+ }
113
121
  return result;
114
122
  });
115
123
  } finally {
@@ -63,6 +63,10 @@ export function createSessionControlsApi(bag) {
63
63
  taskControl: (args = {}) => {
64
64
  return runtime.taskControl?.(args) ?? null;
65
65
  },
66
+ // Structured stop of one background shell job: { stopped, error? }.
67
+ stopShellJob: async (taskId) => {
68
+ return (await runtime.stopShellJob?.(taskId)) ?? { stopped: false, error: 'shell job control is unavailable' };
69
+ },
66
70
  goalControl: async (args = {}) => {
67
71
  const result = await runtime.goalControl?.(args);
68
72
  if (['pause', 'stop'].includes(result?.action)) {
@@ -83,8 +83,10 @@ export function createSessionExtensionsApi(bag) {
83
83
  }
84
84
  return await runtime.setExtensionScope(kind, name, projects);
85
85
  },
86
- skillsStatus: () => {
87
- return runtime.skillsStatus?.() || { cwd: getState().cwd, count: 0, skills: [] };
86
+ // `options.cwd`: list and scope skills for that folder instead of this
87
+ // session's (the desktop resolves a new-task draft's Project to it).
88
+ skillsStatus: (options) => {
89
+ return runtime.skillsStatus?.(options) || { cwd: getState().cwd, count: 0, skills: [] };
88
90
  },
89
91
  skillContent: (name) => {
90
92
  return runtime.skillContent?.(name);
@@ -13,7 +13,8 @@ export function createRewindAction(bag) {
13
13
  if (getState().busy || getState().commandBusy) return null;
14
14
  const items = getState().items || [];
15
15
  const index = items.findIndex((item) => item?.kind === 'user' && String(item?.id) === target);
16
- if (index < 0) return null;
16
+ // An archived prompt left the model context: there is nothing to rewind.
17
+ if (index < 0 || items[index]?.archived === true) return null;
17
18
  const text = String(items[index]?.text || '').trim();
18
19
  if (!text) return null;
19
20
  set({ commandBusy: true });
@@ -61,6 +61,23 @@ export function createSessionIntegrationsApi(bag, { oauthFlows }) {
61
61
  checkpointId
62
62
  );
63
63
  },
64
+ getTurnChanges: async (options = {}) => {
65
+ return await requireRuntimeMethod('getTurnChanges', 'Turn changes are unavailable')(options);
66
+ },
67
+ revertTurnChanges: async (checkpointId, file, revision) => {
68
+ return await requireRuntimeMethod('revertTurnChanges', 'Turn changes undo is unavailable')(
69
+ checkpointId,
70
+ file,
71
+ revision
72
+ );
73
+ },
74
+ reapplyTurnChanges: async (checkpointId, file, revision) => {
75
+ return await requireRuntimeMethod('reapplyTurnChanges', 'Turn changes reapply is unavailable')(
76
+ checkpointId,
77
+ file,
78
+ revision
79
+ );
80
+ },
64
81
  getOnboardingStatus: () => {
65
82
  return runtime.getOnboardingStatus?.() || { completed: true, workflowRoutes: {} };
66
83
  },
@@ -35,7 +35,12 @@ export function createDisposeAction(bag, { oauthFlows }) {
35
35
  try {
36
36
  clearInterval(lifecycle.runtimePulseTimer);
37
37
  } catch {}
38
- for (const key of ['unsubscribeRuntimeNotifications', 'unsubscribeAgentStatus', 'unsubscribeRemoteState']) {
38
+ for (const key of [
39
+ 'unsubscribeRuntimeNotifications',
40
+ 'unsubscribeAgentStatus',
41
+ 'unsubscribeRemoteState',
42
+ 'unsubscribeCompletionWakeGate',
43
+ ]) {
39
44
  try {
40
45
  lifecycle[key]?.();
41
46
  } catch {}
@@ -25,6 +25,8 @@ export function createInheritanceActions(bag, { restoreTranscriptItems }) {
25
25
  set({
26
26
  sessionId,
27
27
  items: replaceItems(items),
28
+ // An heir carries the conversation, never the source's archive.
29
+ transcriptArchive: null,
28
30
  toasts: [],
29
31
  queued: [],
30
32
  thinking: null,
@@ -1,6 +1,7 @@
1
1
  // Resume: reopen a stored session, rebuild the visible transcript from its
2
2
  // messages and reconcile live-share and steering at the same boundary.
3
3
  import { primeContextEstimates } from '../../../../runtime/agent/orchestrator/session/context-utils.mjs';
4
+ import { resumedTranscriptArchive } from '../../compaction-view.mjs';
4
5
 
5
6
  export function createResumeAction(bag, { restoreTranscriptItems }) {
6
7
  const {
@@ -52,6 +53,8 @@ export function createResumeAction(bag, { restoreTranscriptItems }) {
52
53
  });
53
54
  set({
54
55
  items: replaceItems(items),
56
+ // Paged views continue into the compaction archive past these rows.
57
+ transcriptArchive: resumedTranscriptArchive(r.transcriptArchive),
55
58
  toasts: [],
56
59
  queued: [],
57
60
  thinking: null,
@@ -9,7 +9,16 @@ import { createApiHelpers } from './shared.mjs';
9
9
  // published before the runtime write settles. What is NOT previewed about the
10
10
  // route (effort options, Fast capability, context window) is provider
11
11
  // metadata the runtime resolves while the preview is already on screen.
12
- const ROUTE_PREVIEW_KEYS = ['provider', 'model', 'effort', 'fast', 'modelParameters', 'contextPercent'];
12
+ const ROUTE_PREVIEW_KEYS = [
13
+ 'provider',
14
+ 'model',
15
+ 'effort',
16
+ 'fast',
17
+ 'autoEffort',
18
+ 'modelParameters',
19
+ 'contextPercent',
20
+ 'contextTokens',
21
+ ];
13
22
 
14
23
  /**
15
24
  * The patch that publishes a requested route before the runtime write settles.
@@ -129,6 +129,8 @@ export function createSessionSettingsApi(bag) {
129
129
  getTidyInstallStatus: () => runtime.getTidyInstallStatus?.(),
130
130
  getDeveloperSettings: () => runtime.getDeveloperSettings?.(),
131
131
  setDeveloperOption: lockedRuntimeCall((id, enabled) => runtime.setDeveloperOption?.(id, enabled)),
132
+ getWorktreeSettings: () => runtime.getWorktreeSettings(),
133
+ setWorktreeSettings: lockedRuntimeCall((patch) => runtime.setWorktreeSettings(patch)),
132
134
  setWebSearchEnabled: lockedRuntimeCall((enabled) => runtime.setWebSearchEnabled?.(enabled)),
133
135
  setInstructionFiles: lockedRuntimeCall((mode) => runtime.setInstructionFiles?.(mode)),
134
136
  setMemoryToolsEnabled: lockedRuntimeCall((enabled) => runtime.setMemoryToolsEnabled?.(enabled)),
@@ -152,6 +154,13 @@ export function createSessionSettingsApi(bag) {
152
154
  inspectHuggingFaceModel: (options) => runtime.inspectHuggingFaceModel(options),
153
155
  registerHuggingFaceModel: (previewId, licenseAccepted) =>
154
156
  runtime.registerHuggingFaceModel(previewId, licenseAccepted),
157
+ // Conversation import (advertised session actions; one object argument).
158
+ // Background jobs, so never behind commandBusy.
159
+ listImportableConversations: (params) => runtime.listImportableConversations(params),
160
+ getConversationImportJobs: (params) => runtime.getConversationImportJobs(params),
161
+ registerConversationImportFile: (params) => runtime.registerConversationImportFile(params),
162
+ startConversationImport: (params) => runtime.startConversationImport(params),
163
+ cancelConversationImport: (params) => runtime.cancelConversationImport(params),
155
164
  getChannelSettings: (options = {}) => {
156
165
  return (
157
166
  runtime.getChannelSettings?.(options) || {
@@ -0,0 +1,60 @@
1
+ /**
2
+ * worktree.mjs — the session object's Lead worktree surface. The daemon
3
+ * resolves these advertised actions by name (session-protocol.mjs) and each
4
+ * delegates to the runtime's workspace transition authority
5
+ * (session-runtime/workspace/transitions.mjs), then republishes the route
6
+ * state so the new `workspace` reaches every viewer. Failures are typed
7
+ * WorktreeErrors whose `code` crosses the daemon wire; a runtime without the
8
+ * authority rejects with WORKTREE_NOT_IMPLEMENTED.
9
+ *
10
+ * getBranchMenu() → { workspace, pendingWorktree, branches, occupancy, retainedWorktree }
11
+ * getProjectBranchMenu({ projectPath }) → { workspace, branches, occupancy, retainedWorktree: null }
12
+ * (no session: a New Task draft or the source-control dock)
13
+ * selectBranch({ branch, create?, expectedRevision?, confirmLarge? }) → { revision, workspace }
14
+ * selectProjectBranch({ projectPath, branch, create?, remote?, startPoint? }) → { branch, changed, commit? }
15
+ * selectProjectBranch({ projectPath, detach: commitId }) → { branch: null, changed, commit, detached: true }
16
+ * (no session: the guarded project-folder checkout)
17
+ * mergeProjectBranch({ projectPath, branch, target }) → backend merge result
18
+ * (no session: the source-control dock's merge into the confirmed target)
19
+ * requestWorktree({ name?, confirmLarge?, provision?, prompt?, txId?, expectedRevision? }) → { revision, workspace, pending, warnings? }
20
+ * (provision: a New Task's first send creates and enters it now)
21
+ * mergeWorkspace({ confirmed: true, target, cleanup?, expectedRevision? }) → backend merge result (+ cleanup)
22
+ * removeWorktree({ force?, expectedRevision? }) → { revision, workspace, removed }
23
+ * (expectedRevision: WORKTREE_REVISION_CONFLICT when the session moved on)
24
+ * (WORKTREE_REMOVAL_INCOMPLETE: partly removed; call again to finish)
25
+ * listWorktrees() → every managed worktree with its retention
26
+ * pruneWorktrees() → reconcile report (never a retained worktree)
27
+ */
28
+ import { worktreeError } from '../../../runtime/shared/worktrees/contract.mjs';
29
+
30
+ /** Session actions of the Lead worktree feature (settings live in settings.mjs). */
31
+ export const SESSION_WORKTREE_ACTIONS = Object.freeze([
32
+ 'getBranchMenu',
33
+ 'getProjectBranchMenu',
34
+ 'selectBranch',
35
+ 'selectProjectBranch',
36
+ 'mergeProjectBranch',
37
+ 'requestWorktree',
38
+ 'mergeWorkspace',
39
+ 'removeWorktree',
40
+ 'listWorktrees',
41
+ 'pruneWorktrees',
42
+ ]);
43
+
44
+ export function createSessionWorktreeApi({ runtime, set, routeState } = {}) {
45
+ return Object.fromEntries(
46
+ SESSION_WORKTREE_ACTIONS.map((action) => [
47
+ action,
48
+ async (input = {}) => {
49
+ if (typeof runtime?.[action] !== 'function') {
50
+ throw worktreeError('WORKTREE_NOT_IMPLEMENTED', `${action} is not implemented yet.`);
51
+ }
52
+ const value = await runtime[action](input ?? {});
53
+ if (!action.startsWith('get') && typeof set === 'function' && typeof routeState === 'function') {
54
+ set({ ...routeState() });
55
+ }
56
+ return value;
57
+ },
58
+ ])
59
+ );
60
+ }
@@ -12,6 +12,7 @@ import { createSessionControlsApi } from './session-api/controls.mjs';
12
12
  import { createSessionExtensionsApi } from './session-api/extensions.mjs';
13
13
  import { createSessionCommandsApi } from './session-api/commands.mjs';
14
14
  import { createQuotaResumeApi } from './session-api/quota-resume.mjs';
15
+ import { createSessionWorktreeApi } from './session-api/worktree.mjs';
15
16
 
16
17
  export function createSessionApi(bag) {
17
18
  const api = { ...createSessionApiA(bag), ...createSessionApiB(bag) };
@@ -59,5 +60,6 @@ export function createSessionApiA(bag) {
59
60
  ...createSessionExtensionsApi(bag),
60
61
  ...createSessionCommandsApi(bag),
61
62
  ...createQuotaResumeApi(bag),
63
+ ...createSessionWorktreeApi(bag),
62
64
  };
63
65
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { presentErrorText } from '../../../runtime/shared/err-text.mjs';
7
7
  import { sessionActivityTimestamp } from '../queue-helpers.mjs';
8
+ import { archiveItemsForCompaction, compactionArchivedRows } from '../compaction-view.mjs';
8
9
 
9
10
  // Upper bound on the awaited idle compaction. Without a bound a stalled
10
11
  // compaction wedges autoClearRunning/commandBusy and suppresses input drain.
@@ -52,23 +53,26 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
52
53
  autoClearState,
53
54
  routeState,
54
55
  syncContextStats,
56
+ replaceItems,
55
57
  } = bag;
56
58
 
57
- // Only an actual compaction resets the visible transcript; an unchanged
58
- // success keeps it. The model transcript always belongs to runtime.compact.
59
+ // Only an actual compaction resets the visible activity; an unchanged
60
+ // success keeps it. The compacted rows stay in view, archived above the
61
+ // divider. The model transcript always belongs to runtime.compact.
59
62
  function applyAutoClearUi(result) {
60
63
  if (result.changed === false) return false;
61
- const compactChanged = result.changed !== false;
62
- if (compactChanged) {
63
- reset.resetStats();
64
- reset.clearUiActivityBeforeContextSync();
65
- }
66
- syncContextStats({ allowEstimated: true, invalidateExact: compactChanged });
64
+ const kept = getState().items;
65
+ reset.resetStats();
66
+ reset.clearUiActivityBeforeContextSync({ keepTranscript: true });
67
+ syncContextStats({ allowEstimated: true, invalidateExact: true });
68
+ const { items } = archiveItemsForCompaction(kept, { id: nextId() }, null, {
69
+ archived: compactionArchivedRows(result),
70
+ });
67
71
  set({
72
+ items: replaceItems(items, { preserveSpill: true }),
68
73
  ...routeState(),
69
74
  stats: { ...getState().stats },
70
75
  });
71
- pushItem({ kind: 'statusdone', id: nextId(), label: 'Auto-clear complete' });
72
76
  return true;
73
77
  }
74
78
 
@@ -129,7 +133,9 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
129
133
  }
130
134
  }
131
135
 
132
- async function autoClearBeforeSubmit() {
136
+ // `ignorePending`: a completion-wake drain has already dequeued its own
137
+ // batch, so other queued entries must not veto the idle check.
138
+ async function autoClearBeforeSubmit({ ignorePending = false } = {}) {
133
139
  flushDeferredClearedSessionUi();
134
140
  const cfg = autoClearState();
135
141
  const now = Date.now();
@@ -138,7 +144,7 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
138
144
  const notIdle =
139
145
  !cfg.enabled ||
140
146
  getState().busy ||
141
- pending.length > 0 ||
147
+ (!ignorePending && pending.length > 0) ||
142
148
  flags.autoClearRunning ||
143
149
  flags.autoClearInFlight ||
144
150
  idleMs < cfg.idleMs;
@@ -188,5 +194,18 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
188
194
  }
189
195
  }
190
196
 
191
- return { autoClearBeforeSubmit, performAutoClear, flushDeferredClearedSessionUi };
197
+ // Same eligibility as a user submit, run before a completion wake turn so a
198
+ // cold cache after a long idle is compacted first. Never throws: a skipped or
199
+ // failed auto-clear must still let the wake run. A viewer mirroring another
200
+ // surface's owner leaves compaction to that owner.
201
+ async function autoClearBeforeWake() {
202
+ if (bag.liveShareMirroring?.() === true) return false;
203
+ try {
204
+ return await autoClearBeforeSubmit({ ignorePending: true });
205
+ } catch {
206
+ return false;
207
+ }
208
+ }
209
+
210
+ return { autoClearBeforeSubmit, autoClearBeforeWake, performAutoClear, flushDeferredClearedSessionUi };
192
211
  }
@@ -65,7 +65,19 @@ function renderBatchItems(batch, pushUserOrSyntheticItem) {
65
65
  }
66
66
  }
67
67
 
68
- function turnOptionsForBatch(batch, steering) {
68
+ const COMPLETION_WAKE_MODES = new Set(['task-notification', 'pending-resume']);
69
+
70
+ // Trusted provenance of a drained batch: Goal turns keep their own source; a
71
+ // batch made only of completion wakes (task notifications, pending resumes)
72
+ // is the runtime reporting, carried as a task notification so the runtime
73
+ // stores it as one and never treats its text as a user skill selection.
74
+ function batchPromptSource(batch) {
75
+ if (isGoalQueuedEntry(batch[0])) return batch[0].mode;
76
+ if (batch.length > 0 && batch.every((entry) => COMPLETION_WAKE_MODES.has(entry?.mode))) return 'task-notification';
77
+ return undefined;
78
+ }
79
+
80
+ export function turnOptionsForBatch(batch, steering) {
69
81
  const nonEditable = batch.filter((entry) => !isQueuedEntryEditable(entry));
70
82
  // A completion resume is owned by the completion that woke it. Esc
71
83
  // consumes that ownership; unlike ordinary notifications it must never
@@ -75,7 +87,7 @@ function turnOptionsForBatch(batch, steering) {
75
87
  (entry) => entry?.abortDiscardOnAbort === true || entry?.mode === 'pending-resume'
76
88
  );
77
89
  return {
78
- promptSource: isGoalQueuedEntry(batch[0]) ? batch[0].mode : undefined,
90
+ promptSource: batchPromptSource(batch),
79
91
  retryFailedTurn: batch[0]?.retryFailedTurn === true,
80
92
  displayText: batch
81
93
  .map((entry) => entry.text)
@@ -114,7 +126,10 @@ function turnOptionsForBatch(batch, steering) {
114
126
  };
115
127
  }
116
128
 
117
- export function createDrainLoop(bag, { queue, steering, submissions, flushDeferredClearedSessionUi }) {
129
+ export function createDrainLoop(
130
+ bag,
131
+ { queue, steering, submissions, flushDeferredClearedSessionUi, autoClearBeforeWake }
132
+ ) {
118
133
  const {
119
134
  tuiDebug,
120
135
  flags,
@@ -248,6 +263,15 @@ export function createDrainLoop(bag, { queue, steering, submissions, flushDeferr
248
263
  if (isGoalQueuedEntry(batch[0]) && bag.shouldRunGoalContinuation?.(batch[0]) !== true) {
249
264
  continue;
250
265
  }
266
+ // A completion wake calls the model like a user turn, so a cold cache
267
+ // after a long idle is compacted first; the wake runs regardless.
268
+ if (autoClearBeforeWake && batch.every((entry) => COMPLETION_WAKE_MODES.has(entry.mode))) {
269
+ await autoClearBeforeWake();
270
+ if (flags.drainEpoch !== drainEpoch || admission() !== 'open') {
271
+ queue.requeueEntriesFront(batch);
272
+ return;
273
+ }
274
+ }
251
275
  tuiDebug(`busy-queue drain batch=${batch.length} remaining=${pending.length}`);
252
276
  const merged = mergePromptContents(batch);
253
277
  rewindFailedTurnRows(batch);
@@ -30,12 +30,13 @@ export function createSessionResetOps(bag) {
30
30
  return stats;
31
31
  };
32
32
 
33
- const clearUiActivityBeforeContextSync = () => {
33
+ // `keepTranscript`: a compaction keeps the visible rows (its caller archives
34
+ // them); a clear or session reset wipes them and the archive range with them.
35
+ const clearUiActivityBeforeContextSync = ({ keepTranscript = false } = {}) => {
34
36
  clearToastTimers();
35
37
  resetAllStreamingMarkdownStablePrefixes();
36
- const items = replaceItems([]);
37
38
  set({
38
- items,
39
+ ...(keepTranscript ? {} : { items: replaceItems([]), transcriptArchive: null }),
39
40
  toasts: [],
40
41
  queued: [],
41
42
  thinking: null,