@humain/terminal 0.0.4-beta.1 → 0.0.5

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 (675) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1 -0
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js.map +1 -1
  5. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  6. package/dist/bun/restore-sandbox-env.js.map +1 -1
  7. package/dist/cli/args.d.ts +1 -0
  8. package/dist/cli/args.d.ts.map +1 -1
  9. package/dist/cli/args.js +11 -0
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/auth-check.d.ts.map +1 -1
  12. package/dist/cli/auth-check.js.map +1 -1
  13. package/dist/cli/auth-command.d.ts.map +1 -1
  14. package/dist/cli/auth-command.js.map +1 -1
  15. package/dist/cli/config-selector.d.ts.map +1 -1
  16. package/dist/cli/config-selector.js.map +1 -1
  17. package/dist/cli/credential-print.d.ts.map +1 -1
  18. package/dist/cli/credential-print.js.map +1 -1
  19. package/dist/cli/experimental/auth.d.ts.map +1 -1
  20. package/dist/cli/experimental/auth.js.map +1 -1
  21. package/dist/cli/experimental/cli.d.ts.map +1 -1
  22. package/dist/cli/experimental/command-options.d.ts.map +1 -1
  23. package/dist/cli/experimental/command-options.js.map +1 -1
  24. package/dist/cli/experimental/command.d.ts.map +1 -1
  25. package/dist/cli/experimental/command.js +2 -5
  26. package/dist/cli/experimental/command.js.map +1 -1
  27. package/dist/cli/experimental/commands/client.d.ts.map +1 -1
  28. package/dist/cli/experimental/commands/client.js.map +1 -1
  29. package/dist/cli/experimental/commands/pi.d.ts.map +1 -1
  30. package/dist/cli/experimental/commands/pi.js.map +1 -1
  31. package/dist/cli/experimental/commands/server.d.ts.map +1 -1
  32. package/dist/cli/experimental/commands/server.js.map +1 -1
  33. package/dist/cli/experimental/transport-address.d.ts.map +1 -1
  34. package/dist/cli/experimental/transport-address.js.map +1 -1
  35. package/dist/cli/file-processor.d.ts.map +1 -1
  36. package/dist/cli/file-processor.js.map +1 -1
  37. package/dist/cli/initial-message.d.ts +1 -1
  38. package/dist/cli/initial-message.d.ts.map +1 -1
  39. package/dist/cli/initial-message.js.map +1 -1
  40. package/dist/cli/list-models.d.ts.map +1 -1
  41. package/dist/cli/list-models.js.map +1 -1
  42. package/dist/cli/project-trust.d.ts.map +1 -1
  43. package/dist/cli/project-trust.js.map +1 -1
  44. package/dist/cli/session-picker.d.ts.map +1 -1
  45. package/dist/cli/session-picker.js.map +1 -1
  46. package/dist/cli/startup-ui.d.ts.map +1 -1
  47. package/dist/cli/startup-ui.js.map +1 -1
  48. package/dist/cli.d.ts.map +1 -1
  49. package/dist/cli.js.map +1 -1
  50. package/dist/client/index.d.ts.map +1 -1
  51. package/dist/client/remote-session.d.ts.map +1 -1
  52. package/dist/client/remote-session.js.map +1 -1
  53. package/dist/client/transcript.d.ts.map +1 -1
  54. package/dist/client/transcript.js +1 -1
  55. package/dist/client/transcript.js.map +1 -1
  56. package/dist/config.d.ts.map +1 -1
  57. package/dist/config.js.map +1 -1
  58. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  59. package/dist/core/agent-session-runtime.js +0 -8
  60. package/dist/core/agent-session-runtime.js.map +1 -1
  61. package/dist/core/agent-session-services.d.ts.map +1 -1
  62. package/dist/core/agent-session-services.js.map +1 -1
  63. package/dist/core/agent-session.d.ts +36 -2
  64. package/dist/core/agent-session.d.ts.map +1 -1
  65. package/dist/core/agent-session.js +100 -128
  66. package/dist/core/agent-session.js.map +1 -1
  67. package/dist/core/auth-guidance.d.ts.map +1 -1
  68. package/dist/core/auth-guidance.js.map +1 -1
  69. package/dist/core/auth-storage.d.ts.map +1 -1
  70. package/dist/core/auth-storage.js +3 -8
  71. package/dist/core/auth-storage.js.map +1 -1
  72. package/dist/core/bash-executor.d.ts.map +1 -1
  73. package/dist/core/bash-executor.js.map +1 -1
  74. package/dist/core/cache-stats.d.ts.map +1 -1
  75. package/dist/core/cache-stats.js.map +1 -1
  76. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  77. package/dist/core/compaction/branch-summarization.js.map +1 -1
  78. package/dist/core/compaction/compaction.d.ts.map +1 -1
  79. package/dist/core/compaction/compaction.js.map +1 -1
  80. package/dist/core/compaction/index.d.ts.map +1 -1
  81. package/dist/core/compaction/utils.d.ts.map +1 -1
  82. package/dist/core/compaction/utils.js.map +1 -1
  83. package/dist/core/defaults.d.ts.map +1 -1
  84. package/dist/core/diagnostics.d.ts.map +1 -1
  85. package/dist/core/event-bus.d.ts.map +1 -1
  86. package/dist/core/event-bus.js.map +1 -1
  87. package/dist/core/exec.d.ts.map +1 -1
  88. package/dist/core/exec.js.map +1 -1
  89. package/dist/core/experimental.d.ts +4 -0
  90. package/dist/core/experimental.d.ts.map +1 -1
  91. package/dist/core/experimental.js +4 -0
  92. package/dist/core/experimental.js.map +1 -1
  93. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  94. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  95. package/dist/core/export-html/index.d.ts.map +1 -1
  96. package/dist/core/export-html/index.js.map +1 -1
  97. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  98. package/dist/core/export-html/tool-renderer.js.map +1 -1
  99. package/dist/core/extensions/index.d.ts.map +1 -1
  100. package/dist/core/extensions/loader.d.ts.map +1 -1
  101. package/dist/core/extensions/loader.js.map +1 -1
  102. package/dist/core/extensions/runner.d.ts.map +1 -1
  103. package/dist/core/extensions/runner.js +22 -30
  104. package/dist/core/extensions/runner.js.map +1 -1
  105. package/dist/core/extensions/types.d.ts +4 -0
  106. package/dist/core/extensions/types.d.ts.map +1 -1
  107. package/dist/core/extensions/types.js.map +1 -1
  108. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  109. package/dist/core/extensions/wrapper.js.map +1 -1
  110. package/dist/core/footer-data-provider.d.ts.map +1 -1
  111. package/dist/core/footer-data-provider.js +17 -18
  112. package/dist/core/footer-data-provider.js.map +1 -1
  113. package/dist/core/http-dispatcher.d.ts.map +1 -1
  114. package/dist/core/http-dispatcher.js.map +1 -1
  115. package/dist/core/index.d.ts.map +1 -1
  116. package/dist/core/keybindings.d.ts +24 -0
  117. package/dist/core/keybindings.d.ts.map +1 -1
  118. package/dist/core/keybindings.js +0 -1
  119. package/dist/core/keybindings.js.map +1 -1
  120. package/dist/core/messages.d.ts.map +1 -1
  121. package/dist/core/messages.js.map +1 -1
  122. package/dist/core/model-config.d.ts +5 -0
  123. package/dist/core/model-config.d.ts.map +1 -1
  124. package/dist/core/model-config.js +1 -2
  125. package/dist/core/model-config.js.map +1 -1
  126. package/dist/core/model-registry.d.ts.map +1 -1
  127. package/dist/core/model-registry.js +0 -1
  128. package/dist/core/model-registry.js.map +1 -1
  129. package/dist/core/model-resolver.d.ts.map +1 -1
  130. package/dist/core/model-resolver.js.map +1 -1
  131. package/dist/core/model-runtime.d.ts.map +1 -1
  132. package/dist/core/model-runtime.js +15 -25
  133. package/dist/core/model-runtime.js.map +1 -1
  134. package/dist/core/models-store.d.ts.map +1 -1
  135. package/dist/core/models-store.js +3 -4
  136. package/dist/core/models-store.js.map +1 -1
  137. package/dist/core/output-guard.d.ts.map +1 -1
  138. package/dist/core/output-guard.js.map +1 -1
  139. package/dist/core/package-manager.d.ts.map +1 -1
  140. package/dist/core/package-manager.js +0 -7
  141. package/dist/core/package-manager.js.map +1 -1
  142. package/dist/core/pi-manifest.d.ts.map +1 -1
  143. package/dist/core/pi-manifest.js.map +1 -1
  144. package/dist/core/project-trust.d.ts.map +1 -1
  145. package/dist/core/project-trust.js.map +1 -1
  146. package/dist/core/prompt-templates.d.ts.map +1 -1
  147. package/dist/core/prompt-templates.js.map +1 -1
  148. package/dist/core/provider-attribution.d.ts.map +1 -1
  149. package/dist/core/provider-attribution.js.map +1 -1
  150. package/dist/core/provider-composer.d.ts.map +1 -1
  151. package/dist/core/provider-composer.js.map +1 -1
  152. package/dist/core/radius.d.ts.map +1 -1
  153. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  154. package/dist/core/remote-catalog-provider.js.map +1 -1
  155. package/dist/core/resolve-config-value.d.ts.map +1 -1
  156. package/dist/core/resolve-config-value.js.map +1 -1
  157. package/dist/core/resource-loader.d.ts.map +1 -1
  158. package/dist/core/resource-loader.js +0 -44
  159. package/dist/core/resource-loader.js.map +1 -1
  160. package/dist/core/runtime-credentials.d.ts.map +1 -1
  161. package/dist/core/runtime-credentials.js +1 -2
  162. package/dist/core/runtime-credentials.js.map +1 -1
  163. package/dist/core/sdk.d.ts +5 -3
  164. package/dist/core/sdk.d.ts.map +1 -1
  165. package/dist/core/sdk.js +2 -1
  166. package/dist/core/sdk.js.map +1 -1
  167. package/dist/core/session-cwd.d.ts.map +1 -1
  168. package/dist/core/session-cwd.js +0 -1
  169. package/dist/core/session-cwd.js.map +1 -1
  170. package/dist/core/session-manager.d.ts.map +1 -1
  171. package/dist/core/session-manager.js +9 -13
  172. package/dist/core/session-manager.js.map +1 -1
  173. package/dist/core/settings-manager.d.ts +6 -0
  174. package/dist/core/settings-manager.d.ts.map +1 -1
  175. package/dist/core/settings-manager.js +19 -17
  176. package/dist/core/settings-manager.js.map +1 -1
  177. package/dist/core/skills.d.ts.map +1 -1
  178. package/dist/core/skills.js.map +1 -1
  179. package/dist/core/slash-commands.d.ts.map +1 -1
  180. package/dist/core/source-info.d.ts.map +1 -1
  181. package/dist/core/source-info.js.map +1 -1
  182. package/dist/core/system-prompt.d.ts.map +1 -1
  183. package/dist/core/system-prompt.js +1 -1
  184. package/dist/core/system-prompt.js.map +1 -1
  185. package/dist/core/telemetry.d.ts.map +1 -1
  186. package/dist/core/telemetry.js.map +1 -1
  187. package/dist/core/timings.d.ts.map +1 -1
  188. package/dist/core/timings.js.map +1 -1
  189. package/dist/core/tools/bash.d.ts.map +1 -1
  190. package/dist/core/tools/bash.js +10 -5
  191. package/dist/core/tools/bash.js.map +1 -1
  192. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  193. package/dist/core/tools/edit-diff.js.map +1 -1
  194. package/dist/core/tools/edit.d.ts.map +1 -1
  195. package/dist/core/tools/edit.js +2 -0
  196. package/dist/core/tools/edit.js.map +1 -1
  197. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  198. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  199. package/dist/core/tools/find.d.ts +1 -1
  200. package/dist/core/tools/find.d.ts.map +1 -1
  201. package/dist/core/tools/find.js +1 -1
  202. package/dist/core/tools/find.js.map +1 -1
  203. package/dist/core/tools/grep.d.ts.map +1 -1
  204. package/dist/core/tools/grep.js +1 -1
  205. package/dist/core/tools/grep.js.map +1 -1
  206. package/dist/core/tools/index.d.ts.map +1 -1
  207. package/dist/core/tools/index.js.map +1 -1
  208. package/dist/core/tools/ls.d.ts.map +1 -1
  209. package/dist/core/tools/ls.js.map +1 -1
  210. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  211. package/dist/core/tools/output-accumulator.js +12 -18
  212. package/dist/core/tools/output-accumulator.js.map +1 -1
  213. package/dist/core/tools/path-utils.d.ts.map +1 -1
  214. package/dist/core/tools/path-utils.js.map +1 -1
  215. package/dist/core/tools/read.d.ts.map +1 -1
  216. package/dist/core/tools/read.js +2 -0
  217. package/dist/core/tools/read.js.map +1 -1
  218. package/dist/core/tools/render-utils.d.ts.map +1 -1
  219. package/dist/core/tools/render-utils.js.map +1 -1
  220. package/dist/core/tools/subagent.d.ts +3 -0
  221. package/dist/core/tools/subagent.d.ts.map +1 -1
  222. package/dist/core/tools/subagent.js +30 -9
  223. package/dist/core/tools/subagent.js.map +1 -1
  224. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  225. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  226. package/dist/core/tools/truncate.d.ts.map +1 -1
  227. package/dist/core/tools/truncate.js.map +1 -1
  228. package/dist/core/tools/write.d.ts.map +1 -1
  229. package/dist/core/tools/write.js +2 -1
  230. package/dist/core/tools/write.js.map +1 -1
  231. package/dist/core/trust-manager.d.ts.map +1 -1
  232. package/dist/core/trust-manager.js +0 -1
  233. package/dist/core/trust-manager.js.map +1 -1
  234. package/dist/core/usage-totals.d.ts.map +1 -1
  235. package/dist/core/usage-totals.js.map +1 -1
  236. package/dist/extensions/index.d.ts.map +1 -1
  237. package/dist/extensions/llama/client.d.ts.map +1 -1
  238. package/dist/extensions/llama/client.js +0 -2
  239. package/dist/extensions/llama/client.js.map +1 -1
  240. package/dist/extensions/llama/huggingface.d.ts.map +1 -1
  241. package/dist/extensions/llama/huggingface.js +0 -2
  242. package/dist/extensions/llama/huggingface.js.map +1 -1
  243. package/dist/extensions/llama/index.d.ts.map +1 -1
  244. package/dist/extensions/llama/index.js.map +1 -1
  245. package/dist/extensions/llama/provider.d.ts.map +1 -1
  246. package/dist/extensions/llama/provider.js.map +1 -1
  247. package/dist/extensions/llama/ui.d.ts.map +1 -1
  248. package/dist/extensions/llama/ui.js +12 -28
  249. package/dist/extensions/llama/ui.js.map +1 -1
  250. package/dist/humain/agent-execution-protocol.d.ts.map +1 -1
  251. package/dist/humain/agent-execution-protocol.js.map +1 -1
  252. package/dist/humain/agent-execution-runtime.d.ts.map +1 -1
  253. package/dist/humain/agent-execution-runtime.js.map +1 -1
  254. package/dist/humain/bedrock-provider/vendor/index.bundle.mjs +127 -7
  255. package/dist/humain/brand-logo.d.ts.map +1 -1
  256. package/dist/humain/index.d.ts.map +1 -1
  257. package/dist/humain/index.js.map +1 -1
  258. package/dist/humain/legacy-workflow-tiers.d.ts.map +1 -1
  259. package/dist/humain/legacy-workflow-tiers.js.map +1 -1
  260. package/dist/humain/mcp-adapter/vendor/package.json +3 -3
  261. package/dist/humain/mcp-adapter.d.ts.map +1 -1
  262. package/dist/humain/mcp-adapter.js.map +1 -1
  263. package/dist/humain/pi-agent-execution-host.d.ts.map +1 -1
  264. package/dist/humain/pi-agent-execution-host.js.map +1 -1
  265. package/dist/humain/web-access/host.d.ts.map +1 -1
  266. package/dist/humain/web-access/index.d.ts.map +1 -1
  267. package/dist/humain/web-access/index.js.map +1 -1
  268. package/dist/humain/web-access/vendor/activity.d.ts.map +1 -1
  269. package/dist/humain/web-access/vendor/activity.js +7 -5
  270. package/dist/humain/web-access/vendor/activity.js.map +1 -1
  271. package/dist/humain/web-access/vendor/anysearch.d.ts.map +1 -1
  272. package/dist/humain/web-access/vendor/anysearch.js.map +1 -1
  273. package/dist/humain/web-access/vendor/auth-fetch.d.ts.map +1 -1
  274. package/dist/humain/web-access/vendor/auth-fetch.js.map +1 -1
  275. package/dist/humain/web-access/vendor/bocha.d.ts.map +1 -1
  276. package/dist/humain/web-access/vendor/bocha.js.map +1 -1
  277. package/dist/humain/web-access/vendor/brave.d.ts.map +1 -1
  278. package/dist/humain/web-access/vendor/brave.js.map +1 -1
  279. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts.map +1 -1
  280. package/dist/humain/web-access/vendor/brightdata-unlocker.js.map +1 -1
  281. package/dist/humain/web-access/vendor/brightdata.d.ts.map +1 -1
  282. package/dist/humain/web-access/vendor/brightdata.js.map +1 -1
  283. package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -1
  284. package/dist/humain/web-access/vendor/chrome-cookies.js +101 -19
  285. package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -1
  286. package/dist/humain/web-access/vendor/content-find.d.ts.map +1 -1
  287. package/dist/humain/web-access/vendor/content-find.js.map +1 -1
  288. package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -1
  289. package/dist/humain/web-access/vendor/credential-source.js +0 -2
  290. package/dist/humain/web-access/vendor/credential-source.js.map +1 -1
  291. package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
  292. package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
  293. package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
  294. package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
  295. package/dist/humain/web-access/vendor/data-uri-sanitize.d.ts +21 -0
  296. package/dist/humain/web-access/vendor/data-uri-sanitize.d.ts.map +1 -0
  297. package/dist/humain/web-access/vendor/data-uri-sanitize.js +373 -0
  298. package/dist/humain/web-access/vendor/data-uri-sanitize.js.map +1 -0
  299. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts.map +1 -1
  300. package/dist/humain/web-access/vendor/datalab-pdf-extract.js.map +1 -1
  301. package/dist/humain/web-access/vendor/declared-web-links.d.ts.map +1 -1
  302. package/dist/humain/web-access/vendor/declared-web-links.js.map +1 -1
  303. package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -1
  304. package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -1
  305. package/dist/humain/web-access/vendor/exa.d.ts.map +1 -1
  306. package/dist/humain/web-access/vendor/exa.js.map +1 -1
  307. package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
  308. package/dist/humain/web-access/vendor/extract.js +14 -2
  309. package/dist/humain/web-access/vendor/extract.js.map +1 -1
  310. package/dist/humain/web-access/vendor/feature-config.d.ts.map +1 -1
  311. package/dist/humain/web-access/vendor/feature-config.js.map +1 -1
  312. package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -1
  313. package/dist/humain/web-access/vendor/fetch-params.js.map +1 -1
  314. package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -1
  315. package/dist/humain/web-access/vendor/firecrawl.js +15 -2
  316. package/dist/humain/web-access/vendor/firecrawl.js.map +1 -1
  317. package/dist/humain/web-access/vendor/gemini-api.d.ts.map +1 -1
  318. package/dist/humain/web-access/vendor/gemini-api.js.map +1 -1
  319. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts.map +1 -1
  320. package/dist/humain/web-access/vendor/gemini-pdf-extract.js.map +1 -1
  321. package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
  322. package/dist/humain/web-access/vendor/gemini-search.js +30 -16
  323. package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
  324. package/dist/humain/web-access/vendor/gemini-url-context.d.ts.map +1 -1
  325. package/dist/humain/web-access/vendor/gemini-url-context.js.map +1 -1
  326. package/dist/humain/web-access/vendor/gemini-web-config.d.ts.map +1 -1
  327. package/dist/humain/web-access/vendor/gemini-web-config.js.map +1 -1
  328. package/dist/humain/web-access/vendor/gemini-web.d.ts.map +1 -1
  329. package/dist/humain/web-access/vendor/gemini-web.js.map +1 -1
  330. package/dist/humain/web-access/vendor/github-api.d.ts.map +1 -1
  331. package/dist/humain/web-access/vendor/github-api.js.map +1 -1
  332. package/dist/humain/web-access/vendor/github-extract.d.ts.map +1 -1
  333. package/dist/humain/web-access/vendor/github-extract.js +69 -35
  334. package/dist/humain/web-access/vendor/github-extract.js.map +1 -1
  335. package/dist/humain/web-access/vendor/index.d.ts +74 -1
  336. package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
  337. package/dist/humain/web-access/vendor/index.js +38 -15
  338. package/dist/humain/web-access/vendor/index.js.map +1 -1
  339. package/dist/humain/web-access/vendor/jina-search.d.ts.map +1 -1
  340. package/dist/humain/web-access/vendor/jina-search.js.map +1 -1
  341. package/dist/humain/web-access/vendor/kagi.d.ts.map +1 -1
  342. package/dist/humain/web-access/vendor/kagi.js.map +1 -1
  343. package/dist/humain/web-access/vendor/ollama.d.ts.map +1 -1
  344. package/dist/humain/web-access/vendor/ollama.js.map +1 -1
  345. package/dist/humain/web-access/vendor/openai-search.d.ts +1 -1
  346. package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -1
  347. package/dist/humain/web-access/vendor/openai-search.js +15 -5
  348. package/dist/humain/web-access/vendor/openai-search.js.map +1 -1
  349. package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -1
  350. package/dist/humain/web-access/vendor/page-query.js.map +1 -1
  351. package/dist/humain/web-access/vendor/parallel-mcp.d.ts.map +1 -1
  352. package/dist/humain/web-access/vendor/parallel-mcp.js.map +1 -1
  353. package/dist/humain/web-access/vendor/parallel.d.ts.map +1 -1
  354. package/dist/humain/web-access/vendor/parallel.js.map +1 -1
  355. package/dist/humain/web-access/vendor/pdf-extract.d.ts +1 -0
  356. package/dist/humain/web-access/vendor/pdf-extract.d.ts.map +1 -1
  357. package/dist/humain/web-access/vendor/pdf-extract.js +15 -5
  358. package/dist/humain/web-access/vendor/pdf-extract.js.map +1 -1
  359. package/dist/humain/web-access/vendor/perplexity.d.ts.map +1 -1
  360. package/dist/humain/web-access/vendor/perplexity.js.map +1 -1
  361. package/dist/humain/web-access/vendor/querit.d.ts.map +1 -1
  362. package/dist/humain/web-access/vendor/querit.js.map +1 -1
  363. package/dist/humain/web-access/vendor/query-rewrite.d.ts.map +1 -1
  364. package/dist/humain/web-access/vendor/query-rewrite.js.map +1 -1
  365. package/dist/humain/web-access/vendor/render-search-error.d.ts.map +1 -1
  366. package/dist/humain/web-access/vendor/render-search-error.js.map +1 -1
  367. package/dist/humain/web-access/vendor/rsc-extract.d.ts.map +1 -1
  368. package/dist/humain/web-access/vendor/rsc-extract.js.map +1 -1
  369. package/dist/humain/web-access/vendor/search1api.d.ts.map +1 -1
  370. package/dist/humain/web-access/vendor/search1api.js.map +1 -1
  371. package/dist/humain/web-access/vendor/searchinfinity.d.ts.map +1 -1
  372. package/dist/humain/web-access/vendor/searchinfinity.js.map +1 -1
  373. package/dist/humain/web-access/vendor/searxng.d.ts.map +1 -1
  374. package/dist/humain/web-access/vendor/searxng.js.map +1 -1
  375. package/dist/humain/web-access/vendor/serpbase.d.ts.map +1 -1
  376. package/dist/humain/web-access/vendor/serpbase.js.map +1 -1
  377. package/dist/humain/web-access/vendor/serpdive.d.ts.map +1 -1
  378. package/dist/humain/web-access/vendor/serpdive.js.map +1 -1
  379. package/dist/humain/web-access/vendor/serper.d.ts.map +1 -1
  380. package/dist/humain/web-access/vendor/serper.js.map +1 -1
  381. package/dist/humain/web-access/vendor/source-check.d.ts.map +1 -1
  382. package/dist/humain/web-access/vendor/source-check.js.map +1 -1
  383. package/dist/humain/web-access/vendor/ssrf-protection.d.ts +2 -0
  384. package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -1
  385. package/dist/humain/web-access/vendor/ssrf-protection.js +11 -2
  386. package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -1
  387. package/dist/humain/web-access/vendor/storage.d.ts.map +1 -1
  388. package/dist/humain/web-access/vendor/storage.js.map +1 -1
  389. package/dist/humain/web-access/vendor/summary-model-scope.d.ts.map +1 -1
  390. package/dist/humain/web-access/vendor/summary-model-scope.js.map +1 -1
  391. package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -1
  392. package/dist/humain/web-access/vendor/summary-review.js.map +1 -1
  393. package/dist/humain/web-access/vendor/tavily.d.ts.map +1 -1
  394. package/dist/humain/web-access/vendor/tavily.js.map +1 -1
  395. package/dist/humain/web-access/vendor/tinyfish.d.ts.map +1 -1
  396. package/dist/humain/web-access/vendor/tinyfish.js.map +1 -1
  397. package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
  398. package/dist/humain/web-access/vendor/utils.js.map +1 -1
  399. package/dist/humain/web-access/vendor/valyu.d.ts.map +1 -1
  400. package/dist/humain/web-access/vendor/valyu.js.map +1 -1
  401. package/dist/humain/web-access/vendor/video-extract.d.ts.map +1 -1
  402. package/dist/humain/web-access/vendor/video-extract.js.map +1 -1
  403. package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -1
  404. package/dist/humain/web-access/vendor/xai-search.js.map +1 -1
  405. package/dist/humain/web-access/vendor/youtube-extract.d.ts.map +1 -1
  406. package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -1
  407. package/dist/index.d.ts +1 -1
  408. package/dist/index.d.ts.map +1 -1
  409. package/dist/index.js.map +1 -1
  410. package/dist/main.d.ts.map +1 -1
  411. package/dist/main.js +4 -0
  412. package/dist/main.js.map +1 -1
  413. package/dist/migrations.d.ts.map +1 -1
  414. package/dist/migrations.js.map +1 -1
  415. package/dist/modes/agent-exec-mode.d.ts.map +1 -1
  416. package/dist/modes/agent-exec-mode.js.map +1 -1
  417. package/dist/modes/index.d.ts.map +1 -1
  418. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  419. package/dist/modes/interactive/components/armin.js +6 -10
  420. package/dist/modes/interactive/components/armin.js.map +1 -1
  421. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  422. package/dist/modes/interactive/components/assistant-message.js +2 -9
  423. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  424. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  425. package/dist/modes/interactive/components/bash-execution.js +4 -9
  426. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  427. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  428. package/dist/modes/interactive/components/bordered-loader.js +0 -3
  429. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  430. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  431. package/dist/modes/interactive/components/branch-summary-message.js +1 -3
  432. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  433. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  434. package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
  435. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  436. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  437. package/dist/modes/interactive/components/config-selector.js +5 -22
  438. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  439. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  440. package/dist/modes/interactive/components/countdown-timer.js +0 -5
  441. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  442. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  443. package/dist/modes/interactive/components/custom-editor.js +1 -8
  444. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  445. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  446. package/dist/modes/interactive/components/custom-entry.js +1 -4
  447. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  448. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  449. package/dist/modes/interactive/components/custom-message.js +1 -7
  450. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  451. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  452. package/dist/modes/interactive/components/daxnuts.js +6 -8
  453. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  454. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  455. package/dist/modes/interactive/components/diff.js +2 -2
  456. package/dist/modes/interactive/components/diff.js.map +1 -1
  457. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  458. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  459. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  460. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  461. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  462. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  463. package/dist/modes/interactive/components/extension-editor.js +1 -7
  464. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  465. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  466. package/dist/modes/interactive/components/extension-input.js +2 -8
  467. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  468. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  469. package/dist/modes/interactive/components/extension-selector.js +1 -9
  470. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  471. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  472. package/dist/modes/interactive/components/first-time-setup.js +2 -4
  473. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  474. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  475. package/dist/modes/interactive/components/footer.js +1 -3
  476. package/dist/modes/interactive/components/footer.js.map +1 -1
  477. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  478. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  479. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  480. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  481. package/dist/modes/interactive/components/login-dialog.js +3 -9
  482. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  483. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -1
  484. package/dist/modes/interactive/components/markdown-transform.js.map +1 -1
  485. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  486. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  487. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  488. package/dist/modes/interactive/components/model-selector.js +14 -26
  489. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  490. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  491. package/dist/modes/interactive/components/oauth-selector.js +3 -11
  492. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  493. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  494. package/dist/modes/interactive/components/scoped-models-selector.js +9 -14
  495. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  496. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  497. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  498. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  499. package/dist/modes/interactive/components/session-selector.js +33 -57
  500. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  501. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  502. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  503. package/dist/modes/interactive/components/settings-selector.js +10 -14
  504. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  505. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  506. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  507. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  508. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  509. package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
  510. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  511. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  512. package/dist/modes/interactive/components/status-indicator.js +0 -2
  513. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  514. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  515. package/dist/modes/interactive/components/theme-selector.js +0 -2
  516. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  517. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  518. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  519. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  520. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  521. package/dist/modes/interactive/components/tool-execution.js +19 -25
  522. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  523. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  524. package/dist/modes/interactive/components/tree-selector.js +18 -34
  525. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  526. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  527. package/dist/modes/interactive/components/trust-selector.js +0 -6
  528. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  529. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  530. package/dist/modes/interactive/components/user-message-selector.js +3 -6
  531. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  532. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  533. package/dist/modes/interactive/components/user-message.js +0 -4
  534. package/dist/modes/interactive/components/user-message.js.map +1 -1
  535. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  536. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  537. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  538. package/dist/modes/interactive/external-editor.js.map +1 -1
  539. package/dist/modes/interactive/interactive-mode.d.ts +18 -2
  540. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  541. package/dist/modes/interactive/interactive-mode.js +147 -137
  542. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  543. package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
  544. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
  545. package/dist/modes/interactive/model-catalog-refresh.js +36 -0
  546. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
  547. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  548. package/dist/modes/interactive/model-search.js.map +1 -1
  549. package/dist/modes/interactive/theme/dark.json +2 -0
  550. package/dist/modes/interactive/theme/light.json +2 -0
  551. package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
  552. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  553. package/dist/modes/interactive/theme/theme-controller.js +25 -18
  554. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  555. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  556. package/dist/modes/interactive/theme/theme.d.ts +7 -5
  557. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  558. package/dist/modes/interactive/theme/theme.js +12 -8
  559. package/dist/modes/interactive/theme/theme.js.map +1 -1
  560. package/dist/modes/json-event.d.ts +4 -1
  561. package/dist/modes/json-event.d.ts.map +1 -1
  562. package/dist/modes/json-event.js +5 -2
  563. package/dist/modes/json-event.js.map +1 -1
  564. package/dist/modes/print-mode.d.ts.map +1 -1
  565. package/dist/modes/print-mode.js.map +1 -1
  566. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  567. package/dist/modes/rpc/jsonl.js.map +1 -1
  568. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  569. package/dist/modes/rpc/rpc-client.js +9 -10
  570. package/dist/modes/rpc/rpc-client.js.map +1 -1
  571. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  572. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  573. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  574. package/dist/package-manager-cli.d.ts.map +1 -1
  575. package/dist/package-manager-cli.js.map +1 -1
  576. package/dist/rpc-entry.d.ts.map +1 -1
  577. package/dist/rpc-entry.js.map +1 -1
  578. package/dist/server/create-harness.d.ts.map +1 -1
  579. package/dist/server/create-harness.js +2 -0
  580. package/dist/server/create-harness.js.map +1 -1
  581. package/dist/utils/abort.d.ts.map +1 -1
  582. package/dist/utils/abort.js.map +1 -1
  583. package/dist/utils/ansi.d.ts.map +1 -1
  584. package/dist/utils/ansi.js.map +1 -1
  585. package/dist/utils/changelog.d.ts.map +1 -1
  586. package/dist/utils/changelog.js.map +1 -1
  587. package/dist/utils/child-process.d.ts.map +1 -1
  588. package/dist/utils/child-process.js.map +1 -1
  589. package/dist/utils/clipboard-image.d.ts.map +1 -1
  590. package/dist/utils/clipboard-image.js +1 -1
  591. package/dist/utils/clipboard-image.js.map +1 -1
  592. package/dist/utils/clipboard-native.d.ts.map +1 -1
  593. package/dist/utils/clipboard-native.js.map +1 -1
  594. package/dist/utils/clipboard.d.ts.map +1 -1
  595. package/dist/utils/clipboard.js.map +1 -1
  596. package/dist/utils/deprecation.d.ts.map +1 -1
  597. package/dist/utils/deprecation.js.map +1 -1
  598. package/dist/utils/exif-orientation.d.ts.map +1 -1
  599. package/dist/utils/exif-orientation.js.map +1 -1
  600. package/dist/utils/frontmatter.d.ts.map +1 -1
  601. package/dist/utils/frontmatter.js.map +1 -1
  602. package/dist/utils/fs-watch.d.ts.map +1 -1
  603. package/dist/utils/fs-watch.js.map +1 -1
  604. package/dist/utils/git.d.ts.map +1 -1
  605. package/dist/utils/git.js.map +1 -1
  606. package/dist/utils/html.d.ts.map +1 -1
  607. package/dist/utils/html.js.map +1 -1
  608. package/dist/utils/image-convert.d.ts.map +1 -1
  609. package/dist/utils/image-convert.js.map +1 -1
  610. package/dist/utils/image-process.d.ts.map +1 -1
  611. package/dist/utils/image-process.js.map +1 -1
  612. package/dist/utils/image-resize-core.d.ts.map +1 -1
  613. package/dist/utils/image-resize-core.js.map +1 -1
  614. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  615. package/dist/utils/image-resize-worker.js.map +1 -1
  616. package/dist/utils/image-resize.d.ts.map +1 -1
  617. package/dist/utils/image-resize.js.map +1 -1
  618. package/dist/utils/json.d.ts.map +1 -1
  619. package/dist/utils/json.js.map +1 -1
  620. package/dist/utils/management-http.d.ts.map +1 -1
  621. package/dist/utils/management-http.js.map +1 -1
  622. package/dist/utils/mime.d.ts.map +1 -1
  623. package/dist/utils/mime.js.map +1 -1
  624. package/dist/utils/open-browser.d.ts.map +1 -1
  625. package/dist/utils/open-browser.js.map +1 -1
  626. package/dist/utils/paths.d.ts.map +1 -1
  627. package/dist/utils/paths.js.map +1 -1
  628. package/dist/utils/photon.d.ts.map +1 -1
  629. package/dist/utils/photon.js.map +1 -1
  630. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  631. package/dist/utils/pi-user-agent.js.map +1 -1
  632. package/dist/utils/shell.d.ts.map +1 -1
  633. package/dist/utils/shell.js.map +1 -1
  634. package/dist/utils/sleep.d.ts.map +1 -1
  635. package/dist/utils/sleep.js.map +1 -1
  636. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  637. package/dist/utils/syntax-highlight.js +1 -1
  638. package/dist/utils/syntax-highlight.js.map +1 -1
  639. package/dist/utils/tool-result-images.d.ts.map +1 -1
  640. package/dist/utils/tool-result-images.js.map +1 -1
  641. package/dist/utils/tools-manager.d.ts +10 -1
  642. package/dist/utils/tools-manager.d.ts.map +1 -1
  643. package/dist/utils/tools-manager.js +14 -19
  644. package/dist/utils/tools-manager.js.map +1 -1
  645. package/dist/utils/version-check.d.ts.map +1 -1
  646. package/dist/utils/version-check.js.map +1 -1
  647. package/dist/utils/windows-self-update.d.ts.map +1 -1
  648. package/dist/utils/windows-self-update.js.map +1 -1
  649. package/docs/compaction.md +3 -3
  650. package/docs/custom-provider.md +1 -1
  651. package/docs/environment-variables.md +1 -0
  652. package/docs/extensions.md +4 -0
  653. package/docs/json.md +6 -4
  654. package/docs/keybindings.md +8 -2
  655. package/docs/rpc.md +15 -4
  656. package/docs/sdk.md +9 -0
  657. package/docs/settings.md +31 -0
  658. package/docs/terminal-setup.md +23 -2
  659. package/docs/themes.md +23 -3
  660. package/docs/tui.md +2 -2
  661. package/docs/usage.md +3 -2
  662. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  663. package/examples/extensions/custom-provider-anthropic/package.json +2 -2
  664. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  665. package/examples/extensions/gondolin/package-lock.json +2 -2
  666. package/examples/extensions/gondolin/package.json +1 -1
  667. package/examples/extensions/minimal-mode.ts +6 -6
  668. package/examples/extensions/sandbox/package-lock.json +2 -2
  669. package/examples/extensions/sandbox/package.json +2 -2
  670. package/examples/extensions/with-deps/package-lock.json +2 -2
  671. package/examples/extensions/with-deps/package.json +1 -1
  672. package/npm-shrinkwrap.json +853 -661
  673. package/package.json +33 -33
  674. package/src/humain/web-access/UPSTREAM.md +1 -1
  675. package/src/humain/web-access/upstream.json +4 -4
