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
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Discovery of importable foreign conversations on disk (read-only).
3
3
  *
4
- * codex $CODEX_HOME/sessions/**\/rollout-*.jsonl (default ~/.codex)
4
+ * codex $CODEX_HOME/sessions/**\/rollout-*.jsonl[.zst] (default ~/.codex)
5
5
  * claude $CLAUDE_CONFIG_DIR/projects/*\/*.jsonl (default ~/.claude)
6
+ * cowork %APPDATA%\Claude\local-agent-mode-sessions (Claude Desktop; Windows only)
6
7
  *
7
8
  * Enumeration is stat-only; per-file metadata (foreign id, cwd, title, and
8
9
  * the message count when the whole file fit the read) comes from a bounded
@@ -11,9 +12,11 @@
11
12
  * shares one cache, one candidate registry and one set of listing views.
12
13
  */
13
14
  import { createHash, randomUUID } from 'node:crypto';
14
- import { open, readdir, realpath, stat } from 'node:fs/promises';
15
+ import { open, readdir, readFile, realpath, stat } from 'node:fs/promises';
15
16
  import { homedir } from 'node:os';
16
- import { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'node:path';
17
+ import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
18
+ import { pipeline } from 'node:stream';
19
+ import zlib from 'node:zlib';
17
20
  import {
18
21
  IMPORT_MAX_FILE_BYTES,
19
22
  IMPORT_MAX_LINE_BYTES,
@@ -24,7 +27,13 @@ import {
24
27
  isImportSource,
25
28
  } from '../../runtime/agent/orchestrator/session/conversation-import/convert.mjs';
26
29
  import { codexMetaFromTruncatedLine } from '../../runtime/agent/orchestrator/session/conversation-import/codex.mjs';
27
- import { IMPORT_WARNING_CWD_MISSING } from '../../runtime/agent/orchestrator/session/conversation-import/turns.mjs';
30
+ import {
31
+ IMPORT_ERROR_NEEDS_NEWER_NODE,
32
+ IMPORT_WARNING_CWD_MISSING,
33
+ IMPORT_WARNING_HISTORY_PARTIAL,
34
+ IMPORT_WARNING_HISTORY_SIZE_LIMIT,
35
+ IMPORT_WARNING_HISTORY_UNAVAILABLE,
36
+ } from '../../runtime/agent/orchestrator/session/conversation-import/turns.mjs';
28
37
  import { importOriginKey } from '../../runtime/agent/orchestrator/session/conversation-import/imported-session.mjs';
29
38
  import { loadCodexThreadTitles } from './codex-titles.mjs';
30
39
 
@@ -69,6 +78,11 @@ const envDir = (value) => (typeof value === 'string' && value.trim() ? resolve(v
69
78
  export function sourceRoot(source, env = process.env) {
70
79
  if (source === 'codex') return join(envDir(env.CODEX_HOME) || join(homedir(), '.codex'), 'sessions');
71
80
  if (source === 'claude') return join(envDir(env.CLAUDE_CONFIG_DIR) || join(homedir(), '.claude'), 'projects');
81
+ // Only Windows sets APPDATA; elsewhere Claude Desktop has no Cowork folder to search.
82
+ if (source === 'cowork') {
83
+ const appData = envDir(env.APPDATA);
84
+ return appData ? join(appData, 'Claude', 'local-agent-mode-sessions') : null;
85
+ }
72
86
  throw importError('unsupported');
73
87
  }
74
88
 
@@ -83,8 +97,8 @@ export function loadStoredTitles(source, env = process.env) {
83
97
  }
84
98
 
85
99
  /** The app's stored title of a conversation, else the one derived from its messages. */
86
- export function displayTitle(meta, titles) {
87
- return (meta?.foreignSessionId && titles?.get(meta.foreignSessionId)) || meta?.title || null;
100
+ export function displayTitle(meta, titles, manifestTitle = null) {
101
+ return manifestTitle || (meta?.foreignSessionId && titles?.get(meta.foreignSessionId)) || meta?.title || null;
88
102
  }
89
103
 
90
104
  const caseFold = (value) => (process.platform === 'win32' ? value.toLowerCase() : value);
@@ -106,6 +120,51 @@ export function isNetworkOrDevicePath(path) {
106
120
 
107
121
  const fileIdentity = (info) => `${info.dev}:${info.ino}`;
108
122
 
123
+ // Rollout file-name rules, as the source app applies them: a compressed rollout is a
124
+ // name ending `.jsonl.zst`; a rollout name is, after dropping a `.zst` suffix,
125
+ // `rollout-` … `.jsonl`. Both are case-sensitive.
126
+ const COMPRESSED_ROLLOUT_SUFFIX = '.jsonl.zst';
127
+ const isCompressed = (path) => basename(path).endsWith(COMPRESSED_ROLLOUT_SUFFIX);
128
+ const isRolloutName = (name) => {
129
+ const plain = name.endsWith(COMPRESSED_ROLLOUT_SUFFIX) ? name.slice(0, -'.zst'.length) : name;
130
+ return plain.startsWith('rollout-') && plain.endsWith('.jsonl');
131
+ };
132
+ const zstdSupported = () => typeof zlib.createZstdDecompress === 'function';
133
+
134
+ /**
135
+ * Sequential `read(buffer, offset, length, position)` / `close()` over the
136
+ * decompressed bytes of an open compressed file, shaped like a file handle so
137
+ * the line reader needs no other change. Positions must run on from the last
138
+ * read; closing stops the decompression.
139
+ */
140
+ function zstdReader(handle) {
141
+ if (!zstdSupported()) throw importError(IMPORT_ERROR_NEEDS_NEWER_NODE);
142
+ const decoder = zlib.createZstdDecompress();
143
+ pipeline(handle.createReadStream({ autoClose: false }), decoder, () => {});
144
+ const chunks = decoder[Symbol.asyncIterator]();
145
+ let rest = Buffer.alloc(0);
146
+ let position = 0;
147
+ return {
148
+ async read(buffer, offset, length, from) {
149
+ if (from !== position) throw importError('unreadable');
150
+ if (!rest.length) {
151
+ const next = await chunks.next();
152
+ if (next.done) return { bytesRead: 0, buffer };
153
+ rest = next.value;
154
+ }
155
+ const bytesRead = Math.min(length, rest.length);
156
+ rest.copy(buffer, offset, 0, bytesRead);
157
+ rest = rest.subarray(bytesRead);
158
+ position += bytesRead;
159
+ return { bytesRead, buffer };
160
+ },
161
+ async close() {
162
+ decoder.destroy();
163
+ await handle.close();
164
+ },
165
+ };
166
+ }
167
+
109
168
  export function candidateId(source, canonicalPath) {
110
169
  return createHash('sha256')
111
170
  .update(`${source}\0${caseFold(canonicalPath)}`)
@@ -144,7 +203,10 @@ async function walkCodex(rootReal, dir, files, seenDirs) {
144
203
  continue;
145
204
  }
146
205
  }
147
- if (/^rollout-.*\.jsonl$/i.test(entry.name)) files.push(path);
206
+ if (!isRolloutName(entry.name)) continue;
207
+ // A compressed rollout is skipped while its plain sibling exists.
208
+ if (isCompressed(entry.name) && (await stat(path.slice(0, -'.zst'.length)).catch(() => null))) continue;
209
+ files.push(path);
148
210
  }
149
211
  }
150
212
 
@@ -159,6 +221,68 @@ async function walkClaude(rootReal, files) {
159
221
  }
160
222
  }
161
223
 
224
+ // Cowork keeps one `local_<id>.json` manifest per conversation (the account/org folders hold
225
+ // `local_*.json` directly, the agent variant under `agent/`), next to a `local_<id>/` folder whose
226
+ // `.claude/projects/<project>/<cliSessionId>.jsonl` is the Claude Code transcript. The manifest also
227
+ // holds the system prompt and account details, so only title / isStarred / cliSessionId are read.
228
+ // The agent variant (`local_ditto_*`, sessionType "agent") is the user's own Claude desktop chat
229
+ // (its initialMessage is user-typed), so it is listed like the others.
230
+ const COWORK_MANIFEST_MAX_BYTES = 8 * 1024 * 1024;
231
+ const COWORK_TITLE_MAX_CHARS = 200;
232
+ const COWORK_SESSION_ID_RE = /^[\w-]+$/;
233
+
234
+ async function coworkManifestPaths(rootReal) {
235
+ const manifests = [];
236
+ for (const account of await entriesOf(rootReal)) {
237
+ if (!account.isDirectory()) continue;
238
+ for (const org of await entriesOf(join(rootReal, account.name))) {
239
+ if (!org.isDirectory()) continue;
240
+ for (const dir of [join(rootReal, account.name, org.name), join(rootReal, account.name, org.name, 'agent')]) {
241
+ for (const file of await entriesOf(dir)) {
242
+ if (file.isFile() && /^local_.+\.json$/.test(file.name)) manifests.push(join(dir, file.name));
243
+ }
244
+ }
245
+ }
246
+ }
247
+ return manifests;
248
+ }
249
+
250
+ // The transcript a manifest names, with the manifest's title and star; null when it has none.
251
+ async function coworkTranscript(rootReal, manifestPath) {
252
+ const real = await containedRealpath(rootReal, manifestPath);
253
+ const info = real ? await stat(real).catch(() => null) : null;
254
+ if (!info?.isFile() || info.size > COWORK_MANIFEST_MAX_BYTES) return null;
255
+ let manifest;
256
+ try {
257
+ manifest = JSON.parse(await readFile(real, 'utf8'));
258
+ } catch {
259
+ return null;
260
+ }
261
+ const cliSessionId = manifest?.cliSessionId;
262
+ if (typeof cliSessionId !== 'string' || !COWORK_SESSION_ID_RE.test(cliSessionId)) return null;
263
+ const projects = join(real.slice(0, -'.json'.length), '.claude', 'projects');
264
+ for (const project of await entriesOf(projects)) {
265
+ if (!project.isDirectory()) continue;
266
+ const path = join(projects, project.name, `${cliSessionId}.jsonl`);
267
+ if (await containedRealpath(rootReal, path)) {
268
+ const title = typeof manifest.title === 'string' ? manifest.title.trim().slice(0, COWORK_TITLE_MAX_CHARS) : '';
269
+ return { path, title: title || null, starred: manifest.isStarred === true };
270
+ }
271
+ }
272
+ return null;
273
+ }
274
+
275
+ async function walkCowork(rootReal, files, extras) {
276
+ const found = await mapBounded(await coworkManifestPaths(rootReal), STAT_CONCURRENCY, (path) =>
277
+ coworkTranscript(rootReal, path)
278
+ );
279
+ for (const entry of found) {
280
+ if (!entry) continue;
281
+ files.push(entry.path);
282
+ extras.set(entry.path, { title: entry.title, starred: entry.starred });
283
+ }
284
+ }
285
+
162
286
  async function mapBounded(items, limit, fn) {
163
287
  const out = new Array(items.length);
164
288
  let next = 0;
@@ -175,6 +299,7 @@ async function mapBounded(items, limit, fn) {
175
299
  /** Regular files under the source root, canonical and contained, as candidates. */
176
300
  export async function enumerateCandidates(source, env = process.env) {
177
301
  const root = sourceRoot(source, env);
302
+ if (!root) return { root: '', candidates: [] };
178
303
  let rootReal;
179
304
  try {
180
305
  rootReal = await realpath(root);
@@ -182,13 +307,17 @@ export async function enumerateCandidates(source, env = process.env) {
182
307
  return { root, candidates: [] };
183
308
  }
184
309
  const paths = [];
310
+ const extras = new Map(); // transcript path → manifest title / star (Cowork)
185
311
  if (source === 'codex') await walkCodex(rootReal, rootReal, paths, new Set([caseFold(rootReal)]));
312
+ else if (source === 'cowork') await walkCowork(rootReal, paths, extras);
186
313
  else await walkClaude(rootReal, paths);
187
314
  const stamped = await mapBounded(paths, STAT_CONCURRENCY, async (path) => {
188
315
  const real = await containedRealpath(rootReal, path);
189
316
  if (!real) return null;
190
317
  const info = await stat(real).catch(() => null);
191
- return info?.isFile() ? { path: real, size: info.size, mtimeMs: info.mtimeMs, fileId: fileIdentity(info) } : null;
318
+ return info?.isFile()
319
+ ? { path: real, size: info.size, mtimeMs: info.mtimeMs, fileId: fileIdentity(info), ...extras.get(path) }
320
+ : null;
192
321
  });
193
322
  const unique = new Map();
194
323
  for (const file of stamped) {
@@ -205,7 +334,9 @@ function compareCodeUnits(left, right) {
205
334
  return left < right ? -1 : 1;
206
335
  }
207
336
 
337
+ // Starred conversations (Cowork) come first, then newest first.
208
338
  function byModifiedThenId(left, right) {
339
+ if (!left.starred !== !right.starred) return left.starred ? -1 : 1;
209
340
  if (right.mtimeMs !== left.mtimeMs) return right.mtimeMs - left.mtimeMs;
210
341
  return compareCodeUnits(left.id, right.id);
211
342
  }
@@ -275,7 +406,7 @@ async function openCandidate(candidate) {
275
406
  ) {
276
407
  throw importError('unreadable');
277
408
  }
278
- return handle;
409
+ return isCompressed(candidate.path) ? zstdReader(handle) : handle;
279
410
  } catch (error) {
280
411
  await handle.close();
281
412
  throw error;
@@ -351,6 +482,10 @@ async function readTailLines(handle, size) {
351
482
  return (size > length ? text.slice(text.indexOf('\n') + 1) : text).split('\n');
352
483
  }
353
484
 
485
+ // Whether the rollout a listed file continues is absent (a stat-only search): its own records are then all there is to name and count.
486
+ const baseIsMissing = async (candidate, meta) =>
487
+ !!meta.historyBaseId && !(await findRolloutById(dirname(candidate.root ?? sourceRoot('codex')), meta.historyBaseId));
488
+
354
489
  async function readPrefixMeta(candidate) {
355
490
  const converter = createConversationConverter(candidate.source);
356
491
  const handle = await openCandidate(candidate);
@@ -358,7 +493,7 @@ async function readPrefixMeta(candidate) {
358
493
  // nothing but sidechain messages has been seen the scan streams on, line by
359
494
  // line, to EOF or to the import file-size limit. A file over that limit stays
360
495
  // unclassified (listed); importing it fails as tooLarge.
361
- const claude = candidate.source === 'claude';
496
+ const claude = candidate.source === 'claude' || candidate.source === 'cowork';
362
497
  let read;
363
498
  try {
364
499
  read = await streamJsonlLines(handle, (line) => converter.pushLine(line), {
@@ -385,12 +520,14 @@ async function readPrefixMeta(candidate) {
385
520
  }
386
521
  const conversion = converter.result();
387
522
  // A thread continuing a history base is only counted, named and judged empty once the base is followed (on import).
388
- const listing = (meta) =>
389
- conversion.historyBase
523
+ const listing = async (meta) =>
524
+ conversion.historyBase && !(await baseIsMissing(candidate, meta))
390
525
  ? { ...meta, title: null, messageCount: null, errorCode: meta.errorCode === 'empty' ? null : meta.errorCode }
391
- : meta;
526
+ : conversion.historyBase
527
+ ? { ...meta, warnings: [...meta.warnings, IMPORT_WARNING_HISTORY_UNAVAILABLE] }
528
+ : meta;
392
529
  if (read.eof) return listing(metaFromConversion(conversion, true));
393
- const meta = listing(metaFromConversion(conversion, false));
530
+ const meta = await listing(metaFromConversion(conversion, false));
394
531
  if (candidate.source === 'codex' && (!meta.foreignSessionId || !meta.cwd) && read.firstPartial) {
395
532
  // A session_meta line longer than the prefix still names its id/cwd.
396
533
  const fromLine = codexMetaFromTruncatedLine(read.firstPartial.replace(/^\uFEFF/, ''));
@@ -404,10 +541,13 @@ async function readPrefixMeta(candidate) {
404
541
  // ── Codex history base chain ─────────────────────────────────────────────────
405
542
  const HISTORY_CHAIN_MAX_DEPTH = 32;
406
543
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
407
- const ROLLOUT_ID_RE = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
544
+ const ROLLOUT_ID_RE = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl(?:\.zst)?$/i;
408
545
 
409
- /** Rollout id a rollout file name ends with (`…-<thread>.jsonl` or `…-<thread>_<rollout>.jsonl`). */
410
- const rolloutIdOf = (path) => basename(path).match(ROLLOUT_ID_RE)?.[1].toLowerCase() ?? null;
546
+ /** Rollout id a rollout file name ends with (`…-<thread>.jsonl[.zst]` or `…-<thread>_<rollout>.jsonl[.zst]`). */
547
+ const rolloutIdOf = (path) => {
548
+ const name = basename(path);
549
+ return isRolloutName(name) ? (name.match(ROLLOUT_ID_RE)?.[1].toLowerCase() ?? null) : null;
550
+ };
411
551
 
412
552
  const META_CHUNK_BYTES = 8 * 1024;
413
553
 
@@ -439,20 +579,34 @@ async function firstRecord(candidate, { maxBytes, maxLineBytes }) {
439
579
  }
440
580
  }
441
581
 
442
- // Whether a cutoff falls on a record boundary: the end of the file or just after a line feed.
582
+ // Whether a cutoff, in (decompressed) file bytes, falls on a record boundary: the end of the file or just after a line feed.
443
583
  async function endsOnRecord(candidate, end) {
444
- if (end === candidate.size) return true;
584
+ const compressed = isCompressed(candidate.path);
585
+ if (!compressed && end === candidate.size) return true;
445
586
  const handle = await openCandidate(candidate);
446
587
  try {
447
588
  const byte = Buffer.alloc(1);
448
- const { bytesRead } = await handle.read(byte, 0, 1, end - 1);
449
- return bytesRead === 1 && byte[0] === 10;
589
+ if (!compressed) {
590
+ const { bytesRead } = await handle.read(byte, 0, 1, end - 1);
591
+ return bytesRead === 1 && byte[0] === 10;
592
+ }
593
+ // The decompressed size is unknown: read up to the cutoff, then see whether the file ends there.
594
+ const chunk = Buffer.allocUnsafe(IMPORT_CHUNK_BYTES);
595
+ let position = 0;
596
+ let last = 0;
597
+ while (position < end) {
598
+ const { bytesRead } = await handle.read(chunk, 0, Math.min(chunk.length, end - position), position);
599
+ if (!bytesRead) return false;
600
+ position += bytesRead;
601
+ last = chunk[bytesRead - 1];
602
+ }
603
+ return last === 10 || (await handle.read(byte, 0, 1, position)).bytesRead === 0;
450
604
  } finally {
451
605
  await handle.close();
452
606
  }
453
607
  }
454
608
 
455
- /** The plain rollout file with this rollout id under the live, then the archived, sessions folder. */
609
+ /** The rollout file with this rollout id under the live, then the archived, sessions folder (walking lists a plain file instead of its compressed sibling). */
456
610
  async function findRolloutById(home, rolloutId) {
457
611
  for (const folder of ['sessions', 'archived_sessions']) {
458
612
  let rootReal;
@@ -475,23 +629,43 @@ async function findRolloutById(home, rolloutId) {
475
629
  return null;
476
630
  }
477
631
 
632
+ // Size of a compressed file once decompressed, counting no further than `cap`.
633
+ async function decompressedLength(candidate, cap) {
634
+ const handle = await openCandidate(candidate);
635
+ try {
636
+ const chunk = Buffer.allocUnsafe(IMPORT_CHUNK_BYTES);
637
+ let length = 0;
638
+ while (length < cap) {
639
+ const { bytesRead } = await handle.read(chunk, 0, Math.min(chunk.length, cap - length), length);
640
+ if (!bytesRead) break;
641
+ length += bytesRead;
642
+ }
643
+ return length;
644
+ } finally {
645
+ await handle.close();
646
+ }
647
+ }
648
+
478
649
  /**
479
650
  * Rollouts a `history_base` leads to, nearest first, each with the byte offset
480
651
  * its contribution ends at, and `metaBytes`, what reading their metadata took.
481
- * Stops (`partial`) at a base that is missing, unreadable (compressed rollouts
482
- * are not read), not paginated, already visited, past the depth cap, with a
483
- * cutoff that excludes the session metadata, passes the end of the file or
484
- * does not end a record, or that would take the total read (the file, the
652
+ * Cutoffs and byte counts are of the decompressed rollout. Stops (`partial`,
653
+ * the warning code saying why) at a base that is missing or unreadable
654
+ * (`historyUnavailable`), that would take the total read (the file, the
485
655
  * `spent` metadata reads so far, every cutoff and every metadata read) beyond
486
- * `maxFileBytes`.
656
+ * `maxFileBytes` (`historySizeLimit`), or is not paginated, already visited,
657
+ * past the depth cap, with a cutoff that excludes the session metadata,
658
+ * passes the end of the file or does not end a record (`historyPartial`).
487
659
  */
488
660
  async function resolveHistoryChain(candidate, firstBase, { maxFileBytes, maxLineBytes, spent }) {
489
661
  const home = dirname(candidate.root ?? sourceRoot('codex'));
490
662
  const seen = new Set([rolloutIdOf(candidate.path)]);
491
663
  const segments = [];
492
- let used = candidate.size + spent;
664
+ // The file itself is reserved at its decompressed size, which only reading it tells.
665
+ let used =
666
+ (isCompressed(candidate.path) ? await decompressedLength(candidate, maxFileBytes) : candidate.size) + spent;
493
667
  let metaBytes = 0;
494
- const partial = () => ({ segments, partial: true, metaBytes });
668
+ const partial = (warning = IMPORT_WARNING_HISTORY_PARTIAL) => ({ segments, partial: warning, metaBytes });
495
669
  for (let base = firstBase; base; ) {
496
670
  const id = typeof base.thread_id === 'string' ? base.thread_id.toLowerCase() : '';
497
671
  const end = base.end_byte_offset;
@@ -500,13 +674,20 @@ async function resolveHistoryChain(candidate, firstBase, { maxFileBytes, maxLine
500
674
  seen.add(id);
501
675
  if (!Number.isSafeInteger(ordinal) || ordinal <= 0 || !Number.isSafeInteger(end) || end <= 0) return partial();
502
676
  const found = await findRolloutById(home, id);
503
- if (!found || end > found.size || used + end > maxFileBytes) return partial();
677
+ if (!found) return partial(IMPORT_WARNING_HISTORY_UNAVAILABLE);
678
+ if (!isCompressed(found.path) && end > found.size) return partial();
679
+ if (used + end > maxFileBytes) return partial(IMPORT_WARNING_HISTORY_SIZE_LIMIT);
504
680
  let head;
505
681
  try {
506
682
  if (!(await endsOnRecord(found, end))) return partial();
507
683
  head = await firstRecord(found, { maxBytes: Math.min(end, maxFileBytes - used - end), maxLineBytes });
508
- } catch {
509
- return partial();
684
+ } catch (error) {
685
+ // A runtime without zstd names its own fix; any other failure to open or read the base is "unavailable".
686
+ return partial(
687
+ error?.code === IMPORT_ERROR_NEEDS_NEWER_NODE
688
+ ? IMPORT_ERROR_NEEDS_NEWER_NODE
689
+ : IMPORT_WARNING_HISTORY_UNAVAILABLE
690
+ );
510
691
  }
511
692
  used += end + head.bytes;
512
693
  metaBytes += head.bytes;
@@ -515,7 +696,7 @@ async function resolveHistoryChain(candidate, firstBase, { maxFileBytes, maxLine
515
696
  const next = head.record.payload.history_base;
516
697
  base = next && typeof next === 'object' ? next : null;
517
698
  }
518
- return { segments, partial: false, metaBytes };
699
+ return { segments, partial: null, metaBytes };
519
700
  }
520
701
 
521
702
  /**
@@ -524,8 +705,10 @@ async function resolveHistoryChain(candidate, firstBase, { maxFileBytes, maxLine
524
705
  * converter's limits fails the file with `tooLarge` without reading the rest.
525
706
  * A Codex rollout continuing a `history_base` is preceded by the records of
526
707
  * each base up to its cutoff, oldest first (their session metadata dropped),
527
- * all within the one `maxFileBytes`; a base that cannot be followed leaves the
528
- * `historyPartial` warning. `bytesRead` is how far the read got.
708
+ * all within the one `maxFileBytes` (counted in decompressed bytes for a
709
+ * compressed rollout); a base that cannot be followed leaves a `historyPartial`,
710
+ * `historySizeLimit` or `historyUnavailable` warning. `bytesRead` is how far
711
+ * the read got.
529
712
  */
530
713
  export async function convertCandidateFile(
531
714
  candidate,
@@ -553,10 +736,10 @@ export async function convertCandidateFile(
553
736
  const chain =
554
737
  head.record.payload.history_mode === 'paginated'
555
738
  ? await resolveHistoryChain(candidate, base, { maxFileBytes, maxLineBytes, spent: inheritedBytes })
556
- : { segments: [], partial: true, metaBytes: 0 };
739
+ : { segments: [], partial: IMPORT_WARNING_HISTORY_PARTIAL, metaBytes: 0 };
557
740
  inheritedBytes += chain.metaBytes;
558
741
  const { segments, partial } = chain;
559
- if (partial) converter.markHistoryPartial();
742
+ if (partial) converter.markHistoryPartial(partial);
560
743
  for (const { candidate: baseFile, end } of segments.reverse()) {
561
744
  const baseHandle = await openCandidate(baseFile);
562
745
  try {
@@ -587,12 +770,22 @@ export async function convertCandidateFile(
587
770
  }
588
771
  }
589
772
 
773
+ // On a runtime without zstd, a listed conversation whose history base is compressed says so on its row.
774
+ async function withCompressedBaseNotice(candidate, meta) {
775
+ if (!meta.historyBaseId || zstdSupported()) return meta;
776
+ const found = await findRolloutById(dirname(candidate.root ?? sourceRoot('codex')), meta.historyBaseId);
777
+ return found && isCompressed(found.path)
778
+ ? { ...meta, warnings: [...meta.warnings, IMPORT_ERROR_NEEDS_NEWER_NODE] }
779
+ : meta;
780
+ }
781
+
590
782
  function pumpMetaQueue() {
591
783
  while (state.active < META_CONCURRENCY && state.queue.length) {
592
784
  const job = state.queue.shift();
593
785
  state.active += 1;
594
786
  readPrefixMeta(job.candidate)
595
- .catch(() => ({
787
+ .then((meta) => withCompressedBaseNotice(job.candidate, meta))
788
+ .catch((error) => ({
596
789
  foreignSessionId: null,
597
790
  cwd: null,
598
791
  title: null,
@@ -600,7 +793,7 @@ function pumpMetaQueue() {
600
793
  historyBaseId: null,
601
794
  messageCount: null,
602
795
  warnings: [],
603
- errorCode: 'unreadable',
796
+ errorCode: error?.code === IMPORT_ERROR_NEEDS_NEWER_NODE ? IMPORT_ERROR_NEEDS_NEWER_NODE : 'unreadable',
604
797
  }))
605
798
  .then((value) => {
606
799
  state.meta.set(job.candidate.path, { stampKey: stampKey(job.candidate), value });
@@ -675,7 +868,8 @@ function rowFor(candidate, meta, cwdInfo, imported, titles) {
675
868
  return {
676
869
  id: candidate.id,
677
870
  source: candidate.source,
678
- title: displayTitle(meta, titles),
871
+ title: displayTitle(meta, titles, candidate.title),
872
+ starred: candidate.starred === true,
679
873
  cwd: cwdInfo?.path ?? null,
680
874
  modifiedAt: candidate.mtimeMs,
681
875
  messageCount: meta?.messageCount ?? null,
@@ -684,7 +878,7 @@ function rowFor(candidate, meta, cwdInfo, imported, titles) {
684
878
  };
685
879
  }
686
880
 
687
- export async function buildRow(candidate, imported, cwdCache = new Map(), titles = null) {
881
+ async function buildRow(candidate, imported, cwdCache = new Map(), titles = null) {
688
882
  const meta = cachedMeta(candidate);
689
883
  const cwdInfo = meta?.cwd ? await resolveSourceCwd(meta.cwd, cwdCache) : null;
690
884
  return rowFor(candidate, meta, cwdInfo, imported, titles);
@@ -828,7 +1022,10 @@ async function filterCandidates(candidates, filters, imported, titles) {
828
1022
  const cwdInfo = meta.cwd ? await resolveSourceCwd(meta.cwd, cwdCache) : null;
829
1023
  if (
830
1024
  needle &&
831
- !(foldText(displayTitle(meta, titles)).includes(needle) || foldText(cwdInfo?.path).includes(needle))
1025
+ !(
1026
+ foldText(displayTitle(meta, titles, candidate.title)).includes(needle) ||
1027
+ foldText(cwdInfo?.path).includes(needle)
1028
+ )
832
1029
  ) {
833
1030
  continue;
834
1031
  }
@@ -903,7 +1100,7 @@ export async function resolveViewSelection(viewId, excludeIds, imported) {
903
1100
  }
904
1101
 
905
1102
  // ── picked files ─────────────────────────────────────────────────────────────
906
- /** Validate and register a file chosen in a native picker (a local regular .jsonl). */
1103
+ /** Validate and register a file chosen in a native picker (a local regular .jsonl, or a Codex .jsonl.zst). */
907
1104
  export async function registerFile({ source, path } = {}, { imported, limits, env = process.env } = {}) {
908
1105
  requireSource(source);
909
1106
  if (typeof path !== 'string' || !path.trim() || path.includes('\0')) throw importError('invalidPath');
@@ -911,7 +1108,8 @@ export async function registerFile({ source, path } = {}, { imported, limits, en
911
1108
  // Network/device forms are refused before any filesystem call.
912
1109
  if (isNetworkOrDevicePath(requested)) throw importError('unsupported');
913
1110
  if (!isAbsolute(requested)) throw importError('invalidPath');
914
- if (extname(basename(requested)).toLowerCase() !== '.jsonl') throw importError('unsupported');
1111
+ const pickable = (path) => /\.jsonl$/i.test(path) || (source === 'codex' && isCompressed(path));
1112
+ if (!pickable(basename(requested))) throw importError('unsupported');
915
1113
  let real;
916
1114
  let info;
917
1115
  try {
@@ -920,7 +1118,7 @@ export async function registerFile({ source, path } = {}, { imported, limits, en
920
1118
  } catch {
921
1119
  throw importError('unreadable');
922
1120
  }
923
- if (isNetworkOrDevicePath(real) || !info.isFile() || extname(real).toLowerCase() !== '.jsonl') {
1121
+ if (isNetworkOrDevicePath(real) || !info.isFile() || !pickable(basename(real))) {
924
1122
  throw importError('unsupported');
925
1123
  }
926
1124
  const candidate = registerCandidate({
@@ -935,8 +1133,8 @@ export async function registerFile({ source, path } = {}, { imported, limits, en
935
1133
  let conversion;
936
1134
  try {
937
1135
  conversion = await convertCandidateFile(candidate, limits);
938
- } catch {
939
- throw importError('unreadable');
1136
+ } catch (error) {
1137
+ throw importError(error?.code === IMPORT_ERROR_NEEDS_NEWER_NODE ? IMPORT_ERROR_NEEDS_NEWER_NODE : 'unreadable');
940
1138
  }
941
1139
  if (conversion.errorCode) throw importError(conversion.errorCode);
942
1140
  recordConversion(candidate, conversion);
@@ -20,7 +20,10 @@ import {
20
20
  createImportedSession,
21
21
  importOriginKey,
22
22
  } from '../../runtime/agent/orchestrator/session/conversation-import/imported-session.mjs';
23
- import { IMPORT_WARNING_CWD_MISSING } from '../../runtime/agent/orchestrator/session/conversation-import/turns.mjs';
23
+ import {
24
+ IMPORT_ERROR_NEEDS_NEWER_NODE,
25
+ IMPORT_WARNING_CWD_MISSING,
26
+ } from '../../runtime/agent/orchestrator/session/conversation-import/turns.mjs';
24
27
  import { sessionPath } from '../../runtime/agent/orchestrator/session/store/session-paths.mjs';
25
28
  import {
26
29
  cachedMeta,
@@ -140,7 +143,7 @@ const titlesFor = (candidate, context) => (candidate.source === 'codex' ? contex
140
143
  function describeCandidate(candidateId, context) {
141
144
  const candidate = getCandidate(candidateId);
142
145
  return {
143
- title: candidate ? displayTitle(cachedMeta(candidate), titlesFor(candidate, context)) : null,
146
+ title: candidate ? displayTitle(cachedMeta(candidate), titlesFor(candidate, context), candidate.title) : null,
144
147
  sourceName: candidate ? basename(candidate.path) : null,
145
148
  };
146
149
  }
@@ -185,12 +188,16 @@ async function importOne(candidateId, context) {
185
188
  candidate.size = info.size;
186
189
  candidate.mtimeMs = info.mtimeMs;
187
190
  conversion = await convertCandidateFile(candidate, context.limits);
188
- } catch {
189
- return failed(candidateId, 'unreadable');
191
+ } catch (error) {
192
+ return failed(
193
+ candidateId,
194
+ error?.code === IMPORT_ERROR_NEEDS_NEWER_NODE ? IMPORT_ERROR_NEEDS_NEWER_NODE : 'unreadable'
195
+ );
190
196
  }
191
197
  const title = displayTitle(
192
198
  { foreignSessionId: conversion.foreignSessionId, title: listedTitle || conversion.title },
193
- titlesFor(candidate, context)
199
+ titlesFor(candidate, context),
200
+ candidate.title
194
201
  );
195
202
  if (title) conversion = { ...conversion, title };
196
203
  recordConversion(candidate, conversion);
@@ -1,6 +1,15 @@
1
1
  import { markPendingGoalReminder } from '../runtime/agent/orchestrator/runtime-core/goal-reminder.mjs';
2
+ import { adoptLegacyGoalTasks, todoContextBlock } from '../runtime/agent/orchestrator/runtime-core/todo-list.mjs';
3
+ import { SAVE_OUTCOME_SAVED } from '../runtime/agent/orchestrator/session/store/live-state.mjs';
2
4
 
3
- export function createGoalFacadeApi({ agentStatusState, createCurrentSession, getSession, getSessionId, goalRuntime }) {
5
+ export function createGoalFacadeApi({
6
+ agentStatusState,
7
+ createCurrentSession,
8
+ getSession,
9
+ getSessionId,
10
+ goalRuntime,
11
+ persistSession,
12
+ }) {
4
13
  const markGoalReminder = (reason = '') => {
5
14
  try {
6
15
  const pending = markPendingGoalReminder(getSession(), reason);
@@ -14,10 +23,39 @@ export function createGoalFacadeApi({ agentStatusState, createCurrentSession, ge
14
23
  return null;
15
24
  }
16
25
  };
26
+ // A Goal record written before the todo list still carries its tasks: the
27
+ // session's list adopts them, and only once that session is saved does the
28
+ // record let them go. A failed save keeps them on the record, so the next
29
+ // load adopts again (items already listed are skipped, never duplicated).
30
+ const adopting = new Map();
31
+ const adoptLegacyTasks = (sessionId) => {
32
+ if (adopting.has(sessionId)) return adopting.get(sessionId);
33
+ const tasks = goalRuntime.legacyTasks?.(sessionId) || [];
34
+ if (!tasks.length) return null;
35
+ const session = getSession();
36
+ if (session?.id !== sessionId) return null;
37
+ adoptLegacyGoalTasks(session, tasks);
38
+ const adoption = (async () => {
39
+ try {
40
+ // Only an explicit committed write lets the record go: a dropped or
41
+ // stale save resolves too, without the list on disk.
42
+ if ((await persistSession(session)) !== SAVE_OUTCOME_SAVED) return;
43
+ await goalRuntime.clearLegacyTasks(sessionId);
44
+ } catch {
45
+ // Kept on the record; retried on the next load.
46
+ } finally {
47
+ adopting.delete(sessionId);
48
+ }
49
+ })();
50
+ adopting.set(sessionId, adoption);
51
+ return adoption;
52
+ };
17
53
  return {
18
54
  goalStatus() {
19
55
  const sessionId = getSessionId();
20
- return sessionId ? goalRuntime.snapshot(sessionId) : null;
56
+ if (!sessionId) return null;
57
+ adoptLegacyTasks(sessionId);
58
+ return goalRuntime.snapshot(sessionId);
21
59
  },
22
60
  async goalControl(args = {}) {
23
61
  let sessionId = getSessionId();
@@ -31,10 +69,18 @@ export function createGoalFacadeApi({ agentStatusState, createCurrentSession, ge
31
69
  return result;
32
70
  },
33
71
  markGoalReminder,
72
+ /** Settles once a legacy Goal record's tasks are adopted and saved (or kept after a failed save). */
73
+ adoptLegacyGoalTasks(sessionId = getSessionId()) {
74
+ return Promise.resolve(sessionId ? adoptLegacyTasks(sessionId) : null);
75
+ },
34
76
  goalContinuation() {
35
77
  const sessionId = getSessionId();
36
78
  if (!sessionId) return { run: false, reason: 'missing-session', goal: null };
37
- return goalRuntime.continuation(sessionId, { agentStatus: agentStatusState() });
79
+ adoptLegacyTasks(sessionId);
80
+ return goalRuntime.continuation(sessionId, {
81
+ agentStatus: agentStatusState(),
82
+ todo: todoContextBlock(getSession(), 'Todo list for this Goal (exact wordings):', { whole: true }),
83
+ });
38
84
  },
39
85
  goalTurnStarted() {
40
86
  const sessionId = getSessionId();
@@ -523,7 +523,7 @@ export function turnSlice(messages, { runId = '', since = 0 } = {}) {
523
523
  * what its final reply names, then media/office/visualize outputs, then the
524
524
  * files it edited. `written`: only the files it created or modified (no
525
525
  * reply paths, no visualize open targets). */
526
- export function turnArtifactCandidates(messages, { written = false } = {}) {
526
+ function turnArtifactCandidates(messages, { written = false } = {}) {
527
527
  const list = Array.isArray(messages) ? messages : [];
528
528
  const reply = list.findLast((message) => message?.role === 'assistant' && textOf(message.content).trim());
529
529
  const produced = [];