@oh-my-pi-zen/pi-coding-agent 16.3.6-zen.1

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 (2454) hide show
  1. package/CHANGELOG.md +13088 -0
  2. package/README.md +35 -0
  3. package/dist/cli.js +22542 -0
  4. package/dist/types/advisor/__tests__/advisor.test.d.ts +1 -0
  5. package/dist/types/advisor/__tests__/config.test.d.ts +1 -0
  6. package/dist/types/advisor/__tests__/emission-guard.test.d.ts +1 -0
  7. package/dist/types/advisor/advise-tool.d.ts +106 -0
  8. package/dist/types/advisor/config.d.ts +90 -0
  9. package/dist/types/advisor/emission-guard.d.ts +73 -0
  10. package/dist/types/advisor/index.d.ts +6 -0
  11. package/dist/types/advisor/runtime.d.ts +76 -0
  12. package/dist/types/advisor/transcript-recorder.d.ts +63 -0
  13. package/dist/types/advisor/watchdog.d.ts +38 -0
  14. package/dist/types/async/index.d.ts +1 -0
  15. package/dist/types/async/job-manager.d.ts +121 -0
  16. package/dist/types/auto-thinking/classifier.d.ts +37 -0
  17. package/dist/types/autolearn/controller.d.ts +25 -0
  18. package/dist/types/autolearn/managed-skills.d.ts +45 -0
  19. package/dist/types/autoresearch/dashboard.d.ts +4 -0
  20. package/dist/types/autoresearch/git.d.ts +36 -0
  21. package/dist/types/autoresearch/helpers.d.ts +24 -0
  22. package/dist/types/autoresearch/index.d.ts +2 -0
  23. package/dist/types/autoresearch/state.d.ts +17 -0
  24. package/dist/types/autoresearch/storage.d.ts +142 -0
  25. package/dist/types/autoresearch/tools/init-experiment.d.ts +27 -0
  26. package/dist/types/autoresearch/tools/log-experiment.d.ts +21 -0
  27. package/dist/types/autoresearch/tools/run-experiment.d.ts +7 -0
  28. package/dist/types/autoresearch/tools/update-notes.d.ts +11 -0
  29. package/dist/types/autoresearch/types.d.ts +154 -0
  30. package/dist/types/capability/context-file.d.ts +17 -0
  31. package/dist/types/capability/extension-module.d.ts +15 -0
  32. package/dist/types/capability/extension.d.ts +28 -0
  33. package/dist/types/capability/fs.d.ts +20 -0
  34. package/dist/types/capability/hook.d.ts +19 -0
  35. package/dist/types/capability/index.d.ts +80 -0
  36. package/dist/types/capability/instruction.d.ts +17 -0
  37. package/dist/types/capability/mcp.d.ts +47 -0
  38. package/dist/types/capability/prompt.d.ts +15 -0
  39. package/dist/types/capability/rule-buckets.d.ts +30 -0
  40. package/dist/types/capability/rule.d.ts +73 -0
  41. package/dist/types/capability/settings.d.ts +15 -0
  42. package/dist/types/capability/skill.d.ts +43 -0
  43. package/dist/types/capability/slash-command.d.ts +17 -0
  44. package/dist/types/capability/ssh.d.ts +23 -0
  45. package/dist/types/capability/system-prompt.d.ts +15 -0
  46. package/dist/types/capability/tool.d.ts +19 -0
  47. package/dist/types/capability/types.d.ts +154 -0
  48. package/dist/types/cli/agents-cli.d.ts +12 -0
  49. package/dist/types/cli/args.d.ts +77 -0
  50. package/dist/types/cli/auth-broker-cli.d.ts +25 -0
  51. package/dist/types/cli/auth-gateway-cli.d.ts +26 -0
  52. package/dist/types/cli/bench-cli.d.ts +85 -0
  53. package/dist/types/cli/classify-install-target.d.ts +12 -0
  54. package/dist/types/cli/claude-trace-cli.d.ts +54 -0
  55. package/dist/types/cli/commands/init-xdg.d.ts +1 -0
  56. package/dist/types/cli/completion-gen.d.ts +80 -0
  57. package/dist/types/cli/config-cli.d.ts +22 -0
  58. package/dist/types/cli/dry-balance-cli.d.ts +113 -0
  59. package/dist/types/cli/extension-flags.d.ts +36 -0
  60. package/dist/types/cli/file-processor.d.ts +11 -0
  61. package/dist/types/cli/flag-tables.d.ts +144 -0
  62. package/dist/types/cli/gallery-cli.d.ts +49 -0
  63. package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
  64. package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
  65. package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
  66. package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
  67. package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
  68. package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
  69. package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
  70. package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
  71. package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
  72. package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
  73. package/dist/types/cli/gallery-fixtures/types.d.ts +55 -0
  74. package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
  75. package/dist/types/cli/gallery-screenshot.d.ts +35 -0
  76. package/dist/types/cli/gc-cli.d.ts +58 -0
  77. package/dist/types/cli/grep-cli.d.ts +17 -0
  78. package/dist/types/cli/grievances-cli.d.ts +37 -0
  79. package/dist/types/cli/initial-message.d.ts +17 -0
  80. package/dist/types/cli/models-cli.d.ts +49 -0
  81. package/dist/types/cli/plugin-cli.d.ts +32 -0
  82. package/dist/types/cli/profile-alias.d.ts +29 -0
  83. package/dist/types/cli/profile-bootstrap.d.ts +55 -0
  84. package/dist/types/cli/read-cli.d.ts +4 -0
  85. package/dist/types/cli/session-picker.d.ts +11 -0
  86. package/dist/types/cli/setup-cli.d.ts +24 -0
  87. package/dist/types/cli/setup-model-picker.d.ts +14 -0
  88. package/dist/types/cli/shell-cli.d.ts +8 -0
  89. package/dist/types/cli/ssh-cli.d.ts +21 -0
  90. package/dist/types/cli/startup-cwd.d.ts +2 -0
  91. package/dist/types/cli/stats-cli.d.ts +17 -0
  92. package/dist/types/cli/tiny-models-cli.d.ts +11 -0
  93. package/dist/types/cli/ttsr-cli.d.ts +39 -0
  94. package/dist/types/cli/update-cli.d.ts +106 -0
  95. package/dist/types/cli/update-cli.test.d.ts +1 -0
  96. package/dist/types/cli/usage-cli.d.ts +95 -0
  97. package/dist/types/cli/web-search-cli.d.ts +20 -0
  98. package/dist/types/cli/worktree-cli.d.ts +26 -0
  99. package/dist/types/cli-commands.d.ts +33 -0
  100. package/dist/types/cli.d.ts +3 -0
  101. package/dist/types/collab/crypto.d.ts +7 -0
  102. package/dist/types/collab/display-name.d.ts +3 -0
  103. package/dist/types/collab/guest.d.ts +52 -0
  104. package/dist/types/collab/host.d.ts +43 -0
  105. package/dist/types/collab/protocol.d.ts +143 -0
  106. package/dist/types/collab/relay-client.d.ts +22 -0
  107. package/dist/types/collab/replication-shrink.d.ts +39 -0
  108. package/dist/types/commands/acp.d.ts +12 -0
  109. package/dist/types/commands/agents.d.ts +34 -0
  110. package/dist/types/commands/auth-broker.d.ts +54 -0
  111. package/dist/types/commands/auth-gateway.d.ts +35 -0
  112. package/dist/types/commands/bench.d.ts +37 -0
  113. package/dist/types/commands/commit.d.ts +27 -0
  114. package/dist/types/commands/complete.d.ts +6 -0
  115. package/dist/types/commands/completions.d.ts +13 -0
  116. package/dist/types/commands/config.d.ts +30 -0
  117. package/dist/types/commands/dry-balance.d.ts +31 -0
  118. package/dist/types/commands/gallery.d.ts +47 -0
  119. package/dist/types/commands/gc.d.ts +37 -0
  120. package/dist/types/commands/grep.d.ts +42 -0
  121. package/dist/types/commands/grievances.d.ts +40 -0
  122. package/dist/types/commands/install.d.ts +51 -0
  123. package/dist/types/commands/join.d.ts +12 -0
  124. package/dist/types/commands/launch.d.ts +148 -0
  125. package/dist/types/commands/models.d.ts +33 -0
  126. package/dist/types/commands/plugin.d.ts +52 -0
  127. package/dist/types/commands/read.d.ts +15 -0
  128. package/dist/types/commands/say.d.ts +24 -0
  129. package/dist/types/commands/setup.d.ts +34 -0
  130. package/dist/types/commands/shell.d.ts +21 -0
  131. package/dist/types/commands/ssh.d.ts +48 -0
  132. package/dist/types/commands/stats.d.ts +25 -0
  133. package/dist/types/commands/tiny-models.d.ts +22 -0
  134. package/dist/types/commands/token.d.ts +34 -0
  135. package/dist/types/commands/ttsr.d.ts +57 -0
  136. package/dist/types/commands/update.d.ts +25 -0
  137. package/dist/types/commands/usage.d.ts +34 -0
  138. package/dist/types/commands/web-search.d.ts +33 -0
  139. package/dist/types/commands/worktree.d.ts +31 -0
  140. package/dist/types/commit/agentic/agent.d.ts +31 -0
  141. package/dist/types/commit/agentic/fallback.d.ts +5 -0
  142. package/dist/types/commit/agentic/index.d.ts +2 -0
  143. package/dist/types/commit/agentic/state.d.ts +58 -0
  144. package/dist/types/commit/agentic/tools/analyze-file.d.ts +18 -0
  145. package/dist/types/commit/agentic/tools/git-file-diff.d.ts +9 -0
  146. package/dist/types/commit/agentic/tools/git-hunk.d.ts +8 -0
  147. package/dist/types/commit/agentic/tools/git-overview.d.ts +8 -0
  148. package/dist/types/commit/agentic/tools/index.d.ts +16 -0
  149. package/dist/types/commit/agentic/tools/propose-changelog.d.ts +27 -0
  150. package/dist/types/commit/agentic/tools/propose-commit.d.ts +15 -0
  151. package/dist/types/commit/agentic/tools/recent-commits.d.ts +6 -0
  152. package/dist/types/commit/agentic/tools/schemas.d.ts +6 -0
  153. package/dist/types/commit/agentic/tools/split-commit.d.ts +32 -0
  154. package/dist/types/commit/agentic/topo-sort.d.ts +4 -0
  155. package/dist/types/commit/agentic/trivial.d.ts +7 -0
  156. package/dist/types/commit/agentic/validation.d.ts +20 -0
  157. package/dist/types/commit/analysis/conventional.d.ts +22 -0
  158. package/dist/types/commit/analysis/index.d.ts +4 -0
  159. package/dist/types/commit/analysis/scope.d.ts +6 -0
  160. package/dist/types/commit/analysis/summary.d.ts +19 -0
  161. package/dist/types/commit/analysis/validation.d.ts +8 -0
  162. package/dist/types/commit/changelog/detect.d.ts +2 -0
  163. package/dist/types/commit/changelog/generate.d.ts +29 -0
  164. package/dist/types/commit/changelog/index.d.ts +30 -0
  165. package/dist/types/commit/changelog/parse.d.ts +2 -0
  166. package/dist/types/commit/cli.d.ts +3 -0
  167. package/dist/types/commit/git/diff.d.ts +5 -0
  168. package/dist/types/commit/index.d.ts +4 -0
  169. package/dist/types/commit/map-reduce/index.d.ts +28 -0
  170. package/dist/types/commit/map-reduce/map-phase.d.ts +17 -0
  171. package/dist/types/commit/map-reduce/reduce-phase.d.ts +13 -0
  172. package/dist/types/commit/map-reduce/utils.d.ts +2 -0
  173. package/dist/types/commit/message.d.ts +2 -0
  174. package/dist/types/commit/model-selection.d.ts +26 -0
  175. package/dist/types/commit/pipeline.d.ts +5 -0
  176. package/dist/types/commit/shared-llm.d.ts +27 -0
  177. package/dist/types/commit/types.d.ts +78 -0
  178. package/dist/types/commit/utils/exclusions.d.ts +4 -0
  179. package/dist/types/commit/utils.d.ts +20 -0
  180. package/dist/types/config/api-key-resolver.d.ts +43 -0
  181. package/dist/types/config/append-only-context-mode.d.ts +9 -0
  182. package/dist/types/config/config-file.d.ts +62 -0
  183. package/dist/types/config/file-lock.d.ts +29 -0
  184. package/dist/types/config/inline-tool-descriptors-mode.d.ts +12 -0
  185. package/dist/types/config/keybindings.d.ts +362 -0
  186. package/dist/types/config/model-discovery.d.ts +68 -0
  187. package/dist/types/config/model-registry.d.ts +251 -0
  188. package/dist/types/config/model-resolver.d.ts +300 -0
  189. package/dist/types/config/model-roles.d.ts +29 -0
  190. package/dist/types/config/models-config-schema.d.ts +697 -0
  191. package/dist/types/config/models-config.d.ts +436 -0
  192. package/dist/types/config/prompt-templates.d.ts +32 -0
  193. package/dist/types/config/provider-globals.d.ts +7 -0
  194. package/dist/types/config/resolve-config-value.d.ts +17 -0
  195. package/dist/types/config/service-tier.d.ts +49 -0
  196. package/dist/types/config/settings-schema.d.ts +5668 -0
  197. package/dist/types/config/settings.d.ts +181 -0
  198. package/dist/types/config.d.ts +92 -0
  199. package/dist/types/cursor.d.ts +22 -0
  200. package/dist/types/dap/client.d.ts +46 -0
  201. package/dist/types/dap/config.d.ts +19 -0
  202. package/dist/types/dap/index.d.ts +4 -0
  203. package/dist/types/dap/session.d.ts +108 -0
  204. package/dist/types/dap/types.d.ts +534 -0
  205. package/dist/types/debug/index.d.ts +15 -0
  206. package/dist/types/debug/log-formatting.d.ts +4 -0
  207. package/dist/types/debug/log-viewer.d.ts +69 -0
  208. package/dist/types/debug/profiler.d.ts +24 -0
  209. package/dist/types/debug/protocol-probe.d.ts +38 -0
  210. package/dist/types/debug/raw-sse-buffer.d.ts +44 -0
  211. package/dist/types/debug/raw-sse.d.ts +19 -0
  212. package/dist/types/debug/remote-debugger.d.ts +45 -0
  213. package/dist/types/debug/report-bundle.d.ts +58 -0
  214. package/dist/types/debug/system-info.d.ts +26 -0
  215. package/dist/types/debug/terminal-info.d.ts +33 -0
  216. package/dist/types/discovery/agents-md.d.ts +1 -0
  217. package/dist/types/discovery/agents.d.ts +12 -0
  218. package/dist/types/discovery/at-imports.d.ts +15 -0
  219. package/dist/types/discovery/builtin-defaults.d.ts +1 -0
  220. package/dist/types/discovery/builtin-rules/index.d.ts +7 -0
  221. package/dist/types/discovery/builtin.d.ts +1 -0
  222. package/dist/types/discovery/claude-plugins.d.ts +1 -0
  223. package/dist/types/discovery/claude.d.ts +1 -0
  224. package/dist/types/discovery/cline.d.ts +1 -0
  225. package/dist/types/discovery/codex.d.ts +1 -0
  226. package/dist/types/discovery/cursor.d.ts +16 -0
  227. package/dist/types/discovery/gemini.d.ts +1 -0
  228. package/dist/types/discovery/github.d.ts +1 -0
  229. package/dist/types/discovery/helpers.d.ts +278 -0
  230. package/dist/types/discovery/index.d.ts +53 -0
  231. package/dist/types/discovery/mcp-json.d.ts +1 -0
  232. package/dist/types/discovery/omp-extension-roots.d.ts +43 -0
  233. package/dist/types/discovery/omp-plugins.d.ts +1 -0
  234. package/dist/types/discovery/opencode.d.ts +1 -0
  235. package/dist/types/discovery/plugin-dir-roots.d.ts +15 -0
  236. package/dist/types/discovery/ssh.d.ts +1 -0
  237. package/dist/types/discovery/substitute-plugin-root.d.ts +1 -0
  238. package/dist/types/discovery/vscode.d.ts +1 -0
  239. package/dist/types/discovery/windsurf.d.ts +13 -0
  240. package/dist/types/edit/apply-patch/index.d.ts +35 -0
  241. package/dist/types/edit/apply-patch/parser.d.ts +34 -0
  242. package/dist/types/edit/diff.d.ts +60 -0
  243. package/dist/types/edit/file-snapshot-store.d.ts +74 -0
  244. package/dist/types/edit/hashline/block-resolver.d.ts +9 -0
  245. package/dist/types/edit/hashline/diff.d.ts +29 -0
  246. package/dist/types/edit/hashline/execute.d.ts +28 -0
  247. package/dist/types/edit/hashline/filesystem.d.ts +43 -0
  248. package/dist/types/edit/hashline/index.d.ts +5 -0
  249. package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
  250. package/dist/types/edit/hashline/params.d.ts +4 -0
  251. package/dist/types/edit/index.d.ts +83 -0
  252. package/dist/types/edit/modes/apply-patch.d.ts +23 -0
  253. package/dist/types/edit/modes/patch.d.ts +101 -0
  254. package/dist/types/edit/modes/replace.d.ts +141 -0
  255. package/dist/types/edit/normalize.d.ts +31 -0
  256. package/dist/types/edit/notebook.d.ts +23 -0
  257. package/dist/types/edit/read-file.d.ts +2 -0
  258. package/dist/types/edit/renderer.d.ts +118 -0
  259. package/dist/types/edit/snapshot-details.d.ts +33 -0
  260. package/dist/types/edit/streaming.d.ts +105 -0
  261. package/dist/types/eval/__tests__/agent-bridge.test.d.ts +1 -0
  262. package/dist/types/eval/__tests__/bridge-timeout.test.d.ts +1 -0
  263. package/dist/types/eval/__tests__/budget-bridge.test.d.ts +1 -0
  264. package/dist/types/eval/__tests__/completion-bridge.test.d.ts +1 -0
  265. package/dist/types/eval/__tests__/helpers-local-roots.test.d.ts +1 -0
  266. package/dist/types/eval/__tests__/idle-timeout.test.d.ts +1 -0
  267. package/dist/types/eval/__tests__/js-context-manager.test.d.ts +1 -0
  268. package/dist/types/eval/__tests__/julia-prelude.test.d.ts +1 -0
  269. package/dist/types/eval/__tests__/kernel-spawn.test.d.ts +1 -0
  270. package/dist/types/eval/__tests__/prelude-agent.test.d.ts +1 -0
  271. package/dist/types/eval/agent-bridge.d.ts +48 -0
  272. package/dist/types/eval/backend-helpers.d.ts +23 -0
  273. package/dist/types/eval/backend.d.ts +60 -0
  274. package/dist/types/eval/bridge-timeout.d.ts +27 -0
  275. package/dist/types/eval/budget-bridge.d.ts +29 -0
  276. package/dist/types/eval/completion-bridge.d.ts +25 -0
  277. package/dist/types/eval/concurrency-bridge.d.ts +26 -0
  278. package/dist/types/eval/executor-base.d.ts +118 -0
  279. package/dist/types/eval/idle-timeout.d.ts +26 -0
  280. package/dist/types/eval/index.d.ts +6 -0
  281. package/dist/types/eval/jl/executor.d.ts +44 -0
  282. package/dist/types/eval/jl/index.d.ts +11 -0
  283. package/dist/types/eval/jl/kernel.d.ts +28 -0
  284. package/dist/types/eval/jl/prelude.d.ts +1 -0
  285. package/dist/types/eval/jl/runtime.d.ts +22 -0
  286. package/dist/types/eval/js/context-manager.d.ts +40 -0
  287. package/dist/types/eval/js/executor.d.ts +38 -0
  288. package/dist/types/eval/js/index.d.ts +11 -0
  289. package/dist/types/eval/js/shared/helpers.d.ts +32 -0
  290. package/dist/types/eval/js/shared/indirect-eval.d.ts +14 -0
  291. package/dist/types/eval/js/shared/local-module-loader.d.ts +16 -0
  292. package/dist/types/eval/js/shared/prelude.d.ts +1 -0
  293. package/dist/types/eval/js/shared/rewrite-imports.d.ts +25 -0
  294. package/dist/types/eval/js/shared/runtime.d.ts +59 -0
  295. package/dist/types/eval/js/shared/types.d.ts +24 -0
  296. package/dist/types/eval/js/tool-bridge.d.ts +20 -0
  297. package/dist/types/eval/js/worker-core.d.ts +6 -0
  298. package/dist/types/eval/js/worker-entry.d.ts +1 -0
  299. package/dist/types/eval/js/worker-protocol.d.ts +83 -0
  300. package/dist/types/eval/kernel-base.d.ts +105 -0
  301. package/dist/types/eval/py/__tests__/prelude.test.d.ts +1 -0
  302. package/dist/types/eval/py/__tests__/runner-shell-output.test.d.ts +1 -0
  303. package/dist/types/eval/py/display.d.ts +25 -0
  304. package/dist/types/eval/py/executor.d.ts +107 -0
  305. package/dist/types/eval/py/index.d.ts +11 -0
  306. package/dist/types/eval/py/kernel.d.ts +17 -0
  307. package/dist/types/eval/py/prelude.d.ts +1 -0
  308. package/dist/types/eval/py/runtime.d.ts +40 -0
  309. package/dist/types/eval/py/spawn-options.d.ts +58 -0
  310. package/dist/types/eval/py/tool-bridge.d.ts +16 -0
  311. package/dist/types/eval/rb/executor.d.ts +77 -0
  312. package/dist/types/eval/rb/index.d.ts +11 -0
  313. package/dist/types/eval/rb/kernel.d.ts +31 -0
  314. package/dist/types/eval/rb/prelude.d.ts +1 -0
  315. package/dist/types/eval/rb/runtime.d.ts +23 -0
  316. package/dist/types/eval/runtime-env.d.ts +24 -0
  317. package/dist/types/eval/session-id.d.ts +3 -0
  318. package/dist/types/eval/types.d.ts +52 -0
  319. package/dist/types/exa/index.d.ts +2 -0
  320. package/dist/types/exa/mcp-client.d.ts +53 -0
  321. package/dist/types/exa/types.d.ts +72 -0
  322. package/dist/types/exec/bash-executor.d.ts +45 -0
  323. package/dist/types/exec/exec.d.ts +25 -0
  324. package/dist/types/exec/non-interactive-env.d.ts +3 -0
  325. package/dist/types/export/custom-share.d.ts +19 -0
  326. package/dist/types/export/html/index.d.ts +78 -0
  327. package/dist/types/export/html/web-palette.d.ts +117 -0
  328. package/dist/types/export/share.d.ts +55 -0
  329. package/dist/types/export/ttsr.d.ts +67 -0
  330. package/dist/types/extensibility/custom-commands/bundled/ci-green/index.d.ts +9 -0
  331. package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +10 -0
  332. package/dist/types/extensibility/custom-commands/index.d.ts +2 -0
  333. package/dist/types/extensibility/custom-commands/loader.d.ts +29 -0
  334. package/dist/types/extensibility/custom-commands/types.d.ts +112 -0
  335. package/dist/types/extensibility/custom-tools/index.d.ts +6 -0
  336. package/dist/types/extensibility/custom-tools/loader.d.ts +89 -0
  337. package/dist/types/extensibility/custom-tools/types.d.ts +244 -0
  338. package/dist/types/extensibility/custom-tools/wrapper.d.ts +23 -0
  339. package/dist/types/extensibility/extensions/compact-handler.d.ts +26 -0
  340. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +29 -0
  341. package/dist/types/extensibility/extensions/index.d.ts +8 -0
  342. package/dist/types/extensibility/extensions/loader.d.ts +59 -0
  343. package/dist/types/extensibility/extensions/model-api.d.ts +17 -0
  344. package/dist/types/extensibility/extensions/runner.d.ts +161 -0
  345. package/dist/types/extensibility/extensions/types.d.ts +962 -0
  346. package/dist/types/extensibility/extensions/wrapper.d.ts +54 -0
  347. package/dist/types/extensibility/hooks/index.d.ts +6 -0
  348. package/dist/types/extensibility/hooks/loader.d.ts +65 -0
  349. package/dist/types/extensibility/hooks/runner.d.ts +126 -0
  350. package/dist/types/extensibility/hooks/tool-wrapper.d.ts +25 -0
  351. package/dist/types/extensibility/hooks/types.d.ts +442 -0
  352. package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +35 -0
  353. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +115 -0
  354. package/dist/types/extensibility/plugins/doctor.d.ts +3 -0
  355. package/dist/types/extensibility/plugins/git-url.d.ts +44 -0
  356. package/dist/types/extensibility/plugins/index.d.ts +7 -0
  357. package/dist/types/extensibility/plugins/installer.d.ts +5 -0
  358. package/dist/types/extensibility/plugins/legacy-pi-bundled-keys.d.ts +10 -0
  359. package/dist/types/extensibility/plugins/legacy-pi-bundled-registry.d.ts +10 -0
  360. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +79 -0
  361. package/dist/types/extensibility/plugins/loader.d.ts +59 -0
  362. package/dist/types/extensibility/plugins/manager.d.ts +76 -0
  363. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +41 -0
  364. package/dist/types/extensibility/plugins/marketplace/fetcher.d.ts +48 -0
  365. package/dist/types/extensibility/plugins/marketplace/index.d.ts +6 -0
  366. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +57 -0
  367. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +34 -0
  368. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +28 -0
  369. package/dist/types/extensibility/plugins/marketplace/types.d.ts +131 -0
  370. package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
  371. package/dist/types/extensibility/plugins/parser.d.ts +53 -0
  372. package/dist/types/extensibility/plugins/runtime-config.d.ts +3 -0
  373. package/dist/types/extensibility/plugins/types.d.ts +149 -0
  374. package/dist/types/extensibility/session-handler-types.d.ts +23 -0
  375. package/dist/types/extensibility/shared-events.d.ts +308 -0
  376. package/dist/types/extensibility/skills.d.ts +97 -0
  377. package/dist/types/extensibility/slash-commands.d.ts +38 -0
  378. package/dist/types/extensibility/tool-event-input.d.ts +9 -0
  379. package/dist/types/extensibility/tool-proxy.d.ts +4 -0
  380. package/dist/types/extensibility/typebox.d.ts +177 -0
  381. package/dist/types/extensibility/utils.d.ts +24 -0
  382. package/dist/types/goals/guided-setup.d.ts +18 -0
  383. package/dist/types/goals/index.d.ts +3 -0
  384. package/dist/types/goals/runtime.d.ts +69 -0
  385. package/dist/types/goals/state.d.ts +35 -0
  386. package/dist/types/goals/tools/goal-tool.d.ts +53 -0
  387. package/dist/types/hindsight/backend.d.ts +13 -0
  388. package/dist/types/hindsight/bank.d.ts +62 -0
  389. package/dist/types/hindsight/client.d.ts +228 -0
  390. package/dist/types/hindsight/client.test.d.ts +1 -0
  391. package/dist/types/hindsight/config.d.ts +51 -0
  392. package/dist/types/hindsight/content.d.ts +73 -0
  393. package/dist/types/hindsight/index.d.ts +8 -0
  394. package/dist/types/hindsight/mental-models.d.ts +134 -0
  395. package/dist/types/hindsight/state.d.ts +105 -0
  396. package/dist/types/hindsight/transcript.d.ts +28 -0
  397. package/dist/types/index.d.ts +43 -0
  398. package/dist/types/internal-urls/__tests__/ssh-protocol.test.d.ts +1 -0
  399. package/dist/types/internal-urls/agent-protocol.d.ts +13 -0
  400. package/dist/types/internal-urls/artifact-protocol.d.ts +15 -0
  401. package/dist/types/internal-urls/docs-index.d.ts +19 -0
  402. package/dist/types/internal-urls/filesystem-resource.d.ts +9 -0
  403. package/dist/types/internal-urls/history-protocol.d.ts +14 -0
  404. package/dist/types/internal-urls/index.d.ts +25 -0
  405. package/dist/types/internal-urls/issue-pr-protocol.d.ts +17 -0
  406. package/dist/types/internal-urls/json-query.d.ts +30 -0
  407. package/dist/types/internal-urls/local-protocol.d.ts +79 -0
  408. package/dist/types/internal-urls/mcp-protocol.d.ts +12 -0
  409. package/dist/types/internal-urls/memory-protocol.d.ts +24 -0
  410. package/dist/types/internal-urls/omp-protocol.d.ts +13 -0
  411. package/dist/types/internal-urls/parse.d.ts +19 -0
  412. package/dist/types/internal-urls/registry-helpers.d.ts +12 -0
  413. package/dist/types/internal-urls/router.d.ts +21 -0
  414. package/dist/types/internal-urls/rule-protocol.d.ts +7 -0
  415. package/dist/types/internal-urls/skill-protocol.d.ts +14 -0
  416. package/dist/types/internal-urls/ssh-protocol.d.ts +10 -0
  417. package/dist/types/internal-urls/types.d.ts +175 -0
  418. package/dist/types/internal-urls/vault-protocol.d.ts +93 -0
  419. package/dist/types/irc/bus.d.ts +86 -0
  420. package/dist/types/jsonrpc/message-framing.d.ts +35 -0
  421. package/dist/types/lib/xai-http.d.ts +40 -0
  422. package/dist/types/lsp/client.d.ts +84 -0
  423. package/dist/types/lsp/clients/biome-client.d.ts +16 -0
  424. package/dist/types/lsp/clients/index.d.ts +19 -0
  425. package/dist/types/lsp/clients/lsp-linter-client.d.ts +16 -0
  426. package/dist/types/lsp/clients/swiftlint-client.d.ts +20 -0
  427. package/dist/types/lsp/config.d.ts +69 -0
  428. package/dist/types/lsp/diagnostics-ledger.d.ts +10 -0
  429. package/dist/types/lsp/edits.d.ts +34 -0
  430. package/dist/types/lsp/format-options.d.ts +32 -0
  431. package/dist/types/lsp/index.d.ts +120 -0
  432. package/dist/types/lsp/lspmux.d.ts +58 -0
  433. package/dist/types/lsp/render.d.ts +32 -0
  434. package/dist/types/lsp/startup-events.d.ts +11 -0
  435. package/dist/types/lsp/types.d.ts +300 -0
  436. package/dist/types/lsp/utils.d.ts +116 -0
  437. package/dist/types/main.d.ts +70 -0
  438. package/dist/types/markit/converters/docx.d.ts +6 -0
  439. package/dist/types/markit/converters/epub.d.ts +15 -0
  440. package/dist/types/markit/converters/pdf/columns.d.ts +35 -0
  441. package/dist/types/markit/converters/pdf/extract.d.ts +10 -0
  442. package/dist/types/markit/converters/pdf/grid.d.ts +25 -0
  443. package/dist/types/markit/converters/pdf/headers.d.ts +24 -0
  444. package/dist/types/markit/converters/pdf/index.d.ts +6 -0
  445. package/dist/types/markit/converters/pdf/render.d.ts +24 -0
  446. package/dist/types/markit/converters/pdf/types.d.ts +75 -0
  447. package/dist/types/markit/converters/pptx.d.ts +57 -0
  448. package/dist/types/markit/converters/xlsx.d.ts +25 -0
  449. package/dist/types/markit/index.d.ts +2 -0
  450. package/dist/types/markit/registry.d.ts +16 -0
  451. package/dist/types/markit/types.d.ts +30 -0
  452. package/dist/types/mcp/client.d.ts +83 -0
  453. package/dist/types/mcp/config-writer.d.ts +101 -0
  454. package/dist/types/mcp/config.d.ts +75 -0
  455. package/dist/types/mcp/index.d.ts +18 -0
  456. package/dist/types/mcp/json-rpc.d.ts +32 -0
  457. package/dist/types/mcp/loader.d.ts +44 -0
  458. package/dist/types/mcp/manager.d.ts +215 -0
  459. package/dist/types/mcp/oauth-credentials.d.ts +17 -0
  460. package/dist/types/mcp/oauth-discovery.d.ts +65 -0
  461. package/dist/types/mcp/oauth-flow.d.ts +145 -0
  462. package/dist/types/mcp/render.d.ts +25 -0
  463. package/dist/types/mcp/smithery-auth.d.ts +16 -0
  464. package/dist/types/mcp/smithery-connect.d.ts +38 -0
  465. package/dist/types/mcp/smithery-registry.d.ts +52 -0
  466. package/dist/types/mcp/smithery-registry.test.d.ts +1 -0
  467. package/dist/types/mcp/startup-events.d.ts +28 -0
  468. package/dist/types/mcp/timeout.d.ts +9 -0
  469. package/dist/types/mcp/tool-bridge.d.ts +95 -0
  470. package/dist/types/mcp/tool-cache.d.ts +8 -0
  471. package/dist/types/mcp/transports/http.d.ts +45 -0
  472. package/dist/types/mcp/transports/index.d.ts +6 -0
  473. package/dist/types/mcp/transports/sse.d.ts +20 -0
  474. package/dist/types/mcp/transports/stdio.d.ts +108 -0
  475. package/dist/types/mcp/transports/stdio.test.d.ts +1 -0
  476. package/dist/types/mcp/types.d.ts +340 -0
  477. package/dist/types/memories/index.d.ts +54 -0
  478. package/dist/types/memories/storage.d.ts +110 -0
  479. package/dist/types/memory-backend/index.d.ts +7 -0
  480. package/dist/types/memory-backend/local-backend.d.ts +10 -0
  481. package/dist/types/memory-backend/off-backend.d.ts +7 -0
  482. package/dist/types/memory-backend/resolve.d.ts +16 -0
  483. package/dist/types/memory-backend/runtime.d.ts +4 -0
  484. package/dist/types/memory-backend/types.d.ts +132 -0
  485. package/dist/types/mnemopi/backend.d.ts +4 -0
  486. package/dist/types/mnemopi/config.d.ts +60 -0
  487. package/dist/types/mnemopi/embed-client.d.ts +53 -0
  488. package/dist/types/mnemopi/embed-protocol.d.ts +52 -0
  489. package/dist/types/mnemopi/embed-worker.d.ts +12 -0
  490. package/dist/types/mnemopi/index.d.ts +3 -0
  491. package/dist/types/mnemopi/state.d.ts +130 -0
  492. package/dist/types/modes/acp/acp-agent.d.ts +60 -0
  493. package/dist/types/modes/acp/acp-client-bridge.d.ts +9 -0
  494. package/dist/types/modes/acp/acp-event-mapper.d.ts +33 -0
  495. package/dist/types/modes/acp/acp-mode.d.ts +5 -0
  496. package/dist/types/modes/acp/index.d.ts +2 -0
  497. package/dist/types/modes/acp/terminal-auth.d.ts +6 -0
  498. package/dist/types/modes/components/__tests__/move-overlay.test.d.ts +1 -0
  499. package/dist/types/modes/components/__tests__/skill-message.test.d.ts +1 -0
  500. package/dist/types/modes/components/advisor-config.d.ts +59 -0
  501. package/dist/types/modes/components/advisor-message.d.ts +11 -0
  502. package/dist/types/modes/components/agent-dashboard.d.ts +22 -0
  503. package/dist/types/modes/components/agent-hub.d.ts +77 -0
  504. package/dist/types/modes/components/agent-transcript-viewer.d.ts +40 -0
  505. package/dist/types/modes/components/assistant-message.d.ts +58 -0
  506. package/dist/types/modes/components/background-tan-message.d.ts +9 -0
  507. package/dist/types/modes/components/bash-execution.d.ts +35 -0
  508. package/dist/types/modes/components/bordered-loader.d.ts +11 -0
  509. package/dist/types/modes/components/btw-panel.d.ts +19 -0
  510. package/dist/types/modes/components/cache-invalidation-marker.d.ts +52 -0
  511. package/dist/types/modes/components/chat-block.d.ts +64 -0
  512. package/dist/types/modes/components/chat-transcript-builder.d.ts +45 -0
  513. package/dist/types/modes/components/collab-prompt-message.d.ts +10 -0
  514. package/dist/types/modes/components/compaction-summary-message.d.ts +46 -0
  515. package/dist/types/modes/components/copy-selector.d.ts +22 -0
  516. package/dist/types/modes/components/countdown-timer.d.ts +14 -0
  517. package/dist/types/modes/components/custom-editor.d.ts +163 -0
  518. package/dist/types/modes/components/custom-editor.test.d.ts +1 -0
  519. package/dist/types/modes/components/custom-message.d.ts +15 -0
  520. package/dist/types/modes/components/diff.d.ts +11 -0
  521. package/dist/types/modes/components/dynamic-border.d.ts +14 -0
  522. package/dist/types/modes/components/error-banner.d.ts +11 -0
  523. package/dist/types/modes/components/eval-execution.d.ts +29 -0
  524. package/dist/types/modes/components/execution-shared.d.ts +46 -0
  525. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +43 -0
  526. package/dist/types/modes/components/extensions/extension-list.d.ts +52 -0
  527. package/dist/types/modes/components/extensions/index.d.ts +8 -0
  528. package/dist/types/modes/components/extensions/inspector-panel.d.ts +8 -0
  529. package/dist/types/modes/components/extensions/state-manager.d.ts +50 -0
  530. package/dist/types/modes/components/extensions/types.d.ts +147 -0
  531. package/dist/types/modes/components/footer.d.ts +30 -0
  532. package/dist/types/modes/components/history-search.d.ts +7 -0
  533. package/dist/types/modes/components/hook-editor.d.ts +24 -0
  534. package/dist/types/modes/components/hook-input.d.ts +19 -0
  535. package/dist/types/modes/components/hook-message.d.ts +15 -0
  536. package/dist/types/modes/components/hook-selector.d.ts +68 -0
  537. package/dist/types/modes/components/index.d.ts +38 -0
  538. package/dist/types/modes/components/keybinding-hints.d.ts +40 -0
  539. package/dist/types/modes/components/late-diagnostics-message.d.ts +20 -0
  540. package/dist/types/modes/components/login-dialog.d.ts +40 -0
  541. package/dist/types/modes/components/logout-account-selector.d.ts +8 -0
  542. package/dist/types/modes/components/mcp-add-wizard.d.ts +38 -0
  543. package/dist/types/modes/components/message-frame.d.ts +44 -0
  544. package/dist/types/modes/components/model-selector.d.ts +36 -0
  545. package/dist/types/modes/components/move-overlay.d.ts +23 -0
  546. package/dist/types/modes/components/oauth-selector.d.ts +23 -0
  547. package/dist/types/modes/components/omfg-panel.d.ts +19 -0
  548. package/dist/types/modes/components/overlay-box.d.ts +17 -0
  549. package/dist/types/modes/components/plan-review-overlay.d.ts +61 -0
  550. package/dist/types/modes/components/plan-toc.d.ts +41 -0
  551. package/dist/types/modes/components/plugin-selector.d.ts +27 -0
  552. package/dist/types/modes/components/plugin-settings.d.ts +103 -0
  553. package/dist/types/modes/components/queue-mode-selector.d.ts +10 -0
  554. package/dist/types/modes/components/read-tool-group.d.ts +38 -0
  555. package/dist/types/modes/components/reset-usage-selector.d.ts +12 -0
  556. package/dist/types/modes/components/segment-track.d.ts +27 -0
  557. package/dist/types/modes/components/select-list-mouse-routing.d.ts +2 -0
  558. package/dist/types/modes/components/selector-helpers.d.ts +53 -0
  559. package/dist/types/modes/components/session-selector.d.ts +94 -0
  560. package/dist/types/modes/components/settings-defs.d.ts +60 -0
  561. package/dist/types/modes/components/settings-selector.d.ts +70 -0
  562. package/dist/types/modes/components/show-images-selector.d.ts +10 -0
  563. package/dist/types/modes/components/skill-message.d.ts +9 -0
  564. package/dist/types/modes/components/snapcompact-shape-preview.d.ts +31 -0
  565. package/dist/types/modes/components/status-line/component.d.ts +94 -0
  566. package/dist/types/modes/components/status-line/component.test.d.ts +1 -0
  567. package/dist/types/modes/components/status-line/context-thresholds.d.ts +10 -0
  568. package/dist/types/modes/components/status-line/git-utils.d.ts +22 -0
  569. package/dist/types/modes/components/status-line/index.d.ts +5 -0
  570. package/dist/types/modes/components/status-line/presets.d.ts +3 -0
  571. package/dist/types/modes/components/status-line/segments.d.ts +5 -0
  572. package/dist/types/modes/components/status-line/separators.d.ts +3 -0
  573. package/dist/types/modes/components/status-line/token-rate.d.ts +10 -0
  574. package/dist/types/modes/components/status-line/types.d.ts +150 -0
  575. package/dist/types/modes/components/theme-selector.d.ts +11 -0
  576. package/dist/types/modes/components/thinking-selector.d.ts +11 -0
  577. package/dist/types/modes/components/tiny-title-download-progress.d.ts +11 -0
  578. package/dist/types/modes/components/todo-reminder.d.ts +15 -0
  579. package/dist/types/modes/components/tool-execution.d.ts +117 -0
  580. package/dist/types/modes/components/transcript-container.d.ts +86 -0
  581. package/dist/types/modes/components/tree-selector.d.ts +31 -0
  582. package/dist/types/modes/components/ttsr-notification.d.ts +17 -0
  583. package/dist/types/modes/components/usage-row.d.ts +3 -0
  584. package/dist/types/modes/components/user-message-selector.d.ts +28 -0
  585. package/dist/types/modes/components/user-message.d.ts +9 -0
  586. package/dist/types/modes/components/visual-truncate.d.ts +19 -0
  587. package/dist/types/modes/components/welcome.d.ts +66 -0
  588. package/dist/types/modes/controllers/btw-controller.d.ts +14 -0
  589. package/dist/types/modes/controllers/command-controller-shared.d.ts +47 -0
  590. package/dist/types/modes/controllers/command-controller.d.ts +55 -0
  591. package/dist/types/modes/controllers/event-controller.d.ts +28 -0
  592. package/dist/types/modes/controllers/extension-ui-controller.d.ts +88 -0
  593. package/dist/types/modes/controllers/input-controller.d.ts +71 -0
  594. package/dist/types/modes/controllers/mcp-command-controller.d.ts +44 -0
  595. package/dist/types/modes/controllers/omfg-controller.d.ts +10 -0
  596. package/dist/types/modes/controllers/omfg-rule.d.ts +26 -0
  597. package/dist/types/modes/controllers/selector-controller.d.ts +61 -0
  598. package/dist/types/modes/controllers/session-focus-controller.d.ts +31 -0
  599. package/dist/types/modes/controllers/ssh-command-controller.d.ts +10 -0
  600. package/dist/types/modes/controllers/streaming-reveal.d.ts +45 -0
  601. package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
  602. package/dist/types/modes/controllers/todo-command-controller.d.ts +7 -0
  603. package/dist/types/modes/controllers/tool-args-reveal.d.ts +77 -0
  604. package/dist/types/modes/emoji-autocomplete.d.ts +16 -0
  605. package/dist/types/modes/gradient-highlight.d.ts +32 -0
  606. package/dist/types/modes/image-references.d.ts +28 -0
  607. package/dist/types/modes/index.d.ts +10 -0
  608. package/dist/types/modes/interactive-mode.d.ts +401 -0
  609. package/dist/types/modes/internal-url-autocomplete.d.ts +43 -0
  610. package/dist/types/modes/loop-limit.d.ts +35 -0
  611. package/dist/types/modes/magic-keywords.d.ts +26 -0
  612. package/dist/types/modes/markdown-prose.d.ts +27 -0
  613. package/dist/types/modes/oauth-manual-input.d.ts +15 -0
  614. package/dist/types/modes/orchestrate.d.ts +15 -0
  615. package/dist/types/modes/print-mode.d.ts +29 -0
  616. package/dist/types/modes/prompt-action-autocomplete.d.ts +46 -0
  617. package/dist/types/modes/rpc/host-tools.d.ts +16 -0
  618. package/dist/types/modes/rpc/host-uris.d.ts +38 -0
  619. package/dist/types/modes/rpc/rpc-client.d.ts +304 -0
  620. package/dist/types/modes/rpc/rpc-mode.d.ts +145 -0
  621. package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
  622. package/dist/types/modes/rpc/rpc-types.d.ts +705 -0
  623. package/dist/types/modes/running-subagent-badge.d.ts +6 -0
  624. package/dist/types/modes/runtime-init.d.ts +25 -0
  625. package/dist/types/modes/session-observer-registry.d.ts +35 -0
  626. package/dist/types/modes/session-teardown.d.ts +63 -0
  627. package/dist/types/modes/session-teardown.test.d.ts +1 -0
  628. package/dist/types/modes/setup-version.d.ts +11 -0
  629. package/dist/types/modes/setup-wizard/index.d.ts +22 -0
  630. package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
  631. package/dist/types/modes/setup-wizard/scenes/glyph.d.ts +2 -0
  632. package/dist/types/modes/setup-wizard/scenes/outro.d.ts +2 -0
  633. package/dist/types/modes/setup-wizard/scenes/providers.d.ts +2 -0
  634. package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +22 -0
  635. package/dist/types/modes/setup-wizard/scenes/splash.d.ts +11 -0
  636. package/dist/types/modes/setup-wizard/scenes/theme.d.ts +2 -0
  637. package/dist/types/modes/setup-wizard/scenes/types.d.ts +52 -0
  638. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +23 -0
  639. package/dist/types/modes/setup-wizard/startup-splash.d.ts +7 -0
  640. package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +15 -0
  641. package/dist/types/modes/shared.d.ts +15 -0
  642. package/dist/types/modes/skill-command.d.ts +32 -0
  643. package/dist/types/modes/theme/defaults/index.d.ts +9436 -0
  644. package/dist/types/modes/theme/mermaid-cache.d.ts +26 -0
  645. package/dist/types/modes/theme/mermaid-rendering.test.d.ts +1 -0
  646. package/dist/types/modes/theme/shimmer.d.ts +40 -0
  647. package/dist/types/modes/theme/theme.d.ts +360 -0
  648. package/dist/types/modes/turn-budget.d.ts +18 -0
  649. package/dist/types/modes/types.d.ts +399 -0
  650. package/dist/types/modes/ultrathink.d.ts +15 -0
  651. package/dist/types/modes/utils/context-usage.d.ts +64 -0
  652. package/dist/types/modes/utils/copy-targets.d.ts +75 -0
  653. package/dist/types/modes/utils/hotkeys-markdown.d.ts +5 -0
  654. package/dist/types/modes/utils/interactive-context-helpers.d.ts +14 -0
  655. package/dist/types/modes/utils/keybinding-matchers.d.ts +32 -0
  656. package/dist/types/modes/utils/tools-markdown.d.ts +5 -0
  657. package/dist/types/modes/utils/transcript-render-helpers.d.ts +63 -0
  658. package/dist/types/modes/utils/ui-helpers.d.ts +55 -0
  659. package/dist/types/modes/workflow.d.ts +15 -0
  660. package/dist/types/plan-mode/approved-plan-prompt.test.d.ts +1 -0
  661. package/dist/types/plan-mode/approved-plan.d.ts +68 -0
  662. package/dist/types/plan-mode/plan-handoff.d.ts +20 -0
  663. package/dist/types/plan-mode/plan-protection.d.ts +12 -0
  664. package/dist/types/plan-mode/state.d.ts +6 -0
  665. package/dist/types/registry/agent-lifecycle.d.ts +66 -0
  666. package/dist/types/registry/agent-registry.d.ts +97 -0
  667. package/dist/types/sdk.d.ts +370 -0
  668. package/dist/types/secrets/index.d.ts +9 -0
  669. package/dist/types/secrets/obfuscator.d.ts +63 -0
  670. package/dist/types/secrets/regex.d.ts +2 -0
  671. package/dist/types/session/agent-session.d.ts +1419 -0
  672. package/dist/types/session/agent-storage.d.ts +97 -0
  673. package/dist/types/session/artifacts.d.ts +61 -0
  674. package/dist/types/session/auth-broker-config.d.ts +45 -0
  675. package/dist/types/session/auth-storage.d.ts +7 -0
  676. package/dist/types/session/blob-store.d.ts +68 -0
  677. package/dist/types/session/client-bridge.d.ts +88 -0
  678. package/dist/types/session/codex-auto-reset.d.ts +111 -0
  679. package/dist/types/session/compact-modes.d.ts +60 -0
  680. package/dist/types/session/exit-diagnostics.d.ts +48 -0
  681. package/dist/types/session/history-storage.d.ts +30 -0
  682. package/dist/types/session/indexed-session-storage.d.ts +65 -0
  683. package/dist/types/session/messages.d.ts +220 -0
  684. package/dist/types/session/messages.test.d.ts +1 -0
  685. package/dist/types/session/provider-image-budget.d.ts +3 -0
  686. package/dist/types/session/redis-session-storage.d.ts +51 -0
  687. package/dist/types/session/session-context.d.ts +44 -0
  688. package/dist/types/session/session-dump-format.d.ts +30 -0
  689. package/dist/types/session/session-entries.d.ts +197 -0
  690. package/dist/types/session/session-history-format.d.ts +49 -0
  691. package/dist/types/session/session-listing.d.ts +78 -0
  692. package/dist/types/session/session-loader.d.ts +29 -0
  693. package/dist/types/session/session-manager.d.ts +306 -0
  694. package/dist/types/session/session-migrations.d.ts +12 -0
  695. package/dist/types/session/session-paths.d.ts +25 -0
  696. package/dist/types/session/session-persistence.d.ts +12 -0
  697. package/dist/types/session/session-storage.d.ts +129 -0
  698. package/dist/types/session/session-title-slot.d.ts +19 -0
  699. package/dist/types/session/settings-stream-fn.d.ts +21 -0
  700. package/dist/types/session/shake-types.d.ts +24 -0
  701. package/dist/types/session/snapcompact-inline.d.ts +145 -0
  702. package/dist/types/session/snapcompact-savings-journal.d.ts +46 -0
  703. package/dist/types/session/sql-session-storage.d.ts +72 -0
  704. package/dist/types/session/streaming-output.d.ts +229 -0
  705. package/dist/types/session/tool-choice-queue.d.ts +94 -0
  706. package/dist/types/session/turn-persistence.d.ts +88 -0
  707. package/dist/types/session/unexpected-stop-classifier.d.ts +13 -0
  708. package/dist/types/session/yield-queue.d.ts +37 -0
  709. package/dist/types/slash-commands/acp-builtins.d.ts +34 -0
  710. package/dist/types/slash-commands/available-commands.d.ts +34 -0
  711. package/dist/types/slash-commands/builtin-registry.d.ts +36 -0
  712. package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +14 -0
  713. package/dist/types/slash-commands/helpers/collab-qrcode.d.ts +13 -0
  714. package/dist/types/slash-commands/helpers/context-report.d.ts +7 -0
  715. package/dist/types/slash-commands/helpers/format.d.ts +10 -0
  716. package/dist/types/slash-commands/helpers/logout.d.ts +15 -0
  717. package/dist/types/slash-commands/helpers/marketplace-manager.d.ts +8 -0
  718. package/dist/types/slash-commands/helpers/mcp.d.ts +3 -0
  719. package/dist/types/slash-commands/helpers/parse.d.ts +33 -0
  720. package/dist/types/slash-commands/helpers/reset-usage.d.ts +27 -0
  721. package/dist/types/slash-commands/helpers/ssh.d.ts +3 -0
  722. package/dist/types/slash-commands/helpers/stats-dashboard.d.ts +13 -0
  723. package/dist/types/slash-commands/helpers/todo.d.ts +3 -0
  724. package/dist/types/slash-commands/helpers/usage-report.d.ts +7 -0
  725. package/dist/types/slash-commands/marketplace-install-parser.d.ts +33 -0
  726. package/dist/types/slash-commands/types.d.ts +127 -0
  727. package/dist/types/ssh/__tests__/connection-manager-args.test.d.ts +1 -0
  728. package/dist/types/ssh/__tests__/connection-manager-timeout.test.d.ts +1 -0
  729. package/dist/types/ssh/__tests__/file-transfer-posix-guard.test.d.ts +1 -0
  730. package/dist/types/ssh/__tests__/sshfs-mount.test.d.ts +1 -0
  731. package/dist/types/ssh/config-writer.d.ts +49 -0
  732. package/dist/types/ssh/connection-manager.d.ts +109 -0
  733. package/dist/types/ssh/file-transfer.d.ts +79 -0
  734. package/dist/types/ssh/ssh-executor.d.ts +37 -0
  735. package/dist/types/ssh/sshfs-mount.d.ts +15 -0
  736. package/dist/types/ssh/utils.d.ts +24 -0
  737. package/dist/types/startup-splash.d.ts +12 -0
  738. package/dist/types/stt/asr-client.d.ts +68 -0
  739. package/dist/types/stt/asr-protocol.d.ts +97 -0
  740. package/dist/types/stt/asr-worker.d.ts +2 -0
  741. package/dist/types/stt/downloader.d.ts +47 -0
  742. package/dist/types/stt/endpointer.d.ts +59 -0
  743. package/dist/types/stt/index.d.ts +8 -0
  744. package/dist/types/stt/models.d.ts +120 -0
  745. package/dist/types/stt/recorder.d.ts +30 -0
  746. package/dist/types/stt/stt-controller.d.ts +24 -0
  747. package/dist/types/stt/submit-trigger.d.ts +30 -0
  748. package/dist/types/stt/transcriber.d.ts +14 -0
  749. package/dist/types/stt/wav.d.ts +29 -0
  750. package/dist/types/subprocess/worker-client.d.ts +163 -0
  751. package/dist/types/subprocess/worker-runtime.d.ts +118 -0
  752. package/dist/types/system-prompt.d.ts +128 -0
  753. package/dist/types/system-prompt.test.d.ts +1 -0
  754. package/dist/types/task/agents.d.ts +28 -0
  755. package/dist/types/task/commands.d.ts +35 -0
  756. package/dist/types/task/discovery.d.ts +20 -0
  757. package/dist/types/task/executor.d.ts +214 -0
  758. package/dist/types/task/index.d.ts +79 -0
  759. package/dist/types/task/isolation-runner.d.ts +128 -0
  760. package/dist/types/task/name-generator.d.ts +16 -0
  761. package/dist/types/task/omp-command.d.ts +7 -0
  762. package/dist/types/task/output-manager.d.ts +20 -0
  763. package/dist/types/task/parallel.d.ts +55 -0
  764. package/dist/types/task/persisted-revive.d.ts +36 -0
  765. package/dist/types/task/provider-concurrency.d.ts +40 -0
  766. package/dist/types/task/render.d.ts +34 -0
  767. package/dist/types/task/render.test.d.ts +1 -0
  768. package/dist/types/task/renderer.d.ts +14 -0
  769. package/dist/types/task/repair-args.d.ts +53 -0
  770. package/dist/types/task/spawn-policy.d.ts +17 -0
  771. package/dist/types/task/spawn-policy.test.d.ts +1 -0
  772. package/dist/types/task/subprocess-tool-registry.d.ts +72 -0
  773. package/dist/types/task/types.d.ts +384 -0
  774. package/dist/types/task/worktree.d.ts +135 -0
  775. package/dist/types/task/yield-assembly.d.ts +28 -0
  776. package/dist/types/telemetry-export.d.ts +19 -0
  777. package/dist/types/thinking.d.ts +96 -0
  778. package/dist/types/tiny/device.d.ts +78 -0
  779. package/dist/types/tiny/dtype.d.ts +85 -0
  780. package/dist/types/tiny/models.d.ts +230 -0
  781. package/dist/types/tiny/text.d.ts +44 -0
  782. package/dist/types/tiny/title-client.d.ts +68 -0
  783. package/dist/types/tiny/title-protocol.d.ts +78 -0
  784. package/dist/types/tiny/worker.d.ts +2 -0
  785. package/dist/types/tool-discovery/mode.d.ts +8 -0
  786. package/dist/types/tool-discovery/tool-index.d.ts +57 -0
  787. package/dist/types/tools/__tests__/eval-description.test.d.ts +1 -0
  788. package/dist/types/tools/__tests__/json-tree.test.d.ts +1 -0
  789. package/dist/types/tools/acp-bridge.d.ts +29 -0
  790. package/dist/types/tools/approval.d.ts +46 -0
  791. package/dist/types/tools/ask.d.ts +119 -0
  792. package/dist/types/tools/ast-edit.d.ts +84 -0
  793. package/dist/types/tools/ast-grep.d.ts +76 -0
  794. package/dist/types/tools/auto-generated-guard.d.ts +17 -0
  795. package/dist/types/tools/bash-command-fixup.d.ts +11 -0
  796. package/dist/types/tools/bash-interactive.d.ts +16 -0
  797. package/dist/types/tools/bash-interceptor.d.ts +24 -0
  798. package/dist/types/tools/bash-pty-selection.d.ts +7 -0
  799. package/dist/types/tools/bash-skill-urls.d.ts +31 -0
  800. package/dist/types/tools/bash.d.ts +173 -0
  801. package/dist/types/tools/browser/aria/aria-snapshot.d.ts +39 -0
  802. package/dist/types/tools/browser/attach.d.ts +34 -0
  803. package/dist/types/tools/browser/cmux/cmux-tab.d.ts +212 -0
  804. package/dist/types/tools/browser/cmux/rpc.d.ts +70 -0
  805. package/dist/types/tools/browser/cmux/socket-client.d.ts +19 -0
  806. package/dist/types/tools/browser/launch.d.ts +67 -0
  807. package/dist/types/tools/browser/readable.d.ts +17 -0
  808. package/dist/types/tools/browser/registry.d.ts +58 -0
  809. package/dist/types/tools/browser/render.d.ts +54 -0
  810. package/dist/types/tools/browser/run-cancellation.d.ts +4 -0
  811. package/dist/types/tools/browser/tab-protocol.d.ts +146 -0
  812. package/dist/types/tools/browser/tab-supervisor.d.ts +114 -0
  813. package/dist/types/tools/browser/tab-worker-entry.d.ts +1 -0
  814. package/dist/types/tools/browser/tab-worker.d.ts +56 -0
  815. package/dist/types/tools/browser.d.ts +96 -0
  816. package/dist/types/tools/builtin-names.d.ts +6 -0
  817. package/dist/types/tools/checkpoint.d.ts +72 -0
  818. package/dist/types/tools/conflict-detect.d.ts +221 -0
  819. package/dist/types/tools/context.d.ts +19 -0
  820. package/dist/types/tools/debug.d.ts +157 -0
  821. package/dist/types/tools/eval-backends.d.ts +15 -0
  822. package/dist/types/tools/eval-render.d.ts +58 -0
  823. package/dist/types/tools/eval.d.ts +66 -0
  824. package/dist/types/tools/fetch.d.ts +99 -0
  825. package/dist/types/tools/file-recorder.d.ts +13 -0
  826. package/dist/types/tools/fs-cache-invalidation.d.ts +15 -0
  827. package/dist/types/tools/gh-cache-invalidation.d.ts +6 -0
  828. package/dist/types/tools/gh-format.d.ts +6 -0
  829. package/dist/types/tools/gh-renderer.d.ts +25 -0
  830. package/dist/types/tools/gh.d.ts +331 -0
  831. package/dist/types/tools/github-cache.d.ts +123 -0
  832. package/dist/types/tools/glob.d.ts +96 -0
  833. package/dist/types/tools/grep.d.ts +99 -0
  834. package/dist/types/tools/grouped-file-output.d.ts +70 -0
  835. package/dist/types/tools/image-gen.d.ts +66 -0
  836. package/dist/types/tools/index.d.ts +368 -0
  837. package/dist/types/tools/inspect-image-renderer.d.ts +26 -0
  838. package/dist/types/tools/inspect-image.d.ts +32 -0
  839. package/dist/types/tools/irc.d.ts +112 -0
  840. package/dist/types/tools/job.d.ts +73 -0
  841. package/dist/types/tools/json-tree.d.ts +23 -0
  842. package/dist/types/tools/jtd-to-json-schema.d.ts +29 -0
  843. package/dist/types/tools/jtd-to-typescript.d.ts +26 -0
  844. package/dist/types/tools/jtd-utils.d.ts +42 -0
  845. package/dist/types/tools/learn.d.ts +44 -0
  846. package/dist/types/tools/list-limit.d.ts +12 -0
  847. package/dist/types/tools/manage-skill.d.ts +31 -0
  848. package/dist/types/tools/match-line-format.d.ts +11 -0
  849. package/dist/types/tools/memory-edit.d.ts +31 -0
  850. package/dist/types/tools/memory-recall.d.ts +23 -0
  851. package/dist/types/tools/memory-reflect.d.ts +25 -0
  852. package/dist/types/tools/memory-render.d.ts +63 -0
  853. package/dist/types/tools/memory-retain.d.ts +29 -0
  854. package/dist/types/tools/output-meta.d.ts +211 -0
  855. package/dist/types/tools/output-schema-validator.d.ts +77 -0
  856. package/dist/types/tools/path-utils.d.ts +267 -0
  857. package/dist/types/tools/plan-mode-guard.d.ts +33 -0
  858. package/dist/types/tools/read.d.ts +87 -0
  859. package/dist/types/tools/render-utils.d.ts +218 -0
  860. package/dist/types/tools/renderers.d.ts +49 -0
  861. package/dist/types/tools/report-tool-issue.d.ts +127 -0
  862. package/dist/types/tools/resolve.d.ts +94 -0
  863. package/dist/types/tools/review.d.ts +59 -0
  864. package/dist/types/tools/search-tool-bm25.d.ts +65 -0
  865. package/dist/types/tools/sqlite-reader.d.ts +114 -0
  866. package/dist/types/tools/ssh.d.ts +74 -0
  867. package/dist/types/tools/todo.d.ts +126 -0
  868. package/dist/types/tools/tool-errors.d.ts +33 -0
  869. package/dist/types/tools/tool-result.d.ts +34 -0
  870. package/dist/types/tools/tool-timeouts.d.ts +51 -0
  871. package/dist/types/tools/tts.d.ts +42 -0
  872. package/dist/types/tools/write.d.ts +66 -0
  873. package/dist/types/tools/yield.d.ts +39 -0
  874. package/dist/types/tts/downloader.d.ts +20 -0
  875. package/dist/types/tts/index.d.ts +10 -0
  876. package/dist/types/tts/models.d.ts +82 -0
  877. package/dist/types/tts/player.d.ts +32 -0
  878. package/dist/types/tts/runtime.d.ts +6 -0
  879. package/dist/types/tts/speakable.d.ts +47 -0
  880. package/dist/types/tts/speech-enhancer.d.ts +46 -0
  881. package/dist/types/tts/streaming-player.d.ts +40 -0
  882. package/dist/types/tts/tts-client.d.ts +69 -0
  883. package/dist/types/tts/tts-protocol.d.ts +102 -0
  884. package/dist/types/tts/tts-worker.d.ts +2 -0
  885. package/dist/types/tts/vocalizer.d.ts +48 -0
  886. package/dist/types/tts/wav.d.ts +8 -0
  887. package/dist/types/tui/code-cell.d.ts +47 -0
  888. package/dist/types/tui/file-list.d.ts +22 -0
  889. package/dist/types/tui/hyperlink.d.ts +61 -0
  890. package/dist/types/tui/index.d.ts +12 -0
  891. package/dist/types/tui/output-block.d.ts +59 -0
  892. package/dist/types/tui/status-line.d.ts +21 -0
  893. package/dist/types/tui/tree-list.d.ts +20 -0
  894. package/dist/types/tui/types.d.ts +13 -0
  895. package/dist/types/tui/utils.d.ts +36 -0
  896. package/dist/types/tui/width-aware-text.d.ts +23 -0
  897. package/dist/types/utils/active-repo-context.d.ts +8 -0
  898. package/dist/types/utils/block-context.d.ts +35 -0
  899. package/dist/types/utils/changelog.d.ts +33 -0
  900. package/dist/types/utils/clipboard.d.ts +37 -0
  901. package/dist/types/utils/command-args.d.ts +9 -0
  902. package/dist/types/utils/commit-message-generator.d.ts +7 -0
  903. package/dist/types/utils/edit-mode.d.ts +13 -0
  904. package/dist/types/utils/enhanced-paste.d.ts +20 -0
  905. package/dist/types/utils/event-bus.d.ts +6 -0
  906. package/dist/types/utils/external-editor.d.ts +27 -0
  907. package/dist/types/utils/fetch-timeout.d.ts +4 -0
  908. package/dist/types/utils/file-display-mode.d.ts +27 -0
  909. package/dist/types/utils/file-mentions.d.ts +13 -0
  910. package/dist/types/utils/git.d.ts +471 -0
  911. package/dist/types/utils/image-loading.d.ts +67 -0
  912. package/dist/types/utils/image-resize.d.ts +42 -0
  913. package/dist/types/utils/image-vision-fallback.d.ts +28 -0
  914. package/dist/types/utils/ipc.d.ts +22 -0
  915. package/dist/types/utils/jj.d.ts +74 -0
  916. package/dist/types/utils/lang-from-path.d.ts +8 -0
  917. package/dist/types/utils/markit-cache.d.ts +23 -0
  918. package/dist/types/utils/markit.d.ts +20 -0
  919. package/dist/types/utils/mupdf-wasm-embed.d.ts +1 -0
  920. package/dist/types/utils/open.d.ts +2 -0
  921. package/dist/types/utils/prompt-path.d.ts +1 -0
  922. package/dist/types/utils/qrcode.d.ts +48 -0
  923. package/dist/types/utils/session-color.d.ts +27 -0
  924. package/dist/types/utils/shell-snapshot.d.ts +15 -0
  925. package/dist/types/utils/sixel.d.ts +21 -0
  926. package/dist/types/utils/thinking-display.d.ts +7 -0
  927. package/dist/types/utils/title-generator.d.ts +33 -0
  928. package/dist/types/utils/tool-choice.d.ts +15 -0
  929. package/dist/types/utils/tools-manager.d.ts +12 -0
  930. package/dist/types/utils/turndown.d.ts +15 -0
  931. package/dist/types/utils/zip.d.ts +119 -0
  932. package/dist/types/web/kagi.d.ts +99 -0
  933. package/dist/types/web/parallel.d.ts +67 -0
  934. package/dist/types/web/scrapers/artifacthub.d.ts +6 -0
  935. package/dist/types/web/scrapers/arxiv.d.ts +5 -0
  936. package/dist/types/web/scrapers/aur.d.ts +5 -0
  937. package/dist/types/web/scrapers/biorxiv.d.ts +5 -0
  938. package/dist/types/web/scrapers/bluesky.d.ts +5 -0
  939. package/dist/types/web/scrapers/brew.d.ts +5 -0
  940. package/dist/types/web/scrapers/cheatsh.d.ts +8 -0
  941. package/dist/types/web/scrapers/chocolatey.d.ts +5 -0
  942. package/dist/types/web/scrapers/choosealicense.d.ts +2 -0
  943. package/dist/types/web/scrapers/cisa-kev.d.ts +5 -0
  944. package/dist/types/web/scrapers/clojars.d.ts +5 -0
  945. package/dist/types/web/scrapers/coingecko.d.ts +5 -0
  946. package/dist/types/web/scrapers/crates-io.d.ts +5 -0
  947. package/dist/types/web/scrapers/crossref.d.ts +2 -0
  948. package/dist/types/web/scrapers/devto.d.ts +5 -0
  949. package/dist/types/web/scrapers/discogs.d.ts +8 -0
  950. package/dist/types/web/scrapers/discourse.d.ts +5 -0
  951. package/dist/types/web/scrapers/dockerhub.d.ts +5 -0
  952. package/dist/types/web/scrapers/docs-rs.d.ts +2 -0
  953. package/dist/types/web/scrapers/fdroid.d.ts +5 -0
  954. package/dist/types/web/scrapers/firefox-addons.d.ts +2 -0
  955. package/dist/types/web/scrapers/flathub.d.ts +2 -0
  956. package/dist/types/web/scrapers/github-gist.d.ts +5 -0
  957. package/dist/types/web/scrapers/github.d.ts +34 -0
  958. package/dist/types/web/scrapers/gitlab.d.ts +5 -0
  959. package/dist/types/web/scrapers/go-pkg.d.ts +5 -0
  960. package/dist/types/web/scrapers/hackage.d.ts +5 -0
  961. package/dist/types/web/scrapers/hackernews.d.ts +2 -0
  962. package/dist/types/web/scrapers/hex.d.ts +5 -0
  963. package/dist/types/web/scrapers/huggingface.d.ts +2 -0
  964. package/dist/types/web/scrapers/iacr.d.ts +5 -0
  965. package/dist/types/web/scrapers/index.d.ts +84 -0
  966. package/dist/types/web/scrapers/jetbrains-marketplace.d.ts +2 -0
  967. package/dist/types/web/scrapers/lemmy.d.ts +2 -0
  968. package/dist/types/web/scrapers/lobsters.d.ts +5 -0
  969. package/dist/types/web/scrapers/mastodon.d.ts +5 -0
  970. package/dist/types/web/scrapers/maven.d.ts +6 -0
  971. package/dist/types/web/scrapers/mdn.d.ts +2 -0
  972. package/dist/types/web/scrapers/metacpan.d.ts +5 -0
  973. package/dist/types/web/scrapers/musicbrainz.d.ts +5 -0
  974. package/dist/types/web/scrapers/npm.d.ts +5 -0
  975. package/dist/types/web/scrapers/nuget.d.ts +5 -0
  976. package/dist/types/web/scrapers/nvd.d.ts +5 -0
  977. package/dist/types/web/scrapers/ollama.d.ts +2 -0
  978. package/dist/types/web/scrapers/open-vsx.d.ts +5 -0
  979. package/dist/types/web/scrapers/opencorporates.d.ts +5 -0
  980. package/dist/types/web/scrapers/openlibrary.d.ts +5 -0
  981. package/dist/types/web/scrapers/orcid.d.ts +5 -0
  982. package/dist/types/web/scrapers/osv.d.ts +5 -0
  983. package/dist/types/web/scrapers/packagist.d.ts +5 -0
  984. package/dist/types/web/scrapers/pub-dev.d.ts +5 -0
  985. package/dist/types/web/scrapers/pubmed.d.ts +5 -0
  986. package/dist/types/web/scrapers/pypi.d.ts +5 -0
  987. package/dist/types/web/scrapers/rawg.d.ts +2 -0
  988. package/dist/types/web/scrapers/readthedocs.d.ts +5 -0
  989. package/dist/types/web/scrapers/reddit.d.ts +5 -0
  990. package/dist/types/web/scrapers/repology.d.ts +5 -0
  991. package/dist/types/web/scrapers/rfc.d.ts +5 -0
  992. package/dist/types/web/scrapers/rubygems.d.ts +5 -0
  993. package/dist/types/web/scrapers/searchcode.d.ts +2 -0
  994. package/dist/types/web/scrapers/sec-edgar.d.ts +5 -0
  995. package/dist/types/web/scrapers/semantic-scholar.d.ts +2 -0
  996. package/dist/types/web/scrapers/snapcraft.d.ts +2 -0
  997. package/dist/types/web/scrapers/sourcegraph.d.ts +2 -0
  998. package/dist/types/web/scrapers/spdx.d.ts +5 -0
  999. package/dist/types/web/scrapers/spotify.d.ts +8 -0
  1000. package/dist/types/web/scrapers/stackoverflow.d.ts +6 -0
  1001. package/dist/types/web/scrapers/terraform.d.ts +5 -0
  1002. package/dist/types/web/scrapers/tldr.d.ts +7 -0
  1003. package/dist/types/web/scrapers/twitter.d.ts +5 -0
  1004. package/dist/types/web/scrapers/types.d.ts +90 -0
  1005. package/dist/types/web/scrapers/utils.d.ts +26 -0
  1006. package/dist/types/web/scrapers/vimeo.d.ts +5 -0
  1007. package/dist/types/web/scrapers/vscode-marketplace.d.ts +5 -0
  1008. package/dist/types/web/scrapers/w3c.d.ts +2 -0
  1009. package/dist/types/web/scrapers/wikidata.d.ts +5 -0
  1010. package/dist/types/web/scrapers/wikipedia.d.ts +5 -0
  1011. package/dist/types/web/scrapers/youtube.d.ts +5 -0
  1012. package/dist/types/web/search/index.d.ts +74 -0
  1013. package/dist/types/web/search/provider.d.ts +30 -0
  1014. package/dist/types/web/search/providers/anthropic.d.ts +33 -0
  1015. package/dist/types/web/search/providers/base.d.ts +84 -0
  1016. package/dist/types/web/search/providers/brave.d.ts +28 -0
  1017. package/dist/types/web/search/providers/codex.d.ts +36 -0
  1018. package/dist/types/web/search/providers/duckduckgo.d.ts +14 -0
  1019. package/dist/types/web/search/providers/exa.d.ts +70 -0
  1020. package/dist/types/web/search/providers/firecrawl.d.ts +28 -0
  1021. package/dist/types/web/search/providers/gemini.d.ts +63 -0
  1022. package/dist/types/web/search/providers/jina.d.ts +31 -0
  1023. package/dist/types/web/search/providers/kagi.d.ts +30 -0
  1024. package/dist/types/web/search/providers/kimi.d.ts +32 -0
  1025. package/dist/types/web/search/providers/parallel.d.ts +16 -0
  1026. package/dist/types/web/search/providers/perplexity-auth.d.ts +37 -0
  1027. package/dist/types/web/search/providers/perplexity.d.ts +58 -0
  1028. package/dist/types/web/search/providers/searxng.d.ts +45 -0
  1029. package/dist/types/web/search/providers/synthetic.d.ts +25 -0
  1030. package/dist/types/web/search/providers/tavily.d.ts +30 -0
  1031. package/dist/types/web/search/providers/tinyfish.d.ts +29 -0
  1032. package/dist/types/web/search/providers/utils.d.ts +52 -0
  1033. package/dist/types/web/search/providers/xai.d.ts +13 -0
  1034. package/dist/types/web/search/providers/zai.d.ts +29 -0
  1035. package/dist/types/web/search/render.d.ts +34 -0
  1036. package/dist/types/web/search/types.d.ts +431 -0
  1037. package/dist/types/web/search/utils.d.ts +4 -0
  1038. package/dist/types/workspace-tree.d.ts +42 -0
  1039. package/examples/README.md +21 -0
  1040. package/examples/custom-tools/README.md +104 -0
  1041. package/examples/custom-tools/hello/index.ts +20 -0
  1042. package/examples/extensions/README.md +142 -0
  1043. package/examples/extensions/api-demo.ts +79 -0
  1044. package/examples/extensions/chalk-logger.ts +25 -0
  1045. package/examples/extensions/hello.ts +31 -0
  1046. package/examples/extensions/pirate.ts +43 -0
  1047. package/examples/extensions/plan-mode.ts +549 -0
  1048. package/examples/extensions/reload-runtime.ts +38 -0
  1049. package/examples/extensions/thinking-note.ts +13 -0
  1050. package/examples/extensions/tools.ts +145 -0
  1051. package/examples/extensions/with-deps/index.ts +36 -0
  1052. package/examples/extensions/with-deps/package-lock.json +31 -0
  1053. package/examples/extensions/with-deps/package.json +17 -0
  1054. package/examples/hooks/README.md +56 -0
  1055. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  1056. package/examples/hooks/confirm-destructive.ts +58 -0
  1057. package/examples/hooks/custom-compaction.ts +115 -0
  1058. package/examples/hooks/dirty-repo-guard.ts +51 -0
  1059. package/examples/hooks/file-trigger.ts +40 -0
  1060. package/examples/hooks/git-checkpoint.ts +52 -0
  1061. package/examples/hooks/handoff.ts +149 -0
  1062. package/examples/hooks/permission-gate.ts +33 -0
  1063. package/examples/hooks/protected-paths.ts +29 -0
  1064. package/examples/hooks/qna.ts +118 -0
  1065. package/examples/hooks/status-line.ts +39 -0
  1066. package/examples/sdk/01-minimal.ts +21 -0
  1067. package/examples/sdk/02-custom-model.ts +49 -0
  1068. package/examples/sdk/03-custom-prompt.ts +46 -0
  1069. package/examples/sdk/04-skills.ts +43 -0
  1070. package/examples/sdk/06-extensions.ts +82 -0
  1071. package/examples/sdk/06-hooks.ts +61 -0
  1072. package/examples/sdk/07-context-files.ts +35 -0
  1073. package/examples/sdk/08-prompt-templates.ts +41 -0
  1074. package/examples/sdk/08-slash-commands.ts +46 -0
  1075. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  1076. package/examples/sdk/11-sessions.ts +47 -0
  1077. package/examples/sdk/12-redis-sessions.ts +54 -0
  1078. package/examples/sdk/13-sql-sessions.ts +61 -0
  1079. package/examples/sdk/README.md +172 -0
  1080. package/package.json +594 -0
  1081. package/scripts/bench-guard.ts +71 -0
  1082. package/scripts/build-binary.ts +135 -0
  1083. package/scripts/bundle-dist.ts +129 -0
  1084. package/scripts/embed-mupdf-wasm.ts +67 -0
  1085. package/scripts/format-prompts.ts +68 -0
  1086. package/scripts/generate-aria-snapshot.ts +134 -0
  1087. package/scripts/generate-docs-index.ts +148 -0
  1088. package/scripts/generate-legacy-pi-bundled-registry.ts +420 -0
  1089. package/scripts/generate-share-viewer.ts +36 -0
  1090. package/scripts/measure-prompt-tokens.ts +63 -0
  1091. package/scripts/omp +42 -0
  1092. package/scripts/omp.ts +19 -0
  1093. package/src/advisor/__tests__/advisor.test.ts +1662 -0
  1094. package/src/advisor/__tests__/config.test.ts +173 -0
  1095. package/src/advisor/__tests__/emission-guard.test.ts +147 -0
  1096. package/src/advisor/advise-tool.ts +203 -0
  1097. package/src/advisor/config.ts +258 -0
  1098. package/src/advisor/emission-guard.ts +172 -0
  1099. package/src/advisor/index.ts +6 -0
  1100. package/src/advisor/runtime.ts +518 -0
  1101. package/src/advisor/transcript-recorder.ts +159 -0
  1102. package/src/advisor/watchdog.ts +135 -0
  1103. package/src/async/index.ts +1 -0
  1104. package/src/async/job-manager.ts +698 -0
  1105. package/src/auto-thinking/classifier.ts +195 -0
  1106. package/src/autolearn/controller.ts +145 -0
  1107. package/src/autolearn/managed-skills.ts +255 -0
  1108. package/src/autoresearch/command-resume.md +14 -0
  1109. package/src/autoresearch/dashboard.ts +436 -0
  1110. package/src/autoresearch/git.ts +331 -0
  1111. package/src/autoresearch/helpers.ts +218 -0
  1112. package/src/autoresearch/index.ts +541 -0
  1113. package/src/autoresearch/prompt-setup.md +43 -0
  1114. package/src/autoresearch/prompt.md +103 -0
  1115. package/src/autoresearch/resume-message.md +10 -0
  1116. package/src/autoresearch/state.ts +273 -0
  1117. package/src/autoresearch/storage.ts +700 -0
  1118. package/src/autoresearch/tools/init-experiment.ts +269 -0
  1119. package/src/autoresearch/tools/log-experiment.ts +521 -0
  1120. package/src/autoresearch/tools/run-experiment.ts +407 -0
  1121. package/src/autoresearch/tools/update-notes.ts +109 -0
  1122. package/src/autoresearch/types.ts +168 -0
  1123. package/src/capability/context-file.ts +44 -0
  1124. package/src/capability/extension-module.ts +34 -0
  1125. package/src/capability/extension.ts +47 -0
  1126. package/src/capability/fs.ts +117 -0
  1127. package/src/capability/hook.ts +40 -0
  1128. package/src/capability/index.ts +436 -0
  1129. package/src/capability/instruction.ts +37 -0
  1130. package/src/capability/mcp.ts +76 -0
  1131. package/src/capability/prompt.ts +35 -0
  1132. package/src/capability/rule-buckets.ts +66 -0
  1133. package/src/capability/rule.ts +261 -0
  1134. package/src/capability/settings.ts +34 -0
  1135. package/src/capability/skill.ts +63 -0
  1136. package/src/capability/slash-command.ts +40 -0
  1137. package/src/capability/ssh.ts +41 -0
  1138. package/src/capability/system-prompt.ts +34 -0
  1139. package/src/capability/tool.ts +38 -0
  1140. package/src/capability/types.ts +168 -0
  1141. package/src/cli/agents-cli.ts +138 -0
  1142. package/src/cli/args.ts +393 -0
  1143. package/src/cli/auth-broker-cli.ts +921 -0
  1144. package/src/cli/auth-gateway-cli.ts +608 -0
  1145. package/src/cli/bench-cli.ts +623 -0
  1146. package/src/cli/classify-install-target.ts +76 -0
  1147. package/src/cli/claude-trace-cli.ts +795 -0
  1148. package/src/cli/commands/init-xdg.ts +27 -0
  1149. package/src/cli/completion-gen.ts +550 -0
  1150. package/src/cli/config-cli.ts +422 -0
  1151. package/src/cli/dry-balance-cli.ts +853 -0
  1152. package/src/cli/extension-flags.ts +48 -0
  1153. package/src/cli/file-processor.ts +133 -0
  1154. package/src/cli/flag-tables.ts +325 -0
  1155. package/src/cli/gallery-cli.ts +272 -0
  1156. package/src/cli/gallery-fixtures/agentic.ts +416 -0
  1157. package/src/cli/gallery-fixtures/codeintel.ts +187 -0
  1158. package/src/cli/gallery-fixtures/edit.ts +254 -0
  1159. package/src/cli/gallery-fixtures/fs.ts +220 -0
  1160. package/src/cli/gallery-fixtures/index.ts +40 -0
  1161. package/src/cli/gallery-fixtures/interaction.ts +46 -0
  1162. package/src/cli/gallery-fixtures/memory.ts +81 -0
  1163. package/src/cli/gallery-fixtures/misc.ts +250 -0
  1164. package/src/cli/gallery-fixtures/search.ts +213 -0
  1165. package/src/cli/gallery-fixtures/shell.ts +159 -0
  1166. package/src/cli/gallery-fixtures/types.ts +57 -0
  1167. package/src/cli/gallery-fixtures/web.ts +158 -0
  1168. package/src/cli/gallery-screenshot.ts +279 -0
  1169. package/src/cli/gc-cli.ts +946 -0
  1170. package/src/cli/grep-cli.ts +160 -0
  1171. package/src/cli/grievances-cli.ts +256 -0
  1172. package/src/cli/initial-message.ts +58 -0
  1173. package/src/cli/models-cli.ts +368 -0
  1174. package/src/cli/plugin-cli.ts +996 -0
  1175. package/src/cli/profile-alias.ts +369 -0
  1176. package/src/cli/profile-bootstrap.ts +233 -0
  1177. package/src/cli/read-cli.ts +57 -0
  1178. package/src/cli/session-picker.ts +93 -0
  1179. package/src/cli/setup-cli.ts +332 -0
  1180. package/src/cli/setup-model-picker.ts +43 -0
  1181. package/src/cli/shell-cli.ts +176 -0
  1182. package/src/cli/ssh-cli.ts +179 -0
  1183. package/src/cli/startup-cwd.ts +58 -0
  1184. package/src/cli/stats-cli.ts +229 -0
  1185. package/src/cli/tiny-models-cli.ts +153 -0
  1186. package/src/cli/ttsr-cli.ts +995 -0
  1187. package/src/cli/update-cli.test.ts +28 -0
  1188. package/src/cli/update-cli.ts +944 -0
  1189. package/src/cli/usage-cli.ts +857 -0
  1190. package/src/cli/web-search-cli.ts +137 -0
  1191. package/src/cli/worktree-cli.ts +294 -0
  1192. package/src/cli-commands.ts +131 -0
  1193. package/src/cli.ts +348 -0
  1194. package/src/collab/crypto.ts +63 -0
  1195. package/src/collab/display-name.ts +13 -0
  1196. package/src/collab/guest.ts +731 -0
  1197. package/src/collab/host.ts +690 -0
  1198. package/src/collab/protocol.ts +296 -0
  1199. package/src/collab/relay-client.ts +216 -0
  1200. package/src/collab/replication-shrink.ts +111 -0
  1201. package/src/commands/acp.ts +24 -0
  1202. package/src/commands/agents.ts +57 -0
  1203. package/src/commands/auth-broker.ts +99 -0
  1204. package/src/commands/auth-gateway.ts +69 -0
  1205. package/src/commands/bench.ts +51 -0
  1206. package/src/commands/commit.ts +46 -0
  1207. package/src/commands/complete.ts +66 -0
  1208. package/src/commands/completions.ts +60 -0
  1209. package/src/commands/config.ts +51 -0
  1210. package/src/commands/dry-balance.ts +43 -0
  1211. package/src/commands/gallery.ts +60 -0
  1212. package/src/commands/gc.ts +46 -0
  1213. package/src/commands/grep.ts +48 -0
  1214. package/src/commands/grievances.ts +51 -0
  1215. package/src/commands/install.ts +107 -0
  1216. package/src/commands/join.ts +39 -0
  1217. package/src/commands/launch.ts +182 -0
  1218. package/src/commands/models.ts +60 -0
  1219. package/src/commands/plugin.ts +78 -0
  1220. package/src/commands/read.ts +38 -0
  1221. package/src/commands/say.ts +102 -0
  1222. package/src/commands/setup.ts +67 -0
  1223. package/src/commands/shell.ts +29 -0
  1224. package/src/commands/ssh.ts +60 -0
  1225. package/src/commands/stats.ts +29 -0
  1226. package/src/commands/tiny-models.ts +36 -0
  1227. package/src/commands/token.ts +162 -0
  1228. package/src/commands/ttsr.ts +125 -0
  1229. package/src/commands/update.ts +27 -0
  1230. package/src/commands/usage.ts +43 -0
  1231. package/src/commands/web-search.ts +42 -0
  1232. package/src/commands/worktree.ts +62 -0
  1233. package/src/commit/agentic/agent.ts +318 -0
  1234. package/src/commit/agentic/fallback.ts +96 -0
  1235. package/src/commit/agentic/index.ts +355 -0
  1236. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  1237. package/src/commit/agentic/prompts/session-user.md +25 -0
  1238. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  1239. package/src/commit/agentic/prompts/system.md +38 -0
  1240. package/src/commit/agentic/state.ts +60 -0
  1241. package/src/commit/agentic/tools/analyze-file.ts +149 -0
  1242. package/src/commit/agentic/tools/git-file-diff.ts +191 -0
  1243. package/src/commit/agentic/tools/git-hunk.ts +52 -0
  1244. package/src/commit/agentic/tools/git-overview.ts +81 -0
  1245. package/src/commit/agentic/tools/index.ts +54 -0
  1246. package/src/commit/agentic/tools/propose-changelog.ts +147 -0
  1247. package/src/commit/agentic/tools/propose-commit.ts +109 -0
  1248. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  1249. package/src/commit/agentic/tools/schemas.ts +11 -0
  1250. package/src/commit/agentic/tools/split-commit.ts +241 -0
  1251. package/src/commit/agentic/topo-sort.ts +44 -0
  1252. package/src/commit/agentic/trivial.ts +51 -0
  1253. package/src/commit/agentic/validation.ts +183 -0
  1254. package/src/commit/analysis/conventional.ts +64 -0
  1255. package/src/commit/analysis/index.ts +4 -0
  1256. package/src/commit/analysis/scope.ts +242 -0
  1257. package/src/commit/analysis/summary.ts +107 -0
  1258. package/src/commit/analysis/validation.ts +66 -0
  1259. package/src/commit/changelog/detect.ts +40 -0
  1260. package/src/commit/changelog/generate.ts +101 -0
  1261. package/src/commit/changelog/index.ts +234 -0
  1262. package/src/commit/changelog/parse.ts +44 -0
  1263. package/src/commit/cli.ts +85 -0
  1264. package/src/commit/git/diff.ts +148 -0
  1265. package/src/commit/index.ts +5 -0
  1266. package/src/commit/map-reduce/index.ts +69 -0
  1267. package/src/commit/map-reduce/map-phase.ts +193 -0
  1268. package/src/commit/map-reduce/reduce-phase.ts +49 -0
  1269. package/src/commit/map-reduce/utils.ts +9 -0
  1270. package/src/commit/message.ts +11 -0
  1271. package/src/commit/model-selection.ts +95 -0
  1272. package/src/commit/pipeline.ts +243 -0
  1273. package/src/commit/prompts/analysis-system.md +148 -0
  1274. package/src/commit/prompts/analysis-user.md +38 -0
  1275. package/src/commit/prompts/changelog-system.md +50 -0
  1276. package/src/commit/prompts/changelog-user.md +18 -0
  1277. package/src/commit/prompts/file-observer-system.md +24 -0
  1278. package/src/commit/prompts/file-observer-user.md +8 -0
  1279. package/src/commit/prompts/reduce-system.md +50 -0
  1280. package/src/commit/prompts/reduce-user.md +17 -0
  1281. package/src/commit/prompts/summary-retry.md +3 -0
  1282. package/src/commit/prompts/summary-system.md +38 -0
  1283. package/src/commit/prompts/summary-user.md +13 -0
  1284. package/src/commit/prompts/types-description.md +2 -0
  1285. package/src/commit/shared-llm.ts +70 -0
  1286. package/src/commit/types.ts +118 -0
  1287. package/src/commit/utils/exclusions.ts +42 -0
  1288. package/src/commit/utils.ts +58 -0
  1289. package/src/config/api-key-resolver.ts +67 -0
  1290. package/src/config/append-only-context-mode.ts +76 -0
  1291. package/src/config/config-file.ts +315 -0
  1292. package/src/config/file-lock.ts +164 -0
  1293. package/src/config/inline-tool-descriptors-mode.ts +26 -0
  1294. package/src/config/keybindings.ts +636 -0
  1295. package/src/config/mcp-schema.json +247 -0
  1296. package/src/config/model-discovery.ts +919 -0
  1297. package/src/config/model-registry.ts +2275 -0
  1298. package/src/config/model-resolver.ts +1798 -0
  1299. package/src/config/model-roles.ts +99 -0
  1300. package/src/config/models-config-schema.ts +293 -0
  1301. package/src/config/models-config.ts +134 -0
  1302. package/src/config/prompt-templates.ts +205 -0
  1303. package/src/config/provider-globals.ts +25 -0
  1304. package/src/config/resolve-config-value.ts +94 -0
  1305. package/src/config/service-tier.ts +116 -0
  1306. package/src/config/settings-schema.ts +5247 -0
  1307. package/src/config/settings.ts +1540 -0
  1308. package/src/config.ts +242 -0
  1309. package/src/cursor.ts +340 -0
  1310. package/src/dap/client.ts +764 -0
  1311. package/src/dap/config.ts +333 -0
  1312. package/src/dap/defaults.json +212 -0
  1313. package/src/dap/index.ts +4 -0
  1314. package/src/dap/session.ts +1441 -0
  1315. package/src/dap/types.ts +610 -0
  1316. package/src/debug/index.ts +584 -0
  1317. package/src/debug/log-formatting.ts +58 -0
  1318. package/src/debug/log-viewer.ts +966 -0
  1319. package/src/debug/profiler.ts +168 -0
  1320. package/src/debug/protocol-probe.ts +267 -0
  1321. package/src/debug/raw-sse-buffer.ts +294 -0
  1322. package/src/debug/raw-sse.ts +312 -0
  1323. package/src/debug/remote-debugger.ts +151 -0
  1324. package/src/debug/report-bundle.ts +375 -0
  1325. package/src/debug/system-info.ts +111 -0
  1326. package/src/debug/terminal-info.ts +124 -0
  1327. package/src/discovery/agents-md.ts +67 -0
  1328. package/src/discovery/agents.ts +230 -0
  1329. package/src/discovery/at-imports.ts +273 -0
  1330. package/src/discovery/builtin-defaults.ts +39 -0
  1331. package/src/discovery/builtin-rules/go-add-cleanup.md +32 -0
  1332. package/src/discovery/builtin-rules/go-bench-loop.md +36 -0
  1333. package/src/discovery/builtin-rules/go-exp-promoted.md +39 -0
  1334. package/src/discovery/builtin-rules/go-ioutil.md +36 -0
  1335. package/src/discovery/builtin-rules/go-join-hostport.md +29 -0
  1336. package/src/discovery/builtin-rules/go-new-expr.md +44 -0
  1337. package/src/discovery/builtin-rules/go-rand-v2.md +40 -0
  1338. package/src/discovery/builtin-rules/go-range-int.md +45 -0
  1339. package/src/discovery/builtin-rules/index.ts +72 -0
  1340. package/src/discovery/builtin-rules/rs-box-leak.md +48 -0
  1341. package/src/discovery/builtin-rules/rs-future-prelude.md +23 -0
  1342. package/src/discovery/builtin-rules/rs-lazylock.md +51 -0
  1343. package/src/discovery/builtin-rules/rs-match-ergonomics.md +67 -0
  1344. package/src/discovery/builtin-rules/rs-parking-lot.md +44 -0
  1345. package/src/discovery/builtin-rules/rs-result-type.md +19 -0
  1346. package/src/discovery/builtin-rules/ts-bare-catch.md +38 -0
  1347. package/src/discovery/builtin-rules/ts-import-type.md +42 -0
  1348. package/src/discovery/builtin-rules/ts-no-any.md +65 -0
  1349. package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +44 -0
  1350. package/src/discovery/builtin-rules/ts-no-dynamic-import.md +39 -0
  1351. package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +55 -0
  1352. package/src/discovery/builtin-rules/ts-no-return-type.md +44 -0
  1353. package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
  1354. package/src/discovery/builtin-rules/ts-no-tiny-functions.md +51 -0
  1355. package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +65 -0
  1356. package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
  1357. package/src/discovery/builtin-rules/ts-set-map.md +28 -0
  1358. package/src/discovery/builtin.ts +934 -0
  1359. package/src/discovery/claude-plugins.ts +387 -0
  1360. package/src/discovery/claude.ts +584 -0
  1361. package/src/discovery/cline.ts +83 -0
  1362. package/src/discovery/codex.ts +530 -0
  1363. package/src/discovery/cursor.ts +220 -0
  1364. package/src/discovery/gemini.ts +383 -0
  1365. package/src/discovery/github.ts +337 -0
  1366. package/src/discovery/helpers.ts +1102 -0
  1367. package/src/discovery/index.ts +81 -0
  1368. package/src/discovery/mcp-json.ts +172 -0
  1369. package/src/discovery/omp-extension-roots.ts +213 -0
  1370. package/src/discovery/omp-plugins.ts +383 -0
  1371. package/src/discovery/opencode.ts +441 -0
  1372. package/src/discovery/plugin-dir-roots.ts +28 -0
  1373. package/src/discovery/ssh.ts +153 -0
  1374. package/src/discovery/substitute-plugin-root.ts +29 -0
  1375. package/src/discovery/vscode.ts +105 -0
  1376. package/src/discovery/windsurf.ts +147 -0
  1377. package/src/edit/apply-patch/index.ts +87 -0
  1378. package/src/edit/apply-patch/parser.ts +174 -0
  1379. package/src/edit/diff.ts +999 -0
  1380. package/src/edit/file-snapshot-store.ts +157 -0
  1381. package/src/edit/hashline/block-resolver.ts +33 -0
  1382. package/src/edit/hashline/diff.ts +356 -0
  1383. package/src/edit/hashline/execute.ts +279 -0
  1384. package/src/edit/hashline/filesystem.ts +205 -0
  1385. package/src/edit/hashline/index.ts +5 -0
  1386. package/src/edit/hashline/noop-loop-guard.ts +99 -0
  1387. package/src/edit/hashline/params.ts +12 -0
  1388. package/src/edit/index.ts +705 -0
  1389. package/src/edit/modes/apply-patch.lark +19 -0
  1390. package/src/edit/modes/apply-patch.ts +53 -0
  1391. package/src/edit/modes/patch.ts +1950 -0
  1392. package/src/edit/modes/replace.ts +1137 -0
  1393. package/src/edit/normalize.ts +345 -0
  1394. package/src/edit/notebook.ts +242 -0
  1395. package/src/edit/read-file.ts +25 -0
  1396. package/src/edit/renderer.ts +969 -0
  1397. package/src/edit/snapshot-details.ts +77 -0
  1398. package/src/edit/streaming.ts +698 -0
  1399. package/src/eval/__tests__/agent-bridge.test.ts +1399 -0
  1400. package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
  1401. package/src/eval/__tests__/budget-bridge.test.ts +69 -0
  1402. package/src/eval/__tests__/completion-bridge.test.ts +412 -0
  1403. package/src/eval/__tests__/helpers-local-roots.test.ts +55 -0
  1404. package/src/eval/__tests__/idle-timeout.test.ts +80 -0
  1405. package/src/eval/__tests__/js-context-manager.test.ts +291 -0
  1406. package/src/eval/__tests__/julia-prelude.test.ts +66 -0
  1407. package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
  1408. package/src/eval/__tests__/prelude-agent.test.ts +107 -0
  1409. package/src/eval/agent-bridge.ts +584 -0
  1410. package/src/eval/backend-helpers.ts +48 -0
  1411. package/src/eval/backend.ts +71 -0
  1412. package/src/eval/bridge-timeout.ts +44 -0
  1413. package/src/eval/budget-bridge.ts +48 -0
  1414. package/src/eval/completion-bridge.ts +211 -0
  1415. package/src/eval/concurrency-bridge.ts +34 -0
  1416. package/src/eval/executor-base.ts +425 -0
  1417. package/src/eval/idle-timeout.ts +91 -0
  1418. package/src/eval/index.ts +6 -0
  1419. package/src/eval/jl/executor.ts +540 -0
  1420. package/src/eval/jl/index.ts +54 -0
  1421. package/src/eval/jl/kernel.ts +235 -0
  1422. package/src/eval/jl/prelude.jl +735 -0
  1423. package/src/eval/jl/prelude.ts +3 -0
  1424. package/src/eval/jl/runner.jl +666 -0
  1425. package/src/eval/jl/runtime.ts +118 -0
  1426. package/src/eval/js/context-manager.ts +621 -0
  1427. package/src/eval/js/executor.ts +173 -0
  1428. package/src/eval/js/index.ts +40 -0
  1429. package/src/eval/js/shared/helpers.ts +170 -0
  1430. package/src/eval/js/shared/indirect-eval.ts +30 -0
  1431. package/src/eval/js/shared/local-module-loader.ts +364 -0
  1432. package/src/eval/js/shared/prelude.ts +2 -0
  1433. package/src/eval/js/shared/prelude.txt +293 -0
  1434. package/src/eval/js/shared/rewrite-imports.ts +532 -0
  1435. package/src/eval/js/shared/runtime.ts +574 -0
  1436. package/src/eval/js/shared/types.ts +18 -0
  1437. package/src/eval/js/tool-bridge.ts +163 -0
  1438. package/src/eval/js/worker-core.ts +151 -0
  1439. package/src/eval/js/worker-entry.ts +37 -0
  1440. package/src/eval/js/worker-protocol.ts +47 -0
  1441. package/src/eval/kernel-base.ts +569 -0
  1442. package/src/eval/py/__tests__/prelude.test.ts +32 -0
  1443. package/src/eval/py/__tests__/runner-shell-output.test.ts +157 -0
  1444. package/src/eval/py/display.ts +71 -0
  1445. package/src/eval/py/executor.ts +533 -0
  1446. package/src/eval/py/index.ts +57 -0
  1447. package/src/eval/py/kernel.ts +233 -0
  1448. package/src/eval/py/prelude.py +625 -0
  1449. package/src/eval/py/prelude.ts +3 -0
  1450. package/src/eval/py/runner.py +1322 -0
  1451. package/src/eval/py/runtime.ts +276 -0
  1452. package/src/eval/py/spawn-options.ts +126 -0
  1453. package/src/eval/py/tool-bridge.ts +182 -0
  1454. package/src/eval/rb/executor.ts +504 -0
  1455. package/src/eval/rb/index.ts +54 -0
  1456. package/src/eval/rb/kernel.ts +230 -0
  1457. package/src/eval/rb/prelude.rb +553 -0
  1458. package/src/eval/rb/prelude.ts +3 -0
  1459. package/src/eval/rb/runner.rb +581 -0
  1460. package/src/eval/rb/runtime.ts +132 -0
  1461. package/src/eval/runtime-env.ts +104 -0
  1462. package/src/eval/session-id.ts +8 -0
  1463. package/src/eval/types.ts +48 -0
  1464. package/src/exa/index.ts +2 -0
  1465. package/src/exa/mcp-client.ts +370 -0
  1466. package/src/exa/types.ts +69 -0
  1467. package/src/exec/bash-executor.ts +473 -0
  1468. package/src/exec/exec.ts +53 -0
  1469. package/src/exec/non-interactive-env.ts +119 -0
  1470. package/src/export/custom-share.ts +65 -0
  1471. package/src/export/html/index.ts +308 -0
  1472. package/src/export/html/share-loader.js +102 -0
  1473. package/src/export/html/template.css +1337 -0
  1474. package/src/export/html/template.html +49 -0
  1475. package/src/export/html/template.js +1634 -0
  1476. package/src/export/html/tool-views.generated.js +37 -0
  1477. package/src/export/html/vendor/highlight.min.js +1213 -0
  1478. package/src/export/html/vendor/marked.min.js +6 -0
  1479. package/src/export/html/web-palette.ts +142 -0
  1480. package/src/export/share.ts +481 -0
  1481. package/src/export/ttsr.ts +583 -0
  1482. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +54 -0
  1483. package/src/extensibility/custom-commands/bundled/review/index.ts +698 -0
  1484. package/src/extensibility/custom-commands/index.ts +2 -0
  1485. package/src/extensibility/custom-commands/loader.ts +242 -0
  1486. package/src/extensibility/custom-commands/types.ts +119 -0
  1487. package/src/extensibility/custom-tools/index.ts +7 -0
  1488. package/src/extensibility/custom-tools/loader.ts +268 -0
  1489. package/src/extensibility/custom-tools/types.ts +280 -0
  1490. package/src/extensibility/custom-tools/wrapper.ts +47 -0
  1491. package/src/extensibility/extensions/compact-handler.ts +40 -0
  1492. package/src/extensibility/extensions/get-commands-handler.ts +78 -0
  1493. package/src/extensibility/extensions/index.ts +16 -0
  1494. package/src/extensibility/extensions/loader.ts +596 -0
  1495. package/src/extensibility/extensions/model-api.ts +39 -0
  1496. package/src/extensibility/extensions/runner.ts +1039 -0
  1497. package/src/extensibility/extensions/types.ts +1394 -0
  1498. package/src/extensibility/extensions/wrapper.ts +266 -0
  1499. package/src/extensibility/hooks/index.ts +6 -0
  1500. package/src/extensibility/hooks/loader.ts +244 -0
  1501. package/src/extensibility/hooks/runner.ts +425 -0
  1502. package/src/extensibility/hooks/tool-wrapper.ts +117 -0
  1503. package/src/extensibility/hooks/types.ts +613 -0
  1504. package/src/extensibility/legacy-pi-ai-shim.ts +73 -0
  1505. package/src/extensibility/legacy-pi-coding-agent-shim.ts +646 -0
  1506. package/src/extensibility/plugins/doctor.ts +65 -0
  1507. package/src/extensibility/plugins/git-url.ts +367 -0
  1508. package/src/extensibility/plugins/index.ts +9 -0
  1509. package/src/extensibility/plugins/installer.ts +201 -0
  1510. package/src/extensibility/plugins/legacy-pi-bundled-keys.ts +1011 -0
  1511. package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +3430 -0
  1512. package/src/extensibility/plugins/legacy-pi-compat.ts +1141 -0
  1513. package/src/extensibility/plugins/loader.ts +535 -0
  1514. package/src/extensibility/plugins/manager.ts +1121 -0
  1515. package/src/extensibility/plugins/marketplace/cache.ts +136 -0
  1516. package/src/extensibility/plugins/marketplace/fetcher.ts +315 -0
  1517. package/src/extensibility/plugins/marketplace/index.ts +6 -0
  1518. package/src/extensibility/plugins/marketplace/manager.ts +926 -0
  1519. package/src/extensibility/plugins/marketplace/registry.ts +196 -0
  1520. package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
  1521. package/src/extensibility/plugins/marketplace/types.ts +192 -0
  1522. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  1523. package/src/extensibility/plugins/parser.ts +107 -0
  1524. package/src/extensibility/plugins/runtime-config.ts +9 -0
  1525. package/src/extensibility/plugins/types.ts +194 -0
  1526. package/src/extensibility/session-handler-types.ts +21 -0
  1527. package/src/extensibility/shared-events.ts +376 -0
  1528. package/src/extensibility/skills.ts +508 -0
  1529. package/src/extensibility/slash-commands.ts +131 -0
  1530. package/src/extensibility/tool-event-input.ts +80 -0
  1531. package/src/extensibility/tool-proxy.ts +28 -0
  1532. package/src/extensibility/typebox.ts +945 -0
  1533. package/src/extensibility/utils.ts +118 -0
  1534. package/src/goals/guided-setup.ts +143 -0
  1535. package/src/goals/index.ts +3 -0
  1536. package/src/goals/runtime.ts +521 -0
  1537. package/src/goals/state.ts +37 -0
  1538. package/src/goals/tools/goal-tool.ts +251 -0
  1539. package/src/hindsight/backend.ts +354 -0
  1540. package/src/hindsight/bank.ts +156 -0
  1541. package/src/hindsight/client.test.ts +33 -0
  1542. package/src/hindsight/client.ts +643 -0
  1543. package/src/hindsight/config.ts +175 -0
  1544. package/src/hindsight/content.ts +266 -0
  1545. package/src/hindsight/index.ts +8 -0
  1546. package/src/hindsight/mental-models.ts +429 -0
  1547. package/src/hindsight/seeds.json +32 -0
  1548. package/src/hindsight/state.ts +492 -0
  1549. package/src/hindsight/transcript.ts +71 -0
  1550. package/src/index.ts +66 -0
  1551. package/src/internal-urls/__tests__/ssh-protocol.test.ts +331 -0
  1552. package/src/internal-urls/agent-protocol.ts +146 -0
  1553. package/src/internal-urls/artifact-protocol.ts +151 -0
  1554. package/src/internal-urls/docs-index.generated.txt +2 -0
  1555. package/src/internal-urls/docs-index.ts +101 -0
  1556. package/src/internal-urls/filesystem-resource.ts +34 -0
  1557. package/src/internal-urls/history-protocol.ts +118 -0
  1558. package/src/internal-urls/index.ts +26 -0
  1559. package/src/internal-urls/issue-pr-protocol.ts +594 -0
  1560. package/src/internal-urls/json-query.ts +126 -0
  1561. package/src/internal-urls/local-protocol.ts +469 -0
  1562. package/src/internal-urls/mcp-protocol.ts +151 -0
  1563. package/src/internal-urls/memory-protocol.ts +173 -0
  1564. package/src/internal-urls/omp-protocol.ts +94 -0
  1565. package/src/internal-urls/parse.ts +72 -0
  1566. package/src/internal-urls/registry-helpers.ts +40 -0
  1567. package/src/internal-urls/router.ts +107 -0
  1568. package/src/internal-urls/rule-protocol.ts +45 -0
  1569. package/src/internal-urls/skill-protocol.ts +112 -0
  1570. package/src/internal-urls/ssh-protocol.ts +367 -0
  1571. package/src/internal-urls/types.ts +182 -0
  1572. package/src/internal-urls/vault-protocol.ts +939 -0
  1573. package/src/irc/bus.ts +320 -0
  1574. package/src/jsonrpc/message-framing.ts +142 -0
  1575. package/src/lib/xai-http.ts +124 -0
  1576. package/src/lsp/client.ts +1249 -0
  1577. package/src/lsp/clients/biome-client.ts +264 -0
  1578. package/src/lsp/clients/index.ts +50 -0
  1579. package/src/lsp/clients/lsp-linter-client.ts +85 -0
  1580. package/src/lsp/clients/swiftlint-client.ts +120 -0
  1581. package/src/lsp/config.ts +531 -0
  1582. package/src/lsp/defaults.json +499 -0
  1583. package/src/lsp/diagnostics-ledger.ts +51 -0
  1584. package/src/lsp/edits.ts +288 -0
  1585. package/src/lsp/format-options.ts +119 -0
  1586. package/src/lsp/index.ts +2539 -0
  1587. package/src/lsp/lspmux.ts +233 -0
  1588. package/src/lsp/render.ts +668 -0
  1589. package/src/lsp/startup-events.ts +13 -0
  1590. package/src/lsp/types.ts +444 -0
  1591. package/src/lsp/utils.ts +718 -0
  1592. package/src/main.ts +1474 -0
  1593. package/src/markit/NOTICE +32 -0
  1594. package/src/markit/converters/docx.ts +56 -0
  1595. package/src/markit/converters/epub.ts +136 -0
  1596. package/src/markit/converters/mammoth.d.ts +24 -0
  1597. package/src/markit/converters/pdf/columns.ts +103 -0
  1598. package/src/markit/converters/pdf/extract.ts +574 -0
  1599. package/src/markit/converters/pdf/grid.ts +780 -0
  1600. package/src/markit/converters/pdf/headers.ts +106 -0
  1601. package/src/markit/converters/pdf/index.ts +146 -0
  1602. package/src/markit/converters/pdf/render.ts +501 -0
  1603. package/src/markit/converters/pdf/types.ts +84 -0
  1604. package/src/markit/converters/pptx.ts +325 -0
  1605. package/src/markit/converters/xlsx.ts +173 -0
  1606. package/src/markit/index.ts +2 -0
  1607. package/src/markit/registry.ts +59 -0
  1608. package/src/markit/types.ts +35 -0
  1609. package/src/mcp/client.ts +511 -0
  1610. package/src/mcp/config-writer.ts +350 -0
  1611. package/src/mcp/config.ts +369 -0
  1612. package/src/mcp/index.ts +29 -0
  1613. package/src/mcp/json-rpc.ts +122 -0
  1614. package/src/mcp/loader.ts +125 -0
  1615. package/src/mcp/manager.ts +1362 -0
  1616. package/src/mcp/oauth-credentials.ts +104 -0
  1617. package/src/mcp/oauth-discovery.ts +560 -0
  1618. package/src/mcp/oauth-flow.ts +787 -0
  1619. package/src/mcp/render.ts +155 -0
  1620. package/src/mcp/smithery-auth.ts +107 -0
  1621. package/src/mcp/smithery-connect.ts +154 -0
  1622. package/src/mcp/smithery-registry.test.ts +51 -0
  1623. package/src/mcp/smithery-registry.ts +500 -0
  1624. package/src/mcp/startup-events.ts +116 -0
  1625. package/src/mcp/timeout.ts +59 -0
  1626. package/src/mcp/tool-bridge.ts +484 -0
  1627. package/src/mcp/tool-cache.ts +117 -0
  1628. package/src/mcp/transports/http.ts +523 -0
  1629. package/src/mcp/transports/index.ts +7 -0
  1630. package/src/mcp/transports/sse.ts +377 -0
  1631. package/src/mcp/transports/stdio.test.ts +95 -0
  1632. package/src/mcp/transports/stdio.ts +663 -0
  1633. package/src/mcp/types.ts +430 -0
  1634. package/src/memories/index.ts +1395 -0
  1635. package/src/memories/storage.ts +578 -0
  1636. package/src/memory-backend/index.ts +18 -0
  1637. package/src/memory-backend/local-backend.ts +47 -0
  1638. package/src/memory-backend/off-backend.ts +25 -0
  1639. package/src/memory-backend/resolve.ts +25 -0
  1640. package/src/memory-backend/runtime.ts +66 -0
  1641. package/src/memory-backend/types.ts +166 -0
  1642. package/src/mnemopi/backend.ts +612 -0
  1643. package/src/mnemopi/config.ts +267 -0
  1644. package/src/mnemopi/embed-client.ts +246 -0
  1645. package/src/mnemopi/embed-protocol.ts +35 -0
  1646. package/src/mnemopi/embed-worker.ts +113 -0
  1647. package/src/mnemopi/index.ts +3 -0
  1648. package/src/mnemopi/state.ts +722 -0
  1649. package/src/modes/acp/acp-agent.ts +2372 -0
  1650. package/src/modes/acp/acp-client-bridge.ts +154 -0
  1651. package/src/modes/acp/acp-event-mapper.ts +1002 -0
  1652. package/src/modes/acp/acp-mode.ts +23 -0
  1653. package/src/modes/acp/index.ts +2 -0
  1654. package/src/modes/acp/terminal-auth.ts +37 -0
  1655. package/src/modes/components/__tests__/move-overlay.test.ts +237 -0
  1656. package/src/modes/components/__tests__/skill-message.test.ts +92 -0
  1657. package/src/modes/components/advisor-config.ts +555 -0
  1658. package/src/modes/components/advisor-message.ts +109 -0
  1659. package/src/modes/components/agent-dashboard.ts +1183 -0
  1660. package/src/modes/components/agent-hub.ts +586 -0
  1661. package/src/modes/components/agent-transcript-viewer.ts +649 -0
  1662. package/src/modes/components/assistant-message.ts +869 -0
  1663. package/src/modes/components/background-tan-message.ts +36 -0
  1664. package/src/modes/components/bash-execution.ts +229 -0
  1665. package/src/modes/components/bordered-loader.ts +41 -0
  1666. package/src/modes/components/btw-panel.ts +124 -0
  1667. package/src/modes/components/cache-invalidation-marker.ts +110 -0
  1668. package/src/modes/components/chat-block.ts +111 -0
  1669. package/src/modes/components/chat-transcript-builder.ts +449 -0
  1670. package/src/modes/components/collab-prompt-message.ts +32 -0
  1671. package/src/modes/components/compaction-summary-message.ts +215 -0
  1672. package/src/modes/components/copy-selector.ts +206 -0
  1673. package/src/modes/components/countdown-timer.ts +75 -0
  1674. package/src/modes/components/custom-editor.test.ts +283 -0
  1675. package/src/modes/components/custom-editor.ts +835 -0
  1676. package/src/modes/components/custom-message.ts +67 -0
  1677. package/src/modes/components/diff.ts +254 -0
  1678. package/src/modes/components/dynamic-border.ts +34 -0
  1679. package/src/modes/components/error-banner.ts +33 -0
  1680. package/src/modes/components/eval-execution.ts +167 -0
  1681. package/src/modes/components/execution-shared.ts +101 -0
  1682. package/src/modes/components/extensions/extension-dashboard.ts +492 -0
  1683. package/src/modes/components/extensions/extension-list.ts +507 -0
  1684. package/src/modes/components/extensions/index.ts +9 -0
  1685. package/src/modes/components/extensions/inspector-panel.ts +321 -0
  1686. package/src/modes/components/extensions/state-manager.ts +648 -0
  1687. package/src/modes/components/extensions/types.ts +186 -0
  1688. package/src/modes/components/footer.ts +276 -0
  1689. package/src/modes/components/history-search.ts +268 -0
  1690. package/src/modes/components/hook-editor.ts +183 -0
  1691. package/src/modes/components/hook-input.ts +87 -0
  1692. package/src/modes/components/hook-message.ts +67 -0
  1693. package/src/modes/components/hook-selector.ts +678 -0
  1694. package/src/modes/components/index.ts +40 -0
  1695. package/src/modes/components/keybinding-hints.ts +65 -0
  1696. package/src/modes/components/late-diagnostics-message.ts +60 -0
  1697. package/src/modes/components/login-dialog.ts +178 -0
  1698. package/src/modes/components/logout-account-selector.ts +130 -0
  1699. package/src/modes/components/mcp-add-wizard.ts +1408 -0
  1700. package/src/modes/components/message-frame.ts +92 -0
  1701. package/src/modes/components/model-selector.ts +1267 -0
  1702. package/src/modes/components/move-overlay.ts +294 -0
  1703. package/src/modes/components/oauth-selector.ts +457 -0
  1704. package/src/modes/components/omfg-panel.ts +141 -0
  1705. package/src/modes/components/overlay-box.ts +109 -0
  1706. package/src/modes/components/plan-review-overlay.ts +847 -0
  1707. package/src/modes/components/plan-toc.ts +138 -0
  1708. package/src/modes/components/plugin-selector.ts +100 -0
  1709. package/src/modes/components/plugin-settings.ts +745 -0
  1710. package/src/modes/components/queue-mode-selector.ts +61 -0
  1711. package/src/modes/components/read-tool-group.ts +676 -0
  1712. package/src/modes/components/reset-usage-selector.ts +161 -0
  1713. package/src/modes/components/segment-track.ts +89 -0
  1714. package/src/modes/components/select-list-mouse-routing.ts +35 -0
  1715. package/src/modes/components/selector-helpers.ts +129 -0
  1716. package/src/modes/components/session-selector.ts +744 -0
  1717. package/src/modes/components/settings-defs.ts +238 -0
  1718. package/src/modes/components/settings-selector.ts +1265 -0
  1719. package/src/modes/components/show-images-selector.ts +50 -0
  1720. package/src/modes/components/skill-message.ts +110 -0
  1721. package/src/modes/components/snapcompact-shape-preview-doc.md +18 -0
  1722. package/src/modes/components/snapcompact-shape-preview.ts +192 -0
  1723. package/src/modes/components/status-line/component.test.ts +44 -0
  1724. package/src/modes/components/status-line/component.ts +1308 -0
  1725. package/src/modes/components/status-line/context-thresholds.ts +86 -0
  1726. package/src/modes/components/status-line/git-utils.ts +42 -0
  1727. package/src/modes/components/status-line/index.ts +5 -0
  1728. package/src/modes/components/status-line/presets.ts +106 -0
  1729. package/src/modes/components/status-line/segments.ts +663 -0
  1730. package/src/modes/components/status-line/separators.ts +55 -0
  1731. package/src/modes/components/status-line/token-rate.ts +66 -0
  1732. package/src/modes/components/status-line/types.ts +147 -0
  1733. package/src/modes/components/theme-selector.ts +68 -0
  1734. package/src/modes/components/thinking-selector.ts +57 -0
  1735. package/src/modes/components/tiny-title-download-progress.ts +90 -0
  1736. package/src/modes/components/tips.txt +24 -0
  1737. package/src/modes/components/todo-reminder.ts +43 -0
  1738. package/src/modes/components/tool-execution.ts +1308 -0
  1739. package/src/modes/components/transcript-container.ts +456 -0
  1740. package/src/modes/components/tree-selector.ts +1002 -0
  1741. package/src/modes/components/ttsr-notification.ts +123 -0
  1742. package/src/modes/components/usage-row.ts +32 -0
  1743. package/src/modes/components/user-message-selector.ts +227 -0
  1744. package/src/modes/components/user-message.ts +68 -0
  1745. package/src/modes/components/visual-truncate.ts +63 -0
  1746. package/src/modes/components/welcome.ts +579 -0
  1747. package/src/modes/controllers/btw-controller.ts +198 -0
  1748. package/src/modes/controllers/command-controller-shared.ts +109 -0
  1749. package/src/modes/controllers/command-controller.ts +1751 -0
  1750. package/src/modes/controllers/event-controller.ts +1497 -0
  1751. package/src/modes/controllers/extension-ui-controller.ts +977 -0
  1752. package/src/modes/controllers/input-controller.ts +1851 -0
  1753. package/src/modes/controllers/mcp-command-controller.ts +2364 -0
  1754. package/src/modes/controllers/omfg-controller.ts +283 -0
  1755. package/src/modes/controllers/omfg-rule.ts +647 -0
  1756. package/src/modes/controllers/selector-controller.ts +1443 -0
  1757. package/src/modes/controllers/session-focus-controller.ts +112 -0
  1758. package/src/modes/controllers/ssh-command-controller.ts +384 -0
  1759. package/src/modes/controllers/streaming-reveal.ts +392 -0
  1760. package/src/modes/controllers/tan-command-controller.ts +190 -0
  1761. package/src/modes/controllers/todo-command-controller.ts +484 -0
  1762. package/src/modes/controllers/tool-args-reveal.ts +582 -0
  1763. package/src/modes/data/emojis.json +1 -0
  1764. package/src/modes/emoji-autocomplete.ts +285 -0
  1765. package/src/modes/gradient-highlight.ts +99 -0
  1766. package/src/modes/image-references.ts +137 -0
  1767. package/src/modes/index.ts +17 -0
  1768. package/src/modes/interactive-mode.ts +4223 -0
  1769. package/src/modes/internal-url-autocomplete.ts +158 -0
  1770. package/src/modes/loop-limit.ts +192 -0
  1771. package/src/modes/magic-keywords.ts +42 -0
  1772. package/src/modes/markdown-prose.ts +247 -0
  1773. package/src/modes/oauth-manual-input.ts +69 -0
  1774. package/src/modes/orchestrate.ts +42 -0
  1775. package/src/modes/print-mode.ts +130 -0
  1776. package/src/modes/prompt-action-autocomplete.ts +262 -0
  1777. package/src/modes/rpc/host-tools.ts +186 -0
  1778. package/src/modes/rpc/host-uris.ts +235 -0
  1779. package/src/modes/rpc/rpc-client.ts +1033 -0
  1780. package/src/modes/rpc/rpc-mode.ts +1311 -0
  1781. package/src/modes/rpc/rpc-subagents.ts +265 -0
  1782. package/src/modes/rpc/rpc-types.ts +499 -0
  1783. package/src/modes/running-subagent-badge.ts +13 -0
  1784. package/src/modes/runtime-init.ts +142 -0
  1785. package/src/modes/session-observer-registry.ts +215 -0
  1786. package/src/modes/session-teardown.test.ts +219 -0
  1787. package/src/modes/session-teardown.ts +82 -0
  1788. package/src/modes/setup-version.ts +11 -0
  1789. package/src/modes/setup-wizard/index.ts +101 -0
  1790. package/src/modes/setup-wizard/lazy.ts +16 -0
  1791. package/src/modes/setup-wizard/scenes/glyph.ts +103 -0
  1792. package/src/modes/setup-wizard/scenes/outro.ts +35 -0
  1793. package/src/modes/setup-wizard/scenes/providers.ts +104 -0
  1794. package/src/modes/setup-wizard/scenes/sign-in.ts +304 -0
  1795. package/src/modes/setup-wizard/scenes/splash.ts +201 -0
  1796. package/src/modes/setup-wizard/scenes/theme.ts +320 -0
  1797. package/src/modes/setup-wizard/scenes/types.ts +57 -0
  1798. package/src/modes/setup-wizard/scenes/web-search.ts +140 -0
  1799. package/src/modes/setup-wizard/startup-splash.ts +107 -0
  1800. package/src/modes/setup-wizard/wizard-overlay.ts +335 -0
  1801. package/src/modes/shared.ts +49 -0
  1802. package/src/modes/skill-command.ts +91 -0
  1803. package/src/modes/theme/dark.json +95 -0
  1804. package/src/modes/theme/defaults/alabaster.json +93 -0
  1805. package/src/modes/theme/defaults/amethyst.json +96 -0
  1806. package/src/modes/theme/defaults/anthracite.json +93 -0
  1807. package/src/modes/theme/defaults/basalt.json +91 -0
  1808. package/src/modes/theme/defaults/birch.json +95 -0
  1809. package/src/modes/theme/defaults/dark-abyss.json +91 -0
  1810. package/src/modes/theme/defaults/dark-arctic.json +104 -0
  1811. package/src/modes/theme/defaults/dark-aurora.json +95 -0
  1812. package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
  1813. package/src/modes/theme/defaults/dark-cavern.json +91 -0
  1814. package/src/modes/theme/defaults/dark-copper.json +95 -0
  1815. package/src/modes/theme/defaults/dark-cosmos.json +90 -0
  1816. package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
  1817. package/src/modes/theme/defaults/dark-dracula.json +98 -0
  1818. package/src/modes/theme/defaults/dark-eclipse.json +91 -0
  1819. package/src/modes/theme/defaults/dark-ember.json +95 -0
  1820. package/src/modes/theme/defaults/dark-equinox.json +90 -0
  1821. package/src/modes/theme/defaults/dark-forest.json +96 -0
  1822. package/src/modes/theme/defaults/dark-github.json +105 -0
  1823. package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
  1824. package/src/modes/theme/defaults/dark-lavender.json +95 -0
  1825. package/src/modes/theme/defaults/dark-lunar.json +89 -0
  1826. package/src/modes/theme/defaults/dark-midnight.json +95 -0
  1827. package/src/modes/theme/defaults/dark-monochrome.json +94 -0
  1828. package/src/modes/theme/defaults/dark-monokai.json +98 -0
  1829. package/src/modes/theme/defaults/dark-nebula.json +90 -0
  1830. package/src/modes/theme/defaults/dark-nord.json +97 -0
  1831. package/src/modes/theme/defaults/dark-ocean.json +101 -0
  1832. package/src/modes/theme/defaults/dark-one.json +100 -0
  1833. package/src/modes/theme/defaults/dark-poimandres.json +142 -0
  1834. package/src/modes/theme/defaults/dark-rainforest.json +91 -0
  1835. package/src/modes/theme/defaults/dark-reef.json +91 -0
  1836. package/src/modes/theme/defaults/dark-retro.json +92 -0
  1837. package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
  1838. package/src/modes/theme/defaults/dark-sakura.json +95 -0
  1839. package/src/modes/theme/defaults/dark-slate.json +95 -0
  1840. package/src/modes/theme/defaults/dark-solarized.json +97 -0
  1841. package/src/modes/theme/defaults/dark-solstice.json +90 -0
  1842. package/src/modes/theme/defaults/dark-starfall.json +91 -0
  1843. package/src/modes/theme/defaults/dark-sunset.json +99 -0
  1844. package/src/modes/theme/defaults/dark-swamp.json +90 -0
  1845. package/src/modes/theme/defaults/dark-synthwave.json +103 -0
  1846. package/src/modes/theme/defaults/dark-taiga.json +91 -0
  1847. package/src/modes/theme/defaults/dark-terminal.json +95 -0
  1848. package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
  1849. package/src/modes/theme/defaults/dark-tundra.json +91 -0
  1850. package/src/modes/theme/defaults/dark-twilight.json +91 -0
  1851. package/src/modes/theme/defaults/dark-volcanic.json +91 -0
  1852. package/src/modes/theme/defaults/graphite.json +92 -0
  1853. package/src/modes/theme/defaults/index.ts +199 -0
  1854. package/src/modes/theme/defaults/light-arctic.json +107 -0
  1855. package/src/modes/theme/defaults/light-aurora-day.json +91 -0
  1856. package/src/modes/theme/defaults/light-canyon.json +91 -0
  1857. package/src/modes/theme/defaults/light-catppuccin.json +106 -0
  1858. package/src/modes/theme/defaults/light-cirrus.json +90 -0
  1859. package/src/modes/theme/defaults/light-coral.json +95 -0
  1860. package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
  1861. package/src/modes/theme/defaults/light-dawn.json +90 -0
  1862. package/src/modes/theme/defaults/light-dunes.json +91 -0
  1863. package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
  1864. package/src/modes/theme/defaults/light-forest.json +100 -0
  1865. package/src/modes/theme/defaults/light-frost.json +95 -0
  1866. package/src/modes/theme/defaults/light-github.json +115 -0
  1867. package/src/modes/theme/defaults/light-glacier.json +91 -0
  1868. package/src/modes/theme/defaults/light-gruvbox.json +108 -0
  1869. package/src/modes/theme/defaults/light-haze.json +90 -0
  1870. package/src/modes/theme/defaults/light-honeycomb.json +95 -0
  1871. package/src/modes/theme/defaults/light-lagoon.json +91 -0
  1872. package/src/modes/theme/defaults/light-lavender.json +95 -0
  1873. package/src/modes/theme/defaults/light-meadow.json +91 -0
  1874. package/src/modes/theme/defaults/light-mint.json +95 -0
  1875. package/src/modes/theme/defaults/light-monochrome.json +101 -0
  1876. package/src/modes/theme/defaults/light-ocean.json +99 -0
  1877. package/src/modes/theme/defaults/light-one.json +99 -0
  1878. package/src/modes/theme/defaults/light-opal.json +91 -0
  1879. package/src/modes/theme/defaults/light-orchard.json +91 -0
  1880. package/src/modes/theme/defaults/light-paper.json +95 -0
  1881. package/src/modes/theme/defaults/light-poimandres.json +142 -0
  1882. package/src/modes/theme/defaults/light-prism.json +90 -0
  1883. package/src/modes/theme/defaults/light-retro.json +98 -0
  1884. package/src/modes/theme/defaults/light-sand.json +95 -0
  1885. package/src/modes/theme/defaults/light-savanna.json +91 -0
  1886. package/src/modes/theme/defaults/light-solarized.json +102 -0
  1887. package/src/modes/theme/defaults/light-soleil.json +90 -0
  1888. package/src/modes/theme/defaults/light-sunset.json +99 -0
  1889. package/src/modes/theme/defaults/light-synthwave.json +98 -0
  1890. package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
  1891. package/src/modes/theme/defaults/light-wetland.json +91 -0
  1892. package/src/modes/theme/defaults/light-zenith.json +89 -0
  1893. package/src/modes/theme/defaults/limestone.json +94 -0
  1894. package/src/modes/theme/defaults/mahogany.json +97 -0
  1895. package/src/modes/theme/defaults/marble.json +93 -0
  1896. package/src/modes/theme/defaults/obsidian.json +91 -0
  1897. package/src/modes/theme/defaults/onyx.json +91 -0
  1898. package/src/modes/theme/defaults/pearl.json +93 -0
  1899. package/src/modes/theme/defaults/porcelain.json +91 -0
  1900. package/src/modes/theme/defaults/quartz.json +96 -0
  1901. package/src/modes/theme/defaults/sandstone.json +95 -0
  1902. package/src/modes/theme/defaults/titanium.json +90 -0
  1903. package/src/modes/theme/light.json +93 -0
  1904. package/src/modes/theme/mermaid-cache.ts +92 -0
  1905. package/src/modes/theme/mermaid-rendering.test.ts +53 -0
  1906. package/src/modes/theme/shimmer.ts +269 -0
  1907. package/src/modes/theme/theme-schema.json +459 -0
  1908. package/src/modes/theme/theme.ts +3004 -0
  1909. package/src/modes/turn-budget.ts +31 -0
  1910. package/src/modes/types.ts +437 -0
  1911. package/src/modes/ultrathink.ts +41 -0
  1912. package/src/modes/utils/context-usage.ts +432 -0
  1913. package/src/modes/utils/copy-targets.ts +378 -0
  1914. package/src/modes/utils/hotkeys-markdown.ts +62 -0
  1915. package/src/modes/utils/interactive-context-helpers.ts +27 -0
  1916. package/src/modes/utils/keybinding-matchers.ts +86 -0
  1917. package/src/modes/utils/tools-markdown.ts +27 -0
  1918. package/src/modes/utils/transcript-render-helpers.ts +184 -0
  1919. package/src/modes/utils/ui-helpers.ts +864 -0
  1920. package/src/modes/workflow.ts +42 -0
  1921. package/src/plan-mode/approved-plan-prompt.test.ts +36 -0
  1922. package/src/plan-mode/approved-plan.ts +186 -0
  1923. package/src/plan-mode/plan-handoff.ts +37 -0
  1924. package/src/plan-mode/plan-protection.ts +31 -0
  1925. package/src/plan-mode/state.ts +6 -0
  1926. package/src/priority.json +60 -0
  1927. package/src/prompts/advisor/active-repo-watchdog.md +6 -0
  1928. package/src/prompts/advisor/advise-tool.md +3 -0
  1929. package/src/prompts/advisor/context-files.md +8 -0
  1930. package/src/prompts/advisor/system.md +89 -0
  1931. package/src/prompts/agents/designer.md +74 -0
  1932. package/src/prompts/agents/explore.md +58 -0
  1933. package/src/prompts/agents/frontmatter.md +11 -0
  1934. package/src/prompts/agents/init.md +33 -0
  1935. package/src/prompts/agents/librarian.md +119 -0
  1936. package/src/prompts/agents/plan.md +48 -0
  1937. package/src/prompts/agents/reviewer.md +140 -0
  1938. package/src/prompts/agents/task.md +17 -0
  1939. package/src/prompts/agents/tester.md +111 -0
  1940. package/src/prompts/bench.md +6 -0
  1941. package/src/prompts/ci-green-request.md +36 -0
  1942. package/src/prompts/dry-balance-bench.md +8 -0
  1943. package/src/prompts/goals/goal-budget-limit.md +16 -0
  1944. package/src/prompts/goals/goal-continuation.md +28 -0
  1945. package/src/prompts/goals/goal-mode-active.md +23 -0
  1946. package/src/prompts/goals/goal-mode-context.md +4 -0
  1947. package/src/prompts/goals/goal-todo-context.md +20 -0
  1948. package/src/prompts/goals/guided-goal-interview.md +8 -0
  1949. package/src/prompts/goals/guided-goal-system.md +12 -0
  1950. package/src/prompts/memories/consolidation.md +30 -0
  1951. package/src/prompts/memories/consolidation_system.md +4 -0
  1952. package/src/prompts/memories/read-path.md +17 -0
  1953. package/src/prompts/memories/stage_one_input.md +6 -0
  1954. package/src/prompts/memories/stage_one_system.md +21 -0
  1955. package/src/prompts/review-custom-request.md +21 -0
  1956. package/src/prompts/review-headless-request.md +16 -0
  1957. package/src/prompts/review-request.md +68 -0
  1958. package/src/prompts/skills/autoload.md +8 -0
  1959. package/src/prompts/skills/user-invocation.md +11 -0
  1960. package/src/prompts/steering/parent-irc.md +5 -0
  1961. package/src/prompts/steering/user-interjection.md +9 -0
  1962. package/src/prompts/system/active-repo-context.md +4 -0
  1963. package/src/prompts/system/agent-creation-architect.md +50 -0
  1964. package/src/prompts/system/agent-creation-user.md +6 -0
  1965. package/src/prompts/system/auto-continue.md +1 -0
  1966. package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
  1967. package/src/prompts/system/auto-thinking-difficulty.md +12 -0
  1968. package/src/prompts/system/autolearn-guidance-learn.md +1 -0
  1969. package/src/prompts/system/autolearn-guidance.md +7 -0
  1970. package/src/prompts/system/autolearn-nudge-autocontinue.md +5 -0
  1971. package/src/prompts/system/background-tan-dispatch.md +8 -0
  1972. package/src/prompts/system/btw-user.md +8 -0
  1973. package/src/prompts/system/commit-message-system.md +14 -0
  1974. package/src/prompts/system/custom-system-prompt.md +64 -0
  1975. package/src/prompts/system/eager-task.md +7 -0
  1976. package/src/prompts/system/eager-todo.md +18 -0
  1977. package/src/prompts/system/empty-stop-retry.md +4 -0
  1978. package/src/prompts/system/gemini-tool-call-reminder.md +9 -0
  1979. package/src/prompts/system/interrupted-thinking.md +7 -0
  1980. package/src/prompts/system/irc-autoreply.md +6 -0
  1981. package/src/prompts/system/irc-incoming.md +9 -0
  1982. package/src/prompts/system/manual-continue.md +7 -0
  1983. package/src/prompts/system/memory-consolidation-system.md +8 -0
  1984. package/src/prompts/system/memory-extraction-system.md +26 -0
  1985. package/src/prompts/system/mid-run-todo-nudge.md +3 -0
  1986. package/src/prompts/system/omfg-user.md +50 -0
  1987. package/src/prompts/system/orchestrate-notice.md +40 -0
  1988. package/src/prompts/system/personalities/default.md +18 -0
  1989. package/src/prompts/system/personalities/friendly.md +17 -0
  1990. package/src/prompts/system/personalities/pragmatic.md +15 -0
  1991. package/src/prompts/system/plan-mode-active.md +118 -0
  1992. package/src/prompts/system/plan-mode-approved.md +22 -0
  1993. package/src/prompts/system/plan-mode-compact-instructions.md +17 -0
  1994. package/src/prompts/system/plan-mode-reference.md +10 -0
  1995. package/src/prompts/system/plan-mode-subagent.md +33 -0
  1996. package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
  1997. package/src/prompts/system/project-prompt.md +54 -0
  1998. package/src/prompts/system/recap-user.md +9 -0
  1999. package/src/prompts/system/rewind-report.md +6 -0
  2000. package/src/prompts/system/side-channel-no-tools.md +3 -0
  2001. package/src/prompts/system/snapcompact-context-frames-note.md +1 -0
  2002. package/src/prompts/system/snapcompact-context-stub.md +1 -0
  2003. package/src/prompts/system/snapcompact-system-frames-note.md +1 -0
  2004. package/src/prompts/system/snapcompact-system-stub.md +1 -0
  2005. package/src/prompts/system/snapcompact-toolresult-note.md +1 -0
  2006. package/src/prompts/system/speech-rewrite.md +15 -0
  2007. package/src/prompts/system/subagent-system-prompt.md +77 -0
  2008. package/src/prompts/system/subagent-user-prompt.md +3 -0
  2009. package/src/prompts/system/subagent-yield-reminder.md +13 -0
  2010. package/src/prompts/system/system-prompt.md +248 -0
  2011. package/src/prompts/system/thinking-loop-redirect.md +10 -0
  2012. package/src/prompts/system/tiny-title-system.md +8 -0
  2013. package/src/prompts/system/title-marker-instruction.md +1 -0
  2014. package/src/prompts/system/title-system-marker.md +17 -0
  2015. package/src/prompts/system/title-system.md +17 -0
  2016. package/src/prompts/system/tool-call-loop-redirect.md +8 -0
  2017. package/src/prompts/system/ttsr-interrupt.md +7 -0
  2018. package/src/prompts/system/ttsr-tool-reminder.md +5 -0
  2019. package/src/prompts/system/ultrathink-notice.md +3 -0
  2020. package/src/prompts/system/unexpected-stop-classifier.md +17 -0
  2021. package/src/prompts/system/unexpected-stop-retry.md +4 -0
  2022. package/src/prompts/system/web-search.md +25 -0
  2023. package/src/prompts/system/workflow-notice.md +70 -0
  2024. package/src/prompts/tools/apply-patch.md +65 -0
  2025. package/src/prompts/tools/ask.md +22 -0
  2026. package/src/prompts/tools/ast-edit.md +22 -0
  2027. package/src/prompts/tools/ast-grep.md +25 -0
  2028. package/src/prompts/tools/async-result.md +8 -0
  2029. package/src/prompts/tools/bash.md +57 -0
  2030. package/src/prompts/tools/browser.md +45 -0
  2031. package/src/prompts/tools/checkpoint.md +15 -0
  2032. package/src/prompts/tools/debug.md +17 -0
  2033. package/src/prompts/tools/eval.md +72 -0
  2034. package/src/prompts/tools/github.md +17 -0
  2035. package/src/prompts/tools/glob.md +15 -0
  2036. package/src/prompts/tools/goal.md +11 -0
  2037. package/src/prompts/tools/grep.md +22 -0
  2038. package/src/prompts/tools/image-attachment-describe-system.md +8 -0
  2039. package/src/prompts/tools/image-attachment-describe.md +10 -0
  2040. package/src/prompts/tools/image-gen.md +7 -0
  2041. package/src/prompts/tools/inspect-image-system.md +20 -0
  2042. package/src/prompts/tools/inspect-image.md +22 -0
  2043. package/src/prompts/tools/irc.md +24 -0
  2044. package/src/prompts/tools/job.md +11 -0
  2045. package/src/prompts/tools/learn.md +7 -0
  2046. package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
  2047. package/src/prompts/tools/lsp.md +28 -0
  2048. package/src/prompts/tools/manage-skill.md +9 -0
  2049. package/src/prompts/tools/memory-edit.md +8 -0
  2050. package/src/prompts/tools/patch.md +57 -0
  2051. package/src/prompts/tools/read.md +77 -0
  2052. package/src/prompts/tools/recall.md +5 -0
  2053. package/src/prompts/tools/reflect.md +5 -0
  2054. package/src/prompts/tools/replace.md +29 -0
  2055. package/src/prompts/tools/resolve.md +4 -0
  2056. package/src/prompts/tools/retain.md +6 -0
  2057. package/src/prompts/tools/rewind.md +14 -0
  2058. package/src/prompts/tools/search-tool-bm25.md +32 -0
  2059. package/src/prompts/tools/ssh.md +23 -0
  2060. package/src/prompts/tools/task-summary.md +17 -0
  2061. package/src/prompts/tools/task.md +68 -0
  2062. package/src/prompts/tools/todo.md +39 -0
  2063. package/src/prompts/tools/web-search.md +6 -0
  2064. package/src/prompts/tools/write.md +14 -0
  2065. package/src/registry/agent-lifecycle.ts +270 -0
  2066. package/src/registry/agent-registry.ts +190 -0
  2067. package/src/sdk.ts +3037 -0
  2068. package/src/secrets/index.ts +123 -0
  2069. package/src/secrets/obfuscator.ts +441 -0
  2070. package/src/secrets/regex.ts +21 -0
  2071. package/src/session/agent-session.ts +15855 -0
  2072. package/src/session/agent-storage.ts +478 -0
  2073. package/src/session/artifacts.ts +153 -0
  2074. package/src/session/auth-broker-config.ts +92 -0
  2075. package/src/session/auth-storage.ts +24 -0
  2076. package/src/session/blob-store.ts +279 -0
  2077. package/src/session/client-bridge.ts +85 -0
  2078. package/src/session/codex-auto-reset.ts +202 -0
  2079. package/src/session/compact-modes.ts +105 -0
  2080. package/src/session/exit-diagnostics.ts +202 -0
  2081. package/src/session/history-storage.ts +360 -0
  2082. package/src/session/indexed-session-storage.ts +537 -0
  2083. package/src/session/messages.test.ts +125 -0
  2084. package/src/session/messages.ts +740 -0
  2085. package/src/session/provider-image-budget.ts +86 -0
  2086. package/src/session/redis-session-storage.ts +217 -0
  2087. package/src/session/session-context.ts +442 -0
  2088. package/src/session/session-dump-format.ts +216 -0
  2089. package/src/session/session-entries.ts +241 -0
  2090. package/src/session/session-history-format.ts +396 -0
  2091. package/src/session/session-listing.ts +652 -0
  2092. package/src/session/session-loader.ts +284 -0
  2093. package/src/session/session-manager.ts +1995 -0
  2094. package/src/session/session-migrations.ts +78 -0
  2095. package/src/session/session-paths.ts +193 -0
  2096. package/src/session/session-persistence.ts +266 -0
  2097. package/src/session/session-storage.ts +734 -0
  2098. package/src/session/session-title-slot.ts +141 -0
  2099. package/src/session/settings-stream-fn.ts +73 -0
  2100. package/src/session/shake-types.ts +43 -0
  2101. package/src/session/snapcompact-inline.ts +561 -0
  2102. package/src/session/snapcompact-savings-journal.ts +113 -0
  2103. package/src/session/sql-session-storage.ts +374 -0
  2104. package/src/session/streaming-output.ts +1330 -0
  2105. package/src/session/tool-choice-queue.ts +290 -0
  2106. package/src/session/turn-persistence.ts +142 -0
  2107. package/src/session/unexpected-stop-classifier.ts +129 -0
  2108. package/src/session/yield-queue.ts +183 -0
  2109. package/src/slash-commands/acp-builtins.ts +70 -0
  2110. package/src/slash-commands/available-commands.ts +105 -0
  2111. package/src/slash-commands/builtin-registry.ts +2554 -0
  2112. package/src/slash-commands/helpers/active-oauth-account.ts +44 -0
  2113. package/src/slash-commands/helpers/collab-qrcode.ts +28 -0
  2114. package/src/slash-commands/helpers/context-report.ts +66 -0
  2115. package/src/slash-commands/helpers/format.ts +46 -0
  2116. package/src/slash-commands/helpers/logout.ts +88 -0
  2117. package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
  2118. package/src/slash-commands/helpers/mcp.ts +533 -0
  2119. package/src/slash-commands/helpers/parse.ts +85 -0
  2120. package/src/slash-commands/helpers/reset-usage.ts +66 -0
  2121. package/src/slash-commands/helpers/ssh.ts +195 -0
  2122. package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
  2123. package/src/slash-commands/helpers/todo.ts +285 -0
  2124. package/src/slash-commands/helpers/usage-report.ts +162 -0
  2125. package/src/slash-commands/marketplace-install-parser.ts +99 -0
  2126. package/src/slash-commands/types.ts +137 -0
  2127. package/src/ssh/__tests__/connection-manager-args.test.ts +191 -0
  2128. package/src/ssh/__tests__/connection-manager-timeout.test.ts +61 -0
  2129. package/src/ssh/__tests__/file-transfer-posix-guard.test.ts +105 -0
  2130. package/src/ssh/__tests__/sshfs-mount.test.ts +13 -0
  2131. package/src/ssh/config-writer.ts +183 -0
  2132. package/src/ssh/connection-manager.ts +667 -0
  2133. package/src/ssh/file-transfer.ts +214 -0
  2134. package/src/ssh/ssh-executor.ts +178 -0
  2135. package/src/ssh/sshfs-mount.ts +163 -0
  2136. package/src/ssh/utils.ts +51 -0
  2137. package/src/startup-splash.ts +19 -0
  2138. package/src/stt/asr-client.ts +401 -0
  2139. package/src/stt/asr-protocol.ts +65 -0
  2140. package/src/stt/asr-worker.ts +638 -0
  2141. package/src/stt/downloader.ts +144 -0
  2142. package/src/stt/endpointer.ts +259 -0
  2143. package/src/stt/index.ts +8 -0
  2144. package/src/stt/models.ts +150 -0
  2145. package/src/stt/recorder.ts +538 -0
  2146. package/src/stt/stt-controller.ts +409 -0
  2147. package/src/stt/submit-trigger.ts +74 -0
  2148. package/src/stt/transcriber.ts +60 -0
  2149. package/src/stt/wav.ts +173 -0
  2150. package/src/subprocess/worker-client.ts +456 -0
  2151. package/src/subprocess/worker-runtime.ts +494 -0
  2152. package/src/system-prompt.test.ts +158 -0
  2153. package/src/system-prompt.ts +787 -0
  2154. package/src/task/agents.ts +166 -0
  2155. package/src/task/commands.ts +132 -0
  2156. package/src/task/discovery.ts +145 -0
  2157. package/src/task/executor.ts +2481 -0
  2158. package/src/task/index.ts +1481 -0
  2159. package/src/task/isolation-runner.ts +384 -0
  2160. package/src/task/name-generator.ts +1577 -0
  2161. package/src/task/omp-command.ts +26 -0
  2162. package/src/task/output-manager.ts +93 -0
  2163. package/src/task/parallel.ts +178 -0
  2164. package/src/task/persisted-revive.ts +128 -0
  2165. package/src/task/provider-concurrency.ts +100 -0
  2166. package/src/task/render.test.ts +121 -0
  2167. package/src/task/render.ts +1761 -0
  2168. package/src/task/renderer.ts +15 -0
  2169. package/src/task/repair-args.ts +129 -0
  2170. package/src/task/spawn-policy.test.ts +63 -0
  2171. package/src/task/spawn-policy.ts +58 -0
  2172. package/src/task/subprocess-tool-registry.ts +88 -0
  2173. package/src/task/types.ts +495 -0
  2174. package/src/task/worktree.ts +935 -0
  2175. package/src/task/yield-assembly.ts +198 -0
  2176. package/src/telemetry-export.ts +144 -0
  2177. package/src/thinking.ts +219 -0
  2178. package/src/tiny/device.ts +111 -0
  2179. package/src/tiny/dtype.ts +101 -0
  2180. package/src/tiny/models.ts +268 -0
  2181. package/src/tiny/text.ts +336 -0
  2182. package/src/tiny/title-client.ts +438 -0
  2183. package/src/tiny/title-protocol.ts +56 -0
  2184. package/src/tiny/worker.ts +351 -0
  2185. package/src/tool-discovery/mode.ts +24 -0
  2186. package/src/tool-discovery/tool-index.ts +271 -0
  2187. package/src/tools/__tests__/eval-description.test.ts +19 -0
  2188. package/src/tools/__tests__/json-tree.test.ts +35 -0
  2189. package/src/tools/acp-bridge.ts +71 -0
  2190. package/src/tools/approval.ts +189 -0
  2191. package/src/tools/ask.ts +1213 -0
  2192. package/src/tools/ast-edit.ts +708 -0
  2193. package/src/tools/ast-grep.ts +520 -0
  2194. package/src/tools/auto-generated-guard.ts +322 -0
  2195. package/src/tools/bash-command-fixup.ts +37 -0
  2196. package/src/tools/bash-interactive.ts +408 -0
  2197. package/src/tools/bash-interceptor.ts +67 -0
  2198. package/src/tools/bash-pty-selection.ts +14 -0
  2199. package/src/tools/bash-skill-urls.ts +248 -0
  2200. package/src/tools/bash.ts +1421 -0
  2201. package/src/tools/browser/aria/aria-snapshot.bundle.txt +7 -0
  2202. package/src/tools/browser/aria/aria-snapshot.ts +103 -0
  2203. package/src/tools/browser/attach.ts +194 -0
  2204. package/src/tools/browser/cmux/cmux-tab.ts +1378 -0
  2205. package/src/tools/browser/cmux/rpc.ts +156 -0
  2206. package/src/tools/browser/cmux/socket-client.ts +309 -0
  2207. package/src/tools/browser/launch.ts +749 -0
  2208. package/src/tools/browser/readable.ts +112 -0
  2209. package/src/tools/browser/registry.ts +266 -0
  2210. package/src/tools/browser/render.ts +223 -0
  2211. package/src/tools/browser/run-cancellation.ts +47 -0
  2212. package/src/tools/browser/tab-protocol.ts +107 -0
  2213. package/src/tools/browser/tab-supervisor.ts +956 -0
  2214. package/src/tools/browser/tab-worker-entry.ts +29 -0
  2215. package/src/tools/browser/tab-worker.ts +1433 -0
  2216. package/src/tools/browser.ts +409 -0
  2217. package/src/tools/builtin-names.ts +58 -0
  2218. package/src/tools/checkpoint.ts +150 -0
  2219. package/src/tools/conflict-detect.ts +718 -0
  2220. package/src/tools/context.ts +39 -0
  2221. package/src/tools/debug.ts +1088 -0
  2222. package/src/tools/eval-backends.ts +34 -0
  2223. package/src/tools/eval-render.ts +776 -0
  2224. package/src/tools/eval.ts +767 -0
  2225. package/src/tools/fetch.ts +1966 -0
  2226. package/src/tools/file-recorder.ts +35 -0
  2227. package/src/tools/fs-cache-invalidation.ts +28 -0
  2228. package/src/tools/gh-cache-invalidation.ts +255 -0
  2229. package/src/tools/gh-format.ts +12 -0
  2230. package/src/tools/gh-renderer.ts +484 -0
  2231. package/src/tools/gh.ts +3752 -0
  2232. package/src/tools/github-cache.ts +663 -0
  2233. package/src/tools/glob.ts +639 -0
  2234. package/src/tools/grep.ts +1836 -0
  2235. package/src/tools/grouped-file-output.ts +210 -0
  2236. package/src/tools/image-gen.ts +1587 -0
  2237. package/src/tools/index.ts +682 -0
  2238. package/src/tools/inspect-image-renderer.ts +132 -0
  2239. package/src/tools/inspect-image.ts +260 -0
  2240. package/src/tools/irc.ts +827 -0
  2241. package/src/tools/job.ts +612 -0
  2242. package/src/tools/json-tree.ts +260 -0
  2243. package/src/tools/jtd-to-json-schema.ts +219 -0
  2244. package/src/tools/jtd-to-typescript.ts +136 -0
  2245. package/src/tools/jtd-utils.ts +102 -0
  2246. package/src/tools/learn.ts +141 -0
  2247. package/src/tools/list-limit.ts +40 -0
  2248. package/src/tools/manage-skill.ts +100 -0
  2249. package/src/tools/match-line-format.ts +20 -0
  2250. package/src/tools/memory-edit.ts +59 -0
  2251. package/src/tools/memory-recall.ts +102 -0
  2252. package/src/tools/memory-reflect.ts +88 -0
  2253. package/src/tools/memory-render.ts +202 -0
  2254. package/src/tools/memory-retain.ts +89 -0
  2255. package/src/tools/output-meta.ts +818 -0
  2256. package/src/tools/output-schema-validator.ts +307 -0
  2257. package/src/tools/path-utils.ts +1279 -0
  2258. package/src/tools/plan-mode-guard.ts +155 -0
  2259. package/src/tools/puppeteer/00_stealth_tampering.txt +44 -0
  2260. package/src/tools/puppeteer/01_stealth_activity.txt +80 -0
  2261. package/src/tools/puppeteer/02_stealth_hairline.txt +57 -0
  2262. package/src/tools/puppeteer/03_stealth_botd.txt +380 -0
  2263. package/src/tools/puppeteer/04_stealth_iframe.txt +174 -0
  2264. package/src/tools/puppeteer/05_stealth_webgl.txt +233 -0
  2265. package/src/tools/puppeteer/06_stealth_screen.txt +260 -0
  2266. package/src/tools/puppeteer/07_stealth_fonts.txt +99 -0
  2267. package/src/tools/puppeteer/08_stealth_audio.txt +63 -0
  2268. package/src/tools/puppeteer/09_stealth_locale.txt +51 -0
  2269. package/src/tools/puppeteer/10_stealth_plugins.txt +212 -0
  2270. package/src/tools/puppeteer/11_stealth_hardware.txt +59 -0
  2271. package/src/tools/puppeteer/12_stealth_codecs.txt +42 -0
  2272. package/src/tools/puppeteer/13_stealth_worker.txt +235 -0
  2273. package/src/tools/read.ts +3522 -0
  2274. package/src/tools/render-utils.ts +913 -0
  2275. package/src/tools/renderers.ts +107 -0
  2276. package/src/tools/report-tool-issue.ts +530 -0
  2277. package/src/tools/resolve.ts +302 -0
  2278. package/src/tools/review.ts +261 -0
  2279. package/src/tools/search-tool-bm25.ts +351 -0
  2280. package/src/tools/sqlite-reader.ts +884 -0
  2281. package/src/tools/ssh.ts +397 -0
  2282. package/src/tools/todo.ts +944 -0
  2283. package/src/tools/tool-errors.ts +62 -0
  2284. package/src/tools/tool-result.ts +102 -0
  2285. package/src/tools/tool-timeouts.ts +30 -0
  2286. package/src/tools/tts.ts +266 -0
  2287. package/src/tools/write.ts +1219 -0
  2288. package/src/tools/yield.ts +455 -0
  2289. package/src/tts/downloader.ts +64 -0
  2290. package/src/tts/index.ts +10 -0
  2291. package/src/tts/models.ts +137 -0
  2292. package/src/tts/player.ts +137 -0
  2293. package/src/tts/runtime.ts +21 -0
  2294. package/src/tts/speakable.ts +382 -0
  2295. package/src/tts/speech-enhancer.ts +204 -0
  2296. package/src/tts/streaming-player.ts +321 -0
  2297. package/src/tts/tts-client.ts +475 -0
  2298. package/src/tts/tts-protocol.ts +69 -0
  2299. package/src/tts/tts-worker.ts +434 -0
  2300. package/src/tts/vocalizer.ts +393 -0
  2301. package/src/tts/wav.ts +58 -0
  2302. package/src/tui/code-cell.ts +268 -0
  2303. package/src/tui/file-list.ts +55 -0
  2304. package/src/tui/hyperlink.ts +178 -0
  2305. package/src/tui/index.ts +13 -0
  2306. package/src/tui/output-block.ts +251 -0
  2307. package/src/tui/status-line.ts +54 -0
  2308. package/src/tui/tree-list.ts +133 -0
  2309. package/src/tui/types.ts +15 -0
  2310. package/src/tui/utils.ts +103 -0
  2311. package/src/tui/width-aware-text.ts +58 -0
  2312. package/src/utils/active-repo-context.ts +143 -0
  2313. package/src/utils/block-context.ts +312 -0
  2314. package/src/utils/changelog.ts +132 -0
  2315. package/src/utils/clipboard.ts +356 -0
  2316. package/src/utils/command-args.ts +76 -0
  2317. package/src/utils/commit-message-generator.ts +146 -0
  2318. package/src/utils/edit-mode.ts +58 -0
  2319. package/src/utils/enhanced-paste.ts +230 -0
  2320. package/src/utils/event-bus.ts +33 -0
  2321. package/src/utils/external-editor.ts +78 -0
  2322. package/src/utils/fetch-timeout.ts +10 -0
  2323. package/src/utils/file-display-mode.ts +44 -0
  2324. package/src/utils/file-mentions.ts +293 -0
  2325. package/src/utils/git.ts +2181 -0
  2326. package/src/utils/image-loading.ts +231 -0
  2327. package/src/utils/image-resize.ts +420 -0
  2328. package/src/utils/image-vision-fallback.ts +196 -0
  2329. package/src/utils/ipc.ts +38 -0
  2330. package/src/utils/jj.ts +295 -0
  2331. package/src/utils/lang-from-path.ts +244 -0
  2332. package/src/utils/markit-cache.ts +166 -0
  2333. package/src/utils/markit.ts +211 -0
  2334. package/src/utils/mupdf-wasm-embed.ts +12 -0
  2335. package/src/utils/open.ts +100 -0
  2336. package/src/utils/prompt-path.ts +3 -0
  2337. package/src/utils/qrcode.ts +535 -0
  2338. package/src/utils/session-color.ts +142 -0
  2339. package/src/utils/shell-snapshot-fn-env.sh +60 -0
  2340. package/src/utils/shell-snapshot.ts +306 -0
  2341. package/src/utils/sixel.ts +69 -0
  2342. package/src/utils/thinking-display.ts +117 -0
  2343. package/src/utils/title-generator.ts +348 -0
  2344. package/src/utils/tool-choice.ts +49 -0
  2345. package/src/utils/tools-manager.ts +429 -0
  2346. package/src/utils/turndown.ts +83 -0
  2347. package/src/utils/zip.ts +1091 -0
  2348. package/src/web/kagi.ts +304 -0
  2349. package/src/web/parallel.ts +354 -0
  2350. package/src/web/scrapers/artifacthub.ts +207 -0
  2351. package/src/web/scrapers/arxiv.ts +83 -0
  2352. package/src/web/scrapers/aur.ts +162 -0
  2353. package/src/web/scrapers/biorxiv.ts +133 -0
  2354. package/src/web/scrapers/bluesky.ts +262 -0
  2355. package/src/web/scrapers/brew.ts +172 -0
  2356. package/src/web/scrapers/cheatsh.ts +68 -0
  2357. package/src/web/scrapers/chocolatey.ts +196 -0
  2358. package/src/web/scrapers/choosealicense.ts +95 -0
  2359. package/src/web/scrapers/cisa-kev.ts +87 -0
  2360. package/src/web/scrapers/clojars.ts +154 -0
  2361. package/src/web/scrapers/coingecko.ts +177 -0
  2362. package/src/web/scrapers/crates-io.ts +97 -0
  2363. package/src/web/scrapers/crossref.ts +136 -0
  2364. package/src/web/scrapers/devto.ts +147 -0
  2365. package/src/web/scrapers/discogs.ts +306 -0
  2366. package/src/web/scrapers/discourse.ts +197 -0
  2367. package/src/web/scrapers/dockerhub.ts +138 -0
  2368. package/src/web/scrapers/docs-rs.ts +652 -0
  2369. package/src/web/scrapers/fdroid.ts +134 -0
  2370. package/src/web/scrapers/firefox-addons.ts +191 -0
  2371. package/src/web/scrapers/flathub.ts +223 -0
  2372. package/src/web/scrapers/github-gist.ts +58 -0
  2373. package/src/web/scrapers/github.ts +800 -0
  2374. package/src/web/scrapers/gitlab.ts +401 -0
  2375. package/src/web/scrapers/go-pkg.ts +266 -0
  2376. package/src/web/scrapers/hackage.ts +140 -0
  2377. package/src/web/scrapers/hackernews.ts +189 -0
  2378. package/src/web/scrapers/hex.ts +105 -0
  2379. package/src/web/scrapers/huggingface.ts +321 -0
  2380. package/src/web/scrapers/iacr.ts +89 -0
  2381. package/src/web/scrapers/index.ts +252 -0
  2382. package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
  2383. package/src/web/scrapers/lemmy.ts +203 -0
  2384. package/src/web/scrapers/lobsters.ts +175 -0
  2385. package/src/web/scrapers/mastodon.ts +292 -0
  2386. package/src/web/scrapers/maven.ts +138 -0
  2387. package/src/web/scrapers/mdn.ts +173 -0
  2388. package/src/web/scrapers/metacpan.ts +222 -0
  2389. package/src/web/scrapers/musicbrainz.ts +250 -0
  2390. package/src/web/scrapers/npm.ts +98 -0
  2391. package/src/web/scrapers/nuget.ts +183 -0
  2392. package/src/web/scrapers/nvd.ts +222 -0
  2393. package/src/web/scrapers/ollama.ts +239 -0
  2394. package/src/web/scrapers/open-vsx.ts +106 -0
  2395. package/src/web/scrapers/opencorporates.ts +292 -0
  2396. package/src/web/scrapers/openlibrary.ts +336 -0
  2397. package/src/web/scrapers/orcid.ts +286 -0
  2398. package/src/web/scrapers/osv.ts +176 -0
  2399. package/src/web/scrapers/packagist.ts +160 -0
  2400. package/src/web/scrapers/pub-dev.ts +143 -0
  2401. package/src/web/scrapers/pubmed.ts +211 -0
  2402. package/src/web/scrapers/pypi.ts +112 -0
  2403. package/src/web/scrapers/rawg.ts +110 -0
  2404. package/src/web/scrapers/readthedocs.ts +120 -0
  2405. package/src/web/scrapers/reddit.ts +95 -0
  2406. package/src/web/scrapers/repology.ts +251 -0
  2407. package/src/web/scrapers/rfc.ts +201 -0
  2408. package/src/web/scrapers/rubygems.ts +103 -0
  2409. package/src/web/scrapers/searchcode.ts +189 -0
  2410. package/src/web/scrapers/sec-edgar.ts +261 -0
  2411. package/src/web/scrapers/semantic-scholar.ts +171 -0
  2412. package/src/web/scrapers/snapcraft.ts +187 -0
  2413. package/src/web/scrapers/sourcegraph.ts +336 -0
  2414. package/src/web/scrapers/spdx.ts +108 -0
  2415. package/src/web/scrapers/spotify.ts +198 -0
  2416. package/src/web/scrapers/stackoverflow.ts +120 -0
  2417. package/src/web/scrapers/terraform.ts +277 -0
  2418. package/src/web/scrapers/tldr.ts +47 -0
  2419. package/src/web/scrapers/twitter.ts +94 -0
  2420. package/src/web/scrapers/types.ts +354 -0
  2421. package/src/web/scrapers/utils.ts +109 -0
  2422. package/src/web/scrapers/vimeo.ts +133 -0
  2423. package/src/web/scrapers/vscode-marketplace.ts +187 -0
  2424. package/src/web/scrapers/w3c.ts +156 -0
  2425. package/src/web/scrapers/wikidata.ts +344 -0
  2426. package/src/web/scrapers/wikipedia.ts +84 -0
  2427. package/src/web/scrapers/youtube.ts +325 -0
  2428. package/src/web/search/index.ts +312 -0
  2429. package/src/web/search/provider.ts +214 -0
  2430. package/src/web/search/providers/anthropic.ts +343 -0
  2431. package/src/web/search/providers/base.ts +91 -0
  2432. package/src/web/search/providers/brave.ts +152 -0
  2433. package/src/web/search/providers/codex.ts +593 -0
  2434. package/src/web/search/providers/duckduckgo.ts +212 -0
  2435. package/src/web/search/providers/exa.ts +484 -0
  2436. package/src/web/search/providers/firecrawl.ts +144 -0
  2437. package/src/web/search/providers/gemini.ts +618 -0
  2438. package/src/web/search/providers/jina.ts +111 -0
  2439. package/src/web/search/providers/kagi.ts +86 -0
  2440. package/src/web/search/providers/kimi.ts +196 -0
  2441. package/src/web/search/providers/parallel.ts +136 -0
  2442. package/src/web/search/providers/perplexity-auth.ts +133 -0
  2443. package/src/web/search/providers/perplexity.ts +878 -0
  2444. package/src/web/search/providers/searxng.ts +325 -0
  2445. package/src/web/search/providers/synthetic.ts +114 -0
  2446. package/src/web/search/providers/tavily.ts +193 -0
  2447. package/src/web/search/providers/tinyfish.ts +159 -0
  2448. package/src/web/search/providers/utils.ts +128 -0
  2449. package/src/web/search/providers/xai.ts +292 -0
  2450. package/src/web/search/providers/zai.ts +419 -0
  2451. package/src/web/search/render.ts +262 -0
  2452. package/src/web/search/types.ts +470 -0
  2453. package/src/web/search/utils.ts +17 -0
  2454. package/src/workspace-tree.ts +326 -0
@@ -0,0 +1,3522 @@
1
+ import { Database } from "bun:sqlite";
2
+ import * as fs from "node:fs/promises";
3
+ import * as os from "node:os";
4
+ import * as path from "node:path";
5
+ import { formatHashlineHeader, formatNumberedLine, formatNumberedLines } from "@oh-my-pi-zen/hashline";
6
+ import type {
7
+ AgentTool,
8
+ AgentToolContext,
9
+ AgentToolResult,
10
+ AgentToolUpdateCallback,
11
+ ToolTier,
12
+ } from "@oh-my-pi-zen/pi-agent-core";
13
+ import type { ImageContent, TextContent } from "@oh-my-pi-zen/pi-ai";
14
+ import { glob, type SummaryResult, summarizeCode } from "@oh-my-pi-zen/pi-natives";
15
+ import type { Component } from "@oh-my-pi-zen/pi-tui";
16
+ import { Text } from "@oh-my-pi-zen/pi-tui";
17
+ import {
18
+ getRemoteDir,
19
+ type ImageMetadata,
20
+ isProbablyBinary,
21
+ logger,
22
+ prompt,
23
+ readImageMetadata,
24
+ untilAborted,
25
+ } from "@oh-my-pi-zen/pi-utils";
26
+ import { type } from "arktype";
27
+ import { LRUCache } from "lru-cache/raw";
28
+ import {
29
+ canonicalSnapshotKey,
30
+ getFileSnapshotStore,
31
+ recordFileSnapshot,
32
+ recordSeenLines,
33
+ recordSeenLinesFromBody,
34
+ SNAPSHOT_MAX_BYTES,
35
+ } from "../edit/file-snapshot-store";
36
+ import { normalizeToLF } from "../edit/normalize";
37
+ import { isNotebookPath, readEditableNotebookText } from "../edit/notebook";
38
+ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
39
+ import { InternalUrlRouter, resolveLocalUrlToFile } from "../internal-urls";
40
+ import { type ResolvedArtifactFile, resolveArtifactFile } from "../internal-urls/artifact-protocol";
41
+ import { parseInternalUrl } from "../internal-urls/parse";
42
+ import type { InternalUrl } from "../internal-urls/types";
43
+ import { getLanguageFromPath, type Theme } from "../modes/theme/theme";
44
+ import readDescription from "../prompts/tools/read.md" with { type: "text" };
45
+ import type { ToolSession } from "../sdk";
46
+ import {
47
+ DEFAULT_MAX_BYTES,
48
+ DEFAULT_MAX_LINES,
49
+ noTruncResult,
50
+ type TruncationResult,
51
+ truncateHead,
52
+ truncateHeadBytes,
53
+ truncateLine,
54
+ } from "../session/streaming-output";
55
+ import { fileHyperlink, renderCodeCell, renderMarkdownCell, renderStatusLine, tryResolveInternalUrlSync } from "../tui";
56
+ import { CachedOutputBlock, markFramedBlockComponent } from "../tui/output-block";
57
+ import { buildLineEntriesWithBlockContext, type LineEntry, lineEntriesToPlainText } from "../utils/block-context";
58
+ import { resolveFileDisplayMode } from "../utils/file-display-mode";
59
+ import {
60
+ ImageInputTooLargeError,
61
+ loadImageInput,
62
+ MAX_IMAGE_INPUT_BYTES,
63
+ webpExclusionForModel,
64
+ } from "../utils/image-loading";
65
+ import { convertFileWithMarkit } from "../utils/markit";
66
+ import { type ArchiveReader, formatArchiveEntryLines, openArchive, parseArchivePathCandidates } from "../utils/zip";
67
+ import { buildDirectoryTree, type DirectoryTree } from "../workspace-tree";
68
+ import {
69
+ type ConflictEntry,
70
+ type ConflictScope,
71
+ formatConflictSummary,
72
+ formatConflictWarning,
73
+ getConflictHistory,
74
+ parseConflictUri,
75
+ renderConflictRegion,
76
+ scanConflictLines,
77
+ scanFileForConflicts,
78
+ } from "./conflict-detect";
79
+ import {
80
+ executeReadUrl,
81
+ loadReadUrlCacheEntry,
82
+ parseReadUrlTarget,
83
+ type ReadUrlToolDetails,
84
+ renderReadUrlCall,
85
+ renderReadUrlResult,
86
+ } from "./fetch";
87
+ import { applyListLimit } from "./list-limit";
88
+ import {
89
+ formatFullOutputReference,
90
+ formatStyledTruncationWarning,
91
+ type OutputMeta,
92
+ resolveOutputMaxColumns,
93
+ stripOutputNotice,
94
+ } from "./output-meta";
95
+ import {
96
+ expandPath,
97
+ formatPathRelativeToCwd,
98
+ isReadableUrlPath,
99
+ type LineRange,
100
+ parseLineRanges,
101
+ pathTargetsSsh,
102
+ resolveReadPath,
103
+ splitDelimitedPathEntry,
104
+ splitInternalUrlSel,
105
+ splitPathAndSel,
106
+ } from "./path-utils";
107
+ import { formatBytes, replaceTabs, shortenPath, wrapBrackets } from "./render-utils";
108
+ import {
109
+ executeReadQuery,
110
+ getRowByKey,
111
+ getRowByRowId,
112
+ getTableSchema,
113
+ isSqliteFile,
114
+ listTables,
115
+ MAX_RAW_QUERY_ROWS,
116
+ parseSqlitePathCandidates,
117
+ parseSqliteSelector,
118
+ queryRows,
119
+ renderRow,
120
+ renderSchema,
121
+ renderTable,
122
+ renderTableList,
123
+ resolveTableRowLookup,
124
+ } from "./sqlite-reader";
125
+ import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
126
+ import { toolResult } from "./tool-result";
127
+
128
+ // Per-session memo for tree-sitter summaries. `summarizeCode` is a pure function
129
+ // of (code, path, fold settings) but costs ~12-18ms for a ~1500-line file, and a
130
+ // repeat summary read of the same unchanged file re-parses from scratch. Key on
131
+ // the content hash of the freshly-read bytes (+ path + fold settings): the file
132
+ // is still read fresh on every call, so a hit only reuses the deterministic
133
+ // parse — there is no staleness window and no stat guard is needed. Bounded LRU,
134
+ // aged out with the session via WeakMap.
135
+ // Unusable results (not parsed, or nothing elided) are memoized as `false`: the
136
+ // full SummaryResult embeds the whole source in kept segments, and the caller
137
+ // only ever renders `parsed && elided` summaries — caching the segments would
138
+ // retain up to 48 near-2MiB sources just to remember "no summary".
139
+ const SUMMARY_CACHE_MAX = 48;
140
+ const summaryParseCaches = new WeakMap<object, LRUCache<string, SummaryResult | false>>();
141
+ function getSummaryParseCache(session: object): LRUCache<string, SummaryResult | false> {
142
+ let cache = summaryParseCaches.get(session);
143
+ if (!cache) {
144
+ cache = new LRUCache<string, SummaryResult | false>({ max: SUMMARY_CACHE_MAX });
145
+ summaryParseCaches.set(session, cache);
146
+ }
147
+ return cache;
148
+ }
149
+
150
+ // Document types converted to markdown via markit.
151
+ const CONVERTIBLE_EXTENSIONS = new Set([".pdf", ".doc", ".docx", ".ppt", ".pptx", ".xls", ".xlsx", ".rtf", ".epub"]);
152
+
153
+ const MAX_SUMMARY_BYTES = 2 * 1024 * 1024;
154
+ const MAX_SUMMARY_LINES = 20_000;
155
+ const MAX_ARTIFACT_RAW_INLINE_BYTES = DEFAULT_MAX_BYTES;
156
+ /**
157
+ * Per-line column cap for file reads. Lines wider than the value of
158
+ * `tools.outputMaxColumns` are ellipsis-truncated at display time; the file
159
+ * on disk is unchanged. Shared with the streaming sink path so one setting
160
+ * covers `bash`/`ssh`/`python`/`js eval` and `read` uniformly.
161
+ */
162
+ const PROSE_SUMMARY_EXTENSIONS = new Set([".md", ".txt"]);
163
+ // Remote mount path prefix (sshfs mounts) - skip fuzzy matching to avoid hangs
164
+ const REMOTE_MOUNT_PREFIX = getRemoteDir() + path.sep;
165
+
166
+ async function readBracketContextFullLines(absolutePath: string, fileSize: number): Promise<string[] | undefined> {
167
+ if (fileSize > SNAPSHOT_MAX_BYTES) return undefined;
168
+ try {
169
+ return normalizeToLF(await Bun.file(absolutePath).text()).split("\n");
170
+ } catch {
171
+ return undefined;
172
+ }
173
+ }
174
+
175
+ function isRemoteMountPath(absolutePath: string): boolean {
176
+ return absolutePath.startsWith(REMOTE_MOUNT_PREFIX);
177
+ }
178
+
179
+ function prependLineNumbers(text: string, startNum: number): string {
180
+ const textLines = text.split("\n");
181
+ return textLines.map((line, i) => `${startNum + i}|${line}`).join("\n");
182
+ }
183
+
184
+ interface HashlineHeaderContext {
185
+ header: string;
186
+ tag: string;
187
+ fullText?: string;
188
+ }
189
+
190
+ function formatReadHashlineHeader(displayPath: string, tag: string): string {
191
+ // In-workspace reads collapse to the bare filename for brevity: the edit
192
+ // tool's snapshot-tag recovery rebinds a bare `[name#tag]` onto the in-tree
193
+ // file it uniquely names. Out-of-workspace reads can't lean on that —
194
+ // recovery refuses to redirect a write outside the cwd/sandbox
195
+ // (HashlineFilesystem.allowTagPathRecovery) — so an absolute displayPath
196
+ // must stay directly resolvable, otherwise the basename resolves against
197
+ // cwd, misses, and the edit fails with "File not found" (e.g. ~/.claude/*).
198
+ // `shortenPath` keeps `~/.claude/...` (round-trips through resolveToCwd's ~
199
+ // expansion) instead of leaking the full home path into the read output.
200
+ const anchor = path.isAbsolute(displayPath) ? shortenPath(displayPath) : path.basename(displayPath);
201
+ return formatHashlineHeader(anchor, tag);
202
+ }
203
+
204
+ function recordFullHashlineContext(
205
+ session: ToolSession,
206
+ absolutePath: string | undefined,
207
+ displayPath: string,
208
+ fullText: string,
209
+ ): HashlineHeaderContext | undefined {
210
+ if (!absolutePath || !path.isAbsolute(absolutePath)) return undefined;
211
+ const normalized = normalizeToLF(fullText);
212
+ const tag = getFileSnapshotStore(session).record(canonicalSnapshotKey(absolutePath), normalized);
213
+ return {
214
+ header: formatReadHashlineHeader(displayPath, tag),
215
+ tag,
216
+ fullText: normalized,
217
+ };
218
+ }
219
+
220
+ async function readHashlineHeaderContext(
221
+ session: ToolSession,
222
+ absolutePath: string,
223
+ cwd: string,
224
+ ): Promise<HashlineHeaderContext> {
225
+ const fullText = await Bun.file(absolutePath).text();
226
+ const context = recordFullHashlineContext(
227
+ session,
228
+ absolutePath,
229
+ formatPathRelativeToCwd(absolutePath, cwd),
230
+ fullText,
231
+ );
232
+ if (!context) throw new ToolError(`Cannot record hashline snapshot for non-absolute path: ${absolutePath}`);
233
+ return context;
234
+ }
235
+
236
+ function hashlineHeaderContext(displayPath: string, tag: string): HashlineHeaderContext {
237
+ return { header: formatReadHashlineHeader(displayPath, tag), tag };
238
+ }
239
+
240
+ function prependHashlineHeader(text: string, context: HashlineHeaderContext | undefined): string {
241
+ return context ? `${context.header}\n${text}` : text;
242
+ }
243
+
244
+ function formatTextWithMode(
245
+ text: string,
246
+ startNum: number,
247
+ shouldAddHashLines: boolean,
248
+ shouldAddLineNumbers: boolean,
249
+ ): string {
250
+ if (shouldAddHashLines) return formatNumberedLines(text, startNum);
251
+ if (shouldAddLineNumbers) return prependLineNumbers(text, startNum);
252
+ return text;
253
+ }
254
+
255
+ const BRACKET_CONTEXT_ELLIPSIS = "…";
256
+
257
+ function formatLineEntryWithMode(entry: LineEntry, shouldAddHashLines: boolean, shouldAddLineNumbers: boolean): string {
258
+ if (entry.kind === "ellipsis") return BRACKET_CONTEXT_ELLIPSIS;
259
+ return formatSingleLine(entry.lineNumber, entry.text, shouldAddHashLines, shouldAddLineNumbers);
260
+ }
261
+
262
+ function formatLineEntriesWithMode(
263
+ entries: readonly LineEntry[],
264
+ shouldAddHashLines: boolean,
265
+ shouldAddLineNumbers: boolean,
266
+ ): string {
267
+ return entries.map(entry => formatLineEntryWithMode(entry, shouldAddHashLines, shouldAddLineNumbers)).join("\n");
268
+ }
269
+
270
+ const BRACE_PAIRS: Record<string, string> = { "{": "}", "(": ")", "[": "]" };
271
+ const BRACE_TAIL_TRAILING_RE = /^[;,)\]}]*$/;
272
+
273
+ /**
274
+ * Decide whether the kept lines surrounding an elided range collapse to a
275
+ * single brace-pair line in the rendered summary. Returns true when the head
276
+ * line ends with `{` / `(` / `[` and the tail line is the matching closer
277
+ * (optionally followed by terminating punctuation like `;`, `,`, or further
278
+ * closers — e.g. `};`, `})`, `]);`).
279
+ */
280
+ function canMergeBracePair(headLine: string, tailLine: string): boolean {
281
+ const head = headLine.trimEnd();
282
+ const tail = tailLine.trim();
283
+ const opener = head.slice(-1);
284
+ const closer = BRACE_PAIRS[opener];
285
+ if (!closer) return false;
286
+ if (!tail.startsWith(closer)) return false;
287
+ return BRACE_TAIL_TRAILING_RE.test(tail.slice(closer.length));
288
+ }
289
+
290
+ function formatSingleLine(
291
+ line: number,
292
+ text: string,
293
+ shouldAddHashLines: boolean,
294
+ shouldAddLineNumbers: boolean,
295
+ ): string {
296
+ if (shouldAddHashLines) return formatNumberedLine(line, text);
297
+ if (shouldAddLineNumbers) return `${line}|${text}`;
298
+ return text;
299
+ }
300
+
301
+ function formatMergedBraceLine(
302
+ startLine: number,
303
+ endLine: number,
304
+ headText: string,
305
+ tailText: string,
306
+ shouldAddHashLines: boolean,
307
+ shouldAddLineNumbers: boolean,
308
+ ): { model: string; display: string } {
309
+ const merged = `${headText.trimEnd()} … ${tailText.trim()}`;
310
+ if (shouldAddHashLines) {
311
+ return { model: `${startLine}-${endLine}:${merged}`, display: merged };
312
+ }
313
+ if (shouldAddLineNumbers) {
314
+ return { model: `${startLine}-${endLine}|${merged}`, display: merged };
315
+ }
316
+ return { model: merged, display: merged };
317
+ }
318
+
319
+ function countTextLines(text: string): number {
320
+ if (text.length === 0) return 0;
321
+ // Count newlines directly instead of allocating an array via split("\n").
322
+ // Called on every read of file content; the result is identical (N newlines
323
+ // ⇒ N+1 lines for non-empty text).
324
+ let lines = 1;
325
+ for (let i = 0; i < text.length; i++) {
326
+ if (text.charCodeAt(i) === 10) lines++;
327
+ }
328
+ return lines;
329
+ }
330
+
331
+ function contiguousLineNumbers(startLine: number, count: number): number[] {
332
+ const lines: number[] = [];
333
+ for (let offset = 0; offset < count; offset++) lines.push(startLine + offset);
334
+ return lines;
335
+ }
336
+
337
+ function lineNumbersFromSpans(spans: readonly { startLine: number; endLine: number }[]): number[] {
338
+ const lines: number[] = [];
339
+ for (const span of spans) {
340
+ for (let line = span.startLine; line <= span.endLine; line++) lines.push(line);
341
+ }
342
+ return lines;
343
+ }
344
+
345
+ function recordInMemorySeenLines(
346
+ session: ToolSession,
347
+ absolutePath: string | undefined,
348
+ fullText: string,
349
+ seenLines: readonly number[] | undefined,
350
+ ): void {
351
+ if (!absolutePath || !path.isAbsolute(absolutePath) || !seenLines || seenLines.length === 0) return;
352
+ getFileSnapshotStore(session).record(canonicalSnapshotKey(absolutePath), normalizeToLF(fullText), seenLines);
353
+ }
354
+
355
+ function lineNumbersFromEntries(entries: readonly LineEntry[]): number[] {
356
+ const lines: number[] = [];
357
+ for (const entry of entries) {
358
+ if (entry.kind === "line") lines.push(entry.lineNumber);
359
+ }
360
+ return lines;
361
+ }
362
+
363
+ /** Inclusive line range describing one elided span in a structural summary. */
364
+ interface ElidedRange {
365
+ start: number;
366
+ end: number;
367
+ }
368
+
369
+ /** Sample ranges shown in the footer to demonstrate the multi-range syntax. */
370
+ const FOOTER_RANGE_SAMPLES = 2;
371
+
372
+ /**
373
+ * Footer appended to summarized reads telling the model how to recover the
374
+ * elided body. Without this hint, agents either ignore the `…`/`{ … }`
375
+ * markers or burn a turn guessing the right selector (see issue #1046). The
376
+ * footer demonstrates the multi-range selector syntax with concrete sample
377
+ * ranges drawn from the actual elision so the model re-reads only what it
378
+ * needs instead of falling back to `:raw` or whole-file reads.
379
+ */
380
+ function formatSummaryElisionFooter(
381
+ readPath: string,
382
+ elidedRanges: ReadonlyArray<ElidedRange>,
383
+ elidedLines: number,
384
+ ): string {
385
+ if (elidedRanges.length === 0) return "";
386
+ const sampleCount = Math.min(elidedRanges.length, FOOTER_RANGE_SAMPLES);
387
+ const selector = elidedRanges
388
+ .slice(0, sampleCount)
389
+ .map(r => `${r.start}-${r.end}`)
390
+ .join(",");
391
+ const example = `${readPath}:${selector}`;
392
+ const tail = elidedRanges.length > sampleCount ? `, e.g. ${example}` : ` with ${example}`;
393
+ return `[…${elidedLines}ln elided; re-read needed ranges${tail}]`;
394
+ }
395
+ const READ_CHUNK_SIZE = 8 * 1024;
396
+
397
+ /**
398
+ * Context lines added around an explicit range read. Anchor-stale failures
399
+ * cluster on edits whose anchors land just outside the most recent read
400
+ * window, but the data (`scripts/session-stats/analyze_selector_reads.py`)
401
+ * shows most follow-up reads are disjoint hops, not adjacent extensions —
402
+ * so symmetric padding rarely pays for itself.
403
+ *
404
+ * Leading=1 catches accidental single-line reads where the anchor is the
405
+ * line immediately above the requested start. Trailing=3 buffers the
406
+ * common case where the agent asks for a narrow range and then needs the
407
+ * next few lines to disambiguate an anchor.
408
+ */
409
+ const RANGE_LEADING_CONTEXT_LINES = 1;
410
+ const RANGE_TRAILING_CONTEXT_LINES = 3;
411
+
412
+ /**
413
+ * Expand a [start, end) range with leading/trailing context lines on the
414
+ * sides where the user actually constrained the range. A start of 0 (no
415
+ * explicit offset) does not get leading context — that's already an
416
+ * open-ended read from the top.
417
+ */
418
+ function expandRangeWithContext(
419
+ requestedStart: number,
420
+ requestedEnd: number,
421
+ totalLines: number,
422
+ expandStart: boolean,
423
+ expandEnd: boolean,
424
+ ): { startLine: number; endLine: number } {
425
+ return {
426
+ startLine: expandStart ? Math.max(0, requestedStart - RANGE_LEADING_CONTEXT_LINES) : requestedStart,
427
+ endLine: expandEnd ? Math.min(totalLines, requestedEnd + RANGE_TRAILING_CONTEXT_LINES) : requestedEnd,
428
+ };
429
+ }
430
+
431
+ async function streamLinesFromFile(
432
+ filePath: string,
433
+ startLine: number,
434
+ maxLinesToCollect: number,
435
+ maxBytes: number,
436
+ selectedLineLimit: number | null,
437
+ signal?: AbortSignal,
438
+ stopScanAfterCollect = false,
439
+ ): Promise<{
440
+ lines: string[];
441
+ totalFileLines: number;
442
+ collectedBytes: number;
443
+ stoppedByByteLimit: boolean;
444
+ firstLinePreview?: { text: string; bytes: number };
445
+ firstLineByteLength?: number;
446
+ selectedBytesTotal: number;
447
+ /** False when `stopScanAfterCollect` cut the scan short — `totalFileLines` is then a lower bound. */
448
+ reachedEof: boolean;
449
+ }> {
450
+ const bufferChunk = Buffer.allocUnsafe(READ_CHUNK_SIZE);
451
+ const collectedLines: string[] = [];
452
+ let lineIndex = 0;
453
+ let collectedBytes = 0;
454
+ let stoppedByByteLimit = false;
455
+ let doneCollecting = false;
456
+ let reachedEof = true;
457
+ let fileHandle: fs.FileHandle | null = null;
458
+ let currentLineLength = 0;
459
+ let currentLineChunks: Buffer[] = [];
460
+ let sawAnyByte = false;
461
+ let endedWithNewline = false;
462
+ let firstLinePreviewBytes = 0;
463
+ const firstLinePreviewChunks: Buffer[] = [];
464
+ let firstLineByteLength: number | undefined;
465
+ let selectedBytesTotal = 0;
466
+ let selectedLinesSeen = 0;
467
+ let captureLine = false;
468
+ let discardLineChunks = false;
469
+ let lineCaptureLimit = 0;
470
+
471
+ const setupLineState = () => {
472
+ captureLine = !doneCollecting && lineIndex >= startLine;
473
+ discardLineChunks = !captureLine;
474
+ if (captureLine) {
475
+ const separatorBytes = collectedLines.length > 0 ? 1 : 0;
476
+ lineCaptureLimit = maxBytes - collectedBytes - separatorBytes;
477
+ if (lineCaptureLimit <= 0) {
478
+ discardLineChunks = true;
479
+ }
480
+ } else {
481
+ lineCaptureLimit = 0;
482
+ }
483
+ };
484
+
485
+ const decodeLine = (): string => {
486
+ if (currentLineLength === 0) return "";
487
+ if (currentLineChunks.length === 1 && currentLineChunks[0]?.length === currentLineLength) {
488
+ return currentLineChunks[0].toString("utf-8");
489
+ }
490
+ return Buffer.concat(currentLineChunks, currentLineLength).toString("utf-8");
491
+ };
492
+
493
+ const maybeCapturePreview = (segment: Uint8Array) => {
494
+ if (doneCollecting || lineIndex < startLine || collectedLines.length !== 0) return;
495
+ if (firstLinePreviewBytes >= maxBytes || segment.length === 0) return;
496
+ const remaining = maxBytes - firstLinePreviewBytes;
497
+ const slice = segment.length > remaining ? segment.subarray(0, remaining) : segment;
498
+ if (slice.length === 0) return;
499
+ firstLinePreviewChunks.push(Buffer.from(slice));
500
+ firstLinePreviewBytes += slice.length;
501
+ };
502
+
503
+ const appendSegment = (segment: Uint8Array) => {
504
+ currentLineLength += segment.length;
505
+ maybeCapturePreview(segment);
506
+ if (!captureLine || discardLineChunks || segment.length === 0) return;
507
+ if (currentLineLength <= lineCaptureLimit) {
508
+ currentLineChunks.push(Buffer.from(segment));
509
+ } else {
510
+ discardLineChunks = true;
511
+ }
512
+ };
513
+
514
+ const finalizeLine = () => {
515
+ if (lineIndex >= startLine && (selectedLineLimit === null || selectedLinesSeen < selectedLineLimit)) {
516
+ selectedBytesTotal += currentLineLength + (selectedLinesSeen > 0 ? 1 : 0);
517
+ selectedLinesSeen++;
518
+ }
519
+
520
+ if (!doneCollecting && lineIndex >= startLine) {
521
+ const separatorBytes = collectedLines.length > 0 ? 1 : 0;
522
+ if (collectedLines.length >= maxLinesToCollect) {
523
+ doneCollecting = true;
524
+ } else if (collectedLines.length === 0 && currentLineLength > maxBytes) {
525
+ stoppedByByteLimit = true;
526
+ doneCollecting = true;
527
+ if (firstLineByteLength === undefined) {
528
+ firstLineByteLength = currentLineLength;
529
+ }
530
+ } else if (collectedLines.length > 0 && collectedBytes + separatorBytes + currentLineLength > maxBytes) {
531
+ stoppedByByteLimit = true;
532
+ doneCollecting = true;
533
+ } else {
534
+ const lineText = decodeLine();
535
+ collectedLines.push(lineText);
536
+ collectedBytes += separatorBytes + currentLineLength;
537
+ if (firstLineByteLength === undefined) {
538
+ firstLineByteLength = currentLineLength;
539
+ }
540
+ if (collectedBytes > maxBytes) {
541
+ stoppedByByteLimit = true;
542
+ doneCollecting = true;
543
+ } else if (collectedLines.length >= maxLinesToCollect) {
544
+ doneCollecting = true;
545
+ }
546
+ }
547
+ } else if (lineIndex >= startLine && firstLineByteLength === undefined) {
548
+ firstLineByteLength = currentLineLength;
549
+ }
550
+
551
+ lineIndex++;
552
+ currentLineLength = 0;
553
+ currentLineChunks = [];
554
+ setupLineState();
555
+ };
556
+
557
+ setupLineState();
558
+
559
+ try {
560
+ fileHandle = await fs.open(filePath, "r");
561
+
562
+ while (true) {
563
+ throwIfAborted(signal);
564
+ const { bytesRead } = await fileHandle.read(bufferChunk, 0, bufferChunk.length, null);
565
+ if (bytesRead === 0) break;
566
+
567
+ sawAnyByte = true;
568
+ const chunk = bufferChunk.subarray(0, bytesRead);
569
+ endedWithNewline = chunk[bytesRead - 1] === 0x0a;
570
+
571
+ // Once collection and selected-line accounting are both finished, the
572
+ // remaining scan only computes `totalFileLines` — count newlines with
573
+ // native indexOf instead of the per-byte JS loop (a multi-GB tail
574
+ // otherwise stalls the read for seconds to minutes).
575
+ if (doneCollecting && selectedLineLimit !== null && selectedLinesSeen >= selectedLineLimit) {
576
+ if (stopScanAfterCollect) {
577
+ reachedEof = false;
578
+ break;
579
+ }
580
+ let searchFrom = 0;
581
+ let newlineAt = chunk.indexOf(0x0a);
582
+ while (newlineAt !== -1) {
583
+ lineIndex++;
584
+ searchFrom = newlineAt + 1;
585
+ newlineAt = chunk.indexOf(0x0a, searchFrom);
586
+ }
587
+ if (searchFrom === 0) {
588
+ currentLineLength += chunk.length;
589
+ } else {
590
+ currentLineLength = chunk.length - searchFrom;
591
+ }
592
+ continue;
593
+ }
594
+
595
+ let start = 0;
596
+ for (let i = 0; i < chunk.length; i++) {
597
+ if (chunk[i] === 0x0a) {
598
+ const segment = chunk.subarray(start, i);
599
+ if (segment.length > 0) {
600
+ appendSegment(segment);
601
+ }
602
+ finalizeLine();
603
+ start = i + 1;
604
+ }
605
+ }
606
+
607
+ if (start < chunk.length) {
608
+ appendSegment(chunk.subarray(start));
609
+ }
610
+ }
611
+ } finally {
612
+ if (fileHandle) {
613
+ await fileHandle.close();
614
+ }
615
+ }
616
+
617
+ if (reachedEof && (endedWithNewline || currentLineLength > 0 || !sawAnyByte)) {
618
+ finalizeLine();
619
+ }
620
+
621
+ let firstLinePreview: { text: string; bytes: number } | undefined;
622
+ if (firstLinePreviewBytes > 0) {
623
+ const { text, bytes } = truncateHeadBytes(Buffer.concat(firstLinePreviewChunks, firstLinePreviewBytes), maxBytes);
624
+ firstLinePreview = { text, bytes };
625
+ }
626
+
627
+ return {
628
+ lines: collectedLines,
629
+ totalFileLines: lineIndex,
630
+ collectedBytes,
631
+ stoppedByByteLimit,
632
+ firstLinePreview,
633
+ firstLineByteLength,
634
+ selectedBytesTotal,
635
+ reachedEof,
636
+ };
637
+ }
638
+
639
+ // Maximum image file size (20MB) - larger images will be rejected to prevent OOM during serialization
640
+ const MAX_IMAGE_SIZE = MAX_IMAGE_INPUT_BYTES;
641
+ const GLOB_TIMEOUT_MS = 5000;
642
+
643
+ function isNotFoundError(error: unknown): boolean {
644
+ if (!error || typeof error !== "object") return false;
645
+ const code = (error as { code?: string }).code;
646
+ return code === "ENOENT" || code === "ENOTDIR";
647
+ }
648
+
649
+ /**
650
+ * Escape glob metacharacters so a literal path (e.g. `foo[1].ts`) interpolated
651
+ * into a suffix-glob pattern matches itself. Each metachar is wrapped in a
652
+ * character class (the native glob engine rewrites `\` to `/`, so backslash
653
+ * escaping is unavailable). `]`/`}` need no escaping once their openers are
654
+ * neutralized — unmatched closers are literal.
655
+ */
656
+ function escapeGlobMetachars(value: string): string {
657
+ return value.replace(/[*?[{]/g, "[$&]");
658
+ }
659
+
660
+ /**
661
+ * Attempt to resolve a non-existent path by finding a unique suffix match within the workspace.
662
+ * Uses a glob suffix pattern so the native engine handles matching directly.
663
+ * Returns null when 0 or >1 candidates match (ambiguous = no auto-resolution).
664
+ */
665
+ async function findUniqueSuffixMatch(
666
+ rawPath: string,
667
+ cwd: string,
668
+ signal?: AbortSignal,
669
+ ): Promise<{ absolutePath: string; displayPath: string } | null> {
670
+ const normalized = rawPath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
671
+ if (!normalized) return null;
672
+ const pattern = `**/${escapeGlobMetachars(normalized)}`;
673
+
674
+ const timeoutSignal = AbortSignal.timeout(GLOB_TIMEOUT_MS);
675
+ const combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
676
+
677
+ let matches: string[];
678
+ try {
679
+ const result = await untilAborted(combinedSignal, () =>
680
+ glob({
681
+ pattern,
682
+ path: cwd,
683
+ // No fileType filter: matches both files and directories
684
+ hidden: true,
685
+ }),
686
+ );
687
+ matches = result.matches.map(m => m.path);
688
+ } catch (error) {
689
+ if (error instanceof Error && error.name === "AbortError") {
690
+ if (!signal?.aborted) return null; // timeout — give up silently
691
+ throw new ToolAbortError();
692
+ }
693
+ return null;
694
+ }
695
+
696
+ if (matches.length !== 1) return null;
697
+
698
+ return {
699
+ absolutePath: path.resolve(cwd, matches[0]),
700
+ displayPath: matches[0],
701
+ };
702
+ }
703
+
704
+ function decodeUtf8Text(bytes: Uint8Array): string | null {
705
+ if (bytes.indexOf(0) !== -1) return null;
706
+
707
+ try {
708
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
709
+ } catch {
710
+ return null;
711
+ }
712
+ }
713
+
714
+ function prependSuffixResolutionNotice(text: string, suffixResolution?: { from: string; to: string }): string {
715
+ if (!suffixResolution) return text;
716
+
717
+ const notice = `[Path '${suffixResolution.from}' not found; resolved to '${suffixResolution.to}' via suffix match]`;
718
+ return text ? `${notice}\n${text}` : notice;
719
+ }
720
+ const PDF_IMAGE_PLACEHOLDER_RE = /<!--\s*image:\s*([^\s<>]+)(.*?)-->/g;
721
+ const PDF_IMAGE_MEMBER_RE = /^(.*\.pdf):(.*)$/i;
722
+ const PDF_IMAGE_MEMBER_EXTENSION_RE = /\.png$/i;
723
+
724
+ function pdfImageMemberPath(pdfPath: string, imageId: string): string {
725
+ const member = PDF_IMAGE_MEMBER_EXTENSION_RE.test(imageId) ? imageId : `${imageId}.png`;
726
+ return `${pdfPath}:${member}`;
727
+ }
728
+
729
+ function rewritePdfImagePlaceholders(markdown: string, pdfPath: string): string {
730
+ return markdown.replace(PDF_IMAGE_PLACEHOLDER_RE, (_match: string, imageId: string, metadataText: string) => {
731
+ const metadata = metadataText.trim();
732
+ const suffix = metadata.length > 0 ? ` (${metadata})` : "";
733
+ return `Image ${imageId}${suffix}: read \`${pdfImageMemberPath(pdfPath, imageId)}\``;
734
+ });
735
+ }
736
+
737
+ function splitPdfImageMemberReadPath(readPath: string): { pdfPath: string; member: string } | null {
738
+ const match = PDF_IMAGE_MEMBER_RE.exec(readPath);
739
+ if (!match) return null;
740
+ const pdfPath = match[1];
741
+ const member = match[2];
742
+ if (pdfPath === undefined || member === undefined) return null;
743
+ if (member.length !== 0 && !PDF_IMAGE_MEMBER_EXTENSION_RE.test(member)) return null;
744
+ return { pdfPath, member };
745
+ }
746
+
747
+ const readSchema = type({
748
+ path: type("string").describe(
749
+ 'Local path, internal URI (e.g. "omp://", "issue://123", "pr://123"), or URL; append :<sel> for line ranges or raw mode (e.g. "src/foo.ts:50-100")',
750
+ ),
751
+ });
752
+
753
+ export type ReadToolInput = typeof readSchema.infer;
754
+
755
+ export interface ReadToolDetails {
756
+ kind?: "file" | "url";
757
+ truncation?: TruncationResult;
758
+ isDirectory?: boolean;
759
+ resolvedPath?: string;
760
+ suffixResolution?: { from: string; to: string };
761
+ url?: string;
762
+ finalUrl?: string;
763
+ contentType?: string;
764
+ method?: string;
765
+ notes?: string[];
766
+ meta?: OutputMeta;
767
+ /** Raw text + start line for user-visible TUI rendering, set when content is text-like.
768
+ * Mirrors the same lines the model receives but without hashline/line-number prefixes,
769
+ * so the TUI can render the file content with its own gutter without re-parsing the formatted text. */
770
+ displayContent?: {
771
+ text: string;
772
+ startLine: number;
773
+ lineNumbers?: Array<number | null>;
774
+ };
775
+ summary?: { lines: number; elidedSpans: number; elidedLines: number };
776
+ /** Number of unresolved git conflicts surfaced by this read (TUI uses for inline `⚠ N` badge). */
777
+ conflictCount?: number;
778
+ /** Paths recovered from a delimited read argument; used only by the TUI to render one call as multiple read rows. */
779
+ displayReadTargets?: string[];
780
+ }
781
+
782
+ type ReadParams = ReadToolInput;
783
+
784
+ /** Parsed representation of a path-embedded selector. */
785
+ type ParsedSelector =
786
+ | { kind: "none" }
787
+ | { kind: "raw" }
788
+ | { kind: "conflicts" }
789
+ | { kind: "lines"; ranges: [LineRange, ...LineRange[]]; raw?: boolean };
790
+
791
+ /** Returns true when the selector requested verbatim/raw output (alone or combined with a range). */
792
+ function isRawSelector(parsed: ParsedSelector): boolean {
793
+ return parsed.kind === "raw" || (parsed.kind === "lines" && parsed.raw === true);
794
+ }
795
+
796
+ /** Returns true when the selector requested multiple line ranges. */
797
+ function isMultiRange(parsed: ParsedSelector): boolean {
798
+ return parsed.kind === "lines" && parsed.ranges.length > 1;
799
+ }
800
+
801
+ function selectorChunkLooksReadLike(chunk: string): boolean {
802
+ const lower = chunk.toLowerCase();
803
+ return (
804
+ lower === "raw" || lower === "conflicts" || /^-\d+(?:[-+]\d+)?$/.test(chunk) || parseLineRanges(chunk) !== null
805
+ );
806
+ }
807
+
808
+ function invalidSelector(sel: string): ToolError {
809
+ return new ToolError(
810
+ `Invalid selector ':${sel}'. Use :N, :N-M, :N+K, :N- (open-ended), a comma-separated list of ranges, :raw, or a range combined with raw (e.g. :raw:50-100).`,
811
+ );
812
+ }
813
+
814
+ function parseSel(sel: string | undefined): ParsedSelector {
815
+ if (!sel || sel.length === 0) return { kind: "none" };
816
+
817
+ // Compound selector: `1-50:raw` or `raw:1-50`. Split into chunks and accept
818
+ // exactly one line range (possibly multi) plus the literal `raw`. Selector-like
819
+ // compounds that are not in that accepted set are invalid rather than "none";
820
+ // otherwise `read` can silently widen a malformed selector like
821
+ // `artifact://5:conflicts:1-1` while `grep` rejects it.
822
+ if (sel.includes(":")) {
823
+ const chunks = sel.split(":");
824
+ if (chunks.length === 2) {
825
+ const [a, b] = chunks as [string, string];
826
+ const aIsRaw = a.toLowerCase() === "raw";
827
+ const bIsRaw = b.toLowerCase() === "raw";
828
+ const rangeChunk = aIsRaw ? b : bIsRaw ? a : null;
829
+ const rawChunk = aIsRaw ? a : bIsRaw ? b : null;
830
+ if (rangeChunk !== null && rawChunk !== null) {
831
+ const ranges = parseLineRanges(rangeChunk);
832
+ if (ranges) {
833
+ return { kind: "lines", ranges, raw: true };
834
+ }
835
+ }
836
+ }
837
+ if (chunks.every(selectorChunkLooksReadLike)) throw invalidSelector(sel);
838
+ // Unrecognized compound — fall through (sqlite/archive/url consume their own colon syntax).
839
+ return { kind: "none" };
840
+ }
841
+
842
+ if (sel.toLowerCase() === "raw") return { kind: "raw" };
843
+ if (sel.toLowerCase() === "conflicts") return { kind: "conflicts" };
844
+ const ranges = parseLineRanges(sel);
845
+ if (ranges) {
846
+ return { kind: "lines", ranges };
847
+ }
848
+ // Unrecognized selectors fall through; sqlite/archive/url readers consume their own colon syntax.
849
+ return { kind: "none" };
850
+ }
851
+
852
+ /**
853
+ * Convert a single-range selector to the offset/limit pair used by internal pagination.
854
+ * Returns the FIRST range only — multi-range callers MUST branch on `isMultiRange` before
855
+ * calling this helper.
856
+ */
857
+ function selToOffsetLimit(parsed: ParsedSelector): { offset?: number; limit?: number } {
858
+ if (parsed.kind === "lines") {
859
+ const first = parsed.ranges[0];
860
+ const limit = first.endLine !== undefined ? first.endLine - first.startLine + 1 : undefined;
861
+ return { offset: first.startLine, limit };
862
+ }
863
+ return {};
864
+ }
865
+
866
+ interface ResolvedArchiveReadPath {
867
+ absolutePath: string;
868
+ archiveSubPath: string;
869
+ suffixResolution?: { from: string; to: string };
870
+ }
871
+
872
+ interface ResolvedSqliteReadPath {
873
+ absolutePath: string;
874
+ sqliteSubPath: string;
875
+ queryString: string;
876
+ suffixResolution?: { from: string; to: string };
877
+ }
878
+
879
+ /** Per-execute memo of suffix-glob lookups; `null` records a confirmed miss. */
880
+ type SuffixMatchCache = Map<string, { absolutePath: string; displayPath: string } | null>;
881
+
882
+ /**
883
+ * Read tool implementation.
884
+ *
885
+ * Reads files with support for images, converted documents (via markit), and text.
886
+ * Directories return a formatted listing with modification times.
887
+ */
888
+ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
889
+ readonly name = "read";
890
+ readonly approval = (args: unknown): ToolTier =>
891
+ pathTargetsSsh(String((args as { path?: unknown }).path ?? "")) ? "exec" : "read";
892
+ readonly label = "Read";
893
+ readonly loadMode = "essential";
894
+ readonly description: string;
895
+ readonly parameters = readSchema;
896
+ readonly strict = true;
897
+
898
+ readonly #autoResizeImages: boolean;
899
+ readonly #defaultLimit: number;
900
+ readonly #inspectImageEnabled: boolean;
901
+
902
+ constructor(private readonly session: ToolSession) {
903
+ const displayMode = resolveFileDisplayMode(session);
904
+ this.#autoResizeImages = session.settings.get("images.autoResize");
905
+ this.#defaultLimit = Math.max(
906
+ 1,
907
+ Math.min(session.settings.get("read.defaultLimit") ?? DEFAULT_MAX_LINES, DEFAULT_MAX_LINES),
908
+ );
909
+ this.#inspectImageEnabled = session.settings.get("inspect_image.enabled");
910
+ this.description = prompt.render(readDescription, {
911
+ DEFAULT_LIMIT: String(this.#defaultLimit),
912
+ DEFAULT_MAX_LINES: String(DEFAULT_MAX_LINES),
913
+ IS_HL_MODE: displayMode.hashLines,
914
+ IS_LINE_NUMBER_MODE: !displayMode.hashLines && displayMode.lineNumbers,
915
+ INSPECT_IMAGE_ENABLED: this.#inspectImageEnabled,
916
+ });
917
+ }
918
+
919
+ async #tryReadDelimitedPaths(
920
+ readPath: string,
921
+ signal?: AbortSignal,
922
+ ): Promise<AgentToolResult<ReadToolDetails> | null> {
923
+ const parts = await splitDelimitedPathEntry(readPath, this.session.cwd);
924
+ if (!parts) return null;
925
+
926
+ const notice = `Note: interpreted as ${parts.length} paths: ${parts.join(", ")}`;
927
+ const notes = [notice];
928
+ const content: Array<TextContent | ImageContent> = [];
929
+ const displayReadTargets: string[] = [];
930
+ let pendingText = notice;
931
+ const flushText = () => {
932
+ if (pendingText.length === 0) return;
933
+ content.push({ type: "text", text: pendingText });
934
+ pendingText = "";
935
+ };
936
+ const appendText = (text: string) => {
937
+ pendingText = pendingText.length > 0 ? `${pendingText}\n\n${text}` : text;
938
+ };
939
+
940
+ for (const part of parts) {
941
+ try {
942
+ const result = await this.execute("read-delimited-part", { path: part }, signal);
943
+ displayReadTargets.push(result.details?.suffixResolution?.to ?? part);
944
+ for (const block of result.content) {
945
+ if (block.type === "text") {
946
+ appendText(block.text);
947
+ continue;
948
+ }
949
+ flushText();
950
+ content.push(block);
951
+ }
952
+ } catch (error) {
953
+ if (error instanceof ToolAbortError || signal?.aborted) throw error;
954
+ const message = error instanceof Error ? error.message : String(error);
955
+ const errorNote = `Could not read ${part}: ${message}`;
956
+ notes.push(errorNote);
957
+ displayReadTargets.push(part);
958
+ appendText(`[${errorNote}]`);
959
+ }
960
+ }
961
+ flushText();
962
+
963
+ return toolResult<ReadToolDetails>({ notes, displayReadTargets }).content(content).done();
964
+ }
965
+
966
+ /**
967
+ * Memoized {@link findUniqueSuffixMatch} for a single read call. A missing
968
+ * path with archive/sqlite extensions probes the workspace once per stage
969
+ * (archive candidates, sqlite candidates, plain path) — each glob carries a
970
+ * 5s timeout, so repeated lookups of the same string stack into a long
971
+ * stall before erroring. The cache collapses repeats within one execute().
972
+ */
973
+ async #findSuffixMatchCached(
974
+ cache: SuffixMatchCache,
975
+ rawPath: string,
976
+ signal?: AbortSignal,
977
+ ): Promise<{ absolutePath: string; displayPath: string } | null> {
978
+ const hit = cache.get(rawPath);
979
+ if (hit !== undefined) return hit;
980
+ const result = await findUniqueSuffixMatch(rawPath, this.session.cwd, signal);
981
+ cache.set(rawPath, result);
982
+ return result;
983
+ }
984
+
985
+ async #resolveArchiveReadPath(
986
+ readPath: string,
987
+ suffixCache: SuffixMatchCache,
988
+ signal?: AbortSignal,
989
+ ): Promise<ResolvedArchiveReadPath | null> {
990
+ const candidates = parseArchivePathCandidates(readPath);
991
+ for (const candidate of candidates) {
992
+ let absolutePath = resolveReadPath(candidate.archivePath, this.session.cwd);
993
+ let suffixResolution: { from: string; to: string } | undefined;
994
+
995
+ try {
996
+ const stat = await Bun.file(absolutePath).stat();
997
+ if (stat.isDirectory()) continue;
998
+ return {
999
+ absolutePath,
1000
+ archiveSubPath: candidate.archivePath === readPath ? "" : candidate.subPath,
1001
+ suffixResolution,
1002
+ };
1003
+ } catch (error) {
1004
+ if (!isNotFoundError(error) || isRemoteMountPath(absolutePath)) continue;
1005
+
1006
+ const suffixMatch = await this.#findSuffixMatchCached(suffixCache, candidate.archivePath, signal);
1007
+ if (!suffixMatch) continue;
1008
+
1009
+ try {
1010
+ const retryStat = await Bun.file(suffixMatch.absolutePath).stat();
1011
+ if (retryStat.isDirectory()) continue;
1012
+
1013
+ absolutePath = suffixMatch.absolutePath;
1014
+ suffixResolution = { from: candidate.archivePath, to: suffixMatch.displayPath };
1015
+ return {
1016
+ absolutePath,
1017
+ archiveSubPath: candidate.archivePath === readPath ? "" : candidate.subPath,
1018
+ suffixResolution,
1019
+ };
1020
+ } catch (retryError) {
1021
+ if (!isNotFoundError(retryError)) {
1022
+ throw retryError;
1023
+ }
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ return null;
1029
+ }
1030
+
1031
+ async #resolveSqliteReadPath(
1032
+ readPath: string,
1033
+ suffixCache: SuffixMatchCache,
1034
+ signal?: AbortSignal,
1035
+ ): Promise<ResolvedSqliteReadPath | null> {
1036
+ const candidates = parseSqlitePathCandidates(readPath);
1037
+ for (const candidate of candidates) {
1038
+ let absolutePath = resolveReadPath(candidate.sqlitePath, this.session.cwd);
1039
+ let suffixResolution: { from: string; to: string } | undefined;
1040
+
1041
+ try {
1042
+ const stat = await Bun.file(absolutePath).stat();
1043
+ if (stat.isDirectory()) continue;
1044
+ if (!(await isSqliteFile(absolutePath))) continue;
1045
+
1046
+ return {
1047
+ absolutePath,
1048
+ sqliteSubPath: candidate.subPath,
1049
+ queryString: candidate.queryString,
1050
+ suffixResolution,
1051
+ };
1052
+ } catch (error) {
1053
+ if (!isNotFoundError(error) || isRemoteMountPath(absolutePath)) continue;
1054
+
1055
+ const suffixMatch = await this.#findSuffixMatchCached(suffixCache, candidate.sqlitePath, signal);
1056
+ if (!suffixMatch) continue;
1057
+
1058
+ try {
1059
+ const retryStat = await Bun.file(suffixMatch.absolutePath).stat();
1060
+ if (retryStat.isDirectory()) continue;
1061
+ if (!(await isSqliteFile(suffixMatch.absolutePath))) continue;
1062
+
1063
+ absolutePath = suffixMatch.absolutePath;
1064
+ suffixResolution = { from: candidate.sqlitePath, to: suffixMatch.displayPath };
1065
+ return {
1066
+ absolutePath,
1067
+ sqliteSubPath: candidate.subPath,
1068
+ queryString: candidate.queryString,
1069
+ suffixResolution,
1070
+ };
1071
+ } catch (retryError) {
1072
+ if (!isNotFoundError(retryError)) {
1073
+ throw retryError;
1074
+ }
1075
+ }
1076
+ }
1077
+ }
1078
+
1079
+ return null;
1080
+ }
1081
+
1082
+ #pdfImageCacheDir(absolutePdfPath: string): string {
1083
+ const artifactsDir = this.session.getArtifactsDir?.();
1084
+ let root = artifactsDir ?? undefined;
1085
+ if (root === undefined) {
1086
+ const sessionFile = this.session.getSessionFile();
1087
+ root = sessionFile?.endsWith(".jsonl")
1088
+ ? sessionFile.slice(0, -6)
1089
+ : path.join(os.tmpdir(), "omp-read-pdf-images");
1090
+ }
1091
+ const basename = path.basename(absolutePdfPath).replace(/[^A-Za-z0-9._-]/g, "_");
1092
+ return path.join(root, "read-pdf-images", `${basename}-${Bun.hash(absolutePdfPath).toString(36)}`);
1093
+ }
1094
+
1095
+ async #listPdfImageMembers(imageDir: string): Promise<string[]> {
1096
+ try {
1097
+ const entries = await fs.readdir(imageDir, { withFileTypes: true });
1098
+ const members: string[] = [];
1099
+ for (const entry of entries) {
1100
+ if (entry.isFile() && PDF_IMAGE_MEMBER_EXTENSION_RE.test(entry.name)) members.push(entry.name);
1101
+ }
1102
+ return members.sort();
1103
+ } catch (error) {
1104
+ if (isNotFoundError(error)) return [];
1105
+ throw error;
1106
+ }
1107
+ }
1108
+
1109
+ async #ensurePdfImageCache(absolutePdfPath: string, signal?: AbortSignal): Promise<string> {
1110
+ const imageDir = this.#pdfImageCacheDir(absolutePdfPath);
1111
+ const markerPath = path.join(imageDir, ".extracted");
1112
+ try {
1113
+ await fs.stat(markerPath);
1114
+ return imageDir;
1115
+ } catch (error) {
1116
+ if (!isNotFoundError(error)) throw error;
1117
+ }
1118
+
1119
+ await fs.rm(imageDir, { recursive: true, force: true });
1120
+ await fs.mkdir(imageDir, { recursive: true });
1121
+ const result = await convertFileWithMarkit(absolutePdfPath, signal, { imageDir });
1122
+ if (!result.ok) {
1123
+ await fs.rm(imageDir, { recursive: true, force: true });
1124
+ throw new ToolError(`Cannot extract images from PDF: ${result.error ?? "conversion failed"}`);
1125
+ }
1126
+ await Bun.write(markerPath, "ok");
1127
+ return imageDir;
1128
+ }
1129
+
1130
+ async #readPdfImageMember(
1131
+ absolutePdfPath: string,
1132
+ pdfDisplayPath: string,
1133
+ member: string,
1134
+ suffixResolution: { from: string; to: string } | undefined,
1135
+ signal?: AbortSignal,
1136
+ ): Promise<AgentToolResult<ReadToolDetails>> {
1137
+ const imageDir = await this.#ensurePdfImageCache(absolutePdfPath, signal);
1138
+ const members = await this.#listPdfImageMembers(imageDir);
1139
+ if (member.length === 0) {
1140
+ const text =
1141
+ members.length === 0
1142
+ ? "No extractable PDF image members found."
1143
+ : `Extractable PDF image members:\n${members
1144
+ .map(imageMember => `- read \`${pdfDisplayPath}:${imageMember}\``)
1145
+ .join("\n")}`;
1146
+ return toolResult<ReadToolDetails>({ resolvedPath: absolutePdfPath, suffixResolution })
1147
+ .text(prependSuffixResolutionNotice(text, suffixResolution))
1148
+ .sourcePath(absolutePdfPath)
1149
+ .done();
1150
+ }
1151
+
1152
+ if (!members.includes(member)) {
1153
+ const available = members.length === 0 ? "(none)" : members.join(", ");
1154
+ throw new ToolError(`PDF image member '${member}' not found. Available members: ${available}`);
1155
+ }
1156
+
1157
+ const imagePath = path.join(imageDir, member);
1158
+ const imageStat = await Bun.file(imagePath).stat();
1159
+ if (imageStat.size > MAX_IMAGE_SIZE) {
1160
+ const sizeStr = formatBytes(imageStat.size);
1161
+ const maxStr = formatBytes(MAX_IMAGE_SIZE);
1162
+ throw new ToolError(`Image file too large: ${sizeStr} exceeds ${maxStr} limit.`);
1163
+ }
1164
+ const metadata = await readImageMetadata(imagePath);
1165
+ const mimeType = metadata?.mimeType;
1166
+ if (!mimeType) throw new ToolError(`PDF image member '${member}' is not a supported image.`);
1167
+ const imageInput = await loadImageInput({
1168
+ path: `${pdfDisplayPath}:${member}`,
1169
+ cwd: this.session.cwd,
1170
+ autoResize: this.#autoResizeImages,
1171
+ maxBytes: MAX_IMAGE_SIZE,
1172
+ resolvedPath: imagePath,
1173
+ detectedMimeType: mimeType,
1174
+ excludeWebP: webpExclusionForModel(this.session.getActiveModel?.()),
1175
+ });
1176
+ if (!imageInput) {
1177
+ throw new ToolError(`Read image file [${mimeType}] failed: unsupported image format.`);
1178
+ }
1179
+ const textNote = prependSuffixResolutionNotice(imageInput.textNote, suffixResolution);
1180
+ return toolResult<ReadToolDetails>({ resolvedPath: absolutePdfPath, suffixResolution })
1181
+ .content([
1182
+ { type: "text", text: textNote },
1183
+ { type: "image", data: imageInput.data, mimeType: imageInput.mimeType },
1184
+ ])
1185
+ .sourcePath(imageInput.resolvedPath)
1186
+ .done();
1187
+ }
1188
+
1189
+ /**
1190
+ * Build content blocks for an on-disk image file: an `inspect_image`
1191
+ * metadata note when inspection is enabled, otherwise the decoded image
1192
+ * block. Shared by the plain-file read path and the `local://` image fast
1193
+ * path so both honor `inspect_image.enabled`, the size cap, and auto-resize
1194
+ * identically. Too-large / unsupported images surface as {@link ToolError}.
1195
+ */
1196
+ async #loadImageContent(options: {
1197
+ readPath: string;
1198
+ absolutePath: string;
1199
+ mimeType: string;
1200
+ imageMetadata: ImageMetadata | null;
1201
+ fileSize: number;
1202
+ }): Promise<{ content: Array<TextContent | ImageContent>; details: ReadToolDetails; sourcePath: string }> {
1203
+ const { readPath, absolutePath, mimeType, imageMetadata, fileSize } = options;
1204
+ if (this.#inspectImageEnabled) {
1205
+ const outputMime = imageMetadata?.mimeType ?? mimeType;
1206
+ const metadataLines = [
1207
+ "Image metadata:",
1208
+ `- MIME: ${outputMime}`,
1209
+ `- Bytes: ${fileSize} (${formatBytes(fileSize)})`,
1210
+ imageMetadata?.width !== undefined && imageMetadata.height !== undefined
1211
+ ? `- Dimensions: ${imageMetadata.width}x${imageMetadata.height}`
1212
+ : "- Dimensions: unknown",
1213
+ imageMetadata?.channels !== undefined ? `- Channels: ${imageMetadata.channels}` : "- Channels: unknown",
1214
+ imageMetadata?.hasAlpha === true
1215
+ ? "- Alpha: yes"
1216
+ : imageMetadata?.hasAlpha === false
1217
+ ? "- Alpha: no"
1218
+ : "- Alpha: unknown",
1219
+ "",
1220
+ `If you want to analyze the image, call inspect_image with path="${formatPathRelativeToCwd(
1221
+ absolutePath,
1222
+ this.session.cwd,
1223
+ )}" and a question describing what to inspect and the desired output format.`,
1224
+ ];
1225
+ return { content: [{ type: "text", text: metadataLines.join("\n") }], details: {}, sourcePath: absolutePath };
1226
+ }
1227
+
1228
+ if (fileSize > MAX_IMAGE_SIZE) {
1229
+ const sizeStr = formatBytes(fileSize);
1230
+ const maxStr = formatBytes(MAX_IMAGE_SIZE);
1231
+ throw new ToolError(`Image file too large: ${sizeStr} exceeds ${maxStr} limit.`);
1232
+ }
1233
+ try {
1234
+ const imageInput = await loadImageInput({
1235
+ path: readPath,
1236
+ cwd: this.session.cwd,
1237
+ autoResize: this.#autoResizeImages,
1238
+ maxBytes: MAX_IMAGE_SIZE,
1239
+ resolvedPath: absolutePath,
1240
+ detectedMimeType: mimeType,
1241
+ excludeWebP: webpExclusionForModel(this.session.getActiveModel?.()),
1242
+ });
1243
+ if (!imageInput) {
1244
+ throw new ToolError(`Read image file [${mimeType}] failed: unsupported image format.`);
1245
+ }
1246
+ return {
1247
+ content: [
1248
+ { type: "text", text: imageInput.textNote },
1249
+ { type: "image", data: imageInput.data, mimeType: imageInput.mimeType },
1250
+ ],
1251
+ details: {},
1252
+ sourcePath: imageInput.resolvedPath,
1253
+ };
1254
+ } catch (error) {
1255
+ if (error instanceof ImageInputTooLargeError) {
1256
+ throw new ToolError(error.message);
1257
+ }
1258
+ throw error;
1259
+ }
1260
+ }
1261
+
1262
+ #buildInMemoryTextResult(
1263
+ text: string,
1264
+ offset: number | undefined,
1265
+ limit: number | undefined,
1266
+ options: {
1267
+ details?: ReadToolDetails;
1268
+ sourcePath?: string;
1269
+ sourceUrl?: string;
1270
+ sourceInternal?: string;
1271
+ entityLabel: string;
1272
+ ignoreResultLimits?: boolean;
1273
+ raw?: boolean;
1274
+ immutable?: boolean;
1275
+ },
1276
+ ): AgentToolResult<ReadToolDetails> {
1277
+ const displayMode = resolveFileDisplayMode(this.session, { raw: options.raw, immutable: options.immutable });
1278
+ const details = options.details ?? {};
1279
+ const allLines = text.split("\n");
1280
+ const totalLines = allLines.length;
1281
+ // User-requested 0-indexed range start. Lines BEFORE this are leading
1282
+ // context (added below if offset is explicit).
1283
+ const requestedStart = offset ? Math.max(0, offset - 1) : 0;
1284
+ const ignoreResultLimits = options.ignoreResultLimits ?? false;
1285
+ const requestedEnd = limit !== undefined ? Math.min(requestedStart + limit, allLines.length) : allLines.length;
1286
+ // Expand only on sides the user actually constrained: leading context
1287
+ // when offset>1, trailing context when a finite limit was set.
1288
+ const expanded = expandRangeWithContext(
1289
+ requestedStart,
1290
+ requestedEnd,
1291
+ allLines.length,
1292
+ offset !== undefined && offset > 1,
1293
+ limit !== undefined,
1294
+ );
1295
+ const startLine = expanded.startLine;
1296
+ const endLineExpanded = expanded.endLine;
1297
+ const startLineDisplay = startLine + 1;
1298
+
1299
+ const resultBuilder = toolResult(details);
1300
+ if (options.sourcePath) {
1301
+ resultBuilder.sourcePath(options.sourcePath);
1302
+ }
1303
+ if (options.sourceUrl) {
1304
+ resultBuilder.sourceUrl(options.sourceUrl);
1305
+ }
1306
+ if (options.sourceInternal) {
1307
+ resultBuilder.sourceInternal(options.sourceInternal);
1308
+ }
1309
+
1310
+ if (requestedStart >= allLines.length) {
1311
+ const suggestion =
1312
+ allLines.length === 0
1313
+ ? `The ${options.entityLabel} is empty.`
1314
+ : `Use :1 to read from the start, or :${allLines.length} to read the last line.`;
1315
+ return resultBuilder
1316
+ .text(
1317
+ `Line ${requestedStart + 1} is beyond end of ${options.entityLabel} (${allLines.length} lines total). ${suggestion}`,
1318
+ )
1319
+ .done();
1320
+ }
1321
+
1322
+ const endLine = endLineExpanded;
1323
+ const selectedContent = allLines.slice(startLine, endLine).join("\n");
1324
+ const userLimitedLines = limit !== undefined ? endLine - startLine : undefined;
1325
+ const truncation = ignoreResultLimits ? noTruncResult(selectedContent) : truncateHead(selectedContent);
1326
+
1327
+ const shouldAddHashLines = displayMode.hashLines;
1328
+ const shouldAddLineNumbers = shouldAddHashLines ? false : displayMode.lineNumbers;
1329
+ const hashContext =
1330
+ shouldAddHashLines && options.sourcePath
1331
+ ? recordFullHashlineContext(
1332
+ this.session,
1333
+ options.sourcePath,
1334
+ formatPathRelativeToCwd(options.sourcePath, this.session.cwd),
1335
+ text,
1336
+ )
1337
+ : undefined;
1338
+ let emittedHashlineHeader = false;
1339
+ let seenLines: number[] | undefined;
1340
+ let rawSeenLines: number[] | undefined;
1341
+ const formatText = (content: string, startNum: number): string => {
1342
+ const lineCount = countTextLines(content);
1343
+ details.displayContent = {
1344
+ text: content,
1345
+ startLine: startNum,
1346
+ lineNumbers: Array.from({ length: lineCount }, (_, i) => startNum + i),
1347
+ };
1348
+ if (shouldAddHashLines) seenLines = contiguousLineNumbers(startNum, lineCount);
1349
+ const formatted = formatTextWithMode(content, startNum, shouldAddHashLines, shouldAddLineNumbers);
1350
+ if (!hashContext || emittedHashlineHeader) return formatted;
1351
+ emittedHashlineHeader = true;
1352
+ return prependHashlineHeader(formatted, hashContext);
1353
+ };
1354
+ const formatLineEntries = (entries: readonly LineEntry[], startNum: number): string => {
1355
+ const firstLine = entries.find(entry => entry.kind === "line");
1356
+ details.displayContent = {
1357
+ text: lineEntriesToPlainText(entries, BRACKET_CONTEXT_ELLIPSIS),
1358
+ startLine: firstLine?.kind === "line" ? firstLine.lineNumber : startNum,
1359
+ lineNumbers: entries.map(entry => (entry.kind === "line" ? entry.lineNumber : null)),
1360
+ };
1361
+ if (shouldAddHashLines) seenLines = lineNumbersFromEntries(entries);
1362
+ const formatted = formatLineEntriesWithMode(entries, shouldAddHashLines, shouldAddLineNumbers);
1363
+ if (!hashContext || emittedHashlineHeader) return formatted;
1364
+ emittedHashlineHeader = true;
1365
+ return prependHashlineHeader(formatted, hashContext);
1366
+ };
1367
+ const buildLineEntries = (endLineDisplay: number): LineEntry[] =>
1368
+ buildLineEntriesWithBlockContext(allLines, [{ startLine: startLineDisplay, endLine: endLineDisplay }], {
1369
+ path: options.sourcePath,
1370
+ });
1371
+
1372
+ let outputText: string;
1373
+ let truncationInfo:
1374
+ | { result: TruncationResult; options: { direction: "head"; startLine?: number; totalFileLines?: number } }
1375
+ | undefined;
1376
+
1377
+ if (truncation.firstLineExceedsLimit) {
1378
+ const firstLine = allLines[startLine] ?? "";
1379
+ const firstLineBytes = Buffer.byteLength(firstLine, "utf-8");
1380
+ const snippet = truncateHeadBytes(firstLine, DEFAULT_MAX_BYTES);
1381
+
1382
+ if (shouldAddHashLines) {
1383
+ outputText = `[Line ${startLineDisplay} is ${formatBytes(
1384
+ firstLineBytes,
1385
+ )}, exceeds ${formatBytes(DEFAULT_MAX_BYTES)} limit. Hashline output requires full lines; cannot emit an editable numbered preview for a truncated line.]`;
1386
+ } else {
1387
+ outputText = formatText(snippet.text, startLineDisplay);
1388
+ }
1389
+
1390
+ if (snippet.text.length === 0) {
1391
+ outputText = `[Line ${startLineDisplay} is ${formatBytes(
1392
+ firstLineBytes,
1393
+ )}, exceeds ${formatBytes(DEFAULT_MAX_BYTES)} limit. Unable to display a valid UTF-8 snippet.]`;
1394
+ }
1395
+
1396
+ details.truncation = truncation;
1397
+ truncationInfo = {
1398
+ result: truncation,
1399
+ options: { direction: "head", startLine: startLineDisplay, totalFileLines: totalLines },
1400
+ };
1401
+ } else if (truncation.truncated) {
1402
+ const outputLines = truncation.outputLines ?? countTextLines(truncation.content);
1403
+ const endLineDisplay = startLineDisplay + Math.max(0, outputLines - 1);
1404
+ if (options.raw === true) {
1405
+ rawSeenLines = contiguousLineNumbers(startLineDisplay, outputLines);
1406
+ outputText = formatText(truncation.content, startLineDisplay);
1407
+ } else {
1408
+ outputText = formatLineEntries(buildLineEntries(endLineDisplay), startLineDisplay);
1409
+ }
1410
+ details.truncation = truncation;
1411
+ truncationInfo = {
1412
+ result: truncation,
1413
+ options: { direction: "head", startLine: startLineDisplay, totalFileLines: totalLines },
1414
+ };
1415
+ } else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {
1416
+ const remaining = allLines.length - (startLine + userLimitedLines);
1417
+ const nextOffset = startLine + userLimitedLines + 1;
1418
+
1419
+ if (options.raw === true) {
1420
+ rawSeenLines = contiguousLineNumbers(startLineDisplay, userLimitedLines);
1421
+ outputText = formatText(selectedContent, startLineDisplay);
1422
+ } else {
1423
+ outputText = formatLineEntries(buildLineEntries(endLine), startLineDisplay);
1424
+ }
1425
+ outputText += `\n\n[${remaining} more lines in ${options.entityLabel}. Use :${nextOffset} to continue]`;
1426
+ } else {
1427
+ if (options.raw === true) {
1428
+ rawSeenLines = contiguousLineNumbers(startLineDisplay, endLine - startLine);
1429
+ outputText = formatText(truncation.content, startLineDisplay);
1430
+ } else {
1431
+ outputText = formatLineEntries(buildLineEntries(endLine), startLineDisplay);
1432
+ }
1433
+ }
1434
+
1435
+ if (hashContext?.tag && options.sourcePath && seenLines) {
1436
+ recordSeenLines(this.session, options.sourcePath, hashContext.tag, seenLines);
1437
+ }
1438
+ if (options.raw === true && options.sourcePath && options.immutable !== true && rawSeenLines) {
1439
+ recordInMemorySeenLines(this.session, options.sourcePath, text, rawSeenLines);
1440
+ }
1441
+ resultBuilder.text(outputText);
1442
+ if (truncationInfo) {
1443
+ resultBuilder.truncation(truncationInfo.result, truncationInfo.options);
1444
+ }
1445
+ return resultBuilder.done();
1446
+ }
1447
+
1448
+ /**
1449
+ * Render a multi-range read against in-memory text. Each range emits a
1450
+ * formatted block with its own anchors / line numbers, blocks are joined
1451
+ * with an elision separator, and ranges past EOF surface as `[…]` notices
1452
+ * so the model can correct the next call. No leading/trailing context is
1453
+ * added — multi-range callers always specify exact bounds.
1454
+ */
1455
+ #buildInMemoryMultiRangeResult(
1456
+ text: string,
1457
+ ranges: readonly LineRange[],
1458
+ options: {
1459
+ details?: ReadToolDetails;
1460
+ sourcePath?: string;
1461
+ sourceUrl?: string;
1462
+ sourceInternal?: string;
1463
+ entityLabel: string;
1464
+ raw?: boolean;
1465
+ immutable?: boolean;
1466
+ },
1467
+ ): AgentToolResult<ReadToolDetails> {
1468
+ const displayMode = resolveFileDisplayMode(this.session, { raw: options.raw, immutable: options.immutable });
1469
+ const details = options.details ?? {};
1470
+ const allLines = text.split("\n");
1471
+ const totalLines = allLines.length;
1472
+ const shouldAddHashLines = displayMode.hashLines;
1473
+ const shouldAddLineNumbers = shouldAddHashLines ? false : displayMode.lineNumbers;
1474
+ const hashContext =
1475
+ shouldAddHashLines && options.sourcePath
1476
+ ? recordFullHashlineContext(
1477
+ this.session,
1478
+ options.sourcePath,
1479
+ formatPathRelativeToCwd(options.sourcePath, this.session.cwd),
1480
+ text,
1481
+ )
1482
+ : undefined;
1483
+ let emittedHashlineHeader = false;
1484
+
1485
+ let seenLines: number[] | undefined;
1486
+ const resultBuilder = toolResult(details);
1487
+ if (options.sourcePath) resultBuilder.sourcePath(options.sourcePath);
1488
+ if (options.sourceUrl) resultBuilder.sourceUrl(options.sourceUrl);
1489
+ if (options.sourceInternal) resultBuilder.sourceInternal(options.sourceInternal);
1490
+
1491
+ const outOfBounds: LineRange[] = [];
1492
+ const visibleSpans: Array<{ startLine: number; endLine: number }> = [];
1493
+ const rawParts: string[] = [];
1494
+ for (const range of ranges) {
1495
+ if (range.startLine > totalLines) {
1496
+ outOfBounds.push(range);
1497
+ continue;
1498
+ }
1499
+ const effectiveEnd = Math.min(range.endLine ?? totalLines, totalLines);
1500
+ visibleSpans.push({ startLine: range.startLine, endLine: effectiveEnd });
1501
+ if (options.raw === true) {
1502
+ rawParts.push(allLines.slice(range.startLine - 1, effectiveEnd).join("\n"));
1503
+ }
1504
+ }
1505
+
1506
+ let outputText = "";
1507
+ if (options.raw === true) {
1508
+ outputText = rawParts.length > 0 ? rawParts.join("\n\n…\n\n") : "";
1509
+ } else if (visibleSpans.length > 0) {
1510
+ const entries = buildLineEntriesWithBlockContext(allLines, visibleSpans, { path: options.sourcePath });
1511
+ if (shouldAddHashLines) seenLines = lineNumbersFromEntries(entries);
1512
+ const firstLine = entries.find(entry => entry.kind === "line");
1513
+ if (firstLine?.kind === "line") {
1514
+ details.displayContent = {
1515
+ text: lineEntriesToPlainText(entries, BRACKET_CONTEXT_ELLIPSIS),
1516
+ startLine: firstLine.lineNumber,
1517
+ lineNumbers: entries.map(entry => (entry.kind === "line" ? entry.lineNumber : null)),
1518
+ };
1519
+ }
1520
+ const formatted = formatLineEntriesWithMode(entries, shouldAddHashLines, shouldAddLineNumbers);
1521
+ outputText = hashContext && !emittedHashlineHeader ? prependHashlineHeader(formatted, hashContext) : formatted;
1522
+ if (hashContext) emittedHashlineHeader = true;
1523
+ }
1524
+ const notices: string[] = [];
1525
+ for (const range of outOfBounds) {
1526
+ const bound = range.endLine !== undefined ? `${range.startLine}-${range.endLine}` : `${range.startLine}`;
1527
+ notices.push(`[Range ${bound} is beyond end of ${options.entityLabel} (${totalLines} lines total); skipped]`);
1528
+ }
1529
+ const finalText =
1530
+ notices.length > 0 ? (outputText ? `${outputText}\n${notices.join("\n")}` : notices.join("\n")) : outputText;
1531
+ if (hashContext?.tag && options.sourcePath && seenLines) {
1532
+ recordSeenLines(this.session, options.sourcePath, hashContext.tag, seenLines);
1533
+ }
1534
+ if (options.raw === true && options.sourcePath && options.immutable !== true && visibleSpans.length > 0) {
1535
+ recordInMemorySeenLines(this.session, options.sourcePath, text, lineNumbersFromSpans(visibleSpans));
1536
+ }
1537
+ resultBuilder.text(finalText);
1538
+ return resultBuilder.done();
1539
+ }
1540
+
1541
+ /**
1542
+ * Stream multiple non-contiguous ranges from a local file. ACP bridge takes
1543
+ * priority when present (editor buffer is source of truth); otherwise each
1544
+ * range is streamed independently with its own line/byte budget. Out-of-bounds
1545
+ * ranges surface as inline notices rather than aborting the read.
1546
+ */
1547
+ async #readLocalFileMultiRange(
1548
+ absolutePath: string,
1549
+ ranges: readonly LineRange[],
1550
+ fileSize: number,
1551
+ parsed: ParsedSelector,
1552
+ displayMode: { hashLines: boolean; lineNumbers: boolean },
1553
+ suffixResolution: { from: string; to: string } | undefined,
1554
+ signal: AbortSignal | undefined,
1555
+ allowBridge = true,
1556
+ ): Promise<{
1557
+ outputText: string;
1558
+ columnTruncated: number;
1559
+ displayContent?: { text: string; startLine: number; lineNumbers?: Array<number | null> };
1560
+ bridgeResult?: AgentToolResult<ReadToolDetails>;
1561
+ }> {
1562
+ const rawSelector = isRawSelector(parsed);
1563
+
1564
+ // ACP bridge first — the editor's in-memory buffer is source of truth.
1565
+ const bridgePromise = allowBridge ? this.#routeReadThroughBridge(absolutePath) : undefined;
1566
+ if (bridgePromise !== undefined) {
1567
+ try {
1568
+ const bridgeText = await bridgePromise;
1569
+ const bridgeResult = this.#buildInMemoryMultiRangeResult(bridgeText, ranges, {
1570
+ details: { resolvedPath: absolutePath, suffixResolution },
1571
+ sourcePath: absolutePath,
1572
+ entityLabel: "file",
1573
+ raw: rawSelector,
1574
+ });
1575
+ if (suffixResolution) {
1576
+ const notice = `[Path '${suffixResolution.from}' not found; resolved to '${suffixResolution.to}' via suffix match]`;
1577
+ const firstText = bridgeResult.content.find((c): c is TextContent => c.type === "text");
1578
+ if (firstText) firstText.text = `${notice}\n${firstText.text}`;
1579
+ }
1580
+ return { outputText: "", columnTruncated: 0, bridgeResult };
1581
+ } catch (error) {
1582
+ logger.warn("ACP fs readTextFile failed; falling back to disk", { path: absolutePath, error });
1583
+ }
1584
+ }
1585
+
1586
+ const shouldAddHashLines = !rawSelector && displayMode.hashLines;
1587
+ const shouldAddLineNumbers = rawSelector ? false : shouldAddHashLines ? false : displayMode.lineNumbers;
1588
+ const maxColumns = resolveOutputMaxColumns(this.session.settings);
1589
+
1590
+ const blocks: string[] = [];
1591
+ const notices: string[] = [];
1592
+ const visibleSpans: Array<{ startLine: number; endLine: number }> = [];
1593
+ const displayLineByNumber = new Map<number, string>();
1594
+ const fullLines = rawSelector ? undefined : await readBracketContextFullLines(absolutePath, fileSize);
1595
+ let columnTruncated = 0;
1596
+ const clippedLines = new Set<number>();
1597
+ let displayContent: { text: string; startLine: number; lineNumbers?: Array<number | null> } | undefined;
1598
+
1599
+ for (const range of ranges) {
1600
+ const rangeStart = range.startLine - 1; // 0-indexed
1601
+ const requestedLength = range.endLine !== undefined ? range.endLine - range.startLine + 1 : this.#defaultLimit;
1602
+ const maxLines = Math.min(requestedLength, DEFAULT_MAX_LINES);
1603
+
1604
+ // When the full file is already in memory (the common case for files
1605
+ // within the snapshot byte cap), slice ranges from it instead of
1606
+ // re-streaming the file once per range.
1607
+ let collectedLines: string[];
1608
+ let totalFileLines: number;
1609
+ if (fullLines) {
1610
+ totalFileLines = fullLines.length;
1611
+ collectedLines = fullLines.slice(rangeStart, rangeStart + maxLines);
1612
+ } else {
1613
+ const maxBytesForRead = Math.max(DEFAULT_MAX_BYTES, maxLines * 512);
1614
+ const streamResult = await streamLinesFromFile(
1615
+ absolutePath,
1616
+ rangeStart,
1617
+ maxLines,
1618
+ maxBytesForRead,
1619
+ maxLines,
1620
+ signal,
1621
+ fileSize > SNAPSHOT_MAX_BYTES, // giant file: collected ranges don't need an exact EOF line count
1622
+ );
1623
+ totalFileLines = streamResult.totalFileLines;
1624
+ collectedLines = streamResult.lines;
1625
+ }
1626
+
1627
+ if (rangeStart >= totalFileLines) {
1628
+ const bound = range.endLine !== undefined ? `${range.startLine}-${range.endLine}` : `${range.startLine}`;
1629
+ notices.push(`[Range ${bound} is beyond end of file (${totalFileLines} lines total); skipped]`);
1630
+ continue;
1631
+ }
1632
+
1633
+ // Column truncation is display-only; clone before stamping ellipsis so
1634
+ // the original on-disk lines stay intact for display reconstruction.
1635
+ let displayLines: string[] = collectedLines;
1636
+ if (!rawSelector && maxColumns > 0) {
1637
+ let cloned: string[] | undefined;
1638
+ for (let i = 0; i < collectedLines.length; i++) {
1639
+ const { text, wasTruncated } = truncateLine(collectedLines[i], maxColumns);
1640
+ if (wasTruncated) {
1641
+ if (!cloned) cloned = collectedLines.slice();
1642
+ cloned[i] = text;
1643
+ columnTruncated = maxColumns;
1644
+ clippedLines.add(range.startLine + i);
1645
+ }
1646
+ }
1647
+ if (cloned) displayLines = cloned;
1648
+ }
1649
+ if (displayLines.length > 0) {
1650
+ const endLine = range.startLine + displayLines.length - 1;
1651
+ visibleSpans.push({ startLine: range.startLine, endLine });
1652
+ for (let i = 0; i < displayLines.length; i++) {
1653
+ displayLineByNumber.set(range.startLine + i, displayLines[i] ?? "");
1654
+ }
1655
+ if (!fullLines || rawSelector) {
1656
+ const blockText = displayLines.join("\n");
1657
+ blocks.push(formatTextWithMode(blockText, range.startLine, shouldAddHashLines, shouldAddLineNumbers));
1658
+ }
1659
+ }
1660
+ }
1661
+
1662
+ let outputText: string;
1663
+ if (!rawSelector && fullLines && visibleSpans.length > 0) {
1664
+ const entries = buildLineEntriesWithBlockContext(
1665
+ fullLines,
1666
+ visibleSpans,
1667
+ { path: absolutePath },
1668
+ {
1669
+ lineText: (lineNumber, sourceText) => {
1670
+ const visibleText = displayLineByNumber.get(lineNumber);
1671
+ if (visibleText !== undefined) return visibleText;
1672
+ if (maxColumns <= 0) return sourceText;
1673
+ const truncated = truncateLine(sourceText, maxColumns);
1674
+ if (truncated.wasTruncated) {
1675
+ columnTruncated = maxColumns;
1676
+ clippedLines.add(lineNumber);
1677
+ }
1678
+ return truncated.text;
1679
+ },
1680
+ },
1681
+ );
1682
+ const firstLine = entries.find(entry => entry.kind === "line");
1683
+ displayContent = {
1684
+ text: lineEntriesToPlainText(entries, BRACKET_CONTEXT_ELLIPSIS),
1685
+ startLine: firstLine?.kind === "line" ? firstLine.lineNumber : (visibleSpans[0]?.startLine ?? 1),
1686
+ lineNumbers: entries.map(entry => (entry.kind === "line" ? entry.lineNumber : null)),
1687
+ };
1688
+ outputText = formatLineEntriesWithMode(entries, shouldAddHashLines, shouldAddLineNumbers);
1689
+ } else {
1690
+ outputText = blocks.join("\n\n…\n\n");
1691
+ }
1692
+ if (shouldAddHashLines && outputText) {
1693
+ const tag = await recordFileSnapshot(this.session, absolutePath);
1694
+ if (tag) {
1695
+ recordSeenLinesFromBody(this.session, absolutePath, tag, outputText, clippedLines);
1696
+ outputText = `${formatReadHashlineHeader(formatPathRelativeToCwd(absolutePath, this.session.cwd), tag)}\n${outputText}`;
1697
+ }
1698
+ } else if (rawSelector && visibleSpans.length > 0) {
1699
+ const rawSeenLines = lineNumbersFromSpans(visibleSpans);
1700
+ if (rawSeenLines.length > 0) await recordFileSnapshot(this.session, absolutePath, rawSeenLines);
1701
+ }
1702
+ if (notices.length > 0) {
1703
+ outputText = outputText ? `${outputText}\n${notices.join("\n")}` : notices.join("\n");
1704
+ }
1705
+ return { outputText, columnTruncated, displayContent };
1706
+ }
1707
+
1708
+ async #readArchiveDirectory(
1709
+ archive: ArchiveReader,
1710
+ archivePath: string,
1711
+ subPath: string,
1712
+ offset: number | undefined,
1713
+ limit: number | undefined,
1714
+ details: ReadToolDetails,
1715
+ signal?: AbortSignal,
1716
+ ): Promise<AgentToolResult<ReadToolDetails>> {
1717
+ const DEFAULT_LIMIT = 500;
1718
+ const effectiveLimit = limit ?? DEFAULT_LIMIT;
1719
+ const allEntries = archive.listDirectory(subPath);
1720
+ // `offset` is 1-indexed (line-selector semantics): `a.zip:dir:50` starts
1721
+ // the listing at the 50th entry instead of being silently ignored.
1722
+ const entries = offset !== undefined && offset > 1 ? allEntries.slice(offset - 1) : allEntries;
1723
+
1724
+ const listLimit = applyListLimit(entries, { limit: effectiveLimit });
1725
+ const limitedEntries = listLimit.items;
1726
+ const limitMeta = listLimit.meta;
1727
+
1728
+ for (let index = 0; index < limitedEntries.length; index++) {
1729
+ throwIfAborted(signal);
1730
+ }
1731
+ const results = formatArchiveEntryLines(limitedEntries);
1732
+
1733
+ const output = results.length > 0 ? results.join("\n") : "(empty archive directory)";
1734
+ const text = prependSuffixResolutionNotice(output, details.suffixResolution);
1735
+ const truncation = truncateHead(text, { maxLines: Number.MAX_SAFE_INTEGER });
1736
+ const directoryDetails: ReadToolDetails = { ...details, isDirectory: true };
1737
+ const resultBuilder = toolResult<ReadToolDetails>(directoryDetails).text(truncation.content);
1738
+ resultBuilder.sourcePath(archivePath).limits({ resultLimit: limitMeta.resultLimit?.reached });
1739
+ if (truncation.truncated) {
1740
+ directoryDetails.truncation = truncation;
1741
+ resultBuilder.truncation(truncation, { direction: "head" });
1742
+ }
1743
+ return resultBuilder.done();
1744
+ }
1745
+
1746
+ async #readArchive(
1747
+ readPath: string,
1748
+ parsedSel: ParsedSelector,
1749
+ resolvedArchivePath: ResolvedArchiveReadPath,
1750
+ signal?: AbortSignal,
1751
+ ): Promise<AgentToolResult<ReadToolDetails>> {
1752
+ throwIfAborted(signal);
1753
+ const archive = await openArchive(resolvedArchivePath.absolutePath);
1754
+ throwIfAborted(signal);
1755
+
1756
+ const details: ReadToolDetails = {
1757
+ resolvedPath: resolvedArchivePath.absolutePath,
1758
+ suffixResolution: resolvedArchivePath.suffixResolution,
1759
+ };
1760
+
1761
+ let archiveSubPath = resolvedArchivePath.archiveSubPath;
1762
+ let sel = parsedSel;
1763
+ let node = archive.getNode(archiveSubPath);
1764
+ if (!node && archiveSubPath) {
1765
+ // `archive.zip:500` / `archive.zip:raw`: the whole subPath is a
1766
+ // selector on the archive root, not a member name. Member names take
1767
+ // precedence (getNode above); fall back to root + selector.
1768
+ const wholeSel = parseSel(archiveSubPath);
1769
+ if (wholeSel.kind !== "none") {
1770
+ node = archive.getNode("");
1771
+ archiveSubPath = "";
1772
+ sel = wholeSel;
1773
+ }
1774
+ }
1775
+ if (!node) {
1776
+ throw new ToolError(`Path '${readPath}' not found inside archive`);
1777
+ }
1778
+
1779
+ if (node.isDirectory) {
1780
+ if (isMultiRange(sel)) {
1781
+ throw new ToolError("Multi-range line selectors are not supported for archive directory listings.");
1782
+ }
1783
+ const { offset, limit } = selToOffsetLimit(sel);
1784
+ return this.#readArchiveDirectory(
1785
+ archive,
1786
+ resolvedArchivePath.absolutePath,
1787
+ archiveSubPath,
1788
+ offset,
1789
+ limit,
1790
+ details,
1791
+ signal,
1792
+ );
1793
+ }
1794
+
1795
+ const entry = await archive.readFile(archiveSubPath);
1796
+ const text = decodeUtf8Text(entry.bytes);
1797
+ if (text === null) {
1798
+ return toolResult<ReadToolDetails>(details)
1799
+ .text(
1800
+ prependSuffixResolutionNotice(
1801
+ `[Cannot read binary archive entry '${entry.path}' (${formatBytes(entry.size)})]`,
1802
+ resolvedArchivePath.suffixResolution,
1803
+ ),
1804
+ )
1805
+ .sourcePath(resolvedArchivePath.absolutePath)
1806
+ .done();
1807
+ }
1808
+
1809
+ // Archive members are immutable: there is no edit path for bytes inside
1810
+ // an archive, and a hashline tag keyed to the archive file would invite
1811
+ // (and fail) edits while clobbering sibling members' snapshots.
1812
+ const raw = isRawSelector(sel);
1813
+ const result =
1814
+ isMultiRange(sel) && sel.kind === "lines"
1815
+ ? this.#buildInMemoryMultiRangeResult(text, sel.ranges, {
1816
+ details,
1817
+ sourcePath: resolvedArchivePath.absolutePath,
1818
+ entityLabel: "archive entry",
1819
+ raw,
1820
+ immutable: true,
1821
+ })
1822
+ : this.#buildInMemoryTextResult(text, selToOffsetLimit(sel).offset, selToOffsetLimit(sel).limit, {
1823
+ details,
1824
+ sourcePath: resolvedArchivePath.absolutePath,
1825
+ entityLabel: "archive entry",
1826
+ raw,
1827
+ immutable: true,
1828
+ });
1829
+ const firstText = result.content.find((content): content is TextContent => content.type === "text");
1830
+ if (firstText) {
1831
+ firstText.text = prependSuffixResolutionNotice(firstText.text, resolvedArchivePath.suffixResolution);
1832
+ }
1833
+ return result;
1834
+ }
1835
+
1836
+ async #readSqlite(
1837
+ resolvedSqlitePath: ResolvedSqliteReadPath,
1838
+ signal?: AbortSignal,
1839
+ ): Promise<AgentToolResult<ReadToolDetails>> {
1840
+ throwIfAborted(signal);
1841
+
1842
+ const selectorInput = {
1843
+ subPath: resolvedSqlitePath.sqliteSubPath,
1844
+ queryString: resolvedSqlitePath.queryString,
1845
+ };
1846
+ const selector = parseSqliteSelector(selectorInput.subPath, selectorInput.queryString);
1847
+ const details: ReadToolDetails = {
1848
+ resolvedPath: resolvedSqlitePath.absolutePath,
1849
+ suffixResolution: resolvedSqlitePath.suffixResolution,
1850
+ };
1851
+
1852
+ let db: Database | null = null;
1853
+ try {
1854
+ db = new Database(resolvedSqlitePath.absolutePath, { readonly: true, strict: true });
1855
+ db.run("PRAGMA busy_timeout = 3000");
1856
+ throwIfAborted(signal);
1857
+
1858
+ switch (selector.kind) {
1859
+ case "list": {
1860
+ const listLimit = applyListLimit(listTables(db), { limit: 500 });
1861
+ const output = prependSuffixResolutionNotice(
1862
+ renderTableList(listLimit.items),
1863
+ resolvedSqlitePath.suffixResolution,
1864
+ );
1865
+ const truncation = truncateHead(output, { maxLines: Number.MAX_SAFE_INTEGER });
1866
+ details.truncation = truncation.truncated ? truncation : undefined;
1867
+ const resultBuilder = toolResult<ReadToolDetails>(details)
1868
+ .text(truncation.content)
1869
+ .sourcePath(resolvedSqlitePath.absolutePath)
1870
+ .limits({ resultLimit: listLimit.meta.resultLimit?.reached });
1871
+ if (truncation.truncated) {
1872
+ resultBuilder.truncation(truncation, { direction: "head" });
1873
+ }
1874
+ return resultBuilder.done();
1875
+ }
1876
+ case "schema": {
1877
+ const sampleRows = queryRows(db, selector.table, { limit: selector.sampleLimit, offset: 0 });
1878
+ let output = renderSchema(getTableSchema(db, selector.table), {
1879
+ columns: sampleRows.columns,
1880
+ rows: sampleRows.rows,
1881
+ });
1882
+ if (sampleRows.rows.length < sampleRows.totalCount) {
1883
+ const remaining = sampleRows.totalCount - sampleRows.rows.length;
1884
+ output += `\n[${remaining} more rows; append :${selector.table}?limit=20&offset=${sampleRows.rows.length} to the database path to continue]`;
1885
+ }
1886
+ return toolResult<ReadToolDetails>(details)
1887
+ .text(prependSuffixResolutionNotice(output, resolvedSqlitePath.suffixResolution))
1888
+ .sourcePath(resolvedSqlitePath.absolutePath)
1889
+ .done();
1890
+ }
1891
+ case "row": {
1892
+ const lookup = resolveTableRowLookup(db, selector.table);
1893
+ const row =
1894
+ lookup.kind === "pk"
1895
+ ? getRowByKey(db, selector.table, lookup, selector.key)
1896
+ : getRowByRowId(db, selector.table, selector.key);
1897
+ if (!row) {
1898
+ return toolResult<ReadToolDetails>(details)
1899
+ .text(
1900
+ prependSuffixResolutionNotice(
1901
+ `No row found in table '${selector.table}' for key '${selector.key}'.`,
1902
+ resolvedSqlitePath.suffixResolution,
1903
+ ),
1904
+ )
1905
+ .sourcePath(resolvedSqlitePath.absolutePath)
1906
+ .done();
1907
+ }
1908
+ return toolResult<ReadToolDetails>(details)
1909
+ .text(prependSuffixResolutionNotice(renderRow(row), resolvedSqlitePath.suffixResolution))
1910
+ .sourcePath(resolvedSqlitePath.absolutePath)
1911
+ .done();
1912
+ }
1913
+ case "query": {
1914
+ const page = queryRows(db, selector.table, selector);
1915
+ return toolResult<ReadToolDetails>(details)
1916
+ .text(
1917
+ prependSuffixResolutionNotice(
1918
+ renderTable(page.columns, page.rows, {
1919
+ totalCount: page.totalCount,
1920
+ offset: selector.offset,
1921
+ limit: selector.limit,
1922
+ table: selector.table,
1923
+ dbPath: resolvedSqlitePath.absolutePath,
1924
+ }),
1925
+ resolvedSqlitePath.suffixResolution,
1926
+ ),
1927
+ )
1928
+ .sourcePath(resolvedSqlitePath.absolutePath)
1929
+ .done();
1930
+ }
1931
+ case "raw": {
1932
+ const result = executeReadQuery(db, selector.sql);
1933
+ let output = renderTable(result.columns, result.rows, {
1934
+ totalCount: result.rows.length,
1935
+ offset: 0,
1936
+ limit: result.rows.length || DEFAULT_MAX_LINES,
1937
+ table: "query",
1938
+ dbPath: resolvedSqlitePath.absolutePath,
1939
+ });
1940
+ if (result.truncated) {
1941
+ output += `\n[Output capped at ${MAX_RAW_QUERY_ROWS} rows; add a LIMIT/OFFSET clause to the query to page through more]`;
1942
+ }
1943
+ return toolResult<ReadToolDetails>(details)
1944
+ .text(prependSuffixResolutionNotice(output, resolvedSqlitePath.suffixResolution))
1945
+ .sourcePath(resolvedSqlitePath.absolutePath)
1946
+ .done();
1947
+ }
1948
+ }
1949
+
1950
+ throw new ToolError("Unsupported SQLite selector");
1951
+ } catch (error) {
1952
+ if (error instanceof ToolError) {
1953
+ throw error;
1954
+ }
1955
+ throw new ToolError(error instanceof Error ? error.message : String(error));
1956
+ } finally {
1957
+ db?.close();
1958
+ }
1959
+ }
1960
+
1961
+ #routeReadThroughBridge(
1962
+ absolutePath: string,
1963
+ options?: { line?: number; limit?: number },
1964
+ ): Promise<string> | undefined {
1965
+ const bridge = this.session.getClientBridge?.();
1966
+ if (!bridge?.capabilities.readTextFile || !bridge.readTextFile) return undefined;
1967
+ return bridge.readTextFile({ path: absolutePath, ...options });
1968
+ }
1969
+
1970
+ async #trySummarize(absolutePath: string, fileSize: number, signal?: AbortSignal): Promise<SummaryResult | null> {
1971
+ if (fileSize > MAX_SUMMARY_BYTES) return null;
1972
+
1973
+ try {
1974
+ throwIfAborted(signal);
1975
+ const bridgePromise = this.#routeReadThroughBridge(absolutePath);
1976
+ const code =
1977
+ bridgePromise !== undefined
1978
+ ? await bridgePromise.catch(() => Bun.file(absolutePath).text())
1979
+ : await Bun.file(absolutePath).text();
1980
+ throwIfAborted(signal);
1981
+ const lineCount = countTextLines(code);
1982
+ if (lineCount > MAX_SUMMARY_LINES) return null;
1983
+ if (lineCount < this.session.settings.get("read.summarize.minTotalLines")) return null;
1984
+
1985
+ const minBodyLines = this.session.settings.get("read.summarize.minBodyLines");
1986
+ const minCommentLines = this.session.settings.get("read.summarize.minCommentLines");
1987
+ const unfoldUntilLines = this.session.settings.get("read.summarize.unfoldUntil");
1988
+ const unfoldLimitLines = this.session.settings.get("read.summarize.unfoldLimit");
1989
+ const cache = getSummaryParseCache(this.session);
1990
+ const cacheKey = `${absolutePath}\0${Bun.hash(code)}\0${minBodyLines},${minCommentLines},${unfoldUntilLines},${unfoldLimitLines}`;
1991
+ const memoized = cache.get(cacheKey);
1992
+ if (memoized !== undefined) return memoized || null;
1993
+ const result = summarizeCode({
1994
+ code,
1995
+ path: absolutePath,
1996
+ minBodyLines,
1997
+ minCommentLines,
1998
+ unfoldUntilLines,
1999
+ unfoldLimitLines,
2000
+ });
2001
+ const usable = result.parsed && result.elided ? result : false;
2002
+ cache.set(cacheKey, usable);
2003
+ return usable || null;
2004
+ } catch {
2005
+ return null;
2006
+ }
2007
+ }
2008
+
2009
+ #renderSummary(summary: SummaryResult): {
2010
+ text: string;
2011
+ displayText: string;
2012
+ elidedRanges: ElidedRange[];
2013
+ elidedLines: number;
2014
+ } {
2015
+ const displayMode = resolveFileDisplayMode(this.session);
2016
+ const shouldAddHashLines = displayMode.hashLines;
2017
+ const shouldAddLineNumbers = shouldAddHashLines ? false : displayMode.lineNumbers;
2018
+
2019
+ // Flatten segments into per-line units so we can merge a kept-head /
2020
+ // elided / kept-tail sandwich into a single brace-pair line when the
2021
+ // boundary lines look like `… {` and `}` (or matching variants).
2022
+ type Unit =
2023
+ | { kind: "line"; line: number; text: string }
2024
+ | { kind: "elided"; startLine: number; endLine: number }
2025
+ | {
2026
+ kind: "merged";
2027
+ startLine: number;
2028
+ endLine: number;
2029
+ headText: string;
2030
+ tailText: string;
2031
+ };
2032
+
2033
+ const raw: Unit[] = [];
2034
+ for (const segment of summary.segments) {
2035
+ if (segment.kind === "elided") {
2036
+ raw.push({ kind: "elided", startLine: segment.startLine, endLine: segment.endLine });
2037
+ continue;
2038
+ }
2039
+ const text = segment.text ?? "";
2040
+ if (text.length === 0) continue;
2041
+ const lines = text.split("\n");
2042
+ for (let i = 0; i < lines.length; i++) {
2043
+ raw.push({ kind: "line", line: segment.startLine + i, text: lines[i] });
2044
+ }
2045
+ }
2046
+
2047
+ const units: Unit[] = [];
2048
+ let i = 0;
2049
+ while (i < raw.length) {
2050
+ const cur = raw[i];
2051
+ if (cur.kind === "elided") {
2052
+ const prev = units.length > 0 ? units[units.length - 1] : null;
2053
+ const next = i + 1 < raw.length ? raw[i + 1] : null;
2054
+ if (prev?.kind === "line" && next?.kind === "line" && canMergeBracePair(prev.text, next.text)) {
2055
+ units.pop();
2056
+ units.push({
2057
+ kind: "merged",
2058
+ startLine: prev.line,
2059
+ endLine: next.line,
2060
+ headText: prev.text,
2061
+ tailText: next.text,
2062
+ });
2063
+ i += 2;
2064
+ continue;
2065
+ }
2066
+ }
2067
+ units.push(cur);
2068
+ i++;
2069
+ }
2070
+
2071
+ const modelParts: string[] = [];
2072
+ const displayParts: string[] = [];
2073
+ const elidedRanges: ElidedRange[] = [];
2074
+ let elidedLines = 0;
2075
+ for (const unit of units) {
2076
+ if (unit.kind === "elided") {
2077
+ modelParts.push("…");
2078
+ displayParts.push("…");
2079
+ elidedRanges.push({ start: unit.startLine, end: unit.endLine });
2080
+ elidedLines += unit.endLine - unit.startLine + 1;
2081
+ continue;
2082
+ }
2083
+ if (unit.kind === "merged") {
2084
+ const formatted = formatMergedBraceLine(
2085
+ unit.startLine,
2086
+ unit.endLine,
2087
+ unit.headText,
2088
+ unit.tailText,
2089
+ shouldAddHashLines,
2090
+ shouldAddLineNumbers,
2091
+ );
2092
+ modelParts.push(formatted.model);
2093
+ displayParts.push(formatted.display);
2094
+ // Suggest the full brace range so re-reading shows both braces
2095
+ // plus the elided body in one shot.
2096
+ elidedRanges.push({ start: unit.startLine, end: unit.endLine });
2097
+ // Merged brace pair encloses (start+1)..(end-1) as elided.
2098
+ elidedLines += Math.max(0, unit.endLine - unit.startLine - 1);
2099
+ continue;
2100
+ }
2101
+ modelParts.push(formatSingleLine(unit.line, unit.text, shouldAddHashLines, shouldAddLineNumbers));
2102
+ displayParts.push(unit.text);
2103
+ }
2104
+
2105
+ return { text: modelParts.join("\n"), displayText: displayParts.join("\n"), elidedRanges, elidedLines };
2106
+ }
2107
+
2108
+ async execute(
2109
+ _toolCallId: string,
2110
+ params: ReadParams,
2111
+ signal?: AbortSignal,
2112
+ _onUpdate?: AgentToolUpdateCallback<ReadToolDetails>,
2113
+ _toolContext?: AgentToolContext,
2114
+ ): Promise<AgentToolResult<ReadToolDetails>> {
2115
+ let { path: readPath } = params;
2116
+ if (readPath.startsWith("file://")) {
2117
+ readPath = expandPath(readPath);
2118
+ }
2119
+
2120
+ const conflictUri = parseConflictUri(readPath);
2121
+ if (conflictUri) {
2122
+ if (conflictUri.id === "*") {
2123
+ throw new ToolError(
2124
+ "Reading `conflict://*` is not supported — wildcards are write-only. Use the `<path>:conflicts` read selector for the full list of conflicts in a file, or read `conflict://<N>` to inspect a single block.",
2125
+ );
2126
+ }
2127
+ return this.#readConflictRegion(conflictUri.id, conflictUri.scope);
2128
+ }
2129
+ const displayMode = resolveFileDisplayMode(this.session);
2130
+
2131
+ const parsedUrlTarget = parseReadUrlTarget(readPath);
2132
+ if (parsedUrlTarget) {
2133
+ if (!this.session.settings.get("fetch.enabled")) {
2134
+ throw new ToolError("URL reads are disabled by settings.");
2135
+ }
2136
+ if (parsedUrlTarget.ranges !== undefined) {
2137
+ const cached = await loadReadUrlCacheEntry(
2138
+ this.session,
2139
+ { path: parsedUrlTarget.path, raw: parsedUrlTarget.raw },
2140
+ signal,
2141
+ { ensureArtifact: true, preferCached: true },
2142
+ );
2143
+ return this.#buildInMemoryMultiRangeResult(cached.output, parsedUrlTarget.ranges, {
2144
+ details: { ...cached.details },
2145
+ sourceUrl: cached.details.finalUrl,
2146
+ entityLabel: "URL output",
2147
+ raw: parsedUrlTarget.raw,
2148
+ immutable: true,
2149
+ });
2150
+ }
2151
+ if (parsedUrlTarget.offset !== undefined || parsedUrlTarget.limit !== undefined) {
2152
+ const cached = await loadReadUrlCacheEntry(
2153
+ this.session,
2154
+ { path: parsedUrlTarget.path, raw: parsedUrlTarget.raw },
2155
+ signal,
2156
+ {
2157
+ ensureArtifact: true,
2158
+ preferCached: true,
2159
+ },
2160
+ );
2161
+ return this.#buildInMemoryTextResult(cached.output, parsedUrlTarget.offset, parsedUrlTarget.limit, {
2162
+ details: { ...cached.details },
2163
+ sourceUrl: cached.details.finalUrl,
2164
+ entityLabel: "URL output",
2165
+ raw: parsedUrlTarget.raw,
2166
+ immutable: true,
2167
+ });
2168
+ }
2169
+ return executeReadUrl(this.session, { path: parsedUrlTarget.path, raw: parsedUrlTarget.raw }, signal);
2170
+ }
2171
+
2172
+ // Handle internal URLs (agent://, artifact://, memory://, skill://, rule://, local://, mcp://, omp://, issue://, pr://).
2173
+ // Use the internal-URL-aware splitter so malformed selectors are peeled
2174
+ // off the URL and surfaced via parseSel rather than confusing handlers.
2175
+ const internalRouter = InternalUrlRouter.instance();
2176
+ if (internalRouter.canHandle(readPath)) {
2177
+ const internalTarget = splitInternalUrlSel(readPath);
2178
+ const parsed = parseSel(internalTarget.sel);
2179
+ if (internalTarget.sel !== undefined && parsed.kind === "none") {
2180
+ throw new ToolError(
2181
+ `Invalid selector ':${internalTarget.sel}' on '${internalTarget.path}'. Use :N, :N-M, :N+K, :N- (open-ended), a comma-separated list of ranges, :raw, or a range combined with raw (e.g. :raw:50-100).`,
2182
+ );
2183
+ }
2184
+ const urlMeta = parseInternalUrl(internalTarget.path);
2185
+ const scheme = urlMeta.protocol.replace(/:$/, "").toLowerCase();
2186
+ if (scheme === "local") {
2187
+ const localFile = await resolveLocalUrlToFile(urlMeta, {
2188
+ cwd: this.session.cwd,
2189
+ settings: this.session.settings,
2190
+ signal,
2191
+ localProtocolOptions: this.session.localProtocolOptions,
2192
+ skills: this.session.skills,
2193
+ });
2194
+ if (localFile) {
2195
+ readPath = internalTarget.sel === undefined ? localFile.path : `${localFile.path}:${internalTarget.sel}`;
2196
+ } else {
2197
+ return this.#handleInternalUrl(internalTarget.path, parsed, signal);
2198
+ }
2199
+ } else {
2200
+ return this.#handleInternalUrl(internalTarget.path, parsed, signal);
2201
+ }
2202
+ }
2203
+
2204
+ // One suffix-glob memo per read call — archive, sqlite, and plain-path
2205
+ // resolution share misses instead of re-globbing the workspace.
2206
+ const suffixCache: SuffixMatchCache = new Map();
2207
+
2208
+ const archivePath = await this.#resolveArchiveReadPath(readPath, suffixCache, signal);
2209
+ if (archivePath) {
2210
+ const archiveSubPath = splitPathAndSel(archivePath.archiveSubPath);
2211
+ const archiveParsed = parseSel(archiveSubPath.sel);
2212
+ return this.#readArchive(
2213
+ readPath,
2214
+ archiveParsed,
2215
+ { ...archivePath, archiveSubPath: archiveSubPath.path },
2216
+ signal,
2217
+ );
2218
+ }
2219
+
2220
+ const sqlitePath = await this.#resolveSqliteReadPath(readPath, suffixCache, signal);
2221
+ if (sqlitePath) {
2222
+ return this.#readSqlite(sqlitePath, signal);
2223
+ }
2224
+
2225
+ const pdfImageMemberPath = splitPdfImageMemberReadPath(readPath);
2226
+ if (pdfImageMemberPath) {
2227
+ let absolutePdfPath = resolveReadPath(pdfImageMemberPath.pdfPath, this.session.cwd);
2228
+ let suffixResolution: { from: string; to: string } | undefined;
2229
+ try {
2230
+ const stat = await Bun.file(absolutePdfPath).stat();
2231
+ if (stat.isDirectory())
2232
+ throw new ToolError(`Path '${pdfImageMemberPath.pdfPath}' is a directory, not a PDF file`);
2233
+ } catch (error) {
2234
+ if (!isNotFoundError(error) || isRemoteMountPath(absolutePdfPath)) throw error;
2235
+ const suffixMatch = await this.#findSuffixMatchCached(suffixCache, pdfImageMemberPath.pdfPath, signal);
2236
+ if (!suffixMatch) throw new ToolError(`Path '${pdfImageMemberPath.pdfPath}' not found`);
2237
+ absolutePdfPath = suffixMatch.absolutePath;
2238
+ suffixResolution = { from: pdfImageMemberPath.pdfPath, to: suffixMatch.displayPath };
2239
+ }
2240
+ return this.#readPdfImageMember(
2241
+ absolutePdfPath,
2242
+ pdfImageMemberPath.pdfPath,
2243
+ pdfImageMemberPath.member,
2244
+ suffixResolution,
2245
+ signal,
2246
+ );
2247
+ }
2248
+
2249
+ const localTarget = splitPathAndSel(readPath);
2250
+ const localReadPath = localTarget.path;
2251
+ const parsed = parseSel(localTarget.sel);
2252
+
2253
+ let absolutePath = resolveReadPath(localReadPath, this.session.cwd);
2254
+ let suffixResolution: { from: string; to: string } | undefined;
2255
+
2256
+ let isDirectory = false;
2257
+ let fileSize = 0;
2258
+ try {
2259
+ const stat = await Bun.file(absolutePath).stat();
2260
+ fileSize = stat.size;
2261
+ isDirectory = stat.isDirectory();
2262
+ } catch (error) {
2263
+ if (isNotFoundError(error)) {
2264
+ // Attempt unique suffix resolution before falling back to fuzzy suggestions
2265
+ if (!isRemoteMountPath(absolutePath)) {
2266
+ const suffixMatch = await this.#findSuffixMatchCached(suffixCache, localReadPath, signal);
2267
+ if (suffixMatch) {
2268
+ try {
2269
+ const retryStat = await Bun.file(suffixMatch.absolutePath).stat();
2270
+ absolutePath = suffixMatch.absolutePath;
2271
+ fileSize = retryStat.size;
2272
+ isDirectory = retryStat.isDirectory();
2273
+ suffixResolution = { from: localReadPath, to: suffixMatch.displayPath };
2274
+ } catch {
2275
+ // Suffix match candidate no longer stats — fall through to error path
2276
+ }
2277
+ }
2278
+ }
2279
+
2280
+ if (!suffixResolution) {
2281
+ const delimitedResult = await this.#tryReadDelimitedPaths(readPath, signal);
2282
+ if (delimitedResult) return delimitedResult;
2283
+ throw new ToolError(`Path '${localReadPath}' not found`);
2284
+ }
2285
+ } else {
2286
+ throw error;
2287
+ }
2288
+ }
2289
+
2290
+ if (isDirectory) {
2291
+ if (isMultiRange(parsed)) {
2292
+ throw new ToolError("Multi-range line selectors are not supported for directory listings.");
2293
+ }
2294
+ const { offset, limit } = selToOffsetLimit(parsed);
2295
+ // Directory listings are deterministic and fast; never abort them mid-scan
2296
+ // (an interrupt would otherwise surface a misleading "Operation aborted").
2297
+ const dirResult = await this.#readDirectory(absolutePath, offset, limit, undefined);
2298
+ if (suffixResolution) {
2299
+ dirResult.details ??= {};
2300
+ dirResult.details.suffixResolution = suffixResolution;
2301
+ }
2302
+ return dirResult;
2303
+ }
2304
+
2305
+ if (parsed.kind === "conflicts") {
2306
+ return this.#readFileConflicts(absolutePath, suffixResolution, signal);
2307
+ }
2308
+
2309
+ const imageMetadata = await readImageMetadata(absolutePath);
2310
+ const mimeType = imageMetadata?.mimeType;
2311
+ const ext = path.extname(absolutePath).toLowerCase();
2312
+ const shouldConvertWithMarkit = CONVERTIBLE_EXTENSIONS.has(ext);
2313
+ // Read the file based on type
2314
+ let content: Array<TextContent | ImageContent> | undefined;
2315
+ let details: ReadToolDetails = {};
2316
+ let sourcePath: string | undefined;
2317
+ let columnTruncated = 0;
2318
+ let truncationInfo:
2319
+ | { result: TruncationResult; options: { direction: "head"; startLine?: number; totalFileLines?: number } }
2320
+ | undefined;
2321
+
2322
+ if (mimeType) {
2323
+ ({ content, details, sourcePath } = await this.#loadImageContent({
2324
+ readPath,
2325
+ absolutePath,
2326
+ mimeType,
2327
+ imageMetadata,
2328
+ fileSize,
2329
+ }));
2330
+ } else if (isNotebookPath(absolutePath) && !isRawSelector(parsed)) {
2331
+ const notebookText = await readEditableNotebookText(absolutePath, localReadPath);
2332
+ if (isMultiRange(parsed) && parsed.kind === "lines") {
2333
+ return this.#buildInMemoryMultiRangeResult(notebookText, parsed.ranges, {
2334
+ details: { resolvedPath: absolutePath },
2335
+ sourcePath: absolutePath,
2336
+ entityLabel: "notebook",
2337
+ });
2338
+ }
2339
+ const { offset, limit } = selToOffsetLimit(parsed);
2340
+ return this.#buildInMemoryTextResult(notebookText, offset, limit, {
2341
+ details: { resolvedPath: absolutePath },
2342
+ sourcePath: absolutePath,
2343
+ entityLabel: "notebook",
2344
+ });
2345
+ } else if (shouldConvertWithMarkit) {
2346
+ // Convert document via markit.
2347
+ const result = await convertFileWithMarkit(absolutePath, signal);
2348
+ if (result.ok) {
2349
+ const renderedContent =
2350
+ ext === ".pdf" ? rewritePdfImagePlaceholders(result.content, localReadPath) : result.content;
2351
+ // Route the converted markdown through the in-memory text builder
2352
+ // so line-range selectors (`file.pdf:50-100`, `:5-16,40-80`) and
2353
+ // raw mode apply against the converted output. Without this,
2354
+ // `file.pdf:50-100` silently returned the head of the document
2355
+ // because only `truncateHead` was being applied.
2356
+ if (isMultiRange(parsed) && parsed.kind === "lines") {
2357
+ return this.#buildInMemoryMultiRangeResult(renderedContent, parsed.ranges, {
2358
+ details: { resolvedPath: absolutePath },
2359
+ sourcePath: absolutePath,
2360
+ entityLabel: "document",
2361
+ });
2362
+ }
2363
+ const { offset, limit } = selToOffsetLimit(parsed);
2364
+ return this.#buildInMemoryTextResult(renderedContent, offset, limit, {
2365
+ details: { resolvedPath: absolutePath },
2366
+ sourcePath: absolutePath,
2367
+ entityLabel: "document",
2368
+ raw: isRawSelector(parsed),
2369
+ });
2370
+ } else if (result.error) {
2371
+ content = [{ type: "text", text: `[Cannot read ${ext} file: ${result.error || "conversion failed"}]` }];
2372
+ } else {
2373
+ content = [{ type: "text", text: `[Cannot read ${ext} file: conversion failed]` }];
2374
+ }
2375
+ } else {
2376
+ // Binary sniff before any UTF-8 text materialization. A binary file
2377
+ // (font, object, archive, packed blob) decodes to NUL/control bytes and
2378
+ // U+FFFD mojibake that corrupts the terminal and burns context. Images,
2379
+ // notebooks, and markit-convertible documents were already routed above;
2380
+ // everything reaching here is meant to be plain text. `:raw` stays the
2381
+ // explicit escape hatch for reading bytes verbatim. This single guard
2382
+ // covers both the multi-range and single-range disk paths below.
2383
+ if (!isRawSelector(parsed) && (await isProbablyBinary(absolutePath))) {
2384
+ return toolResult<ReadToolDetails>({ resolvedPath: absolutePath, suffixResolution })
2385
+ .text(
2386
+ prependSuffixResolutionNotice(
2387
+ `[Cannot read binary file '${formatPathRelativeToCwd(absolutePath, this.session.cwd)}' (${formatBytes(fileSize)}); not valid UTF-8 text. Use ':raw' to read bytes verbatim.]`,
2388
+ suffixResolution,
2389
+ ),
2390
+ )
2391
+ .sourcePath(absolutePath)
2392
+ .done();
2393
+ }
2394
+
2395
+ if (
2396
+ parsed.kind === "none" &&
2397
+ this.session.settings.get("read.summarize.enabled") &&
2398
+ (this.session.settings.get("read.summarize.prose") || !PROSE_SUMMARY_EXTENSIONS.has(ext))
2399
+ ) {
2400
+ const summary = await this.#trySummarize(absolutePath, fileSize, signal);
2401
+ if (summary?.parsed && summary.elided) {
2402
+ const renderedSummary = this.#renderSummary(summary);
2403
+ const footer = formatSummaryElisionFooter(
2404
+ localReadPath,
2405
+ renderedSummary.elidedRanges,
2406
+ renderedSummary.elidedLines,
2407
+ );
2408
+ const summaryHashContext = displayMode.hashLines
2409
+ ? await readHashlineHeaderContext(this.session, absolutePath, this.session.cwd)
2410
+ : undefined;
2411
+ const bodyText = footer ? `${renderedSummary.text}\n\n${footer}` : renderedSummary.text;
2412
+ const modelText = prependHashlineHeader(bodyText, summaryHashContext);
2413
+ if (summaryHashContext?.tag) {
2414
+ recordSeenLinesFromBody(this.session, absolutePath, summaryHashContext.tag, renderedSummary.text);
2415
+ }
2416
+ details = {
2417
+ displayContent: { text: renderedSummary.displayText, startLine: 1 },
2418
+ summary: {
2419
+ lines: countTextLines(renderedSummary.text),
2420
+ elidedSpans: renderedSummary.elidedRanges.length,
2421
+ elidedLines: renderedSummary.elidedLines,
2422
+ },
2423
+ };
2424
+
2425
+ sourcePath = absolutePath;
2426
+ content = [{ type: "text", text: modelText }];
2427
+ }
2428
+ }
2429
+
2430
+ if (!content) {
2431
+ if (isMultiRange(parsed) && parsed.kind === "lines") {
2432
+ const multiResult = await this.#readLocalFileMultiRange(
2433
+ absolutePath,
2434
+ parsed.ranges,
2435
+ fileSize,
2436
+ parsed,
2437
+ displayMode,
2438
+ suffixResolution,
2439
+ undefined, // plain-file read: deterministic and fast, never abort mid-read
2440
+ );
2441
+ if (multiResult.bridgeResult) return multiResult.bridgeResult;
2442
+ content = [{ type: "text", text: multiResult.outputText }];
2443
+ sourcePath = absolutePath;
2444
+ details = multiResult.displayContent ? { displayContent: multiResult.displayContent } : {};
2445
+ if (multiResult.columnTruncated > 0) {
2446
+ columnTruncated = multiResult.columnTruncated;
2447
+ }
2448
+ } else {
2449
+ // Raw text or line-range mode
2450
+ const { offset, limit } = selToOffsetLimit(parsed);
2451
+ // Try ACP bridge first — editor's in-memory buffer is source of truth.
2452
+ // Request full text so local range rendering keeps normal context and line numbers.
2453
+ const bridgePromise = this.#routeReadThroughBridge(absolutePath);
2454
+ if (bridgePromise !== undefined) {
2455
+ try {
2456
+ const bridgeText = await bridgePromise;
2457
+ const bridgeResult = this.#buildInMemoryTextResult(bridgeText, offset, limit, {
2458
+ details: { resolvedPath: absolutePath, suffixResolution },
2459
+ sourcePath: absolutePath,
2460
+ entityLabel: "file",
2461
+ raw: isRawSelector(parsed),
2462
+ });
2463
+ if (suffixResolution) {
2464
+ const notice = `[Path '${suffixResolution.from}' not found; resolved to '${suffixResolution.to}' via suffix match]`;
2465
+ const firstText = bridgeResult.content.find((c): c is TextContent => c.type === "text");
2466
+ if (firstText) firstText.text = `${notice}\n${firstText.text}`;
2467
+ }
2468
+ return bridgeResult;
2469
+ } catch (error) {
2470
+ logger.warn("ACP fs readTextFile failed; falling back to disk", { path: absolutePath, error });
2471
+ }
2472
+ }
2473
+
2474
+ // User-requested 0-indexed range start. Lines BEFORE this become
2475
+ // leading context (added below if offset is explicit).
2476
+ const requestedStart = offset ? Math.max(0, offset - 1) : 0;
2477
+ const expandStart = offset !== undefined && offset > 1;
2478
+ const expandEnd = limit !== undefined;
2479
+ const leadingContext = expandStart ? Math.min(requestedStart, RANGE_LEADING_CONTEXT_LINES) : 0;
2480
+ const trailingContext = expandEnd ? RANGE_TRAILING_CONTEXT_LINES : 0;
2481
+ const startLine = requestedStart - leadingContext;
2482
+ const startLineDisplay = startLine + 1;
2483
+
2484
+ const DEFAULT_LIMIT = this.#defaultLimit;
2485
+ const effectiveLimit = limit ?? DEFAULT_LIMIT;
2486
+ const maxLinesToCollect = Math.min(effectiveLimit + leadingContext + trailingContext, DEFAULT_MAX_LINES);
2487
+ const selectedLineLimit = effectiveLimit + leadingContext + trailingContext;
2488
+ // Scale byte budget with line limit so the configured line count actually fits.
2489
+ // Assume ~512 bytes/line average; never go below the shared default.
2490
+ const maxBytesForRead = Math.max(DEFAULT_MAX_BYTES, maxLinesToCollect * 512);
2491
+
2492
+ const streamResult = await streamLinesFromFile(
2493
+ absolutePath,
2494
+ startLine,
2495
+ maxLinesToCollect,
2496
+ maxBytesForRead,
2497
+ selectedLineLimit,
2498
+ undefined, // plain-file read: deterministic and fast, never abort mid-read
2499
+ fileSize > SNAPSHOT_MAX_BYTES, // giant file: don't scan to EOF just for an exact line count
2500
+ );
2501
+
2502
+ const {
2503
+ lines: collectedLines,
2504
+ totalFileLines,
2505
+ collectedBytes,
2506
+ stoppedByByteLimit,
2507
+ firstLinePreview,
2508
+ firstLineByteLength,
2509
+ reachedEof,
2510
+ } = streamResult;
2511
+
2512
+ // Check if offset is out of bounds - return graceful message instead of throwing
2513
+ if (requestedStart >= totalFileLines) {
2514
+ const suggestion =
2515
+ totalFileLines === 0
2516
+ ? "The file is empty."
2517
+ : `Use :1 to read from the start, or :${totalFileLines} to read the last line.`;
2518
+ return toolResult<ReadToolDetails>({ resolvedPath: absolutePath, suffixResolution })
2519
+ .text(
2520
+ `Line ${requestedStart + 1} is beyond end of file (${totalFileLines} lines total). ${suggestion}`,
2521
+ )
2522
+ .done();
2523
+ }
2524
+
2525
+ // Per-line column cap. Skipped in raw mode so `:raw` always returns
2526
+ // verbatim bytes for paste-back-into-tool workflows. Total byte/line
2527
+ // counts in `truncation` keep reflecting the source, not the trimmed
2528
+ // view — column truncation surfaces separately via `.limits()`.
2529
+ const rawSelector = isRawSelector(parsed);
2530
+ const maxColumns = resolveOutputMaxColumns(this.session.settings);
2531
+ // Column truncation is display-only. `collectedLines` MUST stay
2532
+ // byte-for-byte with the on-disk content so the snapshot recorded
2533
+ // below can be verified against the live file. Mutating it with
2534
+ // ellipsis-truncated text made every long-line file uneditable on
2535
+ // the next edit attempt.
2536
+ let displayLines: string[] = collectedLines;
2537
+ const clippedLines = new Set<number>();
2538
+ if (!rawSelector && maxColumns > 0) {
2539
+ let cloned: string[] | undefined;
2540
+ for (let i = 0; i < collectedLines.length; i++) {
2541
+ const { text, wasTruncated } = truncateLine(collectedLines[i], maxColumns);
2542
+ if (wasTruncated) {
2543
+ if (!cloned) cloned = collectedLines.slice();
2544
+ cloned[i] = text;
2545
+ columnTruncated = maxColumns;
2546
+ clippedLines.add(startLineDisplay + i);
2547
+ }
2548
+ }
2549
+ if (cloned) displayLines = cloned;
2550
+ }
2551
+
2552
+ const displayLineByNumber = new Map<number, string>();
2553
+ for (let i = 0; i < displayLines.length; i++) {
2554
+ displayLineByNumber.set(startLineDisplay + i, displayLines[i] ?? "");
2555
+ }
2556
+ const bracketContextFullLines = rawSelector
2557
+ ? undefined
2558
+ : await readBracketContextFullLines(absolutePath, fileSize);
2559
+ const displayedEndLine = startLineDisplay + Math.max(0, displayLines.length - 1);
2560
+
2561
+ const selectedContent = displayLines.join("\n");
2562
+ const userLimitedLines = collectedLines.length;
2563
+
2564
+ const totalSelectedLines = totalFileLines - startLine;
2565
+ const totalSelectedBytes = collectedBytes;
2566
+ const wasTruncated = collectedLines.length < totalSelectedLines || stoppedByByteLimit;
2567
+ const firstLineExceedsLimit = firstLineByteLength !== undefined && firstLineByteLength > maxBytesForRead;
2568
+
2569
+ const truncation: TruncationResult = {
2570
+ content: selectedContent,
2571
+ truncated: wasTruncated,
2572
+ truncatedBy: stoppedByByteLimit ? "bytes" : wasTruncated ? "lines" : undefined,
2573
+ totalLines: totalSelectedLines,
2574
+ totalBytes: totalSelectedBytes,
2575
+ outputLines: collectedLines.length,
2576
+ outputBytes: collectedBytes,
2577
+ lastLinePartial: false,
2578
+ firstLineExceedsLimit,
2579
+ };
2580
+
2581
+ const shouldAddHashLines = !rawSelector && displayMode.hashLines;
2582
+ const shouldAddLineNumbers = rawSelector ? false : shouldAddHashLines ? false : displayMode.lineNumbers;
2583
+ let hashContext: HashlineHeaderContext | undefined;
2584
+ if (shouldAddHashLines && collectedLines.length > 0 && !firstLineExceedsLimit) {
2585
+ // The tag is a content hash of the WHOLE file. A whole-file read
2586
+ // already holds every line in memory; a range read re-reads the
2587
+ // file (bounded by SNAPSHOT_MAX_BYTES) so the tag fingerprints the
2588
+ // full file and any anchor validates while the file is unchanged.
2589
+ const isWholeFile = offset === undefined && limit === undefined && !wasTruncated;
2590
+ const tag = isWholeFile
2591
+ ? getFileSnapshotStore(this.session).record(
2592
+ canonicalSnapshotKey(absolutePath),
2593
+ normalizeToLF(collectedLines.join("\n")),
2594
+ )
2595
+ : await recordFileSnapshot(this.session, absolutePath);
2596
+ if (tag) {
2597
+ hashContext = hashlineHeaderContext(formatPathRelativeToCwd(absolutePath, this.session.cwd), tag);
2598
+ }
2599
+ }
2600
+
2601
+ let capturedDisplayContent:
2602
+ | { text: string; startLine: number; lineNumbers?: Array<number | null> }
2603
+ | undefined;
2604
+ let emittedHashlineHeader = false;
2605
+ const formatText = (text: string, startNum: number): string => {
2606
+ const lineCount = countTextLines(text);
2607
+ capturedDisplayContent = {
2608
+ text,
2609
+ startLine: startNum,
2610
+ lineNumbers: Array.from({ length: lineCount }, (_, i) => startNum + i),
2611
+ };
2612
+ const formatted = formatTextWithMode(text, startNum, shouldAddHashLines, shouldAddLineNumbers);
2613
+ if (!hashContext || emittedHashlineHeader) return formatted;
2614
+ emittedHashlineHeader = true;
2615
+ return prependHashlineHeader(formatted, hashContext);
2616
+ };
2617
+ const formatBracketAwareText = (): string | undefined => {
2618
+ if (!bracketContextFullLines) return undefined;
2619
+ const entries = buildLineEntriesWithBlockContext(
2620
+ bracketContextFullLines,
2621
+ [{ startLine: startLineDisplay, endLine: displayedEndLine }],
2622
+ { path: absolutePath },
2623
+ {
2624
+ lineText: (lineNumber, sourceText) => {
2625
+ const visibleText = displayLineByNumber.get(lineNumber);
2626
+ if (visibleText !== undefined) return visibleText;
2627
+ if (maxColumns <= 0) return sourceText;
2628
+ const truncated = truncateLine(sourceText, maxColumns);
2629
+ if (truncated.wasTruncated) {
2630
+ columnTruncated = maxColumns;
2631
+ clippedLines.add(lineNumber);
2632
+ }
2633
+ return truncated.text;
2634
+ },
2635
+ },
2636
+ );
2637
+ const firstLine = entries.find(entry => entry.kind === "line");
2638
+ capturedDisplayContent = {
2639
+ text: lineEntriesToPlainText(entries, BRACKET_CONTEXT_ELLIPSIS),
2640
+ startLine: firstLine?.kind === "line" ? firstLine.lineNumber : startLineDisplay,
2641
+ lineNumbers: entries.map(entry => (entry.kind === "line" ? entry.lineNumber : null)),
2642
+ };
2643
+ const formatted = formatLineEntriesWithMode(entries, shouldAddHashLines, shouldAddLineNumbers);
2644
+ if (!hashContext || emittedHashlineHeader) return formatted;
2645
+ emittedHashlineHeader = true;
2646
+ return prependHashlineHeader(formatted, hashContext);
2647
+ };
2648
+
2649
+ let outputText: string;
2650
+
2651
+ if (truncation.firstLineExceedsLimit) {
2652
+ const firstLineBytes = firstLineByteLength ?? 0;
2653
+ const snippet = firstLinePreview ?? { text: "", bytes: 0 };
2654
+
2655
+ if (shouldAddHashLines) {
2656
+ outputText = `[Line ${startLineDisplay} is ${formatBytes(
2657
+ firstLineBytes,
2658
+ )}, exceeds ${formatBytes(maxBytesForRead)} limit. Hashline output requires full lines; cannot emit an editable numbered preview for a truncated line.]`;
2659
+ } else {
2660
+ outputText = formatText(snippet.text, startLineDisplay);
2661
+ }
2662
+ if (snippet.text.length === 0) {
2663
+ outputText = `[Line ${startLineDisplay} is ${formatBytes(
2664
+ firstLineBytes,
2665
+ )}, exceeds ${formatBytes(maxBytesForRead)} limit. Unable to display a valid UTF-8 snippet.]`;
2666
+ }
2667
+ details = { truncation };
2668
+ sourcePath = absolutePath;
2669
+ truncationInfo = {
2670
+ result: truncation,
2671
+ options: {
2672
+ direction: "head",
2673
+ startLine: startLineDisplay,
2674
+ totalFileLines: reachedEof ? totalFileLines : undefined,
2675
+ },
2676
+ };
2677
+ } else if (truncation.truncated) {
2678
+ outputText = formatBracketAwareText() ?? formatText(truncation.content, startLineDisplay);
2679
+ details = { truncation };
2680
+ sourcePath = absolutePath;
2681
+ truncationInfo = {
2682
+ result: truncation,
2683
+ options: {
2684
+ direction: "head",
2685
+ startLine: startLineDisplay,
2686
+ totalFileLines: reachedEof ? totalFileLines : undefined,
2687
+ },
2688
+ };
2689
+ } else if (startLine + userLimitedLines < totalFileLines || !reachedEof) {
2690
+ const nextOffset = startLine + userLimitedLines + 1;
2691
+
2692
+ outputText = formatBracketAwareText() ?? formatText(truncation.content, startLineDisplay);
2693
+ outputText += reachedEof
2694
+ ? `\n\n[${totalFileLines - (startLine + userLimitedLines)} more lines in file. Use :${nextOffset} to continue]`
2695
+ : `\n\n[More lines in file (${formatBytes(fileSize)} total; not scanned to EOF). Use :${nextOffset} to continue]`;
2696
+ details = {};
2697
+ sourcePath = absolutePath;
2698
+ } else {
2699
+ // No truncation, no user limit exceeded
2700
+ outputText = formatBracketAwareText() ?? formatText(truncation.content, startLineDisplay);
2701
+ details = {};
2702
+ sourcePath = absolutePath;
2703
+ }
2704
+
2705
+ if (hashContext?.tag) {
2706
+ recordSeenLinesFromBody(this.session, absolutePath, hashContext.tag, outputText, clippedLines);
2707
+ }
2708
+ if (rawSelector && !firstLineExceedsLimit && collectedLines.length > 0) {
2709
+ await recordFileSnapshot(
2710
+ this.session,
2711
+ absolutePath,
2712
+ contiguousLineNumbers(startLineDisplay, collectedLines.length),
2713
+ );
2714
+ }
2715
+
2716
+ if (capturedDisplayContent) {
2717
+ details.displayContent = capturedDisplayContent;
2718
+ }
2719
+
2720
+ if (!firstLineExceedsLimit && collectedLines.length > 0) {
2721
+ const blocks = scanConflictLines(collectedLines, startLineDisplay);
2722
+ if (blocks.length > 0) {
2723
+ const history = getConflictHistory(this.session);
2724
+ const displayPathForWarning = formatPathRelativeToCwd(absolutePath, this.session.cwd);
2725
+ const entries = blocks.map(block =>
2726
+ history.register({
2727
+ absolutePath,
2728
+ displayPath: displayPathForWarning,
2729
+ ...block,
2730
+ }),
2731
+ );
2732
+ // Cheap full-file scan only when the window already showed
2733
+ // at least one conflict — otherwise pay nothing on clean files.
2734
+ let totalInFile = entries.length;
2735
+ let scanTruncated = false;
2736
+ try {
2737
+ const fileScan = await scanFileForConflicts(absolutePath);
2738
+ totalInFile = Math.max(entries.length, fileScan.blocks.length);
2739
+ scanTruncated = fileScan.scanTruncated;
2740
+ } catch {
2741
+ // Best-effort enrichment; fall back to window-only count.
2742
+ }
2743
+ outputText += formatConflictWarning(entries, {
2744
+ totalInFile,
2745
+ displayPath: displayPathForWarning,
2746
+ scanTruncated,
2747
+ });
2748
+ details.conflictCount = entries.length;
2749
+ }
2750
+ }
2751
+
2752
+ content = [{ type: "text", text: outputText }];
2753
+ }
2754
+ }
2755
+ }
2756
+
2757
+ if (suffixResolution) {
2758
+ details.suffixResolution = suffixResolution;
2759
+ // Inline resolution notice into first text block so the model sees the actual path
2760
+ const notice = `[Path '${suffixResolution.from}' not found; resolved to '${suffixResolution.to}' via suffix match]`;
2761
+ const firstText = content.find((c): c is TextContent => c.type === "text");
2762
+ if (firstText) {
2763
+ firstText.text = `${notice}\n${firstText.text}`;
2764
+ } else {
2765
+ content = [{ type: "text", text: notice }, ...content];
2766
+ }
2767
+ }
2768
+ const resultBuilder = toolResult(details).content(content);
2769
+ if (sourcePath) {
2770
+ resultBuilder.sourcePath(sourcePath);
2771
+ }
2772
+ if (truncationInfo) {
2773
+ resultBuilder.truncation(truncationInfo.result, truncationInfo.options);
2774
+ }
2775
+ if (columnTruncated > 0) {
2776
+ resultBuilder.limits({ columnMax: columnTruncated });
2777
+ }
2778
+ return resultBuilder.done();
2779
+ }
2780
+
2781
+ /**
2782
+ * Render a `conflict://<N>` (or `conflict://<N>/<scope>`) region as
2783
+ * regular file content. The lines are emitted with their original
2784
+ * file line numbers so hashline anchors line up with the source
2785
+ * file, and no truncation footer is appended.
2786
+ */
2787
+ async #readConflictRegion(id: number, scope: ConflictScope | undefined): Promise<AgentToolResult<ReadToolDetails>> {
2788
+ const entry: ConflictEntry | undefined = getConflictHistory(this.session).get(id);
2789
+ if (!entry) {
2790
+ throw new ToolError(
2791
+ `Conflict #${id} not found. Conflict ids are registered when \`read\` surfaces a marker block; re-read the file to get a current id.`,
2792
+ );
2793
+ }
2794
+
2795
+ const region = renderConflictRegion(entry, scope);
2796
+ const displayMode = resolveFileDisplayMode(this.session);
2797
+ const shouldAddHashLines = displayMode.hashLines;
2798
+ const shouldAddLineNumbers = shouldAddHashLines ? false : displayMode.lineNumbers;
2799
+
2800
+ const rawText = region.lines.join("\n");
2801
+ const tag = shouldAddHashLines ? await recordFileSnapshot(this.session, entry.absolutePath) : undefined;
2802
+ const hashContext = tag
2803
+ ? hashlineHeaderContext(formatPathRelativeToCwd(entry.absolutePath, this.session.cwd), tag)
2804
+ : undefined;
2805
+ const formattedBody = formatTextWithMode(rawText, region.startLine, shouldAddHashLines, shouldAddLineNumbers);
2806
+ const formattedText = prependHashlineHeader(formattedBody, hashContext);
2807
+
2808
+ const details: ReadToolDetails = {
2809
+ resolvedPath: entry.absolutePath,
2810
+ displayContent: { text: rawText, startLine: region.startLine },
2811
+ };
2812
+ return toolResult<ReadToolDetails>(details).text(formattedText).sourcePath(entry.absolutePath).done();
2813
+ }
2814
+
2815
+ /**
2816
+ * Implement the `<path>:conflicts` read selector: scan the whole file once, register
2817
+ * every block in the session's conflict history, and return a compact
2818
+ * `#N L_a-L_b` index instead of file content. Designed for heavily
2819
+ * conflicted files where dumping every body would be wasteful.
2820
+ */
2821
+ async #readFileConflicts(
2822
+ absolutePath: string,
2823
+ suffixResolution: { from: string; to: string } | undefined,
2824
+ signal: AbortSignal | undefined,
2825
+ ): Promise<AgentToolResult<ReadToolDetails>> {
2826
+ throwIfAborted(signal);
2827
+ const scan = await scanFileForConflicts(absolutePath);
2828
+ const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
2829
+ const history = getConflictHistory(this.session);
2830
+ const entries = scan.blocks.map(block =>
2831
+ history.register({
2832
+ absolutePath,
2833
+ displayPath,
2834
+ ...block,
2835
+ }),
2836
+ );
2837
+
2838
+ const summary =
2839
+ entries.length === 0
2840
+ ? `No unresolved git merge conflicts in ${displayPath}.`
2841
+ : formatConflictSummary(entries, { displayPath, scanTruncated: scan.scanTruncated });
2842
+
2843
+ const details: ReadToolDetails = {
2844
+ resolvedPath: absolutePath,
2845
+ suffixResolution,
2846
+ conflictCount: entries.length,
2847
+ };
2848
+ return toolResult<ReadToolDetails>(details).text(summary).sourcePath(absolutePath).done();
2849
+ }
2850
+
2851
+ #formatArtifactWorkflowNotice(artifact: ResolvedArtifactFile, artifactUrl: string): string {
2852
+ const displayPath = shortenPath(artifact.path);
2853
+ return `Artifact storage: ${displayPath} (${formatBytes(artifact.size)}). Use ${artifactUrl}:N-M to page, ${artifactUrl}:raw:N-M for verbatim chunks, and the artifact file path for search/copy workflows.`;
2854
+ }
2855
+
2856
+ #formatRawArtifactBlockedNotice(artifact: ResolvedArtifactFile, artifactUrl: string): string {
2857
+ const displayPath = shortenPath(artifact.path);
2858
+ return `Unbounded raw read blocked for ${artifactUrl} (${formatBytes(
2859
+ artifact.size,
2860
+ )}). Reading the whole artifact verbatim can exhaust memory. Use ${artifactUrl}:raw:1-3000 for bounded verbatim chunks, ${artifactUrl}:1-3000 for numbered exploration, and the artifact file path for search/copy workflows: ${displayPath}`;
2861
+ }
2862
+
2863
+ async #readArtifactFile(
2864
+ url: InternalUrl,
2865
+ parsedSel: ParsedSelector,
2866
+ signal?: AbortSignal,
2867
+ ): Promise<AgentToolResult<ReadToolDetails>> {
2868
+ const artifact = await resolveArtifactFile(url, {
2869
+ cwd: this.session.cwd,
2870
+ settings: this.session.settings,
2871
+ signal,
2872
+ localProtocolOptions: this.session.localProtocolOptions,
2873
+ skills: this.session.skills,
2874
+ });
2875
+ const artifactUrl = `artifact://${artifact.id}`;
2876
+ const details: ReadToolDetails = {
2877
+ resolvedPath: artifact.path,
2878
+ contentType: "text/plain",
2879
+ };
2880
+
2881
+ if (parsedSel.kind === "raw" && artifact.size > MAX_ARTIFACT_RAW_INLINE_BYTES) {
2882
+ return toolResult<ReadToolDetails>(details)
2883
+ .text(this.#formatRawArtifactBlockedNotice(artifact, artifactUrl))
2884
+ .sourcePath(artifact.path)
2885
+ .sourceInternal(url.href)
2886
+ .done();
2887
+ }
2888
+
2889
+ const rawSelector = isRawSelector(parsedSel);
2890
+ const displayMode = resolveFileDisplayMode(this.session, { raw: rawSelector, immutable: true });
2891
+ if (isMultiRange(parsedSel) && parsedSel.kind === "lines") {
2892
+ const read = await this.#readLocalFileMultiRange(
2893
+ artifact.path,
2894
+ parsedSel.ranges,
2895
+ artifact.size,
2896
+ parsedSel,
2897
+ displayMode,
2898
+ undefined,
2899
+ signal,
2900
+ false,
2901
+ );
2902
+ if (read.bridgeResult) return read.bridgeResult;
2903
+ if (read.displayContent) details.displayContent = read.displayContent;
2904
+ let text = read.outputText;
2905
+ if (!rawSelector && artifact.size > MAX_ARTIFACT_RAW_INLINE_BYTES) {
2906
+ text = text
2907
+ ? `${text}\n\n[${this.#formatArtifactWorkflowNotice(artifact, artifactUrl)}]`
2908
+ : this.#formatArtifactWorkflowNotice(artifact, artifactUrl);
2909
+ }
2910
+ const resultBuilder = toolResult<ReadToolDetails>(details)
2911
+ .text(text)
2912
+ .sourcePath(artifact.path)
2913
+ .sourceInternal(url.href);
2914
+ if (read.columnTruncated > 0) resultBuilder.limits({ columnMax: read.columnTruncated });
2915
+ return resultBuilder.done();
2916
+ }
2917
+
2918
+ const { offset, limit } = selToOffsetLimit(parsedSel);
2919
+ const requestedStart = offset ? Math.max(0, offset - 1) : 0;
2920
+ const expandStart = offset !== undefined && offset > 1;
2921
+ const expandEnd = limit !== undefined;
2922
+ const leadingContext = expandStart ? Math.min(requestedStart, RANGE_LEADING_CONTEXT_LINES) : 0;
2923
+ const trailingContext = expandEnd ? RANGE_TRAILING_CONTEXT_LINES : 0;
2924
+ const startLine = requestedStart - leadingContext;
2925
+ const startLineDisplay = startLine + 1;
2926
+ const effectiveLimit = limit ?? this.#defaultLimit;
2927
+ const maxLinesToCollect = Math.min(effectiveLimit + leadingContext + trailingContext, DEFAULT_MAX_LINES);
2928
+ const selectedLineLimit = effectiveLimit + leadingContext + trailingContext;
2929
+ const maxBytesForRead = Math.max(DEFAULT_MAX_BYTES, maxLinesToCollect * 512);
2930
+ const streamResult = await streamLinesFromFile(
2931
+ artifact.path,
2932
+ startLine,
2933
+ maxLinesToCollect,
2934
+ maxBytesForRead,
2935
+ selectedLineLimit,
2936
+ signal,
2937
+ artifact.size > SNAPSHOT_MAX_BYTES,
2938
+ );
2939
+ const {
2940
+ lines: collectedLines,
2941
+ totalFileLines,
2942
+ collectedBytes,
2943
+ stoppedByByteLimit,
2944
+ firstLinePreview,
2945
+ firstLineByteLength,
2946
+ reachedEof,
2947
+ } = streamResult;
2948
+
2949
+ if (requestedStart >= totalFileLines) {
2950
+ const suggestion =
2951
+ totalFileLines === 0
2952
+ ? "The artifact is empty."
2953
+ : `Use ${artifactUrl}:1 to read from the start, or ${artifactUrl}:${totalFileLines} to read the last line.`;
2954
+ return toolResult<ReadToolDetails>(details)
2955
+ .text(`Line ${requestedStart + 1} is beyond end of artifact (${totalFileLines} lines total). ${suggestion}`)
2956
+ .sourcePath(artifact.path)
2957
+ .sourceInternal(url.href)
2958
+ .done();
2959
+ }
2960
+
2961
+ const shouldAddLineNumbers = rawSelector ? false : displayMode.hashLines ? false : displayMode.lineNumbers;
2962
+ const selectedContent = collectedLines.join("\n");
2963
+ const totalSelectedLines = totalFileLines - startLine;
2964
+ const wasTruncated = collectedLines.length < totalSelectedLines || stoppedByByteLimit;
2965
+ const firstLineExceedsLimit = firstLineByteLength !== undefined && firstLineByteLength > maxBytesForRead;
2966
+ const truncation: TruncationResult = {
2967
+ content: selectedContent,
2968
+ truncated: wasTruncated,
2969
+ truncatedBy: stoppedByByteLimit ? "bytes" : wasTruncated ? "lines" : undefined,
2970
+ totalLines: totalSelectedLines,
2971
+ totalBytes: collectedBytes,
2972
+ outputLines: collectedLines.length,
2973
+ outputBytes: collectedBytes,
2974
+ lastLinePartial: false,
2975
+ firstLineExceedsLimit,
2976
+ };
2977
+
2978
+ let displayContent: { text: string; startLine: number; lineNumbers?: Array<number | null> } | undefined;
2979
+ const formatText = (text: string, startNum: number): string => {
2980
+ const lineCount = countTextLines(text);
2981
+ displayContent = {
2982
+ text,
2983
+ startLine: startNum,
2984
+ lineNumbers: Array.from({ length: lineCount }, (_, i) => startNum + i),
2985
+ };
2986
+ return formatTextWithMode(text, startNum, false, shouldAddLineNumbers);
2987
+ };
2988
+
2989
+ let outputText: string;
2990
+ let truncationInfo:
2991
+ | { result: TruncationResult; options: { direction: "head"; startLine?: number; totalFileLines?: number } }
2992
+ | undefined;
2993
+ if (truncation.firstLineExceedsLimit) {
2994
+ const firstLineBytes = firstLineByteLength ?? 0;
2995
+ const snippet = firstLinePreview ?? { text: "", bytes: 0 };
2996
+ outputText =
2997
+ snippet.text.length > 0
2998
+ ? formatText(snippet.text, startLineDisplay)
2999
+ : `[Line ${startLineDisplay} is ${formatBytes(
3000
+ firstLineBytes,
3001
+ )}, exceeds ${formatBytes(maxBytesForRead)} limit. Unable to display a valid UTF-8 snippet.]`;
3002
+ truncationInfo = {
3003
+ result: truncation,
3004
+ options: {
3005
+ direction: "head",
3006
+ startLine: startLineDisplay,
3007
+ totalFileLines: reachedEof ? totalFileLines : undefined,
3008
+ },
3009
+ };
3010
+ } else {
3011
+ outputText = formatText(truncation.content, startLineDisplay);
3012
+ if (truncation.truncated) {
3013
+ truncationInfo = {
3014
+ result: truncation,
3015
+ options: {
3016
+ direction: "head",
3017
+ startLine: startLineDisplay,
3018
+ totalFileLines: reachedEof ? totalFileLines : undefined,
3019
+ },
3020
+ };
3021
+ } else if (startLine + collectedLines.length < totalFileLines || !reachedEof) {
3022
+ const nextOffset = startLine + collectedLines.length + 1;
3023
+ outputText += reachedEof
3024
+ ? `\n\n[${totalFileLines - (startLine + collectedLines.length)} more lines in artifact. Use ${artifactUrl}:${nextOffset} to continue]`
3025
+ : `\n\n[More lines in artifact (${formatBytes(artifact.size)} total; not scanned to EOF). Use ${artifactUrl}:${nextOffset} to continue]`;
3026
+ }
3027
+ }
3028
+
3029
+ if (!rawSelector && artifact.size > MAX_ARTIFACT_RAW_INLINE_BYTES) {
3030
+ outputText += `\n\n[${this.#formatArtifactWorkflowNotice(artifact, artifactUrl)}]`;
3031
+ }
3032
+ if (displayContent) details.displayContent = displayContent;
3033
+ if (truncationInfo) details.truncation = truncationInfo.result;
3034
+ const resultBuilder = toolResult<ReadToolDetails>(details)
3035
+ .text(outputText)
3036
+ .sourcePath(artifact.path)
3037
+ .sourceInternal(url.href);
3038
+ if (truncationInfo) resultBuilder.truncation(truncationInfo.result, truncationInfo.options);
3039
+ return resultBuilder.done();
3040
+ }
3041
+
3042
+ /**
3043
+ * Handle internal URLs (agent://, artifact://, memory://, skill://, rule://, local://, mcp://).
3044
+ * Supports pagination via offset/limit but rejects them when query extraction is used.
3045
+ */
3046
+ async #handleInternalUrl(
3047
+ url: string,
3048
+ parsedSel: ParsedSelector,
3049
+ signal?: AbortSignal,
3050
+ ): Promise<AgentToolResult<ReadToolDetails>> {
3051
+ const internalRouter = InternalUrlRouter.instance();
3052
+
3053
+ // Check if URL has query extraction (agent:// only).
3054
+ // Use parseInternalUrl which handles colons in host (namespaced skills).
3055
+ let urlMeta: InternalUrl;
3056
+ try {
3057
+ urlMeta = parseInternalUrl(url);
3058
+ } catch (e) {
3059
+ throw new ToolError(e instanceof Error ? e.message : String(e));
3060
+ }
3061
+ const scheme = urlMeta.protocol.replace(/:$/, "").toLowerCase();
3062
+ let hasExtraction = false;
3063
+ if (scheme === "agent") {
3064
+ const hasPathExtraction = urlMeta.pathname && urlMeta.pathname !== "/" && urlMeta.pathname !== "";
3065
+ const queryParam = urlMeta.searchParams.get("q");
3066
+ const hasQueryExtraction = queryParam !== null && queryParam !== "";
3067
+ hasExtraction = hasPathExtraction || hasQueryExtraction;
3068
+ }
3069
+ if (scheme === "artifact") {
3070
+ return this.#readArtifactFile(urlMeta, parsedSel, signal);
3071
+ }
3072
+
3073
+ // local:// files are real on-disk paths. Detect image files and emit a
3074
+ // decoded image block before the text-only resource contract UTF-8
3075
+ // decodes the binary into mojibake. The fast path returns null for
3076
+ // non-images, directories, listings, or any resolution failure, so the
3077
+ // text path below reproduces the router's not-found / symlink-escape
3078
+ // behavior unchanged.
3079
+ if (scheme === "local") {
3080
+ const imageResult = await this.#tryReadLocalImage(urlMeta, signal);
3081
+ if (imageResult) return imageResult;
3082
+ }
3083
+
3084
+ // Reject line selectors when query extraction is used
3085
+ if (hasExtraction && parsedSel.kind !== "none" && parsedSel.kind !== "raw") {
3086
+ throw new ToolError("Cannot combine query extraction with line selectors");
3087
+ }
3088
+
3089
+ // Resolve the internal URL
3090
+ const resource = await internalRouter.resolve(url, {
3091
+ cwd: this.session.cwd,
3092
+ settings: this.session.settings,
3093
+ signal,
3094
+ localProtocolOptions: this.session.localProtocolOptions,
3095
+ skills: this.session.skills,
3096
+ });
3097
+ const details: ReadToolDetails = { resolvedPath: resource.sourcePath, contentType: resource.contentType };
3098
+
3099
+ // If extraction was used, return directly (no pagination)
3100
+ if (hasExtraction) {
3101
+ return toolResult(details).text(resource.content).sourceInternal(url).done();
3102
+ }
3103
+
3104
+ const raw = isRawSelector(parsedSel);
3105
+ if (isMultiRange(parsedSel) && parsedSel.kind === "lines") {
3106
+ return this.#buildInMemoryMultiRangeResult(resource.content, parsedSel.ranges, {
3107
+ details,
3108
+ sourcePath: resource.sourcePath,
3109
+ sourceInternal: url,
3110
+ entityLabel: "resource",
3111
+ immutable: resource.immutable,
3112
+ raw,
3113
+ });
3114
+ }
3115
+
3116
+ const { offset, limit } = selToOffsetLimit(parsedSel);
3117
+ return this.#buildInMemoryTextResult(resource.content, offset, limit, {
3118
+ details,
3119
+ sourcePath: resource.sourcePath,
3120
+ sourceInternal: url,
3121
+ entityLabel: "resource",
3122
+ ignoreResultLimits: scheme === "skill",
3123
+ immutable: resource.immutable,
3124
+ raw,
3125
+ });
3126
+ }
3127
+
3128
+ /**
3129
+ * Fast path for `local://` image files. Resolves the URL to its real
3130
+ * on-disk path with the same realpath + containment checks as
3131
+ * {@link LocalProtocolHandler.resolve} (via {@link resolveLocalUrlToFile}),
3132
+ * and — only when the target is a genuine image — emits a decoded image
3133
+ * block. Returns null for non-images, directories, listings, or any
3134
+ * resolution failure (not-found, symlink escape) so the caller falls back to
3135
+ * normal text resolution, which reproduces the router's errors. Errors from
3136
+ * a confirmed image (too large / unsupported) propagate rather than
3137
+ * degrading into a corrupted text read.
3138
+ */
3139
+ async #tryReadLocalImage(url: InternalUrl, signal?: AbortSignal): Promise<AgentToolResult<ReadToolDetails> | null> {
3140
+ let file: { path: string; size: number } | null;
3141
+ try {
3142
+ file = await resolveLocalUrlToFile(url, {
3143
+ cwd: this.session.cwd,
3144
+ settings: this.session.settings,
3145
+ signal,
3146
+ localProtocolOptions: this.session.localProtocolOptions,
3147
+ });
3148
+ } catch {
3149
+ // Not found / containment escape / no session — let the text path
3150
+ // surface the router's canonical error.
3151
+ return null;
3152
+ }
3153
+ if (!file) return null;
3154
+
3155
+ const imageMetadata = await readImageMetadata(file.path);
3156
+ const mimeType = imageMetadata?.mimeType;
3157
+ if (!mimeType) return null;
3158
+
3159
+ const { content, details, sourcePath } = await this.#loadImageContent({
3160
+ readPath: url.href,
3161
+ absolutePath: file.path,
3162
+ mimeType,
3163
+ imageMetadata,
3164
+ fileSize: file.size,
3165
+ });
3166
+ const resultBuilder = toolResult(details).content(content).sourceInternal(url.href);
3167
+ if (sourcePath) resultBuilder.sourcePath(sourcePath);
3168
+ return resultBuilder.done();
3169
+ }
3170
+
3171
+ /** Read directory contents as a formatted listing */
3172
+ async #readDirectory(
3173
+ absolutePath: string,
3174
+ offset: number | undefined,
3175
+ limit: number | undefined,
3176
+ signal?: AbortSignal,
3177
+ ): Promise<AgentToolResult<ReadToolDetails>> {
3178
+ const READ_DIRECTORY_MAX_DEPTH = 2;
3179
+ const READ_DIRECTORY_CHILD_LIMIT = 12;
3180
+
3181
+ throwIfAborted(signal);
3182
+ let tree: DirectoryTree;
3183
+ try {
3184
+ tree = await buildDirectoryTree(absolutePath, {
3185
+ maxDepth: READ_DIRECTORY_MAX_DEPTH,
3186
+ perDirLimit: READ_DIRECTORY_CHILD_LIMIT,
3187
+ rootLimit: null,
3188
+ // `lineCap` truncates the rendered tree itself, so apply it only when the caller
3189
+ // did not request an offset — otherwise we'd cap the first N lines before slicing.
3190
+ lineCap: offset === undefined && limit !== undefined ? limit : null,
3191
+ });
3192
+ } catch (error) {
3193
+ const message = error instanceof Error ? error.message : String(error);
3194
+ throw new ToolError(`Cannot read directory: ${message}`);
3195
+ }
3196
+ throwIfAborted(signal);
3197
+
3198
+ const output = tree.totalLines <= 1 ? "(empty directory)" : tree.rendered;
3199
+ const details: ReadToolDetails = {
3200
+ isDirectory: true,
3201
+ resolvedPath: tree.rootPath,
3202
+ };
3203
+
3204
+ // Slice the rendered listing when the caller passed an offset/limit. We do this
3205
+ // instead of passing the selector down to `buildDirectoryTree` because the tree
3206
+ // builder lays out entries hierarchically (per-dir caps, recent-then-elided
3207
+ // summaries); line-based slicing operates on the formatted text and matches what
3208
+ // users expect from `:N-M` on long listings.
3209
+ const wantsSlice = offset !== undefined || limit !== undefined;
3210
+ if (wantsSlice) {
3211
+ const allLines = output.split("\n");
3212
+ const start = offset ? Math.max(0, offset - 1) : 0;
3213
+ if (start >= allLines.length) {
3214
+ const suggestion =
3215
+ allLines.length === 0
3216
+ ? "The listing is empty."
3217
+ : `Use :1 to read from the start, or :${allLines.length} to read the last line.`;
3218
+ return toolResult(details)
3219
+ .text(`Line ${start + 1} is beyond end of listing (${allLines.length} lines total). ${suggestion}`)
3220
+ .sourcePath(tree.rootPath)
3221
+ .done();
3222
+ }
3223
+ const end = limit !== undefined ? Math.min(start + limit, allLines.length) : allLines.length;
3224
+ const sliced = allLines.slice(start, end).join("\n");
3225
+ const resultBuilder = toolResult(details).sourcePath(tree.rootPath);
3226
+ let text = sliced;
3227
+ if (end < allLines.length) {
3228
+ const remaining = allLines.length - end;
3229
+ text += `\n\n[${remaining} more lines in listing. Use :${end + 1} to continue]`;
3230
+ }
3231
+ resultBuilder.text(text);
3232
+ if (tree.truncated) {
3233
+ resultBuilder.limits({ resultLimit: 1 });
3234
+ }
3235
+ return resultBuilder.done();
3236
+ }
3237
+
3238
+ const truncation = truncateHead(output, { maxLines: Number.MAX_SAFE_INTEGER });
3239
+ const resultBuilder = toolResult(details).text(truncation.content).sourcePath(tree.rootPath);
3240
+ if (tree.truncated) {
3241
+ resultBuilder.limits({ resultLimit: 1 });
3242
+ }
3243
+ if (truncation.truncated) {
3244
+ resultBuilder.truncation(truncation, { direction: "head" });
3245
+ details.truncation = truncation;
3246
+ }
3247
+
3248
+ return resultBuilder.done();
3249
+ }
3250
+ }
3251
+
3252
+ // =============================================================================
3253
+ // TUI Renderer
3254
+ // =============================================================================
3255
+
3256
+ interface ReadRenderArgs {
3257
+ path?: string;
3258
+ file_path?: string;
3259
+ sel?: string;
3260
+ // Legacy fields from old schema — tolerated for in-flight tool calls during transition
3261
+ offset?: number;
3262
+ limit?: number;
3263
+ raw?: boolean;
3264
+ }
3265
+
3266
+ const INTERNAL_URL_LIKE_RE = /^[a-z][a-z0-9+.-]*:\/\//i;
3267
+
3268
+ function splitReadRenderPath(rawPath: string): { path: string; sel?: string } {
3269
+ if (INTERNAL_URL_LIKE_RE.test(rawPath)) {
3270
+ const internal = splitInternalUrlSel(rawPath);
3271
+ if (internal.sel) return internal;
3272
+ }
3273
+ return splitPathAndSel(rawPath);
3274
+ }
3275
+
3276
+ function firstReadSelectorLine(sel: string | undefined): number | undefined {
3277
+ if (!sel) return undefined;
3278
+ try {
3279
+ const parsed = parseSel(sel);
3280
+ if (parsed.kind !== "lines") return undefined;
3281
+ return parsed.ranges[0].startLine;
3282
+ } catch {
3283
+ return undefined;
3284
+ }
3285
+ }
3286
+
3287
+ /** Absolute fs path the read result actually resolved to, used as the OSC 8 link
3288
+ * target when the structured `resolvedPath` isn't set (the common plain-file and
3289
+ * image reads only record the path in `meta.source`). URL/internal sources are
3290
+ * not fs paths, so only `type: "path"` qualifies. */
3291
+ function readSourceFsPath(details: ReadToolDetails | undefined): string | undefined {
3292
+ const source = details?.meta?.source;
3293
+ return source?.type === "path" ? source.value : undefined;
3294
+ }
3295
+
3296
+ function formatReadPathLink(
3297
+ rawPath: string,
3298
+ options: {
3299
+ resolvedPath?: string;
3300
+ sourcePath?: string;
3301
+ suffixResolution?: { from: string; to: string };
3302
+ offset?: number;
3303
+ fallbackLabel?: string;
3304
+ },
3305
+ ): string {
3306
+ const split = splitReadRenderPath(rawPath);
3307
+ const basePath = split.path || rawPath;
3308
+ const selectorSuffix = split.sel ? `:${split.sel}` : "";
3309
+ const plainDisplayPath = options.suffixResolution
3310
+ ? shortenPath(options.suffixResolution.to)
3311
+ : shortenPath(basePath || options.resolvedPath || options.fallbackLabel || rawPath);
3312
+ const absoluteInputPath = path.isAbsolute(basePath) ? basePath : undefined;
3313
+ const target =
3314
+ options.resolvedPath ?? options.sourcePath ?? tryResolveInternalUrlSync(basePath) ?? absoluteInputPath;
3315
+ const line = firstReadSelectorLine(split.sel) ?? options.offset;
3316
+ const linkOptions = line !== undefined ? { line } : undefined;
3317
+ const linkedPath = target ? fileHyperlink(target, plainDisplayPath, linkOptions) : plainDisplayPath;
3318
+ return `${linkedPath}${selectorSuffix}`;
3319
+ }
3320
+
3321
+ export const readToolRenderer = {
3322
+ renderCall(args: ReadRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
3323
+ if (isReadableUrlPath(args.file_path || args.path || "")) {
3324
+ return renderReadUrlCall(args, _options, uiTheme);
3325
+ }
3326
+
3327
+ const rawPath = args.file_path || args.path || "";
3328
+ const offset = args.offset;
3329
+ const limit = args.limit;
3330
+
3331
+ let pathDisplay = formatReadPathLink(rawPath, { offset, fallbackLabel: "…" }) || "…";
3332
+ if (offset !== undefined || limit !== undefined) {
3333
+ const startLine = offset ?? 1;
3334
+ const endLine = limit !== undefined ? startLine + limit - 1 : "";
3335
+ pathDisplay += `:${startLine}${endLine ? `-${endLine}` : ""}`;
3336
+ }
3337
+
3338
+ const text = renderStatusLine({ icon: "pending", title: "Read", description: pathDisplay }, uiTheme);
3339
+ return new Text(text, 0, 0);
3340
+ },
3341
+
3342
+ renderResult(
3343
+ result: { content: Array<{ type: string; text?: string }>; details?: ReadToolDetails; isError?: boolean },
3344
+ options: RenderResultOptions,
3345
+ uiTheme: Theme,
3346
+ args?: ReadRenderArgs,
3347
+ ): Component {
3348
+ const urlDetails = result.details as ReadUrlToolDetails | undefined;
3349
+ if (urlDetails?.kind === "url" || isReadableUrlPath(args?.file_path || args?.path || "")) {
3350
+ return renderReadUrlResult(
3351
+ result as {
3352
+ content: Array<{ type: string; text?: string }>;
3353
+ details?: ReadUrlToolDetails;
3354
+ isError?: boolean;
3355
+ },
3356
+ options,
3357
+ uiTheme,
3358
+ );
3359
+ }
3360
+
3361
+ if (result.isError) {
3362
+ const rawErrorText = result.content?.find(c => c.type === "text")?.text ?? "";
3363
+ const errorText = (rawErrorText || "Unknown error").replace(/^Error:\s*/, "");
3364
+ const rawPath = args?.file_path || args?.path || "";
3365
+ const filePath =
3366
+ formatReadPathLink(rawPath, { offset: args?.offset, sourcePath: readSourceFsPath(result.details) }) ||
3367
+ shortenPath(rawPath);
3368
+ let title = filePath ? `Read ${filePath}` : "Read";
3369
+ if (args?.offset !== undefined || args?.limit !== undefined) {
3370
+ const startLine = args.offset ?? 1;
3371
+ const endLine = args.limit !== undefined ? startLine + args.limit - 1 : "";
3372
+ title += `:${startLine}${endLine ? `-${endLine}` : ""}`;
3373
+ }
3374
+ const header = renderStatusLine({ icon: "error", title }, uiTheme);
3375
+ const errorLines = errorText.split("\n").map(line => uiTheme.fg("error", replaceTabs(line)));
3376
+ const outputBlock = new CachedOutputBlock();
3377
+ return markFramedBlockComponent({
3378
+ render: (width: number) =>
3379
+ outputBlock.render({ header, state: "error", sections: [{ lines: errorLines }], width }, uiTheme),
3380
+ invalidate: () => outputBlock.invalidate(),
3381
+ });
3382
+ }
3383
+ const details = result.details;
3384
+ const rawText = result.content?.find(c => c.type === "text")?.text ?? "";
3385
+ // Prefer structured `displayContent` from details when available so the TUI
3386
+ // shows clean file content (no model-only hashline anchors) without parsing the formatted text.
3387
+ // Fall back to the raw text, but strip the LLM-facing notice so it doesn't
3388
+ // echo next to the styled warning line below.
3389
+ const contentText = details?.displayContent?.text ?? stripOutputNotice(rawText, details?.meta);
3390
+ const imageContent = result.content?.find(c => c.type === "image");
3391
+ const rawPath = args?.file_path || args?.path || "";
3392
+ const renderPath = splitReadRenderPath(rawPath);
3393
+ const lang = getLanguageFromPath(renderPath.path);
3394
+
3395
+ const warningLines: string[] = [];
3396
+ const truncation = details?.meta?.truncation;
3397
+ const fallback = details?.truncation;
3398
+ if (details?.resolvedPath) {
3399
+ warningLines.push(uiTheme.fg("dim", wrapBrackets(`Resolved path: ${details.resolvedPath}`, uiTheme)));
3400
+ }
3401
+ if (truncation) {
3402
+ if (fallback?.firstLineExceedsLimit) {
3403
+ let warning = `First line exceeds ${formatBytes(fallback.outputBytes ?? fallback.totalBytes)} limit`;
3404
+ if (truncation.artifactId) {
3405
+ warning += `. ${formatFullOutputReference(truncation.artifactId)}`;
3406
+ }
3407
+ warningLines.push(uiTheme.fg("warning", wrapBrackets(warning, uiTheme)));
3408
+ } else {
3409
+ const warning = formatStyledTruncationWarning(details?.meta, uiTheme);
3410
+ if (warning) warningLines.push(warning);
3411
+ }
3412
+ }
3413
+
3414
+ if (imageContent) {
3415
+ const suffix = details?.suffixResolution;
3416
+ const displayPath = formatReadPathLink(rawPath, {
3417
+ resolvedPath: details?.resolvedPath,
3418
+ sourcePath: readSourceFsPath(details),
3419
+ suffixResolution: suffix,
3420
+ fallbackLabel: "image",
3421
+ });
3422
+ const correction = suffix ? ` ${uiTheme.fg("dim", `(corrected from ${shortenPath(suffix.from)})`)}` : "";
3423
+ const header = renderStatusLine(
3424
+ { icon: suffix ? "warning" : "success", title: "Read", description: `${displayPath}${correction}` },
3425
+ uiTheme,
3426
+ );
3427
+ const detailLines = contentText ? contentText.split("\n").map(line => uiTheme.fg("toolOutput", line)) : [];
3428
+ const lines = [...detailLines, ...warningLines];
3429
+ const outputBlock = new CachedOutputBlock();
3430
+ return markFramedBlockComponent({
3431
+ render: (width: number) =>
3432
+ outputBlock.render(
3433
+ {
3434
+ header,
3435
+ state: "success",
3436
+ sections: [
3437
+ {
3438
+ label: uiTheme.fg("toolTitle", "Details"),
3439
+ lines: lines.length > 0 ? lines : [uiTheme.fg("dim", "(image)")],
3440
+ },
3441
+ ],
3442
+ width,
3443
+ },
3444
+ uiTheme,
3445
+ ),
3446
+ invalidate: () => outputBlock.invalidate(),
3447
+ });
3448
+ }
3449
+
3450
+ const suffix = details?.suffixResolution;
3451
+ // resolvedPath is the absolute fs path when a read resolved/corrected the
3452
+ // input (suffix match, internal URL, archive/sqlite/notebook); plain file
3453
+ // reads only record the absolute path in meta.source, so fall back to that
3454
+ // (and then to a sync internal-URL resolver) to keep the title clickable.
3455
+ const displayPath = formatReadPathLink(rawPath, {
3456
+ resolvedPath: details?.resolvedPath,
3457
+ sourcePath: readSourceFsPath(details),
3458
+ suffixResolution: suffix,
3459
+ offset: args?.offset,
3460
+ });
3461
+ const correction = suffix ? ` ${uiTheme.fg("dim", `(corrected from ${shortenPath(suffix.from)})`)}` : "";
3462
+ let title = displayPath ? `Read ${displayPath}${correction}` : "Read";
3463
+ if (args?.offset !== undefined || args?.limit !== undefined) {
3464
+ const startLine = args.offset ?? 1;
3465
+ const endLine = args.limit !== undefined ? startLine + args.limit - 1 : "";
3466
+ title += `:${startLine}${endLine ? `-${endLine}` : ""}`;
3467
+ }
3468
+ if (details?.summary) {
3469
+ title += ` (summary: ${details.summary.elidedSpans} elided span${details.summary.elidedSpans === 1 ? "" : "s"})`;
3470
+ }
3471
+ if (details?.conflictCount && details.conflictCount > 0) {
3472
+ const n = details.conflictCount;
3473
+ title += ` ${uiTheme.fg("warning", `(⚠ ${n} conflict${n === 1 ? "" : "s"})`)}`;
3474
+ }
3475
+ const rawRequested = args?.raw === true || isRawSelector(parseSel(renderPath.sel));
3476
+ const isMarkdown = details?.contentType === "text/markdown" && !rawRequested;
3477
+ let cachedWidth: number | undefined;
3478
+ let cachedExpanded: boolean | undefined;
3479
+ let cachedLines: string[] | undefined;
3480
+ return markFramedBlockComponent({
3481
+ render: (width: number) => {
3482
+ const expanded = options.expanded;
3483
+ if (cachedLines && cachedWidth === width && cachedExpanded === expanded) return cachedLines;
3484
+ cachedLines = isMarkdown
3485
+ ? renderMarkdownCell(
3486
+ {
3487
+ content: contentText,
3488
+ title,
3489
+ status: "complete",
3490
+ output: warningLines.length > 0 ? warningLines.join("\n") : undefined,
3491
+ expanded,
3492
+ width,
3493
+ },
3494
+ uiTheme,
3495
+ )
3496
+ : renderCodeCell(
3497
+ {
3498
+ code: contentText,
3499
+ language: lang,
3500
+ title,
3501
+ status: "complete",
3502
+ output: warningLines.length > 0 ? warningLines.join("\n") : undefined,
3503
+ expanded,
3504
+ codeStartLine: details?.displayContent?.startLine,
3505
+ codeLineNumbers: details?.displayContent?.lineNumbers,
3506
+ width,
3507
+ },
3508
+ uiTheme,
3509
+ );
3510
+ cachedWidth = width;
3511
+ cachedExpanded = expanded;
3512
+ return cachedLines;
3513
+ },
3514
+ invalidate: () => {
3515
+ cachedWidth = undefined;
3516
+ cachedExpanded = undefined;
3517
+ cachedLines = undefined;
3518
+ },
3519
+ });
3520
+ },
3521
+ mergeCallAndResult: true,
3522
+ };