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
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * src/session-runtime/turn/turn-run.mjs - one user turn end to end: viewer
3
- * forwarding, turn open (abort controller, timing, worktree snapshot, warmup
4
- * arming), session preparation, the askSession callback bridge, and the
5
- * settlement that always runs. The phases live under turn-run/.
3
+ * forwarding, turn open (abort controller, timing, warmup arming), session
4
+ * preparation (workspace provisioning, then the worktree review snapshot), the
5
+ * askSession callback bridge, and the settlement that always runs. The phases
6
+ * live under turn-run/.
6
7
  */
7
- import { beginTurnSnapshot, cancelTurnSnapshot, completeTurnSnapshot } from '../../runtime/shared/turn-snapshot.mjs';
8
+ import { beginTurnSnapshot, completeTurnSnapshot } from '../../runtime/shared/turn-snapshot.mjs';
8
9
  import { runWithCwdOverride } from '../../runtime/shared/user-cwd.mjs';
9
10
  import { createTurnTranscript } from './turn-run/transcript.mjs';
10
11
  import { createTurnTimingFactory } from './turn-run/turn-timing.mjs';
@@ -23,7 +24,6 @@ export function createTurnRunner(deps) {
23
24
  endComputerExecution = async () => false,
24
25
  deferComputerSessionRelease = () => false,
25
26
  beginTurnSnapshotForTurn = beginTurnSnapshot,
26
- cancelTurnSnapshotForTurn = cancelTurnSnapshot,
27
27
  completeTurnSnapshotForTurn = completeTurnSnapshot,
28
28
  turnCleanupSettleMs = 2_000,
29
29
  getConfig = () => null,
@@ -35,7 +35,6 @@ export function createTurnRunner(deps) {
35
35
  createSnapshot: createSnapshotTrackerFactory({
36
36
  getCurrentCwd,
37
37
  beginTurnSnapshotForTurn,
38
- cancelTurnSnapshotForTurn,
39
38
  completeTurnSnapshotForTurn,
40
39
  turnCleanupSettleMs,
41
40
  }),
@@ -93,7 +92,7 @@ export function createTurnRunner(deps) {
93
92
  if (attachedSession?.remoteAttached) return forwardAttachedPrompt(attachedSession, prompt, options);
94
93
  const turn = openTurn(options);
95
94
  try {
96
- const session0 = await prepareSession(turn, prompt);
95
+ const session0 = await prepareSession(turn, prompt, options);
97
96
  const turnContext = await dispatchPromptSubmit(turn, session0, prompt, options);
98
97
  const result = await mgr.askSession(
99
98
  session0.id,
@@ -35,6 +35,10 @@ export async function runWebhookSession({
35
35
  workflow = null,
36
36
  attachments = null,
37
37
  signal = null,
38
+ // Endpoint-authored instructions: the run's ONLY skill-selection input.
39
+ // `prompt` also carries the fenced external payload, which must never
40
+ // select a skill; absent means nothing selects.
41
+ skillSelection = '',
38
42
  }) {
39
43
  const endpoint = String(name || '').trim();
40
44
  const body = String(prompt || '').trim();
@@ -63,9 +67,17 @@ export async function runWebhookSession({
63
67
  // askOpts.signal is the parent-abort link: it is cascaded onto the turn
64
68
  // controller, so aborting it stops the in-flight provider/tool work instead
65
69
  // of leaving a timed-out delivery's session running with live side effects.
66
- const ask = (turnContent) =>
67
- askSession(session.id, turnContent, null, null, projectCwd || undefined, undefined, signal ? { signal } : {});
68
- // Agents the run delegates to report back; each result is the next turn.
69
- const result = await runAutomationTurns(session.id, () => ask(content), ask);
70
+ const ask = (turnContent, askOpts) =>
71
+ askSession(session.id, turnContent, null, null, projectCwd || undefined, undefined, {
72
+ ...askOpts,
73
+ ...(signal ? { signal } : {}),
74
+ });
75
+ // Agents the run delegates to report back; each result is the next turn
76
+ // (runAutomationTurns marks those turns as task notifications).
77
+ const result = await runAutomationTurns(
78
+ session.id,
79
+ () => ask(content, { skillSelection: String(skillSelection ?? '') }),
80
+ ask
81
+ );
70
82
  return { sessionId: session.id, result: String(result?.content || '') };
71
83
  }
@@ -3,7 +3,7 @@ import { hasOwn } from '../../runtime/shared/object.mjs';
3
3
  import { isHiddenAgent } from '../../runtime/agent/orchestrator/internal-agents.mjs';
4
4
  import { normalizeWorkflowRoute } from '../../runtime/agent/orchestrator/runtime-core/workflow.mjs';
5
5
  import { ensureProviderEnabled } from '../../runtime/agent/orchestrator/runtime-core/config-helpers.mjs';
6
- import { selectionFastCapable } from '../route-state.mjs';
6
+ import { resolveRouteContextState, selectionFastCapable } from '../route-state.mjs';
7
7
  import { canonicalizeAgentRouteStorage, withAgentDisabled } from '../../runtime/shared/agent-route-config.mjs';
8
8
  import { agentEditorId } from './shared.mjs';
9
9
 
@@ -43,19 +43,31 @@ export function createAgentRouteApi(deps) {
43
43
  clean(selectedRoute.provider) === clean(stored.provider) && clean(selectedRoute.model) === clean(stored.model);
44
44
  const inheritedEffort = sameModel ? stored.effort || null : null;
45
45
  const inheritedModelParameters = sameModel ? stored.modelParameters || {} : {};
46
- const inheritedContextPercent = sameModel ? stored.contextPercent : undefined;
46
+ // A requested percent replaces the stored exact window and requested
47
+ // tokens replace the stored percent.
48
+ const requestsPercent = requested.contextPercent !== undefined;
49
+ const requestsTokens = requested.contextTokens !== undefined;
50
+ const inheritedContextPercent = sameModel && !requestsTokens ? stored.contextPercent : undefined;
51
+ const inheritedContextTokens = sameModel && !requestsPercent ? stored.contextTokens : undefined;
47
52
  selectedRoute = {
48
53
  ...selectedRoute,
49
54
  effort: requested.effort !== undefined ? selectedRoute.effort : inheritedEffort,
50
55
  fast: requested.fast !== undefined ? selectedRoute.fast === true : sameModel && stored.fast === true,
56
+ // Main's modelSettings bucket must not decide an agent's Auto effort.
57
+ autoEffort:
58
+ requested.autoEffort !== undefined ? requested.autoEffort !== false : !sameModel || stored.autoEffort !== false,
51
59
  modelParameters:
52
60
  requested.modelParameters !== undefined ? selectedRoute.modelParameters : inheritedModelParameters,
53
61
  // resolveRoute reads contextPercent from Main's modelSettings bucket;
54
62
  // an agent route owns its own.
55
- contextPercent: requested.contextPercent !== undefined ? requested.contextPercent : inheritedContextPercent,
63
+ contextPercent: requestsPercent ? requested.contextPercent : inheritedContextPercent,
64
+ contextTokens: requestsTokens ? requested.contextTokens : inheritedContextTokens,
56
65
  };
57
66
  await ensureProvidersReady(ensureProviderEnabled(getConfig(), selectedRoute.provider));
58
67
  const modelMeta = await lookupModelMeta(selectedRoute.provider, selectedRoute.model);
68
+ // Stored clamped, and not at all at the default window, as for Main.
69
+ const contextState = resolveRouteContextState(selectedRoute, modelMeta);
70
+ if (contextState.contextDefaultPercent !== undefined) selectedRoute.contextTokens = contextState.contextTokens;
59
71
  const fastCapable = selectionFastCapable(
60
72
  selectedRoute.provider,
61
73
  modelMeta,
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Process-wide admission gate shared by Lead workspace transitions, turn
3
+ * admission and worker spawning.
4
+ *
5
+ * - A transition and a worker spawn of the same Lead never overlap: a
6
+ * transition refuses while a spawn is being prepared, a spawn refuses while
7
+ * a transition is in flight.
8
+ * - Turns and transitions are mutually exclusive: an admitted turn is
9
+ * registered until it settles; a turn that arrives while its own session
10
+ * transitions, or while another session changes the checkout its cwd lies
11
+ * in (a held checkout folder), waits for that change to settle. A checkout
12
+ * folder can only be held while no other session's admitted turn runs in it.
13
+ * - Each worktree-bound Lead's execution root, which every worker of that Lead
14
+ * runs in.
15
+ */
16
+ import { worktreeError } from '../../runtime/shared/worktrees/contract.mjs';
17
+ import { throwIfAborted } from '../../runtime/shared/worktrees/git.mjs';
18
+ import { isWithin } from '../../runtime/shared/worktrees/paths.mjs';
19
+
20
+ /** @type {Map<string, { txId: string, settled: Promise<void> }>} Lead session id → in-flight transition. */
21
+ const transitions = new Map();
22
+ /** @type {Map<string, number>} Lead session id → spawns being prepared. */
23
+ const spawns = new Map();
24
+ /** @type {Map<string, string>} Lead session id → bound worktree execution root. */
25
+ const cwdLocks = new Map();
26
+ /** @type {Map<symbol, { sessionId: string, cwd: () => string }>} Admitted turns (live cwd). */
27
+ const turns = new Map();
28
+ /** @type {Map<symbol, { sessionId: string, folder: string, settled: Promise<void> }>} Checkouts being changed. */
29
+ const folderHolds = new Map();
30
+
31
+ const key = (sessionId) => String(sessionId || '').trim();
32
+
33
+ function latch() {
34
+ let resolve;
35
+ const settled = new Promise((done) => {
36
+ resolve = done;
37
+ });
38
+ return { settled, resolve };
39
+ }
40
+
41
+ function once(fn) {
42
+ let done = false;
43
+ return () => {
44
+ if (done) return;
45
+ done = true;
46
+ fn();
47
+ };
48
+ }
49
+
50
+ const within = (folder, cwd) => Boolean(folder && cwd) && isWithin(folder, cwd);
51
+
52
+ /**
53
+ * Enter a transition for `sessionId`; the returned function leaves it.
54
+ * @returns {() => void}
55
+ */
56
+ export function beginWorkspaceTransition(sessionId, txId) {
57
+ const id = key(sessionId);
58
+ if (!id) throw new TypeError('workspace transition requires a session id.');
59
+ if (transitions.has(id)) {
60
+ throw worktreeError('WORKTREE_BUSY_JOBS', 'Another workspace change is in progress for this session.', {
61
+ reason: 'transition',
62
+ });
63
+ }
64
+ if ((spawns.get(id) || 0) > 0) {
65
+ throw worktreeError('WORKTREE_BUSY_JOBS', undefined, { reason: 'workers', starting: spawns.get(id) });
66
+ }
67
+ const gate = latch();
68
+ transitions.set(id, { txId: String(txId || 'tx'), settled: gate.settled });
69
+ return once(() => {
70
+ transitions.delete(id);
71
+ gate.resolve();
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Hold `folder` (a checkout root) while its branch changes or a merge lands
77
+ * in it. Refuses (WORKTREE_BUSY_JOBS, `folder-in-use`) while another session's
78
+ * admitted turn runs inside it, and (`transition`) while another change holds
79
+ * an overlapping checkout; turns arriving meanwhile wait (admitTurn). The
80
+ * holder's own turns are its own business (the Lead busy check).
81
+ * @param {string|null} sessionId The changing session; '' / null for a session-less change.
82
+ * @returns {() => void} Release.
83
+ */
84
+ export function holdCheckoutFolder(sessionId, folder) {
85
+ const id = key(sessionId);
86
+ const users = new Set();
87
+ for (const turn of turns.values()) {
88
+ if (turn.sessionId !== id && within(folder, turn.cwd())) users.add(turn.sessionId);
89
+ }
90
+ if (users.size) {
91
+ throw worktreeError('WORKTREE_BUSY_JOBS', 'Other sessions are working in the project folder.', {
92
+ reason: 'folder-in-use',
93
+ sessions: [...users],
94
+ });
95
+ }
96
+ if ([...folderHolds.values()].some((hold) => within(hold.folder, folder) || within(folder, hold.folder))) {
97
+ throw worktreeError('WORKTREE_BUSY_JOBS', 'Another branch change is in progress in the project folder.', {
98
+ reason: 'transition',
99
+ });
100
+ }
101
+ const token = Symbol('checkout-folder');
102
+ const gate = latch();
103
+ folderHolds.set(token, { sessionId: id, folder, settled: gate.settled });
104
+ return once(() => {
105
+ folderHolds.delete(token);
106
+ gate.resolve();
107
+ });
108
+ }
109
+
110
+ function admissionBlocker(id, cwd) {
111
+ const own = transitions.get(id);
112
+ if (own) return own.settled;
113
+ const path = cwd();
114
+ for (const hold of folderHolds.values()) {
115
+ if (hold.sessionId !== id && within(hold.folder, path)) return hold.settled;
116
+ }
117
+ return null;
118
+ }
119
+
120
+ function settledOrAborted(promise, signal) {
121
+ if (!signal) return promise;
122
+ return new Promise((resolve, reject) => {
123
+ const abort = () => {
124
+ try {
125
+ throwIfAborted(signal);
126
+ } catch (error) {
127
+ reject(error);
128
+ }
129
+ };
130
+ signal.addEventListener('abort', abort, { once: true });
131
+ promise.then(() => {
132
+ signal.removeEventListener('abort', abort);
133
+ resolve();
134
+ });
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Admit one turn of `sessionId`, whose live cwd is `cwd()`: waits while the
140
+ * session itself transitions or another session holds the checkout the cwd
141
+ * lies in, then registers the turn until the returned release is called.
142
+ * An abort while waiting rejects and registers nothing.
143
+ * @param {{ sessionId: string, cwd: () => string, signal?: AbortSignal }} input
144
+ * @returns {Promise<() => void>}
145
+ */
146
+ export async function admitTurn({ sessionId, cwd, signal }) {
147
+ const id = key(sessionId);
148
+ for (let blocker = admissionBlocker(id, cwd); blocker; blocker = admissionBlocker(id, cwd)) {
149
+ throwIfAborted(signal);
150
+ await settledOrAborted(blocker, signal);
151
+ }
152
+ throwIfAborted(signal);
153
+ const token = Symbol('turn');
154
+ turns.set(token, { sessionId: id, cwd });
155
+ return once(() => turns.delete(token));
156
+ }
157
+
158
+ /**
159
+ * Admit one worker spawn preparation for the Lead(s) in `sessionIds`.
160
+ * @param {Array<string|null|undefined>} sessionIds Owner and caller session ids.
161
+ * @returns {() => void}
162
+ */
163
+ export function enterWorkerSpawn(sessionIds) {
164
+ const ids = [...new Set(sessionIds.map(key).filter(Boolean))];
165
+ if (ids.some((id) => transitions.has(id))) {
166
+ throw worktreeError('WORKTREE_BUSY_JOBS', 'The Lead workspace is changing; spawn the worker after it settles.', {
167
+ reason: 'transition',
168
+ });
169
+ }
170
+ for (const id of ids) spawns.set(id, (spawns.get(id) || 0) + 1);
171
+ let left = false;
172
+ return () => {
173
+ if (left) return;
174
+ left = true;
175
+ for (const id of ids) {
176
+ const next = (spawns.get(id) || 1) - 1;
177
+ if (next > 0) spawns.set(id, next);
178
+ else spawns.delete(id);
179
+ }
180
+ };
181
+ }
182
+
183
+ /** Record (or clear with null) the worktree root a Lead's workers must run in. */
184
+ export function setWorkspaceCwdLock(sessionId, cwd) {
185
+ const id = key(sessionId);
186
+ if (!id) return;
187
+ if (cwd) cwdLocks.set(id, String(cwd));
188
+ else cwdLocks.delete(id);
189
+ }
190
+
191
+ /** The locked worker cwd for the first Lead id that has one, or null. */
192
+ export function workspaceCwdLock(sessionIds) {
193
+ for (const id of sessionIds.map(key)) {
194
+ if (id && cwdLocks.has(id)) return cwdLocks.get(id);
195
+ }
196
+ return null;
197
+ }
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Session-less branch operations on a registered Project's folder (a New
3
+ * Task draft, the source-control dock): its branch menu, a guarded checkout
4
+ * and a guarded merge. They act only on a registered Project (a repository
5
+ * subfolder Project included) and hold the checkout (withProjectFolder) while
6
+ * git changes it.
7
+ */
8
+ import { branchMenuEntries, projectWorkspace, worktreeError } from '../../runtime/shared/worktrees/contract.mjs';
9
+
10
+ function requireText(value, name) {
11
+ if (typeof value !== 'string' || !value.trim()) throw new TypeError(`${name} must be a non-empty string.`);
12
+ return value.trim();
13
+ }
14
+
15
+ /**
16
+ * WORKTREE_UNSUPPORTED_REPO when the project folder has no checked-out branch
17
+ * to merge into; WORKTREE_TARGET_MISMATCH when the confirmed `target` (null:
18
+ * none confirmed) is no longer the checked-out branch.
19
+ */
20
+ export function assertMergeTarget(currentBranch, target) {
21
+ if (!currentBranch) {
22
+ throw worktreeError('WORKTREE_UNSUPPORTED_REPO', 'The project folder has no checked-out branch to merge into.');
23
+ }
24
+ if (target !== null && target !== currentBranch) {
25
+ throw worktreeError(
26
+ 'WORKTREE_TARGET_MISMATCH',
27
+ `The project folder is now on "${currentBranch}"; confirm the merge again.`,
28
+ { target, current: currentBranch }
29
+ );
30
+ }
31
+ }
32
+
33
+ /**
34
+ * @param {object} deps
35
+ * @param {() => Promise<any>} deps.backend The managed-worktree backend.
36
+ * @param {(path: string) => Promise<any>} deps.inspectProject
37
+ * @param {(path: string) => Promise<string|null>} deps.findRegisteredProject
38
+ * @param {<T>(sessionId: string|null, folder: string, fn: () => Promise<T>) => Promise<T>} deps.withProjectFolder
39
+ */
40
+ export function createProjectBranchOps({ backend, inspectProject, findRegisteredProject, withProjectFolder }) {
41
+ /** WORKTREE_PROJECT_UNKNOWN unless `projectPath` is a registered Project. */
42
+ async function registeredProject(projectPath) {
43
+ const path = requireText(projectPath, 'projectPath');
44
+ const registered = await findRegisteredProject(path);
45
+ if (!registered) throw worktreeError('WORKTREE_PROJECT_UNKNOWN', undefined, { projectPath: path });
46
+ return registered;
47
+ }
48
+
49
+ /**
50
+ * A Project's branch menu with no session: the project folder's workspace
51
+ * and the real occupancy (current / session / external / free).
52
+ */
53
+ async function getProjectBranchMenu({ projectPath } = {}) {
54
+ const path = await registeredProject(projectPath);
55
+ const project = await inspectProject(path);
56
+ const menu = await (await backend()).listBranchOccupancy({ projectPath: path, sessionId: null });
57
+ return {
58
+ workspace: projectWorkspace({
59
+ projectPath: path,
60
+ repoCommonDir: project.repoCommonDir,
61
+ branch: project.currentBranch,
62
+ }),
63
+ branches: branchMenuEntries(menu.branches, menu.occupancy),
64
+ occupancy: menu.occupancy,
65
+ retainedWorktree: null,
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Check out (or create) `branch` in a Project folder with no session: the
71
+ * same guarded path a session's branch change takes — refused while another
72
+ * session works in the checkout, which is held until the switch is done;
73
+ * the manager's repository lock, occupancy and no-carry (dirty) checks.
74
+ */
75
+ async function selectProjectBranch({
76
+ projectPath,
77
+ branch,
78
+ create = false,
79
+ remote = false,
80
+ startPoint = null,
81
+ detach = null,
82
+ } = {}) {
83
+ const path = await registeredProject(projectPath);
84
+ if (detach !== null) {
85
+ // A history entry checked out detached: the same guard, no branch.
86
+ if (branch !== undefined || create === true || remote === true || startPoint !== null) {
87
+ throw new TypeError('detach excludes branch, create, remote and startPoint.');
88
+ }
89
+ const commit = requireText(detach, 'detach');
90
+ const project = await inspectProject(path);
91
+ return withProjectFolder(null, project.topLevel || path, async () =>
92
+ (await backend()).checkoutProjectBranch({ projectPath: path, detach: commit })
93
+ );
94
+ }
95
+ const name = requireText(branch, 'branch');
96
+ if (create === true && remote === true) throw new TypeError('create and remote are exclusive.');
97
+ if (startPoint !== null && create !== true) throw new TypeError('startPoint needs create.');
98
+ const project = await inspectProject(path);
99
+ if (create !== true && remote !== true && project.currentBranch === name) return { branch: name, changed: false };
100
+ return withProjectFolder(null, project.topLevel || path, async () => {
101
+ const backendApi = await backend();
102
+ return backendApi.checkoutProjectBranch({
103
+ projectPath: path,
104
+ branch: name,
105
+ create: create === true,
106
+ remote: remote === true,
107
+ ...(startPoint !== null ? { startPoint: requireText(startPoint, 'startPoint') } : {}),
108
+ });
109
+ });
110
+ }
111
+
112
+ /**
113
+ * Merge a local branch into a Project folder's checked-out branch with no
114
+ * session: `target` is the branch the user confirmed and must still be
115
+ * checked out (WORKTREE_TARGET_MISMATCH); refused while another session
116
+ * works in that checkout, which is held (turn admission waits) until the
117
+ * merge is done.
118
+ */
119
+ async function mergeProjectBranch({ projectPath, branch, target } = {}) {
120
+ const path = await registeredProject(projectPath);
121
+ const source = requireText(branch, 'branch');
122
+ const confirmedTarget = requireText(target, 'target');
123
+ const project = await inspectProject(path);
124
+ assertMergeTarget(project.currentBranch, confirmedTarget);
125
+ return withProjectFolder(null, project.topLevel || path, async () =>
126
+ (await backend()).mergeBranchIntoProject({
127
+ projectPath: path,
128
+ source,
129
+ target: confirmedTarget,
130
+ confirmed: true,
131
+ })
132
+ );
133
+ }
134
+
135
+ return { getProjectBranchMenu, selectProjectBranch, mergeProjectBranch };
136
+ }