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
@@ -5,6 +5,7 @@
5
5
  import { READ_MAX_LINE_COLLECT_BYTES } from './read-constants.mjs';
6
6
  import { renderReadLine } from './read-formatting.mjs';
7
7
  import { maybeRecordReadRangeAnchor } from './read-range-index.mjs';
8
+ import { capMarker, windowMarker } from './tool-output-limit.mjs';
8
9
 
9
10
  export function createReadLineCollector({ offset, limit, bodyOutputBytes, rangeIndex, startLine, fileSize = 0 }) {
10
11
  const collected = [];
@@ -148,10 +149,11 @@ export function createReadLineCollector({ offset, limit, bodyOutputBytes, rangeI
148
149
  let out = collected.join('\n');
149
150
  if (truncated) {
150
151
  const nextOffset = (lastEmitted || offset) + readOffsetBase;
151
- const ofFile = fileSize > 0 ? ` of a ${Math.max(1, Math.round(fileSize / 1024))} KB file` : '';
152
- out += `\n\n... [output truncated at ${Math.max(1, Math.round(maxOutputBytes / 1024))} KB${ofFile}; pass offset:${nextOffset} to continue] ...`;
152
+ const ofFile = fileSize > 0 ? `${Math.max(1, Math.round(fileSize / 1024))} KB file` : '';
153
+ out += `\n\n${capMarker({ limit: maxOutputBytes, shown: ofFile, nextOffset })}`;
153
154
  } else if (stoppedAtLimit) {
154
- out += `${out ? '\n' : ''}... [range limit reached; next offset: ${offset + collected.length + readOffsetBase}]`;
155
+ const nextOffset = offset + collected.length + readOffsetBase;
156
+ out += `${out ? '\n' : ''}${windowMarker({ from: offset + 1, to: offset + collected.length, nextOffset })}`;
155
157
  } else if (!out && offset >= lineIdx) {
156
158
  out = `(no lines in range; file has ${lineIdx} lines)`;
157
159
  }
@@ -9,6 +9,7 @@ import { readFile } from 'node:fs/promises';
9
9
  import { sameFileVersion } from './file-version.mjs';
10
10
  import { canCacheReadFile, READ_PREFIX_HASH_BYTES } from './read-cache-policy.mjs';
11
11
  import { decodeUtf16Body, isUtf16Encoding } from './snapshot-helpers.mjs';
12
+ import { capMarker, windowMarker } from './tool-output-limit.mjs';
12
13
 
13
14
  /**
14
15
  * Encoding-aware decode (fresh read AND raw-content cache hit both flow
@@ -51,17 +52,27 @@ function rangeFooter(ctx, render, rendered) {
51
52
  const emittedStart = offset + 1;
52
53
  if (byteCapTruncated) {
53
54
  const emittedEnd = offset + renderedLineCount;
54
- const capKb = Math.round(readMaxOutputBytes / 1024);
55
- const more = emittedEnd < lineCount ? `; pass offset:${emittedEnd + readOffsetBase} to continue` : '';
56
- return { footer: `[lines ${emittedStart}-${emittedEnd} of ${lineCount}; output truncated at ${capKb} KB${more}]` };
55
+ return {
56
+ footer: windowMarker({
57
+ from: emittedStart,
58
+ to: emittedEnd,
59
+ total: lineCount,
60
+ capBytes: readMaxOutputBytes,
61
+ nextOffset: emittedEnd < lineCount ? emittedEnd + readOffsetBase : null,
62
+ }),
63
+ };
57
64
  }
58
65
  if (Buffer.byteLength(rendered, 'utf8') > readMaxOutputBytes) return {};
59
66
  const emittedEnd = offset + sliced.length;
60
67
  // Continuation uses the originating caller's coordinate base. Remaining
61
68
  // content is not automatically required evidence; when it is, it fits one
62
69
  // wider read, not a walk window by window.
63
- const more = emittedEnd < lineCount ? `; pass offset:${emittedEnd + readOffsetBase} to continue` : '';
64
- const footer = `[lines ${emittedStart}-${emittedEnd} of ${lineCount}${more}]`;
70
+ const footer = windowMarker({
71
+ from: emittedStart,
72
+ to: emittedEnd,
73
+ total: lineCount,
74
+ nextOffset: emittedEnd < lineCount ? emittedEnd + readOffsetBase : null,
75
+ });
65
76
  return { footer: widenNote ? `${footer}\n${widenNote}` : footer };
66
77
  }
67
78
 
@@ -110,8 +121,15 @@ function renderReadWindow(content, ctx, helpers) {
110
121
  const slice = byteCapSlice(rendered, readMaxOutputBytes);
111
122
  render.renderedLineCount = Math.max(0, slice.split('\n').length - 1);
112
123
  render.byteCapTruncated = true;
113
- const ofFile = st?.size > 0 ? ` of a ${Math.max(1, Math.round(st.size / 1024))} KB file` : '';
114
- out = `${slice}\n\n... [output truncated at ${Math.round(readMaxOutputBytes / 1024)} KB${ofFile}] ...`;
124
+ const ofFile = st?.size > 0 ? `${Math.max(1, Math.round(st.size / 1024))} KB file` : '';
125
+ // A windowed read's footer already carries the cap and continuation.
126
+ out = hasRangeArgs
127
+ ? slice
128
+ : `${slice}\n\n${capMarker({
129
+ limit: readMaxOutputBytes,
130
+ shown: ofFile ? `${render.renderedLineCount} of ${lineCount} lines shown (${ofFile})` : '',
131
+ nextOffset: offset + render.renderedLineCount + ctx.readOffsetBase,
132
+ })}`;
115
133
  } else {
116
134
  out = rendered;
117
135
  }
@@ -1,6 +1,7 @@
1
1
  import { readFile, stat } from 'node:fs/promises';
2
2
  import { MAX_PDF_BYTES, MAX_PDF_PAGES, isPdfBuffer } from '../../../../attachments/limits.mjs';
3
3
  import { READ_MAX_SIZE_BYTES } from './read-constants.mjs';
4
+ import { capMarker } from './tool-output-limit.mjs';
4
5
  import { imageBlocksFromBuffer } from './read-image-resize.mjs';
5
6
  import { inspectPdfBuffer } from '../../../../attachments/pdf-extract.mjs';
6
7
 
@@ -190,7 +191,7 @@ function capNotebookText(blocks, maxOutputBytes) {
190
191
  if (truncated) {
191
192
  capped.push({
192
193
  type: 'text',
193
- text: `\n\n... [notebook output truncated at ${Math.round(maxOutputBytes / 1024)} KB]`,
194
+ text: `\n\n${capMarker({ limit: maxOutputBytes, shown: 'notebook cells cut', narrow: 'grep the notebook for the cell text you need' })}`,
194
195
  });
195
196
  }
196
197
  return capped;
@@ -27,7 +27,9 @@ const bodyTextFor = (value) => {
27
27
  .join('\n');
28
28
  };
29
29
 
30
- const TRUNCATED_MARKER = /\[TRUNCATED (?:—|-) (\d+) lines \/ (\d+) KB;/;
30
+ // The smart-read cap marker (read-formatting.mjs buildSmartReadTruncationMarker):
31
+ // `[output capped at X; lines a-b of N omitted (K KB file); offset:a for more]`.
32
+ const TRUNCATED_MARKER = /\[output capped at [^;\]]+; lines \d+-\d+ of (\d+) omitted \((\d+) KB file\);/;
31
33
  // When `read` emitted a smart-cap marker, surface the truncation state in the
32
34
  // header so downstream skimming spots it without parsing the body.
33
35
  const truncatedSuffix = (textBody) => {
@@ -1,4 +1,5 @@
1
1
  import { statSync } from 'node:fs';
2
+ import { capMarker, windowMarker } from './tool-output-limit.mjs';
2
3
  import { isAbsolute, resolve } from 'node:path';
3
4
  import { expandAbsoluteGlobs } from './lib/absolute-glob-expand.mjs';
4
5
  import { buildGlobPatternGroups } from './lib/glob-static-prefix.mjs';
@@ -407,17 +408,22 @@ async function orderGlobPaths(unique, { nativeMtimeTotal, groupCount, sortMode,
407
408
 
408
409
  function globIntegritySuffix({ accumTruncated, rgStdoutTruncated, rgStdoutPartial, rgErrors }) {
409
410
  let truncSuffix = '';
410
- if (accumTruncated) truncSuffix = `\n... [truncated at accumulation cap (${GLOB_ACCUM_CAP})]`;
411
- if (rgStdoutTruncated) truncSuffix += '\n... [truncated at rg stdout cap (20MB); results incomplete]';
411
+ const narrow = 'narrow the pattern or path';
412
+ if (accumTruncated) {
413
+ truncSuffix = `\n${capMarker({ limit: `${GLOB_ACCUM_CAP} matches`, shown: 'results incomplete', narrow })}`;
414
+ }
415
+ if (rgStdoutTruncated) {
416
+ truncSuffix += `\n${capMarker({ limit: '20 MB of rg stdout', shown: 'results incomplete', narrow })}`;
417
+ }
412
418
  if (rgStdoutPartial) truncSuffix += '\n... [warning] rg exit 2 (partial results); listing may be incomplete';
413
419
  const errorSuffix = rgErrors.length > 0 ? `\n... [warning] ${rgErrors.join(' | ')}` : '';
414
420
  return errorSuffix + truncSuffix;
415
421
  }
416
422
 
417
- function globMoreSuffix({ rgWindowIncomplete, remaining, totalBeforeOffset, nextOffset }) {
418
- if (rgWindowIncomplete) return `\n... [more entries available — pass offset:${nextOffset} to continue]`;
423
+ function globMoreSuffix({ rgWindowIncomplete, remaining, totalBeforeOffset, from, nextOffset }) {
424
+ if (rgWindowIncomplete) return `\n${windowMarker({ unit: 'entries', from, to: nextOffset, nextOffset })}`;
419
425
  if (remaining > 0) {
420
- return `\n... [${remaining} more entries of ${totalBeforeOffset} total — pass offset:${nextOffset} to continue]`;
426
+ return `\n${windowMarker({ unit: 'entries', from, to: nextOffset, total: totalBeforeOffset, nextOffset })}`;
421
427
  }
422
428
  return '';
423
429
  }
@@ -489,6 +495,7 @@ async function renderGlobPage(scan, merged, { capped, remaining, totalBeforeOffs
489
495
  rgWindowIncomplete: merged.rgWindowIncomplete,
490
496
  remaining,
491
497
  totalBeforeOffset,
498
+ from: offset + 1,
492
499
  nextOffset: offset + capped.length,
493
500
  });
494
501
  if (capped.length > 0) return `${capped.join('\n')}${moreSuffix}${errSuffix}`;
@@ -1,5 +1,5 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { isAbsolute } from 'node:path';
2
+ import { isAbsolute, resolve as resolvePath, sep as pathSep } from 'node:path';
3
3
  import {
4
4
  coerceReadFamilyPathArg,
5
5
  GREP_AUTO_CONTEXT_LINES,
@@ -12,6 +12,7 @@ import {
12
12
  appendNotFoundCwdNote,
13
13
  buildNotFoundHintBody,
14
14
  finalizeReadFamilyEnoentTail,
15
+ realRootOf,
15
16
  } from './search-path-diagnostics.mjs';
16
17
  import { buildGrepCacheKey, buildGrepRgArgs } from './search-builders.mjs';
17
18
  import { runRg, runRgWindowedLines } from './native-search-runner.mjs';
@@ -498,10 +499,7 @@ async function runLegacyContextGrep(scope, rgArgs) {
498
499
  async function runPlainGrep(scope, rgArgs, effectiveHeadLimit) {
499
500
  const { options, outputMode, headLimit, offset, cacheKey, grepResolvedPath } = scope;
500
501
  const window = await collectGrepWindow(scope, rgArgs, effectiveHeadLimit);
501
- let { windowed } = window;
502
- if (outputMode === 'files_with_matches' && windowed.length > 1) {
503
- windowed = await sortNewestFirst(windowed, scope.rgSpawnCwd);
504
- }
502
+ const { windowed } = window;
505
503
  let body = formatGrepOutput({
506
504
  windowed,
507
505
  totalWindowed: window.totalWindowed,
@@ -542,7 +540,12 @@ async function runPlainGrep(scope, rgArgs, effectiveHeadLimit) {
542
540
  // complete.
543
541
  async function collectGrepWindow(scope, rgArgs, effectiveHeadLimit) {
544
542
  const { outputMode, offset, searchExecOptions } = scope;
545
- if (effectiveHeadLimit !== Infinity) {
543
+ // The native scan emits content matches in inventory path order (stable, so
544
+ // the streamed content window pages directly). File lists are presented
545
+ // newest-first, so they are pageable only once the WHOLE set is re-ordered;
546
+ // `offset` slices after the sort.
547
+ const fileList = outputMode === 'files_with_matches' || outputMode === 'count';
548
+ if (effectiveHeadLimit !== Infinity && !fileList) {
546
549
  const streamed = await runRgWindowedLines(rgArgs, searchExecOptions, {
547
550
  offset,
548
551
  limit: effectiveHeadLimit,
@@ -556,7 +559,8 @@ async function collectGrepWindow(scope, rgArgs, effectiveHeadLimit) {
556
559
  };
557
560
  }
558
561
  const stdout = await runRg(rgArgs, searchExecOptions);
559
- const allLines = String(stdout).split('\n').filter(Boolean);
562
+ let allLines = String(stdout).split('\n').filter(Boolean);
563
+ if (fileList) allLines = await orderFileListLines(unifyRootSpelling(allLines, scope), outputMode, scope.rgSpawnCwd);
560
564
  const windowed = offset > 0 ? allLines.slice(offset) : allLines;
561
565
  const boxed = typeof stdout === 'object' ? stdout : {};
562
566
  return {
@@ -568,25 +572,60 @@ async function collectGrepWindow(scope, rgArgs, effectiveHeadLimit) {
568
572
  };
569
573
  }
570
574
 
571
- // files_with_matches: newest-first (mtime desc, path tiebreak) so recently
572
- // edited files surface first. Statting is bounded (64 workers, 5s
573
- // deadline); stat-failed entries keep rg traversal order after the statted
574
- // ones. Sort covers the shown window — with the default head limit the
575
- // common case is the complete result set.
576
- async function sortNewestFirst(windowed, rgSpawnCwd) {
577
- const withStat = await statPathsForMtime(windowed, rgSpawnCwd, 64, { deadlineMs: 5000 });
575
+ // A search root reached through a symlink or junction (macOS /var ->
576
+ // /private/var) can come back from the walker under either spelling: rows that
577
+ // the inventory repaired after a filesystem event carry the realpath while the
578
+ // rest carry the given root. Left alone they sort apart, page twice and print
579
+ // as absolute paths. Rewrite realpath rows to the given spelling, then drop the
580
+ // repeats, so ordering, offset paging and relativization see one spelling.
581
+ function unifyRootSpelling(lines, scope) {
582
+ const given = scope.searchPath;
583
+ const absGiven = resolvePath(scope.rgSpawnCwd, given);
584
+ const real = realRootOf(absGiven);
585
+ if (real === absGiven) return lines;
586
+ const fold = (text) => (process.platform === 'win32' ? text.toLocaleLowerCase() : text);
587
+ const realPrefix = fold(`${real.replace(/\\/g, '/').replace(/\/+$/, '')}/`);
588
+ const sep = given.includes('/') && !given.includes('\\') ? '/' : pathSep;
589
+ const givenPrefix = `${given.replace(/[\\/]+$/, '')}${sep}`;
590
+ const seen = new Set();
591
+ const unified = [];
592
+ for (const line of lines) {
593
+ const fwd = line.replace(/\\/g, '/');
594
+ const row = fold(fwd).startsWith(realPrefix)
595
+ ? givenPrefix + fwd.slice(realPrefix.length).replace(/\//g, sep)
596
+ : line;
597
+ if (seen.has(row)) continue;
598
+ seen.add(row);
599
+ unified.push(row);
600
+ }
601
+ return unified;
602
+ }
603
+
604
+ function compareCodeUnits(a, b) {
605
+ if (a === b) return 0;
606
+ return a < b ? -1 : 1;
607
+ }
608
+
609
+ // Total order over the complete file list, applied BEFORE offset/limit slice:
610
+ // files_with_matches is newest-first (mtime desc, path tiebreak) so recently
611
+ // edited files surface first; stat-failed entries follow in path order
612
+ // (statting is bounded: 64 workers, 5s deadline). count lines sort by path.
613
+ async function orderFileListLines(lines, outputMode, rgSpawnCwd) {
614
+ if (lines.length < 2) return lines;
615
+ if (outputMode === 'count') {
616
+ const pathOf = (line) => parseGrepCountLine(line)?.path ?? line;
617
+ return [...lines].sort((a, b) => compareCodeUnits(pathOf(a), pathOf(b)) || compareCodeUnits(a, b));
618
+ }
619
+ const withStat = await statPathsForMtime(lines, rgSpawnCwd, 64, { deadlineMs: 5000 });
578
620
  const statted = [];
579
621
  const unstatted = [];
580
- for (let i = 0; i < windowed.length; i++) {
622
+ for (let i = 0; i < lines.length; i++) {
581
623
  const entry = withStat[i];
582
- if (entry?.stat) statted.push({ line: windowed[i], mtimeMs: entry.mtimeMs });
583
- else unstatted.push(windowed[i]);
624
+ if (entry?.stat) statted.push({ line: lines[i], mtimeMs: entry.mtimeMs });
625
+ else unstatted.push(lines[i]);
584
626
  }
585
- statted.sort((a, b) => {
586
- const dm = b.mtimeMs - a.mtimeMs;
587
- if (dm !== 0) return dm;
588
- return a.line.localeCompare(b.line);
589
- });
627
+ statted.sort((a, b) => b.mtimeMs - a.mtimeMs || compareCodeUnits(a.line, b.line));
628
+ unstatted.sort(compareCodeUnits);
590
629
  return [...statted.map((e) => e.line), ...unstatted];
591
630
  }
592
631
 
@@ -3,7 +3,7 @@
3
3
  * grep/glob in search-tool.mjs. search-tool.mjs re-exports these for unchanged
4
4
  * importers so it can stay a thin executor.
5
5
  */
6
- import { statSync } from 'node:fs';
6
+ import { realpathSync, statSync } from 'node:fs';
7
7
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
8
8
  import { findDirectoryByBasename, findFileByBasename, listSiblings } from './path-diagnostics.mjs';
9
9
  import { normalizeOutputPath, resolveAgainstCwd } from './path-utils.mjs';
@@ -233,16 +233,40 @@ export async function buildNotFoundHintBody(workDir, missingPath, actionVerb, er
233
233
  return elsewhere.exhaustive === true ? ENOENT_ABSENT : '';
234
234
  }
235
235
 
236
+ // The realpath of a working directory, memoized: a search root reached through
237
+ // a symlink or junction (macOS /var -> /private/var) is reported by the walker
238
+ // under its realpath, so results must be relativized against both spellings.
239
+ const realRootCache = new Map();
240
+ const REAL_ROOT_CACHE_MAX = 64;
241
+ export function realRootOf(root) {
242
+ if (realRootCache.has(root)) return realRootCache.get(root);
243
+ let real;
244
+ try {
245
+ real = realpathSync.native(root);
246
+ } catch {
247
+ return root;
248
+ }
249
+ if (realRootCache.size >= REAL_ROOT_CACHE_MAX) realRootCache.clear();
250
+ realRootCache.set(root, real);
251
+ return real;
252
+ }
253
+
254
+ function relativeUnderRoot(absFwd, root) {
255
+ const rootFwd = root.replace(/\\/g, '/').replace(/\/+$/, '');
256
+ const haystack = process.platform === 'win32' ? absFwd.toLocaleLowerCase() : absFwd;
257
+ const needle = process.platform === 'win32' ? rootFwd.toLocaleLowerCase() : rootFwd;
258
+ if (haystack.startsWith(`${needle}/`) || haystack === needle) return absFwd.slice(rootFwd.length + 1) || '.';
259
+ return null;
260
+ }
261
+
236
262
  export function relativePathPrefix(pathPrefix, workDir) {
237
263
  if (!workDir) return pathPrefix;
238
- const cwdFwd = workDir.replace(/\\/g, '/').replace(/\/+$/, '');
239
264
  const absFwd = String(pathPrefix || '').replace(/\\/g, '/');
240
- const haystack = process.platform === 'win32' ? absFwd.toLocaleLowerCase() : absFwd;
241
- const needle = process.platform === 'win32' ? cwdFwd.toLocaleLowerCase() : cwdFwd;
242
- if (haystack.startsWith(`${needle}/`) || haystack === needle) {
243
- return absFwd.slice(cwdFwd.length + 1) || '.';
244
- }
245
- return pathPrefix;
265
+ const given = relativeUnderRoot(absFwd, workDir);
266
+ if (given !== null) return given;
267
+ const real = realRootOf(workDir);
268
+ if (real === workDir) return pathPrefix;
269
+ return relativeUnderRoot(absFwd, real) ?? pathPrefix;
246
270
  }
247
271
 
248
272
  export function relativeSearchResultPath(path, workDir) {