mixdog 1.4.1 → 1.4.2

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 (326) hide show
  1. package/package.json +3 -2
  2. package/scripts/build-shipped-history.mjs +115 -33
  3. package/scripts/gate-local.mjs +172 -61
  4. package/scripts/lib/gate-scheduler.mjs +138 -32
  5. package/scripts/lib/gate-timing-reporter.mjs +16 -0
  6. package/scripts/lib/run-node-tests.mjs +54 -29
  7. package/scripts/lib/scoped-temp.mjs +1 -0
  8. package/scripts/lib/test-failure-records.mjs +14 -1
  9. package/scripts/lib/test-failure-summary.mjs +16 -4
  10. package/scripts/lib/test-spawn-ledger.mjs +12 -3
  11. package/scripts/pptx-kit-index.mjs +5 -6
  12. package/scripts/suite-health.mjs +110 -28
  13. package/scripts/test.mjs +9 -14
  14. package/src/agents/advisor/AGENT.md +4 -4
  15. package/src/agents/advisor/agent.json +1 -1
  16. package/src/agents/explore/AGENT.md +22 -0
  17. package/src/agents/explore/agent.json +6 -0
  18. package/src/cli.mjs +7 -0
  19. package/src/defaults/agents.json +7 -0
  20. package/src/defaults/shipped-history.json +18 -2
  21. package/src/defaults/skills/browser-use/SKILL.md +4 -1
  22. package/src/defaults/skills/code-tidy/SKILL.md +71 -102
  23. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
  24. package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
  25. package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
  26. package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
  27. package/src/defaults/skills/computer-use/SKILL.md +12 -2
  28. package/src/defaults/skills/goal-management/SKILL.md +1 -1
  29. package/src/defaults/skills/setup/references/actions.md +12 -6
  30. package/src/defaults/skills/setup/references/surfaces.md +2 -2
  31. package/src/defaults/skills/setup-guide/SKILL.md +5 -2
  32. package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
  33. package/src/defaults/skills/skill-creator/SKILL.md +85 -190
  34. package/src/defaults/skills/skill-creator/references/design.md +70 -162
  35. package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
  36. package/src/defaults/skills/test-suite/SKILL.md +194 -0
  37. package/src/defaults/skills/test-suite/references/case-management.md +51 -0
  38. package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
  39. package/src/defaults/skills/test-suite/references/reliability.md +49 -0
  40. package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
  41. package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
  42. package/src/defaults/skills/visualize/SKILL.md +6 -2
  43. package/src/lib/rules-builder.cjs +6 -30
  44. package/src/rules/lead/LEAD.md +3 -3
  45. package/src/rules/shared/20-research.md +3 -6
  46. package/src/rules/shared/40-editing.md +1 -0
  47. package/src/rules/shared/60-verification.md +10 -9
  48. package/src/rules/shared/70-delivery.md +4 -3
  49. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
  50. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
  51. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +130 -21
  52. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
  53. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
  54. package/src/runtime/agent/orchestrator/config.mjs +12 -7
  55. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +7 -7
  56. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
  57. package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
  58. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
  59. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
  60. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
  61. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
  62. package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
  63. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +83 -52
  64. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
  65. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +43 -8
  66. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +30 -28
  67. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
  69. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
  70. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
  71. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  72. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
  73. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
  74. package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
  75. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
  76. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
  77. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
  78. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
  79. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
  80. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +48 -31
  81. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
  82. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
  83. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
  84. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
  85. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
  86. package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +26 -28
  88. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +3 -1
  89. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +1 -0
  90. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
  92. package/src/runtime/agent/orchestrator/providers/registry.mjs +33 -2
  93. package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
  94. package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
  95. package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
  96. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
  97. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  98. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +2 -1
  99. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  100. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -0
  101. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
  102. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
  103. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
  104. package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
  105. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +94 -10
  106. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +3 -3
  107. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +10 -5
  108. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +5 -5
  109. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +11 -1
  110. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
  111. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
  112. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +5 -3
  113. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +21 -2
  114. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
  115. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
  116. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
  117. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
  118. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
  119. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +3 -4
  120. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +2 -0
  121. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
  122. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
  123. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +25 -14
  124. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +17 -14
  125. package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
  126. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
  127. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -3
  128. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +47 -29
  129. package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
  130. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
  131. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +1 -1
  132. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +243 -38
  133. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
  134. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
  135. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
  136. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
  137. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +36 -26
  138. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +3 -5
  139. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
  141. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
  142. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
  143. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  144. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
  145. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
  146. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
  147. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
  148. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
  149. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
  150. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
  151. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
  153. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
  154. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  155. package/src/runtime/channels/lib/whisper-port.mjs +19 -10
  156. package/src/runtime/channels/lib/whisper-server.mjs +10 -1
  157. package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
  158. package/src/runtime/connectors/gmail-app-password.mjs +3 -3
  159. package/src/runtime/explore/explorer.mjs +93 -0
  160. package/src/runtime/explore/tool-defs.mjs +35 -0
  161. package/src/runtime/explore/tool.mjs +123 -0
  162. package/src/runtime/memory/index.mjs +4 -0
  163. package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
  164. package/src/runtime/memory/lib/embedding-worker.mjs +4 -0
  165. package/src/runtime/office/quality/assurance-structure-docx.mjs +1 -1
  166. package/src/runtime/shared/agent-route-config.mjs +17 -2
  167. package/src/runtime/shared/atomic-file.mjs +103 -2
  168. package/src/runtime/shared/background-tasks.mjs +15 -6
  169. package/src/runtime/shared/connector-accounts.mjs +5 -5
  170. package/src/runtime/shared/connector-catalog.d.mts +11 -4
  171. package/src/runtime/shared/connector-catalog.mjs +60 -52
  172. package/src/runtime/shared/custom-provider-keys.mjs +20 -0
  173. package/src/runtime/shared/file-has-data.mjs +26 -2
  174. package/src/runtime/shared/file-lock.mjs +13 -15
  175. package/src/runtime/shared/git-launch.d.mts +9 -0
  176. package/src/runtime/shared/git-launch.mjs +213 -0
  177. package/src/runtime/shared/git-runner-worker.mjs +2 -1
  178. package/src/runtime/shared/llm/cost.mjs +6 -1
  179. package/src/runtime/shared/llm/http-agent.mjs +313 -29
  180. package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
  181. package/src/runtime/shared/llm/model-catalog.mjs +46 -6
  182. package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
  183. package/src/runtime/shared/llm/system-proxy.mjs +452 -0
  184. package/src/runtime/shared/provider-accounts.mjs +52 -2
  185. package/src/runtime/shared/staged-install-worker.mjs +5 -0
  186. package/src/runtime/shared/staged-update.mjs +47 -2
  187. package/src/runtime/shared/tool-surface.mjs +110 -36
  188. package/src/runtime/shared/tool-work-units.mjs +4 -0
  189. package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
  190. package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
  191. package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
  192. package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
  193. package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
  194. package/src/runtime/shared/worktrees/git.mjs +57 -0
  195. package/src/runtime/shared/worktrees/manager.mjs +205 -137
  196. package/src/runtime/tidy/install.mjs +95 -15
  197. package/src/runtime/tidy/languages.mjs +17 -15
  198. package/src/runtime/tidy/process.mjs +7 -4
  199. package/src/runtime/tidy/resolve.mjs +19 -16
  200. package/src/runtime/tidy/runners/biome.mjs +3 -3
  201. package/src/runtime/tidy/tool.mjs +1 -1
  202. package/src/runtime/tidy/worktree.mjs +10 -6
  203. package/src/runtime/visualize-bridge/client.mjs +4 -1
  204. package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
  205. package/src/runtime/web-search/index.mjs +1 -1
  206. package/src/session-runtime/agent-task-sessions.mjs +410 -353
  207. package/src/session-runtime/boot/tools.mjs +2 -0
  208. package/src/session-runtime/bot-status.mjs +103 -103
  209. package/src/session-runtime/connector-merge-migration.mjs +18 -15
  210. package/src/session-runtime/conversation-import/discovery.mjs +159 -40
  211. package/src/session-runtime/conversation-import/service.mjs +9 -3
  212. package/src/session-runtime/handoff-attachments.mjs +1 -1
  213. package/src/session-runtime/held-requests.mjs +3 -1
  214. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
  215. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
  216. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +143 -116
  217. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
  218. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  219. package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
  220. package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
  221. package/src/session-runtime/mixy-heartbeat.mjs +1 -1
  222. package/src/session-runtime/provider-auth/login.mjs +2 -2
  223. package/src/session-runtime/resource-mcp-api.mjs +98 -35
  224. package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
  225. package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
  226. package/src/session-runtime/resource-mcp-servers.mjs +5 -4
  227. package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
  228. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
  229. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
  230. package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
  231. package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
  232. package/src/session-runtime/services/daemon-candidate.mjs +4 -1
  233. package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
  234. package/src/session-runtime/services/plugin-admin.mjs +10 -6
  235. package/src/session-runtime/services/provider-admin.mjs +281 -10
  236. package/src/session-runtime/session-turn-api.mjs +2 -0
  237. package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
  238. package/src/session-runtime/settings-system-api.mjs +1 -1
  239. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
  240. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
  241. package/src/session-runtime/setup-tool/executor.mjs +6 -2
  242. package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
  243. package/src/session-runtime/turn/agent-ops.mjs +23 -0
  244. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
  245. package/src/session-runtime/workflow-agents-api/agent-route.mjs +10 -1
  246. package/src/session-runtime/workspace/activity-guards.mjs +176 -0
  247. package/src/session-runtime/workspace/session-view.mjs +149 -0
  248. package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
  249. package/src/session-runtime/workspace/transition-runner.mjs +188 -0
  250. package/src/session-runtime/workspace/transitions.mjs +108 -1066
  251. package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
  252. package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
  253. package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
  254. package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
  255. package/src/session-runtime/workspace/worktree-tool.mjs +54 -54
  256. package/src/standalone/daemon-desktop-runtime.mjs +2 -0
  257. package/src/standalone/daemon-session-control.mjs +151 -136
  258. package/src/standalone/daemon.mjs +7 -0
  259. package/src/standalone/desktop-service-registry.mjs +9 -0
  260. package/src/standalone/local-session-runtime.mjs +5 -1
  261. package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
  262. package/src/standalone/session-client.mjs +5 -1
  263. package/src/standalone/session-frame-stream.mjs +83 -11
  264. package/src/standalone/session-protocol.mjs +4 -0
  265. package/src/standalone/session-service/agent-tree.mjs +45 -9
  266. package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
  267. package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
  268. package/src/standalone/session-service/stored-reader.mjs +127 -40
  269. package/src/tui/App.jsx +154 -164
  270. package/src/tui/app/app-view/floating-panel.jsx +3 -0
  271. package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
  272. package/src/tui/app/clipboard.mjs +21 -10
  273. package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
  274. package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
  275. package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
  276. package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
  277. package/src/tui/app/provider-setup/oauth-actions.mjs +25 -6
  278. package/src/tui/app/provider-setup-picker.mjs +20 -13
  279. package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
  280. package/src/tui/app/slash-commands.mjs +1 -0
  281. package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
  282. package/src/tui/app/slash-dispatch.mjs +1 -1
  283. package/src/tui/app/use-btw-panel.mjs +29 -0
  284. package/src/tui/app/use-context-panel-refresh.mjs +31 -0
  285. package/src/tui/app/use-model-catalog-cache.mjs +13 -10
  286. package/src/tui/app/use-mouse-input.mjs +11 -0
  287. package/src/tui/app/use-onboarding-start.mjs +8 -3
  288. package/src/tui/app/use-panel-transition.mjs +10 -1
  289. package/src/tui/app/use-pasted-buffers.mjs +28 -20
  290. package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
  291. package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
  292. package/src/tui/app/use-prompt-queue-history.mjs +3 -2
  293. package/src/tui/app/use-selection-focus.mjs +11 -2
  294. package/src/tui/app/use-selection-geometry.mjs +18 -9
  295. package/src/tui/app/use-selection-paint.mjs +4 -4
  296. package/src/tui/app/use-selection-stitch.mjs +3 -3
  297. package/src/tui/app/use-slash-palette.mjs +62 -0
  298. package/src/tui/app/use-terminal-chrome.mjs +2 -2
  299. package/src/tui/app/use-transcript-activity.mjs +47 -32
  300. package/src/tui/app/use-transcript-follow.mjs +12 -4
  301. package/src/tui/app/use-transcript-scroll.mjs +46 -17
  302. package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
  303. package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
  304. package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
  305. package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
  306. package/src/tui/app/use-transcript-window.mjs +21 -11
  307. package/src/tui/app/use-tui-ready.mjs +18 -0
  308. package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
  309. package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
  310. package/src/tui/components/Picker.jsx +27 -3
  311. package/src/tui/components/SignInUrl.jsx +68 -0
  312. package/src/tui/components/TextEntryPanel.jsx +76 -46
  313. package/src/tui/components/sign-in-url-layout.mjs +24 -0
  314. package/src/tui/dist/index.mjs +1896 -1341
  315. package/src/tui/session/goal-turn-state.mjs +6 -2
  316. package/src/tui/session/session-api/controls.mjs +4 -0
  317. package/src/tui/session/session-api/extensions.mjs +8 -0
  318. package/src/tui/session/session-api/intake/abort.mjs +2 -1
  319. package/src/tui/session/session-api/intake.mjs +2 -0
  320. package/src/tui/session/session-api/integrations.mjs +2 -2
  321. package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
  322. package/src/tui/session/session-api/settings.mjs +2 -2
  323. package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
  324. package/src/tui/session/transcript-spill.mjs +92 -4
  325. package/src/tui/session/transcript-store.mjs +2 -0
  326. package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
