mixdog 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. package/package.json +4 -3
  2. package/scripts/build-shipped-history.mjs +125 -33
  3. package/scripts/gate-local.mjs +220 -63
  4. package/scripts/graph-parity.mjs +8 -3
  5. package/scripts/lib/gate-scheduler.mjs +139 -32
  6. package/scripts/lib/gate-timing-reporter.mjs +16 -0
  7. package/scripts/lib/run-node-tests.mjs +71 -34
  8. package/scripts/lib/scoped-temp.mjs +1 -0
  9. package/scripts/lib/test-failure-records.mjs +14 -1
  10. package/scripts/lib/test-failure-summary.mjs +9 -4
  11. package/scripts/lib/test-spawn-ledger.mjs +43 -3
  12. package/scripts/post-release-check.mjs +26 -16
  13. package/scripts/pptx-kit-index.mjs +5 -6
  14. package/scripts/provider-pingpong-live.mjs +1 -1
  15. package/scripts/prune-embedding-runtime.mjs +3 -1
  16. package/scripts/release-paths.mjs +7 -1
  17. package/scripts/suite-health.mjs +110 -28
  18. package/scripts/test.mjs +9 -14
  19. package/src/agents/advisor/AGENT.md +4 -4
  20. package/src/agents/advisor/agent.json +1 -1
  21. package/src/agents/explore/AGENT.md +22 -0
  22. package/src/agents/explore/agent.json +6 -0
  23. package/src/cli.mjs +7 -0
  24. package/src/defaults/agents.json +7 -0
  25. package/src/defaults/shipped-history.json +38 -2
  26. package/src/defaults/skills/browser-use/SKILL.md +4 -1
  27. package/src/defaults/skills/code-tidy/SKILL.md +71 -102
  28. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
  29. package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
  30. package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
  31. package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
  32. package/src/defaults/skills/computer-use/SKILL.md +12 -2
  33. package/src/defaults/skills/setup/SKILL.md +2 -2
  34. package/src/defaults/skills/setup/references/actions.md +28 -9
  35. package/src/defaults/skills/setup/references/surfaces.md +5 -2
  36. package/src/defaults/skills/setup-guide/SKILL.md +11 -3
  37. package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
  38. package/src/defaults/skills/skill-creator/SKILL.md +85 -190
  39. package/src/defaults/skills/skill-creator/references/design.md +70 -162
  40. package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
  41. package/src/defaults/skills/test-suite/SKILL.md +194 -0
  42. package/src/defaults/skills/test-suite/references/case-management.md +51 -0
  43. package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
  44. package/src/defaults/skills/test-suite/references/reliability.md +49 -0
  45. package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
  46. package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
  47. package/src/defaults/skills/visualize/SKILL.md +6 -2
  48. package/src/lib/instruction-text.cjs +36 -0
  49. package/src/lib/rules-builder.cjs +40 -50
  50. package/src/orchestration/balanced.md +23 -0
  51. package/src/orchestration/focused.md +22 -0
  52. package/src/orchestration/none.md +5 -0
  53. package/src/orchestration/swarm.md +24 -0
  54. package/src/rules/agent-mode/AGENT_MODE.md +3 -1
  55. package/src/rules/agent-mode/MIXY.md +2 -2
  56. package/src/rules/lead/LEAD.md +3 -3
  57. package/src/rules/shared/20-research.md +3 -6
  58. package/src/rules/shared/40-editing.md +1 -0
  59. package/src/rules/shared/60-verification.md +10 -9
  60. package/src/rules/shared/70-delivery.md +4 -3
  61. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
  62. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +3 -3
  63. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -2
  64. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +132 -21
  65. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -9
  66. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +2 -2
  67. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +67 -0
  69. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
  70. package/src/runtime/agent/orchestrator/config.mjs +12 -7
  71. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +7 -7
  72. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -30
  73. package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
  74. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +124 -12
  75. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +204 -49
  76. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +16 -7
  77. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +157 -57
  78. package/src/runtime/agent/orchestrator/mcp/client.mjs +54 -23
  79. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +8 -2
  81. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +83 -52
  82. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +1 -1
  83. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +14 -0
  84. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +43 -27
  85. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +43 -8
  86. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +30 -28
  87. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
  89. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-stop.mjs +3 -3
  90. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
  91. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
  92. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  93. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
  94. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
  95. package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
  96. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
  97. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
  98. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
  99. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
  100. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +2 -2
  102. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +48 -31
  103. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
  104. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
  105. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
  106. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
  107. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
  109. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +4 -6
  110. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2784 -2872
  111. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +5 -8
  112. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +26 -28
  113. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +288 -300
  114. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +3 -1
  115. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +1 -0
  116. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
  117. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
  118. package/src/runtime/agent/orchestrator/providers/registry.mjs +33 -2
  119. package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
  120. package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
  121. package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
  122. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +576 -0
  123. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +10 -30
  124. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +32 -0
  125. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +0 -11
  126. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +8 -0
  127. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +17 -3
  128. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +47 -27
  129. package/src/runtime/agent/orchestrator/runtime-core/goal-deadlines.mjs +141 -10
  130. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +26 -63
  131. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +28 -3
  132. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +36 -11
  133. package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +88 -56
  134. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +4 -1
  135. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +51 -32
  136. package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +45 -145
  137. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +15 -98
  138. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +32 -99
  139. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +23 -78
  140. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +69 -47
  141. package/src/runtime/agent/orchestrator/runtime-core/todo-list.mjs +367 -0
  142. package/src/runtime/agent/orchestrator/runtime-core/todo-tool-defs.mjs +47 -0
  143. package/src/runtime/agent/orchestrator/runtime-core/tool-availability.mjs +155 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +12 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +119 -35
  146. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +4 -1
  147. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +15 -6
  148. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
  149. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +28 -22
  150. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +30 -0
  151. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
  152. package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
  153. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +1 -1
  154. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +94 -10
  155. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -2
  156. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +1 -1
  157. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -1
  158. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +3 -0
  159. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +1 -1
  160. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -12
  161. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +4 -4
  162. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +11 -6
  163. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +6 -6
  164. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +7 -3
  165. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +11 -1
  166. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
  167. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +37 -8
  169. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +1 -1
  170. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +11 -1
  172. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +1 -1
  173. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +5 -3
  174. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
  175. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/todo-check.mjs +196 -0
  176. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +116 -50
  177. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +8 -1
  178. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +1 -1
  179. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +1 -1
  180. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -1
  181. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +5 -6
  182. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +27 -3
  183. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +18 -2
  184. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
  185. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
  186. package/src/runtime/agent/orchestrator/session/loop/turn-report.mjs +35 -0
  187. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +1 -1
  188. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +103 -50
  189. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +9 -7
  190. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +21 -3
  191. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +27 -11
  192. package/src/runtime/agent/orchestrator/session/manager/ask-turn-open.mjs +37 -34
  193. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +15 -0
  194. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +25 -15
  195. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +79 -24
  196. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +3 -0
  197. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +12 -1
  198. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
  199. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +6 -1
  200. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +9 -1
  201. package/src/runtime/agent/orchestrator/session/manager/pending-spool-path.mjs +2 -2
  202. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +1 -1
  203. package/src/runtime/agent/orchestrator/session/manager/prompt-settings.mjs +598 -0
  204. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +20 -0
  205. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -14
  206. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +2 -0
  207. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +12 -0
  208. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +1 -1
  210. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +56 -14
  211. package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +31 -0
  212. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +59 -20
  213. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +2 -0
  214. package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
  215. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
  216. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +18 -4
  217. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +8 -9
  218. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +339 -88
  219. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +135 -11
  220. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +377 -104
  221. package/src/runtime/agent/orchestrator/session/manager/turn-durability.mjs +144 -0
  222. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +48 -30
  223. package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
  224. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +4 -0
  225. package/src/runtime/agent/orchestrator/session/manager.mjs +6 -0
  226. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +12 -6
  227. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +8 -1
  228. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +1 -1
  229. package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +5 -1
  230. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +1 -1
  231. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +2 -2
  232. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +23 -2
  233. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +3 -3
  234. package/src/runtime/agent/orchestrator/session/store/transcript-durability.mjs +88 -0
  235. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +5 -0
  236. package/src/runtime/agent/orchestrator/session/store-summary-log.mjs +1 -1
  237. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +243 -38
  238. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
  239. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +177 -8
  240. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
  241. package/src/runtime/agent/orchestrator/session/store.mjs +5 -0
  242. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +7 -1
  243. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +9 -1
  244. package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
  245. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -1
  246. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +2 -2
  247. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -5
  248. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -1
  249. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
  250. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +21 -3
  251. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  252. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/worktree-add-guard.mjs +77 -0
  253. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -1
  254. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +42 -28
  255. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +30 -14
  256. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +2 -2
  257. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
  258. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +1 -1
  259. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +0 -1
  260. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
  261. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +0 -10
  262. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +95 -20
  263. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
  264. package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -24
  265. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary/child-kill.mjs +4 -3
  266. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +1 -2
  267. package/src/runtime/agent/orchestrator/tools/code-graph/modes/calls.mjs +1 -1
  268. package/src/runtime/agent/orchestrator/tools/code-graph/modes/symbols.mjs +2 -2
  269. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +4 -5
  270. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +3 -4
  271. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4 -22
  272. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  273. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
  274. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
  275. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +105 -15
  276. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
  277. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
  278. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
  279. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +35 -11
  280. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +2 -0
  281. package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
  282. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -6
  283. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +0 -1
  284. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  285. package/src/runtime/attachments/attachment-reference.mjs +1 -1
  286. package/src/runtime/attachments/pdf-extract.mjs +1 -1
  287. package/src/runtime/attachments/store.d.mts +1 -0
  288. package/src/runtime/attachments/store.mjs +2 -2
  289. package/src/runtime/channels/lib/config-reload-watch.mjs +42 -0
  290. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +29 -9
  291. package/src/runtime/channels/lib/scheduler.mjs +33 -0
  292. package/src/runtime/channels/lib/schedules-db.mjs +11 -4
  293. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +4 -1
  294. package/src/runtime/channels/lib/webhooks-db.mjs +9 -3
  295. package/src/runtime/channels/lib/whisper-port.mjs +19 -10
  296. package/src/runtime/channels/lib/whisper-server.mjs +22 -13
  297. package/src/runtime/channels/lib/worker-main.mjs +9 -31
  298. package/src/runtime/computer-bridge/linux-readiness.mjs +10 -14
  299. package/src/runtime/connectors/connector-accounts-mcp.mjs +372 -103
  300. package/src/runtime/connectors/gmail-app-password.mjs +4 -4
  301. package/src/runtime/connectors/google-mcp.mjs +1 -1
  302. package/src/runtime/effort-judge/judge-client.mjs +2 -2
  303. package/src/runtime/effort-judge/judge-input.mjs +4 -4
  304. package/src/runtime/explore/explorer.mjs +88 -0
  305. package/src/runtime/explore/tool-defs.mjs +35 -0
  306. package/src/runtime/explore/tool.mjs +123 -0
  307. package/src/runtime/local-provider/hardware.mjs +1 -1
  308. package/src/runtime/media/adapters/codex-image.mjs +3 -3
  309. package/src/runtime/media/adapters/gemini-video.mjs +1 -1
  310. package/src/runtime/media/media-usage.mjs +1 -1
  311. package/src/runtime/media/store.mjs +1 -1
  312. package/src/runtime/memory/index.mjs +15 -1
  313. package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
  314. package/src/runtime/memory/lib/embedding-reindex.mjs +27 -0
  315. package/src/runtime/memory/lib/embedding-worker.mjs +4 -0
  316. package/src/runtime/memory/lib/memory-embed.mjs +83 -14
  317. package/src/runtime/memory/lib/memory-process-lock.mjs +159 -36
  318. package/src/runtime/memory/lib/memory-text-utils.mjs +6 -1
  319. package/src/runtime/memory/lib/memory.mjs +17 -0
  320. package/src/runtime/memory/lib/pg/process.mjs +1 -1
  321. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -96
  322. package/src/runtime/memory/lib/recall-hybrid/hybrid-sql.mjs +12 -3
  323. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  324. package/src/runtime/office/authoring/pptx-author-action.mjs +1 -1
  325. package/src/runtime/office/authoring/xlsx-html-build.mjs +1 -1
  326. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  327. package/src/runtime/office/capabilities.mjs +1 -1
  328. package/src/runtime/office/core/office-core.mjs +1 -1
  329. package/src/runtime/office/design/content-model.mjs +3 -3
  330. package/src/runtime/office/design/docx/design-docx/section.mjs +6 -6
  331. package/src/runtime/office/design/xlsx/design-xlsx-components.mjs +1 -1
  332. package/src/runtime/office/design/xlsx/design-xlsx.mjs +1 -1
  333. package/src/runtime/office/pdf/ocr-engine.mjs +1 -1
  334. package/src/runtime/office/pdf/pdf-writer.mjs +4 -4
  335. package/src/runtime/office/portable/portable-docx-operations.mjs +2 -2
  336. package/src/runtime/office/portable/portable-soffice.mjs +8 -6
  337. package/src/runtime/office/portable/xlsx-contract.mjs +1 -1
  338. package/src/runtime/office/quality/assurance-structure-docx.mjs +1 -1
  339. package/src/runtime/shared/agent-route-config.mjs +17 -2
  340. package/src/runtime/shared/atomic-file.d.mts +8 -0
  341. package/src/runtime/shared/atomic-file.mjs +103 -2
  342. package/src/runtime/shared/background-tasks.mjs +37 -10
  343. package/src/runtime/shared/background-wait.mjs +66 -0
  344. package/src/runtime/shared/child-guardian.mjs +17 -7
  345. package/src/runtime/shared/config.mjs +313 -16
  346. package/src/runtime/shared/connector-accounts.mjs +5 -5
  347. package/src/runtime/shared/connector-catalog.d.mts +14 -8
  348. package/src/runtime/shared/connector-catalog.mjs +70 -52
  349. package/src/runtime/shared/custom-provider-keys.mjs +20 -0
  350. package/src/runtime/shared/file-has-data.mjs +26 -2
  351. package/src/runtime/shared/file-lock.mjs +21 -18
  352. package/src/runtime/shared/git-launch.d.mts +9 -0
  353. package/src/runtime/shared/git-launch.mjs +213 -0
  354. package/src/runtime/shared/git-runner-worker.mjs +2 -1
  355. package/src/runtime/shared/git-runner.mjs +7 -2
  356. package/src/runtime/shared/idle-gc.mjs +30 -7
  357. package/src/runtime/shared/llm/cost.mjs +6 -1
  358. package/src/runtime/shared/llm/http-agent.mjs +316 -29
  359. package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
  360. package/src/runtime/shared/llm/model-catalog.mjs +46 -6
  361. package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
  362. package/src/runtime/shared/llm/system-proxy.mjs +453 -0
  363. package/src/runtime/shared/llm/usage-ledger-quota.mjs +31 -12
  364. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +84 -8
  365. package/src/runtime/shared/llm/usage-ledger.mjs +3 -0
  366. package/src/runtime/shared/llm/usage-rollup.mjs +48 -0
  367. package/src/runtime/shared/maintenance-schedule.mjs +109 -0
  368. package/src/runtime/shared/process-runner.mjs +8 -4
  369. package/src/runtime/shared/provider-accounts.mjs +52 -2
  370. package/src/runtime/shared/routine-trigger.d.mts +13 -0
  371. package/src/runtime/shared/routine-trigger.mjs +34 -0
  372. package/src/runtime/shared/run-child.d.mts +2 -1
  373. package/src/runtime/shared/run-child.mjs +70 -18
  374. package/src/runtime/shared/session-scratch.mjs +14 -2
  375. package/src/runtime/shared/shipped-definitions.mjs +7 -1
  376. package/src/runtime/shared/staged-install-worker.mjs +5 -0
  377. package/src/runtime/shared/staged-update.mjs +47 -2
  378. package/src/runtime/shared/tool-card-model.golden.json +3 -12
  379. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  380. package/src/runtime/shared/tool-surface.mjs +110 -36
  381. package/src/runtime/shared/tool-work-units.mjs +35 -6
  382. package/src/runtime/shared/turn-snapshot.mjs +26 -4
  383. package/src/runtime/shared/turn-worktree-snapshot.mjs +409 -54
  384. package/src/runtime/shared/worker-requests.mjs +17 -3
  385. package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
  386. package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
  387. package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
  388. package/src/runtime/shared/worktrees/branch-management.mjs +5 -3
  389. package/src/runtime/shared/worktrees/contract.mjs +16 -6
  390. package/src/runtime/shared/worktrees/dependencies.mjs +127 -89
  391. package/src/runtime/shared/worktrees/disk.mjs +79 -2
  392. package/src/runtime/shared/worktrees/git.mjs +97 -7
  393. package/src/runtime/shared/worktrees/include.mjs +6 -4
  394. package/src/runtime/shared/worktrees/maintenance.mjs +422 -30
  395. package/src/runtime/shared/worktrees/manager.mjs +962 -197
  396. package/src/runtime/shared/worktrees/settings.mjs +33 -7
  397. package/src/runtime/shared/worktrees/test-support.mjs +5 -1
  398. package/src/runtime/shared/worktrees/worker-snapshots.mjs +82 -0
  399. package/src/runtime/tidy/install.mjs +95 -15
  400. package/src/runtime/tidy/languages.mjs +17 -15
  401. package/src/runtime/tidy/process.mjs +9 -5
  402. package/src/runtime/tidy/resolve.mjs +19 -16
  403. package/src/runtime/tidy/runners/biome.mjs +3 -3
  404. package/src/runtime/tidy/tool.mjs +1 -1
  405. package/src/runtime/tidy/worktree.mjs +10 -6
  406. package/src/runtime/visualize-bridge/client.mjs +4 -1
  407. package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
  408. package/src/runtime/web-search/index.mjs +4 -23
  409. package/src/runtime/web-search/lib/web-tools.mjs +2 -2
  410. package/src/runtime/web-search/tool-defs.mjs +17 -26
  411. package/src/session-runtime/agent-profile-changes.mjs +55 -4
  412. package/src/session-runtime/agent-task-sessions.mjs +410 -353
  413. package/src/session-runtime/boot/apis.mjs +27 -4
  414. package/src/session-runtime/boot/begin.mjs +2 -0
  415. package/src/session-runtime/boot/config.mjs +10 -1
  416. package/src/session-runtime/boot/facade.mjs +1 -0
  417. package/src/session-runtime/boot/providers.mjs +70 -3
  418. package/src/session-runtime/boot/session.mjs +2 -0
  419. package/src/session-runtime/boot/tools.mjs +71 -25
  420. package/src/session-runtime/bot-status.mjs +103 -103
  421. package/src/session-runtime/channel-config-api.mjs +1 -0
  422. package/src/session-runtime/config-change-effects.mjs +179 -0
  423. package/src/session-runtime/config-lifecycle/config-writers.mjs +1 -0
  424. package/src/session-runtime/config-lifecycle.mjs +160 -24
  425. package/src/session-runtime/connector-merge-migration.mjs +18 -15
  426. package/src/session-runtime/conversation-import/discovery.mjs +245 -47
  427. package/src/session-runtime/conversation-import/service.mjs +12 -5
  428. package/src/session-runtime/goal-facade-api.mjs +49 -3
  429. package/src/session-runtime/handoff-attachments.mjs +1 -1
  430. package/src/session-runtime/held-requests.mjs +3 -1
  431. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +3 -0
  432. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -2
  433. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -11
  434. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
  435. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +161 -120
  436. package/src/session-runtime/internal-tool-executor.mjs +12 -19
  437. package/src/session-runtime/lifecycle/cold-heir.mjs +7 -0
  438. package/src/session-runtime/lifecycle/memory-ingest.mjs +3 -3
  439. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +53 -5
  440. package/src/session-runtime/lifecycle/session-switch.mjs +13 -2
  441. package/src/session-runtime/lifecycle/teardown/session-close.mjs +10 -5
  442. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  443. package/src/session-runtime/lifecycle-api.mjs +1 -0
  444. package/src/session-runtime/mcp-glue/server-catalog.mjs +27 -10
  445. package/src/session-runtime/mcp-glue/server-connection.mjs +34 -8
  446. package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
  447. package/src/session-runtime/mixy-heartbeat.mjs +1 -1
  448. package/src/session-runtime/model-route/set-route.mjs +40 -7
  449. package/src/session-runtime/native-web-search/routes.mjs +3 -3
  450. package/src/session-runtime/provider-auth/login.mjs +2 -2
  451. package/src/session-runtime/provider-auth/refresh.mjs +6 -3
  452. package/src/session-runtime/provider-auth/setup.mjs +1 -1
  453. package/src/session-runtime/provider-readiness.mjs +53 -4
  454. package/src/session-runtime/resource-api.mjs +1 -1
  455. package/src/session-runtime/resource-extension-sync.mjs +4 -8
  456. package/src/session-runtime/resource-mcp-api.mjs +98 -35
  457. package/src/session-runtime/resource-mcp-connector-accounts.mjs +49 -32
  458. package/src/session-runtime/resource-mcp-secrets.mjs +27 -10
  459. package/src/session-runtime/resource-mcp-servers.mjs +5 -4
  460. package/src/session-runtime/resource-plugins-api.mjs +4 -0
  461. package/src/session-runtime/routine-executor.mjs +152 -0
  462. package/src/session-runtime/routine-home-turn.mjs +46 -5
  463. package/src/session-runtime/runtime-facade.mjs +5 -0
  464. package/src/session-runtime/runtime-feature-gates.mjs +2 -11
  465. package/src/session-runtime/schedule-session-run.mjs +1 -0
  466. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +6 -1
  467. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +7 -0
  468. package/src/session-runtime/services/agent-tool/send-flow.mjs +120 -8
  469. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +12 -0
  470. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +5 -0
  471. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
  472. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +28 -7
  473. package/src/session-runtime/services/agent-tool.mjs +51 -1
  474. package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
  475. package/src/session-runtime/services/channel-admin.mjs +18 -0
  476. package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
  477. package/src/session-runtime/services/daemon-candidate.mjs +4 -1
  478. package/src/session-runtime/services/hook-bus/command-handler.mjs +7 -11
  479. package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
  480. package/src/session-runtime/services/plugin-admin.mjs +14 -6
  481. package/src/session-runtime/services/provider-admin.mjs +281 -10
  482. package/src/session-runtime/services/seeds.mjs +7 -0
  483. package/src/session-runtime/services/usage-stats-model.mjs +32 -11
  484. package/src/session-runtime/session-create/materialize.mjs +4 -2
  485. package/src/session-runtime/session-create/session-options.mjs +2 -0
  486. package/src/session-runtime/session-turn-api.mjs +2 -0
  487. package/src/session-runtime/settings-builtin-tools-api.mjs +5 -10
  488. package/src/session-runtime/settings-system-api.mjs +1 -1
  489. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
  490. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
  491. package/src/session-runtime/setup-tool/executor.mjs +14 -3
  492. package/src/session-runtime/setup-tool/extended-actions.mjs +2 -0
  493. package/src/session-runtime/setup-tool/settings-contract.mjs +28 -0
  494. package/src/session-runtime/setup-tool/tool-defs.mjs +28 -2
  495. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +40 -43
  496. package/src/session-runtime/tool-policy/mode-switch.mjs +1 -1
  497. package/src/session-runtime/tool-policy/policy-stage.mjs +106 -8
  498. package/src/session-runtime/tool-policy/workflow-overlay.mjs +2 -1
  499. package/src/session-runtime/tool-policy-refresh.mjs +182 -5
  500. package/src/session-runtime/tool-surface.mjs +38 -1
  501. package/src/session-runtime/turn/agent-ops.mjs +33 -2
  502. package/src/session-runtime/turn/session-ops.mjs +2 -0
  503. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +5 -0
  504. package/src/session-runtime/turn/turn-run.mjs +1 -1
  505. package/src/session-runtime/webhook-session-run.mjs +2 -0
  506. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +46 -11
  507. package/src/session-runtime/workflow-agents-api/agent-route.mjs +2 -0
  508. package/src/session-runtime/workflow-agents-api/instruction-files.mjs +165 -0
  509. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +5 -4
  510. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +2 -3
  511. package/src/session-runtime/workflow-agents-api.mjs +2 -0
  512. package/src/session-runtime/workspace/activity-guards.mjs +176 -0
  513. package/src/session-runtime/workspace/project-branches.mjs +1 -1
  514. package/src/session-runtime/workspace/session-view.mjs +149 -0
  515. package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
  516. package/src/session-runtime/workspace/transition-runner.mjs +188 -0
  517. package/src/session-runtime/workspace/transitions.mjs +128 -1070
  518. package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
  519. package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
  520. package/src/session-runtime/workspace/worktree-maintenance.mjs +200 -0
  521. package/src/session-runtime/workspace/worktree-setup.mjs +97 -0
  522. package/src/session-runtime/workspace/worktree-tool.mjs +70 -54
  523. package/src/standalone/daemon-agent-control.mjs +25 -8
  524. package/src/standalone/daemon-desktop-runtime.mjs +8 -2
  525. package/src/standalone/daemon-lag-profiler.mjs +7 -7
  526. package/src/standalone/daemon-session-control.mjs +151 -136
  527. package/src/standalone/daemon.mjs +61 -2
  528. package/src/standalone/desktop-service-registry.mjs +9 -0
  529. package/src/standalone/local-session-runtime.mjs +21 -1
  530. package/src/standalone/session-client/daemon-unavailable.mjs +4 -1
  531. package/src/standalone/session-client.mjs +5 -1
  532. package/src/standalone/session-frame-stream.mjs +83 -11
  533. package/src/standalone/session-protocol.mjs +15 -0
  534. package/src/standalone/session-service/agent-route-follow.mjs +23 -20
  535. package/src/standalone/session-service/agent-tree/agent-turns.mjs +18 -6
  536. package/src/standalone/session-service/agent-tree.mjs +45 -9
  537. package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
  538. package/src/standalone/session-service/quota-resume.mjs +9 -0
  539. package/src/standalone/session-service/session-calls/session-action.mjs +51 -1
  540. package/src/standalone/session-service/session-calls/session-turns.mjs +37 -18
  541. package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
  542. package/src/standalone/session-service/session-calls/turn-gate.mjs +34 -0
  543. package/src/standalone/session-service/session-calls.mjs +2 -1
  544. package/src/standalone/session-service/stored-reader.mjs +127 -40
  545. package/src/tui/App.jsx +162 -164
  546. package/src/tui/app/app-view/floating-panel.jsx +3 -0
  547. package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
  548. package/src/tui/app/clipboard.mjs +22 -11
  549. package/src/tui/app/create-app-pickers.mjs +2 -0
  550. package/src/tui/app/doctor.mjs +2 -2
  551. package/src/tui/app/panel-signature.mjs +1 -1
  552. package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
  553. package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
  554. package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
  555. package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
  556. package/src/tui/app/provider-setup/oauth-actions.mjs +25 -6
  557. package/src/tui/app/provider-setup-picker.mjs +20 -13
  558. package/src/tui/app/settings-picker.mjs +53 -8
  559. package/src/tui/app/shell-layout/row-budgets.mjs +14 -12
  560. package/src/tui/app/slash-commands.mjs +2 -1
  561. package/src/tui/app/slash-dispatch/route-commands.mjs +1 -1
  562. package/src/tui/app/slash-dispatch/session-commands.mjs +47 -1
  563. package/src/tui/app/slash-dispatch.mjs +1 -1
  564. package/src/tui/app/use-btw-panel.mjs +29 -0
  565. package/src/tui/app/use-context-panel-refresh.mjs +31 -0
  566. package/src/tui/app/use-model-catalog-cache.mjs +13 -10
  567. package/src/tui/app/use-mouse-input.mjs +11 -0
  568. package/src/tui/app/use-onboarding-start.mjs +8 -3
  569. package/src/tui/app/use-panel-transition.mjs +10 -1
  570. package/src/tui/app/use-pasted-buffers.mjs +28 -20
  571. package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
  572. package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
  573. package/src/tui/app/use-prompt-queue-history.mjs +5 -4
  574. package/src/tui/app/use-selection-focus.mjs +11 -2
  575. package/src/tui/app/use-selection-geometry.mjs +18 -9
  576. package/src/tui/app/use-selection-paint.mjs +4 -4
  577. package/src/tui/app/use-selection-stitch.mjs +3 -3
  578. package/src/tui/app/use-slash-palette.mjs +62 -0
  579. package/src/tui/app/use-terminal-chrome.mjs +2 -2
  580. package/src/tui/app/use-transcript-activity.mjs +48 -33
  581. package/src/tui/app/use-transcript-follow.mjs +12 -4
  582. package/src/tui/app/use-transcript-scroll.mjs +46 -17
  583. package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
  584. package/src/tui/app/use-transcript-window/geometry.mjs +20 -6
  585. package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
  586. package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
  587. package/src/tui/app/use-transcript-window.mjs +21 -11
  588. package/src/tui/app/use-tui-ready.mjs +18 -0
  589. package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
  590. package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
  591. package/src/tui/components/Picker.jsx +27 -3
  592. package/src/tui/components/SignInUrl.jsx +68 -0
  593. package/src/tui/components/TextEntryPanel.jsx +76 -46
  594. package/src/tui/components/prompt-input/escape-policy.d.mts +0 -1
  595. package/src/tui/components/prompt-input/escape-policy.mjs +1 -1
  596. package/src/tui/components/question-panel-model.mjs +4 -4
  597. package/src/tui/components/sign-in-url-layout.mjs +24 -0
  598. package/src/tui/components/tool-execution/standard-card.jsx +3 -4
  599. package/src/tui/components/user-message-skills.mjs +1 -1
  600. package/src/tui/dist/index.mjs +2205 -1371
  601. package/src/tui/markdown/render-ansi.mjs +1 -1
  602. package/src/tui/session/agent-job-feed/notification-router.mjs +10 -0
  603. package/src/tui/session/agent-job-feed.mjs +2 -0
  604. package/src/tui/session/context-state.mjs +3 -0
  605. package/src/tui/session/goal-turn-state.mjs +6 -2
  606. package/src/tui/session/quota-resume.mjs +1 -1
  607. package/src/tui/session/session-api/controls.mjs +4 -0
  608. package/src/tui/session/session-api/extensions.mjs +8 -0
  609. package/src/tui/session/session-api/intake/abort.mjs +2 -1
  610. package/src/tui/session/session-api/intake.mjs +2 -0
  611. package/src/tui/session/session-api/integrations.mjs +2 -2
  612. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  613. package/src/tui/session/session-api/lifecycle/session-reset.mjs +7 -0
  614. package/src/tui/session/session-api/routes-agent-definitions.mjs +6 -0
  615. package/src/tui/session/session-api/settings.mjs +2 -2
  616. package/src/tui/session/session-api/worktree.mjs +13 -1
  617. package/src/tui/session/session-flow/drain.mjs +11 -14
  618. package/src/tui/session/tool-card-results/grouped-result.mjs +2 -2
  619. package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
  620. package/src/tui/session/transcript-spill.mjs +92 -4
  621. package/src/tui/session/transcript-store.mjs +2 -0
  622. package/src/tui/session/turn-quiet.mjs +1 -1
  623. package/src/tui/session/turn.mjs +3 -0
  624. package/src/tui/session/worktree-setup-notice.mjs +1 -1
  625. package/src/tui/spinner-meta.mjs +3 -3
  626. package/src/tui/spinner-verbs.mjs +2 -2
  627. package/src/defaults/skills/goal-management/SKILL.md +0 -169
  628. package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
  629. package/src/runtime/agent/orchestrator/runtime-core/goal-tasks.mjs +0 -156
  630. package/src/session-runtime/goal-tasks.mjs +0 -1