@@ -18,25 +18,19 @@ function byteLength(text) {
18
18
  * to be preserved.
19
19
  */
20
20
  export class OutputAccumulator {
21
- maxLines;
22
- maxBytes;
23
- maxRollingBytes;
24
- tempFilePrefix;
25
- decoder = new TextDecoder();
26
- rawChunks = [];
27
- tailText = "";
28
- tailBytes = 0;
29
- tailStartsAtLineBoundary = true;
30
- totalRawBytes = 0;
31
- totalDecodedBytes = 0;
32
- completedLines = 0;
33
- totalLines = 0;
34
- currentLineBytes = 0;
35
- hasOpenLine = false;
36
- finished = false;
37
- tempFilePath;
38
- tempFileStream;
39
21
  constructor(options = {}) {
22
+ this.decoder = new TextDecoder();
23
+ this.rawChunks = [];
24
+ this.tailText = "";
25
+ this.tailBytes = 0;
26
+ this.tailStartsAtLineBoundary = true;
27
+ this.totalRawBytes = 0;
28
+ this.totalDecodedBytes = 0;
29
+ this.completedLines = 0;
30
+ this.totalLines = 0;
31
+ this.currentLineBytes = 0;
32
+ this.hasOpenLine = false;
33
+ this.finished = false;
40
34
  this.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
41
35
  this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
42
36
  this.maxRollingBytes = Math.max(this.maxBytes * 2, 1);
@@ -1 +1 @@
1
- {"version":3,"file":"output-accumulator.js","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { createWriteStream, type WriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult, truncateTail } from \"./truncate.ts\";\n\nexport interface OutputAccumulatorOptions {\n\tmaxLines?: number;\n\tmaxBytes?: number;\n\ttempFilePrefix?: string;\n}\n\nexport interface OutputSnapshot {\n\tcontent: string;\n\ttruncation: TruncationResult;\n\tfullOutputPath?: string;\n}\n\nfunction defaultTempFilePath(prefix: string): string {\n\tconst id = randomBytes(8).toString(\"hex\");\n\treturn join(tmpdir(), `${prefix}-${id}.log`);\n}\n\nfunction byteLength(text: string): number {\n\treturn Buffer.byteLength(text, \"utf-8\");\n}\n\n/**\n * Incrementally tracks streaming output with bounded memory.\n *\n * Appends decode chunks with a streaming UTF-8 decoder, keeps only a decoded\n * tail for display snapshots, and opens a temp file when the full output needs\n * to be preserved.\n */\nexport class OutputAccumulator {\n\tprivate readonly maxLines: number;\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxRollingBytes: number;\n\tprivate readonly tempFilePrefix: string;\n\tprivate readonly decoder = new TextDecoder();\n\n\tprivate rawChunks: Buffer[] = [];\n\tprivate tailText = \"\";\n\tprivate tailBytes = 0;\n\tprivate tailStartsAtLineBoundary = true;\n\tprivate totalRawBytes = 0;\n\tprivate totalDecodedBytes = 0;\n\tprivate completedLines = 0;\n\tprivate totalLines = 0;\n\tprivate currentLineBytes = 0;\n\tprivate hasOpenLine = false;\n\tprivate finished = false;\n\n\tprivate tempFilePath: string | undefined;\n\tprivate tempFileStream: WriteStream | undefined;\n\n\tconstructor(options: OutputAccumulatorOptions = {}) {\n\t\tthis.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\t\tthis.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\t\tthis.maxRollingBytes = Math.max(this.maxBytes * 2, 1);\n\t\tthis.tempFilePrefix = options.tempFilePrefix ?? \"pi-output\";\n\t}\n\n\tappend(data: Buffer): void {\n\t\tif (this.finished) {\n\t\t\tthrow new Error(\"Cannot append to a finished output accumulator\");\n\t\t}\n\n\t\tthis.totalRawBytes += data.length;\n\t\tthis.appendDecodedText(this.decoder.decode(data, { stream: true }));\n\n\t\tif (this.tempFileStream || this.shouldUseTempFile()) {\n\t\t\tthis.ensureTempFile();\n\t\t\tthis.tempFileStream?.write(data);\n\t\t} else if (data.length > 0) {\n\t\t\tthis.rawChunks.push(data);\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this.finished) {\n\t\t\treturn;\n\t\t}\n\t\tthis.finished = true;\n\t\tthis.appendDecodedText(this.decoder.decode());\n\t\tif (this.shouldUseTempFile()) {\n\t\t\tthis.ensureTempFile();\n\t\t}\n\t}\n\n\tsnapshot(options: { persistIfTruncated?: boolean } = {}): OutputSnapshot {\n\t\tconst tailTruncation = truncateTail(this.getSnapshotText(), {\n\t\t\tmaxLines: this.maxLines,\n\t\t\tmaxBytes: this.maxBytes,\n\t\t});\n\t\tconst truncated = this.totalLines > this.maxLines || this.totalDecodedBytes > this.maxBytes;\n\t\tconst truncatedBy = truncated\n\t\t\t? (tailTruncation.truncatedBy ?? (this.totalDecodedBytes > this.maxBytes ? \"bytes\" : \"lines\"))\n\t\t\t: null;\n\t\tconst truncation: TruncationResult = {\n\t\t\t...tailTruncation,\n\t\t\ttruncated,\n\t\t\ttruncatedBy,\n\t\t\ttotalLines: this.totalLines,\n\t\t\ttotalBytes: this.totalDecodedBytes,\n\t\t\tmaxLines: this.maxLines,\n\t\t\tmaxBytes: this.maxBytes,\n\t\t};\n\n\t\tif (options.persistIfTruncated && truncation.truncated) {\n\t\t\tthis.ensureTempFile();\n\t\t}\n\n\t\treturn {\n\t\t\tcontent: truncation.content,\n\t\t\ttruncation,\n\t\t\tfullOutputPath: this.tempFilePath,\n\t\t};\n\t}\n\n\tasync closeTempFile(): Promise<void> {\n\t\tif (!this.tempFileStream) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst stream = this.tempFileStream;\n\t\tthis.tempFileStream = undefined;\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst onError = (error: Error) => {\n\t\t\t\tstream.off(\"finish\", onFinish);\n\t\t\t\treject(error);\n\t\t\t};\n\t\t\tconst onFinish = () => {\n\t\t\t\tstream.off(\"error\", onError);\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\tstream.once(\"error\", onError);\n\t\t\tstream.once(\"finish\", onFinish);\n\t\t\tstream.end();\n\t\t});\n\t}\n\n\tgetLastLineBytes(): number {\n\t\treturn this.currentLineBytes;\n\t}\n\n\tprivate appendDecodedText(text: string): void {\n\t\tif (text.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst bytes = byteLength(text);\n\t\tthis.totalDecodedBytes += bytes;\n\t\tthis.tailText += text;\n\t\tthis.tailBytes += bytes;\n\t\tif (this.tailBytes > this.maxRollingBytes * 2) {\n\t\t\tthis.trimTail();\n\t\t}\n\n\t\tlet newlines = 0;\n\t\tlet lastNewline = -1;\n\t\tfor (let i = text.indexOf(\"\\n\"); i !== -1; i = text.indexOf(\"\\n\", i + 1)) {\n\t\t\tnewlines++;\n\t\t\tlastNewline = i;\n\t\t}\n\t\tif (newlines === 0) {\n\t\t\tthis.currentLineBytes += bytes;\n\t\t\tthis.hasOpenLine = true;\n\t\t} else {\n\t\t\tthis.completedLines += newlines;\n\t\t\tconst tail = text.slice(lastNewline + 1);\n\t\t\tthis.currentLineBytes = byteLength(tail);\n\t\t\tthis.hasOpenLine = tail.length > 0;\n\t\t}\n\t\tthis.totalLines = this.completedLines + (this.hasOpenLine ? 1 : 0);\n\t}\n\n\tprivate trimTail(): void {\n\t\tconst buffer = Buffer.from(this.tailText, \"utf-8\");\n\t\tif (buffer.length <= this.maxRollingBytes) {\n\t\t\tthis.tailBytes = buffer.length;\n\t\t\treturn;\n\t\t}\n\n\t\tlet start = buffer.length - this.maxRollingBytes;\n\t\twhile (start < buffer.length && (buffer[start] & 0xc0) === 0x80) {\n\t\t\tstart++;\n\t\t}\n\n\t\tthis.tailStartsAtLineBoundary = start === 0 ? this.tailStartsAtLineBoundary : buffer[start - 1] === 0x0a;\n\t\tthis.tailText = buffer.subarray(start).toString(\"utf-8\");\n\t\tthis.tailBytes = byteLength(this.tailText);\n\t}\n\n\tprivate getSnapshotText(): string {\n\t\tif (this.tailStartsAtLineBoundary) {\n\t\t\treturn this.tailText;\n\t\t}\n\n\t\tconst firstNewline = this.tailText.indexOf(\"\\n\");\n\t\treturn firstNewline === -1 ? this.tailText : this.tailText.slice(firstNewline + 1);\n\t}\n\n\tprivate shouldUseTempFile(): boolean {\n\t\treturn (\n\t\t\tthis.totalRawBytes > this.maxBytes || this.totalDecodedBytes > this.maxBytes || this.totalLines > this.maxLines\n\t\t);\n\t}\n\n\tprivate ensureTempFile(): void {\n\t\tif (this.tempFilePath) {\n\t\t\treturn;\n\t\t}\n\t\tthis.tempFilePath = defaultTempFilePath(this.tempFilePrefix);\n\t\tthis.tempFileStream = createWriteStream(this.tempFilePath);\n\t\tfor (const chunk of this.rawChunks) {\n\t\t\tthis.tempFileStream.write(chunk);\n\t\t}\n\t\tthis.rawChunks = [];\n\t}\n}\n"]}
1
+ {"version":3,"file":"output-accumulator.js","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { createWriteStream, type WriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult, truncateTail } from \"./truncate.ts\";\n\nexport interface OutputAccumulatorOptions {\n\tmaxLines?: number;\n\tmaxBytes?: number;\n\ttempFilePrefix?: string;\n}\n\nexport interface OutputSnapshot {\n\tcontent: string;\n\ttruncation: TruncationResult;\n\tfullOutputPath?: string;\n}\n\nfunction defaultTempFilePath(prefix: string): string {\n\tconst id = randomBytes(8).toString(\"hex\");\n\treturn join(tmpdir(), `${prefix}-${id}.log`);\n}\n\nfunction byteLength(text: string): number {\n\treturn Buffer.byteLength(text, \"utf-8\");\n}\n\n/**\n * Incrementally tracks streaming output with bounded memory.\n *\n * Appends decode chunks with a streaming UTF-8 decoder, keeps only a decoded\n * tail for display snapshots, and opens a temp file when the full output needs\n * to be preserved.\n */\nexport class OutputAccumulator {\n\tprivate readonly maxLines: number;\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxRollingBytes: number;\n\tprivate readonly tempFilePrefix: string;\n\tprivate readonly decoder = new TextDecoder();\n\n\tprivate rawChunks: Buffer[] = [];\n\tprivate tailText = \"\";\n\tprivate tailBytes = 0;\n\tprivate tailStartsAtLineBoundary = true;\n\tprivate totalRawBytes = 0;\n\tprivate totalDecodedBytes = 0;\n\tprivate completedLines = 0;\n\tprivate totalLines = 0;\n\tprivate currentLineBytes = 0;\n\tprivate hasOpenLine = false;\n\tprivate finished = false;\n\n\tprivate tempFilePath: string | undefined;\n\tprivate tempFileStream: WriteStream | undefined;\n\n\tconstructor(options: OutputAccumulatorOptions = {}) {\n\t\tthis.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\t\tthis.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\t\tthis.maxRollingBytes = Math.max(this.maxBytes * 2, 1);\n\t\tthis.tempFilePrefix = options.tempFilePrefix ?? \"pi-output\";\n\t}\n\n\tappend(data: Buffer): void {\n\t\tif (this.finished) {\n\t\t\tthrow new Error(\"Cannot append to a finished output accumulator\");\n\t\t}\n\n\t\tthis.totalRawBytes += data.length;\n\t\tthis.appendDecodedText(this.decoder.decode(data, { stream: true }));\n\n\t\tif (this.tempFileStream || this.shouldUseTempFile()) {\n\t\t\tthis.ensureTempFile();\n\t\t\tthis.tempFileStream?.write(data);\n\t\t} else if (data.length > 0) {\n\t\t\tthis.rawChunks.push(data);\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this.finished) {\n\t\t\treturn;\n\t\t}\n\t\tthis.finished = true;\n\t\tthis.appendDecodedText(this.decoder.decode());\n\t\tif (this.shouldUseTempFile()) {\n\t\t\tthis.ensureTempFile();\n\t\t}\n\t}\n\n\tsnapshot(options: { persistIfTruncated?: boolean } = {}): OutputSnapshot {\n\t\tconst tailTruncation = truncateTail(this.getSnapshotText(), {\n\t\t\tmaxLines: this.maxLines,\n\t\t\tmaxBytes: this.maxBytes,\n\t\t});\n\t\tconst truncated = this.totalLines > this.maxLines || this.totalDecodedBytes > this.maxBytes;\n\t\tconst truncatedBy = truncated\n\t\t\t? (tailTruncation.truncatedBy ?? (this.totalDecodedBytes > this.maxBytes ? \"bytes\" : \"lines\"))\n\t\t\t: null;\n\t\tconst truncation: TruncationResult = {\n\t\t\t...tailTruncation,\n\t\t\ttruncated,\n\t\t\ttruncatedBy,\n\t\t\ttotalLines: this.totalLines,\n\t\t\ttotalBytes: this.totalDecodedBytes,\n\t\t\tmaxLines: this.maxLines,\n\t\t\tmaxBytes: this.maxBytes,\n\t\t};\n\n\t\tif (options.persistIfTruncated && truncation.truncated) {\n\t\t\tthis.ensureTempFile();\n\t\t}\n\n\t\treturn {\n\t\t\tcontent: truncation.content,\n\t\t\ttruncation,\n\t\t\tfullOutputPath: this.tempFilePath,\n\t\t};\n\t}\n\n\tasync closeTempFile(): Promise<void> {\n\t\tif (!this.tempFileStream) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst stream = this.tempFileStream;\n\t\tthis.tempFileStream = undefined;\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst onError = (error: Error) => {\n\t\t\t\tstream.off(\"finish\", onFinish);\n\t\t\t\treject(error);\n\t\t\t};\n\t\t\tconst onFinish = () => {\n\t\t\t\tstream.off(\"error\", onError);\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\tstream.once(\"error\", onError);\n\t\t\tstream.once(\"finish\", onFinish);\n\t\t\tstream.end();\n\t\t});\n\t}\n\n\tgetLastLineBytes(): number {\n\t\treturn this.currentLineBytes;\n\t}\n\n\tprivate appendDecodedText(text: string): void {\n\t\tif (text.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst bytes = byteLength(text);\n\t\tthis.totalDecodedBytes += bytes;\n\t\tthis.tailText += text;\n\t\tthis.tailBytes += bytes;\n\t\tif (this.tailBytes > this.maxRollingBytes * 2) {\n\t\t\tthis.trimTail();\n\t\t}\n\n\t\tlet newlines = 0;\n\t\tlet lastNewline = -1;\n\t\tfor (let i = text.indexOf(\"\\n\"); i !== -1; i = text.indexOf(\"\\n\", i + 1)) {\n\t\t\tnewlines++;\n\t\t\tlastNewline = i;\n\t\t}\n\t\tif (newlines === 0) {\n\t\t\tthis.currentLineBytes += bytes;\n\t\t\tthis.hasOpenLine = true;\n\t\t} else {\n\t\t\tthis.completedLines += newlines;\n\t\t\tconst tail = text.slice(lastNewline + 1);\n\t\t\tthis.currentLineBytes = byteLength(tail);\n\t\t\tthis.hasOpenLine = tail.length > 0;\n\t\t}\n\t\tthis.totalLines = this.completedLines + (this.hasOpenLine ? 1 : 0);\n\t}\n\n\tprivate trimTail(): void {\n\t\tconst buffer = Buffer.from(this.tailText, \"utf-8\");\n\t\tif (buffer.length <= this.maxRollingBytes) {\n\t\t\tthis.tailBytes = buffer.length;\n\t\t\treturn;\n\t\t}\n\n\t\tlet start = buffer.length - this.maxRollingBytes;\n\t\twhile (start < buffer.length && (buffer[start] & 0xc0) === 0x80) {\n\t\t\tstart++;\n\t\t}\n\n\t\tthis.tailStartsAtLineBoundary = start === 0 ? this.tailStartsAtLineBoundary : buffer[start - 1] === 0x0a;\n\t\tthis.tailText = buffer.subarray(start).toString(\"utf-8\");\n\t\tthis.tailBytes = byteLength(this.tailText);\n\t}\n\n\tprivate getSnapshotText(): string {\n\t\tif (this.tailStartsAtLineBoundary) {\n\t\t\treturn this.tailText;\n\t\t}\n\n\t\tconst firstNewline = this.tailText.indexOf(\"\\n\");\n\t\treturn firstNewline === -1 ? this.tailText : this.tailText.slice(firstNewline + 1);\n\t}\n\n\tprivate shouldUseTempFile(): boolean {\n\t\treturn (\n\t\t\tthis.totalRawBytes > this.maxBytes || this.totalDecodedBytes > this.maxBytes || this.totalLines > this.maxLines\n\t\t);\n\t}\n\n\tprivate ensureTempFile(): void {\n\t\tif (this.tempFilePath) {\n\t\t\treturn;\n\t\t}\n\t\tthis.tempFilePath = defaultTempFilePath(this.tempFilePrefix);\n\t\tthis.tempFileStream = createWriteStream(this.tempFilePath);\n\t\tfor (const chunk of this.rawChunks) {\n\t\t\tthis.tempFileStream.write(chunk);\n\t\t}\n\t\tthis.rawChunks = [];\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/path-utils.ts"],"names":[],"mappings":"AA8BA,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAgCrE;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgCzF","sourcesContent":["import { accessSync, constants } from \"node:fs\";\nimport { access } from \"node:fs/promises\";\nimport { normalizePath, resolvePath } from \"../../utils/paths.ts\";\n\nconst NARROW_NO_BREAK_SPACE = \"\\u202F\";\n\nfunction tryMacOSScreenshotPath(filePath: string): string {\n\treturn filePath.replace(/ (AM|PM)\\./gi, `${NARROW_NO_BREAK_SPACE}$1.`);\n}\n\nfunction tryNFDVariant(filePath: string): string {\n\t// macOS stores filenames in NFD (decomposed) form, try converting user input to NFD\n\treturn filePath.normalize(\"NFD\");\n}\n\nfunction tryCurlyQuoteVariant(filePath: string): string {\n\t// macOS uses U+2019 (right single quotation mark) in screenshot names like \"Capture d'écran\"\n\t// Users typically type U+0027 (straight apostrophe)\n\treturn filePath.replace(/'/g, \"\\u2019\");\n}\n\nfunction fileExists(filePath: string): boolean {\n\ttry {\n\t\taccessSync(filePath, constants.F_OK);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n\ttry {\n\t\tawait access(filePath, constants.F_OK);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function expandPath(filePath: string): string {\n\treturn normalizePath(filePath, { normalizeUnicodeSpaces: true, stripAtPrefix: true });\n}\n\n/**\n * Resolve a path relative to the given cwd.\n * Handles ~ expansion and absolute paths.\n */\nexport function resolveToCwd(filePath: string, cwd: string): string {\n\treturn resolvePath(filePath, cwd, { normalizeUnicodeSpaces: true, stripAtPrefix: true });\n}\n\nexport function resolveReadPath(filePath: string, cwd: string): string {\n\tconst resolved = resolveToCwd(filePath, cwd);\n\n\tif (fileExists(resolved)) {\n\t\treturn resolved;\n\t}\n\n\t// Try macOS AM/PM variant (narrow no-break space before AM/PM)\n\tconst amPmVariant = tryMacOSScreenshotPath(resolved);\n\tif (amPmVariant !== resolved && fileExists(amPmVariant)) {\n\t\treturn amPmVariant;\n\t}\n\n\t// Try NFD variant (macOS stores filenames in NFD form)\n\tconst nfdVariant = tryNFDVariant(resolved);\n\tif (nfdVariant !== resolved && fileExists(nfdVariant)) {\n\t\treturn nfdVariant;\n\t}\n\n\t// Try curly quote variant (macOS uses U+2019 in screenshot names)\n\tconst curlyVariant = tryCurlyQuoteVariant(resolved);\n\tif (curlyVariant !== resolved && fileExists(curlyVariant)) {\n\t\treturn curlyVariant;\n\t}\n\n\t// Try combined NFD + curly quote (for French macOS screenshots like \"Capture d'écran\")\n\tconst nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\n\tif (nfdCurlyVariant !== resolved && fileExists(nfdCurlyVariant)) {\n\t\treturn nfdCurlyVariant;\n\t}\n\n\treturn resolved;\n}\n\nexport async function resolveReadPathAsync(filePath: string, cwd: string): Promise<string> {\n\tconst resolved = resolveToCwd(filePath, cwd);\n\n\tif (await pathExists(resolved)) {\n\t\treturn resolved;\n\t}\n\n\t// Try macOS AM/PM variant (narrow no-break space before AM/PM)\n\tconst amPmVariant = tryMacOSScreenshotPath(resolved);\n\tif (amPmVariant !== resolved && (await pathExists(amPmVariant))) {\n\t\treturn amPmVariant;\n\t}\n\n\t// Try NFD variant (macOS stores filenames in NFD form)\n\tconst nfdVariant = tryNFDVariant(resolved);\n\tif (nfdVariant !== resolved && (await pathExists(nfdVariant))) {\n\t\treturn nfdVariant;\n\t}\n\n\t// Try curly quote variant (macOS uses U+2019 in screenshot names)\n\tconst curlyVariant = tryCurlyQuoteVariant(resolved);\n\tif (curlyVariant !== resolved && (await pathExists(curlyVariant))) {\n\t\treturn curlyVariant;\n\t}\n\n\t// Try combined NFD + curly quote (for French macOS screenshots like \"Capture d'écran\")\n\tconst nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\n\tif (nfdCurlyVariant !== resolved && (await pathExists(nfdCurlyVariant))) {\n\t\treturn nfdCurlyVariant;\n\t}\n\n\treturn resolved;\n}\n"]}
1
+ {"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/path-utils.ts"],"names":[],"mappings":"AA8BA,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAgCrE;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgCzF"}
@@ -1 +1 @@
1
- {"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../../../src/core/tools/path-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { accessSync, constants } from \"node:fs\";\nimport { access } from \"node:fs/promises\";\nimport { normalizePath, resolvePath } from \"../../utils/paths.ts\";\n\nconst NARROW_NO_BREAK_SPACE = \"\\u202F\";\n\nfunction tryMacOSScreenshotPath(filePath: string): string {\n\treturn filePath.replace(/ (AM|PM)\\./gi, `${NARROW_NO_BREAK_SPACE}$1.`);\n}\n\nfunction tryNFDVariant(filePath: string): string {\n\t// macOS stores filenames in NFD (decomposed) form, try converting user input to NFD\n\treturn filePath.normalize(\"NFD\");\n}\n\nfunction tryCurlyQuoteVariant(filePath: string): string {\n\t// macOS uses U+2019 (right single quotation mark) in screenshot names like \"Capture d'écran\"\n\t// Users typically type U+0027 (straight apostrophe)\n\treturn filePath.replace(/'/g, \"\\u2019\");\n}\n\nfunction fileExists(filePath: string): boolean {\n\ttry {\n\t\taccessSync(filePath, constants.F_OK);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n\ttry {\n\t\tawait access(filePath, constants.F_OK);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function expandPath(filePath: string): string {\n\treturn normalizePath(filePath, { normalizeUnicodeSpaces: true, stripAtPrefix: true });\n}\n\n/**\n * Resolve a path relative to the given cwd.\n * Handles ~ expansion and absolute paths.\n */\nexport function resolveToCwd(filePath: string, cwd: string): string {\n\treturn resolvePath(filePath, cwd, { normalizeUnicodeSpaces: true, stripAtPrefix: true });\n}\n\nexport function resolveReadPath(filePath: string, cwd: string): string {\n\tconst resolved = resolveToCwd(filePath, cwd);\n\n\tif (fileExists(resolved)) {\n\t\treturn resolved;\n\t}\n\n\t// Try macOS AM/PM variant (narrow no-break space before AM/PM)\n\tconst amPmVariant = tryMacOSScreenshotPath(resolved);\n\tif (amPmVariant !== resolved && fileExists(amPmVariant)) {\n\t\treturn amPmVariant;\n\t}\n\n\t// Try NFD variant (macOS stores filenames in NFD form)\n\tconst nfdVariant = tryNFDVariant(resolved);\n\tif (nfdVariant !== resolved && fileExists(nfdVariant)) {\n\t\treturn nfdVariant;\n\t}\n\n\t// Try curly quote variant (macOS uses U+2019 in screenshot names)\n\tconst curlyVariant = tryCurlyQuoteVariant(resolved);\n\tif (curlyVariant !== resolved && fileExists(curlyVariant)) {\n\t\treturn curlyVariant;\n\t}\n\n\t// Try combined NFD + curly quote (for French macOS screenshots like \"Capture d'écran\")\n\tconst nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\n\tif (nfdCurlyVariant !== resolved && fileExists(nfdCurlyVariant)) {\n\t\treturn nfdCurlyVariant;\n\t}\n\n\treturn resolved;\n}\n\nexport async function resolveReadPathAsync(filePath: string, cwd: string): Promise<string> {\n\tconst resolved = resolveToCwd(filePath, cwd);\n\n\tif (await pathExists(resolved)) {\n\t\treturn resolved;\n\t}\n\n\t// Try macOS AM/PM variant (narrow no-break space before AM/PM)\n\tconst amPmVariant = tryMacOSScreenshotPath(resolved);\n\tif (amPmVariant !== resolved && (await pathExists(amPmVariant))) {\n\t\treturn amPmVariant;\n\t}\n\n\t// Try NFD variant (macOS stores filenames in NFD form)\n\tconst nfdVariant = tryNFDVariant(resolved);\n\tif (nfdVariant !== resolved && (await pathExists(nfdVariant))) {\n\t\treturn nfdVariant;\n\t}\n\n\t// Try curly quote variant (macOS uses U+2019 in screenshot names)\n\tconst curlyVariant = tryCurlyQuoteVariant(resolved);\n\tif (curlyVariant !== resolved && (await pathExists(curlyVariant))) {\n\t\treturn curlyVariant;\n\t}\n\n\t// Try combined NFD + curly quote (for French macOS screenshots like \"Capture d'écran\")\n\tconst nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\n\tif (nfdCurlyVariant !== resolved && (await pathExists(nfdCurlyVariant))) {\n\t\treturn nfdCurlyVariant;\n\t}\n\n\treturn resolved;\n}\n"]}
1
+ {"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../../../src/core/tools/path-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { accessSync, constants } from \"node:fs\";\nimport { access } from \"node:fs/promises\";\nimport { normalizePath, resolvePath } from \"../../utils/paths.ts\";\n\nconst NARROW_NO_BREAK_SPACE = \"\\u202F\";\n\nfunction tryMacOSScreenshotPath(filePath: string): string {\n\treturn filePath.replace(/ (AM|PM)\\./gi, `${NARROW_NO_BREAK_SPACE}$1.`);\n}\n\nfunction tryNFDVariant(filePath: string): string {\n\t// macOS stores filenames in NFD (decomposed) form, try converting user input to NFD\n\treturn filePath.normalize(\"NFD\");\n}\n\nfunction tryCurlyQuoteVariant(filePath: string): string {\n\t// macOS uses U+2019 (right single quotation mark) in screenshot names like \"Capture d'écran\"\n\t// Users typically type U+0027 (straight apostrophe)\n\treturn filePath.replace(/'/g, \"\\u2019\");\n}\n\nfunction fileExists(filePath: string): boolean {\n\ttry {\n\t\taccessSync(filePath, constants.F_OK);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n\ttry {\n\t\tawait access(filePath, constants.F_OK);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function expandPath(filePath: string): string {\n\treturn normalizePath(filePath, { normalizeUnicodeSpaces: true, stripAtPrefix: true });\n}\n\n/**\n * Resolve a path relative to the given cwd.\n * Handles ~ expansion and absolute paths.\n */\nexport function resolveToCwd(filePath: string, cwd: string): string {\n\treturn resolvePath(filePath, cwd, { normalizeUnicodeSpaces: true, stripAtPrefix: true });\n}\n\nexport function resolveReadPath(filePath: string, cwd: string): string {\n\tconst resolved = resolveToCwd(filePath, cwd);\n\n\tif (fileExists(resolved)) {\n\t\treturn resolved;\n\t}\n\n\t// Try macOS AM/PM variant (narrow no-break space before AM/PM)\n\tconst amPmVariant = tryMacOSScreenshotPath(resolved);\n\tif (amPmVariant !== resolved && fileExists(amPmVariant)) {\n\t\treturn amPmVariant;\n\t}\n\n\t// Try NFD variant (macOS stores filenames in NFD form)\n\tconst nfdVariant = tryNFDVariant(resolved);\n\tif (nfdVariant !== resolved && fileExists(nfdVariant)) {\n\t\treturn nfdVariant;\n\t}\n\n\t// Try curly quote variant (macOS uses U+2019 in screenshot names)\n\tconst curlyVariant = tryCurlyQuoteVariant(resolved);\n\tif (curlyVariant !== resolved && fileExists(curlyVariant)) {\n\t\treturn curlyVariant;\n\t}\n\n\t// Try combined NFD + curly quote (for French macOS screenshots like \"Capture d'écran\")\n\tconst nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\n\tif (nfdCurlyVariant !== resolved && fileExists(nfdCurlyVariant)) {\n\t\treturn nfdCurlyVariant;\n\t}\n\n\treturn resolved;\n}\n\nexport async function resolveReadPathAsync(filePath: string, cwd: string): Promise<string> {\n\tconst resolved = resolveToCwd(filePath, cwd);\n\n\tif (await pathExists(resolved)) {\n\t\treturn resolved;\n\t}\n\n\t// Try macOS AM/PM variant (narrow no-break space before AM/PM)\n\tconst amPmVariant = tryMacOSScreenshotPath(resolved);\n\tif (amPmVariant !== resolved && (await pathExists(amPmVariant))) {\n\t\treturn amPmVariant;\n\t}\n\n\t// Try NFD variant (macOS stores filenames in NFD form)\n\tconst nfdVariant = tryNFDVariant(resolved);\n\tif (nfdVariant !== resolved && (await pathExists(nfdVariant))) {\n\t\treturn nfdVariant;\n\t}\n\n\t// Try curly quote variant (macOS uses U+2019 in screenshot names)\n\tconst curlyVariant = tryCurlyQuoteVariant(resolved);\n\tif (curlyVariant !== resolved && (await pathExists(curlyVariant))) {\n\t\treturn curlyVariant;\n\t}\n\n\t// Try combined NFD + curly quote (for French macOS screenshots like \"Capture d'écran\")\n\tconst nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\n\tif (nfdCurlyVariant !== resolved && (await pathExists(nfdCurlyVariant))) {\n\t\treturn nfdCurlyVariant;\n\t}\n\n\treturn resolved;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAK/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAO5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAItF,OAAO,EAAoD,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEtH,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;CAGnC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AASD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,qCAAqC;IACrC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,+CAA+C;IAC/C,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,sEAAsE;IACtE,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CACnF;AAQD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AA4ID,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CA6IhE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { basename, dirname, isAbsolute, relative, resolve as resolvePath, sep } from \"node:path\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport type { Api, ImageContent, Model, TextContent } from \"@earendil-works/pi-ai\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { constants } from \"fs\";\nimport { access as fsAccess, readFile as fsReadFile } from \"fs/promises\";\nimport { type Static, Type } from \"typebox\";\nimport { getReadmePath } from \"../../config.ts\";\nimport { keyHint, keyText } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getLanguageFromPath, highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { processImage } from \"../../utils/image-process.ts\";\nimport { detectSupportedImageMimeTypeFromFile } from \"../../utils/mime.ts\";\nimport { formatPathRelativeToCwdOrAbsolute } from \"../../utils/paths.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { resolveReadPathAsync, resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, renderToolPath, replaceTabs, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\n});\n\nexport const readToolSystemPromptContribution = {\n\tsnippet: \"Read file contents\",\n\tguidelines: [\"Use read to examine files instead of cat or sed.\"],\n} as const;\n\nexport type ReadToolInput = Static<typeof readSchema>;\n\nexport interface ReadToolDetails {\n\ttruncation?: TruncationResult;\n}\n\ninterface CompactReadClassification {\n\tkind: \"docs\" | \"resource\" | \"skill\";\n\tlabel: string;\n}\n\nconst COMPACT_RESOURCE_FILE_NAMES = new Set([\"AGENTS.override.md\", \"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"]);\n\n/**\n * Pluggable operations for the read tool.\n * Override these to delegate file reading to remote systems (for example SSH).\n */\nexport interface ReadOperations {\n\t/** Read file contents as a Buffer */\n\treadFile: (absolutePath: string) => Promise<Buffer>;\n\t/** Check if file is readable (throw if not) */\n\taccess: (absolutePath: string) => Promise<void>;\n\t/** Detect image MIME type, return null or undefined for non-images */\n\tdetectImageMimeType?: (absolutePath: string) => Promise<string | null | undefined>;\n}\n\nconst defaultReadOperations: ReadOperations = {\n\treadFile: (path) => fsReadFile(path),\n\taccess: (path) => fsAccess(path, constants.R_OK),\n\tdetectImageMimeType: detectSupportedImageMimeTypeFromFile,\n};\n\nexport interface ReadToolOptions {\n\t/** Whether to auto-resize images to 2000x2000 max. Default: true */\n\tautoResizeImages?: boolean;\n\t/** Custom operations for file reading. Default: local filesystem */\n\toperations?: ReadOperations;\n}\n\ntype ReadRenderArgs = { path?: string; file_path?: string; offset?: number; limit?: number };\n\nfunction formatReadLineRange(args: ReadRenderArgs | undefined, theme: Theme): string {\n\tif (args?.offset === undefined && args?.limit === undefined) return \"\";\n\tconst startLine = args.offset ?? 1;\n\tconst endLine = args.limit !== undefined ? startLine + args.limit - 1 : \"\";\n\treturn theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n}\n\nfunction formatReadCall(args: ReadRenderArgs | undefined, theme: Theme, cwd: string): string {\n\tconst pathDisplay = renderToolPath(str(args?.file_path ?? args?.path), theme, cwd);\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"read\"))} ${pathDisplay}${formatReadLineRange(args, theme)}`;\n}\n\nfunction trimTrailingEmptyLines(lines: string[]): string[] {\n\tlet end = lines.length;\n\twhile (end > 0 && lines[end - 1] === \"\") {\n\t\tend--;\n\t}\n\treturn lines.slice(0, end);\n}\n\nfunction getNonVisionImageNote(model: Model<Api> | undefined): string | undefined {\n\tif (!model || model.input.includes(\"image\")) {\n\t\treturn undefined;\n\t}\n\treturn \"[Current model does not support images. The image will be omitted from this request.]\";\n}\n\nfunction toPosixPath(filePath: string): string {\n\treturn filePath.split(sep).join(\"/\");\n}\n\nfunction getPiDocsClassification(absolutePath: string): CompactReadClassification | undefined {\n\tconst packageRoot = dirname(getReadmePath());\n\tconst relativePath = relative(resolvePath(packageRoot), resolvePath(absolutePath));\n\tif (\n\t\trelativePath === \"\" ||\n\t\trelativePath === \"..\" ||\n\t\trelativePath.startsWith(`..${sep}`) ||\n\t\tisAbsolute(relativePath)\n\t) {\n\t\treturn undefined;\n\t}\n\n\tconst label = toPosixPath(relativePath);\n\tif (label === \"README.md\" || label.startsWith(\"docs/\") || label.startsWith(\"examples/\")) {\n\t\treturn { kind: \"docs\", label };\n\t}\n\treturn undefined;\n}\n\nfunction getCompactReadClassification(\n\targs: ReadRenderArgs | undefined,\n\tcwd: string,\n): CompactReadClassification | undefined {\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tif (!rawPath) return undefined;\n\n\tconst absolutePath = resolveToCwd(rawPath, cwd);\n\tconst fileName = basename(absolutePath);\n\tif (fileName === \"SKILL.md\") {\n\t\treturn { kind: \"skill\", label: basename(dirname(absolutePath)) || fileName };\n\t}\n\n\tconst docsClassification = getPiDocsClassification(absolutePath);\n\tif (docsClassification) return docsClassification;\n\n\tif (COMPACT_RESOURCE_FILE_NAMES.has(fileName)) {\n\t\treturn { kind: \"resource\", label: formatPathRelativeToCwdOrAbsolute(absolutePath, cwd) };\n\t}\n\n\treturn undefined;\n}\n\nfunction formatCompactReadCall(\n\tclassification: CompactReadClassification,\n\targs: ReadRenderArgs | undefined,\n\ttheme: Theme,\n): string {\n\tconst expandHint = theme.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n\tif (classification.kind === \"skill\") {\n\t\treturn (\n\t\t\ttheme.fg(\"customMessageLabel\", `\\x1b[1m[skill]\\x1b[22m `) +\n\t\t\ttheme.fg(\"customMessageText\", classification.label) +\n\t\t\tformatReadLineRange(args, theme) +\n\t\t\texpandHint\n\t\t);\n\t}\n\n\treturn (\n\t\ttheme.fg(\"toolTitle\", theme.bold(`read ${classification.kind}`)) +\n\t\t\" \" +\n\t\ttheme.fg(\"accent\", classification.label) +\n\t\tformatReadLineRange(args, theme) +\n\t\texpandHint\n\t);\n}\n\nfunction formatReadResult(\n\targs: ReadRenderArgs | undefined,\n\tresult: { content: (TextContent | ImageContent)[]; details?: ReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n\t_cwd: string,\n\tisError: boolean,\n): string {\n\tif (!options.expanded && !isError) {\n\t\treturn \"\";\n\t}\n\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst output = getTextOutput(result, showImages);\n\tconst lang = !isError && rawPath ? getLanguageFromPath(rawPath) : undefined;\n\tconst renderedLines = lang ? highlightCode(replaceTabs(output), lang) : output.split(\"\\n\");\n\tconst lines = trimTrailingEmptyLines(renderedLines);\n\tconst maxLines = options.expanded ? lines.length : 10;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => (lang ? replaceTabs(line) : theme.fg(\"toolOutput\", replaceTabs(line)))).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t}\n\n\tconst truncation = result.details?.truncation;\n\tif (truncation?.truncated) {\n\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\ttext += `\\n${theme.fg(\"warning\", `[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`)}`;\n\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)]`)}`;\n\t\t} else {\n\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`)}`;\n\t\t}\n\t}\n\treturn text;\n}\n\nexport function createReadToolDefinition(\n\tcwd: string,\n\toptions?: ReadToolOptions,\n): ToolDefinition<typeof readSchema, ReadToolDetails | undefined> {\n\tconst autoResizeImages = options?.autoResizeImages ?? true;\n\tconst ops = options?.operations ?? defaultReadOperations;\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n\t\tpromptSnippet: readToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...readToolSystemPromptContribution.guidelines],\n\t\tparameters: readSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, offset, limit }: { path: string; offset?: number; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\tctx?,\n\t\t) {\n\t\t\treturn new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(\n\t\t\t\t(resolve, reject) => {\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tlet aborted = false;\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t};\n\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst absolutePath = await resolveReadPathAsync(path, cwd);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\t// Check if file exists and is readable.\n\t\t\t\t\t\t\tawait ops.access(absolutePath);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tconst mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : undefined;\n\t\t\t\t\t\t\tlet content: (TextContent | ImageContent)[];\n\t\t\t\t\t\t\tlet details: ReadToolDetails | undefined;\n\t\t\t\t\t\t\tconst nonVisionImageNote = getNonVisionImageNote(ctx?.model);\n\t\t\t\t\t\t\tif (mimeType) {\n\t\t\t\t\t\t\t\t// Read image as binary.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst processed = await processImage(buffer, mimeType, { autoResizeImages });\n\t\t\t\t\t\t\t\tif (!processed.ok) {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${mimeType}]\\n${processed.message}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: textNote }];\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${processed.mimeType}]`;\n\t\t\t\t\t\t\t\t\tif (processed.hints.length > 0) textNote += `\\n${processed.hints.join(\"\\n\")}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [\n\t\t\t\t\t\t\t\t\t\t{ type: \"text\", text: textNote },\n\t\t\t\t\t\t\t\t\t\t{ type: \"image\", data: processed.data, mimeType: processed.mimeType },\n\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Read text content.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst textContent = buffer.toString(\"utf-8\");\n\t\t\t\t\t\t\t\tconst allLines = textContent.split(\"\\n\");\n\t\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\n\t\t\t\t\t\t\t\t// Apply offset if specified. Convert from 1-indexed input to 0-indexed array access.\n\t\t\t\t\t\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\n\t\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1;\n\t\t\t\t\t\t\t\t// Check if offset is out of bounds.\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length) {\n\t\t\t\t\t\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlet selectedContent: string;\n\t\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\n\t\t\t\t\t\t\t\t// If limit is specified by the user, honor it first. Otherwise truncateHead decides.\n\t\t\t\t\t\t\t\tif (limit !== undefined) {\n\t\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t\tuserLimitedLines = endLine - startLine;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Apply truncation, respecting both line and byte limits.\n\t\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\n\t\t\t\t\t\t\t\tlet outputText: string;\n\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\t\t\t\t// First line alone exceeds the byte limit. Point the model at a bash fallback.\n\t\t\t\t\t\t\t\t\tconst firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], \"utf-8\"));\n\t\t\t\t\t\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (truncation.truncated) {\n\t\t\t\t\t\t\t\t\t// Truncation occurred. Build an actionable continuation notice.\n\t\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\t\t\t\t\t\t// User-specified limit stopped early, but the file still has more content.\n\t\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\t\t\t\t\t\t\t\t\toutputText = `${truncation.content}\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// No truncation and no remaining user-limited content.\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: outputText }];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tresolve({ content, details });\n\t\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tif (!aborted) reject(error);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tconst classification = !context.expanded ? getCompactReadClassification(args, context.cwd) : undefined;\n\t\t\ttext.setText(\n\t\t\t\tclassification\n\t\t\t\t\t? formatCompactReadCall(classification, args, theme)\n\t\t\t\t\t: formatReadCall(args, theme, context.cwd),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(\n\t\t\t\tformatReadResult(context.args, result, options, theme, context.showImages, context.cwd, context.isError),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createReadTool(cwd: string, options?: ReadToolOptions): AgentTool<typeof readSchema> {\n\treturn wrapToolDefinition(createReadToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAK/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAQ5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAItF,OAAO,EAAoD,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEtH,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,eAAO,MAAM,gCAAgC;aAC5C,OAAO,EAAE,oBAAoB;aAC7B,UAAU,YAAG,kDAAkD;CACtD,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AASD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,qCAAqC;IACrC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,+CAA+C;IAC/C,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,sEAAsE;IACtE,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CACnF;AAQD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AA4ID,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CA8IhE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG"}
@@ -9,6 +9,7 @@ import { getLanguageFromPath, highlightCode } from "../../modes/interactive/them
9
9
  import { processImage } from "../../utils/image-process.js";
