@bastani/atomic 0.9.9-alpha.1 → 0.9.9-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (576) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +12 -0
  3. package/dist/builtin/cursor/package.json +3 -3
  4. package/dist/builtin/intercom/CHANGELOG.md +14 -0
  5. package/dist/builtin/intercom/README.md +10 -3
  6. package/dist/builtin/intercom/broker/client.ts +2 -0
  7. package/dist/builtin/intercom/broker/send-handler.ts +22 -20
  8. package/dist/builtin/intercom/foreground-detach-handoff.ts +3 -1
  9. package/dist/builtin/intercom/inbound-idle-queue.ts +82 -0
  10. package/dist/builtin/intercom/index-heavy.ts +47 -37
  11. package/dist/builtin/intercom/intercom-tool.ts +6 -4
  12. package/dist/builtin/intercom/intercom-utils.ts +30 -0
  13. package/dist/builtin/intercom/lifecycle.ts +8 -5
  14. package/dist/builtin/intercom/package.json +3 -3
  15. package/dist/builtin/intercom/reply-tracker.ts +19 -19
  16. package/dist/builtin/intercom/session-target.ts +68 -0
  17. package/dist/builtin/intercom/skills/intercom/SKILL.md +7 -4
  18. package/dist/builtin/intercom/source-ownership.ts +34 -0
  19. package/dist/builtin/intercom/subagent-relay.ts +45 -20
  20. package/dist/builtin/intercom/terminal-ordering-barrier.ts +111 -0
  21. package/dist/builtin/intercom/types.ts +5 -0
  22. package/dist/builtin/mcp/CHANGELOG.md +13 -0
  23. package/dist/builtin/mcp/package.json +4 -4
  24. package/dist/builtin/subagents/CHANGELOG.md +13 -0
  25. package/dist/builtin/subagents/package.json +5 -5
  26. package/dist/builtin/subagents/src/runs/background/notify.ts +53 -9
  27. package/dist/builtin/subagents/src/shared/types-config.ts +1 -0
  28. package/dist/builtin/web-access/CHANGELOG.md +13 -0
  29. package/dist/builtin/web-access/package.json +3 -3
  30. package/dist/builtin/web-access/web-search-tool.ts +1 -2
  31. package/dist/builtin/workflows/CHANGELOG.md +13 -0
  32. package/dist/builtin/workflows/package.json +3 -3
  33. package/dist/builtin/workflows/src/extension/workflow-tool.ts +18 -2
  34. package/dist/builtin/workflows/src/shared/serializable.ts +1 -1
  35. package/dist/bun/cli.d.ts.map +1 -1
  36. package/dist/bun/internal-intercom-broker.d.ts.map +1 -1
  37. package/dist/bun/register-bedrock.d.ts.map +1 -1
  38. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  39. package/dist/bun/split-loader.d.ts.map +1 -1
  40. package/dist/cli/args.d.ts.map +1 -1
  41. package/dist/cli/config-selector.d.ts.map +1 -1
  42. package/dist/cli/file-processor.d.ts.map +1 -1
  43. package/dist/cli/initial-message.d.ts.map +1 -1
  44. package/dist/cli/list-models.d.ts.map +1 -1
  45. package/dist/cli/project-trust.d.ts.map +1 -1
  46. package/dist/cli/session-picker.d.ts.map +1 -1
  47. package/dist/cli/startup-ui.d.ts.map +1 -1
  48. package/dist/cli.d.ts.map +1 -1
  49. package/dist/config-self-update.d.ts.map +1 -1
  50. package/dist/config.d.ts.map +1 -1
  51. package/dist/core/agent-session-accessors.d.ts.map +1 -1
  52. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  53. package/dist/core/agent-session-bash.d.ts.map +1 -1
  54. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  55. package/dist/core/agent-session-events.d.ts.map +1 -1
  56. package/dist/core/agent-session-export.d.ts.map +1 -1
  57. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  58. package/dist/core/agent-session-extension-bindings.js +9 -0
  59. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  60. package/dist/core/agent-session-message-queue.d.ts +4 -1
  61. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  62. package/dist/core/agent-session-message-queue.js +35 -0
  63. package/dist/core/agent-session-message-queue.js.map +1 -1
  64. package/dist/core/agent-session-methods.d.ts +2 -1
  65. package/dist/core/agent-session-methods.d.ts.map +1 -1
  66. package/dist/core/agent-session-methods.js.map +1 -1
  67. package/dist/core/agent-session-models.d.ts.map +1 -1
  68. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  69. package/dist/core/agent-session-retry.d.ts.map +1 -1
  70. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  71. package/dist/core/agent-session-services.d.ts.map +1 -1
  72. package/dist/core/agent-session-skill-block.d.ts.map +1 -1
  73. package/dist/core/agent-session-state.d.ts.map +1 -1
  74. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
  75. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  76. package/dist/core/agent-session-tree.d.ts.map +1 -1
  77. package/dist/core/agent-session-types.d.ts.map +1 -1
  78. package/dist/core/agent-session.d.ts.map +1 -1
  79. package/dist/core/anthropic-thinking-guard.d.ts.map +1 -1
  80. package/dist/core/async/format.d.ts.map +1 -1
  81. package/dist/core/async/job-manager.d.ts.map +1 -1
  82. package/dist/core/async/session-manager.d.ts.map +1 -1
  83. package/dist/core/async/types.d.ts.map +1 -1
  84. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  85. package/dist/core/auth-guidance.d.ts.map +1 -1
  86. package/dist/core/auth-storage-backends.d.ts.map +1 -1
  87. package/dist/core/auth-storage.d.ts +4 -0
  88. package/dist/core/auth-storage.d.ts.map +1 -1
  89. package/dist/core/bash-executor.d.ts.map +1 -1
  90. package/dist/core/builtin-packages.d.ts.map +1 -1
  91. package/dist/core/codex-fast-mode.d.ts.map +1 -1
  92. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  93. package/dist/core/compaction/compaction-boundary.d.ts.map +1 -1
  94. package/dist/core/compaction/compaction-parameters.d.ts.map +1 -1
  95. package/dist/core/compaction/compaction-runner.d.ts.map +1 -1
  96. package/dist/core/compaction/compaction-types.d.ts.map +1 -1
  97. package/dist/core/compaction/compaction.d.ts.map +1 -1
  98. package/dist/core/compaction/deleted-ranges.d.ts.map +1 -1
  99. package/dist/core/compaction/index.d.ts.map +1 -1
  100. package/dist/core/compaction/range-planner.d.ts.map +1 -1
  101. package/dist/core/compaction/transcript-serialization.d.ts.map +1 -1
  102. package/dist/core/compaction/utils.d.ts.map +1 -1
  103. package/dist/core/context-window.d.ts.map +1 -1
  104. package/dist/core/copilot-anthropic-sse-repair.d.ts.map +1 -1
  105. package/dist/core/copilot-errors.d.ts.map +1 -1
  106. package/dist/core/copilot-gemini-payload-sanitizer.d.ts.map +1 -1
  107. package/dist/core/copilot-gemini-reasoning.d.ts.map +1 -1
  108. package/dist/core/copilot-gemini-tool-arguments.d.ts.map +1 -1
  109. package/dist/core/copilot-hosts.d.ts.map +1 -1
  110. package/dist/core/copilot-model-catalog.d.ts.map +1 -1
  111. package/dist/core/copilot-model-static-fallbacks.d.ts.map +1 -1
  112. package/dist/core/copilot-model-synthesis.d.ts.map +1 -1
  113. package/dist/core/defaults.d.ts.map +1 -1
  114. package/dist/core/diagnostics.d.ts.map +1 -1
  115. package/dist/core/event-bus.d.ts.map +1 -1
  116. package/dist/core/exec.d.ts.map +1 -1
  117. package/dist/core/experimental.d.ts.map +1 -1
  118. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  119. package/dist/core/export-html/index.d.ts.map +1 -1
  120. package/dist/core/export-html/template-script.d.ts.map +1 -1
  121. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  122. package/dist/core/extensions/agent-events.d.ts.map +1 -1
  123. package/dist/core/extensions/api-types.d.ts +3 -1
  124. package/dist/core/extensions/api-types.d.ts.map +1 -1
  125. package/dist/core/extensions/api-types.js.map +1 -1
  126. package/dist/core/extensions/command-types.d.ts.map +1 -1
  127. package/dist/core/extensions/context-types.d.ts.map +1 -1
  128. package/dist/core/extensions/event-results.d.ts.map +1 -1
  129. package/dist/core/extensions/event-types.d.ts.map +1 -1
  130. package/dist/core/extensions/index.d.ts +1 -1
  131. package/dist/core/extensions/index.d.ts.map +1 -1
  132. package/dist/core/extensions/index.js.map +1 -1
  133. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  134. package/dist/core/extensions/loader-api.js +4 -0
  135. package/dist/core/extensions/loader-api.js.map +1 -1
  136. package/dist/core/extensions/loader-core.d.ts.map +1 -1
  137. package/dist/core/extensions/loader-discovery.d.ts.map +1 -1
  138. package/dist/core/extensions/loader-resources.d.ts.map +1 -1
  139. package/dist/core/extensions/loader-runtime.d.ts.map +1 -1
  140. package/dist/core/extensions/loader-runtime.js +1 -0
  141. package/dist/core/extensions/loader-runtime.js.map +1 -1
  142. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  143. package/dist/core/extensions/loader.d.ts.map +1 -1
  144. package/dist/core/extensions/message-types.d.ts +3 -0
  145. package/dist/core/extensions/message-types.d.ts.map +1 -1
  146. package/dist/core/extensions/message-types.js.map +1 -1
  147. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  148. package/dist/core/extensions/reactive-widget.d.ts.map +1 -1
  149. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  150. package/dist/core/extensions/runner-events.d.ts.map +1 -1
  151. package/dist/core/extensions/runner-handlers.d.ts.map +1 -1
  152. package/dist/core/extensions/runner-project-trust.d.ts.map +1 -1
  153. package/dist/core/extensions/runner-registries.d.ts.map +1 -1
  154. package/dist/core/extensions/runner-shortcuts.d.ts.map +1 -1
  155. package/dist/core/extensions/runner-ui.d.ts.map +1 -1
  156. package/dist/core/extensions/runner.d.ts.map +1 -1
  157. package/dist/core/extensions/runner.js +1 -0
  158. package/dist/core/extensions/runner.js.map +1 -1
  159. package/dist/core/extensions/runtime-types.d.ts +3 -1
  160. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  161. package/dist/core/extensions/runtime-types.js.map +1 -1
  162. package/dist/core/extensions/session-events.d.ts.map +1 -1
  163. package/dist/core/extensions/tool-events.d.ts.map +1 -1
  164. package/dist/core/extensions/tool-types.d.ts.map +1 -1
  165. package/dist/core/extensions/types.d.ts.map +1 -1
  166. package/dist/core/extensions/ui-types.d.ts.map +1 -1
  167. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  168. package/dist/core/flattened-tool-arguments.d.ts.map +1 -1
  169. package/dist/core/footer-data-provider.d.ts.map +1 -1
  170. package/dist/core/http-dispatcher.d.ts.map +1 -1
  171. package/dist/core/index.d.ts.map +1 -1
  172. package/dist/core/keybindings.d.ts.map +1 -1
  173. package/dist/core/messages.d.ts.map +1 -1
  174. package/dist/core/model-registry-auth.d.ts.map +1 -1
  175. package/dist/core/model-registry-builtins.d.ts.map +1 -1
  176. package/dist/core/model-registry-builtins.js.map +1 -1
  177. package/dist/core/model-registry-custom-loader.d.ts.map +1 -1
  178. package/dist/core/model-registry-custom-loader.js.map +1 -1
  179. package/dist/core/model-registry-dynamic.d.ts.map +1 -1
  180. package/dist/core/model-registry-loader.d.ts.map +1 -1
  181. package/dist/core/model-registry-schemas.d.ts +65 -13
  182. package/dist/core/model-registry-schemas.d.ts.map +1 -1
  183. package/dist/core/model-registry-schemas.js +5 -1
  184. package/dist/core/model-registry-schemas.js.map +1 -1
  185. package/dist/core/model-registry-types.d.ts.map +1 -1
  186. package/dist/core/model-registry.d.ts.map +1 -1
  187. package/dist/core/model-resolver-cli.d.ts.map +1 -1
  188. package/dist/core/model-resolver-defaults.d.ts.map +1 -1
  189. package/dist/core/model-resolver-initial.d.ts.map +1 -1
  190. package/dist/core/model-resolver-patterns.d.ts.map +1 -1
  191. package/dist/core/model-resolver-scope.d.ts.map +1 -1
  192. package/dist/core/model-resolver-types.d.ts.map +1 -1
  193. package/dist/core/model-resolver.d.ts.map +1 -1
  194. package/dist/core/openai-responses-payload-sanitizer.d.ts.map +1 -1
  195. package/dist/core/output-guard.d.ts.map +1 -1
  196. package/dist/core/package-manager-auto-resources.d.ts.map +1 -1
  197. package/dist/core/package-manager-command.d.ts.map +1 -1
  198. package/dist/core/package-manager-constants.d.ts.map +1 -1
  199. package/dist/core/package-manager-env.d.ts.map +1 -1
  200. package/dist/core/package-manager-git.d.ts.map +1 -1
  201. package/dist/core/package-manager-manifest.d.ts.map +1 -1
  202. package/dist/core/package-manager-npm.d.ts.map +1 -1
  203. package/dist/core/package-manager-operations.d.ts.map +1 -1
  204. package/dist/core/package-manager-paths.d.ts.map +1 -1
  205. package/dist/core/package-manager-progress.d.ts.map +1 -1
  206. package/dist/core/package-manager-resolver.d.ts.map +1 -1
  207. package/dist/core/package-manager-resource-accumulator.d.ts.map +1 -1
  208. package/dist/core/package-manager-resource-collector.d.ts.map +1 -1
  209. package/dist/core/package-manager-resource-files.d.ts.map +1 -1
  210. package/dist/core/package-manager-resource-patterns.d.ts.map +1 -1
  211. package/dist/core/package-manager-settings.d.ts.map +1 -1
  212. package/dist/core/package-manager-source.d.ts.map +1 -1
  213. package/dist/core/package-manager-types.d.ts.map +1 -1
  214. package/dist/core/package-manager.d.ts.map +1 -1
  215. package/dist/core/project-trust.d.ts.map +1 -1
  216. package/dist/core/prompt-templates-async.d.ts.map +1 -1
  217. package/dist/core/prompt-templates.d.ts.map +1 -1
  218. package/dist/core/provider-attribution.d.ts.map +1 -1
  219. package/dist/core/provider-context-usage.d.ts.map +1 -1
  220. package/dist/core/provider-display-names.d.ts.map +1 -1
  221. package/dist/core/resolve-config-value.d.ts.map +1 -1
  222. package/dist/core/resource-loader-assets.d.ts.map +1 -1
  223. package/dist/core/resource-loader-context-files.d.ts.map +1 -1
  224. package/dist/core/resource-loader-core.d.ts.map +1 -1
  225. package/dist/core/resource-loader-discovery.d.ts.map +1 -1
  226. package/dist/core/resource-loader-extensions.d.ts.map +1 -1
  227. package/dist/core/resource-loader-helpers.d.ts.map +1 -1
  228. package/dist/core/resource-loader-internals.d.ts.map +1 -1
  229. package/dist/core/resource-loader-package-resources.d.ts.map +1 -1
  230. package/dist/core/resource-loader-paths.d.ts.map +1 -1
  231. package/dist/core/resource-loader-reload.d.ts.map +1 -1
  232. package/dist/core/resource-loader-source-info.d.ts.map +1 -1
  233. package/dist/core/resource-loader-types.d.ts.map +1 -1
  234. package/dist/core/resource-loader.d.ts.map +1 -1
  235. package/dist/core/sdk-exports.d.ts.map +1 -1
  236. package/dist/core/sdk-types.d.ts.map +1 -1
  237. package/dist/core/sdk.d.ts.map +1 -1
  238. package/dist/core/session-cwd.d.ts.map +1 -1
  239. package/dist/core/session-entry-normalization.d.ts.map +1 -1
  240. package/dist/core/session-manager-archive.d.ts.map +1 -1
  241. package/dist/core/session-manager-classification.d.ts.map +1 -1
  242. package/dist/core/session-manager-core.d.ts.map +1 -1
  243. package/dist/core/session-manager-entries.d.ts.map +1 -1
  244. package/dist/core/session-manager-history.d.ts.map +1 -1
  245. package/dist/core/session-manager-list.d.ts.map +1 -1
  246. package/dist/core/session-manager-migrations.d.ts.map +1 -1
  247. package/dist/core/session-manager-paths.d.ts.map +1 -1
  248. package/dist/core/session-manager-storage.d.ts.map +1 -1
  249. package/dist/core/session-manager-types.d.ts.map +1 -1
  250. package/dist/core/session-manager-validation.d.ts.map +1 -1
  251. package/dist/core/session-manager.d.ts.map +1 -1
  252. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  253. package/dist/core/settings-manager-core.d.ts.map +1 -1
  254. package/dist/core/settings-manager-internals.d.ts.map +1 -1
  255. package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -1
  256. package/dist/core/settings-manager-ui-accessors.d.ts.map +1 -1
  257. package/dist/core/settings-manager.d.ts.map +1 -1
  258. package/dist/core/settings-merge.d.ts.map +1 -1
  259. package/dist/core/settings-storage.d.ts.map +1 -1
  260. package/dist/core/settings-types.d.ts.map +1 -1
  261. package/dist/core/skills-async.d.ts.map +1 -1
  262. package/dist/core/skills.d.ts.map +1 -1
  263. package/dist/core/slash-commands.d.ts.map +1 -1
  264. package/dist/core/source-info.d.ts.map +1 -1
  265. package/dist/core/system-prompt.d.ts.map +1 -1
  266. package/dist/core/telemetry.d.ts.map +1 -1
  267. package/dist/core/thinking-blocks.d.ts.map +1 -1
  268. package/dist/core/timings.d.ts.map +1 -1
  269. package/dist/core/tools/artifact-protocol.d.ts.map +1 -1
  270. package/dist/core/tools/artifacts.d.ts.map +1 -1
  271. package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
  272. package/dist/core/tools/ask-user-question/config.d.ts.map +1 -1
  273. package/dist/core/tools/ask-user-question/index.d.ts.map +1 -1
  274. package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts.map +1 -1
  275. package/dist/core/tools/ask-user-question/state/inline-input.d.ts.map +1 -1
  276. package/dist/core/tools/ask-user-question/state/key-router.d.ts.map +1 -1
  277. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
  278. package/dist/core/tools/ask-user-question/state/row-intent.d.ts.map +1 -1
  279. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts.map +1 -1
  280. package/dist/core/tools/ask-user-question/state/selectors/derivations.d.ts.map +1 -1
  281. package/dist/core/tools/ask-user-question/state/selectors/focus.d.ts.map +1 -1
  282. package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts.map +1 -1
  283. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
  284. package/dist/core/tools/ask-user-question/state/state.d.ts.map +1 -1
  285. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts.map +1 -1
  286. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts.map +1 -1
  287. package/dist/core/tools/ask-user-question/tool/types.d.ts.map +1 -1
  288. package/dist/core/tools/ask-user-question/tool/validate-questionnaire.d.ts.map +1 -1
  289. package/dist/core/tools/ask-user-question/view/body-residual-spacer.d.ts.map +1 -1
  290. package/dist/core/tools/ask-user-question/view/component-binding.d.ts.map +1 -1
  291. package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts.map +1 -1
  292. package/dist/core/tools/ask-user-question/view/components/multi-select-view.d.ts.map +1 -1
  293. package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts.map +1 -1
  294. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.d.ts.map +1 -1
  295. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts.map +1 -1
  296. package/dist/core/tools/ask-user-question/view/components/preview/preview-box-renderer.d.ts.map +1 -1
  297. package/dist/core/tools/ask-user-question/view/components/preview/preview-layout-decider.d.ts.map +1 -1
  298. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.d.ts.map +1 -1
  299. package/dist/core/tools/ask-user-question/view/components/submit-picker.d.ts.map +1 -1
  300. package/dist/core/tools/ask-user-question/view/components/tab-bar.d.ts.map +1 -1
  301. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
  302. package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts.map +1 -1
  303. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts.map +1 -1
  304. package/dist/core/tools/ask-user-question/view/stateful-view.d.ts.map +1 -1
  305. package/dist/core/tools/ask-user-question/view/tab-components.d.ts.map +1 -1
  306. package/dist/core/tools/ask-user-question/view/tab-content-strategy.d.ts.map +1 -1
  307. package/dist/core/tools/bash-async-execution.d.ts.map +1 -1
  308. package/dist/core/tools/bash-async-jobs.d.ts.map +1 -1
  309. package/dist/core/tools/bash-async-output.d.ts.map +1 -1
  310. package/dist/core/tools/bash-interceptor.d.ts.map +1 -1
  311. package/dist/core/tools/bash-leading-cd.d.ts.map +1 -1
  312. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  313. package/dist/core/tools/bash.d.ts.map +1 -1
  314. package/dist/core/tools/block-resolver.d.ts.map +1 -1
  315. package/dist/core/tools/conflict-registry.d.ts.map +1 -1
  316. package/dist/core/tools/directory-tree.d.ts.map +1 -1
  317. package/dist/core/tools/edit-diff-preserve.d.ts.map +1 -1
  318. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  319. package/dist/core/tools/edit.d.ts.map +1 -1
  320. package/dist/core/tools/fetch-url.d.ts.map +1 -1
  321. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  322. package/dist/core/tools/find.d.ts.map +1 -1
  323. package/dist/core/tools/glob-path-utils.d.ts.map +1 -1
  324. package/dist/core/tools/grep.d.ts.map +1 -1
  325. package/dist/core/tools/hashline-engine/apply.d.ts.map +1 -1
  326. package/dist/core/tools/hashline-engine/block.d.ts.map +1 -1
  327. package/dist/core/tools/hashline-engine/diff-preview.d.ts.map +1 -1
  328. package/dist/core/tools/hashline-engine/format.d.ts.map +1 -1
  329. package/dist/core/tools/hashline-engine/fs.d.ts.map +1 -1
  330. package/dist/core/tools/hashline-engine/index.d.ts.map +1 -1
  331. package/dist/core/tools/hashline-engine/input.d.ts.map +1 -1
  332. package/dist/core/tools/hashline-engine/messages.d.ts.map +1 -1
  333. package/dist/core/tools/hashline-engine/mismatch.d.ts.map +1 -1
  334. package/dist/core/tools/hashline-engine/normalize.d.ts.map +1 -1
  335. package/dist/core/tools/hashline-engine/parser.d.ts.map +1 -1
  336. package/dist/core/tools/hashline-engine/patcher.d.ts.map +1 -1
  337. package/dist/core/tools/hashline-engine/prefixes.d.ts.map +1 -1
  338. package/dist/core/tools/hashline-engine/recovery.d.ts.map +1 -1
  339. package/dist/core/tools/hashline-engine/snapshots.d.ts.map +1 -1
  340. package/dist/core/tools/hashline-engine/stream.d.ts.map +1 -1
  341. package/dist/core/tools/hashline-engine/tokenizer.d.ts.map +1 -1
  342. package/dist/core/tools/hashline-engine/types.d.ts.map +1 -1
  343. package/dist/core/tools/hashline.d.ts.map +1 -1
  344. package/dist/core/tools/index.d.ts.map +1 -1
  345. package/dist/core/tools/ls.d.ts.map +1 -1
  346. package/dist/core/tools/notebook.d.ts.map +1 -1
  347. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  348. package/dist/core/tools/oversized-tool-result.d.ts.map +1 -1
  349. package/dist/core/tools/path-utils.d.ts.map +1 -1
  350. package/dist/core/tools/read-document-extract.d.ts.map +1 -1
  351. package/dist/core/tools/read-selectors.d.ts.map +1 -1
  352. package/dist/core/tools/read-url.d.ts.map +1 -1
  353. package/dist/core/tools/read.d.ts.map +1 -1
  354. package/dist/core/tools/render-utils.d.ts.map +1 -1
  355. package/dist/core/tools/resource-selectors.d.ts.map +1 -1
  356. package/dist/core/tools/search-details.d.ts.map +1 -1
  357. package/dist/core/tools/search-line-ranges.d.ts.map +1 -1
  358. package/dist/core/tools/search-native.d.ts.map +1 -1
  359. package/dist/core/tools/search.d.ts.map +1 -1
  360. package/dist/core/tools/structured-output.d.ts.map +1 -1
  361. package/dist/core/tools/todos-execute.d.ts.map +1 -1
  362. package/dist/core/tools/todos-locks.d.ts.map +1 -1
  363. package/dist/core/tools/todos-model.d.ts.map +1 -1
  364. package/dist/core/tools/todos-mutations.d.ts.map +1 -1
  365. package/dist/core/tools/todos-paths.d.ts.map +1 -1
  366. package/dist/core/tools/todos-render.d.ts.map +1 -1
  367. package/dist/core/tools/todos-storage.d.ts.map +1 -1
  368. package/dist/core/tools/todos-types.d.ts.map +1 -1
  369. package/dist/core/tools/todos-types.js +1 -1
  370. package/dist/core/tools/todos-types.js.map +1 -1
  371. package/dist/core/tools/todos.d.ts.map +1 -1
  372. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  373. package/dist/core/tools/tool-definition-wrapper.js +6 -2
  374. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  375. package/dist/core/tools/tool-limits.d.ts.map +1 -1
  376. package/dist/core/tools/truncate.d.ts.map +1 -1
  377. package/dist/core/tools/url-ip-guards.d.ts.map +1 -1
  378. package/dist/core/tools/write.d.ts.map +1 -1
  379. package/dist/core/trust-manager.d.ts.map +1 -1
  380. package/dist/core/typebox-compat.d.ts +12 -0
  381. package/dist/core/typebox-compat.d.ts.map +1 -0
  382. package/dist/core/typebox-compat.js +10 -0
  383. package/dist/core/typebox-compat.js.map +1 -0
  384. package/dist/index-extensions.d.ts.map +1 -1
  385. package/dist/index.d.ts +1 -0
  386. package/dist/index.d.ts.map +1 -1
  387. package/dist/index.js +1 -0
  388. package/dist/index.js.map +1 -1
  389. package/dist/main-app-mode.d.ts.map +1 -1
  390. package/dist/main-deferred-startup.d.ts.map +1 -1
  391. package/dist/main-early-input.d.ts.map +1 -1
  392. package/dist/main-session-options.d.ts.map +1 -1
  393. package/dist/main-session.d.ts.map +1 -1
  394. package/dist/main-stdio.d.ts.map +1 -1
  395. package/dist/main.d.ts.map +1 -1
  396. package/dist/migrations-config-values.d.ts.map +1 -1
  397. package/dist/migrations.d.ts.map +1 -1
  398. package/dist/modes/index.d.ts.map +1 -1
  399. package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -1
  400. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  401. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  402. package/dist/modes/interactive/components/atomic-banner.d.ts.map +1 -1
  403. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  404. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  405. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  406. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  407. package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
  408. package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -1
  409. package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
  410. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  411. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -1
  412. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  413. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts.map +1 -1
  414. package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -1
  415. package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
  416. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  417. package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
  418. package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -1
  419. package/dist/modes/interactive/components/config-selector-list.d.ts.map +1 -1
  420. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  421. package/dist/modes/interactive/components/context-window-selector.d.ts.map +1 -1
  422. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  423. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  424. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  425. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  426. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  427. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  428. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  429. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  430. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  431. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  432. package/dist/modes/interactive/components/fast-mode-selector.d.ts.map +1 -1
  433. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  434. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  435. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  436. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  437. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  438. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  439. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  440. package/dist/modes/interactive/components/session-selector-delete.d.ts.map +1 -1
  441. package/dist/modes/interactive/components/session-selector-header.d.ts.map +1 -1
  442. package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
  443. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  444. package/dist/modes/interactive/components/session-selector-tree.d.ts.map +1 -1
  445. package/dist/modes/interactive/components/session-selector-types.d.ts.map +1 -1
  446. package/dist/modes/interactive/components/session-selector-utils.d.ts.map +1 -1
  447. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  448. package/dist/modes/interactive/components/settings-selector-handlers.d.ts.map +1 -1
  449. package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -1
  450. package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -1
  451. package/dist/modes/interactive/components/settings-selector-submenus.d.ts.map +1 -1
  452. package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -1
  453. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  454. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  455. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  456. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  457. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  458. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  459. package/dist/modes/interactive/components/tree-selector-component.d.ts.map +1 -1
  460. package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
  461. package/dist/modes/interactive/components/tree-selector-help.d.ts.map +1 -1
  462. package/dist/modes/interactive/components/tree-selector-label-input.d.ts.map +1 -1
  463. package/dist/modes/interactive/components/tree-selector-list.d.ts.map +1 -1
  464. package/dist/modes/interactive/components/tree-selector-model.d.ts.map +1 -1
  465. package/dist/modes/interactive/components/tree-selector-types.d.ts.map +1 -1
  466. package/dist/modes/interactive/components/tree-selector-viewport.d.ts.map +1 -1
  467. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  468. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  469. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  470. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  471. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  472. package/dist/modes/interactive/components/working-status.d.ts.map +1 -1
  473. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  474. package/dist/modes/interactive/interactive-auth-login.d.ts.map +1 -1
  475. package/dist/modes/interactive/interactive-auth-routing.d.ts.map +1 -1
  476. package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
  477. package/dist/modes/interactive/interactive-bash-compact.d.ts.map +1 -1
  478. package/dist/modes/interactive/interactive-child-ordering.d.ts.map +1 -1
  479. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  480. package/dist/modes/interactive/interactive-editor-actions.d.ts.map +1 -1
  481. package/dist/modes/interactive/interactive-extension-context.d.ts.map +1 -1
  482. package/dist/modes/interactive/interactive-extension-custom-ui.d.ts.map +1 -1
  483. package/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
  484. package/dist/modes/interactive/interactive-extension-runtime.d.ts.map +1 -1
  485. package/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  486. package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
  487. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  488. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  489. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  490. package/dist/modes/interactive/interactive-mode-helpers.d.ts.map +1 -1
  491. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  492. package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
  493. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  494. package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
  495. package/dist/modes/interactive/interactive-onboarding.d.ts.map +1 -1
  496. package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -1
  497. package/dist/modes/interactive/interactive-queueing.d.ts.map +1 -1
  498. package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
  499. package/dist/modes/interactive/interactive-resource-disclosure.d.ts.map +1 -1
  500. package/dist/modes/interactive/interactive-resource-paths.d.ts.map +1 -1
  501. package/dist/modes/interactive/interactive-resource-rendering.d.ts.map +1 -1
  502. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  503. package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
  504. package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -1
  505. package/dist/modes/interactive/interactive-slash-commands.d.ts.map +1 -1
  506. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  507. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  508. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  509. package/dist/modes/interactive/theme/export-colors.d.ts.map +1 -1
  510. package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
  511. package/dist/modes/interactive/theme/terminal-detection.d.ts.map +1 -1
  512. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  513. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  514. package/dist/modes/interactive/theme/theme-loading.d.ts.map +1 -1
  515. package/dist/modes/interactive/theme/theme-parse.d.ts.map +1 -1
  516. package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  517. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  518. package/dist/modes/interactive/theme/tui-theme.d.ts.map +1 -1
  519. package/dist/modes/interactive/whimsical-messages.d.ts.map +1 -1
  520. package/dist/modes/print-mode.d.ts.map +1 -1
  521. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  522. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  523. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  524. package/dist/modes/rpc/rpc-extension-ui.d.ts.map +1 -1
  525. package/dist/modes/rpc/rpc-input.d.ts.map +1 -1
  526. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  527. package/dist/modes/rpc/rpc-responses.d.ts.map +1 -1
  528. package/dist/modes/rpc/rpc-session-binding.d.ts.map +1 -1
  529. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  530. package/dist/package-manager-cli-parser.d.ts.map +1 -1
  531. package/dist/package-manager-cli.d.ts.map +1 -1
  532. package/dist/rpc-entry.d.ts.map +1 -1
  533. package/dist/utils/ansi.d.ts.map +1 -1
  534. package/dist/utils/changelog.d.ts.map +1 -1
  535. package/dist/utils/child-process.d.ts.map +1 -1
  536. package/dist/utils/clipboard-image.d.ts.map +1 -1
  537. package/dist/utils/clipboard-native.d.ts.map +1 -1
  538. package/dist/utils/clipboard.d.ts.map +1 -1
  539. package/dist/utils/deprecation.d.ts.map +1 -1
  540. package/dist/utils/event-loop.d.ts.map +1 -1
  541. package/dist/utils/exif-orientation.d.ts.map +1 -1
  542. package/dist/utils/frontmatter.d.ts.map +1 -1
  543. package/dist/utils/fs-watch.d.ts.map +1 -1
  544. package/dist/utils/git-env.d.ts.map +1 -1
  545. package/dist/utils/git.d.ts.map +1 -1
  546. package/dist/utils/html.d.ts.map +1 -1
  547. package/dist/utils/image-convert.d.ts.map +1 -1
  548. package/dist/utils/image-process.d.ts.map +1 -1
  549. package/dist/utils/image-resize-core.d.ts.map +1 -1
  550. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  551. package/dist/utils/image-resize.d.ts.map +1 -1
  552. package/dist/utils/json.d.ts.map +1 -1
  553. package/dist/utils/markit.d.ts.map +1 -1
  554. package/dist/utils/mime.d.ts.map +1 -1
  555. package/dist/utils/module-require.d.ts.map +1 -1
  556. package/dist/utils/open-browser.d.ts.map +1 -1
  557. package/dist/utils/paths.d.ts.map +1 -1
  558. package/dist/utils/photon.d.ts.map +1 -1
  559. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  560. package/dist/utils/shell.d.ts.map +1 -1
  561. package/dist/utils/sleep.d.ts.map +1 -1
  562. package/dist/utils/split-launcher.d.ts.map +1 -1
  563. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  564. package/dist/utils/tools-manager.d.ts.map +1 -1
  565. package/dist/utils/version-check.d.ts.map +1 -1
  566. package/dist/utils/windows-self-update.d.ts.map +1 -1
  567. package/docs/custom-provider.md +7 -1
  568. package/docs/extensions.md +19 -4
  569. package/docs/subagents.md +2 -0
  570. package/docs/workflows.md +2 -2
  571. package/examples/extensions/README.md +3 -1
  572. package/examples/extensions/subagent/schemas.ts +1 -1
  573. package/examples/extensions/tic-tac-toe.ts +1 -2
  574. package/examples/extensions/todo.ts +1 -2
  575. package/npm-shrinkwrap.json +214 -98
  576. package/package.json +12 -12
