mixdog 1.2.5 → 1.2.6

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 (290) hide show
  1. package/package.json +1 -1
  2. package/scripts/lib/gate-scheduler.mjs +2 -2
  3. package/scripts/lib/run-node-tests.mjs +5 -14
  4. package/scripts/provider-pingpong-live.mjs +9 -9
  5. package/src/agents/advisor/AGENT.md +4 -4
  6. package/src/agents/advisor/agent.json +1 -1
  7. package/src/agents/reviewer/AGENT.md +2 -3
  8. package/src/agents/reviewer/agent.json +1 -1
  9. package/src/defaults/shipped-history.json +10 -0
  10. package/src/defaults/skills/browser-use/SKILL.md +2 -1
  11. package/src/defaults/skills/computer-use/SKILL.md +3 -1
  12. package/src/defaults/skills/visualize/SKILL.md +3 -2
  13. package/src/lib/rules-builder.cjs +1 -1
  14. package/src/output-styles/common.md +22 -6
  15. package/src/output-styles/detailed.md +7 -5
  16. package/src/output-styles/minimal.md +7 -3
  17. package/src/output-styles/simple.md +2 -3
  18. package/src/rules/agent/AGENT.md +3 -1
  19. package/src/rules/lead/LEAD.md +4 -3
  20. package/src/rules/shared/10-tool-workflow.md +2 -1
  21. package/src/rules/shared/60-verification.md +4 -5
  22. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
  23. package/src/runtime/agent/orchestrator/config.mjs +6 -0
  24. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +1 -1
  25. package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
  26. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +53 -60
  27. package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
  28. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
  29. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +40 -19
  31. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
  32. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
  33. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
  34. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
  35. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
  36. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
  37. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +1 -2
  38. package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
  39. package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
  40. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
  41. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
  42. package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
  43. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
  44. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
  45. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  46. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
  47. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  48. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  49. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
  50. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
  51. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
  52. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  53. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
  54. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  55. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
  56. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
  57. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
  58. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
  59. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
  60. package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
  61. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
  62. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
  63. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
  64. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
  65. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
  66. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
  67. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
  68. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
  69. package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
  70. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +2 -3
  71. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +3 -8
  72. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
  73. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
  74. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
  75. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
  76. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
  77. package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
  78. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
  79. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +9 -19
  80. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -3
  81. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -0
  82. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
  83. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
  84. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
  85. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
  86. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
  87. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
  88. package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
  89. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
  90. package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
  91. package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
  92. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
  93. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
  94. package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
  95. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
  96. package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
  97. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
  98. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +306 -0
  99. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +70 -21
  100. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
  101. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
  102. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
  103. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
  104. package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
  105. package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
  106. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
  107. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
  108. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
  109. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
  111. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
  112. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
  113. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
  114. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
  115. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
  116. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
  117. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
  118. package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
  119. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
  120. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
  121. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
  122. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
  123. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
  124. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
  125. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
  126. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
  127. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
  128. package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
  129. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
  130. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
  131. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
  132. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
  133. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
  134. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
  135. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
  136. package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
  137. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +119 -32
  138. package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
  139. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
  140. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
  141. package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
  142. package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
  143. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
  144. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
  145. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
  146. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  147. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
  148. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +40 -2
  149. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -2
  150. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
  151. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +3 -1
  153. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
  154. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +35 -4
  155. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
  156. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
  157. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
  158. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  159. package/src/runtime/attachments/office-extract.mjs +11 -9
  160. package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
  161. package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
  162. package/src/runtime/memory/lib/tool-call-handler.mjs +7 -5
  163. package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
  164. package/src/runtime/office/core/tabular.mjs +1 -1
  165. package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
  166. package/src/runtime/office/portable/docx-formatting.mjs +1 -1
  167. package/src/runtime/office/portable/docx-runs.mjs +1 -1
  168. package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
  169. package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
  170. package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
  171. package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
  172. package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
  173. package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
  174. package/src/runtime/office/portable/portable-opc.mjs +27 -13
  175. package/src/runtime/office/portable/portable-pivot.mjs +3 -3
  176. package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
  177. package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
  178. package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
  179. package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
  180. package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
  181. package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
  182. package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
  183. package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
  184. package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
  185. package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
  186. package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
  187. package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
  188. package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
  189. package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
  190. package/src/runtime/office/portable/portable-xml.mjs +1 -1
  191. package/src/runtime/shared/atomic-file.mjs +22 -13
  192. package/src/runtime/shared/background-tasks.mjs +60 -20
  193. package/src/runtime/shared/child-spawn-gate.mjs +26 -16
  194. package/src/runtime/shared/config.mjs +0 -10
  195. package/src/runtime/shared/file-lock.mjs +7 -1
  196. package/src/runtime/shared/file-permissions-worker.mjs +38 -0
  197. package/src/runtime/shared/file-permissions.d.mts +19 -4
  198. package/src/runtime/shared/file-permissions.mjs +310 -4
  199. package/src/runtime/shared/git-runner-worker.mjs +6 -78
  200. package/src/runtime/shared/llm/http-agent.mjs +7 -3
  201. package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
  202. package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
  203. package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
  204. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
  205. package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
  206. package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
  207. package/src/runtime/shared/memory-snapshot.mjs +5 -1
  208. package/src/runtime/shared/notify-trace.mjs +8 -1
  209. package/src/runtime/shared/pristine-execution-contract.json +5 -1
  210. package/src/runtime/shared/process-runner-worker.mjs +7 -0
  211. package/src/runtime/shared/process-runner.mjs +38 -0
  212. package/src/runtime/shared/provider-accounts.mjs +2 -1
  213. package/src/runtime/shared/provider-api-key.mjs +0 -1
  214. package/src/runtime/shared/read-row-numbers.mjs +1 -1
  215. package/src/runtime/shared/resource-admission.mjs +60 -18
  216. package/src/runtime/shared/run-child.mjs +84 -0
  217. package/src/runtime/shared/session-activity-signal.mjs +23 -0
  218. package/src/runtime/shared/shell-output-summary.mjs +23 -0
  219. package/src/runtime/shared/singleton-owner.mjs +126 -42
  220. package/src/runtime/shared/tool-output-limit.mjs +4 -2
  221. package/src/runtime/shared/tool-output-marker.mjs +58 -0
  222. package/src/runtime/shared/user-data-guard.mjs +28 -9
  223. package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
  224. package/src/runtime/shared/worktrees/git-head.mjs +20 -2
  225. package/src/runtime/shared/worktrees/lock.mjs +3 -2
  226. package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
  227. package/src/runtime/tidy/runners/biome.mjs +3 -1
  228. package/src/runtime/tidy/shadow.mjs +2 -1
  229. package/src/runtime/web-search/index.mjs +5 -7
  230. package/src/runtime/web-search/lib/formatter.mjs +42 -6
  231. package/src/runtime/web-search/tool-defs.mjs +6 -1
  232. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
  233. package/src/session-runtime/lifecycle/session-switch/resume.mjs +7 -4
  234. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
  235. package/src/session-runtime/lifecycle/shared.mjs +19 -2
  236. package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
  237. package/src/session-runtime/lifecycle/teardown.mjs +5 -2
  238. package/src/session-runtime/lifecycle-api.mjs +3 -1
  239. package/src/session-runtime/provider-auth/login.mjs +10 -6
  240. package/src/session-runtime/provider-auth/setup.mjs +19 -2
  241. package/src/session-runtime/provider-catalog-cache.mjs +101 -25
  242. package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
  243. package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
  244. package/src/session-runtime/provider-models.mjs +76 -10
  245. package/src/session-runtime/provider-readiness.mjs +4 -0
  246. package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
  247. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
  248. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
  249. package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
  250. package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
  251. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
  252. package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
  253. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
  254. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
  255. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
  256. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
  257. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
  258. package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
  259. package/src/session-runtime/services/agent-tool.mjs +20 -0
  260. package/src/session-runtime/services/provider-admin.mjs +92 -20
  261. package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
  262. package/src/session-runtime/services/usage-dashboard.mjs +27 -69
  263. package/src/session-runtime/turn/session-ops.mjs +2 -2
  264. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  265. package/src/session-runtime/usage-stats-api.mjs +6 -1
  266. package/src/standalone/channel-transport/http-routes.mjs +10 -9
  267. package/src/standalone/daemon-desktop-runtime.mjs +20 -7
  268. package/src/standalone/daemon-owner.mjs +117 -25
  269. package/src/standalone/daemon.mjs +43 -13
  270. package/src/standalone/session-call-cache.mjs +6 -0
  271. package/src/standalone/session-protocol.mjs +1 -1
  272. package/src/standalone/session-service/retention/busy.mjs +7 -2
  273. package/src/standalone/session-transport/routes.mjs +7 -6
  274. package/src/tui/app/model-options.mjs +39 -2
  275. package/src/tui/app/model-picker.mjs +16 -2
  276. package/src/tui/app/provider-setup-picker.mjs +1 -2
  277. package/src/tui/dist/index.mjs +385 -104
  278. package/src/tui/session/notice-text.mjs +0 -1
  279. package/src/tui/session/session-api/intake/submission.mjs +7 -13
  280. package/src/tui/session/session-api/integrations.mjs +1 -5
  281. package/src/tui/session/session-flow/drain.mjs +8 -0
  282. package/src/tui/session/session-flow/steering.mjs +46 -0
  283. package/src/tui/session/session-flow.mjs +2 -0
  284. package/src/tui/session/turn-stream.mjs +33 -0
  285. package/src/tui/session/turn.mjs +30 -3
  286. package/src/ui/statusline.mjs +1 -6
  287. package/src/ui/streaming-markdown-heal.mjs +24 -7
  288. package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
  289. package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
  290. package/src/workflows/default/WORKFLOW.md +9 -13