@@ -4,6 +4,9 @@ import {
4
4
  assertConnectorPolicyNotWidened,
5
5
  CONNECTOR_PERMISSIONS,
6
6
  connectorEnabled,
7
+ connectorGroupId,
8
+ connectorToolEntries,
9
+ connectorToolPermission,
7
10
  DENY_ALL_CONNECTORS,
8
11
  migrateLegacyConnectorPolicy,
9
12
  NO_WIDEN_MESSAGE,
@@ -108,8 +111,8 @@ export function createAgentConnectorsApi(deps, editor) {
108
111
  return getAgentConnectors(agentId);
109
112
  }
110
113
 
111
- // Older per-tool overrides keep working (the profile no longer shows them):
112
- // `permission` null drops the tool's entry, so the tool is auto again.
114
+ // One tool's permission (the profile's tool list, getAgentConnectorTools):
115
+ // `permission` null drops the tool's entry, so the tool is on its default again.
113
116
  async function setAgentConnectorToolPermission(agentId, connectorId, toolName, permission, options) {
114
117
  if (permission != null && !CONNECTOR_PERMISSIONS.includes(permission)) {
115
118
  throw new Error(`permission must be one of ${CONNECTOR_PERMISSIONS.join(', ')}`);
@@ -117,19 +120,25 @@ export function createAgentConnectorsApi(deps, editor) {
117
120
  const server = requireId(connectorId, 'connector id');
118
121
  const tool = requireId(toolName, 'tool name');
119
122
  const policy = editablePolicy(agentId);
120
- const own = { ...policy.tools[server] };
123
+ // The accounts of one connector (`gmail`, `gmail-2`…) share the permission,
124
+ // stored once under the connector's id; an entry an account kept of its own
125
+ // for this tool goes in the same write.
126
+ const group = connectorGroupId(server);
127
+ const tools = Object.fromEntries(
128
+ Object.entries(policy.tools).map(([id, entries]) => {
129
+ if (id === group || connectorGroupId(id) !== group) return [id, entries];
130
+ const { [tool]: _dropped, ...rest } = entries;
131
+ return [id, rest];
132
+ })
133
+ );
134
+ const own = { ...tools[group] };
121
135
  if (permission == null) delete own[tool];
122
136
  else own[tool] = permission;
137
+ tools[group] = own;
123
138
  if (options?.noWiden) {
124
- assertConnectorPolicyNotWidened(editor.getAgentConnectorPolicy(agentId), {
125
- off: policy.off,
126
- tools: { ...policy.tools, [server]: own },
127
- });
139
+ assertConnectorPolicyNotWidened(editor.getAgentConnectorPolicy(agentId), { off: policy.off, tools });
128
140
  }
129
- return editor.setAgentConnectorPolicy(
130
- agentId,
131
- storedConnectorPolicy({ off: policy.off, tools: { ...policy.tools, [server]: own } })
132
- );
141
+ return editor.setAgentConnectorPolicy(agentId, storedConnectorPolicy({ off: policy.off, tools }));
133
142
  }
134
143
 
135
144
  // A card's "항상 허용" for a connector tool saves through this same writer.
@@ -149,6 +158,31 @@ export function createAgentConnectorsApi(deps, editor) {
149
158
  .sort((a, b) => a.connector.localeCompare(b.connector) || a.tool.localeCompare(b.tool));
150
159
  }
151
160
 
161
+ /** `[{ connector, tool, permission, explicit }]`: each installed connector's
162
+ * tools (the connected server's own, and any the agent's policy names) with
163
+ * the permission the agent has for the tool itself, so a connector switched
164
+ * off does not change it, and whether that is an entry of its own policy
165
+ * rather than the tool's default. The profile's per-tool editor reads it. */
166
+ function getAgentConnectorTools(agentId) {
167
+ const { tools } = editablePolicy(agentId);
168
+ return installedIds().flatMap((connector) => {
169
+ const group = connectorGroupId(connector);
170
+ const accounts = Object.entries(tools).filter(([id]) => connectorGroupId(id) === group);
171
+ const names = new Set([
172
+ ...listConnectorTools(connector).map(({ name }) => name),
173
+ ...accounts.flatMap(([, entries]) => Object.keys(entries)),
174
+ ]);
175
+ // Accounts share one permission (stored under the connector); entries an
176
+ // account kept of its own follow the topmost.
177
+ return [...names].map((tool) => ({
178
+ connector,
179
+ tool,
180
+ permission: connectorToolPermission({ off: [], tools }, { mcpServerName: connector, mcpToolName: tool }),
181
+ explicit: connectorToolEntries(tools, group, tool).length > 0,
182
+ }));
183
+ });
184
+ }
185
+
152
186
  /** Replace the agent's connector policy (null removes it). With `options.noWiden`
153
187
  * the replacement may not give any tool more authority than the stored policy. */
154
188
  async function setAgentConnectors(agentId, connectors, options) {
@@ -279,6 +313,7 @@ export function createAgentConnectorsApi(deps, editor) {
279
313
  setAgentConnectorEnabled,
280
314
  setAgentConnectorToolPermission,
281
315
  getAgentAlwaysAllowedTools,
316
+ getAgentConnectorTools,
282
317
  getProjectConnectors,
283
318
  setProjectConnectorEnabled,
284
319
  migrateConnectorPolicies,
@@ -226,5 +226,7 @@ export function createAgentRouteApi(deps) {
226
226
  return stayOff ? { ...routeToSave, id, disabled: true } : routeToSave;
227
227
  }
228
228
 
229
+ // Explore's route decides whether the explore tool exists; sessions take a
230
+ // change of it at their next turn start (reconcileTurnSettings).
229
231
  return { setAgentRoute };
230
232
  }
@@ -0,0 +1,165 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync, mkdirSync, rmSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { writeFileAtomicSync } from '../../runtime/shared/atomic-file.mjs';
5
+ import { normalizeText } from '../../runtime/shared/shipped-definitions.mjs';
6
+ import { decodeInstructionFile, INSTRUCTION_FILE_MAX_BYTES } from '../../lib/instruction-text.cjs';
7
+ import { outputStyleMetaFromMarkdown } from '../../lib/output-style-meta.cjs';
8
+ import {
9
+ readInstructionFile,
10
+ shippedOrchestrationPath,
11
+ userOrchestrationPath,
12
+ } from '../../runtime/agent/orchestrator/runtime-core/orchestration.mjs';
13
+ import { ORCHESTRATION_MODES } from '../../runtime/shared/orchestration.mjs';
14
+ import { publishAgentProfileChange } from '../agent-profile-changes.mjs';
15
+ import { STANDALONE_ROOT } from '../runtime-paths.mjs';
16
+ import { resolveDataDir } from './shared.mjs';
17
+
18
+ // The editable instruction texts: the four orchestration modes (delegation)
19
+ // and the four output-style depth levels. Each has a shipped .md file and a
20
+ // same-name user file in the data dir that replaces it; the set is fixed.
21
+ export const INSTRUCTION_FILE_CONFLICT = 'INSTRUCTION_FILE_CONFLICT';
22
+
23
+ const MODE_LABELS = { none: 'Solo', focused: 'Focused', balanced: 'Balanced', swarm: 'Swarm' };
24
+ const STYLES = [
25
+ ['detailed', 'Detailed'],
26
+ ['simple', 'Simple'],
27
+ ['minimal', 'Minimal'],
28
+ ['extreme-minimal', 'Extreme Minimal'],
29
+ ];
30
+ const INSTRUCTION_GROUPS = Object.freeze(['delegation', 'outputStyle']);
31
+
32
+ const FRONTMATTER = /^---[ \t]*\r?\n[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/;
33
+ const bodyOfStyle = (text) =>
34
+ String(text || '')
35
+ .replace(FRONTMATTER, '')
36
+ .trim();
37
+ const hashOf = (text) => createHash('sha256').update(String(text)).digest('hex').slice(0, 24);
38
+
39
+ // One item's files and the text <-> file mapping. The style editor shows and
40
+ // saves the file's body only: the shipped front matter (name, title,
41
+ // description) is kept, and common.md is not part of it.
42
+ function itemFor(group, id, deps) {
43
+ if (group === 'delegation') {
44
+ if (!ORCHESTRATION_MODES.includes(id))
45
+ throw new Error(`orchestration mode must be one of ${ORCHESTRATION_MODES.join(', ')}`);
46
+ return {
47
+ group,
48
+ id,
49
+ label: MODE_LABELS[id],
50
+ shipped: shippedOrchestrationPath(id),
51
+ user: userOrchestrationPath(id),
52
+ body: (text) => text,
53
+ file: (body) => `${body}\n`,
54
+ accepts: () => true,
55
+ };
56
+ }
57
+ if (group === 'outputStyle') {
58
+ const style = STYLES.find(([styleId]) => styleId === id);
59
+ if (!style) throw new Error(`output style must be one of ${STYLES.map(([styleId]) => styleId).join(', ')}`);
60
+ const shipped = join(deps.rootDir ?? STANDALONE_ROOT, 'output-styles', `${id}.md`);
61
+ return {
62
+ group,
63
+ id,
64
+ label: style[1],
65
+ shipped,
66
+ user: join(resolveDataDir(deps), 'output-styles', `${id}.md`),
67
+ body: bodyOfStyle,
68
+ file: (body, shippedText) => `${(FRONTMATTER.exec(shippedText) || [''])[0].trimEnd()}\n\n${body}\n`,
69
+ // A file whose front matter names another style defines that one instead
70
+ // (the prompt builder registers it by name): it does not replace this one.
71
+ accepts: (text) => outputStyleMetaFromMarkdown(text, `${id}.md`)?.id === id,
72
+ };
73
+ }
74
+ throw new Error(`instruction group must be one of ${INSTRUCTION_GROUPS.join(', ')}`);
75
+ }
76
+
77
+ export function createInstructionFilesApi(deps) {
78
+ function stateOf(item) {
79
+ const shipped = readInstructionFile(item.shipped);
80
+ const defaultBody = item.body(shipped?.text ?? '');
81
+ const user = readInstructionFile(item.user);
82
+ const accepted = Boolean(user?.text) && item.accepts(user.text);
83
+ const userBody = accepted ? item.body(user.text) : '';
84
+ // An existing user file that cannot serve (empty, too large, not text, a
85
+ // style under another name) is passed over by the prompt builders: the
86
+ // built-in applies.
87
+ const usable = Boolean(userBody);
88
+ const problem = user && !usable ? (user.problem ?? (accepted ? 'empty' : 'invalid')) : undefined;
89
+ const body = usable ? userBody : defaultBody;
90
+ return {
91
+ group: item.group,
92
+ id: item.id,
93
+ label: item.label,
94
+ body,
95
+ defaultBody,
96
+ userOverride: Boolean(user),
97
+ modified: usable && normalizeText(userBody) !== normalizeText(defaultBody),
98
+ ...(problem ? { problem } : {}),
99
+ ...(user ? { path: item.user } : {}),
100
+ revision: hashOf(`${usable ? 'user' : 'default'}\0${problem ?? ''}\0${body}`),
101
+ };
102
+ }
103
+
104
+ // A write or reset made against a state that has moved on is refused.
105
+ function assertCurrent(payloadRevision, before, item) {
106
+ if (payloadRevision === undefined || String(payloadRevision) === before.revision) return;
107
+ const conflict = new Error(`${INSTRUCTION_FILE_CONFLICT}: "${item.id}" changed since it was loaded`);
108
+ conflict.code = INSTRUCTION_FILE_CONFLICT;
109
+ throw conflict;
110
+ }
111
+
112
+ const get = (group, id) => stateOf(itemFor(group, id, deps));
113
+
114
+ function list() {
115
+ return [...ORCHESTRATION_MODES.map((id) => get('delegation', id)), ...STYLES.map(([id]) => get('outputStyle', id))];
116
+ }
117
+
118
+ async function announce() {
119
+ deps.invalidateContextStatusCache?.();
120
+ await publishAgentProfileChange();
121
+ }
122
+
123
+ async function save(payload = {}) {
124
+ const item = itemFor(payload.group, payload.id, deps);
125
+ const body = String(payload.body ?? '')
126
+ .replace(/\r\n/g, '\n')
127
+ .trim();
128
+ if (!body) throw new Error('instruction text must not be empty');
129
+ if (body.includes('\0')) throw new Error('instruction text must be plain text');
130
+ const before = stateOf(item);
131
+ assertCurrent(payload.expectedRevision, before, item);
132
+ if (normalizeText(body) === normalizeText(before.defaultBody)) {
133
+ // Equal to the shipped text: keep no copy, so it follows the shipped version.
134
+ rmSync(item.user, { force: true });
135
+ } else {
136
+ // The bytes that reach the disk — front matter and newline included —
137
+ // must pass the reader's check, or the saved file would be ignored.
138
+ const bytes = Buffer.from(item.file(body, readInstructionFile(item.shipped)?.text ?? ''));
139
+ if (bytes.length > INSTRUCTION_FILE_MAX_BYTES) throw new Error('instruction text is larger than 256 KB');
140
+ const problem = decodeInstructionFile(bytes).problem;
141
+ if (problem) throw new Error(`instruction text cannot be saved (${problem})`);
142
+ mkdirSync(dirname(item.user), { recursive: true });
143
+ writeFileAtomicSync(item.user, bytes, { backup: true, mode: 0o644 });
144
+ }
145
+ await announce();
146
+ return stateOf(item);
147
+ }
148
+
149
+ async function reset(group, id, expectedRevision) {
150
+ const item = itemFor(group, id, deps);
151
+ if (!existsSync(item.user)) throw new Error(`"${item.id}" has no user override to reset`);
152
+ assertCurrent(expectedRevision, stateOf(item), item);
153
+ rmSync(item.user, { force: true });
154
+ rmSync(`${item.user}.bak`, { force: true });
155
+ await announce();
156
+ return stateOf(item);
157
+ }
158
+
159
+ return {
160
+ listInstructionFiles: list,
161
+ getInstructionFile: get,
162
+ saveInstructionFile: save,
163
+ resetInstructionFile: reset,
164
+ };
165
+ }
@@ -30,7 +30,9 @@ export function createStyleAndModeApi(deps) {
30
30
  scheduleOutputStyleSave(selected.id);
31
31
  const freshStatus = { configured: selected.id, current: selected, styles: before.styles };
32
32
  seedOutputStyleStatusCache(freshStatus);
33
- const appliedToCurrentSession = !getSession()?.id;
33
+ // An empty session is rebuilt at its next turn start; a conversation is
34
+ // told then and folds the style in at its next cold point.
35
+ const appliedToCurrentSession = deps.settingsReachCurrentSession?.() ?? !getSession()?.id;
34
36
  invalidateContextStatusCache();
35
37
  return { ...freshStatus, appliedToCurrentSession };
36
38
  }
@@ -53,10 +55,9 @@ export function createStyleAndModeApi(deps) {
53
55
  }
54
56
  }
55
57
  saveConfigAndAdopt({ ...getConfig(), orchestrationMode: mode });
56
- const applied = await deps.refreshEmptySessionToolPolicy?.();
57
- deps.invalidatePreSessionToolSurface?.();
58
+ // An empty session takes it at its next turn start (reconcileTurnSettings).
58
59
  invalidateContextStatusCache();
59
- return { mode, appliedToCurrentSession: applied?.appliedToCurrentSession !== false };
60
+ return { mode, appliedToCurrentSession: deps.settingsReachCurrentSession?.() !== false };
60
61
  }
61
62
 
62
63
  return {
@@ -66,9 +66,8 @@ export function createWorkflowPacksApi(deps) {
66
66
  if (switched) return { ...switched.workflow, ...switched };
67
67
  }
68
68
  saveActiveWorkflow(id);
69
- const applied = await deps.refreshEmptySessionToolPolicy?.();
70
- deps.invalidatePreSessionToolSurface?.();
71
- return { ...workflowSummary(pack), appliedToCurrentSession: applied?.appliedToCurrentSession !== false };
69
+ // An empty session takes it at its next turn start (reconcileTurnSettings).
70
+ return { ...workflowSummary(pack), appliedToCurrentSession: deps.settingsReachCurrentSession?.() !== false };
72
71
  }
73
72
 
74
73
  function getWorkflowPack(workflowId) {
@@ -4,6 +4,7 @@ import { createAgentConnectorsApi } from './workflow-agents-api/agent-connectors
4
4
  import { createAgentRouteApi } from './workflow-agents-api/agent-route.mjs';
5
5
  import { createWorkflowPacksApi } from './workflow-agents-api/workflow-packs.mjs';
6
6
  import { createStyleAndModeApi } from './workflow-agents-api/style-and-mode.mjs';
7
+ import { createInstructionFilesApi } from './workflow-agents-api/instruction-files.mjs';
7
8
 
8
9
  // Onboarding + agents/workflows/output-style selection surface. Stateless
9
10
  // helpers are imported by the phase modules under workflow-agents-api/; the
@@ -20,5 +21,6 @@ export function createWorkflowAgentsApi(deps) {
20
21
  ...routeApi,
21
22
  ...createWorkflowPacksApi(deps),
22
23
  ...createStyleAndModeApi(deps),
24
+ ...createInstructionFilesApi(deps),
23
25
  };
24
26
  }
@@ -0,0 +1,176 @@
1
+ /**
2
+ * The activity checks every workspace change runs first: whether the hosted
3
+ * Lead (its turn, workers and background shells) is idle, and whether other
4
+ * sessions work in a shared checkout — then holding that checkout so new
5
+ * turns there wait until the change settles (admission gate).
6
+ */
7
+ import { worktreeError, worktreeRefusal } from '../../runtime/shared/worktrees/contract.mjs';
8
+ import { isWithin } from '../../runtime/shared/worktrees/paths.mjs';
9
+ import {
10
+ holdWorkspaceActivity,
11
+ isExternalCheckout,
12
+ releaseAll,
13
+ } from '../../runtime/shared/worktrees/activity-gate.mjs';
14
+ import { AGENT_OWNER } from '../../runtime/agent/orchestrator/agent-owner.mjs';
15
+ import { holdCheckoutFolder } from './admission-gate.mjs';
16
+
17
+ const ACTIVE_STAGES = new Set(['connecting', 'requesting', 'streaming', 'tool_running', 'running', 'cancelling']);
18
+ const BUSY_WORKER_STATES = new Set([...ACTIVE_STAGES, 'starting', 'spawning', 'queued', 'pending']);
19
+ const BUSY_JOB_STATES = new Set(['starting', 'spawning', 'queued', 'pending', 'running']);
20
+
21
+ const lower = (value) => String(value || '').toLowerCase();
22
+
23
+ /** @param {object} deps The activity sources of createWorkspaceTransitions. */
24
+ export function createActivityGuards({
25
+ getActiveTurnCount,
26
+ agentStatusState,
27
+ countOwnShellJobs,
28
+ listLiveSessions,
29
+ sessionManager,
30
+ listWorkspaceConsumers,
31
+ listWorkspaceJobs,
32
+ }) {
33
+ function isSessionActive(session) {
34
+ const runtime = sessionManager?.getSessionRuntime?.(session.id);
35
+ if (runtime?.controller?.signal && !runtime.controller.signal.aborted) return true;
36
+ return ACTIVE_STAGES.has(lower(runtime?.stage || session.status));
37
+ }
38
+
39
+ const workersOf = (session) =>
40
+ listLiveSessions().filter(
41
+ (candidate) =>
42
+ candidate?.id &&
43
+ candidate.id !== session.id &&
44
+ candidate.owner === AGENT_OWNER &&
45
+ candidate.closed !== true &&
46
+ (candidate.ownerSessionId === session.id || candidate.parentSessionId === session.id)
47
+ );
48
+
49
+ /**
50
+ * WORKTREE_BUSY_JOBS while this Lead has a turn, workers or background
51
+ * shells running (`shellJobs: false` tolerates background shells).
52
+ */
53
+ async function assertLeadIdle(session, { ownTurn = false, shellJobs: checkShellJobs = true } = {}) {
54
+ if (!ownTurn && getActiveTurnCount() > 0) {
55
+ throw worktreeError('WORKTREE_BUSY_JOBS', 'The session is running a turn; wait for it to finish.', {
56
+ reason: 'turn',
57
+ });
58
+ }
59
+ const status = agentStatusState?.() || {};
60
+ const workers = Array.isArray(status.agentWorkers) ? status.agentWorkers : [];
61
+ const jobs = Array.isArray(status.agentJobs) ? status.agentJobs : [];
62
+ const busyWorkers = workers.filter(
63
+ (row) => BUSY_WORKER_STATES.has(lower(row?.status)) || BUSY_WORKER_STATES.has(lower(row?.stage))
64
+ ).length;
65
+ const busyJobs = jobs.filter((row) => BUSY_JOB_STATES.has(lower(row?.status))).length;
66
+ if (busyWorkers || busyJobs) {
67
+ throw worktreeError('WORKTREE_BUSY_JOBS', undefined, { reason: 'workers', workers: busyWorkers, jobs: busyJobs });
68
+ }
69
+ if (!checkShellJobs) return;
70
+ const ids = new Set([session.id, ...workers.map((row) => row?.sessionId).filter(Boolean)]);
71
+ for (const worker of workersOf(session)) ids.add(worker.id);
72
+ const shellJobs = await countOwnShellJobs([...ids]);
73
+ if (shellJobs > 0) throw worktreeError('WORKTREE_BUSY_JOBS', undefined, { reason: 'shell-jobs', shellJobs });
74
+ }
75
+
76
+ /**
77
+ * A checkout or merge in the shared checkout `folder` refuses while another
78
+ * session (not this Lead's own workers) works there, then holds the folder
79
+ * until the returned release: other sessions' turns that arrive meanwhile
80
+ * wait (admission gate). `sessionId` null: a session-less (draft) change.
81
+ * @returns {() => void}
82
+ */
83
+ function holdProjectFolder(sessionId, folder, { hold = true } = {}) {
84
+ const users = listLiveSessions().filter(
85
+ (candidate) =>
86
+ candidate?.id &&
87
+ candidate.id !== sessionId &&
88
+ candidate.closed !== true &&
89
+ (!sessionId || (candidate.ownerSessionId !== sessionId && candidate.parentSessionId !== sessionId)) &&
90
+ typeof candidate.cwd === 'string' &&
91
+ isWithin(folder, candidate.cwd) &&
92
+ isSessionActive(candidate)
93
+ );
94
+ if (users.length) throw worktreeRefusal('folder-in-use', { sessions: users.map((candidate) => candidate.id) });
95
+ return holdCheckoutFolder(sessionId, folder, { hold });
96
+ }
97
+
98
+ /** Run `fn` holding the checkout `folder` (holdProjectFolder); released when it settles. */
99
+ async function withProjectFolder(sessionId, folder, fn) {
100
+ const release = holdProjectFolder(sessionId, folder);
101
+ try {
102
+ return await fn();
103
+ } finally {
104
+ release();
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Before a carry clears the shared checkout `folder` (held by the caller,
110
+ * so no new turn starts there): WORKTREE_BUSY_JOBS while any other session
111
+ * working in it — idle or not, this Lead's workers included — owns a
112
+ * running background shell (holdProjectFolder already refused running
113
+ * turns and agents there, assertLeadIdle this Lead's own). Processes
114
+ * outside Mixdog (editors, watchers) cannot be excluded.
115
+ */
116
+ async function assertCheckoutQuiet(session, folder) {
117
+ const sharing = listLiveSessions()
118
+ .filter(
119
+ (candidate) =>
120
+ candidate?.id &&
121
+ candidate.id !== session.id &&
122
+ candidate.closed !== true &&
123
+ typeof candidate.cwd === 'string' &&
124
+ isWithin(folder, candidate.cwd)
125
+ )
126
+ .map((candidate) => candidate.id);
127
+ if (!sharing.length) return;
128
+ const shellJobs = await countOwnShellJobs(sharing);
129
+ if (shellJobs > 0) throw worktreeRefusal('folder-shell-jobs', { shellJobs });
130
+ }
131
+
132
+ /**
133
+ * The shared admission of every merge and folder cleanup (manageProjectBranch):
134
+ * refuses while a session or worker runs in an affected folder, or a
135
+ * background command does; `removing` refuses while any session still uses
136
+ * one. Then holds the folders — Mixdog checkouts only; an external checkout
137
+ * takes no lease from this profile — so new Mixdog work there waits until `run`
138
+ * settles. `actor`: the session acting on its own checkout, whose own turn
139
+ * and workers its caller already checked (assertLeadIdle).
140
+ */
141
+ async function withManagementFolders(folders, removing, run, { actor = null } = {}) {
142
+ const release = [];
143
+ try {
144
+ for (const folder of [...new Set(folders)].sort()) {
145
+ release.push(holdProjectFolder(actor, folder, { hold: !isExternalCheckout(folder) }));
146
+ }
147
+ release.push(holdWorkspaceActivity(folders, { sessionId: actor }));
148
+ const stored = await listWorkspaceConsumers();
149
+ const consumers = new Map(stored.map((session) => [session.id, session]));
150
+ for (const session of listLiveSessions()) if (session?.closed !== true) consumers.set(session.id, session);
151
+ const affected = [...consumers.values()].filter((session) =>
152
+ folders.some((folder) => session.cwd && isWithin(folder, session.cwd))
153
+ );
154
+ const blocking = removing
155
+ ? affected
156
+ : affected.filter(
157
+ (session) =>
158
+ !(actor && [session.id, session.ownerSessionId, session.parentSessionId].includes(actor)) &&
159
+ isSessionActive(session)
160
+ );
161
+ if (blocking.length) throw worktreeRefusal('folder-in-use', { sessions: blocking.map((session) => session.id) });
162
+ const jobs = await listWorkspaceJobs();
163
+ if (jobs.some((job) => !job.terminal && folders.some((folder) => isWithin(folder, job.cwd)))) {
164
+ throw worktreeRefusal('folder-shell-jobs');
165
+ }
166
+ if ((await countOwnShellJobs(affected.map((session) => session.id))) > 0) {
167
+ throw worktreeRefusal('folder-shell-jobs');
168
+ }
169
+ return await run([...consumers.keys()]);
170
+ } finally {
171
+ releaseAll(release);
172
+ }
173
+ }
174
+
175
+ return { workersOf, assertLeadIdle, withProjectFolder, assertCheckoutQuiet, withManagementFolders };
176
+ }
@@ -52,7 +52,7 @@ export function createProjectBranchOps({
52
52
  return {
53
53
  // Detached: branch null and the checked-out commit in baseCommit.
54
54
  workspace: project.currentBranch ? workspace : { ...workspace, baseCommit: project.headCommit ?? null },
55
- branches: branchMenuEntries(menu.branches, menu.occupancy),
55
+ branches: branchMenuEntries(menu.branches, menu.occupancy, menu.committedAt),
56
56
  occupancy: menu.occupancy,
57
57
  retainedWorktree: null,
58
58
  };
@@ -0,0 +1,149 @@
1
+ /**
2
+ * The hosted Lead's workspace as the transitions read it: the session this
3
+ * runtime hosts, its stored (or project-folder) workspace record, the live
4
+ * view the session snapshot publishes and the branch menu.
5
+ */
6
+ import { isDeepStrictEqual } from 'node:util';
7
+ import {
8
+ branchMenuEntries,
9
+ isWorktreeBound,
10
+ normalizeSessionWorkspace,
11
+ worktreeError,
12
+ } from '../../runtime/shared/worktrees/contract.mjs';
13
+ import { samePath } from '../../runtime/shared/worktrees/paths.mjs';
14
+ import { readGitHead } from '../../runtime/shared/worktrees/git-head.mjs';
15
+ import { readSessionWorkspace } from './workspace-state.mjs';
16
+
17
+ /**
18
+ * @param {object} deps The host hooks of createWorkspaceTransitions plus its
19
+ * `backend()` loader and `pendingWorktree()` (the armed worktree intent).
20
+ */
21
+ export function createSessionWorkspaceView({
22
+ getSession,
23
+ getCurrentCwd,
24
+ getDesktopSession,
25
+ createCurrentSession,
26
+ inspectProject,
27
+ backend,
28
+ pendingWorktree,
29
+ }) {
30
+ function hostedSession(sessionRef) {
31
+ const session = getSession();
32
+ const requested = String(sessionRef?.sessionId || '').trim();
33
+ if (!session?.id || (requested && requested !== session.id)) {
34
+ throw new Error(`workspace: session ${requested || '(none)'} is not hosted by this runtime.`);
35
+ }
36
+ return session;
37
+ }
38
+
39
+ async function ensureSession() {
40
+ if (!getSession()?.id && typeof createCurrentSession === 'function') await createCurrentSession('workspace');
41
+ return hostedSession(null);
42
+ }
43
+
44
+ function projectPathOf(session) {
45
+ const desktop = getDesktopSession?.() || session?.desktopSession;
46
+ if (desktop?.classification === 'project' && desktop.projectPath) return desktop.projectPath;
47
+ return session?.cwd || getCurrentCwd();
48
+ }
49
+
50
+ /** The stored record, or the project-folder workspace (revision 0) of a session that never moved. */
51
+ function currentWorkspace(session) {
52
+ const stored = readSessionWorkspace(session);
53
+ if (stored) return stored;
54
+ const projectPath = projectPathOf(session);
55
+ return normalizeSessionWorkspace({ projectPath, cwd: getCurrentCwd() || projectPath, revision: 0 });
56
+ }
57
+
58
+ let liveWorkspace = null;
59
+
60
+ /**
61
+ * The workspace the session publishes: a worktree-bound record as stored; a
62
+ * project-folder session (never moved, back from a worktree, or carrying a
63
+ * transition stub) with the folder's checked-out branch / detached commit and
64
+ * repoCommonDir read straight from HEAD — no git process. Null outside a git
65
+ * repository for a session without a record. Identity-stable while equal.
66
+ */
67
+ function getLiveWorkspace() {
68
+ const session = getSession();
69
+ const stored = readSessionWorkspace(session);
70
+ if (isWorktreeBound(stored)) return session.workspace;
71
+ let base;
72
+ try {
73
+ base = stored ?? currentWorkspace(session);
74
+ } catch {
75
+ return session?.workspace ?? null;
76
+ }
77
+ const head = readGitHead(base.cwd);
78
+ if (!head) return session?.workspace ?? null;
79
+ const next = {
80
+ ...base,
81
+ repoCommonDir: head.repoCommonDir,
82
+ branch: head.branch,
83
+ baseCommit: head.branch ? base.baseCommit : head.commit,
84
+ };
85
+ if (!liveWorkspace || !isDeepStrictEqual(liveWorkspace, next)) liveWorkspace = next;
86
+ return liveWorkspace;
87
+ }
88
+
89
+ /** WORKTREE_PROJECT_MISMATCH unless `repoCommonDir` (when given) is the session Project's repository. */
90
+ async function sessionProject(session, repoCommonDir) {
91
+ const workspace = currentWorkspace(session);
92
+ const project = await inspectProject(workspace.projectPath);
93
+ if (repoCommonDir && !samePath(repoCommonDir, project.repoCommonDir)) {
94
+ throw worktreeError(
95
+ 'WORKTREE_PROJECT_MISMATCH',
96
+ "Managed worktrees belong to this session's Project repository; run the command there.",
97
+ { projectPath: workspace.projectPath, repoCommonDir }
98
+ );
99
+ }
100
+ return { workspace, project };
101
+ }
102
+
103
+ async function getBranchMenu() {
104
+ const session = getSession();
105
+ const workspace = session?.id
106
+ ? currentWorkspace(session)
107
+ : normalizeSessionWorkspace({ projectPath: projectPathOf(null), cwd: getCurrentCwd(), revision: 0 });
108
+ const menu = await (await backend()).listBranchOccupancy({
109
+ projectPath: workspace.projectPath,
110
+ sessionId: session?.id || null,
111
+ });
112
+ const selectedEntry = workspace.worktreeId ? await (await backend()).findWorktreeContaining(workspace.cwd) : null;
113
+ // A session outside a managed worktree (the project folder — never moved,
114
+ // or back from a worktree — or a linked checkout of the selected branch)
115
+ // is on whatever that folder has checked out now.
116
+ // Its repository is the project's (a never-moved session has no stored
117
+ // record), and a detached checkout shows branch null with the commit in
118
+ // baseCommit — never mistaken for "not a repository".
119
+ let view = workspace;
120
+ if (!isWorktreeBound(workspace)) {
121
+ const project = await inspectProject(workspace.cwd);
122
+ const checkedOut = project.currentBranch ?? null;
123
+ view = {
124
+ ...workspace,
125
+ repoCommonDir: project.repoCommonDir ?? workspace.repoCommonDir,
126
+ branch: checkedOut,
127
+ baseCommit: checkedOut ? workspace.baseCommit : (project.headCommit ?? null),
128
+ };
129
+ }
130
+ return {
131
+ workspace: view,
132
+ pendingWorktree: pendingWorktree(),
133
+ branches: branchMenuEntries(menu.branches, menu.occupancy, menu.committedAt),
134
+ occupancy: menu.occupancy,
135
+ retainedWorktree: selectedEntry ?? menu.retainedWorktree ?? null,
136
+ // Creation notes of the retained worktree (submodules, include entries).
137
+ warnings: Array.isArray(menu.retainedWorktree?.warnings) ? [...menu.retainedWorktree.warnings] : [],
138
+ };
139
+ }
140
+
141
+ return {
142
+ hostedSession,
143
+ ensureSession,
144
+ currentWorkspace,
145
+ getLiveWorkspace,
146
+ sessionProject,
147
+ getBranchMenu,
148
+ };
149
+ }