@@ -46,7 +46,8 @@ import { executionFallbacks } from '../../../../shared/model-route-chain.mjs';
46
46
  import { ownerRouteFallbacks } from './owner-route-fallbacks.mjs';
47
47
  import { applyPendingWorkspaceReroot, refreshSessionBp3Environment } from './prompt-utils.mjs';
48
48
  import { isWorktreeBound } from '../../../../shared/worktrees/contract.mjs';
49
- import { applyAgentToolExposure } from '../loop/tool-exposure-migration.mjs';
49
+ import { applyAgentToolExposure, markToolSurfaceMigrated } from '../loop/tool-exposure-migration.mjs';
50
+ import { useOwnScratchEnvironment } from './session-scratch-environment.mjs';
50
51
  import { prewarmSessionAutoEffort } from './ask-turn-auto-effort.mjs';
51
52
  import { cancelCacheWarm } from '../cache-warm.mjs';
52
53
 
@@ -164,9 +165,9 @@ function resolveSessionRoute(opts, presetObj, profile) {
164
165
  const modelName = opts.model || presetObj?.model;
165
166
  // opts.tools (caller-supplied) wins over presetObj.tools — caller
166
167
  // intent ('tools:readonly' from Pool C, etc.) must override the
167
- // preset's default 'full'. Previous priority let HAIKU's tools='full'
168
- // shadow Pool C's explicit readonly request, leaking write tools and
169
- // bash into a read-only agent.
168
+ // preset's default 'full'; otherwise a preset's tools='full' would shadow
169
+ // an explicit readonly request and leak write tools and bash into a
170
+ // read-only agent.
170
171
  const toolPreset = opts.tools || presetObj?.tools || (typeof opts.preset === 'string' ? opts.preset : null) || 'full';
171
172
  const effort = Object.hasOwn(opts, 'effort') ? opts.effort || null : presetObj?.effort || null;
172
173
  const fast = presetObj?.fast === true || opts.fast === true;
@@ -237,17 +238,21 @@ export function createSession(createOpts) {
237
238
  : { ...createOpts, sessionMode };
238
239
  // A Lead-class session (actingAgent set) takes its owner's chain while it
239
240
  // runs on the owner's primary model; an agent keeps its preset's.
240
- const routeFallbacks = actingAgent
241
- ? Object.hasOwn(opts, 'routeFallbacks')
241
+ const explicitRouteFallbacks = Object.hasOwn(opts, 'routeFallbacks');
242
+ let routeFallbacks;
243
+ if (actingAgent) {
244
+ routeFallbacks = explicitRouteFallbacks
242
245
  ? opts.routeFallbacks
243
- : ownerRouteFallbacks({ sessionMode, agentId: actingAgent, provider: providerName, model: modelName })
244
- : executionFallbacks(
245
- normalizeWorkflowRoute({
246
- provider: providerName,
247
- model: modelName,
248
- fallbacks: Object.hasOwn(opts, 'routeFallbacks') ? opts.routeFallbacks : presetObj?.fallbacks,
249
- })
250
- );
246
+ : ownerRouteFallbacks({ sessionMode, agentId: actingAgent, provider: providerName, model: modelName });
247
+ } else {
248
+ routeFallbacks = executionFallbacks(
249
+ normalizeWorkflowRoute({
250
+ provider: providerName,
251
+ model: modelName,
252
+ fallbacks: explicitRouteFallbacks ? opts.routeFallbacks : presetObj?.fallbacks,
253
+ })
254
+ );
255
+ }
251
256
  // Provider cache strategy — agentRuntime.resolveSync() above is a
252
257
  // best-effort injection point (setAgentRuntime() has no live caller
253
258
  // today, so that branch never fires); build it directly here so every
@@ -594,6 +599,12 @@ export async function resumeSession(sessionId, preset, options = {}) {
594
599
  _recoverTurnCheckpointDurably(session, sessionId);
595
600
  _refreshResumedTools(session, sessionId, preset);
596
601
  refreshSessionProviderCacheOpts(session);
602
+ // An archive saved before clear learned to rename it still names the
603
+ // session it was copied from: a changed prefix is one cache break.
604
+ if (useOwnScratchEnvironment(session)) {
605
+ invalidateContextUsageSnapshot(session);
606
+ markToolSurfaceMigrated(session, 'prompt_fold');
607
+ }
597
608
  // The live session already owns the refreshed tools and desktop scope.
598
609
  // Defer the structured clone + worker round-trip so opening a conversation
599
610
  // is not blocked on persisting the same in-memory state back to disk.
@@ -25,6 +25,18 @@ import { sessionScratchDir } from '../../../../shared/session-scratch.mjs';
25
25
  import { delegationDisabled } from './session-tool-surface.mjs';
26
26
  import { contextAckMessage } from '../compact/user-message-kind.mjs';
27
27
 
28
+ /** What the generated scratch line starts with; the one place that line is recognised. */
29
+ export const SCRATCH_LINE_PREFIX = '- Scratch: ';
30
+
31
+ /** The environment line naming `sessionId`'s scratch directory, '' without one. */
32
+ export function scratchEnvironmentLine(sessionId) {
33
+ // Fixed per session id and data dir, so the line never changes across turns.
34
+ const scratchDir = sessionScratchDir(sessionId);
35
+ return scratchDir
36
+ ? `${SCRATCH_LINE_PREFIX}${scratchDir} — this session's scratch directory; TEMP, TMP and TMPDIR in shell commands point here.`
37
+ : '';
38
+ }
39
+
28
40
  // Preserve the exact pre-layout environment payload: Lead carried the
29
41
  // shell preference in Profile Preferences, while any routing surface with
30
42
  // shell carried the startup capability line in BP1.
@@ -33,8 +45,6 @@ import { contextAckMessage } from '../compact/user-message-kind.mjs';
33
45
  // resolves explicit session signals first and never leaks the daemon's
34
46
  // install root (user-cwd.mjs safe fallback chain).
35
47
  function buildShellEnvironmentContext(opts, ownerIsAgent, toolsForRouting, sessionId = null) {
36
- // Fixed per session id and data dir, so the line never changes across turns.
37
- const scratchDir = sessionScratchDir(sessionId);
38
48
  const sessionCwdLine = opts.cwd || captureOriginalUserCwd();
39
49
  const wantsGitStartupLine = toolsForRouting.some((tool) => tool?.name === 'git');
40
50
  let cwdContextLine = '';
@@ -48,9 +58,7 @@ function buildShellEnvironmentContext(opts, ownerIsAgent, toolsForRouting, sessi
48
58
  return [
49
59
  cwdContextLine,
50
60
  `- Shell: ${shellName}. Use ${shellName} syntax unless the user specifies otherwise.`,
51
- scratchDir
52
- ? `- Scratch: ${scratchDir} — this session's scratch directory; TEMP, TMP and TMPDIR in shell commands point here.`
53
- : '',
61
+ scratchEnvironmentLine(sessionId),
54
62
  // Which common tools the shell can run, measured where commands run
55
63
  // (login shell on POSIX, this process's PATH on Windows); see
56
64
  // runtime-capabilities.mjs. Recorded runs spent a round per session
@@ -113,15 +121,11 @@ export function sessionRolePromptFields(identity, { ownerIsAgent, toolFreeRole,
113
121
  const mixy = (identity.agent || MIXY_AGENT_ID) === MIXY_AGENT_ID;
114
122
  let roleRules = '';
115
123
  if (!skipRules) {
116
- roleRules = ownerIsAgent
117
- ? _buildAgentRules(identity.agentRulesProfile)
118
- : _buildLeadRules({ includeLeadBrief: !delegationFree });
124
+ roleRules = ownerIsAgent ? _buildAgentRules() : _buildLeadRules({ includeLeadBrief: !delegationFree });
119
125
  }
120
- const identityLine = agentMode
121
- ? agentModeIdentityLine(identity.agent || MIXY_AGENT_ID)
122
- : lead
123
- ? _buildLeadRules({ includeLeadBrief: !delegationFree, part: 'identity' })
124
- : '';
126
+ let identityLine = '';
127
+ if (agentMode) identityLine = agentModeIdentityLine(identity.agent || MIXY_AGENT_ID);
128
+ else if (lead) identityLine = _buildLeadRules({ includeLeadBrief: !delegationFree, part: 'identity' });
125
129
  return {
126
130
  roleRules,
127
131
  ...(lead
@@ -172,7 +176,6 @@ export function composeSessionSystem(opts, { profile, providerName, modelName, s
172
176
  skipAgentRules: opts.skipAgentRules === true,
173
177
  profileSkip: { ...profile?.skip },
174
178
  agent: resolvedAgent,
175
- agentRulesProfile: surface.agentRulesProfile,
176
179
  };
177
180
  const roleFields = sessionRolePromptFields(promptIdentity, {
178
181
  ownerIsAgent,
@@ -0,0 +1,70 @@
1
+ // manager/session-scratch-environment.mjs
2
+ // A session record that was copied from another session (a clear archive)
3
+ // still names the SOURCE's scratch directory in its generated environment,
4
+ // while its shell commands use its own. This rewrites only that line.
5
+ import {
6
+ BP3_PART_SEPARATOR,
7
+ bp3SystemMessage,
8
+ bpEnvSystemMessage,
9
+ replaceSystemMessageContent,
10
+ replaceWorkspaceEnvironment,
11
+ } from './prompt-utils.mjs';
12
+ import { SCRATCH_LINE_PREFIX, scratchEnvironmentLine } from './session-prompt-composition.mjs';
13
+
14
+ // The first line the generator's own prefix starts is the scratch line.
15
+ function withLine(text, line) {
16
+ if (typeof text !== 'string') return text;
17
+ const rows = text.split('\n');
18
+ const at = rows.findIndex((row) => row.startsWith(SCRATCH_LINE_PREFIX));
19
+ if (at < 0) return text;
20
+ rows[at] = line;
21
+ return rows.join('\n');
22
+ }
23
+
24
+ // Only the generated environment facts (the first part of the environment
25
+ // tail) hold the line; memory and instruction files never do.
26
+ function tailWithLine(tail, line) {
27
+ if (typeof tail !== 'string') return tail;
28
+ const facts = tail.split(BP3_PART_SEPARATOR)[0];
29
+ const fixed = withLine(facts, line);
30
+ return fixed === facts ? tail : replaceWorkspaceEnvironment(tail, fixed);
31
+ }
32
+
33
+ /**
34
+ * Make `session`'s generated environment name its own scratch directory:
35
+ * the persisted environment tail, the system block carrying it and the
36
+ * environment facts of a staged workspace change. Instruction files, memory
37
+ * and every conversation message stay as they are; a session that already
38
+ * names its own directory is left byte-identical (message objects included).
39
+ * System messages are replaced in the session's own array, never mutated.
40
+ * @returns {boolean} whether the system prefix changed
41
+ */
42
+ export function useOwnScratchEnvironment(session) {
43
+ const line = scratchEnvironmentLine(session?.id);
44
+ if (!line) return false;
45
+ const oldTail = session.bp3EnvironmentContext;
46
+ const newTail = tailWithLine(oldTail, line);
47
+ session.bp3EnvironmentContext = newTail;
48
+ const pending = session.workspaceReroot;
49
+ const seen = tailWithLine(pending?.seen?.environmentContext, line);
50
+ const target = tailWithLine(pending?.target?.environmentContext, line);
51
+ if (seen !== pending?.seen?.environmentContext || target !== pending?.target?.environmentContext) {
52
+ // The staged state may be shared with the session this one was copied
53
+ // from: replace it, never edit it.
54
+ session.workspaceReroot = {
55
+ ...pending,
56
+ seen: { ...pending.seen, environmentContext: seen },
57
+ target: { ...pending.target, environmentContext: target },
58
+ };
59
+ }
60
+ if (newTail === oldTail || typeof oldTail !== 'string') return false;
61
+ // The generated environment closes its block (split env block, or the
62
+ // combined tier3 block after core + session start): swap that suffix.
63
+ const block = session.bp3EnvSplit === true ? bpEnvSystemMessage(session) : bp3SystemMessage(session);
64
+ const content = block?.content;
65
+ const suffix = oldTail.trim();
66
+ if (typeof content !== 'string' || !suffix || !content.endsWith(suffix)) return false;
67
+ const next = content.slice(0, -suffix.length) + newTail.trim();
68
+ // The prefix changed exactly when the system block's text did.
69
+ return replaceSystemMessageContent(session, block, next) && next !== content;
70
+ }
@@ -74,8 +74,6 @@ function schemaOmittedToolNames(toolsForRouting, tools) {
74
74
  export function resolveSessionToolSurface(opts, { profile, toolPreset, modelName }) {
75
75
  const ownerIsAgent = isAgentOwner(opts.owner);
76
76
  const resolvedAgent = opts.agent || opts.role || profile?.taskType || null;
77
- const hiddenAgent = getHiddenAgent(resolvedAgent);
78
- const isRetrievalAgent = hiddenAgent?.kind === 'retrieval';
79
77
  const hasCallerAllow = Array.isArray(opts.schemaAllowedTools);
80
78
  const schemaAllowedTools = honoredSchemaAllowlist(opts.schemaAllowedTools, { ownerIsAgent, agent: resolvedAgent });
81
79
  // Lead and Agent share the same cwd-scoped Skill inventory. A session that
@@ -112,7 +110,6 @@ export function resolveSessionToolSurface(opts, { profile, toolPreset, modelName
112
110
  return {
113
111
  ownerIsAgent,
114
112
  resolvedAgent,
115
- agentRulesProfile: isRetrievalAgent ? 'retrieval' : 'full',
116
113
  skills,
117
114
  sessionDeny,
118
115
  toolPermission,
@@ -91,6 +91,11 @@ const ALL_BUILTIN_SESSION_TOOLS = orderSessionTools(
91
91
  _dedupByName([...BUILTIN_TOOLS, ...PATCH_TOOL_DEFS, ...CODE_GRAPH_TOOL_DEFS])
92
92
  );
93
93
 
94
+ /** The read-only filesystem tools (`tools:readonly`), in session route order. */
95
+ export function readOnlyFilesystemTools() {
96
+ return ALL_BUILTIN_SESSION_TOOLS.filter((t) => READONLY_FS_TOOL_NAMES.has(t.name));
97
+ }
98
+
94
99
  export function resolveSessionTools(
95
100
  toolSpec,
96
101
  skills,
@@ -154,7 +159,7 @@ function _computeBaseTools(toolSpec, mcp, skillTools) {
154
159
  addMany(ALL_BUILTIN_SESSION_TOOLS.filter((t) => FILESYSTEM_TOOL_NAMES.has(t.name)));
155
160
  break;
156
161
  case 'tools:readonly':
157
- addMany(ALL_BUILTIN_SESSION_TOOLS.filter((t) => READONLY_FS_TOOL_NAMES.has(t.name)));
162
+ addMany(readOnlyFilesystemTools());
158
163
  break;
159
164
  case 'tools:shell':
160
165
  case 'tools:analysis':
@@ -186,8 +191,7 @@ function _computeBaseTools(toolSpec, mcp, skillTools) {
186
191
  case 'mcp':
187
192
  return orderSessionTools(_dedupByName([...mcp, ...skillTools]));
188
193
  case 'readonly': {
189
- const readTools = ALL_BUILTIN_SESSION_TOOLS.filter((t) => READONLY_FS_TOOL_NAMES.has(t.name));
190
- return orderSessionTools(_dedupByName([...readTools, ...mcp, ...skillTools]));
194
+ return orderSessionTools(_dedupByName([...readOnlyFilesystemTools(), ...mcp, ...skillTools]));
191
195
  }
192
196
  // 'full' and any unknown spec.
193
197
  default:
@@ -195,8 +195,8 @@ function appendObservedTurnOutput(
195
195
  }
196
196
  }
197
197
 
198
- export function createTurnInterruptionTracker() {
199
- const state = {
198
+ function newInterruptionState() {
199
+ return {
200
200
  responseStarted: false,
201
201
  partialAssistantContent: '',
202
202
  tombstonedAssistantContent: '',
@@ -213,7 +213,10 @@ export function createTurnInterruptionTracker() {
213
213
  tombEpoch: 0,
214
214
  callsEpoch: 0,
215
215
  };
216
+ }
216
217
 
218
+ /** Streamed assistant text, including the tombstone of a retracted attempt. */
219
+ function textBufferMethods(state) {
217
220
  return {
218
221
  recordTextDelta(chunk) {
219
222
  const value = String(chunk ?? '');
@@ -263,33 +266,12 @@ export function createTurnInterruptionTracker() {
263
266
  state.tombEpoch += 1;
264
267
  return true;
265
268
  },
266
- hasResponseStarted() {
267
- return state.responseStarted;
268
- },
269
- recordReasoningDelta(chunk) {
270
- const value = String(chunk ?? '');
271
- if (!value) return;
272
- state.responseStarted = true;
273
- state.partialReasoningContent += value;
274
- },
275
- recordAssistantText(text) {
276
- const value = String(text ?? '');
277
- if (!value.trim()) return;
278
- state.responseStarted = true;
279
- // Buffered providers report the whole segment here; streaming
280
- // providers already accumulated the same segment via text deltas.
281
- if (!state.partialAssistantContent.trim()) state.partialAssistantContent += value;
282
- },
283
- markAssistantMessageCommitted() {
284
- state.partialAssistantContent = '';
285
- state.tombstonedAssistantContent = '';
286
- state.partialReasoningContent = '';
287
- state.observedToolCalls.clear();
288
- state.textEpoch += 1;
289
- state.reasoningEpoch += 1;
290
- state.tombEpoch += 1;
291
- state.callsEpoch += 1;
292
- },
269
+ };
270
+ }
271
+
272
+ /** Tool calls and early-notified results observed during the turn. */
273
+ function toolObservationMethods(state) {
274
+ return {
293
275
  recordToolCalls(calls, { eagerStarted = false } = {}) {
294
276
  for (const call of Array.isArray(calls) ? calls : []) {
295
277
  if (!call?.id) continue;
@@ -317,6 +299,42 @@ export function createTurnInterruptionTracker() {
317
299
  state.observedToolResults.delete(callId);
318
300
  }
319
301
  },
302
+ };
303
+ }
304
+
305
+ export function createTurnInterruptionTracker() {
306
+ const state = newInterruptionState();
307
+
308
+ return {
309
+ ...textBufferMethods(state),
310
+ ...toolObservationMethods(state),
311
+ hasResponseStarted() {
312
+ return state.responseStarted;
313
+ },
314
+ recordReasoningDelta(chunk) {
315
+ const value = String(chunk ?? '');
316
+ if (!value) return;
317
+ state.responseStarted = true;
318
+ state.partialReasoningContent += value;
319
+ },
320
+ recordAssistantText(text) {
321
+ const value = String(text ?? '');
322
+ if (!value.trim()) return;
323
+ state.responseStarted = true;
324
+ // Buffered providers report the whole segment here; streaming
325
+ // providers already accumulated the same segment via text deltas.
326
+ if (!state.partialAssistantContent.trim()) state.partialAssistantContent += value;
327
+ },
328
+ markAssistantMessageCommitted() {
329
+ state.partialAssistantContent = '';
330
+ state.tombstonedAssistantContent = '';
331
+ state.partialReasoningContent = '';
332
+ state.observedToolCalls.clear();
333
+ state.textEpoch += 1;
334
+ state.reasoningEpoch += 1;
335
+ state.tombEpoch += 1;
336
+ state.callsEpoch += 1;
337
+ },
320
338
  markProviderSendStarted() {
321
339
  state.phase = 'streaming';
322
340
  },
@@ -0,0 +1,125 @@
1
+ // manager/turn-reap.mjs
2
+ // A turn abandoned by a timeout or stall stops the background shell work that
3
+ // turn started — a job auto-promoted during it, and the survivors its commands
4
+ // left running. Only those: a user cancel, a steering interrupt, a normal
5
+ // finish, and jobs from earlier turns keep their jobs. Only the entry's own
6
+ // turn start is armed, and a new turn clears it, so a reap that runs late
7
+ // never touches a newer turn's work.
8
+ import { cancelBackgroundTasks, getBackgroundTask } from '../../../../shared/background-tasks.mjs';
9
+ import { runtimeState } from './runtime-state.mjs';
10
+
11
+ // Timeout ownership is explicit and turn-scoped: the code that makes a timeout
12
+ // WIN (the watchdog's own abort, the provider's terminal error) arms the reap
13
+ // itself, and only while nothing else has stopped the turn. An abort that
14
+ // arrives first stays a cancel; an error chain is never read afterwards.
15
+
16
+ // Codes of the runtime's own timeout/stall errors (stall-policy's
17
+ // streamStalledError / providerTimeoutError, the Gemini stream timeout).
18
+ const PROVIDER_TIMEOUT_CODES = new Set(['ESTREAMSTALL', 'EPROVIDERTIMEOUT', 'EGEMINITIMEOUT']);
19
+
20
+ /** A timeout is the first thing to stop this session's turn: arm its reap now,
21
+ * before the abort propagates. No-op when the turn's controller is already
22
+ * aborted (a cancel, interrupt or close won) or no turn runs. */
23
+ export function armTurnTimeout(id) {
24
+ const entry = runtimeState.get(id);
25
+ if (!entry || entry.controller?.signal.aborted) return;
26
+ armTurnShellReap(id, entry);
27
+ }
28
+
29
+ /** The turn ended with a provider timeout/stall error that no retry recovered
30
+ * from: arm only while the turn's own signal is un-aborted and the error
31
+ * itself carries a timeout code or the producer's own `streamStalled` flag. */
32
+ export function armTurnTimeoutOnProviderError(id, entry, turnSignal, err) {
33
+ if (turnSignal?.aborted) return;
34
+ if (!PROVIDER_TIMEOUT_CODES.has(err?.code) && err?.streamStalled !== true) return;
35
+ armTurnShellReap(id, entry);
36
+ }
37
+
38
+ // session id -> jobs stopped by a timeout reap, until the owner's handoff
39
+ // reports them (or the session's next turn starts).
40
+ const stoppedJobs = new Map();
41
+
42
+ // What the cancel path already produces, read without waiting: a task whose
43
+ // own cancel hook kills (survivors of a finished command) answers with its
44
+ // kill outcome; a promoted job is over once its process tree is no longer
45
+ // tracked.
46
+ function trackStoppedJob(taskId) {
47
+ const job = { taskId, outcome: null, terminated: false };
48
+ const kill = getBackgroundTask(taskId)?.cancelOutcome;
49
+ if (kill) {
50
+ job.outcome = kill;
51
+ Promise.resolve(kill).then(
52
+ (result) => {
53
+ job.terminated = result?.terminated === true;
54
+ },
55
+ () => {}
56
+ );
57
+ }
58
+ return job;
59
+ }
60
+
61
+ // shell-jobs depends on the session manager, which loads this module, so it is
62
+ // loaded at the first reap. The classification awaits only this module load,
63
+ // never a process; a probe that cannot be loaded leaves a job "still stopping".
64
+ let shellJobProbe = null;
65
+ function loadShellJobProbe() {
66
+ shellJobProbe ??= import('../../tools/builtin/shell-jobs.mjs').then(
67
+ (shellJobs) => shellJobs.isShellJobRunning,
68
+ () => null
69
+ );
70
+ return shellJobProbe;
71
+ }
72
+
73
+ // Confirmed by the runtime's own state, never assumed: a task whose cancel hook
74
+ // kills is confirmed by that kill's `terminated`; a promoted job once neither
75
+ // its native task nor its process-tree tracker is live. Without the probe
76
+ // (shell-jobs not loaded) nothing is confirmed.
77
+ function isConfirmedGone(job, isRunning) {
78
+ if (job.outcome) return job.terminated;
79
+ return Boolean(isRunning) && !isRunning(job.taskId);
80
+ }
81
+
82
+ function reap(id, entry) {
83
+ loadShellJobProbe();
84
+ const { taskIds } = cancelBackgroundTasks({
85
+ surface: 'shell',
86
+ executionSessionId: id,
87
+ startedSinceMs: entry.shellReapSince,
88
+ reason: 'turn-timeout',
89
+ notify: false,
90
+ });
91
+ if (taskIds.length > 0) stoppedJobs.set(id, [...(stoppedJobs.get(id) || []), ...taskIds.map(trackStoppedJob)]);
92
+ }
93
+
94
+ /** The turn is being abandoned by a timeout: remember when it started and stop
95
+ * what it has started so far. A settled (idle) entry has no turn to reap. */
96
+ export function armTurnShellReap(id, entry) {
97
+ if (!(entry?.askStartedAt > 0) || entry.closed) return;
98
+ entry.shellReapSince = entry.askStartedAt;
99
+ reap(id, entry);
100
+ }
101
+
102
+ /** The abandoned turn has unwound: sweep what it registered while stopping
103
+ * (survivors of its aborted commands). No-op unless this turn was armed. */
104
+ export function reapTurnShellJobs(id, entry) {
105
+ if (entry?.shellReapSince > 0 && !entry.closed && runtimeState.get(id) === entry) reap(id, entry);
106
+ }
107
+
108
+ /** A new turn owns the session: nothing earlier may be reaped on its account. */
109
+ export function resetTurnShellReap(id, entry) {
110
+ entry.shellReapSince = null;
111
+ stoppedJobs.delete(id);
112
+ }
113
+
114
+ /** The jobs the reap stopped, split by what is known now: `stopped` are
115
+ * confirmed gone, `stopping` were killed but their processes are not yet
116
+ * confirmed gone (they keep being terminated). */
117
+ export async function takeStoppedShellJobs(id) {
118
+ const jobs = stoppedJobs.get(id) || [];
119
+ stoppedJobs.delete(id);
120
+ if (jobs.length === 0) return { stopped: [], stopping: [] };
121
+ const isRunning = await loadShellJobProbe();
122
+ const taskIds = (confirmed) =>
123
+ jobs.filter((job) => isConfirmedGone(job, isRunning) === confirmed).map((job) => job.taskId);
124
+ return { stopped: taskIds(true), stopping: taskIds(false) };
125
+ }
@@ -3,9 +3,13 @@
3
3
  // Every model- or user-facing string that names it reads this, re-read on each
4
4
  // use so a rename applies at once. Text shared across agents (tool schemas,
5
5
  // other agents' shared prompt block) says "the representative agent" instead,
6
- // so a rename never changes cached bytes.
7
- import { dirname, join } from 'node:path';
8
- import { mixdogGlobalDir, readSafe } from '../context/skill-catalog.mjs';
6
+ // so a rename never changes those cached bytes. Each other bot's own contact
7
+ // catalog (workflow/context.mjs) names her, so a request naming her finds her.
8
+ // Light imports only: the prompt's contact catalog (workflow/context.mjs) reads
9
+ // the name too, and must not pull the skill catalog and config in with it.
10
+ import { readFileSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { resolvePluginData } from '../../../shared/plugin-paths.mjs';
9
13
  import { mixyIdentityDir } from '../../../shared/agent-store.mjs';
10
14
 
11
15
  export const DEFAULT_MIXY_NAME = 'Mixy';
@@ -19,9 +23,11 @@ export function mixyNameOf(manifest) {
19
23
  export function mixyDisplayName() {
20
24
  try {
21
25
  // bots/mixy once Mixy is its own bot, agents/lead before (agent-store.mjs).
22
- const dir = mixyIdentityDir(dirname(mixdogGlobalDir('agents')));
23
- return mixyNameOf(JSON.parse(readSafe(join(dir, 'agent.json')) || '{}'));
26
+ const dir = mixyIdentityDir(resolvePluginData());
27
+ return mixyNameOf(JSON.parse(readFileSync(join(dir, 'agent.json'), 'utf8')));
24
28
  } catch {
29
+ // Never throws: prompt composition calls this unguarded, and the name only labels Mixy.
30
+ // A missing, empty, unreadable or malformed agent.json is the unrenamed default.
25
31
  return DEFAULT_MIXY_NAME;
26
32
  }
27
33
  }
@@ -1,4 +1,4 @@
1
- // Child process of restart-prefix-parity.test.mjs: one phase of a scripted
1
+ // Child process of restart-prefix-parity.slow.test.mjs: one phase of a scripted
2
2
  // anthropic-oauth session in its own process, so a "restart" is a real new
3
3
  // process reading the data dir the previous one left. The fake provider
4
4
  // records the request body the real OAuth builder makes for every main-loop