@@ -49,6 +49,17 @@ function sameFileStat(left, right) {
49
49
  );
50
50
  }
51
51
 
52
+ // The file at `fileStat` provably still holds the bytes read under `known`.
53
+ const settledSameFile = (known, fileStat, now) =>
54
+ sameFileStat(known, fileStat) && now - Math.max(fileStat.mtimeMs, fileStat.ctimeMs) > SETTLED_FILE_AGE_MS;
55
+
56
+ /** Content identity of a record's text. UTF-16 preserves exact JavaScript
57
+ * code units, including lone surrogates that UTF-8 would collapse into the
58
+ * same replacement character. */
59
+ export function transcriptTextHash(text) {
60
+ return createHash('sha256').update(text, 'utf16le').digest('hex');
61
+ }
62
+
52
63
  let stampSequence = 0;
53
64
  const stampEpoch = `${process.pid}:${Date.now().toString(36)}`;
54
65
 
@@ -72,6 +83,9 @@ export function createStoredTranscriptCache({
72
83
  const entries = new Map();
73
84
  /** key -> { text, fingerprint, promise } for reads still parsing. */
74
85
  const inFlight = new Map();
86
+ /** key -> { fingerprint, fileStat, promise } for reads not yet answered,
87
+ * from before their body is loaded. */
88
+ const reading = new Map();
75
89
  /** Keys evicted for space (insertion order = age), bounded. */
76
90
  const ghosts = new Set();
77
91
  let retainedBytes = 0;
@@ -143,59 +157,135 @@ export function createStoredTranscriptCache({
143
157
  }
144
158
  };
145
159
 
160
+ // The cached entry, when it still holds content identified by `digest`.
161
+ const entryWithContent = (key, fingerprint, digest) => {
162
+ const entry = entries.get(key);
163
+ return entry &&
164
+ entry.fingerprint === fingerprint &&
165
+ entry.textChars === digest.textChars &&
166
+ entry.textHash === digest.textHash
167
+ ? entry
168
+ : null;
169
+ };
170
+
171
+ // `project(known)` reads, digests and projects the record elsewhere (a
172
+ // worker thread) in one step: `{ textChars, textHash, value }`, or
173
+ // `{ textChars, textHash, same: true }` without a projection when the
174
+ // content is the `known` digest of the cached entry; null when the record
175
+ // cannot be read. Undefined when it could not answer at all.
176
+ async function readProjected({ key, group, fingerprint, fileStat, project, now }) {
177
+ for (let attempt = 0; attempt < 2; attempt += 1) {
178
+ const cached = entries.get(key);
179
+ const known =
180
+ attempt === 0 && cached?.fingerprint === fingerprint
181
+ ? { textChars: cached.textChars, textHash: cached.textHash }
182
+ : null;
183
+ // A newer read of this key, clear or forget replaces or drops the
184
+ // record; only a still-current answer may then be remembered.
185
+ const record = { text: null, fingerprint, promise: null };
186
+ inFlight.set(key, record);
187
+ let answer;
188
+ try {
189
+ answer = await project(known);
190
+ } catch {
191
+ answer = undefined;
192
+ }
193
+ const current = inFlight.get(key) === record;
194
+ if (current) inFlight.delete(key);
195
+ if (answer === undefined) return undefined;
196
+ if (answer === null || typeof answer !== 'object') return { value: null, hit: false, read: true };
197
+ if (answer.same === true) {
198
+ const entry = entryWithContent(key, fingerprint, answer);
199
+ // Evicted meanwhile: project it after all.
200
+ if (!entry) continue;
201
+ entry.fileStat = fileStat;
202
+ touch(key, entry, now);
203
+ return { value: entry.value, hit: true, read: true };
204
+ }
205
+ const value = answer.value ?? null;
206
+ if (current && value && typeof value === 'object') {
207
+ remember(key, group, answer.textChars, answer.textHash, fingerprint, fileStat, value, now);
208
+ }
209
+ return { value, hit: false, read: true };
210
+ }
211
+ return undefined;
212
+ }
213
+
214
+ async function readFresh({ key, group, fingerprint, fileStat, loadText, produce, project, now }) {
215
+ if (typeof project === 'function') {
216
+ const answered = await readProjected({ key, group, fingerprint, fileStat, project, now });
217
+ if (answered !== undefined) return answered;
218
+ // It could not answer (worker unavailable): load and produce here.
219
+ }
220
+ const cached = entries.get(key);
221
+ // `loadText` may answer asynchronously (a large record is read without
222
+ // blocking the loop); a plain string is unchanged.
223
+ let text = loadText();
224
+ if (typeof text?.then === 'function') text = await text;
225
+ if (typeof text !== 'string') return { value: null, hit: false, read: true };
226
+ const textHash = transcriptTextHash(text);
227
+ if (cached && entryWithContent(key, fingerprint, { textChars: text.length, textHash }) === cached) {
228
+ cached.fileStat = fileStat;
229
+ touch(key, cached, now);
230
+ return { value: cached.value, hit: true, read: true };
231
+ }
232
+ const pending = inFlight.get(key);
233
+ if (pending && pending.fingerprint === fingerprint && pending.text === text) {
234
+ return { value: await pending.promise, hit: true, read: true };
235
+ }
236
+ const record = { text, fingerprint, promise: null };
237
+ const promise = (async () => {
238
+ const value = await produce(text);
239
+ if (inFlight.get(key) === record && value && typeof value === 'object') {
240
+ remember(key, group, text.length, textHash, fingerprint, fileStat, value, now);
241
+ }
242
+ return value;
243
+ })();
244
+ record.promise = promise;
245
+ inFlight.set(key, record);
246
+ try {
247
+ return { value: await promise, hit: false, read: true };
248
+ } finally {
249
+ if (inFlight.get(key) === record) inFlight.delete(key);
250
+ }
251
+ }
252
+
146
253
  return {
147
254
  /** The cached projection for this exact content, or a fresh one from
148
- * `produce`. `loadText` runs only when stat alone cannot vouch for
149
- * the entry. Concurrent callers with the same content share one parse.
255
+ * `project` (when given and able to answer) or `produce`. `loadText` /
256
+ * `project` run only when stat alone cannot vouch for the entry.
257
+ * Concurrent callers with the same content share one parse; callers of
258
+ * one unchanged, settled file share one read before it is even loaded.
150
259
  * Entries naming the same `group` replace each other. */
151
- async read({ key, group = null, fingerprint, fileStat = null, loadText, produce, now = Date.now() }) {
260
+ async read({
261
+ key,
262
+ group = null,
263
+ fingerprint,
264
+ fileStat = null,
265
+ loadText,
266
+ produce,
267
+ project = null,
268
+ now = Date.now(),
269
+ }) {
152
270
  trimIdle(now);
153
271
  const cached = entries.get(key);
154
- if (
155
- cached &&
156
- cached.fingerprint === fingerprint &&
157
- sameFileStat(cached.fileStat, fileStat) &&
158
- now - Math.max(fileStat.mtimeMs, fileStat.ctimeMs) > SETTLED_FILE_AGE_MS
159
- ) {
272
+ if (cached && cached.fingerprint === fingerprint && settledSameFile(cached.fileStat, fileStat, now)) {
160
273
  touch(key, cached, now);
161
274
  return { value: cached.value, hit: true, read: false };
162
275
  }
163
- // `loadText` may answer asynchronously (a large record is read without
164
- // blocking the loop); a plain string is unchanged.
165
- let text = loadText();
166
- if (typeof text?.then === 'function') text = await text;
167
- if (typeof text !== 'string') return { value: null, hit: false, read: true };
168
- // UTF-16 preserves exact JavaScript code units, including lone surrogates
169
- // that UTF-8 would collapse into the same replacement character.
170
- const textHash = createHash('sha256').update(text, 'utf16le').digest('hex');
171
- if (
172
- cached &&
173
- cached.fingerprint === fingerprint &&
174
- cached.textChars === text.length &&
175
- cached.textHash === textHash
176
- ) {
177
- cached.fileStat = fileStat;
178
- touch(key, cached, now);
179
- return { value: cached.value, hit: true, read: true };
180
- }
181
- const pending = inFlight.get(key);
182
- if (pending && pending.fingerprint === fingerprint && pending.text === text) {
183
- return { value: await pending.promise, hit: true, read: true };
276
+ const joined = reading.get(key);
277
+ if (joined && joined.fingerprint === fingerprint && settledSameFile(joined.fileStat, fileStat, now)) {
278
+ const { value } = await joined.promise;
279
+ // A read that found nothing is not shared: this caller learns why itself.
280
+ if (value) return { value, hit: true, read: false };
184
281
  }
185
- const record = { text, fingerprint, promise: null };
186
- const promise = (async () => {
187
- const value = await produce(text);
188
- if (inFlight.get(key) === record && value && typeof value === 'object') {
189
- remember(key, group, text.length, textHash, fingerprint, fileStat, value, now);
190
- }
191
- return value;
192
- })();
193
- record.promise = promise;
194
- inFlight.set(key, record);
282
+ const record = { fingerprint, fileStat, promise: null };
283
+ record.promise = readFresh({ key, group, fingerprint, fileStat, loadText, produce, project, now });
284
+ reading.set(key, record);
195
285
  try {
196
- return { value: await promise, hit: false, read: true };
286
+ return await record.promise;
197
287
  } finally {
198
- if (inFlight.get(key) === record) inFlight.delete(key);
288
+ if (reading.get(key) === record) reading.delete(key);
199
289
  }
200
290
  },
201
291
  /** The last view of these projections left: they turn idle now and stay
@@ -207,8 +297,10 @@ export function createStoredTranscriptCache({
207
297
  trimIdle(now);
208
298
  },
209
299
  forget(keyPrefix) {
210
- for (const key of inFlight.keys()) {
211
- if (key.startsWith(keyPrefix)) inFlight.delete(key);
300
+ for (const pending of [inFlight, reading]) {
301
+ for (const key of pending.keys()) {
302
+ if (key.startsWith(keyPrefix)) pending.delete(key);
303
+ }
212
304
  }
213
305
  for (const key of [...entries.keys()]) {
214
306
  if (key.startsWith(keyPrefix)) drop(key);
@@ -220,11 +312,18 @@ export function createStoredTranscriptCache({
220
312
  clear() {
221
313
  entries.clear();
222
314
  inFlight.clear();
315
+ reading.clear();
223
316
  ghosts.clear();
224
317
  retainedBytes = 0;
225
318
  },
226
319
  stats() {
227
- return { entries: entries.size, retainedBytes, inFlight: inFlight.size };
320
+ return {
321
+ entries: entries.size,
322
+ retainedBytes,
323
+ inFlight: inFlight.size,
324
+ reading: reading.size,
325
+ ghosts: ghosts.size,
326
+ };
228
327
  },
229
328
  };
230
329
  }
@@ -19,6 +19,14 @@ import { dataDir } from './store-summary-locations.mjs';
19
19
  /** The parse/recovery/projection body of a stored transcript read. Runs once
20
20
  * per distinct content; its result is shared read-only through the cache. */
21
21
  export async function projectStoredTranscript(sessionId, doc, options) {
22
+ return windowStoredTranscript(sessionId, await prepareStoredTranscriptBase(sessionId, doc, options), options);
23
+ }
24
+
25
+ /** The window-independent half of a projection: recovery, the prepared
26
+ * session and its whole-transcript context gauge. Every transcript window of
27
+ * the same content is cut from one base (windowStoredTranscript), which
28
+ * never mutates it. */
29
+ export async function prepareStoredTranscriptBase(sessionId, doc, options) {
22
30
  let session = doc;
23
31
  if (!options.checkpointAbsent) {
24
32
  const { projectTurnCheckpointMessages, readTurnCheckpoint } = await import('./manager/turn-checkpoint.mjs');
@@ -37,7 +45,7 @@ export async function projectStoredTranscript(sessionId, doc, options) {
37
45
  if (session?.activeTurnCheckpoint) projectCheckpoint();
38
46
  }
39
47
  }
40
- const { restoreTranscriptItems, sessionContextSnapshotProjection } = await import('./transcript-restore/restore.mjs');
48
+ const { sessionContextSnapshotProjection } = await import('./transcript-restore/restore.mjs');
41
49
  let preparedContextProjection = null;
42
50
  try {
43
51
  const [{ prepareSessionProjection }, { createContextStatus }, { primeContextEstimates }] = await Promise.all([
@@ -81,6 +89,28 @@ export async function projectStoredTranscript(sessionId, doc, options) {
81
89
  rawAutoCompactTokenLimit && (!displayContextWindow || rawAutoCompactTokenLimit < displayContextWindow)
82
90
  ? rawAutoCompactTokenLimit
83
91
  : 0;
92
+ return {
93
+ session,
94
+ messages,
95
+ contextFields: preparedContextProjection
96
+ ? {
97
+ ...preparedContextProjection,
98
+ preparedContextProjection: true,
99
+ }
100
+ : {
101
+ stats: measuredStats,
102
+ contextWindow: contextWindow || null,
103
+ rawContextWindow: rawContextWindow || null,
104
+ displayContextWindow: displayContextWindow || null,
105
+ autoCompactTokenLimit: autoCompactTokenLimit || null,
106
+ },
107
+ };
108
+ }
109
+
110
+ /** One transcript window (`options.itemLimit`, default whole) of a base. */
111
+ export async function windowStoredTranscript(sessionId, base, options) {
112
+ const { session, messages, contextFields } = base;
113
+ const { restoreTranscriptItems } = await import('./transcript-restore/restore.mjs');
84
114
  // Restoring one item past a finite limit proves whether older history exists
85
115
  // without projecting it; restore ids are message-positional, so the kept
86
116
  // tail is identical either way.
@@ -115,17 +145,6 @@ export async function projectStoredTranscript(sessionId, doc, options) {
115
145
  cwd: session.cwd || '',
116
146
  desktopSession: desktopSession(session.desktopSession, session.cwd),
117
147
  workflow: session.workflow || null,
118
- ...(preparedContextProjection
119
- ? {
120
- ...preparedContextProjection,
121
- preparedContextProjection: true,
122
- }
123
- : {
124
- stats: measuredStats,
125
- contextWindow: contextWindow || null,
126
- rawContextWindow: rawContextWindow || null,
127
- displayContextWindow: displayContextWindow || null,
128
- autoCompactTokenLimit: autoCompactTokenLimit || null,
129
- }),
148
+ ...contextFields,
130
149
  };
131
150
  }