@@ -1 +1 @@
1
- {"version":3,"file":"tokenizer.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/tokenizer.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA8D9D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBzD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIlD;AAoBD,kEAAkE;AAClE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAW7D;AAsDD,MAAM,MAAM,WAAW,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACf;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAgKnB,UAAU,SAAS;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,KAAK,GACd,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,GAC/B,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,GACxC,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,GACtC,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,GAC/B,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACjE,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,GACvD,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GACvD,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AA6B/C,qBAAa,SAAS;;IAKrB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAK3B;IAED,GAAG,IAAI,KAAK,EAAE,CASb;IAED,KAAK,IAAI,IAAI,CAIZ;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,CAKjC;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,KAAK,CAEzC;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1B;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9B;IAED,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMtC;CAgBD;AAED,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * Stateful, line-oriented classifier for hashline diff text.\n *\n * Format shape:\n * ```\n * [path/to/file.ts#1A2B]\n * replace 5..7:\n * +literal new line\n * ```\n */\nimport {\n\tdescribeAnchorExamples,\n\tHL_BLOCK_KEYWORD,\n\tHL_DELETE_KEYWORD,\n\tHL_FILE_HASH_LENGTH,\n\tHL_FILE_HASH_SEP,\n\tHL_FILE_PREFIX,\n\tHL_FILE_SUFFIX,\n\tHL_HEADER_COLON,\n\tHL_INSERT_AFTER,\n\tHL_INSERT_BEFORE,\n\tHL_INSERT_HEAD,\n\tHL_INSERT_KEYWORD,\n\tHL_INSERT_TAIL,\n\tHL_PAYLOAD_REPLACE,\n\tHL_REPLACE_KEYWORD,\n} from \"./format.js\";\nimport { ABORT_MARKER, BEGIN_PATCH_MARKER, END_PATCH_MARKER } from \"./messages.js\";\nimport type { Anchor, Cursor, ParsedRange } from \"./types.js\";\n\nconst CHAR_LINE_FEED = 10;\nconst CHAR_CARRIAGE_RETURN = 13;\nconst CHAR_ZERO = 48;\nconst CHAR_NINE = 57;\nconst CHAR_HASH = 35;\nconst CHAR_TAB = 9;\nconst CHAR_SPACE = 32;\nconst CHAR_DOT = 46;\nconst CHAR_HYPHEN = 45;\nconst CHAR_ELLIPSIS = 0x2026;\n\nconst CHAR_UPPER_A = 65;\nconst CHAR_UPPER_F = 70;\nconst CHAR_LOWER_A = 97;\nconst CHAR_LOWER_F = 102;\nconst CHAR_PAYLOAD_REPLACE = HL_PAYLOAD_REPLACE.charCodeAt(0);\nconst CHAR_COLON = HL_HEADER_COLON.charCodeAt(0);\nconst FILE_PREFIX_LENGTH = HL_FILE_PREFIX.length;\nconst FILE_SUFFIX_LENGTH = HL_FILE_SUFFIX.length;\n\nfunction isDigitCode(code: number): boolean {\n\treturn code >= CHAR_ZERO && code <= CHAR_NINE;\n}\n\nfunction isNonZeroDigitCode(code: number): boolean {\n\treturn code > CHAR_ZERO && code <= CHAR_NINE;\n}\n\nfunction isHexDigitCode(code: number): boolean {\n\treturn (\n\t\tisDigitCode(code) ||\n\t\t(code >= CHAR_UPPER_A && code <= CHAR_UPPER_F) ||\n\t\t(code >= CHAR_LOWER_A && code <= CHAR_LOWER_F)\n\t);\n}\n\nfunction isWhitespaceCode(code: number): boolean {\n\treturn code === CHAR_SPACE || (code >= CHAR_TAB && code <= CHAR_CARRIAGE_RETURN);\n}\n\nfunction skipWhitespace(line: string, index: number, end = line.length): number {\n\twhile (index < end && isWhitespaceCode(line.charCodeAt(index))) index++;\n\treturn index;\n}\n\nfunction trimEndIndex(line: string): number {\n\tlet end = line.length;\n\twhile (end > 0 && isWhitespaceCode(line.charCodeAt(end - 1))) end--;\n\treturn end;\n}\n\nfunction isEmptyLine(line: string): boolean {\n\treturn line.length === 0;\n}\n\nfunction markerLineEquals(line: string, marker: string): boolean {\n\tconst end = trimEndIndex(line);\n\treturn end === marker.length && line.startsWith(marker);\n}\n\nexport function splitHashlineLines(text: string): string[] {\n\tif (text.length === 0) return [\"\"];\n\tconst lines: string[] = [];\n\tlet start = 0;\n\tfor (let index = 0; index < text.length; index++) {\n\t\tif (text.charCodeAt(index) !== CHAR_LINE_FEED) continue;\n\t\tlet end = index;\n\t\tif (end > start && text.charCodeAt(end - 1) === CHAR_CARRIAGE_RETURN) end--;\n\t\tlines.push(text.slice(start, end));\n\t\tstart = index + 1;\n\t}\n\tif (start < text.length) {\n\t\tlet end = text.length;\n\t\tif (end > start && text.charCodeAt(end - 1) === CHAR_CARRIAGE_RETURN) end--;\n\t\tlines.push(text.slice(start, end));\n\t}\n\treturn lines;\n}\n\nexport function cloneCursor(cursor: Cursor): Cursor {\n\tif (cursor.kind === \"before_anchor\") return { kind: \"before_anchor\", anchor: { ...cursor.anchor } };\n\tif (cursor.kind === \"after_anchor\") return { kind: \"after_anchor\", anchor: { ...cursor.anchor } };\n\treturn cursor;\n}\n\ninterface NumberScan {\n\tline: number;\n\tnextIndex: number;\n}\n\nfunction scanLineNumber(line: string, index: number, end: number): NumberScan | null {\n\tif (index >= end || !isNonZeroDigitCode(line.charCodeAt(index))) return null;\n\tlet lineNumber = 0;\n\tlet nextIndex = index;\n\twhile (nextIndex < end) {\n\t\tconst code = line.charCodeAt(nextIndex);\n\t\tif (!isDigitCode(code)) break;\n\t\tlineNumber = lineNumber * 10 + (code - CHAR_ZERO);\n\t\tnextIndex++;\n\t}\n\treturn { line: lineNumber, nextIndex };\n}\n\n/** Parse a bare line-number anchor. Throws on malformed input. */\nexport function parseLid(raw: string, lineNum: number): Anchor {\n\tconst end = trimEndIndex(raw);\n\tconst numberStart = skipWhitespace(raw, 0, end);\n\tconst number = scanLineNumber(raw, numberStart, end);\n\tif (number === null || skipWhitespace(raw, number.nextIndex, end) !== end) {\n\t\tthrow new Error(\n\t\t\t`line ${lineNum}: expected a line number such as ${describeAnchorExamples(\"119\")}; ` +\n\t\t\t\t`got ${JSON.stringify(raw)}. Use ${HL_FILE_PREFIX}PATH${HL_FILE_HASH_SEP}hash${HL_FILE_SUFFIX} from your latest read for file-version binding.`,\n\t\t);\n\t}\n\treturn { line: number.line };\n}\n\ninterface RangeScan {\n\trange: ParsedRange;\n\tnextIndex: number;\n}\n\nfunction scanRangeSeparator(line: string, index: number, end: number): number | null {\n\tlet cursor = index;\n\tlet consumedSeparator = false;\n\twhile (cursor < end) {\n\t\tconst code = line.charCodeAt(cursor);\n\t\tif (isWhitespaceCode(code)) {\n\t\t\tcursor++;\n\t\t\tconsumedSeparator = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (code === CHAR_HYPHEN || code === CHAR_ELLIPSIS) {\n\t\t\tcursor++;\n\t\t\tconsumedSeparator = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (code === CHAR_DOT && cursor + 1 < end && line.charCodeAt(cursor + 1) === CHAR_DOT) {\n\t\t\tcursor += 2;\n\t\t\tconsumedSeparator = true;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\tif (!consumedSeparator) return null;\n\tif (cursor >= end || !isNonZeroDigitCode(line.charCodeAt(cursor))) return null;\n\treturn cursor;\n}\n\nfunction scanHeaderRange(line: string, index = 0, end = trimEndIndex(line), allowSingle = false): RangeScan | null {\n\tconst numberStart = skipWhitespace(line, index, end);\n\tconst start = scanLineNumber(line, numberStart, end);\n\tif (start === null) return null;\n\tconst afterFirst = scanRangeSeparator(line, start.nextIndex, end);\n\tif (afterFirst === null) {\n\t\tif (!allowSingle) return null;\n\t\treturn {\n\t\t\trange: { start: { line: start.line }, end: { line: start.line } },\n\t\t\tnextIndex: skipWhitespace(line, start.nextIndex, end),\n\t\t};\n\t}\n\tconst endNumber = scanLineNumber(line, afterFirst, end);\n\tif (endNumber === null) return null;\n\treturn {\n\t\trange: { start: { line: start.line }, end: { line: endNumber.line } },\n\t\tnextIndex: skipWhitespace(line, endNumber.nextIndex, end),\n\t};\n}\n\nexport type BlockTarget =\n\t| { kind: \"replace\"; range: ParsedRange }\n\t| { kind: \"block\"; anchor: Anchor }\n\t| { kind: \"delete\"; range: ParsedRange }\n\t| { kind: \"delete_block\"; anchor: Anchor }\n\t| { kind: \"insert_before\"; anchor: Anchor }\n\t| { kind: \"insert_after\"; anchor: Anchor }\n\t| { kind: \"insert_after_block\"; anchor: Anchor }\n\t| { kind: \"bof\" }\n\t| { kind: \"eof\" };\n\ninterface TargetScan {\n\ttarget: BlockTarget;\n\tnextIndex: number;\n}\n\nfunction scanKeyword(line: string, index: number, end: number, keyword: string): number | null {\n\tif (!line.startsWith(keyword, index)) return null;\n\tconst next = index + keyword.length;\n\tif (next < end) {\n\t\tconst code = line.charCodeAt(next);\n\t\tif (!isWhitespaceCode(code) && code !== CHAR_COLON) return null;\n\t}\n\treturn next;\n}\n\nfunction consumeOptionalColon(line: string, index: number, end: number): number {\n\tconst cursor = skipWhitespace(line, index, end);\n\treturn cursor < end && line.charCodeAt(cursor) === CHAR_COLON ? skipWhitespace(line, cursor + 1, end) : cursor;\n}\n\nfunction scanInsertTarget(line: string, index: number, end: number): TargetScan | null {\n\tconst cursor = skipWhitespace(line, index, end);\n\tconst beforeEnd = scanKeyword(line, cursor, end, HL_INSERT_BEFORE);\n\tif (beforeEnd !== null) {\n\t\tconst anchor = scanLineNumber(line, skipWhitespace(line, beforeEnd, end), end);\n\t\tif (anchor === null) return null;\n\t\tconst nextIndex = consumeOptionalColon(line, anchor.nextIndex, end);\n\t\treturn { target: { kind: \"insert_before\", anchor: { line: anchor.line } }, nextIndex };\n\t}\n\tconst afterEnd = scanKeyword(line, cursor, end, HL_INSERT_AFTER);\n\tif (afterEnd !== null) {\n\t\t// `insert after block N:` — resolve N to a tree-sitter block range at\n\t\t// apply time and insert after its last line. Try the `block` sub-keyword\n\t\t// before falling back to a literal `insert after N:` anchor.\n\t\tconst blockEnd = scanKeyword(line, skipWhitespace(line, afterEnd, end), end, HL_BLOCK_KEYWORD);\n\t\tif (blockEnd !== null) {\n\t\t\tconst anchor = scanLineNumber(line, skipWhitespace(line, blockEnd, end), end);\n\t\t\tif (anchor === null) return null;\n\t\t\tconst nextIndex = consumeOptionalColon(line, anchor.nextIndex, end);\n\t\t\treturn { target: { kind: \"insert_after_block\", anchor: { line: anchor.line } }, nextIndex };\n\t\t}\n\t\tconst anchor = scanLineNumber(line, skipWhitespace(line, afterEnd, end), end);\n\t\tif (anchor === null) return null;\n\t\tconst nextIndex = consumeOptionalColon(line, anchor.nextIndex, end);\n\t\treturn { target: { kind: \"insert_after\", anchor: { line: anchor.line } }, nextIndex };\n\t}\n\tconst headEnd = scanKeyword(line, cursor, end, HL_INSERT_HEAD);\n\tif (headEnd !== null) return { target: { kind: \"bof\" }, nextIndex: consumeOptionalColon(line, headEnd, end) };\n\tconst tailEnd = scanKeyword(line, cursor, end, HL_INSERT_TAIL);\n\tif (tailEnd !== null) return { target: { kind: \"eof\" }, nextIndex: consumeOptionalColon(line, tailEnd, end) };\n\treturn null;\n}\n\nfunction scanHunkAnchor(line: string, start: number, end: number): TargetScan | null {\n\tconst cursor = skipWhitespace(line, start, end);\n\tconst replaceEnd = scanKeyword(line, cursor, end, HL_REPLACE_KEYWORD);\n\tif (replaceEnd !== null) {\n\t\t// `replace block N:` — resolve N to a tree-sitter block range at apply\n\t\t// time. Try the `block` sub-keyword before falling back to a literal\n\t\t// `replace N..M:` range.\n\t\tconst blockEnd = scanKeyword(line, skipWhitespace(line, replaceEnd, end), end, HL_BLOCK_KEYWORD);\n\t\tif (blockEnd !== null) {\n\t\t\tconst anchor = scanLineNumber(line, skipWhitespace(line, blockEnd, end), end);\n\t\t\tif (anchor === null) return null;\n\t\t\treturn {\n\t\t\t\ttarget: { kind: \"block\", anchor: { line: anchor.line } },\n\t\t\t\tnextIndex: consumeOptionalColon(line, anchor.nextIndex, end),\n\t\t\t};\n\t\t}\n\t\tconst range = scanHeaderRange(line, replaceEnd, end, true);\n\t\tif (range === null) return null;\n\t\treturn {\n\t\t\ttarget: { kind: \"replace\", range: range.range },\n\t\t\tnextIndex: consumeOptionalColon(line, range.nextIndex, end),\n\t\t};\n\t}\n\tconst deleteEnd = scanKeyword(line, cursor, end, HL_DELETE_KEYWORD);\n\tif (deleteEnd !== null) {\n\t\t// `delete block N` — resolve N to a tree-sitter block range at apply\n\t\t// time and delete its whole span. Like `delete N..M`, it takes no body\n\t\t// and no trailing colon.\n\t\tconst blockEnd = scanKeyword(line, skipWhitespace(line, deleteEnd, end), end, HL_BLOCK_KEYWORD);\n\t\tif (blockEnd !== null) {\n\t\t\tconst anchor = scanLineNumber(line, skipWhitespace(line, blockEnd, end), end);\n\t\t\tif (anchor === null) return null;\n\t\t\tconst next = skipWhitespace(line, anchor.nextIndex, end);\n\t\t\tif (next < end && line.charCodeAt(next) === CHAR_COLON) return null;\n\t\t\treturn { target: { kind: \"delete_block\", anchor: { line: anchor.line } }, nextIndex: next };\n\t\t}\n\t\tconst range = scanHeaderRange(line, deleteEnd, end, true);\n\t\tif (range === null) return null;\n\t\tconst next = skipWhitespace(line, range.nextIndex, end);\n\t\tif (next < end && line.charCodeAt(next) === CHAR_COLON) return null;\n\t\treturn { target: { kind: \"delete\", range: range.range }, nextIndex: next };\n\t}\n\tconst insertEnd = scanKeyword(line, cursor, end, HL_INSERT_KEYWORD);\n\tif (insertEnd !== null) return scanInsertTarget(line, insertEnd, end);\n\treturn null;\n}\n\ninterface ParsedHunkHeader {\n\ttarget: BlockTarget;\n}\n\nfunction tryParseHunkHeader(line: string): ParsedHunkHeader | null {\n\tconst end = trimEndIndex(line);\n\tconst start = skipWhitespace(line, 0, end);\n\tif (start >= end) return null;\n\tconst scan = scanHunkAnchor(line, start, end);\n\tif (scan === null) return null;\n\tif (scan.nextIndex !== end) return null;\n\treturn { target: scan.target };\n}\n\nfunction tryParseHeader(line: string): { path: string; fileHash?: string } | null {\n\tif (!line.startsWith(HL_FILE_PREFIX)) return null;\n\tconst end = trimEndIndex(line);\n\tif (FILE_PREFIX_LENGTH + FILE_SUFFIX_LENGTH >= end) return null;\n\tif (!line.endsWith(HL_FILE_SUFFIX, end)) return null;\n\tconst bodyEnd = end - FILE_SUFFIX_LENGTH;\n\tif (FILE_PREFIX_LENGTH >= bodyEnd) return null;\n\n\t// The snapshot tag, when present, is the trailing `#XXXX` block inside the\n\t// bracketed header. We detect it from the suffix so the path may\n\t// legitimately contain whitespace (e.g. `OneDrive - Company/file.ts`).\n\tlet pathEnd = bodyEnd;\n\tlet fileHash: string | undefined;\n\tconst trailingHashStart = bodyEnd - HL_FILE_HASH_LENGTH - 1;\n\tif (trailingHashStart >= FILE_PREFIX_LENGTH && line.charCodeAt(trailingHashStart) === CHAR_HASH) {\n\t\tlet allHex = true;\n\t\tfor (let probe = trailingHashStart + 1; probe < bodyEnd; probe++) {\n\t\t\tif (!isHexDigitCode(line.charCodeAt(probe))) {\n\t\t\t\tallHex = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (allHex) {\n\t\t\tpathEnd = trailingHashStart;\n\t\t\tfileHash = line.slice(trailingHashStart + 1, bodyEnd).toUpperCase();\n\t\t}\n\t}\n\n\t// The hashline header grammar uses `#` as the path/tag separator and\n\t// does not allow `#` inside filenames. Anything `#` left in the path\n\t// body — short tags (`#1A2`), non-hex tags (`#1A2G`), over-long tags\n\t// (`#1A2B5`), stale-tag copy-paste (`#1A2B copied from read`), or\n\t// line-suffixed tags (`#1A2B:42`) — means the header is malformed.\n\t// Surface the focused diagnostic instead of silently mis-routing the\n\t// edit or reporting a missing tag downstream.\n\tfor (let i = FILE_PREFIX_LENGTH; i < pathEnd; i++) {\n\t\tif (line.charCodeAt(i) === CHAR_HASH) return null;\n\t}\n\n\tif (pathEnd === FILE_PREFIX_LENGTH) return null;\n\tconst path = line.slice(FILE_PREFIX_LENGTH, pathEnd);\n\treturn fileHash !== undefined ? { path, fileHash } : { path };\n}\n\ninterface TokenBase {\n\tlineNum: number;\n}\n\nexport type Token =\n\t| (TokenBase & { kind: \"blank\" })\n\t| (TokenBase & { kind: \"envelope-begin\" })\n\t| (TokenBase & { kind: \"envelope-end\" })\n\t| (TokenBase & { kind: \"abort\" })\n\t| (TokenBase & { kind: \"header\"; path: string; fileHash?: string })\n\t| (TokenBase & { kind: \"op-block\"; target: BlockTarget })\n\t| (TokenBase & { kind: \"payload-literal\"; text: string })\n\t| (TokenBase & { kind: \"raw\"; text: string });\n\nfunction classifyLine(line: string, lineNum: number): Token {\n\tif (isEmptyLine(line)) return { kind: \"blank\", lineNum };\n\tif (markerLineEquals(line, BEGIN_PATCH_MARKER)) return { kind: \"envelope-begin\", lineNum };\n\tif (markerLineEquals(line, END_PATCH_MARKER)) return { kind: \"envelope-end\", lineNum };\n\tif (markerLineEquals(line, ABORT_MARKER)) return { kind: \"abort\", lineNum };\n\tconst firstCode = line.charCodeAt(0);\n\tif (line.startsWith(HL_FILE_PREFIX)) {\n\t\tconst header = tryParseHeader(line);\n\t\tif (header !== null) {\n\t\t\treturn header.fileHash !== undefined\n\t\t\t\t? { kind: \"header\", lineNum, path: header.path, fileHash: header.fileHash }\n\t\t\t\t: { kind: \"header\", lineNum, path: header.path };\n\t\t}\n\t}\n\tconst lead = skipWhitespace(line, 0);\n\tconst isHunkLead =\n\t\tline.startsWith(HL_REPLACE_KEYWORD, lead) ||\n\t\tline.startsWith(HL_DELETE_KEYWORD, lead) ||\n\t\tline.startsWith(HL_INSERT_KEYWORD, lead);\n\tif (isHunkLead) {\n\t\tconst hunk = tryParseHunkHeader(line);\n\t\tif (hunk !== null) return { kind: \"op-block\", lineNum, target: hunk.target };\n\t}\n\tif (firstCode === CHAR_PAYLOAD_REPLACE) return { kind: \"payload-literal\", lineNum, text: line.slice(1) };\n\treturn { kind: \"raw\", lineNum, text: line };\n}\n\nexport class Tokenizer {\n\t#buffer = \"\";\n\t#nextLineNum = 1;\n\t#closed = false;\n\n\tfeed(chunk: string): Token[] {\n\t\tif (this.#closed) throw new Error(\"Tokenizer is closed; call reset() before reusing.\");\n\t\tif (chunk.length === 0) return [];\n\t\tthis.#buffer = this.#buffer ? this.#buffer + chunk : chunk;\n\t\treturn this.#drainCompleteLines();\n\t}\n\n\tend(): Token[] {\n\t\tif (this.#closed) return [];\n\t\tthis.#closed = true;\n\t\tconst buf = this.#buffer;\n\t\tthis.#buffer = \"\";\n\t\tif (buf.length === 0) return [];\n\t\tlet stop = buf.length;\n\t\tif (buf.charCodeAt(stop - 1) === CHAR_CARRIAGE_RETURN) stop--;\n\t\treturn [classifyLine(buf.slice(0, stop), this.#nextLineNum++)];\n\t}\n\n\treset(): void {\n\t\tthis.#buffer = \"\";\n\t\tthis.#nextLineNum = 1;\n\t\tthis.#closed = false;\n\t}\n\n\ttokenizeAll(text: string): Token[] {\n\t\tthis.reset();\n\t\tconst first = this.feed(text);\n\t\tconst last = this.end();\n\t\treturn last.length === 0 ? first : first.concat(last);\n\t}\n\n\ttokenize(line: string, lineNum = 0): Token {\n\t\treturn classifyLine(line, lineNum);\n\t}\n\n\tisOp(line: string): boolean {\n\t\treturn tryParseHunkHeader(line) !== null;\n\t}\n\n\tisHeader(line: string): boolean {\n\t\treturn tryParseHeader(line) !== null;\n\t}\n\n\tisEnvelopeMarker(line: string): boolean {\n\t\treturn (\n\t\t\tmarkerLineEquals(line, BEGIN_PATCH_MARKER) ||\n\t\t\tmarkerLineEquals(line, END_PATCH_MARKER) ||\n\t\t\tmarkerLineEquals(line, ABORT_MARKER)\n\t\t);\n\t}\n\n\t#drainCompleteLines(): Token[] {\n\t\tconst tokens: Token[] = [];\n\t\tconst buf = this.#buffer;\n\t\tlet start = 0;\n\t\tfor (let index = 0; index < buf.length; index++) {\n\t\t\tif (buf.charCodeAt(index) !== CHAR_LINE_FEED) continue;\n\t\t\tlet stop = index;\n\t\t\tif (stop > start && buf.charCodeAt(stop - 1) === CHAR_CARRIAGE_RETURN) stop--;\n\t\t\ttokens.push(classifyLine(buf.slice(start, stop), this.#nextLineNum++));\n\t\t\tstart = index + 1;\n\t\t}\n\t\tthis.#buffer = start < buf.length ? buf.slice(start) : \"\";\n\t\treturn tokens;\n\t}\n}\n\nexport type { ParsedRange } from \"./types.js\";\n"]}
1
+ {"version":3,"file":"tokenizer.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/tokenizer.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA8D9D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBzD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIlD;AAoBD,kEAAkE;AAClE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAW7D;AAsDD,MAAM,MAAM,WAAW,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACf;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAgKnB,UAAU,SAAS;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,KAAK,GACd,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,GAC/B,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,GACxC,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,GACtC,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,GAC/B,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACjE,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,GACvD,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GACvD,CAAC,SAAS,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AA6B/C,qBAAa,SAAS;;IAKrB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAK3B;IAED,GAAG,IAAI,KAAK,EAAE,CASb;IAED,KAAK,IAAI,IAAI,CAIZ;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,CAKjC;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,KAAK,CAEzC;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1B;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9B;IAED,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMtC;CAgBD;AAED,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/types.ts"],"names":[],"mappings":"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","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * Pure data types shared across the hashline parser, applier, and patcher.\n * Nothing in this file references a filesystem, agent runtime, or schema\n * library — keep it that way.\n */\n\n/** A line-number anchor (1-indexed). */\nexport interface Anchor {\n\tline: number;\n}\n\n/** Where an `insert` edit should land relative to existing content. */\nexport type Cursor =\n\t| { kind: \"bof\" }\n\t| { kind: \"eof\" }\n\t| { kind: \"before_anchor\"; anchor: Anchor }\n\t| { kind: \"after_anchor\"; anchor: Anchor };\n\n/**\n * A single low-level edit produced by the parser and consumed by the applier.\n * Multi-line replacements decompose to one `insert` per replacement line plus\n * one `delete` per consumed line. Replacement payloads are tagged so the\n * applier can distinguish literal insertion from new content for a deleted\n * line.\n */\nexport type Edit =\n\t| {\n\t\t\tkind: \"insert\";\n\t\t\tcursor: Cursor;\n\t\t\ttext: string;\n\t\t\tlineNum: number;\n\t\t\tindex: number;\n\t\t\tmode?: \"replacement\";\n\t\t\t/**\n\t\t\t * Present on inserts lowered from `insert after block N:`: the\n\t\t\t * resolved block's first line. Lets the applier slide a body that\n\t\t\t * claims a depth inside the block back across the block's trailing\n\t\t\t * closer lines (never above this line).\n\t\t\t */\n\t\t\tblockStart?: number;\n\t }\n\t| { kind: \"delete\"; anchor: Anchor; lineNum: number; index: number; oldAssertion?: string }\n\t| {\n\t\t\t/**\n\t\t\t * Deferred block edit (`replace block N:` / `delete block N` /\n\t\t\t * `insert after block N:`). The exact line span is unknown at parse\n\t\t\t * time — it is computed by {@link resolveBlockEdits} once file text +\n\t\t\t * path (→ language) are available, then expanded into concrete edits:\n\t\t\t * a non-empty `payloads` without `mode` (from `replace block`) becomes\n\t\t\t * the same `replacement` inserts + deletes that `replace start..end:`\n\t\t\t * produces; an empty `payloads` (from `delete block`) becomes a pure\n\t\t\t * range deletion; `mode: \"insert_after\"` becomes plain `after_anchor`\n\t\t\t * inserts at the block's last line. `applyEdits` never sees this\n\t\t\t * variant.\n\t\t\t */\n\t\t\tkind: \"block\";\n\t\t\tanchor: Anchor;\n\t\t\tpayloads: string[];\n\t\t\tmode?: \"insert_after\";\n\t\t\tlineNum: number;\n\t\t\tindex: number;\n\t };\n\n/** Result of applying a parsed set of edits to a text body. */\nexport interface ApplyResult {\n\t/** Post-edit text body. */\n\ttext: string;\n\t/** First line number (1-indexed) that changed, or `undefined` for a no-op apply. */\n\tfirstChangedLine?: number;\n\t/** Diagnostic warnings collected by the parser, patcher, or recovery. */\n\twarnings?: string[];\n\t/**\n\t * Resolved spans for each `replace block`/`delete block` op in this apply,\n\t * in patch order. Present only when the apply matched the tagged content\n\t * (the common no-drift path), so the line numbers line up with what the\n\t * caller read. Absent when there were no block ops.\n\t */\n\tblockResolutions?: BlockResolution[];\n}\n\n/** A parsed `[A..B]` line range. */\nexport interface ParsedRange {\n\tstart: Anchor;\n\tend: Anchor;\n}\n\n/** Optional hints for {@link splitPatchInput}. */\nexport interface SplitOptions {\n\t/** Resolves absolute paths inside hashline headers to cwd-relative form. */\n\tcwd?: string;\n\t/**\n\t * Fallback path used when the input lacks a `[PATH]` header but contains\n\t * recognizable hashline operations. Lets streaming previews work before\n\t * the model has written the header.\n\t */\n\tpath?: string;\n}\n\n/** Streaming-formatter knobs for {@link streamHashLines}. */\nexport interface StreamOptions {\n\t/** First line number to use when formatting (1-indexed, default 1). */\n\tstartLine?: number;\n\t/** Maximum formatted lines per yielded chunk (default 200). */\n\tmaxChunkLines?: number;\n\t/** Maximum UTF-8 bytes per yielded chunk (default 64 KiB). */\n\tmaxChunkBytes?: number;\n}\n\n/** Result of {@link buildCompactDiffPreview}. */\nexport interface CompactDiffPreview {\n\tpreview: string;\n\taddedLines: number;\n\tremovedLines: number;\n}\n\n/** Optional knobs for {@link buildCompactDiffPreview}. */\nexport interface CompactDiffOptions {\n\t/** Added lines kept on each side of a long added-run elision (default 2). */\n\tmaxAddedRunContext?: number;\n\t/** Back-compat alias for {@link maxAddedRunContext}. */\n\tmaxUnchangedRun?: number;\n}\n\n/**\n * Resolved 1-indexed inclusive line span of a `replace block N:` target.\n */\nexport interface BlockSpan {\n\t/** First line of the block (1-indexed, inclusive). */\n\tstart: number;\n\t/** Last line of the block (1-indexed, inclusive). */\n\tend: number;\n}\n\n/**\n * One `replace block N:` / `delete block N` / `insert after block N:` anchor\n * resolved to its concrete line span. Surfaced on {@link ApplyResult} so the\n * host can echo \"block N → lines start..end\" and let the model catch a wrong\n * opener — e.g. a decorator or doc-comment that sits in a separate node\n * outside the resolved block.\n */\nexport interface BlockResolution {\n\t/** The 1-indexed line the block op was anchored on (the `N`). */\n\tanchorLine: number;\n\t/** First line of the resolved span (1-indexed, inclusive). */\n\tstart: number;\n\t/** Last line of the resolved span (1-indexed, inclusive). */\n\tend: number;\n\t/** Which block op produced this resolution. */\n\top: \"replace\" | \"delete\" | \"insert_after\";\n}\n\n/** Request handed to a {@link BlockResolver} to resolve one `replace block N:` anchor. */\nexport interface BlockResolverRequest {\n\t/** Target file path (used to infer language by extension). */\n\tpath: string;\n\t/** Full text the block must be resolved against (the snapshot the tag names). */\n\ttext: string;\n\t/** 1-indexed line the block must begin on. */\n\tline: number;\n}\n\n/**\n * Resolves a `replace block N:` anchor to the line span of the syntactic block\n * that begins on line N. Returns `null` when no block can be resolved\n * (unrecognized language, blank/out-of-range line, no node begins there, or the\n * resolved subtree has a syntax error). Pure seam: the hashline core declares\n * the contract; the host injects a tree-sitter-backed implementation.\n */\nexport type BlockResolver = (request: BlockResolverRequest) => BlockSpan | null;\n"]}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"hashline.d.ts","sourceRoot":"","sources":["../../../src/core/tools/hashline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqF,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGnJ,MAAM,WAAW,gBAAgB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC7E,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;CAC7E;AAMD,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,2BAA2B,IAAI,qBAAqB,CAkBnE;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,CAEzI;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,SAAmB,EAAE,SAAS,SAAI,GAAG,MAAM,CAEnH;AAED,MAAM,WAAW,uBAAuB;IAAG,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE;AAE/E,wBAAgB,uCAAuC,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,uBAAuB,CAoDnK;AAED,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAExI;AAED,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ,GAAE,SAAS,MAAM,EAAO,GAAG,MAAM,CAExK","sourcesContent":["import { computeFileHash, formatHashlineHeader, formatNumberedLines, InMemorySnapshotStore, type SnapshotStore } from \"./hashline-engine/index.ts\";\nimport { isAbsolute, normalize as normalizePath, relative, sep } from \"node:path\";\n\nexport interface HashlineSnapshot {\n\tabsolutePath: string;\n\tdisplayPath: string;\n\ttag: string;\n\tcontent: string;\n}\n\nexport interface HashlineSnapshotStore {\n\treadonly snapshots: SnapshotStore;\n\trecord(absolutePath: string, cwd: string, content: string): HashlineSnapshot;\n\tfindByHeader(displayPath: string, tag: string): HashlineSnapshot | undefined;\n}\n\nfunction toPosixPath(filePath: string): string {\n\treturn filePath.split(sep).join(\"/\");\n}\n\nexport function hashlineDisplayPath(absolutePath: string, cwd: string): string {\n\tconst relativePath = relative(cwd, absolutePath);\n\tif (relativePath && !relativePath.startsWith(\"..\") && !isAbsolute(relativePath)) return toPosixPath(relativePath);\n\treturn toPosixPath(absolutePath);\n}\n\nexport function normalizeHashlineContent(content: string): string {\n\treturn content.replace(/^\\uFEFF/, \"\").replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n}\n\nexport function computeHashlineTag(content: string): string {\n\treturn computeFileHash(normalizeHashlineContent(content));\n}\n\nexport function createHashlineSnapshotStore(): HashlineSnapshotStore {\n\tconst snapshots = new InMemorySnapshotStore();\n\tconst headers = new Map<string, HashlineSnapshot>();\n\treturn {\n\t\tsnapshots,\n\t\trecord(absolutePath: string, cwd: string, content: string): HashlineSnapshot {\n\t\t\tconst normalizedPath = normalizePath(absolutePath);\n\t\t\tconst normalized = normalizeHashlineContent(content);\n\t\t\tconst displayPath = hashlineDisplayPath(normalizedPath, cwd);\n\t\t\tconst tag = snapshots.record(normalizedPath, normalized);\n\t\t\tconst snapshot = { absolutePath: normalizedPath, displayPath, tag, content: normalized };\n\t\t\theaders.set(`${displayPath}\\0${tag}`, snapshot);\n\t\t\treturn snapshot;\n\t\t},\n\t\tfindByHeader(displayPath: string, tag: string): HashlineSnapshot | undefined {\n\t\t\treturn headers.get(`${displayPath}\\0${tag.toUpperCase()}`);\n\t\t},\n\t};\n}\n\nexport function recordHashlineSnapshot(absolutePath: string, cwd: string, content: string, store: HashlineSnapshotStore): HashlineSnapshot {\n\treturn store.record(absolutePath, cwd, content);\n}\n\nexport function formatHashlineContent(snapshot: HashlineSnapshot, content = snapshot.content, startLine = 1): string {\n\treturn [formatHashlineHeader(snapshot.displayPath, snapshot.tag), formatNumberedLines(normalizeHashlineContent(content), startLine)].join(\"\\n\");\n}\n\nexport interface StrippedHashlineContent { content: string; stripped: boolean }\n\nexport function stripKnownHashlineCopiedContentWithMeta(content: string, _absolutePath: string, _cwd: string, store: HashlineSnapshotStore): StrippedHashlineContent {\n\tconst normalized = normalizeHashlineContent(content);\n\tconst lines = normalized.split(\"\\n\");\n\tconst headerIndex = lines.findIndex((line, index) => /^\\[[^\\]\\n]+#[0-9A-Fa-f]{4}\\]$/.test(line) && lines.slice(0, index).every((prefix) => prefix.trim() === \"\" || /^#\\s+.+\\/?$/.test(prefix)));\n\tif (headerIndex < 0) return { content, stripped: false };\n\tconst header = (lines[headerIndex] ?? \"\").match(/^\\[([^\\]\\n]+)#([0-9A-Fa-f]{4})\\]$/);\n\tif (!header) return { content, stripped: false };\n\tconst snapshot = store.findByHeader(header[1] ?? \"\", header[2] ?? \"\");\n\tif (!snapshot) return { content, stripped: false };\n\tconst body = lines.slice(headerIndex + 1);\n\tif (body.length === 0) return { content: snapshot.content, stripped: true };\n\tconst stripped: string[] = [];\n\tconst snapshotLines = snapshot.content.split(\"\\n\");\n\tlet sawRow = false;\n\t// Trailing tool chrome a model is likely to copy along with the hashline\n\t// body: the read/search continuation footers, the write tool's own\n\t// `Successfully wrote N bytes to <path>` confirmation (and its stripped-\n\t// note), and `Resolved …` conflict footers. These never carry a line\n\t// number, so they mark the end of the numbered body — they must not abort\n\t// stripping the way an arbitrary non-row line would.\n\tconst isToolFooter = (line: string): boolean =>\n\t\tline.trim() === \"\"\n\t\t|| /^\\[\\d+ more lines in file\\./.test(line)\n\t\t|| /^\\[Showing lines /.test(line)\n\t\t|| /^Successfully wrote \\d+ bytes to /.test(line)\n\t\t|| /^Resolved \\d+ conflicts?/.test(line)\n\t\t|| /^Resolved conflict \\d+/.test(line)\n\t\t|| /^Note: stripped copied hashline/.test(line)\n\t\t|| /^\\[[^\\]\\n]+#[0-9A-Fa-f]{4}\\]$/.test(line);\n\tlet onlyFooter = true;\n\tfor (const line of body) {\n\t\tif (isToolFooter(line)) {\n\t\t\t// A footer after the numbered body ends the body; a footer before any\n\t\t\t// row (leading blanks / a copied snapshot header) is just skipped.\n\t\t\tif (sawRow) break;\n\t\t\tcontinue;\n\t\t}\n\t\tonlyFooter = false;\n\t\tconst match = line.match(/^[* ]?(\\d+):(.*)$/s);\n\t\tif (!match) return { content, stripped: false };\n\t\tsawRow = true;\n\t\tconst lineNumber = Number.parseInt(match[1] ?? \"0\", 10);\n\t\tconst strippedLine = match[2] ?? \"\";\n\t\tif (snapshotLines[lineNumber - 1] !== strippedLine) return { content, stripped: false };\n\t\tstripped.push(strippedLine);\n\t}\n\tif (sawRow) return { content: stripped.join(\"\\n\"), stripped: true };\n\t// Header + only tool chrome (e.g. a copied write confirmation\n\t// `Successfully wrote N bytes to <path>`) names a known snapshot with no\n\t// numbered body to recover — resolve to the snapshot's stored content.\n\tif (onlyFooter) return { content: snapshot.content, stripped: true };\n\treturn { content, stripped: false };\n}\n\nexport function stripKnownHashlineCopiedContent(content: string, absolutePath: string, cwd: string, store: HashlineSnapshotStore): string {\n\treturn stripKnownHashlineCopiedContentWithMeta(content, absolutePath, cwd, store).content;\n}\n\nexport function formatCompactHashlineEditResult(snapshot: HashlineSnapshot, diff: { diff?: string; firstChangedLine?: number }, messages: readonly string[] = []): string {\n\treturn [formatHashlineHeader(snapshot.displayPath, snapshot.tag), ...messages, diff.diff?.trim() || `First changed line: ${diff.firstChangedLine ?? 1}`].join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"hashline.d.ts","sourceRoot":"","sources":["../../../src/core/tools/hashline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqF,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGnJ,MAAM,WAAW,gBAAgB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC7E,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;CAC7E;AAMD,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,2BAA2B,IAAI,qBAAqB,CAkBnE;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,CAEzI;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,SAAmB,EAAE,SAAS,SAAI,GAAG,MAAM,CAEnH;AAED,MAAM,WAAW,uBAAuB;IAAG,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE;AAE/E,wBAAgB,uCAAuC,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,uBAAuB,CAoDnK;AAED,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAExI;AAED,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ,GAAE,SAAS,MAAM,EAAO,GAAG,MAAM,CAExK"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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","sourcesContent":["export {\n\ttype BashOperations,\n\ttype BashSpawnContext,\n\ttype BashSpawnHook,\n\ttype BashToolDetails,\n\ttype BashToolInput,\n\ttype BashToolOptions,\n\tcreateBashTool,\n\tcreateBashToolDefinition,\n\tcreateLocalBashOperations,\n} from \"./bash.ts\";\nexport {\n\tcreateEditTool,\n\tcreateEditToolDefinition,\n\ttype EditOperations,\n\ttype EditToolDetails,\n\ttype EditToolInput,\n\ttype EditToolOptions,\n} from \"./edit.ts\";\nexport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nexport {\n\tcreateFindTool,\n\tcreateFindToolDefinition,\n\ttype FindOperations,\n\ttype FindToolDetails,\n\ttype FindToolInput,\n\ttype FindToolOptions,\n} from \"./find.ts\";\nexport {\n\tcreateSearchTool,\n\tcreateSearchToolDefinition,\n\ttype SearchToolDetails,\n\ttype SearchToolInput,\n\ttype SearchToolOptions,\n} from \"./search.ts\";\nexport {\n\tcreateLsTool,\n\tcreateLsToolDefinition,\n\ttype LsOperations,\n\ttype LsToolDetails,\n\ttype LsToolInput,\n\ttype LsToolOptions,\n} from \"./ls.ts\";\nexport {\n\tcreateReadTool,\n\tcreateReadToolDefinition,\n\ttype ReadOperations,\n\ttype ReadToolDetails,\n\ttype ReadToolInput,\n\ttype ReadToolOptions,\n} from \"./read.ts\";\nexport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationOptions,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n\ttruncateTail,\n} from \"./truncate.ts\";\nexport {\n\tcreateWriteTool,\n\tcreateWriteToolDefinition,\n\ttype WriteOperations,\n\ttype WriteToolInput,\n\ttype WriteToolOptions,\n} from \"./write.ts\";\nexport { createAskUserQuestionToolDefinition } from \"./ask-user-question/index.ts\";\nexport {\n\tSTRUCTURED_OUTPUT_TOOL_NAME,\n\tcreateStructuredOutputCapture,\n\tcreateStructuredOutputTool,\n\ttype JsonObject,\n\ttype JsonPrimitive,\n\ttype JsonValue,\n\ttype StructuredOutputCapture,\n\ttype StructuredOutputFileCapture,\n\ttype StructuredOutputToolOptions,\n} from \"./structured-output.ts\";\nexport { createTodoToolDefinition } from \"./todos.ts\";\n\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport type { TSchema } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { createAskUserQuestionToolDefinition } from \"./ask-user-question/index.ts\";\nimport { createHashlineSnapshotStore, type HashlineSnapshotStore } from \"./hashline.ts\";\nimport { type BashToolOptions, createBashTool, createBashToolDefinition } from \"./bash.ts\";\nimport { createEditTool, createEditToolDefinition, type EditToolOptions } from \"./edit.ts\";\nimport { createFindTool, createFindToolDefinition, type FindToolOptions } from \"./find.ts\";\nimport { createLsTool, createLsToolDefinition, type LsToolOptions } from \"./ls.ts\";\nimport { createSearchTool, createSearchToolDefinition, type SearchToolOptions } from \"./search.ts\";\nimport { createReadTool, createReadToolDefinition, type ReadToolOptions } from \"./read.ts\";\nimport { createTodoToolDefinition } from \"./todos.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { createWriteTool, createWriteToolDefinition, type WriteToolOptions } from \"./write.ts\";\n\nexport type Tool = AgentTool<TSchema, unknown>;\nexport type ToolDef = ToolDefinition<TSchema, unknown>;\nexport type ToolName =\n\t| \"read\"\n\t| \"bash\"\n\t| \"edit\"\n\t| \"write\"\n\t| \"find\"\n\t| \"search\"\n\t| \"ls\"\n\t| \"ask_user_question\"\n\t| \"todo\";\nexport const allToolNames: Set<ToolName> = new Set([\n\t\"read\",\n\t\"bash\",\n\t\"edit\",\n\t\"write\",\n\t\"find\",\n\t\"search\",\n\t\"ls\",\n\t\"ask_user_question\",\n\t\"todo\",\n]);\n\nexport const defaultToolNames: readonly ToolName[] = [\n\t\"read\",\n\t\"bash\",\n\t\"edit\",\n\t\"write\",\n\t\"find\",\n\t\"search\",\n\t\"ask_user_question\",\n\t\"todo\",\n];\n\nexport interface ToolsOptions {\n\tread?: ReadToolOptions;\n\tbash?: BashToolOptions;\n\twrite?: WriteToolOptions;\n\tedit?: EditToolOptions;\n\tfind?: FindToolOptions;\n\tsearch?: SearchToolOptions;\n\tls?: LsToolOptions;\n\thashlineStore?: HashlineSnapshotStore;\n}\n\nexport function createToolDefinition(toolName: ToolName, cwd: string, options?: ToolsOptions): ToolDef {\n\t// Default a shared store so the singular factories don't hand read/edit/\n\t// write/search isolated stores (which silently degrades drift recovery).\n\tconst hashlineStore = options?.hashlineStore ?? createHashlineSnapshotStore();\n\tswitch (toolName) {\n\t\tcase \"read\":\n\t\t\treturn createReadToolDefinition(cwd, { ...options?.read, hashlineStore });\n\t\tcase \"bash\":\n\t\t\treturn createBashToolDefinition(cwd, options?.bash);\n\t\tcase \"edit\":\n\t\t\treturn createEditToolDefinition(cwd, { ...options?.edit, hashlineStore });\n\t\tcase \"write\":\n\t\t\treturn createWriteToolDefinition(cwd, { ...options?.write, hashlineStore });\n\t\tcase \"find\":\n\t\t\treturn createFindToolDefinition(cwd, options?.find);\n\t\tcase \"search\":\n\t\t\treturn createSearchToolDefinition(cwd, { ...options?.search, hashlineStore });\n\t\tcase \"ls\":\n\t\t\treturn createLsToolDefinition(cwd, options?.ls);\n\t\tcase \"ask_user_question\":\n\t\t\treturn createAskUserQuestionToolDefinition();\n\t\tcase \"todo\":\n\t\t\treturn createTodoToolDefinition(cwd);\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n}\n\nexport function createTool(toolName: ToolName, cwd: string, options?: ToolsOptions): Tool {\n\tconst hashlineStore = options?.hashlineStore ?? createHashlineSnapshotStore();\n\tswitch (toolName) {\n\t\tcase \"read\":\n\t\t\treturn createReadTool(cwd, { ...options?.read, hashlineStore });\n\t\tcase \"bash\":\n\t\t\treturn createBashTool(cwd, options?.bash);\n\t\tcase \"edit\":\n\t\t\treturn createEditTool(cwd, { ...options?.edit, hashlineStore });\n\t\tcase \"write\":\n\t\t\treturn createWriteTool(cwd, { ...options?.write, hashlineStore });\n\t\tcase \"find\":\n\t\t\treturn createFindTool(cwd, options?.find);\n\t\tcase \"search\":\n\t\t\treturn createSearchTool(cwd, { ...options?.search, hashlineStore });\n\t\tcase \"ls\":\n\t\t\treturn createLsTool(cwd, options?.ls);\n\t\tcase \"ask_user_question\":\n\t\t\treturn wrapToolDefinition(createAskUserQuestionToolDefinition());\n\t\tcase \"todo\":\n\t\t\treturn wrapToolDefinition(createTodoToolDefinition(cwd));\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n}\n\nexport function createCodingToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\tconst hashlineStore = options?.hashlineStore ?? createHashlineSnapshotStore();\n\treturn [\n\t\tcreateReadToolDefinition(cwd, { ...options?.read, hashlineStore }),\n\t\tcreateBashToolDefinition(cwd, { asyncEnabled: true, ...options?.bash }),\n\t\tcreateEditToolDefinition(cwd, { ...options?.edit, hashlineStore }),\n\t\tcreateWriteToolDefinition(cwd, { ...options?.write, hashlineStore }),\n\t\tcreateFindToolDefinition(cwd, options?.find),\n\t\tcreateSearchToolDefinition(cwd, { ...options?.search, hashlineStore }),\n\t];\n}\n\nexport function createReadOnlyToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\tconst hashlineStore = options?.hashlineStore ?? createHashlineSnapshotStore();\n\treturn [\n\t\tcreateReadToolDefinition(cwd, { ...options?.read, hashlineStore }),\n\t\tcreateFindToolDefinition(cwd, options?.find),\n\t\tcreateSearchToolDefinition(cwd, { ...options?.search, hashlineStore }),\n\t\tcreateLsToolDefinition(cwd, options?.ls),\n\t];\n}\n\nexport function createAllToolDefinitions(cwd: string, options?: ToolsOptions): Record<ToolName, ToolDef> {\n\tconst hashlineStore = options?.hashlineStore ?? createHashlineSnapshotStore();\n\treturn {\n\t\tread: createReadToolDefinition(cwd, { ...options?.read, hashlineStore }),\n\t\tbash: createBashToolDefinition(cwd, { asyncEnabled: true, ...options?.bash }),\n\t\tedit: createEditToolDefinition(cwd, { ...options?.edit, hashlineStore }),\n\t\twrite: createWriteToolDefinition(cwd, { ...options?.write, hashlineStore }),\n\t\tfind: createFindToolDefinition(cwd, options?.find),\n\t\tsearch: createSearchToolDefinition(cwd, { ...options?.search, hashlineStore }),\n\t\tls: createLsToolDefinition(cwd, options?.ls),\n\t\task_user_question: createAskUserQuestionToolDefinition(),\n\t\ttodo: createTodoToolDefinition(cwd),\n\t};\n}\n\nexport function createCodingTools(cwd: string, options?: ToolsOptions): Tool[] {\n\tconst hashlineStore = options?.hashlineStore ?? createHashlineSnapshotStore();\n\treturn [\n\t\tcreateReadTool(cwd, { ...options?.read, hashlineStore }),\n\t\tcreateBashTool(cwd, { asyncEnabled: true, ...options?.bash }),\n\t\tcreateEditTool(cwd, { ...options?.edit, hashlineStore }),\n\t\tcreateWriteTool(cwd, { ...options?.write, hashlineStore }),\n\t\tcreateFindTool(cwd, options?.find),\n\t\tcreateSearchTool(cwd, { ...options?.search, hashlineStore }),\n\t];\n}\n\nexport function createReadOnlyTools(cwd: string, options?: ToolsOptions): Tool[] {\n\tconst hashlineStore = options?.hashlineStore ?? createHashlineSnapshotStore();\n\treturn [\n\t\tcreateReadTool(cwd, { ...options?.read, hashlineStore }),\n\t\tcreateFindTool(cwd, options?.find),\n\t\tcreateSearchTool(cwd, { ...options?.search, hashlineStore }),\n\t\tcreateLsTool(cwd, options?.ls),\n\t];\n}\n\nexport function createAllTools(cwd: string, options?: ToolsOptions): Record<ToolName, Tool> {\n\tconst hashlineStore = options?.hashlineStore ?? createHashlineSnapshotStore();\n\treturn {\n\t\tread: createReadTool(cwd, { ...options?.read, hashlineStore }),\n\t\tbash: createBashTool(cwd, { asyncEnabled: true, ...options?.bash }),\n\t\tedit: createEditTool(cwd, { ...options?.edit, hashlineStore }),\n\t\twrite: createWriteTool(cwd, { ...options?.write, hashlineStore }),\n\t\tfind: createFindTool(cwd, options?.find),\n\t\tsearch: createSearchTool(cwd, { ...options?.search, hashlineStore }),\n\t\tls: createLsTool(cwd, options?.ls),\n\t\task_user_question: wrapToolDefinition(createAskUserQuestionToolDefinition()),\n\t\ttodo: wrapToolDefinition(createTodoToolDefinition(cwd)),\n\t};\n}\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAItF,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEnG,QAAA,MAAM,QAAQ;;;EAGZ,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC;AAIlD,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,2BAA2B;IAC3B,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAC7D,wDAAwD;IACxD,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC,GAAG;QAAE,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC;IACzG,6BAA6B;IAC7B,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;CAChE;AAQD,MAAM,WAAW,aAAa;IAC7B,yEAAyE;IACzE,UAAU,CAAC,EAAE,YAAY,CAAC;CAC1B;AAkDD,wBAAgB,sBAAsB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,aAAa,GACrB,cAAc,CAAC,OAAO,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC,CA4H5D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC,OAAO,QAAQ,CAAC,CAE7F","sourcesContent":["import { readdir as fsReaddir, stat as fsStat } from \"node:fs/promises\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { pathExists, resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\n/**\n * Pluggable operations for the ls tool.\n * Override these to delegate directory listing to remote systems (for example SSH).\n */\nexport interface LsOperations {\n\t/** Check if path exists */\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Get file or directory stats. Throws if not found. */\n\tstat: (absolutePath: string) => Promise<{ isDirectory: () => boolean }> | { isDirectory: () => boolean };\n\t/** Read directory entries */\n\treaddir: (absolutePath: string) => Promise<string[]> | string[];\n}\n\nconst defaultLsOperations: LsOperations = {\n\texists: pathExists,\n\tstat: fsStat,\n\treaddir: fsReaddir,\n};\n\nexport interface LsToolOptions {\n\t/** Custom operations for directory listing. Default: local filesystem */\n\toperations?: LsOperations;\n}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"Expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t}\n\t}\n\n\tconst entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createLsToolDefinition(\n\tcwd: string,\n\toptions?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = options?.operations ?? defaultLsOperations;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Output is truncated to ${DEFAULT_LIMIT} entries or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit }: { path?: string; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\tif (!(await ops.exists(dirPath))) {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Read directory entries.\n\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t} catch (e: unknown) {\n\t\t\t\t\t\t\tconst message = e instanceof Error ? e.message : String(e);\n\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${message}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Sort alphabetically, case-insensitive.\n\t\t\t\t\t\tentries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\n\t\t\t\t\t\t// Format entries with directory indicators.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\t\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Skip entries we cannot stat.\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e: unknown) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\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\ttext.setText(formatLsCall(args, theme));\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(formatLsResult(result, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(cwd: string, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAItF,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEnG,QAAA,MAAM,QAAQ;;;EAGZ,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC;AAIlD,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,2BAA2B;IAC3B,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAC7D,wDAAwD;IACxD,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC,GAAG;QAAE,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC;IACzG,6BAA6B;IAC7B,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;CAChE;AAQD,MAAM,WAAW,aAAa;IAC7B,yEAAyE;IACzE,UAAU,CAAC,EAAE,YAAY,CAAC;CAC1B;AAkDD,wBAAgB,sBAAsB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,aAAa,GACrB,cAAc,CAAC,OAAO,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC,CA4H5D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC,OAAO,QAAQ,CAAC,CAE7F"}
@@ -1 +1 @@
1
- {"version":3,"file":"notebook.d.ts","sourceRoot":"","sources":["../../../src/core/tools/notebook.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;AAE3D,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAMD,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAE5D;AAYD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG,MAAM,CAIzE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7D;AAED,wBAAgB,aAAa,IAAI,gBAAgB,CAEhD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAIxF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAQzE;AAkCD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAyBzH;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAG1F;AAED,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI3G","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\n\n/**\n * Editable notebook projection, mirrored from oh-my-pi's\n * `packages/coding-agent/src/edit/notebook.ts` at 15b5c1397fc.\n *\n * A notebook is projected to an editable text form using cell markers:\n *\n * # %% [code|markdown|raw] cell:<index>\n *\n * Source lines that themselves look like a cell marker are escaped by adding\n * one extra `%`. Edits applied to the projected text are mapped back to the\n * underlying notebook JSON, preserving cell metadata/outputs/execution counts.\n */\n\nexport type NotebookCellType = \"code\" | \"markdown\" | \"raw\";\n\nexport interface NotebookCell {\n\tcell_type: NotebookCellType;\n\tsource?: string | string[];\n\tmetadata?: Record<string, unknown>;\n\texecution_count?: number | null;\n\toutputs?: unknown[];\n\t[key: string]: unknown;\n}\n\nexport interface NotebookDocument {\n\tcells: NotebookCell[];\n\tmetadata: Record<string, unknown>;\n\tnbformat: number;\n\tnbformat_minor: number;\n\t[key: string]: unknown;\n}\n\nconst CELL_MARKER_RE = /^# %% \\[(code|markdown|raw)\\](?: cell:(\\d+))?$/;\nconst ESCAPABLE_MARKER_RE = /^# %%+ \\[(?:code|markdown|raw)\\](?: cell:\\d+)?$/;\nconst ESCAPED_MARKER_RE = /^# %%%+ \\[(?:code|markdown|raw)\\](?: cell:\\d+)?$/;\n\nexport function isNotebookPath(absolutePath: string): boolean {\n\treturn /\\.ipynb$/i.test(absolutePath);\n}\n\nfunction escapeMarkerLikeSourceLine(line: string): string {\n\tif (ESCAPABLE_MARKER_RE.test(line)) return `${line.slice(0, 2)}%${line.slice(2)}`;\n\treturn line;\n}\n\nfunction unescapeMarkerLikeSourceLine(line: string): string {\n\tif (ESCAPED_MARKER_RE.test(line)) return `${line.slice(0, 2)}${line.slice(3)}`;\n\treturn line;\n}\n\nexport function cellSourceToString(source: NotebookCell[\"source\"]): string {\n\tif (source === undefined) return \"\";\n\tif (typeof source === \"string\") return source;\n\treturn source.join(\"\");\n}\n\nexport function splitNotebookSource(content: string): string[] {\n\treturn content.match(/[^\\n]*\\n|[^\\n]+$/g) ?? [];\n}\n\nexport function emptyNotebook(): NotebookDocument {\n\treturn { cells: [], metadata: {}, nbformat: 4, nbformat_minor: 5 };\n}\n\nexport function newNotebookCell(cellType: NotebookCellType, source: string): NotebookCell {\n\tconst cell: NotebookCell = { cell_type: cellType, metadata: {}, source: splitNotebookSource(source) };\n\tif (cellType === \"code\") { cell.execution_count = null; cell.outputs = []; }\n\treturn cell;\n}\n\nexport function notebookToEditableText(notebook: NotebookDocument): string {\n\tconst lines: string[] = [];\n\tfor (const [index, cell] of notebook.cells.entries()) {\n\t\tconst source = cellSourceToString(cell.source);\n\t\tlines.push(`# %% [${cell.cell_type}] cell:${index}`);\n\t\tif (source !== \"\") for (const line of source.split(\"\\n\")) lines.push(escapeMarkerLikeSourceLine(line));\n\t}\n\treturn lines.join(\"\\n\");\n}\n\ninterface ParsedVirtualCell {\n\tcellType: NotebookCellType;\n\tcellIndex?: number;\n\tsource: string;\n}\n\nfunction parseNotebookEditableText(text: string, displayPath: string): ParsedVirtualCell[] {\n\tconst lines = text.split(\"\\n\");\n\tconst cells: ParsedVirtualCell[] = [];\n\tlet current: ParsedVirtualCell | null = null;\n\tlet sawMarker = false;\n\tfor (const line of lines) {\n\t\tconst match = line.match(CELL_MARKER_RE);\n\t\tif (match) {\n\t\t\tsawMarker = true;\n\t\t\tconst cellType = (match[1] ?? \"raw\") as NotebookCellType;\n\t\t\tconst cellIndex = match[2] !== undefined ? Number.parseInt(match[2], 10) : undefined;\n\t\t\tcurrent = { cellType, cellIndex, source: \"\" };\n\t\t\tcells.push(current);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!sawMarker) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid notebook editable representation for ${displayPath}: expected first line to be \"# %% [code] cell:0\", \"# %% [markdown] cell:0\", or \"# %% [raw] cell:0\".`,\n\t\t\t);\n\t\t}\n\t\tconst restored = unescapeMarkerLikeSourceLine(line);\n\t\tcurrent!.source = current!.source === \"\" ? restored : `${current!.source}\\n${restored}`;\n\t}\n\treturn cells;\n}\n\nexport function applyNotebookEditableText(notebook: NotebookDocument, text: string, displayPath: string): NotebookDocument {\n\tconst parsed = parseNotebookEditableText(text, displayPath);\n\tconst next = structuredClone(notebook) as NotebookDocument;\n\tconst used = new Set<number>();\n\tnext.cells = parsed.map((parsedCell) => {\n\t\tlet cell: NotebookCell;\n\t\tconst cellIndex = parsedCell.cellIndex;\n\t\tif (cellIndex !== undefined && cellIndex >= 0 && cellIndex < notebook.cells.length && !used.has(cellIndex)) {\n\t\t\tused.add(cellIndex);\n\t\t\tcell = structuredClone(notebook.cells[cellIndex]!) as NotebookCell;\n\t\t} else {\n\t\t\tcell = newNotebookCell(parsedCell.cellType, \"\");\n\t\t}\n\t\tcell.cell_type = parsedCell.cellType;\n\t\tcell.source = splitNotebookSource(parsedCell.source);\n\t\tif (parsedCell.cellType === \"code\") {\n\t\t\tif (cell.execution_count === undefined) cell.execution_count = null;\n\t\t\tif (cell.outputs === undefined) cell.outputs = [];\n\t\t} else {\n\t\t\tdelete cell.execution_count;\n\t\t\tdelete cell.outputs;\n\t\t}\n\t\treturn cell;\n\t});\n\treturn next;\n}\n\nexport function readEditableNotebookText(absolutePath: string, displayPath: string): string {\n\tconst notebook = existsSync(absolutePath) ? parseNotebookSafe(readFileSync(absolutePath, \"utf8\"), displayPath) : emptyNotebook();\n\treturn notebookToEditableText(notebook);\n}\n\nexport function serializeEditedNotebookText(absolutePath: string, displayPath: string, text: string): string {\n\tconst notebook = existsSync(absolutePath) ? parseNotebookSafe(readFileSync(absolutePath, \"utf8\"), displayPath) : emptyNotebook();\n\tconst next = applyNotebookEditableText(notebook, text, displayPath);\n\treturn JSON.stringify(next, null, 1);\n}\n\nfunction parseNotebookSafe(raw: string, displayPath: string): NotebookDocument {\n\tlet parsed: unknown;\n\ttry { parsed = JSON.parse(raw); } catch { throw new Error(`Invalid notebook JSON for ${displayPath}`); }\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) throw new Error(`Invalid notebook JSON for ${displayPath}`);\n\tconst doc = parsed as Partial<NotebookDocument>;\n\treturn { ...doc, cells: Array.isArray(doc.cells) ? doc.cells as NotebookCell[] : [], metadata: (doc.metadata ?? {}) as Record<string, unknown>, nbformat: doc.nbformat ?? 4, nbformat_minor: doc.nbformat_minor ?? 5 };\n}\n"]}
1
+ {"version":3,"file":"notebook.d.ts","sourceRoot":"","sources":["../../../src/core/tools/notebook.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;AAE3D,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAMD,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAE5D;AAYD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG,MAAM,CAIzE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7D;AAED,wBAAgB,aAAa,IAAI,gBAAgB,CAEhD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAIxF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAQzE;AAkCD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAyBzH;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAG1F;AAED,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI3G"}
@@ -1 +1 @@
1
- {"version":3,"file":"output-accumulator.d.ts","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAE1G,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAWD;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAE7C,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,wBAAwB,CAAQ;IACxC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,cAAc,CAA0B;IAEhD,YAAY,OAAO,GAAE,wBAA6B,EAKjD;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAczB;IAED,MAAM,IAAI,IAAI,CASb;IAED,QAAQ,CAAC,OAAO,GAAE;QAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,cAAc,CA4BvE;IAEK,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAqBnC;IAED,gBAAgB,IAAI,MAAM,CAEzB;IAED,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,cAAc;CAWtB","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { createWriteStream, type WriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { APP_NAME } from \"../../config.ts\";\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 ?? `${APP_NAME}-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.d.ts","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAE1G,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAWD;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAE7C,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,wBAAwB,CAAQ;IACxC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,cAAc,CAA0B;IAEhD,YAAY,OAAO,GAAE,wBAA6B,EAKjD;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAczB;IAED,MAAM,IAAI,IAAI,CASb;IAED,QAAQ,CAAC,OAAO,GAAE;QAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,cAAc,CA4BvE;IAEK,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAqBnC;IAED,gBAAgB,IAAI,MAAM,CAEzB;IAED,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,cAAc;CAWtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"oversized-tool-result.d.ts","sourceRoot":"","sources":["../../../src/core/tools/oversized-tool-result.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAU9E;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,0BAA0B,CAAC,EAAE,MAAM,GAAG,MAAM,CAQnF;AAED,MAAM,WAAW,gCAAgC,CAAC,QAAQ,GAAG,OAAO;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC,CAAC;IAC/D,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,8BAA8B;IAC9C,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAc1D;AAcD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA4BxG;AA4FD;;;;;;;;;;;GAWG;AACH,wBAAsB,2BAA2B,CAAC,QAAQ,GAAG,OAAO,EACnE,KAAK,EAAE,gCAAgC,CAAC,QAAQ,CAAC,GAC/C,OAAO,CAAC,8BAA8B,GAAG,SAAS,CAAC,CAwCrD","sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai/compat\";\nimport { APP_NAME } from \"../../config.js\";\nimport {\n\tDEFAULT_MAX_RESULT_SIZE_CHARS,\n\tPERSISTED_OUTPUT_CLOSING_TAG,\n\tPERSISTED_OUTPUT_TAG,\n\tPREVIEW_SIZE_BYTES,\n\tTOOL_RESULTS_SUBDIR,\n} from \"./tool-limits.js\";\n\n/**\n * Resolve the effective persistence threshold (in characters) for a tool.\n *\n * Mirrors the upstream `getPersistenceThreshold` convention: a tool may declare a\n * lower per-tool cap, but the global {@link DEFAULT_MAX_RESULT_SIZE_CHARS} acts as\n * a system-wide ceiling. `Infinity` is a hard opt-out for self-bounded tools whose\n * output is already a file the model reads back, where persisting would be circular.\n */\nexport function getPersistenceThreshold(declaredMaxResultSizeChars?: number): number {\n\tif (declaredMaxResultSizeChars === undefined) {\n\t\treturn DEFAULT_MAX_RESULT_SIZE_CHARS;\n\t}\n\tif (!Number.isFinite(declaredMaxResultSizeChars)) {\n\t\treturn declaredMaxResultSizeChars;\n\t}\n\treturn Math.min(declaredMaxResultSizeChars, DEFAULT_MAX_RESULT_SIZE_CHARS);\n}\n\nexport interface RedirectOversizedToolResultInput<TDetails = unknown> {\n\ttoolName: string;\n\ttoolCallId: string;\n\tresult: Pick<AgentToolResult<TDetails>, \"content\" | \"details\">;\n\tisError: boolean;\n\tsessionId: string;\n\tsessionDir?: string;\n\t/** Optional per-tool character cap; clamped by {@link DEFAULT_MAX_RESULT_SIZE_CHARS}. */\n\tmaxResultSizeChars?: number;\n}\n\nexport interface OversizedToolResultReplacement {\n\tcontent: TextContent[];\n\tdetails: unknown;\n\tisError: boolean;\n}\n\n/**\n * Human-readable byte size, e.g. `1536` → \"1.5KB\". Intentionally mirrors\n * upstream Claude Code `formatFileSize` wording instead of using tools/truncate.ts.\n */\nexport function formatFileSize(sizeInBytes: number): string {\n\tconst kb = sizeInBytes / 1024;\n\tif (kb < 1) {\n\t\treturn `${sizeInBytes} bytes`;\n\t}\n\tif (kb < 1024) {\n\t\treturn `${kb.toFixed(1).replace(/\\.0$/, \"\")}KB`;\n\t}\n\tconst mb = kb / 1024;\n\tif (mb < 1024) {\n\t\treturn `${mb.toFixed(1).replace(/\\.0$/, \"\")}MB`;\n\t}\n\tconst gb = mb / 1024;\n\treturn `${gb.toFixed(1).replace(/\\.0$/, \"\")}GB`;\n}\n\nfunction hasImageBlock(content: readonly (TextContent | ImageContent)[]): boolean {\n\treturn content.some((block) => block.type === \"image\");\n}\n\n/** Concatenate the text blocks of a tool result into a single string. */\nfunction collectText(content: readonly (TextContent | ImageContent)[]): string {\n\treturn content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\");\n}\n\n/**\n * Generate a preview of content, truncating at a newline boundary when possible.\n * Ported from the reference `generatePreview`.\n */\nexport function generatePreview(content: string, maxBytes: number): { preview: string; hasMore: boolean } {\n\tif (Buffer.byteLength(content, \"utf8\") <= maxBytes) {\n\t\treturn { preview: content, hasMore: false };\n\t}\n\n\tlet bytes = 0;\n\tlet hardCutIndex = 0;\n\tlet lastNewlineIndex = -1;\n\tlet lastNewlineBytes = 0;\n\n\tfor (const character of content) {\n\t\tconst characterBytes = Buffer.byteLength(character, \"utf8\");\n\t\tif (bytes + characterBytes > maxBytes) {\n\t\t\tbreak;\n\t\t}\n\t\tconst characterStartIndex = hardCutIndex;\n\t\tbytes += characterBytes;\n\t\thardCutIndex += character.length;\n\t\tif (character === \"\\n\") {\n\t\t\tlastNewlineIndex = characterStartIndex;\n\t\t\tlastNewlineBytes = bytes - characterBytes;\n\t\t}\n\t}\n\n\t// Find the last newline within the byte limit to avoid cutting mid-line;\n\t// fall back to the hard byte limit when the newline is too close to the start.\n\tconst cutPoint = lastNewlineBytes > maxBytes * 0.5 ? lastNewlineIndex : hardCutIndex;\n\treturn { preview: content.slice(0, cutPoint), hasMore: true };\n}\n\n/**\n * Build the `<persisted-output>` preview message shown to the model in place of\n * the oversized content. Ported from the reference `buildLargeToolResultMessage`.\n */\nfunction buildPersistedOutputMessage(input: {\n\toriginalSizeBytes: number;\n\tfilepath: string;\n\tpreview: string;\n\thasMore: boolean;\n}): string {\n\tlet message = `${PERSISTED_OUTPUT_TAG}\\n`;\n\tmessage += `Output too large (${formatFileSize(input.originalSizeBytes)}). Full output saved to: ${input.filepath}\\n\\n`;\n\tmessage += `Preview (first ${formatFileSize(PREVIEW_SIZE_BYTES)}):\\n`;\n\tmessage += input.preview;\n\tmessage += input.hasMore ? \"\\n...\\n\" : \"\\n\";\n\tmessage += PERSISTED_OUTPUT_CLOSING_TAG;\n\treturn message;\n}\n\n/** Strip leading/trailing underscores with a linear scan (no backtracking regex). */\nfunction trimUnderscores(value: string): string {\n\tlet start = 0;\n\tlet end = value.length;\n\twhile (start < end && value[start] === \"_\") {\n\t\tstart++;\n\t}\n\twhile (end > start && value[end - 1] === \"_\") {\n\t\tend--;\n\t}\n\treturn value.slice(start, end);\n}\n\nfunction sanitizePathComponent(value: string, fallback: string): string {\n\t// Collapse disallowed characters to \"_\", then strip leading/trailing \"_\". The trim uses\n\t// a manual linear scan instead of a /^_+|_+$/ regex to avoid a polynomial-time ReDoS on\n\t// tool-call ids containing long runs of underscores (CodeQL js/polynomial-redos).\n\tconst sanitized = trimUnderscores(value.replace(/[^a-zA-Z0-9._-]+/g, \"_\")).slice(0, 64);\n\treturn sanitized.length > 0 ? sanitized : fallback;\n}\n\n/** Session-scoped directory for persisted tool results: `<sessionDir>/tool-results`. */\nfunction getToolResultsDir(input: { sessionDir?: string; sessionId: string }): string {\n\tif (input.sessionDir?.trim()) {\n\t\treturn join(input.sessionDir, TOOL_RESULTS_SUBDIR);\n\t}\n\t// Fall back to a stable session-scoped temp directory for in-memory sessions.\n\tconst safeApp = sanitizePathComponent(APP_NAME || \"atomic\", \"atomic\");\n\tconst safeSessionId = sanitizePathComponent(input.sessionId || \"session\", \"session\");\n\treturn join(tmpdir(), `${safeApp}-${TOOL_RESULTS_SUBDIR}`, safeSessionId);\n}\n\nfunction getErrnoCode(error: unknown): string | undefined {\n\tif (error && typeof error === \"object\" && \"code\" in error) {\n\t\tconst code = (error as { code?: unknown }).code;\n\t\treturn typeof code === \"string\" ? code : undefined;\n\t}\n\treturn undefined;\n}\n\n/**\n * Persist the full tool output to a session-scoped file and return its path.\n *\n * The tool_use_id is unique per invocation and the content is deterministic for a\n * given id, so we write with the `wx` flag and treat `EEXIST` as success — this\n * makes repeated calls (e.g. replay/compaction) idempotent without rewriting.\n * Returns `undefined` on any other write failure so the caller can fall back to\n * returning the original result unchanged.\n */\nasync function persistToolOutput(input: {\n\ttext: string;\n\tsessionDir?: string;\n\tsessionId: string;\n\ttoolCallId: string;\n}): Promise<string | undefined> {\n\tconst dir = getToolResultsDir({ sessionDir: input.sessionDir, sessionId: input.sessionId });\n\tconst fileName = `${sanitizePathComponent(input.toolCallId, \"tool-result\")}.txt`;\n\tconst filepath = join(dir, fileName);\n\ttry {\n\t\tawait mkdir(dir, { recursive: true, mode: 0o700 });\n\t\tawait writeFile(filepath, input.text, { encoding: \"utf8\", mode: 0o600, flag: \"wx\" });\n\t} catch (error) {\n\t\tif (getErrnoCode(error) === \"EEXIST\") {\n\t\t\t// Already persisted on a prior turn — reuse the existing file.\n\t\t\treturn filepath;\n\t\t}\n\t\treturn undefined;\n\t}\n\treturn filepath;\n}\n\n/**\n * When a tool result's text content exceeds the persistence threshold (default\n * 50,000 chars — {@link DEFAULT_MAX_RESULT_SIZE_CHARS}), persist the full output\n * to a session-scoped file and replace the model-visible content with a\n * `<persisted-output>` preview that references the saved file.\n *\n * Returns `undefined` (leave the result untouched) when the result is within the\n * threshold, contains image blocks, or cannot be persisted to disk.\n *\n * Convention ported from the upstream `maybePersistLargeToolResult`\n * (mehmoodosman/claude-code, `src/utils/toolResultStorage.ts`).\n */\nexport async function redirectOversizedToolResult<TDetails = unknown>(\n\tinput: RedirectOversizedToolResultInput<TDetails>,\n): Promise<OversizedToolResultReplacement | undefined> {\n\tconst content = input.result.content;\n\n\t// Image content must be sent to the model as-is; never persist.\n\tif (hasImageBlock(content)) {\n\t\treturn undefined;\n\t}\n\n\tconst text = collectText(content);\n\tconst threshold = getPersistenceThreshold(input.maxResultSizeChars);\n\tif (text.length <= threshold) {\n\t\treturn undefined;\n\t}\n\n\tconst filepath = await persistToolOutput({\n\t\ttext,\n\t\tsessionDir: input.sessionDir,\n\t\tsessionId: input.sessionId,\n\t\ttoolCallId: input.toolCallId,\n\t});\n\t// Graceful degradation: if persistence failed, leave the original result unchanged.\n\tif (filepath === undefined) {\n\t\treturn undefined;\n\t}\n\n\tconst { preview, hasMore } = generatePreview(text, PREVIEW_SIZE_BYTES);\n\tconst message = buildPersistedOutputMessage({\n\t\toriginalSizeBytes: Buffer.byteLength(text, \"utf8\"),\n\t\tfilepath,\n\t\tpreview,\n\t\thasMore,\n\t});\n\n\treturn {\n\t\tcontent: [{ type: \"text\", text: message }],\n\t\t// Details (tool metadata) are passed through untouched, matching the reference\n\t\t// convention which only replaces the model-visible content block.\n\t\tdetails: input.result.details,\n\t\tisError: input.isError,\n\t};\n}\n"]}
1
+ {"version":3,"file":"oversized-tool-result.d.ts","sourceRoot":"","sources":["../../../src/core/tools/oversized-tool-result.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAU9E;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,0BAA0B,CAAC,EAAE,MAAM,GAAG,MAAM,CAQnF;AAED,MAAM,WAAW,gCAAgC,CAAC,QAAQ,GAAG,OAAO;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC,CAAC;IAC/D,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,8BAA8B;IAC9C,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAc1D;AAcD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA4BxG;AA4FD;;;;;;;;;;;GAWG;AACH,wBAAsB,2BAA2B,CAAC,QAAQ,GAAG,OAAO,EACnE,KAAK,EAAE,gCAAgC,CAAC,QAAQ,CAAC,GAC/C,OAAO,CAAC,8BAA8B,GAAG,SAAS,CAAC,CAwCrD"}
@@ -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":"read-document-extract.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read-document-extract.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKlG,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAgD;AAwJ1G,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI7F;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAMtL","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { convertBufferWithMarkit, convertFileWithMarkit } from \"../../utils/markit.ts\";\nimport { selectExactReadRanges, selectReadRanges, type ReadLineRange } from \"./read-selectors.ts\";\n\nconst DOCUMENT_EXTENSIONS = /\\.(?:pdf|doc|docx|ppt|pptx|xls|xlsx|rtf|epub|ipynb)(?:$|[?#])/i;\nconst MARKIT_EXTENSIONS = /\\.(?:pdf|doc|docx|ppt|pptx|xls|xlsx|rtf|epub)(?:$|[?#])/i;\n\nexport function isDocumentPath(pathValue: string): boolean { return DOCUMENT_EXTENSIONS.test(pathValue); }\n\nfunction documentExtensionFromContentType(contentType: string): string | undefined {\n\tif (/ipynb|jupyter/i.test(contentType)) return \".ipynb\";\n\tif (/pdf/i.test(contentType)) return \".pdf\";\n\tif (/msword/i.test(contentType)) return \".doc\";\n\tif (/wordprocessingml|officedocument\\.word/i.test(contentType)) return \".docx\";\n\tif (/presentationml|officedocument\\.presentation/i.test(contentType)) return \".pptx\";\n\tif (/ms-powerpoint|vnd\\.ms-powerpoint/i.test(contentType)) return \".ppt\";\n\tif (/spreadsheetml|officedocument\\.spreadsheet/i.test(contentType)) return \".xlsx\";\n\tif (/epub/i.test(contentType)) return \".epub\";\n\tif (/ms-excel|vnd\\.ms-excel/i.test(contentType)) return \".xls\";\n\tif (/rtf/i.test(contentType)) return \".rtf\";\n\treturn undefined;\n}\n\nfunction isHtmlWhitespace(char: string | undefined): boolean { return char === \" \" || char === \"\\t\" || char === \"\\n\" || char === \"\\r\" || char === \"\\f\"; }\n\nfunction findElementStart(lowerHtml: string, tagName: string, fromIndex: number): number {\n\tconst needle = `<${tagName}`;\n\tlet index = fromIndex;\n\tfor (;;) {\n\t\tconst found = lowerHtml.indexOf(needle, index);\n\t\tif (found < 0) return -1;\n\t\tconst next = lowerHtml[found + needle.length];\n\t\tif (next === undefined || next === \">\" || next === \"/\" || isHtmlWhitespace(next)) return found;\n\t\tindex = found + needle.length;\n\t}\n}\n\nfunction findClosingTag(lowerHtml: string, tagName: string, fromIndex: number): number {\n\tconst needle = `</${tagName}`;\n\tlet index = fromIndex;\n\tfor (;;) {\n\t\tconst found = lowerHtml.indexOf(needle, index);\n\t\tif (found < 0) return -1;\n\t\tlet cursor = found + needle.length;\n\t\twhile (isHtmlWhitespace(lowerHtml[cursor])) cursor++;\n\t\tif (lowerHtml[cursor] === \">\") return found;\n\t\tindex = found + needle.length;\n\t}\n}\n\nfunction stripElementBlocks(html: string, tagName: string): string {\n\tconst lowerHtml = html.toLowerCase();\n\tconst chunks: string[] = [];\n\tlet index = 0;\n\tfor (;;) {\n\t\tconst start = findElementStart(lowerHtml, tagName, index);\n\t\tif (start < 0) break;\n\t\tchunks.push(html.slice(index, start));\n\t\tconst startEnd = html.indexOf(\">\", start);\n\t\tif (startEnd < 0) { index = html.length; break; }\n\t\tconst closeStart = findClosingTag(lowerHtml, tagName, startEnd + 1);\n\t\tif (closeStart < 0) { index = html.length; break; }\n\t\tconst closeEnd = html.indexOf(\">\", closeStart);\n\t\tif (closeEnd < 0) { index = html.length; break; }\n\t\tindex = closeEnd + 1;\n\t}\n\tchunks.push(html.slice(index));\n\treturn chunks.join(\"\");\n}\n\nfunction extractElementText(html: string, tagName: string): string | undefined {\n\tconst lowerHtml = html.toLowerCase();\n\tconst start = findElementStart(lowerHtml, tagName, 0);\n\tif (start < 0) return undefined;\n\tconst startEnd = html.indexOf(\">\", start);\n\tif (startEnd < 0) return undefined;\n\tconst closeStart = findClosingTag(lowerHtml, tagName, startEnd + 1);\n\treturn closeStart < 0 ? undefined : html.slice(startEnd + 1, closeStart);\n}\n\nfunction readTagName(tagContent: string): { closing: boolean; name: string } {\n\tlet index = 0;\n\twhile (isHtmlWhitespace(tagContent[index])) index++;\n\tconst closing = tagContent[index] === \"/\";\n\tif (closing) index++;\n\twhile (isHtmlWhitespace(tagContent[index])) index++;\n\tconst start = index;\n\twhile (index < tagContent.length) {\n\t\tconst char = tagContent[index];\n\t\tif (!char || !(char >= \"a\" && char <= \"z\") && !(char >= \"A\" && char <= \"Z\") && !(char >= \"0\" && char <= \"9\")) break;\n\t\tindex++;\n\t}\n\treturn { closing, name: tagContent.slice(start, index).toLowerCase() };\n}\n\nfunction htmlMarkupToPlainText(html: string): string {\n\tlet output = \"\";\n\tlet index = 0;\n\twhile (index < html.length) {\n\t\tconst open = html.indexOf(\"<\", index);\n\t\tif (open < 0) { output += html.slice(index); break; }\n\t\toutput += html.slice(index, open);\n\t\tconst close = html.indexOf(\">\", open + 1);\n\t\tif (close < 0) break;\n\t\tconst tag = readTagName(html.slice(open + 1, close));\n\t\tif (tag.name === \"br\" || tag.closing && [\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"p\", \"div\", \"li\", \"tr\", \"blockquote\", \"pre\"].includes(tag.name)) output += \"\\n\";\n\t\telse if (!tag.closing && tag.name === \"li\") output += \"- \";\n\t\tindex = close + 1;\n\t}\n\treturn normalizeDecodedText(output);\n}\n\nfunction normalizeDecodedText(value: string): string {\n\treturn decodeEntities(value).split(\"\\n\").map((line) => line.trim()).filter(Boolean).join(\"\\n\");\n}\n\nfunction htmlToReadableText(html: string): string {\n\tconst stripped = stripElementBlocks(stripElementBlocks(html, \"script\"), \"style\");\n\tconst title = extractElementText(stripped, \"title\");\n\tconst titleText = title ? htmlMarkupToPlainText(title).split(\"\\n\").join(\" \").trim() : undefined;\n\tconst text = htmlMarkupToPlainText(stripped);\n\treturn titleText && !text.startsWith(titleText) ? `# ${titleText}\\n\\n${text}` : text;\n}\n\nfunction decodeEntities(value: string): string {\n\tconst entities: Record<string, string> = { nbsp: \" \", amp: \"&\", lt: \"<\", gt: \">\", quot: '\"', \"#39\": \"'\" };\n\tlet output = \"\";\n\tlet index = 0;\n\twhile (index < value.length) {\n\t\tconst ampersand = value.indexOf(\"&\", index);\n\t\tif (ampersand < 0) { output += value.slice(index); break; }\n\t\toutput += value.slice(index, ampersand);\n\t\tconst semicolon = value.indexOf(\";\", ampersand + 1);\n\t\tif (semicolon < 0 || semicolon - ampersand > 12) { output += \"&\"; index = ampersand + 1; continue; }\n\t\tconst entity = value.slice(ampersand + 1, semicolon).toLowerCase();\n\t\tconst decoded = entities[entity];\n\t\toutput += decoded ?? value.slice(ampersand, semicolon + 1);\n\t\tindex = semicolon + 1;\n\t}\n\treturn output;\n}\n\nfunction notebookMarkdown(buffer: Buffer, source: string): string {\n\tconst nb = JSON.parse(buffer.toString(\"utf8\")) as { cells?: Array<{ cell_type?: string; source?: string | string[] }> };\n\tconst cells = nb.cells ?? [];\n\treturn cells.map((cell, index) => {\n\t\tconst sourceText = Array.isArray(cell.source) ? cell.source.join(\"\") : cell.source ?? \"\";\n\t\treturn `# %% [${cell.cell_type ?? \"raw\"}] cell:${index}\\n${sourceText.trimEnd()}`;\n\t}).join(\"\\n\\n\") || `# ${source}\\n\\n(empty notebook)`;\n}\n\nfunction documentExtension(source: string): string { return `.${source.match(/\\.(pdf|docx?|pptx?|xlsx?|rtf|epub)(?:$|[?#])/i)?.[1]?.toLowerCase() ?? \"bin\"}`; }\n\nasync function extractMarkitDocument(buffer: Buffer, source: string): Promise<string> {\n\tconst ext = documentExtension(source);\n\tconst result = existsSync(source) ? await convertFileWithMarkit(source) : await convertBufferWithMarkit(buffer, ext);\n\treturn result.ok ? result.content : `[Cannot read ${ext} file: ${result.error || \"conversion failed\"}]`;\n}\n\nexport async function extractDocumentMarkdown(buffer: Buffer, source: string): Promise<string> {\n\tif (/\\.ipynb(?:$|[?#])/i.test(source)) return notebookMarkdown(buffer, source);\n\tif (MARKIT_EXTENSIONS.test(source)) return extractMarkitDocument(buffer, source);\n\treturn buffer.toString(\"utf8\");\n}\n\nexport async function decodeReadableUrl(response: Response, url: string): Promise<string> {\n\tconst contentType = response.headers.get(\"content-type\") ?? \"\";\n\tconst buffer = Buffer.from(await response.arrayBuffer());\n\tconst contentTypeExtension = documentExtensionFromContentType(contentType);\n\tif (contentTypeExtension || isDocumentPath(url)) return extractDocumentMarkdown(buffer, contentTypeExtension && !isDocumentPath(url) ? `${url}${contentTypeExtension}` : url);\n\tconst text = buffer.toString(\"utf8\");\n\tif (/html/i.test(contentType) || /<html[\\s>]/i.test(text)) return htmlToReadableText(text);\n\treturn text;\n}\n\nexport function applyReadLineSelection(allLines: string[], ranges: ReadLineRange[] | undefined, offset?: number, limit?: number, exact = false): { lines: string[]; firstLine: number } {\n\tconst rangeSelection = (exact ? selectExactReadRanges : selectReadRanges)(allLines, ranges);\n\tconst rangeStart = ranges?.[0]?.start;\n\tconst startLine = rangeSelection ? (rangeSelection.selectedLines.length === 0 ? rangeStart ?? rangeSelection.firstLine : rangeSelection.firstLine) - 1 : offset ? Math.max(0, offset - 1) : 0;\n\tconst endLine = limit !== undefined ? Math.min(startLine + limit, allLines.length) : allLines.length;\n\treturn { lines: rangeSelection?.selectedLines ?? allLines.slice(startLine, endLine), firstLine: startLine + 1 };\n}\n"]}
1
+ {"version":3,"file":"read-document-extract.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read-document-extract.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKlG,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAgD;AAwJ1G,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI7F;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAMtL"}
@@ -1 +1 @@
1
- {"version":3,"file":"read-selectors.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read-selectors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE;AAE9D,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AA8BD,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEjE;AAuID,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAUzE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAYlI;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG;IAAE,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAwBhO;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,SAAI,GAAG,MAAM,CAE1H","sourcesContent":["export interface ReadLineRange { start: number; end?: number }\n\nexport interface ReadLineSelector {\n\tpath: string;\n\toffset?: number;\n\tlimit?: number;\n\tranges?: ReadLineRange[];\n\traw?: boolean;\n\tconflicts?: boolean;\n}\n\nconst ARCHIVE_SELECTOR_EXTENSIONS = [\".tar.gz\", \".zip\", \".jar\", \".tar\", \".tgz\", \".gz\"];\nconst RESOURCE_SELECTOR_EXTENSIONS = [\".tar.gz\", \".sqlite\", \".zip\", \".jar\", \".tar\", \".tgz\", \".gz\", \".db\"];\n\nfunction isAsciiDigit(char: string | undefined): boolean { return char !== undefined && char >= \"0\" && char <= \"9\"; }\nfunction hasUrlScheme(value: string): boolean {\n\tconst schemeEnd = value.indexOf(\"://\");\n\tif (schemeEnd <= 0) return false;\n\tfor (let index = 0; index < schemeEnd; index++) {\n\t\tconst char = value[index]!;\n\t\tif (!((char >= \"a\" && char <= \"z\") || (char >= \"A\" && char <= \"Z\"))) return false;\n\t}\n\treturn true;\n}\nfunction selectorExtensionColonIndex(value: string, extensions: readonly string[]): number {\n\tconst lower = value.toLowerCase();\n\tlet best = Number.POSITIVE_INFINITY;\n\tfor (const extension of extensions) {\n\t\tlet from = 0;\n\t\tfor (;;) {\n\t\t\tconst extensionIndex = lower.indexOf(`${extension}:`, from);\n\t\t\tif (extensionIndex < 0) break;\n\t\t\tif (extensionIndex > 0) best = Math.min(best, extensionIndex + extension.length);\n\t\t\tfrom = extensionIndex + 1;\n\t\t}\n\t}\n\treturn Number.isFinite(best) ? best : -1;\n}\n\nexport function isReadResourceSelector(pathValue: string): boolean {\n\treturn selectorExtensionColonIndex(pathValue, RESOURCE_SELECTOR_EXTENSIONS) >= 0 || hasUrlScheme(pathValue) || pathValue.startsWith(\"skill://\");\n}\nfunction archiveSelectorColonIndex(value: string): number { return selectorExtensionColonIndex(value, ARCHIVE_SELECTOR_EXTENSIONS); }\nfunction isArchiveSelectorPath(value: string): boolean { return archiveSelectorColonIndex(value) >= 0; }\nfunction hasArchiveMember(value: string): boolean { const colonIndex = archiveSelectorColonIndex(value); return colonIndex >= 0 && colonIndex < value.length - 1; }\nfunction peelArchiveReadSuffixes(value: string, state: { raw: boolean; conflicts: boolean }): string {\n\tlet working = value;\n\tfor (;;) {\n\t\tconst lower = working.toLowerCase();\n\t\tif (lower.endsWith(\":raw\")) { state.raw = true; working = working.slice(0, -4); continue; }\n\t\tif (lower.endsWith(\":conflicts\")) { state.conflicts = true; working = working.slice(0, -10); continue; }\n\t\treturn working;\n\t}\n}\nfunction findInlineSelector(value: string, selector: \"raw\" | \"conflicts\"): number {\n\tconst needle = `:${selector}`;\n\tlet index = 0;\n\tfor (;;) {\n\t\tconst found = value.toLowerCase().indexOf(needle, index);\n\t\tif (found < 0) return -1;\n\t\tconst next = value[found + needle.length];\n\t\tif (next === undefined || next === \":\") return found;\n\t\tindex = found + needle.length;\n\t}\n}\nfunction peelInlineReadSuffixes(value: string, state: { raw: boolean; conflicts: boolean }): string {\n\tlet working = value;\n\tfor (;;) {\n\t\tconst rawIndex = findInlineSelector(working, \"raw\");\n\t\tif (rawIndex >= 0) { state.raw = true; working = `${working.slice(0, rawIndex)}${working.slice(rawIndex + 4)}`; continue; }\n\t\tconst conflictIndex = findInlineSelector(working, \"conflicts\");\n\t\tif (conflictIndex >= 0) { state.conflicts = true; working = `${working.slice(0, conflictIndex)}${working.slice(conflictIndex + 10)}`; continue; }\n\t\treturn working;\n\t}\n}\nfunction startsLikeLineRange(value: string): boolean {\n\tlet index = value[0]?.toLowerCase() === \"l\" ? 1 : 0;\n\treturn isAsciiDigit(value[index]);\n}\nfunction readNumber(value: string, start: number): { value: number; end: number } | undefined {\n\tlet index = start;\n\twhile (isAsciiDigit(value[index])) index++;\n\tif (index === start) return undefined;\n\treturn { value: Number.parseInt(value.slice(start, index), 10), end: index };\n}\nfunction parseLineRangeToken(token: string, invalid: (message: string) => void): ReadLineRange | undefined {\n\tlet index = token[0]?.toLowerCase() === \"l\" ? 1 : 0;\n\tconst startNumber = readNumber(token, index);\n\tif (!startNumber) return undefined;\n\tconst start = startNumber.value;\n\tif (start < 1) { invalid(\"Line selector 0 is invalid; lines are 1-indexed. Use :1.\"); return undefined; }\n\tindex = startNumber.end;\n\tif (index === token.length) return { start };\n\tlet separator: \"-\" | \"..\" | \"+\" | undefined;\n\tif (token.startsWith(\"..\", index)) { separator = \"..\"; index += 2; }\n\telse if (token[index] === \"-\" || token[index] === \"+\") { separator = token[index] as \"-\" | \"+\"; index++; }\n\tif (!separator) { invalid(`Invalid line selector: ${token}`); return undefined; }\n\tif (token[index]?.toLowerCase() === \"l\") index++;\n\tconst endNumber = readNumber(token, index);\n\tif (!endNumber) {\n\t\tif (separator === \"+\") invalid(`Invalid line selector :${token}; + requires a line count >= 1.`);\n\t\treturn separator === \"+\" ? undefined : { start };\n\t}\n\tif (endNumber.end !== token.length) { invalid(`Invalid line selector: ${token}`); return undefined; }\n\tconst parsed = endNumber.value;\n\tif (separator === \"+\") {\n\t\tif (parsed < 1) { invalid(`Invalid line selector :${token}; + count must be >= 1.`); return undefined; }\n\t\treturn { start, end: start + parsed - 1 };\n\t}\n\tif (parsed < start) { invalid(`Invalid line selector :${token}; end must be >= start.`); return undefined; }\n\treturn { start, end: parsed };\n}\nfunction isLineRangeListCandidate(value: string): boolean {\n\tif (!startsLikeLineRange(value)) return false;\n\tfor (const char of value) {\n\t\tif (!isAsciiDigit(char) && char !== \"L\" && char !== \"l\" && char !== \"+\" && char !== \"-\" && char !== \".\" && char !== \",\") return false;\n\t}\n\treturn true;\n}\n\nfunction parseLineRangeList(value: string, invalid: (message: string) => void): ReadLineRange[] | undefined {\n\tif (!isLineRangeListCandidate(value)) return undefined;\n\tconst ranges: ReadLineRange[] = [];\n\tfor (const token of value.split(\",\")) {\n\t\tif (!token) { invalid(`Invalid line selector: ${value}`); return undefined; }\n\t\tconst range = parseLineRangeToken(token, invalid);\n\t\tif (!range) return undefined;\n\t\tranges.push(range);\n\t}\n\treturn ranges;\n}\nfunction isBareLineNumber(value: string): boolean { return value.length > 0 && [...value].every(isAsciiDigit); }\nfunction extractTrailingLineRange(value: string, invalid: (message: string) => void): { path: string; ranges: ReadLineRange[] } | undefined {\n\tconst colonIndex = value.lastIndexOf(\":\");\n\tif (colonIndex < 0) return undefined;\n\tconst rangeText = value.slice(colonIndex + 1);\n\tconst ranges = parseLineRangeList(rangeText, invalid);\n\tif (!ranges) return undefined;\n\tconst path = value.slice(0, colonIndex);\n\t// Support the `file:START:END` (and grep-style `file:LINE:COL`) colon\n\t// convention: a trailing bare-number segment preceded by another bare-number\n\t// segment reads as START..END. Without this the leading number stays glued to\n\t// the path (`file:395`) and produces a broken filename.\n\tconst prevColon = path.lastIndexOf(\":\");\n\tif (prevColon >= 0 && ranges.length === 1 && ranges[0]!.end === undefined && isBareLineNumber(rangeText)) {\n\t\tconst prevSegment = path.slice(prevColon + 1);\n\t\tif (isBareLineNumber(prevSegment)) {\n\t\t\tconst start = Number.parseInt(prevSegment, 10);\n\t\t\tconst end = ranges[0]!.start;\n\t\t\tif (start >= 1) return { path: path.slice(0, prevColon), ranges: [end >= start ? { start, end } : { start }] };\n\t\t}\n\t}\n\treturn { path, ranges };\n}\nfunction selectorFromRanges(path: string, ranges: ReadLineRange[], raw: boolean, conflicts: boolean): ReadLineSelector {\n\tif (ranges.length === 1 && ranges[0]!.end === undefined) return { path, offset: ranges[0]!.start, raw, conflicts };\n\treturn { path, ranges, raw, conflicts };\n}\nfunction parseArchiveReadSelector(value: string): ReadLineSelector {\n\tconst state = { raw: false, conflicts: false };\n\tlet working = peelArchiveReadSuffixes(value, state);\n\tconst extracted = extractTrailingLineRange(working, () => undefined);\n\tif (!extracted) return { path: working, raw: state.raw, conflicts: state.conflicts };\n\tconst suffixState = { ...state };\n\tconst peeledPath = peelArchiveReadSuffixes(extracted.path, suffixState);\n\tconst selectorPath = hasArchiveMember(peeledPath) ? (state.raw = suffixState.raw, state.conflicts = suffixState.conflicts, peeledPath) : extracted.path;\n\tif (!hasArchiveMember(selectorPath)) return { path: working, raw: state.raw, conflicts: state.conflicts };\n\treturn selectorFromRanges(selectorPath, extracted.ranges, state.raw, state.conflicts);\n}\nfunction isHttpUrlWithPortOnly(value: string): boolean {\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn (url.protocol === \"http:\" || url.protocol === \"https:\") && url.port !== \"\" && url.pathname === \"/\" && url.search === \"\" && url.hash === \"\";\n\t} catch { return false; }\n}\n\nexport function splitReadLineSelector(pathValue: string): ReadLineSelector {\n\tconst state = { raw: false, conflicts: false };\n\tlet value = pathValue;\n\tif (isArchiveSelectorPath(value)) return parseArchiveReadSelector(value);\n\tvalue = peelInlineReadSuffixes(value, state);\n\tif (isHttpUrlWithPortOnly(value)) return { path: value, raw: state.raw, conflicts: state.conflicts };\n\tlet parseError: string | undefined;\n\tconst extracted = extractTrailingLineRange(value, (message) => { parseError = message; });\n\tif (parseError) throw new Error(parseError);\n\treturn extracted ? selectorFromRanges(extracted.path, extracted.ranges, state.raw, state.conflicts) : { path: value, raw: state.raw, conflicts: state.conflicts };\n}\n\nexport function selectExactReadRanges(allLines: string[], ranges: ReadLineRange[] | undefined): ReturnType<typeof selectReadRanges> {\n\tif (!ranges || ranges.length === 0) return undefined;\n\tconst selectedLines: string[] = [], lineNumbers: number[] = [], merged: ReadLineRange[] = [];\n\tfor (const range of [...ranges].sort((a, b) => a.start - b.start)) {\n\t\tif (range.start > allLines.length) continue;\n\t\tconst end = Math.min(range.end ?? allLines.length, allLines.length);\n\t\tconst previous = merged.at(-1);\n\t\tif (previous && range.start <= (previous.end ?? 0) + 1) previous.end = Math.max(previous.end ?? 0, end);\n\t\telse merged.push({ start: range.start, end });\n\t}\n\tfor (const range of merged) for (let line = range.start; line <= (range.end ?? allLines.length); line++) { selectedLines.push(allLines[line - 1] ?? \"\"); lineNumbers.push(line); }\n\treturn { selectedLines, selectedContent: selectedLines.join(\"\\n\"), firstLine: lineNumbers[0] ?? 1, lineNumbers, userLimitedLines: selectedLines.length };\n}\n\nexport function selectReadRanges(allLines: string[], ranges: ReadLineRange[] | undefined): { selectedLines: string[]; selectedContent: string; firstLine: number; lineNumbers?: number[]; userLimitedLines?: number } | undefined {\n\tif (!ranges || ranges.length === 0) return undefined;\n\tconst selectedLines: string[] = [];\n\tconst lineNumbers: number[] = [];\n\tconst merged: ReadLineRange[] = [];\n\tfor (const range of [...ranges].sort((a, b) => a.start - b.start)) {\n\t\tconst bounded = range.end !== undefined;\n\t\tif (range.start > allLines.length) continue;\n\t\tconst requestedEnd = Math.min(range.end ?? allLines.length, allLines.length);\n\t\tif (requestedEnd < range.start) continue;\n\t\tconst start = Math.max(1, range.start - (bounded ? 1 : 0));\n\t\tconst end = Math.min(allLines.length, requestedEnd + (bounded ? 3 : 0));\n\t\tconst previous = merged.at(-1);\n\t\tif (previous && start <= (previous.end ?? 0) + 1) previous.end = Math.max(previous.end ?? 0, end);\n\t\telse merged.push({ start, end });\n\t}\n\tfor (const range of merged) {\n\t\tconst end = Math.min(range.end ?? allLines.length, allLines.length);\n\t\tfor (let line = range.start; line <= end; line++) {\n\t\t\tselectedLines.push(allLines[line - 1] ?? \"\");\n\t\t\tlineNumbers.push(line);\n\t\t}\n\t}\n\treturn { selectedLines, selectedContent: selectedLines.join(\"\\n\"), firstLine: lineNumbers[0] ?? 1, lineNumbers, userLimitedLines: selectedLines.length };\n}\n\nexport function formatHashlineSelectedLines(header: string, lines: string[], lineNumbers?: number[], startLine = 1): string {\n\treturn [header, ...lines.map((line, index) => `${lineNumbers?.[index] ?? startLine + index}:${line}`)].join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"read-selectors.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read-selectors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE;AAE9D,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AA8BD,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEjE;AAuID,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAUzE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAYlI;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG;IAAE,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAwBhO;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,SAAI,GAAG,MAAM,CAE1H"}
@@ -1 +1 @@
1
- {"version":3,"file":"read-url.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read-url.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAIjD,MAAM,WAAW,iBAAiB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,SAAS,CAAC;IAC/D,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,KAAK;QAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,CAAC;IACzO,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,eAAe,CAAC;CAChD;AAED,MAAM,MAAM,mBAAmB,GAAG;IAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAAC,OAAO,EAAE,eAAe,GAAG,SAAS,CAAA;CAAE,CAAC;AAEnG,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA6BzF","sourcesContent":["/**\n * URL branch of the `read` tool: routes plain URL reads through the\n * cache/artifact/llms.txt fetch pipeline ({@link executeReadUrl}); explicit\n * URL line selectors reuse the same safe rendering path before slicing lines.\n */\nimport { resolve as resolvePath } from \"node:path\";\nimport type { TextContent } from \"@earendil-works/pi-ai/compat\";\nimport type { ReadToolDetails } from \"./read.ts\";\nimport { applyReadLineSelection, decodeReadableUrl } from \"./read-document-extract.ts\";\nimport { executeReadUrl, loadPage } from \"./fetch-url.ts\";\n\nexport interface ReadUrlBranchArgs {\n\teffectivePath: string;\n\trawOutput: boolean;\n\teffectiveRanges: { start: number; end?: number }[] | undefined;\n\teffectiveOffset: number | undefined;\n\teffectiveLimit: number | undefined;\n\tcwd: string;\n\tctx: unknown;\n\tsignal?: AbortSignal;\n\tmaxChars: number;\n\tmaxBytes: number;\n\toversized: (details: { blocked: true; path: string; chars: number; maxChars: number; startLine: number; totalFileLines: number; firstLineBytes: number; byteGuidance: boolean }) => { content: TextContent[]; details: ReadToolDetails };\n\tsourceMeta: (source: string) => ReadToolDetails;\n}\n\nexport type ReadUrlBranchResult = { content: TextContent[]; details: ReadToolDetails | undefined };\n\nexport async function readUrlBranch(args: ReadUrlBranchArgs): Promise<ReadUrlBranchResult> {\n\tconst { effectivePath, rawOutput, effectiveRanges, effectiveOffset, effectiveLimit, cwd, ctx, signal, maxChars, maxBytes, oversized, sourceMeta } = args;\n\tconst session = (ctx as { sessionManager?: { getSessionDir?: () => string | undefined; getSessionId?: () => string | undefined } } | undefined)?.sessionManager;\n\tconst sessionDir = session?.getSessionDir?.();\n\tconst scope = session?.getSessionId?.() ?? cwd;\n\tconst artifactsDir = sessionDir ? resolvePath(sessionDir, \"artifacts\") : undefined;\n\tif (!effectiveRanges && !effectiveOffset && effectiveLimit === undefined) {\n\t\tconst result = await executeReadUrl(scope, { path: effectivePath, raw: rawOutput }, artifactsDir, signal);\n\t\tconst artifactId = result.artifactId ?? result.details.meta?.artifactId;\n\t\tconst truncation = result.details.meta?.truncation;\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text: result.content }],\n\t\t\tdetails: {\n\t\t\t\t...(truncation ? { truncation } : {}),\n\t\t\t\tmeta: { ...(result.details.meta ?? {}), source: effectivePath, sourcePath: effectivePath, ...(artifactId ? { artifactId } : {}) },\n\t\t\t},\n\t\t};\n\t}\n\tconst page = await loadPage(effectivePath, 10_000, signal);\n\tconst textContent = rawOutput ? page.content : await decodeReadableUrl(new Response(page.content, { headers: { \"content-type\": page.contentType } }), page.finalUrl || effectivePath);\n\tconst selection = applyReadLineSelection(textContent.split(\"\\n\"), effectiveRanges, effectiveOffset, effectiveLimit, rawOutput), selectedText = selection.lines.join(\"\\n\");\n\tif ((effectiveRanges || effectiveOffset) && selection.lines.length === 0) {\n\t\tconst requested = effectiveRanges?.[0]?.start ?? effectiveOffset ?? 1;\n\t\treturn { content: [{ type: \"text\", text: `Requested line ${requested} is beyond end of resource (${textContent.split(\"\\n\").length} lines total).` }], details: undefined };\n\t}\n\tif (selectedText.length > maxChars || Buffer.byteLength(selectedText, \"utf8\") > maxBytes) {\n\t\treturn oversized({ blocked: true, path: effectivePath, chars: selectedText.length, maxChars, startLine: selection.firstLine, totalFileLines: textContent.split(\"\\n\").length, firstLineBytes: Buffer.byteLength(selection.lines[0] ?? \"\", \"utf8\"), byteGuidance: false });\n\t}\n\treturn { content: [{ type: \"text\", text: rawOutput ? selectedText : `URL: ${effectivePath}\\nStatus: ${page.status}\\nContent-Type: ${page.contentType || \"unknown\"}\\n\\n${selectedText}` }], details: sourceMeta(effectivePath) };\n}\n"]}
1
+ {"version":3,"file":"read-url.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read-url.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAIjD,MAAM,WAAW,iBAAiB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,SAAS,CAAC;IAC/D,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,KAAK;QAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,CAAC;IACzO,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,eAAe,CAAC;CAChD;AAED,MAAM,MAAM,mBAAmB,GAAG;IAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAAC,OAAO,EAAE,eAAe,GAAG,SAAS,CAAA;CAAE,CAAC;AAEnG,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA6BzF"}
@@ -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;AAa5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAA8E,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAMvI,OAAO,EAAoD,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AACtH,QAAA,MAAM,UAAU;;EAEmB,CAAC;AACpC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,eAAe;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,gBAAgB,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;CACrI;AAMD,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CACnF;AAMD,MAAM,WAAW,eAAe;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,aAAa,CAAC,EAAE,qBAAqB,CAAC;CACtC;AAwJD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAsP/I;AACD,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/compat\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { constants } from \"fs\";\nimport { access as fsAccess, readFile as fsReadFile, stat as fsStat } 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 { parseConflictBlocks, registerConflictBlocks } from \"./conflict-registry.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 { buildDirectoryTree } from \"./directory-tree.ts\";\nimport { applyReadLineSelection, extractDocumentMarkdown, isDocumentPath } from \"./read-document-extract.ts\";\nimport { isReadableUrlPath } from \"./fetch-url.ts\";\nimport { readUrlBranch } from \"./read-url.ts\";\nimport { isNotebookPath, readEditableNotebookText } from \"./notebook.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { createHashlineSnapshotStore, formatHashlineContent, recordHashlineSnapshot, type HashlineSnapshotStore } from \"./hashline.ts\";\nimport { resolveReadPathAsync, resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, replaceTabs, shortenPath, str } from \"./render-utils.ts\";\nimport { formatHashlineSelectedLines, isReadResourceSelector, selectExactReadRanges, selectReadRanges, splitReadLineSelector, type ReadLineSelector } from \"./read-selectors.ts\";\nimport { parseArchiveSelector, readArchiveSelector, readInternalSelector, readSqliteSelector, resolveArchiveSelector, resolveInternalSelector, sqliteSelectorForPath, type InternalResourceContext } from \"./resource-selectors.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"File, directory, archive member, SQLite selector, internal resource, image, document, or URL to read. Append selectors such as :raw, :conflicts, :N, :A-B, :A+C, or :A-B,C-D to scope output.\" }),\n}, { additionalProperties: false });\nexport type ReadToolInput = Static<typeof readSchema>;\nconst READ_TOOL_MAX_RESULT_CHARS = 50_000;\nexport interface OversizedReadDetails {\n\tblocked: true;\n\tpath: string;\n\tchars: number;\n\tmaxChars: number;\n\tstartLine: number;\n\trequestedLimit?: number;\n\ttotalFileLines: number;\n\tfirstLineBytes: number;\n\tbyteGuidance: boolean;\n}\nexport interface ReadToolDetails {\n\tisDirectory?: boolean;\n\tresolvedPath?: string;\n\ttruncation?: TruncationResult;\n\toversizedRead?: OversizedReadDetails;\n\tmeta?: { source?: string; sourcePath?: string; artifactId?: string; truncation?: TruncationResult; limits?: Record<string, number> };\n}\ninterface CompactReadClassification {\n\tkind: \"docs\" | \"resource\" | \"skill\";\n\tlabel: string;\n}\nconst COMPACT_RESOURCE_FILE_NAMES = new Set([\"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"]);\nexport interface ReadOperations {\n\treadFile: (absolutePath: string) => Promise<Buffer>;\n\taccess: (absolutePath: string) => Promise<void>;\n\tdetectImageMimeType?: (absolutePath: string) => Promise<string | null | undefined>;\n}\nconst defaultReadOperations: ReadOperations = {\n\treadFile: (path) => fsReadFile(path),\n\taccess: (path) => fsAccess(path, constants.R_OK),\n\tdetectImageMimeType: detectSupportedImageMimeTypeFromFile,\n};\nexport interface ReadToolOptions {\n\tautoResizeImages?: boolean;\n\toperations?: ReadOperations;\n\thashlineStore?: HashlineSnapshotStore;\n}\ntype ReadRenderArgs = { path?: string };\nfunction formatReadLineRange(_args: ReadRenderArgs | undefined, _theme: Theme): string {\n\treturn \"\";\n}\nfunction formatReadCall(args: ReadRenderArgs | undefined, theme: Theme): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath) : null;\n\tconst invalidArg = invalidArgText(theme);\n\tconst pathDisplay = path === null ? invalidArg : path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"read\"))} ${pathDisplay}${formatReadLineRange(args, theme)}`;\n}\nfunction trimTrailingEmptyLines(lines: string[]): string[] { let end = lines.length; while (end > 0 && lines[end - 1] === \"\") end--; return lines.slice(0, end); }\nfunction getNonVisionImageNote(model: Model<Api> | undefined): string | undefined { return !model || model.input.includes(\"image\") ? undefined : \"[Current model does not support images. The image will be omitted from this request.]\"; }\nfunction toPosixPath(filePath: string): string { return filePath.split(sep).join(\"/\"); }\nfunction formatCount(count: number): string { return count.toLocaleString(\"en-US\"); }\nfunction shellQuote(value: string): string {\n\treturn `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\nfunction buildOversizedReadMessage(details: OversizedReadDetails): string {\n\tconst pathForExample = JSON.stringify(details.path);\n\tconst rangePathForExample = JSON.stringify(`${details.path}:${details.startLine}+200`);\n\tconst shellPathForExample = shellQuote(details.path);\n\tconst requestedLimitLine =\n\t\tdetails.requestedLimit !== undefined ? [`Requested line limit: ${formatCount(details.requestedLimit)}`] : [];\n\tif (details.byteGuidance) {\n\t\treturn [\n\t\t\t`File read blocked: requested selected range is too large (${formatCount(details.chars)} chars; threshold: ${formatCount(details.maxChars)} chars).`,\n\t\t\t`Path: ${details.path}`,\n\t\t\t...requestedLimitLine,\n\t\t\t\"\",\n\t\t\t\"The selected content starts with a single oversized line, so line pagination is not useful. Read byte slices instead. Examples:\",\n\t\t\t`- Inspect the start of line ${details.startLine}: sed -n '${details.startLine}p' ${shellPathForExample} | head -c ${DEFAULT_MAX_BYTES}`,\n\t\t\t`- Inspect a later byte window: sed -n '${details.startLine}p' ${shellPathForExample} | tail -c +${DEFAULT_MAX_BYTES + 1} | head -c ${DEFAULT_MAX_BYTES}`,\n\t\t\t`- Search for relevant text first: search({ \"pattern\": \"functionName\", \"paths\": ${pathForExample} })`,\n\t\t].join(\"\\n\");\n\t}\n\tconst targetedSnippetOffset = Math.max(details.startLine, 120);\n\tconst snippetPathForExample = JSON.stringify(`${details.path}:${targetedSnippetOffset}+80`);\n\treturn [\n\t\t`File read blocked: requested selected range is too large (${formatCount(details.chars)} chars; threshold: ${formatCount(details.maxChars)} chars).`,\n\t\t`Path: ${details.path}`,\n\t\t...requestedLimitLine,\n\t\t\"\",\n\t\t\"Read only the needed context incrementally. Examples:\",\n\t\t`- Search for relevant symbols first: search({ \"pattern\": \"functionName\", \"paths\": ${pathForExample} })`,\n\t\t`- Read a smaller line range: read({ \"path\": ${rangePathForExample} })`,\n\t\t`- Read a targeted snippet around a match: read({ \"path\": ${snippetPathForExample} })`,\n\t].join(\"\\n\");\n}\nfunction readSourceMeta(source: string): ReadToolDetails { return { meta: { source, sourcePath: source } }; }\nfunction oversizedReadResult(details: OversizedReadDetails): { content: TextContent[]; details: ReadToolDetails } { return { content: [{ type: \"text\", text: buildOversizedReadMessage(details) }], details: { oversizedRead: details, meta: { source: details.path, sourcePath: details.path, limits: { maxChars: details.maxChars }, } } }; }\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\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}\nfunction getCompactReadClassification(\n\targs: ReadRenderArgs | undefined,\n\tcwd: string,\n): CompactReadClassification | undefined {\n\tconst rawPath = str(args?.path);\n\tif (!rawPath) return undefined;\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\tconst docsClassification = getPiDocsClassification(absolutePath);\n\tif (docsClassification) return docsClassification;\n\tif (COMPACT_RESOURCE_FILE_NAMES.has(fileName)) {\n\t\treturn { kind: \"resource\", label: formatPathRelativeToCwdOrAbsolute(absolutePath, cwd) };\n\t}\n\treturn undefined;\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\")} 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\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}\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\tconst oversizedRead = result.details?.oversizedRead;\n\tconst oversizedReadBlocked = oversizedRead?.blocked === true;\n\tif (!options.expanded && !isError && !oversizedReadBlocked) {\n\t\treturn \"\";\n\t}\n\tconst rawPath = str(args?.path);\n\tconst output = oversizedRead ? buildOversizedReadMessage(oversizedRead) : getTextOutput(result, showImages);\n\tconst lang = rawPath && !oversizedReadBlocked ? 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\", \"Expand\")}${theme.fg(\"muted\", \")\")}`;\n\t}\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}\nfunction archiveSelectorMemberExists(pathValue: string, cwd: string): boolean { const archive = parseArchiveSelector(pathValue); if (!archive || !archive.memberPath) return false; try { readArchiveSelector(resolveArchiveSelector(archive, cwd)); return true; } catch { return false; } }\nfunction appendReadSelectors(pathValue: string, selector: ReadLineSelector): string {\n\tconst range = selector.ranges?.map((item) => item.end === undefined ? `${item.start}` : `${item.start}-${item.end}`).join(\",\") ?? (selector.offset ? `${selector.offset}` : \"\");\n\treturn `${pathValue}${range ? `:${range}` : \"\"}${selector.conflicts ? \":conflicts\" : \"\"}${selector.raw ? \":raw\" : \"\"}`;\n}\nexport function createReadToolDefinition(cwd: string, options?: ReadToolOptions): ToolDefinition<typeof readSchema, ReadToolDetails | undefined> {\n\tconst autoResizeImages = options?.autoResizeImages ?? true;\n\tconst ops = options?.operations ?? defaultReadOperations;\n\tconst hashlineStore = options?.hashlineStore ?? createHashlineSnapshotStore();\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: \"Read files, directories, archives, SQLite databases, internal resources, images, documents, and URLs through one path string.\",\n\t\tpromptSnippet: \"Read a path selector.\",\n\t\tpromptGuidelines: [\"Use read to inspect file and resource contents; use path selectors for line ranges, raw output, and conflict views.\"],\n\t\tparameters: readSchema,\n\t\tmaxResultSizeChars: Infinity,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path }: ReadToolInput,\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\tctx?,\n\t\t) {\n\t\t\tconst resourceCtx = ctx as InternalResourceContext | undefined;\n\t\t\tconst splitSelector = splitReadLineSelector(path), markerless = path.replace(/:raw(?=(:|$))/g, \"\").replace(/:conflicts(?=(:|$))/g, \"\"), sqliteOriginal = sqliteSelectorForPath(markerless, cwd), sqliteDirect = sqliteSelectorForPath(path, cwd);\n\t\t\tconst selector = archiveSelectorMemberExists(path, cwd) ? { path } : sqliteDirect && (sqliteDirect.table === \"raw\" || sqliteDirect.table === \"conflicts\") ? { path } : sqliteOriginal?.rowId && splitSelector.path !== markerless ? { path: markerless, raw: splitSelector.raw, conflicts: splitSelector.conflicts } : sqliteOriginal && splitSelector.path === markerless && markerless !== path ? { path: markerless, raw: splitSelector.raw, conflicts: splitSelector.conflicts } : splitSelector.path === path && sqliteDirect ? { path } : splitSelector;\n\t\t\tconst effectivePath = selector.path;\n\t\t\tconst effectiveOffset = selector.offset;\n\t\t\tconst effectiveLimit = selector.limit;\n\t\t\tconst effectiveRanges = selector.ranges;\n\t\t\tconst rawOutput = selector.raw;\n\t\t\tconst conflictsOnly = selector.conflicts;\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\t\t\t\t\t(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst archive = parseArchiveSelector(effectivePath);\n\t\t\t\t\t\t\tconst sqlite = sqliteSelectorForPath(effectivePath, cwd);\n\t\t\t\t\t\t\tif (isReadableUrlPath(effectivePath)) {\n\t\t\t\t\t\t\t\tresolve(await readUrlBranch({ effectivePath, rawOutput: rawOutput === true, effectiveRanges, effectiveOffset, effectiveLimit, cwd, ctx, signal, maxChars: READ_TOOL_MAX_RESULT_CHARS, maxBytes: DEFAULT_MAX_BYTES, oversized: oversizedReadResult, sourceMeta: readSourceMeta }));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (sqlite) {\n\t\t\t\t\t\t\t\tconst textContent = readSqliteSelector(sqlite), selection = applyReadLineSelection(textContent.split(\"\\n\"), effectiveRanges, effectiveOffset, effectiveLimit, rawOutput), selectedText = selection.lines.join(\"\\n\");\n\t\t\t\t\t\t\t\tif ((effectiveRanges || effectiveOffset) && selection.lines.length === 0) { const requested = effectiveRanges?.[0]?.start ?? effectiveOffset ?? 1; resolve({ content: [{ type: \"text\", text: `Requested line ${requested} is beyond end of resource (${textContent.split(\"\\n\").length} lines total).` }], details: undefined }); return; }\n\t\t\t\t\t\t\t\tif (selectedText.length > READ_TOOL_MAX_RESULT_CHARS || Buffer.byteLength(selectedText, \"utf8\") > DEFAULT_MAX_BYTES) { resolve(oversizedReadResult({ blocked: true, path: effectivePath, chars: selectedText.length, maxChars: READ_TOOL_MAX_RESULT_CHARS, startLine: selection.firstLine, totalFileLines: textContent.split(\"\\n\").length, firstLineBytes: Buffer.byteLength(selection.lines[0] ?? \"\", \"utf8\"), byteGuidance: false })); return; }\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: selectedText }], details: readSourceMeta(effectivePath) }); return;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (archive) {\n\t\t\t\t\t\t\t\tconst resolvedArchive = resolveArchiveSelector(archive, cwd);\n\t\t\t\t\t\t\t\tconst textContent = readArchiveSelector(resolvedArchive);\n\t\t\t\t\t\t\t\tlet allLines = textContent.split(\"\\n\");\n\t\t\t\t\t\t\t\tif (conflictsOnly) {\n\t\t\t\t\t\t\t\t\tlet inConflict = false;\n\t\t\t\t\t\t\t\t\tconst conflictLines = allLines.filter((line) => { if (line.startsWith(\"<<<<<<<\")) inConflict = true; const keep = inConflict; if (line.startsWith(\">>>>>>>\")) inConflict = false; return keep; });\n\t\t\t\t\t\t\t\t\tif (conflictLines.length === 0) { resolve({ content: [{ type: \"text\", text: \"No conflict markers found\" }], details: undefined }); return; }\n\t\t\t\t\t\t\t\t\tallLines = conflictLines;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst rangeSelection = (rawOutput ? selectExactReadRanges : selectReadRanges)(allLines, effectiveRanges);\n\t\t\t\t\t\t\t\tconst startLine = rangeSelection ? rangeSelection.firstLine - 1 : effectiveOffset ? Math.max(0, effectiveOffset - 1) : 0;\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length || (effectiveRanges && rangeSelection?.selectedLines.length === 0)) {\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: `Requested line ${startLine + 1} is beyond end of resource (${allLines.length} lines total).` }], details: undefined });\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst endLine = effectiveLimit !== undefined ? Math.min(startLine + effectiveLimit, allLines.length) : allLines.length;\n\t\t\t\t\t\t\t\tconst selectedLines = rangeSelection?.selectedLines ?? allLines.slice(startLine, endLine);\n\t\t\t\t\t\t\t\tconst selectedText = selectedLines.join(\"\\n\");\n\t\t\t\t\t\t\t\tif (selectedText.length > READ_TOOL_MAX_RESULT_CHARS || Buffer.byteLength(selectedText, \"utf8\") > DEFAULT_MAX_BYTES) { resolve(oversizedReadResult({ blocked: true, path: `${resolvedArchive.archivePath}:${resolvedArchive.memberPath}`, chars: selectedText.length, maxChars: READ_TOOL_MAX_RESULT_CHARS, startLine: startLine + 1, totalFileLines: allLines.length, firstLineBytes: Buffer.byteLength(selectedLines[0] ?? \"\", \"utf8\"), byteGuidance: false })); return; }\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: selectedText }], details: readSourceMeta(`${resolvedArchive.archivePath}:${resolvedArchive.memberPath}`) });\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (/^(?:skill|agent|artifact|history|issue|local|memory|pr|conflict|omp|rule|mcp|vault):\\/\\//.test(effectivePath)) {\n\t\t\t\t\t\t\t\tconst sourcePath = effectivePath.startsWith(\"local://\") ? resolveInternalSelector(effectivePath, cwd) : undefined;\n\t\t\t\t\t\t\t\tif (sourcePath) { resolve(await createReadToolDefinition(cwd, options).execute(_toolCallId, { path: appendReadSelectors(sourcePath, selector) }, signal, _onUpdate, ctx as never)); return; }\n\t\t\t\t\t\t\t\tconst allLines = (await readInternalSelector(effectivePath, cwd, resourceCtx)).split(\"\\n\");\n\t\t\t\t\t\t\t\tconst rangeSelection = (rawOutput ? selectExactReadRanges : selectReadRanges)(allLines, effectiveRanges);\n\t\t\t\t\t\t\t\tconst startLine = rangeSelection ? rangeSelection.firstLine - 1 : effectiveOffset ? Math.max(0, effectiveOffset - 1) : 0;\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length || (effectiveRanges && rangeSelection?.selectedLines.length === 0)) {\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: `Requested line ${startLine + 1} is beyond end of resource (${allLines.length} lines total).` }], details: undefined });\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst endLine = effectiveLimit !== undefined ? Math.min(startLine + effectiveLimit, allLines.length) : allLines.length;\n\t\t\t\t\t\t\t\tconst selectedLines = rangeSelection?.selectedLines ?? allLines.slice(startLine, endLine);\n\t\t\t\t\t\t\t\tconst selectedText = selectedLines.join(\"\\n\");\n\t\t\t\t\t\t\t\tif (selectedText.length > READ_TOOL_MAX_RESULT_CHARS || Buffer.byteLength(selectedText, \"utf8\") > DEFAULT_MAX_BYTES) { resolve(oversizedReadResult({ blocked: true, path: effectivePath, chars: selectedText.length, maxChars: READ_TOOL_MAX_RESULT_CHARS, startLine: startLine + 1, totalFileLines: allLines.length, firstLineBytes: Buffer.byteLength(selectedLines[0] ?? \"\", \"utf8\"), byteGuidance: false })); return; }\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: selectedText }], details: readSourceMeta(effectivePath) });\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (isReadResourceSelector(effectivePath)) throw new Error(`Read resource selectors are not supported by this filesystem backend: ${path}`);\n\t\t\t\t\t\t\tconst absolutePath = await resolveReadPathAsync(effectivePath, cwd);\n\t\t\t\t\t\t\tif (aborted) return;\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\tawait ops.access(absolutePath);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tif (isDocumentPath(absolutePath) && !rawOutput && !isNotebookPath(absolutePath)) {\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst textContent = await extractDocumentMarkdown(buffer, absolutePath);\n\t\t\t\t\t\t\t\tconst selection = applyReadLineSelection(textContent.split(\"\\n\"), effectiveRanges, effectiveOffset, effectiveLimit, rawOutput);\n\t\t\t\t\t\t\t\tif (selection.lines.length === 0) { resolve({ content: [{ type: \"text\", text: `Requested line ${selection.firstLine} is beyond end of document (${textContent.split(\"\\n\").length} lines total).` }], details: undefined }); return; }\n\t\t\t\t\t\t\t\tconst selectedText = selection.lines.join(\"\\n\");\n\t\t\t\t\t\t\tif (selectedText.length > READ_TOOL_MAX_RESULT_CHARS || Buffer.byteLength(selectedText, \"utf8\") > DEFAULT_MAX_BYTES) { resolve(oversizedReadResult({ blocked: true, path: absolutePath, chars: selectedText.length, maxChars: READ_TOOL_MAX_RESULT_CHARS, startLine: selection.firstLine, totalFileLines: textContent.split(\"\\n\").length, firstLineBytes: Buffer.byteLength(selection.lines[0] ?? \"\", \"utf8\"), byteGuidance: false })); return; }\n\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: selectedText }]; resolve({ content, details: readSourceMeta(absolutePath) }); return;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!options?.operations && (await fsStat(absolutePath)).isDirectory()) {\n\t\t\t\t\t\t\t\tconst tree = await buildDirectoryTree(absolutePath, { maxDepth: 2, perDirLimit: 12, rootLimit: null });\n\t\t\t\t\t\t\t\tconst allLines = tree.rendered.split(\"\\n\"), rangeSelection = (rawOutput ? selectExactReadRanges : selectReadRanges)(allLines, effectiveRanges), startLine = rangeSelection ? rangeSelection.firstLine - 1 : effectiveOffset ? Math.max(0, effectiveOffset - 1) : 0;\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length || (effectiveRanges && rangeSelection?.selectedLines.length === 0)) { resolve({ content: [{ type: \"text\", text: `Requested line ${startLine + 1} is beyond end of directory (${allLines.length} lines total).` }], details: undefined }); return; }\n\t\t\t\t\t\t\t\tconst endLine = effectiveLimit !== undefined ? Math.min(startLine + effectiveLimit, allLines.length) : allLines.length, selectedLines = rangeSelection?.selectedLines ?? allLines.slice(startLine, endLine);\n\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: selectedLines.join(\"\\n\") }];\n\t\t\t\t\t\t\t\tconst meta = { ...readSourceMeta(absolutePath).meta, ...(tree.truncated ? { limits: { perDirLimit: 12, totalLines: tree.totalLines } } : {}) };\n\t\t\t\t\t\t\t\tresolve({ content, details: { isDirectory: true, resolvedPath: absolutePath, meta } });\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : 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\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst textContent = (isNotebookPath(absolutePath) && !rawOutput) ? readEditableNotebookText(absolutePath, effectivePath) : buffer.toString(\"utf-8\");\n\t\t\t\t\t\t\t\tlet allLines = textContent.split(\"\\n\");\n\t\t\t\t\t\t\t\tlet conflictLineNumbers: number[] | undefined;\n\t\t\t\t\t\t\t\tif (conflictsOnly) {\n\t\t\t\t\t\t\t\t\tregisterConflictBlocks(cwd, parseConflictBlocks(absolutePath, textContent));\n\t\t\t\t\t\t\t\t\tconst conflictLines: string[] = [];\n\t\t\t\t\t\t\t\t\tconflictLineNumbers = [];\n\t\t\t\t\t\t\t\t\tlet inConflict = false;\n\t\t\t\t\t\t\t\t\tallLines.forEach((line, index) => {\n\t\t\t\t\t\t\t\t\t\tif (line.startsWith(\"<<<<<<<\")) inConflict = true;\n\t\t\t\t\t\t\t\t\t\tif (inConflict) { conflictLines.push(line); conflictLineNumbers!.push(index + 1); }\n\t\t\t\t\t\t\t\t\t\tif (line.startsWith(\">>>>>>>\")) inConflict = false;\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\tif (conflictLines.length > 0) allLines = conflictLines;\n\t\t\t\t\t\t\t\t\telse { signal?.removeEventListener(\"abort\", onAbort); resolve({ content: [{ type: \"text\", text: \"No conflict markers found\" }], details: undefined }); return; }\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\n\t\t\t\t\t\t\t\tconst rangeSelection = (rawOutput ? selectExactReadRanges : selectReadRanges)(allLines, effectiveRanges);\n\t\t\t\t\t\t\t\tconst startLine = rangeSelection ? rangeSelection.firstLine - 1 : effectiveOffset ? Math.max(0, effectiveOffset - 1) : 0;\n\t\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1;\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length || (effectiveRanges && rangeSelection?.selectedLines.length === 0)) {\n\t\t\t\t\t\t\t\t\tconst requested = effectiveRanges?.[0]?.start ?? startLineDisplay;\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: `Requested line ${requested} is beyond end of file (${allLines.length} lines total). Use ${effectivePath}:${Math.max(1, allLines.length)} to read the final line.` }], details: undefined });\n\t\t\t\t\t\t\t\t\treturn;\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 selectedLines: string[];\n\t\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\n\t\t\t\t\t\t\t\tif (rangeSelection) {\n\t\t\t\t\t\t\t\t\tselectedLines = rangeSelection.selectedLines;\n\t\t\t\t\t\t\t\t\tselectedContent = rangeSelection.selectedContent;\n\t\t\t\t\t\t\t\t\tuserLimitedLines = rangeSelection.userLimitedLines;\n\t\t\t\t\t\t\t\t} else if (effectiveLimit !== undefined) {\n\t\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + effectiveLimit, allLines.length);\n\t\t\t\t\t\t\t\t\tselectedLines = allLines.slice(startLine, endLine);\n\t\t\t\t\t\t\t\t\tselectedContent = selectedLines.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\tselectedLines = allLines.slice(startLine);\n\t\t\t\t\t\t\t\t\tselectedContent = selectedLines.join(\"\\n\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (selectedContent.length > READ_TOOL_MAX_RESULT_CHARS) {\n\t\t\t\t\t\t\t\t\tconst firstSelectedLine = allLines[startLine] ?? \"\";\n\t\t\t\t\t\t\t\t\tconst firstLineBytes = Buffer.byteLength(firstSelectedLine, \"utf-8\");\n\t\t\t\t\t\t\t\t\tconst selectedLineCount = trimTrailingEmptyLines(selectedLines).length;\n\t\t\t\t\t\t\t\t\tconst byteGuidance = selectedLineCount <= 1 || firstLineBytes > DEFAULT_MAX_BYTES;\n\t\t\t\t\t\t\t\t\tconst oversizedRead: OversizedReadDetails = { blocked: true, path: absolutePath, chars: selectedContent.length, maxChars: READ_TOOL_MAX_RESULT_CHARS, startLine: startLineDisplay, ...(effectiveLimit !== undefined ? { requestedLimit: effectiveLimit } : {}), totalFileLines, firstLineBytes, byteGuidance };\n\t\t\t\t\t\t\t\tdetails = { oversizedRead, meta: readSourceMeta(absolutePath).meta };\n\t\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: buildOversizedReadMessage(oversizedRead) }];\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\n\t\t\t\t\t\t\t\t\tlet outputText = truncation.content;\n\t\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\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\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${effectivePath} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\t\t\tdetails = { truncation, meta: { source: absolutePath, sourcePath: absolutePath, truncation } };\n\t\t\t\t\t\t\t\t\t} else if (truncation.truncated) {\n\t\t\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\t\t\t\t\t\t\t\t\t\toutputText += truncation.truncatedBy === \"lines\" ? `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Continue with path selector :${nextOffset}.]` : `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Continue with path selector :${nextOffset}.]`;\n\t\t\t\t\t\tdetails = { truncation, meta: { source: absolutePath, sourcePath: absolutePath, truncation } };\n\t\t\t\t\t\t\t\t\t} else if (!rawOutput && userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\t\t\t\t\t\t\t\t\t\toutputText = `${truncation.content}\\n\\n[${remaining} more lines in file. Continue with path selector :${nextOffset}.]`;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) content = [{ type: \"text\", text: outputText }];\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tconst snapshot = recordHashlineSnapshot(absolutePath, cwd, textContent, hashlineStore);\n\t\t\t\t\t\t\t\t\t\tconst visibleContent = truncation.truncated ? truncation.content : selectedContent;\n\t\t\t\t\t\t\t\t\t\tconst header = `[${snapshot.displayPath}#${snapshot.tag}]`;\n\t\t\t\t\t\t\t\t\t\tconst selectedConflictLineNumbers = conflictLineNumbers && rangeSelection?.lineNumbers ? rangeSelection.lineNumbers.map((line) => conflictLineNumbers![line - 1]).filter((line): line is number => typeof line === \"number\") : conflictLineNumbers ? conflictLineNumbers.slice(startLine, startLine + selectedLines.length) : undefined;\n\t\t\t\t\t\t\t\t\t\tlet hashlineOutput = rawOutput ? visibleContent : selectedConflictLineNumbers && visibleContent === selectedContent ? formatHashlineSelectedLines(header, selectedLines, selectedConflictLineNumbers) : rangeSelection && visibleContent === selectedContent ? formatHashlineSelectedLines(header, selectedLines, rangeSelection.lineNumbers) : formatHashlineContent(snapshot, visibleContent, startLineDisplay);\n\t\t\t\t\t\t\t\t\t\tif (outputText.startsWith(truncation.content) && outputText.length > truncation.content.length) hashlineOutput += outputText.slice(truncation.content.length);\n\t\t\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: hashlineOutput }];\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\tif (aborted) return;\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\tresolve({ content, details: details ?? readSourceMeta(absolutePath) });\n\t\t\t\t\t\t} catch (error: unknown) {\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 ? formatCompactReadCall(classification, args, theme) : formatReadCall(args, theme),\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}\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;AAa5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAA8E,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAMvI,OAAO,EAAoD,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AACtH,QAAA,MAAM,UAAU;;EAEmB,CAAC;AACpC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,eAAe;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,gBAAgB,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;CACrI;AAMD,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CACnF;AAMD,MAAM,WAAW,eAAe;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,aAAa,CAAC,EAAE,qBAAqB,CAAC;CACtC;AAwJD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAsP/I;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG"}
@@ -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,8BAA8B,CAAC;AAE9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAKzE,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,cAAc,CAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,EAAE;IAAE,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,EACzD,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,MAAM,CAKR;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;IAAE,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GAAG,MAAM,CAEhG","sourcesContent":["import * as os from \"node:os\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai/compat\";\nimport { getCapabilities, getImageDimensions, hyperlink, imageFallback } from \"@earendil-works/pi-tui\";\nimport type { ThemeColor } 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 renderToolPath(\n\trawPath: string | null,\n\ttheme: { fg: (name: ThemeColor, text: string) => string },\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\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: { fg: (name: ThemeColor, text: string) => string }): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\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,8BAA8B,CAAC;AAE9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAKzE,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,cAAc,CAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,EAAE;IAAE,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,EACzD,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,MAAM,CAKR;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;IAAE,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GAAG,MAAM,CAEhG"}