10
10
  import { detectSupportedImageMimeTypeFromFile } from "../../utils/mime.js";
11
11
  import { formatPathRelativeToCwdOrAbsolute } from "../../utils/paths.js";
12
+ import { getExperimentalToolSampling } from "../experimental.js";
12
13
  import { resolveReadPathAsync, resolveToCwd } from "./path-utils.js";
13
14
  import { getTextOutput, renderToolPath, replaceTabs, str } from "./render-utils.js";
14
15
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
@@ -141,6 +142,7 @@ export function createReadToolDefinition(cwd, options) {
141
142
  promptSnippet: readToolSystemPromptContribution.snippet,
142
143
  promptGuidelines: [...readToolSystemPromptContribution.guidelines],
143
144
  parameters: readSchema,
145
+ constrainedSampling: getExperimentalToolSampling(),
144
146
  async execute(_toolCallId, { path, offset, limit }, signal, _onUpdate, ctx) {
145
147
  return new Promise((resolve, reject) => {
146
148
  if (signal?.aborted) {
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import { basename, dirname, isAbsolute, relative, resolve as resolvePath, sep } from \"node:path\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport type { Api, ImageContent, Model, TextContent } from \"@earendil-works/pi-ai\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { constants } from \"fs\";\nimport { access as fsAccess, readFile as fsReadFile } from \"fs/promises\";\nimport { type Static, Type } from \"typebox\";\nimport { getReadmePath } from \"../../config.ts\";\nimport { keyHint, keyText } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getLanguageFromPath, highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { processImage } from \"../../utils/image-process.ts\";\nimport { detectSupportedImageMimeTypeFromFile } from \"../../utils/mime.ts\";\nimport { formatPathRelativeToCwdOrAbsolute } from \"../../utils/paths.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { resolveReadPathAsync, resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, renderToolPath, replaceTabs, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\n});\n\nexport const readToolSystemPromptContribution = {\n\tsnippet: \"Read file contents\",\n\tguidelines: [\"Use read to examine files instead of cat or sed.\"],\n} as const;\n\nexport type ReadToolInput = Static<typeof readSchema>;\n\nexport interface ReadToolDetails {\n\ttruncation?: TruncationResult;\n}\n\ninterface CompactReadClassification {\n\tkind: \"docs\" | \"resource\" | \"skill\";\n\tlabel: string;\n}\n\nconst COMPACT_RESOURCE_FILE_NAMES = new Set([\"AGENTS.override.md\", \"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"]);\n\n/**\n * Pluggable operations for the read tool.\n * Override these to delegate file reading to remote systems (for example SSH).\n */\nexport interface ReadOperations {\n\t/** Read file contents as a Buffer */\n\treadFile: (absolutePath: string) => Promise<Buffer>;\n\t/** Check if file is readable (throw if not) */\n\taccess: (absolutePath: string) => Promise<void>;\n\t/** Detect image MIME type, return null or undefined for non-images */\n\tdetectImageMimeType?: (absolutePath: string) => Promise<string | null | undefined>;\n}\n\nconst defaultReadOperations: ReadOperations = {\n\treadFile: (path) => fsReadFile(path),\n\taccess: (path) => fsAccess(path, constants.R_OK),\n\tdetectImageMimeType: detectSupportedImageMimeTypeFromFile,\n};\n\nexport interface ReadToolOptions {\n\t/** Whether to auto-resize images to 2000x2000 max. Default: true */\n\tautoResizeImages?: boolean;\n\t/** Custom operations for file reading. Default: local filesystem */\n\toperations?: ReadOperations;\n}\n\ntype ReadRenderArgs = { path?: string; file_path?: string; offset?: number; limit?: number };\n\nfunction formatReadLineRange(args: ReadRenderArgs | undefined, theme: Theme): string {\n\tif (args?.offset === undefined && args?.limit === undefined) return \"\";\n\tconst startLine = args.offset ?? 1;\n\tconst endLine = args.limit !== undefined ? startLine + args.limit - 1 : \"\";\n\treturn theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n}\n\nfunction formatReadCall(args: ReadRenderArgs | undefined, theme: Theme, cwd: string): string {\n\tconst pathDisplay = renderToolPath(str(args?.file_path ?? args?.path), theme, cwd);\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"read\"))} ${pathDisplay}${formatReadLineRange(args, theme)}`;\n}\n\nfunction trimTrailingEmptyLines(lines: string[]): string[] {\n\tlet end = lines.length;\n\twhile (end > 0 && lines[end - 1] === \"\") {\n\t\tend--;\n\t}\n\treturn lines.slice(0, end);\n}\n\nfunction getNonVisionImageNote(model: Model<Api> | undefined): string | undefined {\n\tif (!model || model.input.includes(\"image\")) {\n\t\treturn undefined;\n\t}\n\treturn \"[Current model does not support images. The image will be omitted from this request.]\";\n}\n\nfunction toPosixPath(filePath: string): string {\n\treturn filePath.split(sep).join(\"/\");\n}\n\nfunction getPiDocsClassification(absolutePath: string): CompactReadClassification | undefined {\n\tconst packageRoot = dirname(getReadmePath());\n\tconst relativePath = relative(resolvePath(packageRoot), resolvePath(absolutePath));\n\tif (\n\t\trelativePath === \"\" ||\n\t\trelativePath === \"..\" ||\n\t\trelativePath.startsWith(`..${sep}`) ||\n\t\tisAbsolute(relativePath)\n\t) {\n\t\treturn undefined;\n\t}\n\n\tconst label = toPosixPath(relativePath);\n\tif (label === \"README.md\" || label.startsWith(\"docs/\") || label.startsWith(\"examples/\")) {\n\t\treturn { kind: \"docs\", label };\n\t}\n\treturn undefined;\n}\n\nfunction getCompactReadClassification(\n\targs: ReadRenderArgs | undefined,\n\tcwd: string,\n): CompactReadClassification | undefined {\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tif (!rawPath) return undefined;\n\n\tconst absolutePath = resolveToCwd(rawPath, cwd);\n\tconst fileName = basename(absolutePath);\n\tif (fileName === \"SKILL.md\") {\n\t\treturn { kind: \"skill\", label: basename(dirname(absolutePath)) || fileName };\n\t}\n\n\tconst docsClassification = getPiDocsClassification(absolutePath);\n\tif (docsClassification) return docsClassification;\n\n\tif (COMPACT_RESOURCE_FILE_NAMES.has(fileName)) {\n\t\treturn { kind: \"resource\", label: formatPathRelativeToCwdOrAbsolute(absolutePath, cwd) };\n\t}\n\n\treturn undefined;\n}\n\nfunction formatCompactReadCall(\n\tclassification: CompactReadClassification,\n\targs: ReadRenderArgs | undefined,\n\ttheme: Theme,\n): string {\n\tconst expandHint = theme.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n\tif (classification.kind === \"skill\") {\n\t\treturn (\n\t\t\ttheme.fg(\"customMessageLabel\", `\\x1b[1m[skill]\\x1b[22m `) +\n\t\t\ttheme.fg(\"customMessageText\", classification.label) +\n\t\t\tformatReadLineRange(args, theme) +\n\t\t\texpandHint\n\t\t);\n\t}\n\n\treturn (\n\t\ttheme.fg(\"toolTitle\", theme.bold(`read ${classification.kind}`)) +\n\t\t\" \" +\n\t\ttheme.fg(\"accent\", classification.label) +\n\t\tformatReadLineRange(args, theme) +\n\t\texpandHint\n\t);\n}\n\nfunction formatReadResult(\n\targs: ReadRenderArgs | undefined,\n\tresult: { content: (TextContent | ImageContent)[]; details?: ReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n\t_cwd: string,\n\tisError: boolean,\n): string {\n\tif (!options.expanded && !isError) {\n\t\treturn \"\";\n\t}\n\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst output = getTextOutput(result, showImages);\n\tconst lang = !isError && rawPath ? getLanguageFromPath(rawPath) : undefined;\n\tconst renderedLines = lang ? highlightCode(replaceTabs(output), lang) : output.split(\"\\n\");\n\tconst lines = trimTrailingEmptyLines(renderedLines);\n\tconst maxLines = options.expanded ? lines.length : 10;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => (lang ? replaceTabs(line) : theme.fg(\"toolOutput\", replaceTabs(line)))).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t}\n\n\tconst truncation = result.details?.truncation;\n\tif (truncation?.truncated) {\n\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\ttext += `\\n${theme.fg(\"warning\", `[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`)}`;\n\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)]`)}`;\n\t\t} else {\n\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`)}`;\n\t\t}\n\t}\n\treturn text;\n}\n\nexport function createReadToolDefinition(\n\tcwd: string,\n\toptions?: ReadToolOptions,\n): ToolDefinition<typeof readSchema, ReadToolDetails | undefined> {\n\tconst autoResizeImages = options?.autoResizeImages ?? true;\n\tconst ops = options?.operations ?? defaultReadOperations;\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n\t\tpromptSnippet: readToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...readToolSystemPromptContribution.guidelines],\n\t\tparameters: readSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, offset, limit }: { path: string; offset?: number; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\tctx?,\n\t\t) {\n\t\t\treturn new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(\n\t\t\t\t(resolve, reject) => {\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tlet aborted = false;\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t};\n\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst absolutePath = await resolveReadPathAsync(path, cwd);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\t// Check if file exists and is readable.\n\t\t\t\t\t\t\tawait ops.access(absolutePath);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tconst mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : undefined;\n\t\t\t\t\t\t\tlet content: (TextContent | ImageContent)[];\n\t\t\t\t\t\t\tlet details: ReadToolDetails | undefined;\n\t\t\t\t\t\t\tconst nonVisionImageNote = getNonVisionImageNote(ctx?.model);\n\t\t\t\t\t\t\tif (mimeType) {\n\t\t\t\t\t\t\t\t// Read image as binary.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst processed = await processImage(buffer, mimeType, { autoResizeImages });\n\t\t\t\t\t\t\t\tif (!processed.ok) {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${mimeType}]\\n${processed.message}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: textNote }];\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${processed.mimeType}]`;\n\t\t\t\t\t\t\t\t\tif (processed.hints.length > 0) textNote += `\\n${processed.hints.join(\"\\n\")}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [\n\t\t\t\t\t\t\t\t\t\t{ type: \"text\", text: textNote },\n\t\t\t\t\t\t\t\t\t\t{ type: \"image\", data: processed.data, mimeType: processed.mimeType },\n\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Read text content.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst textContent = buffer.toString(\"utf-8\");\n\t\t\t\t\t\t\t\tconst allLines = textContent.split(\"\\n\");\n\t\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\n\t\t\t\t\t\t\t\t// Apply offset if specified. Convert from 1-indexed input to 0-indexed array access.\n\t\t\t\t\t\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\n\t\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1;\n\t\t\t\t\t\t\t\t// Check if offset is out of bounds.\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length) {\n\t\t\t\t\t\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlet selectedContent: string;\n\t\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\n\t\t\t\t\t\t\t\t// If limit is specified by the user, honor it first. Otherwise truncateHead decides.\n\t\t\t\t\t\t\t\tif (limit !== undefined) {\n\t\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t\tuserLimitedLines = endLine - startLine;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Apply truncation, respecting both line and byte limits.\n\t\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\n\t\t\t\t\t\t\t\tlet outputText: string;\n\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\t\t\t\t// First line alone exceeds the byte limit. Point the model at a bash fallback.\n\t\t\t\t\t\t\t\t\tconst firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], \"utf-8\"));\n\t\t\t\t\t\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (truncation.truncated) {\n\t\t\t\t\t\t\t\t\t// Truncation occurred. Build an actionable continuation notice.\n\t\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\t\t\t\t\t\t// User-specified limit stopped early, but the file still has more content.\n\t\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\t\t\t\t\t\t\t\t\toutputText = `${truncation.content}\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// No truncation and no remaining user-limited content.\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: outputText }];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tresolve({ content, details });\n\t\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tif (!aborted) reject(error);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tconst classification = !context.expanded ? getCompactReadClassification(args, context.cwd) : undefined;\n\t\t\ttext.setText(\n\t\t\t\tclassification\n\t\t\t\t\t? formatCompactReadCall(classification, args, theme)\n\t\t\t\t\t: formatReadCall(args, theme, context.cwd),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(\n\t\t\t\tformatReadResult(context.args, result, options, theme, context.showImages, context.cwd, context.isError),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createReadTool(cwd: string, options?: ReadToolOptions): AgentTool<typeof readSchema> {\n\treturn wrapToolDefinition(createReadToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import { basename, dirname, isAbsolute, relative, resolve as resolvePath, sep } from \"node:path\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport type { Api, ImageContent, Model, TextContent } from \"@earendil-works/pi-ai\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { constants } from \"fs\";\nimport { access as fsAccess, readFile as fsReadFile } from \"fs/promises\";\nimport { type Static, Type } from \"typebox\";\nimport { getReadmePath } from \"../../config.ts\";\nimport { keyHint, keyText } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getLanguageFromPath, highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { processImage } from \"../../utils/image-process.ts\";\nimport { detectSupportedImageMimeTypeFromFile } from \"../../utils/mime.ts\";\nimport { formatPathRelativeToCwdOrAbsolute } from \"../../utils/paths.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { resolveReadPathAsync, resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, renderToolPath, replaceTabs, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\n});\n\nexport const readToolSystemPromptContribution = {\n\tsnippet: \"Read file contents\",\n\tguidelines: [\"Use read to examine files instead of cat or sed.\"],\n} as const;\n\nexport type ReadToolInput = Static<typeof readSchema>;\n\nexport interface ReadToolDetails {\n\ttruncation?: TruncationResult;\n}\n\ninterface CompactReadClassification {\n\tkind: \"docs\" | \"resource\" | \"skill\";\n\tlabel: string;\n}\n\nconst COMPACT_RESOURCE_FILE_NAMES = new Set([\"AGENTS.override.md\", \"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"]);\n\n/**\n * Pluggable operations for the read tool.\n * Override these to delegate file reading to remote systems (for example SSH).\n */\nexport interface ReadOperations {\n\t/** Read file contents as a Buffer */\n\treadFile: (absolutePath: string) => Promise<Buffer>;\n\t/** Check if file is readable (throw if not) */\n\taccess: (absolutePath: string) => Promise<void>;\n\t/** Detect image MIME type, return null or undefined for non-images */\n\tdetectImageMimeType?: (absolutePath: string) => Promise<string | null | undefined>;\n}\n\nconst defaultReadOperations: ReadOperations = {\n\treadFile: (path) => fsReadFile(path),\n\taccess: (path) => fsAccess(path, constants.R_OK),\n\tdetectImageMimeType: detectSupportedImageMimeTypeFromFile,\n};\n\nexport interface ReadToolOptions {\n\t/** Whether to auto-resize images to 2000x2000 max. Default: true */\n\tautoResizeImages?: boolean;\n\t/** Custom operations for file reading. Default: local filesystem */\n\toperations?: ReadOperations;\n}\n\ntype ReadRenderArgs = { path?: string; file_path?: string; offset?: number; limit?: number };\n\nfunction formatReadLineRange(args: ReadRenderArgs | undefined, theme: Theme): string {\n\tif (args?.offset === undefined && args?.limit === undefined) return \"\";\n\tconst startLine = args.offset ?? 1;\n\tconst endLine = args.limit !== undefined ? startLine + args.limit - 1 : \"\";\n\treturn theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n}\n\nfunction formatReadCall(args: ReadRenderArgs | undefined, theme: Theme, cwd: string): string {\n\tconst pathDisplay = renderToolPath(str(args?.file_path ?? args?.path), theme, cwd);\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"read\"))} ${pathDisplay}${formatReadLineRange(args, theme)}`;\n}\n\nfunction trimTrailingEmptyLines(lines: string[]): string[] {\n\tlet end = lines.length;\n\twhile (end > 0 && lines[end - 1] === \"\") {\n\t\tend--;\n\t}\n\treturn lines.slice(0, end);\n}\n\nfunction getNonVisionImageNote(model: Model<Api> | undefined): string | undefined {\n\tif (!model || model.input.includes(\"image\")) {\n\t\treturn undefined;\n\t}\n\treturn \"[Current model does not support images. The image will be omitted from this request.]\";\n}\n\nfunction toPosixPath(filePath: string): string {\n\treturn filePath.split(sep).join(\"/\");\n}\n\nfunction getPiDocsClassification(absolutePath: string): CompactReadClassification | undefined {\n\tconst packageRoot = dirname(getReadmePath());\n\tconst relativePath = relative(resolvePath(packageRoot), resolvePath(absolutePath));\n\tif (\n\t\trelativePath === \"\" ||\n\t\trelativePath === \"..\" ||\n\t\trelativePath.startsWith(`..${sep}`) ||\n\t\tisAbsolute(relativePath)\n\t) {\n\t\treturn undefined;\n\t}\n\n\tconst label = toPosixPath(relativePath);\n\tif (label === \"README.md\" || label.startsWith(\"docs/\") || label.startsWith(\"examples/\")) {\n\t\treturn { kind: \"docs\", label };\n\t}\n\treturn undefined;\n}\n\nfunction getCompactReadClassification(\n\targs: ReadRenderArgs | undefined,\n\tcwd: string,\n): CompactReadClassification | undefined {\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tif (!rawPath) return undefined;\n\n\tconst absolutePath = resolveToCwd(rawPath, cwd);\n\tconst fileName = basename(absolutePath);\n\tif (fileName === \"SKILL.md\") {\n\t\treturn { kind: \"skill\", label: basename(dirname(absolutePath)) || fileName };\n\t}\n\n\tconst docsClassification = getPiDocsClassification(absolutePath);\n\tif (docsClassification) return docsClassification;\n\n\tif (COMPACT_RESOURCE_FILE_NAMES.has(fileName)) {\n\t\treturn { kind: \"resource\", label: formatPathRelativeToCwdOrAbsolute(absolutePath, cwd) };\n\t}\n\n\treturn undefined;\n}\n\nfunction formatCompactReadCall(\n\tclassification: CompactReadClassification,\n\targs: ReadRenderArgs | undefined,\n\ttheme: Theme,\n): string {\n\tconst expandHint = theme.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n\tif (classification.kind === \"skill\") {\n\t\treturn (\n\t\t\ttheme.fg(\"customMessageLabel\", `\\x1b[1m[skill]\\x1b[22m `) +\n\t\t\ttheme.fg(\"customMessageText\", classification.label) +\n\t\t\tformatReadLineRange(args, theme) +\n\t\t\texpandHint\n\t\t);\n\t}\n\n\treturn (\n\t\ttheme.fg(\"toolTitle\", theme.bold(`read ${classification.kind}`)) +\n\t\t\" \" +\n\t\ttheme.fg(\"accent\", classification.label) +\n\t\tformatReadLineRange(args, theme) +\n\t\texpandHint\n\t);\n}\n\nfunction formatReadResult(\n\targs: ReadRenderArgs | undefined,\n\tresult: { content: (TextContent | ImageContent)[]; details?: ReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n\t_cwd: string,\n\tisError: boolean,\n): string {\n\tif (!options.expanded && !isError) {\n\t\treturn \"\";\n\t}\n\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst output = getTextOutput(result, showImages);\n\tconst lang = !isError && rawPath ? getLanguageFromPath(rawPath) : undefined;\n\tconst renderedLines = lang ? highlightCode(replaceTabs(output), lang) : output.split(\"\\n\");\n\tconst lines = trimTrailingEmptyLines(renderedLines);\n\tconst maxLines = options.expanded ? lines.length : 10;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => (lang ? replaceTabs(line) : theme.fg(\"toolOutput\", replaceTabs(line)))).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t}\n\n\tconst truncation = result.details?.truncation;\n\tif (truncation?.truncated) {\n\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\ttext += `\\n${theme.fg(\"warning\", `[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`)}`;\n\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)]`)}`;\n\t\t} else {\n\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`)}`;\n\t\t}\n\t}\n\treturn text;\n}\n\nexport function createReadToolDefinition(\n\tcwd: string,\n\toptions?: ReadToolOptions,\n): ToolDefinition<typeof readSchema, ReadToolDetails | undefined> {\n\tconst autoResizeImages = options?.autoResizeImages ?? true;\n\tconst ops = options?.operations ?? defaultReadOperations;\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n\t\tpromptSnippet: readToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...readToolSystemPromptContribution.guidelines],\n\t\tparameters: readSchema,\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, offset, limit }: { path: string; offset?: number; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\tctx?,\n\t\t) {\n\t\t\treturn new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(\n\t\t\t\t(resolve, reject) => {\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tlet aborted = false;\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t};\n\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst absolutePath = await resolveReadPathAsync(path, cwd);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\t// Check if file exists and is readable.\n\t\t\t\t\t\t\tawait ops.access(absolutePath);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tconst mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : undefined;\n\t\t\t\t\t\t\tlet content: (TextContent | ImageContent)[];\n\t\t\t\t\t\t\tlet details: ReadToolDetails | undefined;\n\t\t\t\t\t\t\tconst nonVisionImageNote = getNonVisionImageNote(ctx?.model);\n\t\t\t\t\t\t\tif (mimeType) {\n\t\t\t\t\t\t\t\t// Read image as binary.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst processed = await processImage(buffer, mimeType, { autoResizeImages });\n\t\t\t\t\t\t\t\tif (!processed.ok) {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${mimeType}]\\n${processed.message}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: textNote }];\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${processed.mimeType}]`;\n\t\t\t\t\t\t\t\t\tif (processed.hints.length > 0) textNote += `\\n${processed.hints.join(\"\\n\")}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [\n\t\t\t\t\t\t\t\t\t\t{ type: \"text\", text: textNote },\n\t\t\t\t\t\t\t\t\t\t{ type: \"image\", data: processed.data, mimeType: processed.mimeType },\n\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Read text content.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst textContent = buffer.toString(\"utf-8\");\n\t\t\t\t\t\t\t\tconst allLines = textContent.split(\"\\n\");\n\t\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\n\t\t\t\t\t\t\t\t// Apply offset if specified. Convert from 1-indexed input to 0-indexed array access.\n\t\t\t\t\t\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\n\t\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1;\n\t\t\t\t\t\t\t\t// Check if offset is out of bounds.\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length) {\n\t\t\t\t\t\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlet selectedContent: string;\n\t\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\n\t\t\t\t\t\t\t\t// If limit is specified by the user, honor it first. Otherwise truncateHead decides.\n\t\t\t\t\t\t\t\tif (limit !== undefined) {\n\t\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t\tuserLimitedLines = endLine - startLine;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Apply truncation, respecting both line and byte limits.\n\t\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\n\t\t\t\t\t\t\t\tlet outputText: string;\n\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\t\t\t\t// First line alone exceeds the byte limit. Point the model at a bash fallback.\n\t\t\t\t\t\t\t\t\tconst firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], \"utf-8\"));\n\t\t\t\t\t\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (truncation.truncated) {\n\t\t\t\t\t\t\t\t\t// Truncation occurred. Build an actionable continuation notice.\n\t\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\t\t\t\t\t\t// User-specified limit stopped early, but the file still has more content.\n\t\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\t\t\t\t\t\t\t\t\toutputText = `${truncation.content}\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// No truncation and no remaining user-limited content.\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: outputText }];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tresolve({ content, details });\n\t\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tif (!aborted) reject(error);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tconst classification = !context.expanded ? getCompactReadClassification(args, context.cwd) : undefined;\n\t\t\ttext.setText(\n\t\t\t\tclassification\n\t\t\t\t\t? formatCompactReadCall(classification, args, theme)\n\t\t\t\t\t: formatReadCall(args, theme, context.cwd),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(\n\t\t\t\tformatReadResult(context.args, result, options, theme, context.showImages, context.cwd, context.isError),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createReadTool(cwd: string, options?: ReadToolOptions): AgentTool<typeof readSchema> {\n\treturn wrapToolDefinition(createReadToolDefinition(cwd, options));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"render-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAKpE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAOjD;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIjF;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAIjD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,aAAa,CAC5B,MAAM,EAAE;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,SAAS,EACzG,UAAU,EAAE,OAAO,GACjB,MAAM,CAsBR;AAED,MAAM,MAAM,oBAAoB,CAAC,QAAQ,IAAI;IAC5C,OAAO,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACxC,OAAO,EAAE,QAAQ,CAAC;CAClB,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEnD;AAED,wBAAgB,cAAc,CAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,MAAM,CAKR","sourcesContent":["import * as os from \"node:os\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { getCapabilities, getImageDimensions, hyperlink, imageFallback } from \"@earendil-works/pi-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\n\nexport function shortenPath(path: unknown): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value)), value, cwd);\n}\n"]}
1
+ {"version":3,"file":"render-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAKpE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAOjD;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIjF;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAIjD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,aAAa,CAC5B,MAAM,EAAE;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,SAAS,EACzG,UAAU,EAAE,OAAO,GACjB,MAAM,CAsBR;AAED,MAAM,MAAM,oBAAoB,CAAC,QAAQ,IAAI;IAC5C,OAAO,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACxC,OAAO,EAAE,QAAQ,CAAC;CAClB,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEnD;AAED,wBAAgB,cAAc,CAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,MAAM,CAKR"}
@@ -1 +1 @@
1
- {"version":3,"file":"render-utils.js","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { getCapabilities, getImageDimensions, hyperlink, imageFallback } from \"@earendil-works/pi-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\n\nexport function shortenPath(path: unknown): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value)), value, cwd);\n}\n"]}
1
+ {"version":3,"file":"render-utils.js","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { getCapabilities, getImageDimensions, hyperlink, imageFallback } from \"@earendil-works/pi-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\n\nexport function shortenPath(path: unknown): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value)), value, cwd);\n}\n"]}
@@ -62,14 +62,17 @@ export interface SubagentDetails {
62
62
  declare const SubagentParams: Type.TObject<{
63
63
  agent: Type.TOptional<Type.TString>;
64
64
  task: Type.TOptional<Type.TString>;
65
+ model: Type.TOptional<Type.TString>;
65
66
  tasks: Type.TOptional<Type.TArray<Type.TObject<{
66
67
  agent: Type.TString;
67
68
  task: Type.TString;
69
+ model: Type.TOptional<Type.TString>;
68
70
  cwd: Type.TOptional<Type.TString>;
69
71
  }>>>;
70
72
  chain: Type.TOptional<Type.TArray<Type.TObject<{
71
73
  agent: Type.TString;
72
74
  task: Type.TString;
75
+ model: Type.TOptional<Type.TString>;
73
76
  cwd: Type.TOptional<Type.TString>;
74
77
  }>>>;
75
78
  agentScope: Type.TOptional<Type.TUnsafe<"both" | "project" | "user">>;
@@ -1 +1 @@
1
- {"version":3,"file":"subagent.d.ts","sourceRoot":"","sources":["../../../src/core/tools/subagent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI/B,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAU/E,4FAA4F;AAC5F,eAAO,MAAM,kBAAkB,mCAAmC,CAAC;AAUnE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAyED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,oBAAoB,CAmBnF;AAoGD,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;IACtC,UAAU,EAAE,UAAU,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,oBAAoB,EAAE,CAAC;CAChC;AA4RD,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;EAUlB,CAAC;AAEH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAC,OAAO,cAAc,EAAE,eAAe,CAAC,CA+mBhH;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,2EAE7C","sourcesContent":["/**\n * Subagent Tool - Delegate tasks to specialized agents\n *\n * Spawns a separate humain-terminal process for each subagent invocation,\n * giving it an isolated context window.\n *\n * Supports three modes:\n * - Single: { agent: \"name\", task: \"...\" }\n * - Parallel: { tasks: [{ agent: \"name\", task: \"...\" }, ...] }\n * - Chain: { chain: [{ agent: \"name\", task: \"... {previous} ...\" }, ...] }\n *\n * Uses JSON mode to capture structured output from subagents.\n */\n\nimport { spawn } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { Message } from \"@earendil-works/pi-ai\";\nimport { StringEnum } from \"@earendil-works/pi-ai\";\nimport { Container, Markdown, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport { Type } from \"typebox\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../../config.ts\";\nimport { getMarkdownTheme, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { parseFrontmatter } from \"../../utils/frontmatter.ts\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { shortenPath } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst MAX_PARALLEL_TASKS = 8;\nconst MAX_CONCURRENCY = 4;\nconst COLLAPSED_ITEM_COUNT = 10;\nconst PER_TASK_OUTPUT_CAP = 50 * 1024;\n\n/** Children must not delegate further: depth 0 = top-level agent, depth >= 1 = subagent. */\nexport const SUBAGENT_DEPTH_ENV = \"HUMAIN_TERMINAL_SUBAGENT_DEPTH\";\nconst MAX_SUBAGENT_DEPTH = 1;\n\nfunction currentSubagentDepth(): number {\n\tconst raw = Number(process.env[SUBAGENT_DEPTH_ENV] ?? \"0\");\n\treturn Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 0;\n}\n\n// --- Agent discovery ---\n\nexport type AgentScope = \"user\" | \"project\" | \"both\";\n\nexport interface AgentConfig {\n\tname: string;\n\tdescription: string;\n\ttools?: string[];\n\tmodel?: string;\n\tsystemPrompt: string;\n\tsource: \"user\" | \"project\";\n\tfilePath: string;\n}\n\nexport interface AgentDiscoveryResult {\n\tagents: AgentConfig[];\n\tprojectAgentsDir: string | null;\n}\n\nfunction loadAgentsFromDir(dir: string, source: \"user\" | \"project\"): AgentConfig[] {\n\tconst agents: AgentConfig[] = [];\n\n\tif (!fs.existsSync(dir)) {\n\t\treturn agents;\n\t}\n\n\tlet entries: fs.Dirent[];\n\ttry {\n\t\tentries = fs.readdirSync(dir, { withFileTypes: true });\n\t} catch {\n\t\treturn agents;\n\t}\n\n\tfor (const entry of entries) {\n\t\tif (!entry.name.endsWith(\".md\")) continue;\n\t\tif (!entry.isFile() && !entry.isSymbolicLink()) continue;\n\n\t\tconst filePath = path.join(dir, entry.name);\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = fs.readFileSync(filePath, \"utf-8\");\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { frontmatter, body } = parseFrontmatter<Record<string, string>>(content);\n\n\t\tif (!frontmatter.name || !frontmatter.description) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst tools = frontmatter.tools\n\t\t\t?.split(\",\")\n\t\t\t.map((t: string) => t.trim())\n\t\t\t.filter(Boolean);\n\n\t\tagents.push({\n\t\t\tname: frontmatter.name,\n\t\t\tdescription: frontmatter.description,\n\t\t\ttools: tools && tools.length > 0 ? tools : undefined,\n\t\t\tmodel: frontmatter.model,\n\t\t\tsystemPrompt: body,\n\t\t\tsource,\n\t\t\tfilePath,\n\t\t});\n\t}\n\n\treturn agents;\n}\n\nfunction isDirectory(p: string): boolean {\n\ttry {\n\t\treturn fs.statSync(p).isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction findNearestProjectAgentsDir(cwd: string): string | null {\n\tlet currentDir = cwd;\n\twhile (true) {\n\t\tconst candidate = path.join(currentDir, CONFIG_DIR_NAME, \"agents\");\n\t\tif (isDirectory(candidate)) return candidate;\n\n\t\tconst parentDir = path.dirname(currentDir);\n\t\tif (parentDir === currentDir) return null;\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nexport function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryResult {\n\tconst userDir = path.join(getAgentDir(), \"agents\");\n\tconst projectAgentsDir = findNearestProjectAgentsDir(cwd);\n\n\tconst userAgents = scope === \"project\" ? [] : loadAgentsFromDir(userDir, \"user\");\n\tconst projectAgents = scope === \"user\" || !projectAgentsDir ? [] : loadAgentsFromDir(projectAgentsDir, \"project\");\n\n\tconst agentMap = new Map<string, AgentConfig>();\n\n\tif (scope === \"both\") {\n\t\tfor (const agent of userAgents) agentMap.set(agent.name, agent);\n\t\tfor (const agent of projectAgents) agentMap.set(agent.name, agent);\n\t} else if (scope === \"user\") {\n\t\tfor (const agent of userAgents) agentMap.set(agent.name, agent);\n\t} else {\n\t\tfor (const agent of projectAgents) agentMap.set(agent.name, agent);\n\t}\n\n\treturn { agents: Array.from(agentMap.values()), projectAgentsDir };\n}\n\n// --- Formatting helpers ---\n\nfunction formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\treturn `${(count / 1000000).toFixed(1)}M`;\n}\n\nfunction formatUsageStats(\n\tusage: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\tcost: number;\n\t\tcontextTokens?: number;\n\t\tturns?: number;\n\t},\n\tmodel?: string,\n): string {\n\tconst parts: string[] = [];\n\tif (usage.turns) parts.push(`${usage.turns} turn${usage.turns > 1 ? \"s\" : \"\"}`);\n\tif (usage.input) parts.push(`↑${formatTokens(usage.input)}`);\n\tif (usage.output) parts.push(`↓${formatTokens(usage.output)}`);\n\tif (usage.cacheRead) parts.push(`R${formatTokens(usage.cacheRead)}`);\n\tif (usage.cacheWrite) parts.push(`W${formatTokens(usage.cacheWrite)}`);\n\tif (usage.cost) parts.push(`$${usage.cost.toFixed(4)}`);\n\tif (usage.contextTokens && usage.contextTokens > 0) {\n\t\tparts.push(`ctx:${formatTokens(usage.contextTokens)}`);\n\t}\n\tif (model) parts.push(model);\n\treturn parts.join(\" \");\n}\n\nfunction formatToolCall(\n\ttoolName: string,\n\targs: Record<string, unknown>,\n\tthemeFg: (color: any, text: string) => string,\n): string {\n\tswitch (toolName) {\n\t\tcase \"bash\": {\n\t\t\tconst command = (args.command as string) || \"...\";\n\t\t\tconst preview = command.length > 60 ? `${command.slice(0, 60)}...` : command;\n\t\t\treturn themeFg(\"muted\", \"$ \") + themeFg(\"toolOutput\", preview);\n\t\t}\n\t\tcase \"read\": {\n\t\t\tconst rawPath = (args.file_path || args.path || \"...\") as string;\n\t\t\tconst filePath = shortenPath(rawPath);\n\t\t\tconst offset = args.offset as number | undefined;\n\t\t\tconst limit = args.limit as number | undefined;\n\t\t\tlet text = themeFg(\"accent\", filePath);\n\t\t\tif (offset !== undefined || limit !== undefined) {\n\t\t\t\tconst startLine = offset ?? 1;\n\t\t\t\tconst endLine = limit !== undefined ? startLine + limit - 1 : \"\";\n\t\t\t\ttext += themeFg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n\t\t\t}\n\t\t\treturn themeFg(\"muted\", \"read \") + text;\n\t\t}\n\t\tcase \"write\": {\n\t\t\tconst rawPath = (args.file_path || args.path || \"...\") as string;\n\t\t\tconst filePath = shortenPath(rawPath);\n\t\t\tconst content = (args.content || \"\") as string;\n\t\t\tconst lines = content.split(\"\\n\").length;\n\t\t\tlet text = themeFg(\"muted\", \"write \") + themeFg(\"accent\", filePath);\n\t\t\tif (lines > 1) text += themeFg(\"dim\", ` (${lines} lines)`);\n\t\t\treturn text;\n\t\t}\n\t\tcase \"edit\": {\n\t\t\tconst rawPath = (args.file_path || args.path || \"...\") as string;\n\t\t\treturn themeFg(\"muted\", \"edit \") + themeFg(\"accent\", shortenPath(rawPath));\n\t\t}\n\t\tcase \"ls\": {\n\t\t\tconst rawPath = (args.path || \".\") as string;\n\t\t\treturn themeFg(\"muted\", \"ls \") + themeFg(\"accent\", shortenPath(rawPath));\n\t\t}\n\t\tcase \"find\": {\n\t\t\tconst pattern = (args.pattern || \"*\") as string;\n\t\t\tconst rawPath = (args.path || \".\") as string;\n\t\t\treturn themeFg(\"muted\", \"find \") + themeFg(\"accent\", pattern) + themeFg(\"dim\", ` in ${shortenPath(rawPath)}`);\n\t\t}\n\t\tcase \"grep\": {\n\t\t\tconst pattern = (args.pattern || \"\") as string;\n\t\t\tconst rawPath = (args.path || \".\") as string;\n\t\t\treturn (\n\t\t\t\tthemeFg(\"muted\", \"grep \") +\n\t\t\t\tthemeFg(\"accent\", `/${pattern}/`) +\n\t\t\t\tthemeFg(\"dim\", ` in ${shortenPath(rawPath)}`)\n\t\t\t);\n\t\t}\n\t\tdefault: {\n\t\t\tconst argsStr = JSON.stringify(args);\n\t\t\tconst preview = argsStr.length > 50 ? `${argsStr.slice(0, 50)}...` : argsStr;\n\t\t\treturn themeFg(\"accent\", toolName) + themeFg(\"dim\", ` ${preview}`);\n\t\t}\n\t}\n}\n\nexport interface SubagentUsageStats {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\tcost: number;\n\tcontextTokens: number;\n\tturns: number;\n}\n\nexport interface SubagentSingleResult {\n\tagent: string;\n\tagentSource: \"user\" | \"project\" | \"unknown\";\n\ttask: string;\n\texitCode: number;\n\tmessages: Message[];\n\tstderr: string;\n\tusage: SubagentUsageStats;\n\tmodel?: string;\n\tstopReason?: string;\n\terrorMessage?: string;\n\tstep?: number;\n}\n\nexport interface SubagentDetails {\n\tmode: \"single\" | \"parallel\" | \"chain\";\n\tagentScope: AgentScope;\n\tprojectAgentsDir: string | null;\n\tresults: SubagentSingleResult[];\n}\n\nfunction getFinalOutput(messages: Message[]): string {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst msg = messages[i];\n\t\tif (msg.role === \"assistant\") {\n\t\t\tfor (const part of msg.content) {\n\t\t\t\tif (part.type === \"text\") return part.text;\n\t\t\t}\n\t\t}\n\t}\n\treturn \"\";\n}\n\nfunction isFailedResult(result: SubagentSingleResult): boolean {\n\treturn result.exitCode !== 0 || result.stopReason === \"error\" || result.stopReason === \"aborted\";\n}\n\nfunction getResultOutput(result: SubagentSingleResult): string {\n\tif (isFailedResult(result)) {\n\t\treturn result.errorMessage || result.stderr || getFinalOutput(result.messages) || \"(no output)\";\n\t}\n\treturn getFinalOutput(result.messages) || \"(no output)\";\n}\n\nfunction truncateParallelOutput(output: string): string {\n\tconst byteLength = Buffer.byteLength(output, \"utf8\");\n\tif (byteLength <= PER_TASK_OUTPUT_CAP) return output;\n\n\tlet truncated = output.slice(0, PER_TASK_OUTPUT_CAP);\n\twhile (Buffer.byteLength(truncated, \"utf8\") > PER_TASK_OUTPUT_CAP) {\n\t\ttruncated = truncated.slice(0, -1);\n\t}\n\treturn `${truncated}\\n\\n[Output truncated: ${byteLength - Buffer.byteLength(truncated, \"utf8\")} bytes omitted. Full output preserved in tool details.]`;\n}\n\ntype DisplayItem = { type: \"text\"; text: string } | { type: \"toolCall\"; name: string; args: Record<string, any> };\n\nfunction getDisplayItems(messages: Message[]): DisplayItem[] {\n\tconst items: DisplayItem[] = [];\n\tfor (const msg of messages) {\n\t\tif (msg.role === \"assistant\") {\n\t\t\tfor (const part of msg.content) {\n\t\t\t\tif (part.type === \"text\") items.push({ type: \"text\", text: part.text });\n\t\t\t\telse if (part.type === \"toolCall\") items.push({ type: \"toolCall\", name: part.name, args: part.arguments });\n\t\t\t}\n\t\t}\n\t}\n\treturn items;\n}\n\nasync function mapWithConcurrencyLimit<TIn, TOut>(\n\titems: TIn[],\n\tconcurrency: number,\n\tfn: (item: TIn, index: number) => Promise<TOut>,\n\tsignal?: AbortSignal,\n): Promise<TOut[]> {\n\tif (items.length === 0) return [];\n\tconst limit = Math.max(1, Math.min(concurrency, items.length));\n\tconst results: TOut[] = new Array(items.length);\n\tlet nextIndex = 0;\n\tconst workers = new Array(limit).fill(null).map(async () => {\n\t\twhile (true) {\n\t\t\t// Don't spawn doomed children for tasks still queued after an abort.\n\t\t\tif (signal?.aborted) throw new Error(\"Subagent was aborted\");\n\t\t\tconst current = nextIndex++;\n\t\t\tif (current >= items.length) return;\n\t\t\tresults[current] = await fn(items[current], current);\n\t\t}\n\t});\n\tawait Promise.all(workers);\n\treturn results;\n}\n\nasync function writePromptToTempFile(agentName: string, prompt: string): Promise<{ dir: string; filePath: string }> {\n\tconst tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), \"humain-subagent-\"));\n\tconst safeName = agentName.replace(/[^\\w.-]+/g, \"_\");\n\tconst filePath = path.join(tmpDir, `prompt-${safeName}.md`);\n\tawait withFileMutationQueue(filePath, async () => {\n\t\tawait fs.promises.writeFile(filePath, prompt, { encoding: \"utf-8\", mode: 0o600 });\n\t});\n\treturn { dir: tmpDir, filePath };\n}\n\nfunction getCliInvocation(args: string[]): { command: string; args: string[] } {\n\tconst currentScript = process.argv[1];\n\tconst isBunVirtualScript = currentScript?.startsWith(\"/$bunfs/root/\");\n\tif (currentScript && !isBunVirtualScript && fs.existsSync(currentScript)) {\n\t\treturn { command: process.execPath, args: [currentScript, ...args] };\n\t}\n\n\tconst execName = path.basename(process.execPath).toLowerCase();\n\tconst isGenericRuntime = /^(node|bun)(\\.exe)?$/.test(execName);\n\tif (!isGenericRuntime) {\n\t\treturn { command: process.execPath, args };\n\t}\n\n\treturn { command: \"humain-terminal\", args };\n}\n\ntype OnUpdateCallback = (partial: AgentToolResult<SubagentDetails>) => void;\n\nasync function runSingleAgent(\n\tdefaultCwd: string,\n\tagents: AgentConfig[],\n\tagentName: string,\n\ttask: string,\n\tcwd: string | undefined,\n\tstep: number | undefined,\n\tsignal: AbortSignal | undefined,\n\tonUpdate: OnUpdateCallback | undefined,\n\tmakeDetails: (results: SubagentSingleResult[]) => SubagentDetails,\n): Promise<SubagentSingleResult> {\n\tconst agent = agents.find((a) => a.name === agentName);\n\n\tif (!agent) {\n\t\tconst available = agents.map((a) => `\"${a.name}\"`).join(\", \") || \"none\";\n\t\treturn {\n\t\t\tagent: agentName,\n\t\t\tagentSource: \"unknown\",\n\t\t\ttask,\n\t\t\texitCode: 1,\n\t\t\tmessages: [],\n\t\t\tstderr: `Unknown agent: \"${agentName}\". Available agents: ${available}.`,\n\t\t\tusage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },\n\t\t\tstep,\n\t\t};\n\t}\n\n\tconst args: string[] = [\"--mode\", \"json\", \"-p\", \"--no-session\"];\n\tif (agent.model) args.push(\"--model\", agent.model);\n\tif (agent.tools && agent.tools.length > 0) args.push(\"--tools\", agent.tools.join(\",\"));\n\n\tlet tmpPromptDir: string | null = null;\n\tlet tmpPromptPath: string | null = null;\n\n\tconst currentResult: SubagentSingleResult = {\n\t\tagent: agentName,\n\t\tagentSource: agent.source,\n\t\ttask,\n\t\texitCode: 0,\n\t\tmessages: [],\n\t\tstderr: \"\",\n\t\tusage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },\n\t\tmodel: agent.model,\n\t\tstep,\n\t};\n\n\tconst emitUpdate = () => {\n\t\tif (onUpdate) {\n\t\t\tonUpdate({\n\t\t\t\tcontent: [{ type: \"text\", text: getFinalOutput(currentResult.messages) || \"(running...)\" }],\n\t\t\t\tdetails: makeDetails([currentResult]),\n\t\t\t});\n\t\t}\n\t};\n\n\ttry {\n\t\tif (agent.systemPrompt.trim()) {\n\t\t\tconst tmp = await writePromptToTempFile(agent.name, agent.systemPrompt);\n\t\t\ttmpPromptDir = tmp.dir;\n\t\t\ttmpPromptPath = tmp.filePath;\n\t\t\targs.push(\"--append-system-prompt\", tmpPromptPath);\n\t\t}\n\n\t\targs.push(`Task: ${task}`);\n\t\tlet wasAborted = false;\n\n\t\tconst exitCode = await new Promise<number>((resolve) => {\n\t\t\tconst invocation = getCliInvocation(args);\n\t\t\tconst proc = spawn(invocation.command, invocation.args, {\n\t\t\t\tcwd: cwd ?? defaultCwd,\n\t\t\t\tshell: false,\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\tenv: { ...process.env, [SUBAGENT_DEPTH_ENV]: String(currentSubagentDepth() + 1) },\n\t\t\t});\n\t\t\tlet buffer = \"\";\n\n\t\t\tconst processLine = (line: string) => {\n\t\t\t\tif (!line.trim()) return;\n\t\t\t\tlet event: any;\n\t\t\t\ttry {\n\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t} catch {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (event.type === \"message_end\" && event.message) {\n\t\t\t\t\tconst msg = event.message as Message;\n\t\t\t\t\tcurrentResult.messages.push(msg);\n\n\t\t\t\t\tif (msg.role === \"assistant\") {\n\t\t\t\t\t\tcurrentResult.usage.turns++;\n\t\t\t\t\t\tconst usage = msg.usage;\n\t\t\t\t\t\tif (usage) {\n\t\t\t\t\t\t\tcurrentResult.usage.input += usage.input || 0;\n\t\t\t\t\t\t\tcurrentResult.usage.output += usage.output || 0;\n\t\t\t\t\t\t\tcurrentResult.usage.cacheRead += usage.cacheRead || 0;\n\t\t\t\t\t\t\tcurrentResult.usage.cacheWrite += usage.cacheWrite || 0;\n\t\t\t\t\t\t\tcurrentResult.usage.cost += usage.cost?.total || 0;\n\t\t\t\t\t\t\tcurrentResult.usage.contextTokens = usage.totalTokens || 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!currentResult.model && msg.model) currentResult.model = msg.model;\n\t\t\t\t\t\tif (msg.stopReason) currentResult.stopReason = msg.stopReason;\n\t\t\t\t\t\tif (msg.errorMessage) currentResult.errorMessage = msg.errorMessage;\n\t\t\t\t\t}\n\t\t\t\t\temitUpdate();\n\t\t\t\t}\n\n\t\t\t\tif (event.type === \"tool_result_end\" && event.message) {\n\t\t\t\t\tcurrentResult.messages.push(event.message as Message);\n\t\t\t\t\temitUpdate();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tproc.stdout.on(\"data\", (data) => {\n\t\t\t\tbuffer += data.toString();\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() || \"\";\n\t\t\t\tfor (const line of lines) processLine(line);\n\t\t\t});\n\n\t\t\tproc.stderr.on(\"data\", (data) => {\n\t\t\t\tcurrentResult.stderr += data.toString();\n\t\t\t});\n\n\t\t\tproc.on(\"close\", (code) => {\n\t\t\t\tif (buffer.trim()) processLine(buffer);\n\t\t\t\tresolve(code ?? 0);\n\t\t\t});\n\n\t\t\tproc.on(\"error\", () => {\n\t\t\t\tresolve(1);\n\t\t\t});\n\n\t\t\tif (signal) {\n\t\t\t\tconst killProc = () => {\n\t\t\t\t\twasAborted = true;\n\t\t\t\t\tproc.kill(\"SIGTERM\");\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tif (!proc.killed) proc.kill(\"SIGKILL\");\n\t\t\t\t\t}, 5000);\n\t\t\t\t};\n\t\t\t\tif (signal.aborted) killProc();\n\t\t\t\telse signal.addEventListener(\"abort\", killProc, { once: true });\n\t\t\t}\n\t\t});\n\n\t\tcurrentResult.exitCode = exitCode;\n\t\tif (wasAborted) throw new Error(\"Subagent was aborted\");\n\t\treturn currentResult;\n\t} finally {\n\t\tif (tmpPromptPath)\n\t\t\ttry {\n\t\t\t\tfs.unlinkSync(tmpPromptPath);\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\tif (tmpPromptDir)\n\t\t\ttry {\n\t\t\t\tfs.rmdirSync(tmpPromptDir);\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t}\n}\n\nconst TaskItem = Type.Object({\n\tagent: Type.String({ description: \"Name of the agent to invoke\" }),\n\ttask: Type.String({ description: \"Task to delegate to the agent\" }),\n\tcwd: Type.Optional(Type.String({ description: \"Working directory for the agent process\" })),\n});\n\nconst ChainItem = Type.Object({\n\tagent: Type.String({ description: \"Name of the agent to invoke\" }),\n\ttask: Type.String({ description: \"Task with optional {previous} placeholder for prior output\" }),\n\tcwd: Type.Optional(Type.String({ description: \"Working directory for the agent process\" })),\n});\n\nconst AgentScopeSchema = StringEnum([\"user\", \"project\", \"both\"] as const, {\n\tdescription: 'Which agent directories to use. Default: \"user\". Use \"both\" to include project-local agents.',\n\tdefault: \"user\",\n});\n\nconst SubagentParams = Type.Object({\n\tagent: Type.Optional(Type.String({ description: \"Name of the agent to invoke (for single mode)\" })),\n\ttask: Type.Optional(Type.String({ description: \"Task to delegate (for single mode)\" })),\n\ttasks: Type.Optional(Type.Array(TaskItem, { description: \"Array of {agent, task} for parallel execution\" })),\n\tchain: Type.Optional(Type.Array(ChainItem, { description: \"Array of {agent, task} for sequential execution\" })),\n\tagentScope: Type.Optional(AgentScopeSchema),\n\tconfirmProjectAgents: Type.Optional(\n\t\tType.Boolean({ description: \"Prompt before running project-local agents. Default: true.\", default: true }),\n\t),\n\tcwd: Type.Optional(Type.String({ description: \"Working directory for the agent process (single mode)\" })),\n});\n\nexport function createSubagentToolDefinition(cwd: string): ToolDefinition<typeof SubagentParams, SubagentDetails> {\n\treturn {\n\t\tname: \"subagent\",\n\t\tlabel: \"Subagent\",\n\t\tdescription: [\n\t\t\t\"Delegate tasks to specialized subagents with isolated context.\",\n\t\t\t\"Modes: single (agent + task), parallel (tasks array), chain (sequential with {previous} placeholder).\",\n\t\t\t`Default agent scope is \"user\" (from ${path.join(getAgentDir(), \"agents\")}).`,\n\t\t\t`To enable project-local agents in ${CONFIG_DIR_NAME}/agents, set agentScope: \"both\" (or \"project\").`,\n\t\t].join(\" \"),\n\t\tpromptSnippet:\n\t\t\t\"subagent: delegate work to isolated subagents — single task, parallel batch (tasks array), or sequential chain with {previous} placeholder\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use subagent to fan out independent work in parallel (tasks array) or run multi-step pipelines (chain). Subagents run with isolated context and cannot delegate further.\",\n\t\t],\n\t\tparameters: SubagentParams,\n\n\t\tasync execute(_toolCallId, params, signal, onUpdate, ctx: ExtensionContext) {\n\t\t\tconst agentScope: AgentScope = params.agentScope ?? \"user\";\n\t\t\tconst defaultCwd = ctx?.cwd ?? cwd;\n\t\t\tconst discovery = discoverAgents(defaultCwd, agentScope);\n\t\t\tconst agents = discovery.agents;\n\t\t\tconst confirmProjectAgents = params.confirmProjectAgents ?? true;\n\n\t\t\t// Every requested child must appear in details.results, even when\n\t\t\t// nothing ran: external consumers fan out per-child bookkeeping from\n\t\t\t// the tool args and reconcile it against results by index.\n\t\t\tconst requestedChildren = (): Array<{ agent: string; task?: string; step?: number }> => {\n\t\t\t\tif (params.tasks && params.tasks.length > 0)\n\t\t\t\t\treturn params.tasks.map((t) => ({ agent: t.agent, task: t.task }));\n\t\t\t\tif (params.chain && params.chain.length > 0)\n\t\t\t\t\treturn params.chain.map((s, i) => ({ agent: s.agent, task: s.task, step: i + 1 }));\n\t\t\t\tif (params.agent) return [{ agent: params.agent, task: params.task }];\n\t\t\t\treturn [];\n\t\t\t};\n\t\t\tconst stubResult = (\n\t\t\t\tchild: { agent: string; task?: string; step?: number },\n\t\t\t\terrorMessage: string,\n\t\t\t): SubagentSingleResult => ({\n\t\t\t\tagent: child.agent,\n\t\t\t\tagentSource: \"unknown\",\n\t\t\t\ttask: child.task ?? \"\",\n\t\t\t\texitCode: 1,\n\t\t\t\tmessages: [],\n\t\t\t\tstderr: \"\",\n\t\t\t\tusage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },\n\t\t\t\terrorMessage,\n\t\t\t\tstep: child.step,\n\t\t\t});\n\t\t\tconst stubAllChildren = (errorMessage: string): SubagentSingleResult[] =>\n\t\t\t\trequestedChildren().map((child) => stubResult(child, errorMessage));\n\n\t\t\tconst makeDetails =\n\t\t\t\t(mode: \"single\" | \"parallel\" | \"chain\") =>\n\t\t\t\t(results: SubagentSingleResult[]): SubagentDetails => ({\n\t\t\t\t\tmode,\n\t\t\t\t\tagentScope,\n\t\t\t\t\tprojectAgentsDir: discovery.projectAgentsDir,\n\t\t\t\t\tresults,\n\t\t\t\t});\n\n\t\t\tif (currentSubagentDepth() >= MAX_SUBAGENT_DEPTH) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: \"Nested delegation is not allowed: this process is already a subagent. Complete the task directly.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: makeDetails(\"single\")([]),\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst hasChain = (params.chain?.length ?? 0) > 0;\n\t\t\tconst hasTasks = (params.tasks?.length ?? 0) > 0;\n\t\t\tconst hasSingle = Boolean(params.agent && params.task);\n\t\t\tconst modeCount = Number(hasChain) + Number(hasTasks) + Number(hasSingle);\n\n\t\t\tif (modeCount !== 1) {\n\t\t\t\tconst available = agents.map((a) => `${a.name} (${a.source})`).join(\", \") || \"none\";\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Invalid parameters. Provide exactly one mode.\\nAvailable agents: ${available}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: makeDetails(\"single\")(\n\t\t\t\t\t\tstubAllChildren(\"not run: invalid parameters (provide exactly one mode)\"),\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif ((agentScope === \"project\" || agentScope === \"both\") && confirmProjectAgents && ctx?.hasUI) {\n\t\t\t\tconst requestedAgentNames = new Set<string>();\n\t\t\t\tif (params.chain) for (const step of params.chain) requestedAgentNames.add(step.agent);\n\t\t\t\tif (params.tasks) for (const t of params.tasks) requestedAgentNames.add(t.agent);\n\t\t\t\tif (params.agent) requestedAgentNames.add(params.agent);\n\n\t\t\t\tconst projectAgentsRequested = Array.from(requestedAgentNames)\n\t\t\t\t\t.map((name) => agents.find((a) => a.name === name))\n\t\t\t\t\t.filter((a): a is AgentConfig => a?.source === \"project\");\n\n\t\t\t\tif (projectAgentsRequested.length > 0) {\n\t\t\t\t\tconst names = projectAgentsRequested.map((a) => a.name).join(\", \");\n\t\t\t\t\tconst dir = discovery.projectAgentsDir ?? \"(unknown)\";\n\t\t\t\t\tconst ok = await ctx.ui.confirm(\n\t\t\t\t\t\t\"Run project-local agents?\",\n\t\t\t\t\t\t`Agents: ${names}\\nSource: ${dir}\\n\\nProject agents are repo-controlled. Only continue for trusted repositories.`,\n\t\t\t\t\t);\n\t\t\t\t\tif (!ok)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"Canceled: project-local agents not approved.\" }],\n\t\t\t\t\t\t\tdetails: makeDetails(hasChain ? \"chain\" : hasTasks ? \"parallel\" : \"single\")(\n\t\t\t\t\t\t\t\tstubAllChildren(\"canceled: project-local agents not approved\"),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tisError: true,\n\t\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (params.chain && params.chain.length > 0) {\n\t\t\t\tconst results: SubagentSingleResult[] = [];\n\t\t\t\tlet previousOutput = \"\";\n\n\t\t\t\tfor (let i = 0; i < params.chain.length; i++) {\n\t\t\t\t\tconst step = params.chain[i];\n\t\t\t\t\tconst taskWithContext = step.task.replace(/\\{previous\\}/g, previousOutput);\n\n\t\t\t\t\t// Create update callback that includes all previous results\n\t\t\t\t\tconst chainUpdate: OnUpdateCallback | undefined = onUpdate\n\t\t\t\t\t\t? (partial) => {\n\t\t\t\t\t\t\t\t// Combine completed results with current streaming result\n\t\t\t\t\t\t\t\tconst currentResult = partial.details?.results[0];\n\t\t\t\t\t\t\t\tif (currentResult) {\n\t\t\t\t\t\t\t\t\tconst allResults = [...results, currentResult];\n\t\t\t\t\t\t\t\t\tonUpdate({\n\t\t\t\t\t\t\t\t\t\tcontent: partial.content,\n\t\t\t\t\t\t\t\t\t\tdetails: makeDetails(\"chain\")(allResults),\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\t\tconst result = await runSingleAgent(\n\t\t\t\t\t\tdefaultCwd,\n\t\t\t\t\t\tagents,\n\t\t\t\t\t\tstep.agent,\n\t\t\t\t\t\ttaskWithContext,\n\t\t\t\t\t\tstep.cwd,\n\t\t\t\t\t\ti + 1,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tchainUpdate,\n\t\t\t\t\t\tmakeDetails(\"chain\"),\n\t\t\t\t\t);\n\t\t\t\t\tresults.push(result);\n\n\t\t\t\t\tconst isError = isFailedResult(result);\n\t\t\t\t\tif (isError) {\n\t\t\t\t\t\tconst errorMsg = getResultOutput(result);\n\t\t\t\t\t\tconst skipped = params.chain\n\t\t\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t\t\t.map((s, offset) =>\n\t\t\t\t\t\t\t\tstubResult(\n\t\t\t\t\t\t\t\t\t{ agent: s.agent, task: s.task, step: i + 2 + offset },\n\t\t\t\t\t\t\t\t\t`not run: chain stopped at step ${i + 1}`,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: `Chain stopped at step ${i + 1} (${step.agent}): ${errorMsg}` }],\n\t\t\t\t\t\t\tdetails: makeDetails(\"chain\")([...results, ...skipped]),\n\t\t\t\t\t\t\tisError: true,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tpreviousOutput = getFinalOutput(result.messages);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: getFinalOutput(results[results.length - 1].messages) || \"(no output)\" }],\n\t\t\t\t\tdetails: makeDetails(\"chain\")(results),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (params.tasks && params.tasks.length > 0) {\n\t\t\t\tif (params.tasks.length > MAX_PARALLEL_TASKS)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\ttext: `Too many parallel tasks (${params.tasks.length}). Max is ${MAX_PARALLEL_TASKS}.`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tdetails: makeDetails(\"parallel\")(\n\t\t\t\t\t\t\tstubAllChildren(`not run: too many parallel tasks (max ${MAX_PARALLEL_TASKS})`),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\n\t\t\t\t// Track all results for streaming updates\n\t\t\t\tconst allResults: SubagentSingleResult[] = new Array(params.tasks.length);\n\n\t\t\t\t// Initialize placeholder results\n\t\t\t\tfor (let i = 0; i < params.tasks.length; i++) {\n\t\t\t\t\tallResults[i] = {\n\t\t\t\t\t\tagent: params.tasks[i].agent,\n\t\t\t\t\t\tagentSource: \"unknown\",\n\t\t\t\t\t\ttask: params.tasks[i].task,\n\t\t\t\t\t\texitCode: -1, // -1 = still running\n\t\t\t\t\t\tmessages: [],\n\t\t\t\t\t\tstderr: \"\",\n\t\t\t\t\t\tusage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst emitParallelUpdate = () => {\n\t\t\t\t\tif (onUpdate) {\n\t\t\t\t\t\tconst running = allResults.filter((r) => r.exitCode === -1).length;\n\t\t\t\t\t\tconst done = allResults.filter((r) => r.exitCode !== -1).length;\n\t\t\t\t\t\tonUpdate({\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{ type: \"text\", text: `Parallel: ${done}/${allResults.length} done, ${running} running...` },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: makeDetails(\"parallel\")([...allResults]),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst results = await mapWithConcurrencyLimit(\n\t\t\t\t\tparams.tasks,\n\t\t\t\t\tMAX_CONCURRENCY,\n\t\t\t\t\tasync (t, index) => {\n\t\t\t\t\t\tconst result = await runSingleAgent(\n\t\t\t\t\t\t\tdefaultCwd,\n\t\t\t\t\t\t\tagents,\n\t\t\t\t\t\t\tt.agent,\n\t\t\t\t\t\t\tt.task,\n\t\t\t\t\t\t\tt.cwd,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\t// Per-task update callback\n\t\t\t\t\t\t\t(partial) => {\n\t\t\t\t\t\t\t\tif (partial.details?.results[0]) {\n\t\t\t\t\t\t\t\t\tallResults[index] = partial.details.results[0];\n\t\t\t\t\t\t\t\t\temitParallelUpdate();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmakeDetails(\"parallel\"),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tallResults[index] = result;\n\t\t\t\t\t\temitParallelUpdate();\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t},\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\n\t\t\t\tconst successCount = results.filter((r) => !isFailedResult(r)).length;\n\t\t\t\tconst summaries = results.map((r) => {\n\t\t\t\t\tconst output = truncateParallelOutput(getResultOutput(r));\n\t\t\t\t\tconst status = isFailedResult(r)\n\t\t\t\t\t\t? `failed${r.stopReason && r.stopReason !== \"end\" ? ` (${r.stopReason})` : \"\"}`\n\t\t\t\t\t\t: \"completed\";\n\t\t\t\t\treturn `### [${r.agent}] ${status}\\n\\n${output}`;\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Parallel: ${successCount}/${results.length} succeeded\\n\\n${summaries.join(\"\\n\\n---\\n\\n\")}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: makeDetails(\"parallel\")(results),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (params.agent && params.task) {\n\t\t\t\tconst result = await runSingleAgent(\n\t\t\t\t\tdefaultCwd,\n\t\t\t\t\tagents,\n\t\t\t\t\tparams.agent,\n\t\t\t\t\tparams.task,\n\t\t\t\t\tparams.cwd,\n\t\t\t\t\tundefined,\n\t\t\t\t\tsignal,\n\t\t\t\t\tonUpdate,\n\t\t\t\t\tmakeDetails(\"single\"),\n\t\t\t\t);\n\t\t\t\tconst isError = isFailedResult(result);\n\t\t\t\tif (isError) {\n\t\t\t\t\tconst errorMsg = getResultOutput(result);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: `Agent ${result.stopReason || \"failed\"}: ${errorMsg}` }],\n\t\t\t\t\t\tdetails: makeDetails(\"single\")([result]),\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: getFinalOutput(result.messages) || \"(no output)\" }],\n\t\t\t\t\tdetails: makeDetails(\"single\")([result]),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst available = agents.map((a) => `${a.name} (${a.source})`).join(\", \") || \"none\";\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `Invalid parameters. Available agents: ${available}` }],\n\t\t\t\tdetails: makeDetails(\"single\")([]),\n\t\t\t};\n\t\t},\n\n\t\trenderCall(args, theme: Theme, _context) {\n\t\t\tconst scope: AgentScope = args.agentScope ?? \"user\";\n\t\t\tif (args.chain && args.chain.length > 0) {\n\t\t\t\tlet text =\n\t\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"subagent \")) +\n\t\t\t\t\ttheme.fg(\"accent\", `chain (${args.chain.length} steps)`) +\n\t\t\t\t\ttheme.fg(\"muted\", ` [${scope}]`);\n\t\t\t\tfor (let i = 0; i < Math.min(args.chain.length, 3); i++) {\n\t\t\t\t\tconst step = args.chain[i];\n\t\t\t\t\t// Clean up {previous} placeholder for display\n\t\t\t\t\tconst cleanTask = step.task.replace(/\\{previous\\}/g, \"\").trim();\n\t\t\t\t\tconst preview = cleanTask.length > 40 ? `${cleanTask.slice(0, 40)}...` : cleanTask;\n\t\t\t\t\ttext +=\n\t\t\t\t\t\t\"\\n \" +\n\t\t\t\t\t\ttheme.fg(\"muted\", `${i + 1}.`) +\n\t\t\t\t\t\t\" \" +\n\t\t\t\t\t\ttheme.fg(\"accent\", step.agent) +\n\t\t\t\t\t\ttheme.fg(\"dim\", ` ${preview}`);\n\t\t\t\t}\n\t\t\t\tif (args.chain.length > 3) text += `\\n ${theme.fg(\"muted\", `... +${args.chain.length - 3} more`)}`;\n\t\t\t\treturn new Text(text, 0, 0);\n\t\t\t}\n\t\t\tif (args.tasks && args.tasks.length > 0) {\n\t\t\t\tlet text =\n\t\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"subagent \")) +\n\t\t\t\t\ttheme.fg(\"accent\", `parallel (${args.tasks.length} tasks)`) +\n\t\t\t\t\ttheme.fg(\"muted\", ` [${scope}]`);\n\t\t\t\tfor (const t of args.tasks.slice(0, 3)) {\n\t\t\t\t\tconst preview = t.task.length > 40 ? `${t.task.slice(0, 40)}...` : t.task;\n\t\t\t\t\ttext += `\\n ${theme.fg(\"accent\", t.agent)}${theme.fg(\"dim\", ` ${preview}`)}`;\n\t\t\t\t}\n\t\t\t\tif (args.tasks.length > 3) text += `\\n ${theme.fg(\"muted\", `... +${args.tasks.length - 3} more`)}`;\n\t\t\t\treturn new Text(text, 0, 0);\n\t\t\t}\n\t\t\tconst agentName = args.agent || \"...\";\n\t\t\tconst preview = args.task ? (args.task.length > 60 ? `${args.task.slice(0, 60)}...` : args.task) : \"...\";\n\t\t\tlet text =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"subagent \")) +\n\t\t\t\ttheme.fg(\"accent\", agentName) +\n\t\t\t\ttheme.fg(\"muted\", ` [${scope}]`);\n\t\t\ttext += `\\n ${theme.fg(\"dim\", preview)}`;\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\n\t\trenderResult(result, { expanded }, theme: Theme, _context) {\n\t\t\tconst details = result.details as SubagentDetails | undefined;\n\t\t\tif (!details || details.results.length === 0) {\n\t\t\t\tconst text = result.content[0];\n\t\t\t\treturn new Text(text?.type === \"text\" ? text.text : \"(no output)\", 0, 0);\n\t\t\t}\n\n\t\t\tconst mdTheme = getMarkdownTheme();\n\n\t\t\tconst renderDisplayItems = (items: DisplayItem[], limit?: number) => {\n\t\t\t\tconst toShow = limit ? items.slice(-limit) : items;\n\t\t\t\tconst skipped = limit && items.length > limit ? items.length - limit : 0;\n\t\t\t\tlet text = \"\";\n\t\t\t\tif (skipped > 0) text += theme.fg(\"muted\", `... ${skipped} earlier items\\n`);\n\t\t\t\tfor (const item of toShow) {\n\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\tconst preview = expanded ? item.text : item.text.split(\"\\n\").slice(0, 3).join(\"\\n\");\n\t\t\t\t\t\ttext += `${theme.fg(\"toolOutput\", preview)}\\n`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `${theme.fg(\"muted\", \"→ \") + formatToolCall(item.name, item.args, theme.fg.bind(theme))}\\n`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn text.trimEnd();\n\t\t\t};\n\n\t\t\tif (details.mode === \"single\" && details.results.length === 1) {\n\t\t\t\tconst r = details.results[0];\n\t\t\t\tconst isError = isFailedResult(r);\n\t\t\t\tconst icon = isError ? theme.fg(\"error\", \"✗\") : theme.fg(\"success\", \"✓\");\n\t\t\t\tconst displayItems = getDisplayItems(r.messages);\n\t\t\t\tconst finalOutput = getFinalOutput(r.messages);\n\n\t\t\t\tif (expanded) {\n\t\t\t\t\tconst container = new Container();\n\t\t\t\t\tlet header = `${icon} ${theme.fg(\"toolTitle\", theme.bold(r.agent))}${theme.fg(\"muted\", ` (${r.agentSource})`)}`;\n\t\t\t\t\tif (isError && r.stopReason) header += ` ${theme.fg(\"error\", `[${r.stopReason}]`)}`;\n\t\t\t\t\tcontainer.addChild(new Text(header, 0, 0));\n\t\t\t\t\tif (isError && r.errorMessage)\n\t\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"error\", `Error: ${r.errorMessage}`), 0, 0));\n\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"─── Task ───\"), 0, 0));\n\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", r.task), 0, 0));\n\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"─── Output ───\"), 0, 0));\n\t\t\t\t\tif (displayItems.length === 0 && !finalOutput) {\n\t\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"(no output)\"), 0, 0));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor (const item of displayItems) {\n\t\t\t\t\t\t\tif (item.type === \"toolCall\")\n\t\t\t\t\t\t\t\tcontainer.addChild(\n\t\t\t\t\t\t\t\t\tnew Text(\n\t\t\t\t\t\t\t\t\t\ttheme.fg(\"muted\", \"→ \") + formatToolCall(item.name, item.args, theme.fg.bind(theme)),\n\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (finalOutput) {\n\t\t\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\t\t\tcontainer.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst usageStr = formatUsageStats(r.usage, r.model);\n\t\t\t\t\tif (usageStr) {\n\t\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", usageStr), 0, 0));\n\t\t\t\t\t}\n\t\t\t\t\treturn container;\n\t\t\t\t}\n\n\t\t\t\tlet text = `${icon} ${theme.fg(\"toolTitle\", theme.bold(r.agent))}${theme.fg(\"muted\", ` (${r.agentSource})`)}`;\n\t\t\t\tif (isError && r.stopReason) text += ` ${theme.fg(\"error\", `[${r.stopReason}]`)}`;\n\t\t\t\tif (isError && r.errorMessage) text += `\\n${theme.fg(\"error\", `Error: ${r.errorMessage}`)}`;\n\t\t\t\telse if (displayItems.length === 0) text += `\\n${theme.fg(\"muted\", \"(no output)\")}`;\n\t\t\t\telse {\n\t\t\t\t\ttext += `\\n${renderDisplayItems(displayItems, COLLAPSED_ITEM_COUNT)}`;\n\t\t\t\t\tif (displayItems.length > COLLAPSED_ITEM_COUNT) text += `\\n${theme.fg(\"muted\", \"(Ctrl+O to expand)\")}`;\n\t\t\t\t}\n\t\t\t\tconst usageStr = formatUsageStats(r.usage, r.model);\n\t\t\t\tif (usageStr) text += `\\n${theme.fg(\"dim\", usageStr)}`;\n\t\t\t\treturn new Text(text, 0, 0);\n\t\t\t}\n\n\t\t\tconst aggregateUsage = (results: SubagentSingleResult[]) => {\n\t\t\t\tconst total = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };\n\t\t\t\tfor (const r of results) {\n\t\t\t\t\ttotal.input += r.usage.input;\n\t\t\t\t\ttotal.output += r.usage.output;\n\t\t\t\t\ttotal.cacheRead += r.usage.cacheRead;\n\t\t\t\t\ttotal.cacheWrite += r.usage.cacheWrite;\n\t\t\t\t\ttotal.cost += r.usage.cost;\n\t\t\t\t\ttotal.turns += r.usage.turns;\n\t\t\t\t}\n\t\t\t\treturn total;\n\t\t\t};\n\n\t\t\tif (details.mode === \"chain\") {\n\t\t\t\tconst successCount = details.results.filter((r) => r.exitCode === 0).length;\n\t\t\t\tconst icon = successCount === details.results.length ? theme.fg(\"success\", \"✓\") : theme.fg(\"error\", \"✗\");\n\n\t\t\t\tif (expanded) {\n\t\t\t\t\tconst container = new Container();\n\t\t\t\t\tcontainer.addChild(\n\t\t\t\t\t\tnew Text(\n\t\t\t\t\t\t\ticon +\n\t\t\t\t\t\t\t\t\" \" +\n\t\t\t\t\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"chain \")) +\n\t\t\t\t\t\t\t\ttheme.fg(\"accent\", `${successCount}/${details.results.length} steps`),\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tfor (const r of details.results) {\n\t\t\t\t\t\tconst rIcon = r.exitCode === 0 ? theme.fg(\"success\", \"✓\") : theme.fg(\"error\", \"✗\");\n\t\t\t\t\t\tconst displayItems = getDisplayItems(r.messages);\n\t\t\t\t\t\tconst finalOutput = getFinalOutput(r.messages);\n\n\t\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\t\tcontainer.addChild(\n\t\t\t\t\t\t\tnew Text(\n\t\t\t\t\t\t\t\t`${theme.fg(\"muted\", `─── Step ${r.step}: `) + theme.fg(\"accent\", r.agent)} ${rIcon}`,\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Task: \") + theme.fg(\"dim\", r.task), 0, 0));\n\n\t\t\t\t\t\t// Show tool calls\n\t\t\t\t\t\tfor (const item of displayItems) {\n\t\t\t\t\t\t\tif (item.type === \"toolCall\") {\n\t\t\t\t\t\t\t\tcontainer.addChild(\n\t\t\t\t\t\t\t\t\tnew Text(\n\t\t\t\t\t\t\t\t\t\ttheme.fg(\"muted\", \"→ \") + formatToolCall(item.name, item.args, theme.fg.bind(theme)),\n\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Show final output as markdown\n\t\t\t\t\t\tif (finalOutput) {\n\t\t\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\t\t\tcontainer.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst stepUsage = formatUsageStats(r.usage, r.model);\n\t\t\t\t\t\tif (stepUsage) container.addChild(new Text(theme.fg(\"dim\", stepUsage), 0, 0));\n\t\t\t\t\t}\n\n\t\t\t\t\tconst usageStr = formatUsageStats(aggregateUsage(details.results));\n\t\t\t\t\tif (usageStr) {\n\t\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", `Total: ${usageStr}`), 0, 0));\n\t\t\t\t\t}\n\t\t\t\t\treturn container;\n\t\t\t\t}\n\n\t\t\t\t// Collapsed view\n\t\t\t\tlet text =\n\t\t\t\t\ticon +\n\t\t\t\t\t\" \" +\n\t\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"chain \")) +\n\t\t\t\t\ttheme.fg(\"accent\", `${successCount}/${details.results.length} steps`);\n\t\t\t\tfor (const r of details.results) {\n\t\t\t\t\tconst rIcon = r.exitCode === 0 ? theme.fg(\"success\", \"✓\") : theme.fg(\"error\", \"✗\");\n\t\t\t\t\tconst displayItems = getDisplayItems(r.messages);\n\t\t\t\t\ttext += `\\n\\n${theme.fg(\"muted\", `─── Step ${r.step}: `)}${theme.fg(\"accent\", r.agent)} ${rIcon}`;\n\t\t\t\t\tif (displayItems.length === 0) text += `\\n${theme.fg(\"muted\", \"(no output)\")}`;\n\t\t\t\t\telse text += `\\n${renderDisplayItems(displayItems, 5)}`;\n\t\t\t\t}\n\t\t\t\tconst usageStr = formatUsageStats(aggregateUsage(details.results));\n\t\t\t\tif (usageStr) text += `\\n\\n${theme.fg(\"dim\", `Total: ${usageStr}`)}`;\n\t\t\t\ttext += `\\n${theme.fg(\"muted\", \"(Ctrl+O to expand)\")}`;\n\t\t\t\treturn new Text(text, 0, 0);\n\t\t\t}\n\n\t\t\tif (details.mode === \"parallel\") {\n\t\t\t\tconst running = details.results.filter((r) => r.exitCode === -1).length;\n\t\t\t\tconst successCount = details.results.filter((r) => r.exitCode !== -1 && !isFailedResult(r)).length;\n\t\t\t\tconst failCount = details.results.filter((r) => r.exitCode !== -1 && isFailedResult(r)).length;\n\t\t\t\tconst isRunning = running > 0;\n\t\t\t\tconst icon = isRunning\n\t\t\t\t\t? theme.fg(\"warning\", \"⏳\")\n\t\t\t\t\t: failCount > 0\n\t\t\t\t\t\t? theme.fg(\"warning\", \"◐\")\n\t\t\t\t\t\t: theme.fg(\"success\", \"✓\");\n\t\t\t\tconst status = isRunning\n\t\t\t\t\t? `${successCount + failCount}/${details.results.length} done, ${running} running`\n\t\t\t\t\t: `${successCount}/${details.results.length} tasks`;\n\n\t\t\t\tif (expanded && !isRunning) {\n\t\t\t\t\tconst container = new Container();\n\t\t\t\t\tcontainer.addChild(\n\t\t\t\t\t\tnew Text(\n\t\t\t\t\t\t\t`${icon} ${theme.fg(\"toolTitle\", theme.bold(\"parallel \"))}${theme.fg(\"accent\", status)}`,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tfor (const r of details.results) {\n\t\t\t\t\t\tconst rIcon = isFailedResult(r) ? theme.fg(\"error\", \"✗\") : theme.fg(\"success\", \"✓\");\n\t\t\t\t\t\tconst displayItems = getDisplayItems(r.messages);\n\t\t\t\t\t\tconst finalOutput = getFinalOutput(r.messages);\n\n\t\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\t\tcontainer.addChild(\n\t\t\t\t\t\t\tnew Text(`${theme.fg(\"muted\", \"─── \") + theme.fg(\"accent\", r.agent)} ${rIcon}`, 0, 0),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Task: \") + theme.fg(\"dim\", r.task), 0, 0));\n\n\t\t\t\t\t\t// Show tool calls\n\t\t\t\t\t\tfor (const item of displayItems) {\n\t\t\t\t\t\t\tif (item.type === \"toolCall\") {\n\t\t\t\t\t\t\t\tcontainer.addChild(\n\t\t\t\t\t\t\t\t\tnew Text(\n\t\t\t\t\t\t\t\t\t\ttheme.fg(\"muted\", \"→ \") + formatToolCall(item.name, item.args, theme.fg.bind(theme)),\n\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Show final output as markdown\n\t\t\t\t\t\tif (finalOutput) {\n\t\t\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\t\t\tcontainer.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst taskUsage = formatUsageStats(r.usage, r.model);\n\t\t\t\t\t\tif (taskUsage) container.addChild(new Text(theme.fg(\"dim\", taskUsage), 0, 0));\n\t\t\t\t\t}\n\n\t\t\t\t\tconst usageStr = formatUsageStats(aggregateUsage(details.results));\n\t\t\t\t\tif (usageStr) {\n\t\t\t\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\t\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", `Total: ${usageStr}`), 0, 0));\n\t\t\t\t\t}\n\t\t\t\t\treturn container;\n\t\t\t\t}\n\n\t\t\t\t// Collapsed view (or still running)\n\t\t\t\tlet text = `${icon} ${theme.fg(\"toolTitle\", theme.bold(\"parallel \"))}${theme.fg(\"accent\", status)}`;\n\t\t\t\tfor (const r of details.results) {\n\t\t\t\t\tconst rIcon =\n\t\t\t\t\t\tr.exitCode === -1\n\t\t\t\t\t\t\t? theme.fg(\"warning\", \"⏳\")\n\t\t\t\t\t\t\t: isFailedResult(r)\n\t\t\t\t\t\t\t\t? theme.fg(\"error\", \"✗\")\n\t\t\t\t\t\t\t\t: theme.fg(\"success\", \"✓\");\n\t\t\t\t\tconst displayItems = getDisplayItems(r.messages);\n\t\t\t\t\ttext += `\\n\\n${theme.fg(\"muted\", \"─── \")}${theme.fg(\"accent\", r.agent)} ${rIcon}`;\n\t\t\t\t\tif (displayItems.length === 0)\n\t\t\t\t\t\ttext += `\\n${theme.fg(\"muted\", r.exitCode === -1 ? \"(running...)\" : \"(no output)\")}`;\n\t\t\t\t\telse text += `\\n${renderDisplayItems(displayItems, 5)}`;\n\t\t\t\t}\n\t\t\t\tif (!isRunning) {\n\t\t\t\t\tconst usageStr = formatUsageStats(aggregateUsage(details.results));\n\t\t\t\t\tif (usageStr) text += `\\n\\n${theme.fg(\"dim\", `Total: ${usageStr}`)}`;\n\t\t\t\t}\n\t\t\t\tif (!expanded) text += `\\n${theme.fg(\"muted\", \"(Ctrl+O to expand)\")}`;\n\t\t\t\treturn new Text(text, 0, 0);\n\t\t\t}\n\n\t\t\tconst text = result.content[0];\n\t\t\treturn new Text(text?.type === \"text\" ? text.text : \"(no output)\", 0, 0);\n\t\t},\n\t};\n}\n\nexport function createSubagentTool(cwd: string) {\n\treturn wrapToolDefinition(createSubagentToolDefinition(cwd));\n}\n"]}
1
+ {"version":3,"file":"subagent.d.ts","sourceRoot":"","sources":["../../../src/core/tools/subagent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAO,OAAO,EAAS,MAAM,uBAAuB,CAAC;AAGjE,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI/B,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAU/E,4FAA4F;AAC5F,eAAO,MAAM,kBAAkB,mCAAmC,CAAC;AAUnE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAyED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,oBAAoB,CAmBnF;AAoGD,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;IACtC,UAAU,EAAE,UAAU,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,oBAAoB,EAAE,CAAC;CAChC;AAgTD,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;EAWlB,CAAC;AAEH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAC,OAAO,cAAc,EAAE,eAAe,CAAC,CAsnBhH;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,2EAE7C"}