@kolisachint/hoocode-agent 0.4.106 → 0.4.108

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 (305) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/cli/args.d.ts.map +1 -1
  3. package/dist/cli/args.js +4 -4
  4. package/dist/cli/args.js.map +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +0 -1
  7. package/dist/cli.js.map +1 -1
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +2 -2
  10. package/dist/config.js.map +1 -1
  11. package/dist/core/agent-session.d.ts +1 -3
  12. package/dist/core/agent-session.d.ts.map +1 -1
  13. package/dist/core/agent-session.js +2 -2
  14. package/dist/core/agent-session.js.map +1 -1
  15. package/dist/core/bash-executor.d.ts.map +1 -1
  16. package/dist/core/bash-executor.js +1 -1
  17. package/dist/core/bash-executor.js.map +1 -1
  18. package/dist/core/extension-mcp-servers.d.ts +1 -1
  19. package/dist/core/extension-mcp-servers.d.ts.map +1 -1
  20. package/dist/core/extension-mcp-servers.js +1 -1
  21. package/dist/core/extension-mcp-servers.js.map +1 -1
  22. package/dist/core/extensions/plugins/index.d.ts.map +1 -1
  23. package/dist/core/extensions/plugins/index.js +1 -1
  24. package/dist/core/extensions/plugins/index.js.map +1 -1
  25. package/dist/core/extensions/types.d.ts +1 -3
  26. package/dist/core/extensions/types.d.ts.map +1 -1
  27. package/dist/core/extensions/types.js.map +1 -1
  28. package/dist/core/index.d.ts +1 -1
  29. package/dist/core/index.d.ts.map +1 -1
  30. package/dist/core/index.js.map +1 -1
  31. package/dist/core/mode-prompts.d.ts +1 -1
  32. package/dist/core/mode-prompts.d.ts.map +1 -1
  33. package/dist/core/mode-prompts.js +1 -1
  34. package/dist/core/mode-prompts.js.map +1 -1
  35. package/dist/core/package-manager.d.ts.map +1 -1
  36. package/dist/core/package-manager.js +1 -1
  37. package/dist/core/package-manager.js.map +1 -1
  38. package/dist/core/sdk.d.ts.map +1 -1
  39. package/dist/core/sdk.js +1 -2
  40. package/dist/core/sdk.js.map +1 -1
  41. package/dist/core/session-manager.d.ts +2 -97
  42. package/dist/core/session-manager.d.ts.map +1 -1
  43. package/dist/core/session-manager.js +4 -65
  44. package/dist/core/session-manager.js.map +1 -1
  45. package/dist/core/settings-manager.d.ts.map +1 -1
  46. package/dist/core/settings-manager.js +2 -3
  47. package/dist/core/settings-manager.js.map +1 -1
  48. package/dist/core/telemetry.d.ts.map +1 -1
  49. package/dist/core/telemetry.js +1 -1
  50. package/dist/core/telemetry.js.map +1 -1
  51. package/dist/core/timings.d.ts +1 -1
  52. package/dist/core/timings.d.ts.map +1 -1
  53. package/dist/core/timings.js +2 -2
  54. package/dist/core/timings.js.map +1 -1
  55. package/dist/core/tools/{browser-continue.d.ts → browser/browser-continue.d.ts} +1 -1
  56. package/dist/core/tools/browser/browser-continue.d.ts.map +1 -0
  57. package/dist/core/tools/{browser-continue.js → browser/browser-continue.js} +2 -2
  58. package/dist/core/tools/browser/browser-continue.js.map +1 -0
  59. package/dist/core/tools/{browser-run.d.ts → browser/browser-run.d.ts} +2 -2
  60. package/dist/core/tools/browser/browser-run.d.ts.map +1 -0
  61. package/dist/core/tools/{browser-run.js → browser/browser-run.js} +2 -2
  62. package/dist/core/tools/browser/browser-run.js.map +1 -0
  63. package/dist/core/tools/browser/browsertools-shared.d.ts.map +1 -0
  64. package/dist/core/tools/{browsertools-shared.js → browser/browsertools-shared.js} +1 -1
  65. package/dist/core/tools/browser/browsertools-shared.js.map +1 -0
  66. package/dist/core/tools/browser/index.d.ts +8 -0
  67. package/dist/core/tools/browser/index.d.ts.map +1 -0
  68. package/dist/core/tools/browser/index.js +8 -0
  69. package/dist/core/tools/browser/index.js.map +1 -0
  70. package/dist/core/tools/{docedit.d.ts → doc/docedit.d.ts} +2 -2
  71. package/dist/core/tools/doc/docedit.d.ts.map +1 -0
  72. package/dist/core/tools/{docedit.js → doc/docedit.js} +7 -7
  73. package/dist/core/tools/doc/docedit.js.map +1 -0
  74. package/dist/core/tools/{docgrep.d.ts → doc/docgrep.d.ts} +2 -2
  75. package/dist/core/tools/doc/docgrep.d.ts.map +1 -0
  76. package/dist/core/tools/{docgrep.js → doc/docgrep.js} +6 -6
  77. package/dist/core/tools/doc/docgrep.js.map +1 -0
  78. package/dist/core/tools/{docpeek.d.ts → doc/docpeek.d.ts} +2 -2
  79. package/dist/core/tools/{docpeek.js.map → doc/docpeek.d.ts.map} +1 -1
  80. package/dist/core/tools/{docpeek.js → doc/docpeek.js} +6 -6
  81. package/dist/core/tools/doc/docpeek.js.map +1 -0
  82. package/dist/core/tools/{docread.d.ts → doc/docread.d.ts} +2 -2
  83. package/dist/core/tools/doc/docread.d.ts.map +1 -0
  84. package/dist/core/tools/{docread.js → doc/docread.js} +6 -6
  85. package/dist/core/tools/doc/docread.js.map +1 -0
  86. package/dist/core/tools/{docscan.d.ts → doc/docscan.d.ts} +2 -2
  87. package/dist/core/tools/doc/docscan.d.ts.map +1 -0
  88. package/dist/core/tools/{docscan.js → doc/docscan.js} +6 -6
  89. package/dist/core/tools/doc/docscan.js.map +1 -0
  90. package/dist/core/tools/{docwrite.d.ts → doc/docwrite.d.ts} +1 -1
  91. package/dist/core/tools/doc/docwrite.d.ts.map +1 -0
  92. package/dist/core/tools/{docwrite.js → doc/docwrite.js} +6 -6
  93. package/dist/core/tools/doc/docwrite.js.map +1 -0
  94. package/dist/core/tools/doc/index.d.ts +11 -0
  95. package/dist/core/tools/doc/index.d.ts.map +1 -0
  96. package/dist/core/tools/doc/index.js +11 -0
  97. package/dist/core/tools/doc/index.js.map +1 -0
  98. package/dist/core/tools/grep.d.ts.map +1 -1
  99. package/dist/core/tools/grep.js +1 -1
  100. package/dist/core/tools/grep.js.map +1 -1
  101. package/dist/core/tools/index.d.ts +42 -28
  102. package/dist/core/tools/index.d.ts.map +1 -1
  103. package/dist/core/tools/index.js +61 -199
  104. package/dist/core/tools/index.js.map +1 -1
  105. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  106. package/dist/core/tools/output-accumulator.js +1 -1
  107. package/dist/core/tools/output-accumulator.js.map +1 -1
  108. package/dist/core/tools/read.d.ts.map +1 -1
  109. package/dist/core/tools/read.js +1 -1
  110. package/dist/core/tools/read.js.map +1 -1
  111. package/dist/extensions/core/ask-options.d.ts +10 -0
  112. package/dist/extensions/core/ask-options.d.ts.map +1 -0
  113. package/dist/extensions/core/ask-options.js +83 -0
  114. package/dist/extensions/core/ask-options.js.map +1 -0
  115. package/dist/extensions/core/config.d.ts +80 -0
  116. package/dist/extensions/core/config.d.ts.map +1 -0
  117. package/dist/extensions/core/config.js +110 -0
  118. package/dist/extensions/core/config.js.map +1 -0
  119. package/dist/extensions/core/cost.d.ts +11 -0
  120. package/dist/extensions/core/cost.d.ts.map +1 -0
  121. package/dist/extensions/core/cost.js +64 -0
  122. package/dist/extensions/core/cost.js.map +1 -0
  123. package/dist/extensions/core/hoo-core.d.ts +16 -179
  124. package/dist/extensions/core/hoo-core.d.ts.map +1 -1
  125. package/dist/extensions/core/hoo-core.js +27 -1663
  126. package/dist/extensions/core/hoo-core.js.map +1 -1
  127. package/dist/extensions/core/loop.d.ts +15 -0
  128. package/dist/extensions/core/loop.d.ts.map +1 -0
  129. package/dist/extensions/core/loop.js +235 -0
  130. package/dist/extensions/core/loop.js.map +1 -0
  131. package/dist/extensions/core/marketplace.d.ts +17 -0
  132. package/dist/extensions/core/marketplace.d.ts.map +1 -0
  133. package/dist/extensions/core/marketplace.js +167 -0
  134. package/dist/extensions/core/marketplace.js.map +1 -0
  135. package/dist/extensions/core/mcp-loader.d.ts +26 -0
  136. package/dist/extensions/core/mcp-loader.d.ts.map +1 -0
  137. package/dist/extensions/core/mcp-loader.js +391 -0
  138. package/dist/extensions/core/mcp-loader.js.map +1 -0
  139. package/dist/extensions/core/modes.d.ts +56 -0
  140. package/dist/extensions/core/modes.d.ts.map +1 -0
  141. package/dist/extensions/core/modes.js +268 -0
  142. package/dist/extensions/core/modes.js.map +1 -0
  143. package/dist/extensions/core/permission-gate.d.ts +10 -0
  144. package/dist/extensions/core/permission-gate.d.ts.map +1 -0
  145. package/dist/extensions/core/permission-gate.js +167 -0
  146. package/dist/extensions/core/permission-gate.js.map +1 -0
  147. package/dist/extensions/core/scaffold.d.ts +9 -0
  148. package/dist/extensions/core/scaffold.d.ts.map +1 -0
  149. package/dist/extensions/core/scaffold.js +146 -0
  150. package/dist/extensions/core/scaffold.js.map +1 -0
  151. package/dist/extensions/core/thinking-escalation.d.ts +18 -0
  152. package/dist/extensions/core/thinking-escalation.d.ts.map +1 -0
  153. package/dist/extensions/core/thinking-escalation.js +70 -0
  154. package/dist/extensions/core/thinking-escalation.js.map +1 -0
  155. package/dist/index.d.ts +2 -3
  156. package/dist/index.d.ts.map +1 -1
  157. package/dist/index.js +3 -4
  158. package/dist/index.js.map +1 -1
  159. package/dist/main.d.ts.map +1 -1
  160. package/dist/main.js +2 -2
  161. package/dist/main.js.map +1 -1
  162. package/dist/modes/interactive/bash-execution-controller.d.ts +34 -0
  163. package/dist/modes/interactive/bash-execution-controller.d.ts.map +1 -0
  164. package/dist/modes/interactive/bash-execution-controller.js +98 -0
  165. package/dist/modes/interactive/bash-execution-controller.js.map +1 -0
  166. package/dist/modes/interactive/command-executor.d.ts +0 -5
  167. package/dist/modes/interactive/command-executor.d.ts.map +1 -1
  168. package/dist/modes/interactive/command-executor.js +0 -7
  169. package/dist/modes/interactive/command-executor.js.map +1 -1
  170. package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
  171. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  172. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  173. package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
  174. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  175. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  176. package/dist/modes/interactive/components/custom-message.d.ts +1 -1
  177. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  178. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  179. package/dist/modes/interactive/components/index.d.ts +0 -2
  180. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  181. package/dist/modes/interactive/components/index.js +0 -2
  182. package/dist/modes/interactive/components/index.js.map +1 -1
  183. package/dist/modes/interactive/extension-chrome.d.ts +56 -0
  184. package/dist/modes/interactive/extension-chrome.d.ts.map +1 -0
  185. package/dist/modes/interactive/extension-chrome.js +172 -0
  186. package/dist/modes/interactive/extension-chrome.js.map +1 -0
  187. package/dist/modes/interactive/extension-dialogs.d.ts +82 -0
  188. package/dist/modes/interactive/extension-dialogs.d.ts.map +1 -0
  189. package/dist/modes/interactive/extension-dialogs.js +259 -0
  190. package/dist/modes/interactive/extension-dialogs.js.map +1 -0
  191. package/dist/modes/interactive/interactive-mode.d.ts +16 -206
  192. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  193. package/dist/modes/interactive/interactive-mode.js +359 -2370
  194. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  195. package/dist/modes/interactive/login-controller.d.ts +50 -0
  196. package/dist/modes/interactive/login-controller.d.ts.map +1 -0
  197. package/dist/modes/interactive/login-controller.js +352 -0
  198. package/dist/modes/interactive/login-controller.js.map +1 -0
  199. package/dist/modes/interactive/message-queue-controller.d.ts +49 -0
  200. package/dist/modes/interactive/message-queue-controller.d.ts.map +1 -0
  201. package/dist/modes/interactive/message-queue-controller.js +184 -0
  202. package/dist/modes/interactive/message-queue-controller.js.map +1 -0
  203. package/dist/modes/interactive/model-controller.d.ts +43 -0
  204. package/dist/modes/interactive/model-controller.d.ts.map +1 -0
  205. package/dist/modes/interactive/model-controller.js +184 -0
  206. package/dist/modes/interactive/model-controller.js.map +1 -0
  207. package/dist/modes/interactive/resource-display.d.ts +59 -0
  208. package/dist/modes/interactive/resource-display.d.ts.map +1 -0
  209. package/dist/modes/interactive/resource-display.js +499 -0
  210. package/dist/modes/interactive/resource-display.js.map +1 -0
  211. package/dist/modes/interactive/startup-checks.d.ts +17 -0
  212. package/dist/modes/interactive/startup-checks.d.ts.map +1 -0
  213. package/dist/modes/interactive/startup-checks.js +102 -0
  214. package/dist/modes/interactive/startup-checks.js.map +1 -0
  215. package/dist/modes/interactive/team-focus.d.ts +56 -0
  216. package/dist/modes/interactive/team-focus.d.ts.map +1 -0
  217. package/dist/modes/interactive/team-focus.js +167 -0
  218. package/dist/modes/interactive/team-focus.js.map +1 -0
  219. package/dist/modes/interactive/voice/voice-controller.d.ts +66 -0
  220. package/dist/modes/interactive/voice/voice-controller.d.ts.map +1 -0
  221. package/dist/modes/interactive/voice/voice-controller.js +312 -0
  222. package/dist/modes/interactive/voice/voice-controller.js.map +1 -0
  223. package/dist/modes/interactive/voice/voice-panel.d.ts.map +1 -0
  224. package/dist/modes/interactive/voice/voice-panel.js.map +1 -0
  225. package/dist/modes/interactive/voice/voice-transcribe.d.ts.map +1 -0
  226. package/dist/modes/interactive/voice/voice-transcribe.js.map +1 -0
  227. package/dist/modes/rpc/rpc-client.d.ts +1 -2
  228. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  229. package/dist/modes/rpc/rpc-client.js.map +1 -1
  230. package/dist/modes/rpc/rpc-types.d.ts +1 -2
  231. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  232. package/dist/modes/rpc/rpc-types.js.map +1 -1
  233. package/dist/resources-cli.d.ts.map +1 -1
  234. package/dist/resources-cli.js +1 -1
  235. package/dist/resources-cli.js.map +1 -1
  236. package/dist/utils/tools-manager.d.ts.map +1 -1
  237. package/dist/utils/tools-manager.js +1 -1
  238. package/dist/utils/tools-manager.js.map +1 -1
  239. package/dist/utils/version-check.d.ts.map +1 -1
  240. package/dist/utils/version-check.js +2 -2
  241. package/dist/utils/version-check.js.map +1 -1
  242. package/docs/project-local-resources.md +1 -1
  243. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  244. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  245. package/examples/extensions/sandbox/package.json +1 -1
  246. package/examples/extensions/with-deps/package.json +1 -1
  247. package/package.json +4 -4
  248. package/dist/core/compaction/branch-summarization.d.ts +0 -88
  249. package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
  250. package/dist/core/compaction/branch-summarization.js +0 -243
  251. package/dist/core/compaction/branch-summarization.js.map +0 -1
  252. package/dist/core/compaction/compaction.d.ts +0 -123
  253. package/dist/core/compaction/compaction.d.ts.map +0 -1
  254. package/dist/core/compaction/compaction.js +0 -635
  255. package/dist/core/compaction/compaction.js.map +0 -1
  256. package/dist/core/compaction/index.d.ts +0 -7
  257. package/dist/core/compaction/index.d.ts.map +0 -1
  258. package/dist/core/compaction/index.js +0 -7
  259. package/dist/core/compaction/index.js.map +0 -1
  260. package/dist/core/compaction/utils.d.ts +0 -38
  261. package/dist/core/compaction/utils.d.ts.map +0 -1
  262. package/dist/core/compaction/utils.js +0 -156
  263. package/dist/core/compaction/utils.js.map +0 -1
  264. package/dist/core/messages.d.ts +0 -124
  265. package/dist/core/messages.d.ts.map +0 -1
  266. package/dist/core/messages.js +0 -221
  267. package/dist/core/messages.js.map +0 -1
  268. package/dist/core/tools/browser-continue.d.ts.map +0 -1
  269. package/dist/core/tools/browser-continue.js.map +0 -1
  270. package/dist/core/tools/browser-run.d.ts.map +0 -1
  271. package/dist/core/tools/browser-run.js.map +0 -1
  272. package/dist/core/tools/browsertools-shared.d.ts.map +0 -1
  273. package/dist/core/tools/browsertools-shared.js.map +0 -1
  274. package/dist/core/tools/docedit.d.ts.map +0 -1
  275. package/dist/core/tools/docedit.js.map +0 -1
  276. package/dist/core/tools/docgrep.d.ts.map +0 -1
  277. package/dist/core/tools/docgrep.js.map +0 -1
  278. package/dist/core/tools/docpeek.d.ts.map +0 -1
  279. package/dist/core/tools/docread.d.ts.map +0 -1
  280. package/dist/core/tools/docread.js.map +0 -1
  281. package/dist/core/tools/docscan.d.ts.map +0 -1
  282. package/dist/core/tools/docscan.js.map +0 -1
  283. package/dist/core/tools/docwrite.d.ts.map +0 -1
  284. package/dist/core/tools/docwrite.js.map +0 -1
  285. package/dist/core/tools/output-compression.d.ts +0 -53
  286. package/dist/core/tools/output-compression.d.ts.map +0 -1
  287. package/dist/core/tools/output-compression.js +0 -392
  288. package/dist/core/tools/output-compression.js.map +0 -1
  289. package/dist/modes/interactive/components/armin.d.ts +0 -34
  290. package/dist/modes/interactive/components/armin.d.ts.map +0 -1
  291. package/dist/modes/interactive/components/armin.js +0 -333
  292. package/dist/modes/interactive/components/armin.js.map +0 -1
  293. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  294. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  295. package/dist/modes/interactive/components/daxnuts.js +0 -140
  296. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  297. package/dist/modes/interactive/components/voice-panel.d.ts.map +0 -1
  298. package/dist/modes/interactive/components/voice-panel.js.map +0 -1
  299. package/dist/modes/interactive/voice-transcribe.d.ts.map +0 -1
  300. package/dist/modes/interactive/voice-transcribe.js.map +0 -1
  301. /package/dist/core/tools/{browsertools-shared.d.ts → browser/browsertools-shared.d.ts} +0 -0
  302. /package/dist/modes/interactive/{components → voice}/voice-panel.d.ts +0 -0
  303. /package/dist/modes/interactive/{components → voice}/voice-panel.js +0 -0
  304. /package/dist/modes/interactive/{voice-transcribe.d.ts → voice/voice-transcribe.d.ts} +0 -0
  305. /package/dist/modes/interactive/{voice-transcribe.js → voice/voice-transcribe.js} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"docedit.js","sourceRoot":"","sources":["../../../src/core/tools/docedit.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtempSync, renameSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Container, Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { APP_NAME } from \"../../config.js\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { renderEnvelopeText } from \"./docread.js\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nimport {\n\ttype DocNode,\n\tensureExtractRecord,\n\textractDocument,\n\tfindNodeById,\n\tinvalidateExtractRecord,\n\tpatchOpNodeId,\n\tpatchOpsSchema,\n\treconstructDocument,\n\tStalePatchError,\n\ttoPatch,\n} from \"./filetools-shared.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docEditSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to edit in place. Must have been opened with DocRead first.\",\n\t}),\n\tpatch: patchOpsSchema,\n});\n\nexport type DocEditToolInput = Static<typeof docEditSchema>;\n\nexport interface DocEditToolDetails {\n\tops?: number;\n\taffected?: DocNode[];\n}\n\nexport interface DocEditToolOptions {\n\t/** Timeout (seconds) for the filetools invocations. */\n\ttimeoutSecs?: number;\n}\n\nfunction formatDocEditCall(args: { path?: string; patch?: unknown[] } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocEdit \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst ops = Array.isArray(args?.patch) ? args.patch.length : undefined;\n\tif (ops !== undefined) text += appTheme.fg(\"muted\", ` (${ops} op${ops === 1 ? \"\" : \"s\"})`);\n\treturn text;\n}\n\nexport function createDocEditToolDefinition(\n\tcwd: string,\n\toptions?: DocEditToolOptions,\n): ToolDefinition<typeof docEditSchema, DocEditToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocEdit\",\n\t\tlabel: \"DocEdit\",\n\t\tdescription:\n\t\t\t\"Apply an id-based patch to a structured/binary document IN PLACE, losslessly. Targets node ids from a DocRead extract; if the cache is missing or the file changed on disk (e.g. an external script rewrote it) the document is re-extracted automatically, so a separate DocRead is not required. If the patch references ids that no longer exist, the call fails and returns the current structure with fresh ids so you can re-issue. Untouched bytes are preserved exactly; the file is re-extracted after the write so ids stay current for further edits. This is the canonical way to edit these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to rewrite them — that bypasses the lossless id-map and corrupts the file. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Patch a structured/binary document in place by node id\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocEdit to modify a document opened with DocRead; pass a patch of id-based ops (replace/add/remove) targeting the #ids from the extract. It edits in place and re-extracts.\",\n\t\t\t\"Keep patches minimal — only the ops you actually need. DocEdit re-extracts after writing and refreshes ids, so do not DocRead again between edits; the full extract is token-heavy. Reach for a fresh writable DocRead only when ids have gone stale and the failure output isn't enough to continue.\",\n\t\t],\n\t\tparameters: docEditSchema,\n\t\tasync execute(_toolCallId, { path, patch }: DocEditToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Resolve affected nodes from the pre-reconstruct extract: the patch's\n\t\t\t\t// ids are valid against THIS extract, and a later re-extract\n\t\t\t\t// regenerates ids that would not match the patch. reconstructDocument\n\t\t\t\t// auto-extracts when the cache is missing/stale, so capture the record\n\t\t\t\t// the same way to stay in sync with what the patch is applied against.\n\t\t\t\tconst preRecord = await ensureExtractRecord(absolutePath, cwd, signal, {\n\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t});\n\t\t\t\tconst affectedIds = new Set<string>();\n\t\t\t\tfor (const op of toPatch(patch).patch) {\n\t\t\t\t\tconst id = patchOpNodeId(op);\n\t\t\t\t\tif (id) affectedIds.add(id);\n\t\t\t\t}\n\t\t\t\tconst affectedNodes: DocNode[] = [];\n\t\t\t\tfor (const id of affectedIds) {\n\t\t\t\t\tconst node = findNodeById(preRecord.envelope.structure, id);\n\t\t\t\t\tif (node) affectedNodes.push(node);\n\t\t\t\t}\n\n\t\t\t\t// Reconstruct to a temp file, then atomically swap it into place so a\n\t\t\t\t// failed reconstruct never leaves a half-written document behind.\n\t\t\t\tconst stageDir = mkdtempSync(join(tmpdir(), `${APP_NAME}-docedit-`));\n\t\t\t\tconst stagePath = join(stageDir, basename(absolutePath));\n\t\t\t\ttry {\n\t\t\t\t\tawait reconstructDocument(absolutePath, toPatch(patch), stagePath, cwd, signal, {\n\t\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t\t});\n\t\t\t\t\trenameSync(stagePath, absolutePath);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof StalePatchError) {\n\t\t\t\t\t\t// The document was rewritten out-of-band: the cache auto-refreshed\n\t\t\t\t\t\t// but the patch targets ids that no longer exist. Surface the\n\t\t\t\t\t\t// current structure so the agent can re-issue without a DocRead.\n\t\t\t\t\t\tthrow new Error(`${err.message}\\n\\n${renderEnvelopeText(err.envelope, false)}`);\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t} finally {\n\t\t\t\t\trmSync(stageDir, { recursive: true, force: true });\n\t\t\t\t}\n\n\t\t\t\t// The source changed, so the cached id-map is stale. Re-extract to\n\t\t\t\t// refresh ids for subsequent edits (best-effort; a failure here does\n\t\t\t\t// not undo the successful write).\n\t\t\t\tinvalidateExtractRecord(absolutePath);\n\t\t\t\ttry {\n\t\t\t\t\tawait extractDocument(absolutePath, cwd, signal, { timeoutSecs: options?.timeoutSecs });\n\t\t\t\t} catch {\n\t\t\t\t\t// Re-extract failure leaves no cached record; the next DocEdit will\n\t\t\t\t\t// auto-extract (or fall back to DocRead), which is the correct path.\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `Applied ${patch.length} op${patch.length === 1 ? \"\" : \"s\"} to ${path} (re-extracted; ids refreshed).`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { ops: patch.length, affected: affectedNodes.length > 0 ? affectedNodes : undefined },\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(formatDocEditCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, _options, _theme, context) {\n\t\t\tif (!context.isError) {\n\t\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\t\tcomponent.clear();\n\t\t\t\treturn component;\n\t\t\t}\n\t\t\tconst output = (result.content as Array<{ type: string; text?: string }>)\n\t\t\t\t.filter((c) => c.type === \"text\")\n\t\t\t\t.map((c) => c.text || \"\")\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(output ? `\\n${appTheme.fg(\"error\", output)}` : \"\");\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocEditTool(cwd: string, options?: DocEditToolOptions): AgentTool<typeof docEditSchema> {\n\treturn wrapToolDefinition(createDocEditToolDefinition(cwd, options));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"docgrep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/docgrep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,KAAK,QAAQ,EAA6C,MAAM,uBAAuB,CAAC;AAKjG,QAAA,MAAM,aAAa;;;;;EAUjB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IAClC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAcrD;AAgCD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC1B,cAAc,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAsCtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport { type GrepView, grepDocument, truncateRenderToTokenBudget } from \"./filetools-shared.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docGrepSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to search (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\tpattern: Type.String({\n\t\tdescription: \"Literal substring to match per line (NOT a regex).\",\n\t}),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive matching. Default false.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Stop after N matches. Default: all matches.\" })),\n});\n\nexport type DocGrepToolInput = Static<typeof docGrepSchema>;\n\nexport interface DocGrepToolDetails {\n\tpattern?: string;\n\tmatches?: number;\n}\n\nexport interface DocGrepToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/**\n * Render grep matches as `#block_id:line :: \"snippet\"` lines. Each block id\n * feeds straight back into DocPeek (to hydrate) or a DocEdit patch.\n */\nexport function renderGrepView(view: GrepView): string {\n\tconst header = `grep ${JSON.stringify(view.pattern)} — ${view.returned} match${view.returned === 1 ? \"\" : \"es\"}`;\n\tif (view.matches.length === 0) return header;\n\tconst lines: string[] = [header, \"\"];\n\tfor (const m of view.matches) {\n\t\tconst flag = m.writable ? \"\" : \" (read-only)\";\n\t\tlines.push(`#${m.block_id}:${m.line}${flag} :: ${JSON.stringify(m.snippet)}`);\n\t}\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\treturn (\n\t\t`${text}\\n\\n[Truncated: ${droppedLines} more match line${droppedLines === 1 ? \"\" : \"s\"} omitted; ` +\n\t\t`re-run with a smaller limit or a more specific pattern.]`\n\t);\n}\n\nfunction formatDocGrepCall(args: { path?: string; pattern?: string; ignoreCase?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocGrep \"));\n\tconst pattern = str(args?.pattern);\n\tif (pattern) text += `${appTheme.fg(\"accent\", JSON.stringify(pattern))} ${appTheme.fg(\"muted\", \"in\")} `;\n\ttext += appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.ignoreCase) text += appTheme.fg(\"muted\", \" (i)\");\n\treturn text;\n}\n\nfunction formatDocGrepResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocGrepToolDefinition(\n\tcwd: string,\n\toptions?: DocGrepToolOptions,\n): ToolDefinition<typeof docGrepSchema, DocGrepToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocGrep\",\n\t\tlabel: \"DocGrep\",\n\t\tdescription:\n\t\t\t\"Locate blocks in a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) by literal text, WITHOUT hydrating the whole document. Returns each match as an editable el_ node #id, line number, and snippet. Those el_ #ids target a DocEdit/DocWrite patch directly — DocGrep is the fast path from 'find text' to 'edit it' (far cheaper than a full DocRead). Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Find blocks in a structured/binary document by literal text, without hydrating it\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocGrep to find where something is in a large structured/binary document instead of reading it all: it returns editable el_ node #ids + snippets for a literal substring match. Patch those el_ #ids straight with DocEdit/DocWrite.\",\n\t\t\t\"DocGrep's el_ #ids are the edit id-space; they are NOT DocPeek's structural-path ids. To read more context around a match, DocScan/DocPeek by structural path instead.\",\n\t\t\t\"pattern is a literal substring (not a regex); pass ignoreCase for case-insensitive matching.\",\n\t\t\t\"Works across all supported formats including spreadsheet cell values (xlsx) and slide text (pptx); patch a matched el_ #id with DocEdit, or read more context with DocPeek.\",\n\t\t],\n\t\tparameters: docGrepSchema,\n\t\tasync execute(_toolCallId, { path, pattern, ignoreCase, limit }: DocGrepToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await grepDocument(absolutePath, pattern, cwd, signal, {\n\t\t\t\tignoreCase,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderGrepView(view) }],\n\t\t\t\tdetails: { pattern: view.pattern, matches: view.returned },\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(formatDocGrepCall(args));\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(formatDocGrepResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocGrepTool(cwd: string, options?: DocGrepToolOptions): AgentTool<typeof docGrepSchema> {\n\treturn wrapToolDefinition(createDocGrepToolDefinition(cwd, options));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"docgrep.js","sourceRoot":"","sources":["../../../src/core/tools/docgrep.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport { type GrepView, grepDocument, truncateRenderToTokenBudget } from \"./filetools-shared.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docGrepSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to search (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\tpattern: Type.String({\n\t\tdescription: \"Literal substring to match per line (NOT a regex).\",\n\t}),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive matching. Default false.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Stop after N matches. Default: all matches.\" })),\n});\n\nexport type DocGrepToolInput = Static<typeof docGrepSchema>;\n\nexport interface DocGrepToolDetails {\n\tpattern?: string;\n\tmatches?: number;\n}\n\nexport interface DocGrepToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/**\n * Render grep matches as `#block_id:line :: \"snippet\"` lines. Each block id\n * feeds straight back into DocPeek (to hydrate) or a DocEdit patch.\n */\nexport function renderGrepView(view: GrepView): string {\n\tconst header = `grep ${JSON.stringify(view.pattern)} — ${view.returned} match${view.returned === 1 ? \"\" : \"es\"}`;\n\tif (view.matches.length === 0) return header;\n\tconst lines: string[] = [header, \"\"];\n\tfor (const m of view.matches) {\n\t\tconst flag = m.writable ? \"\" : \" (read-only)\";\n\t\tlines.push(`#${m.block_id}:${m.line}${flag} :: ${JSON.stringify(m.snippet)}`);\n\t}\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\treturn (\n\t\t`${text}\\n\\n[Truncated: ${droppedLines} more match line${droppedLines === 1 ? \"\" : \"s\"} omitted; ` +\n\t\t`re-run with a smaller limit or a more specific pattern.]`\n\t);\n}\n\nfunction formatDocGrepCall(args: { path?: string; pattern?: string; ignoreCase?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocGrep \"));\n\tconst pattern = str(args?.pattern);\n\tif (pattern) text += `${appTheme.fg(\"accent\", JSON.stringify(pattern))} ${appTheme.fg(\"muted\", \"in\")} `;\n\ttext += appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.ignoreCase) text += appTheme.fg(\"muted\", \" (i)\");\n\treturn text;\n}\n\nfunction formatDocGrepResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocGrepToolDefinition(\n\tcwd: string,\n\toptions?: DocGrepToolOptions,\n): ToolDefinition<typeof docGrepSchema, DocGrepToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocGrep\",\n\t\tlabel: \"DocGrep\",\n\t\tdescription:\n\t\t\t\"Locate blocks in a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) by literal text, WITHOUT hydrating the whole document. Returns each match as an editable el_ node #id, line number, and snippet. Those el_ #ids target a DocEdit/DocWrite patch directly — DocGrep is the fast path from 'find text' to 'edit it' (far cheaper than a full DocRead). Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Find blocks in a structured/binary document by literal text, without hydrating it\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocGrep to find where something is in a large structured/binary document instead of reading it all: it returns editable el_ node #ids + snippets for a literal substring match. Patch those el_ #ids straight with DocEdit/DocWrite.\",\n\t\t\t\"DocGrep's el_ #ids are the edit id-space; they are NOT DocPeek's structural-path ids. To read more context around a match, DocScan/DocPeek by structural path instead.\",\n\t\t\t\"pattern is a literal substring (not a regex); pass ignoreCase for case-insensitive matching.\",\n\t\t\t\"Works across all supported formats including spreadsheet cell values (xlsx) and slide text (pptx); patch a matched el_ #id with DocEdit, or read more context with DocPeek.\",\n\t\t],\n\t\tparameters: docGrepSchema,\n\t\tasync execute(_toolCallId, { path, pattern, ignoreCase, limit }: DocGrepToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await grepDocument(absolutePath, pattern, cwd, signal, {\n\t\t\t\tignoreCase,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderGrepView(view) }],\n\t\t\t\tdetails: { pattern: view.pattern, matches: view.returned },\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(formatDocGrepCall(args));\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(formatDocGrepResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocGrepTool(cwd: string, options?: DocGrepToolOptions): AgentTool<typeof docGrepSchema> {\n\treturn wrapToolDefinition(createDocGrepToolDefinition(cwd, options));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"docpeek.d.ts","sourceRoot":"","sources":["../../../src/core/tools/docpeek.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EACN,KAAK,QAAQ,EAIb,MAAM,uBAAuB,CAAC;AAK/B,QAAA,MAAM,aAAa;;;;;EAYjB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IAClC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAmBrD;AAuCD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC1B,cAAc,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAuCtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport {\n\ttype ReadView,\n\treadDocumentBlocks,\n\trenderDocNodeLines,\n\ttruncateRenderToTokenBudget,\n} from \"./filetools-shared.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docPeekSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to read (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\tid: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription:\n\t\t\t\t\"Block id(s) to hydrate — use the EXACT ids returned by a prior DocScan (e.g. 'node[title:0]', 'paragraph[3]', 'page[1]'); do NOT hand-construct sub-ranges (an invented 'rows[0-2]' returns nothing — pass the exact 'rows[0-99]' DocScan emitted). These are DocScan's path ids, not DocGrep's el_ node ids. Omit to read a paginated slice of all blocks.\",\n\t\t}),\n\t),\n\toffset: Type.Optional(Type.Number({ description: \"Pagination start when no ids are given. Default 0.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Pagination size when no ids are given. Default: all remaining.\" })),\n});\n\nexport type DocPeekToolInput = Static<typeof docPeekSchema>;\n\nexport interface DocPeekToolDetails {\n\treturned?: number;\n\ttotal?: number;\n}\n\nexport interface DocPeekToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/** Render hydrated read blocks using the same id-addressed node dialect as DocRead. */\nexport function renderReadView(view: ReadView): string {\n\tconst header = `document — ${view.returned}/${view.total} blocks (offset ${view.offset})`;\n\tconst lines: string[] = [header, \"\", ...renderDocNodeLines(view.nodes)];\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tconst seen = view.offset + view.returned;\n\tconst remaining = view.total - seen;\n\tconst parts = [text];\n\tif (droppedLines > 0) {\n\t\tparts.push(\n\t\t\t`\\n[Truncated: ${droppedLines} more node line${droppedLines === 1 ? \"\" : \"s\"} omitted; ` +\n\t\t\t\t`request fewer ids or a smaller limit.]`,\n\t\t);\n\t}\n\tif (remaining > 0) {\n\t\tparts.push(\n\t\t\t`\\n[${remaining} more block${remaining === 1 ? \"\" : \"s\"} not shown — re-run with offset:${seen} to continue.]`,\n\t\t);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\nfunction formatDocPeekCall(\n\targs: { path?: string; id?: string[]; offset?: number; limit?: number } | undefined,\n): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocPeek \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst ids = Array.isArray(args?.id) ? args.id.length : 0;\n\tif (ids > 0) {\n\t\ttext += appTheme.fg(\"muted\", ` (${ids} id${ids === 1 ? \"\" : \"s\"})`);\n\t} else {\n\t\tconst range: string[] = [];\n\t\tif (args?.offset !== undefined) range.push(`offset ${args.offset}`);\n\t\tif (args?.limit !== undefined) range.push(`limit ${args.limit}`);\n\t\tif (range.length > 0) text += appTheme.fg(\"muted\", ` (${range.join(\", \")})`);\n\t}\n\treturn text;\n}\n\nfunction formatDocPeekResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocPeekToolDefinition(\n\tcwd: string,\n\toptions?: DocPeekToolOptions,\n): ToolDefinition<typeof docPeekSchema, DocPeekToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocPeek\",\n\t\tlabel: \"DocPeek\",\n\t\tdescription:\n\t\t\t\"Hydrate specific blocks of a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) by structural-path id — the read half of the token-sensitive loop. Pass the path ids from a prior DocScan (e.g. node[title:0]) to read only those blocks (or omit ids to page through all with offset/limit), instead of dumping the whole document with DocRead. The hydrated nodes carry the editable el_ #ids, which you then patch with DocEdit/DocWrite. Read-only. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Read only specific blocks of a structured/binary document by id\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocPeek to read just the blocks you need (by structural-path id from DocScan, e.g. node[title:0]) instead of a full DocRead — it is much cheaper in tokens. Omit ids and use offset/limit to page through a large document.\",\n\t\t\t\"Pass the EXACT ids DocScan returned; DocPeek does not accept invented sub-ranges (e.g. rows[0-2] when DocScan emitted rows[0-99]).\",\n\t\t\t\"DocPeek takes DocScan's path ids, NOT DocGrep's el_ node ids. The nodes it returns carry the editable el_ #ids — patch those with DocEdit/DocWrite (which auto-extract). If you already have an el_ id from DocGrep, go straight to DocEdit; you do not need DocPeek.\",\n\t\t\t\"Works across all supported formats including spreadsheet cells (hydrating a sheet's rows[a-b] block returns the cell values) and slide text (pptx).\",\n\t\t],\n\t\tparameters: docPeekSchema,\n\t\tasync execute(_toolCallId, { path, id, offset, limit }: DocPeekToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await readDocumentBlocks(absolutePath, cwd, signal, {\n\t\t\t\tids: id,\n\t\t\t\toffset,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderReadView(view) }],\n\t\t\t\tdetails: { returned: view.returned, total: view.total },\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(formatDocPeekCall(args));\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(formatDocPeekResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocPeekTool(cwd: string, options?: DocPeekToolOptions): AgentTool<typeof docPeekSchema> {\n\treturn wrapToolDefinition(createDocPeekToolDefinition(cwd, options));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"docread.d.ts","sourceRoot":"","sources":["../../../src/core/tools/docread.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAGN,KAAK,QAAQ,EAIb,MAAM,uBAAuB,CAAC;AAK/B,QAAA,MAAM,aAAa;;;EAWjB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAClC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAUD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAiB5F;AA6BD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC1B,cAAc,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAyCtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport {\n\tDOCREAD_MAX_RENDER_TOKENS,\n\ttype DocNode,\n\ttype Envelope,\n\textractDocument,\n\trenderDocNodeLines,\n\ttruncateRenderToTokenBudget,\n} from \"./filetools-shared.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docReadSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to extract (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\treadonly: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Analysis-only projection: strips node ids for a smaller view that CANNOT be edited. Omit (default false) when you intend to DocEdit/DocWrite afterwards.\",\n\t\t}),\n\t),\n});\n\nexport type DocReadToolInput = Static<typeof docReadSchema>;\n\nexport interface DocReadToolDetails {\n\ttype?: string;\n\tfidelity?: string;\n\twritable?: boolean;\n\tnodeCount?: number;\n}\n\nexport interface DocReadToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\nfunction countNodes(nodes: DocNode[]): number {\n\tlet total = 0;\n\tfor (const node of nodes) {\n\t\ttotal += 1 + (node.children ? countNodes(node.children) : 0);\n\t}\n\treturn total;\n}\n\n/**\n * Render the envelope as compact, id-addressed text the model edits against.\n * Each line carries the node id so DocEdit/DocWrite patches can target it.\n *\n * The filetools binary has no pagination, so a dense document can project into\n * a huge dump. We truncate the rendered view to a token budget and append an\n * actionable notice instead of flooding the model context.\n */\nexport function renderEnvelopeText(envelope: Envelope, readonly: boolean | undefined): string {\n\tconst header =\n\t\t`document ${envelope.source.path} [${envelope.source.type}, ${envelope.fidelity}, ` +\n\t\t`${envelope.writable ? \"writable\" : \"read-only\"}]`;\n\tconst lines: string[] = [header, \"\", ...renderDocNodeLines(envelope.structure)];\n\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\n\tconst hint = readonly\n\t\t? \"narrow to a smaller or more targeted file\"\n\t\t: \"re-run with readonly:true for a smaller analysis-only view, or target a smaller file\";\n\treturn (\n\t\t`${text}\\n\\n[Truncated: document exceeds the ~${DOCREAD_MAX_RENDER_TOKENS} token render budget; ` +\n\t\t`${droppedLines} more node line${droppedLines === 1 ? \"\" : \"s\"} omitted. The ids shown are still valid for ` +\n\t\t`DocEdit/DocWrite — ${hint}.]`\n\t);\n}\n\nfunction formatDocReadCall(args: { path?: string; readonly?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocRead \")) + appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.readonly) text += appTheme.fg(\"muted\", \" (readonly)\");\n\treturn text;\n}\n\nfunction formatDocReadResult(\n\tresult: { content: Array<{ type: string; text?: string }>; details?: DocReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocReadToolDefinition(\n\tcwd: string,\n\toptions?: DocReadToolOptions,\n): ToolDefinition<typeof docReadSchema, DocReadToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocRead\",\n\t\tlabel: \"DocRead\",\n\t\tdescription:\n\t\t\t\"Extract a structured or binary document (XML, drawio, docx/xlsx/pptx, PDF) into editable, id-addressed JSON the agent can patch losslessly. Each node has a stable #id; edit with DocEdit (in place) or DocWrite (to a new path), passing a patch that targets those ids. This is the canonical way to read and edit these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or rewrite them — that loses the lossless id-map and corrupts formatting. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Extract a structured/binary document into editable, id-addressed JSON\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocRead to open structured/binary documents (XML, drawio, docx/xlsx/pptx, PDF) instead of read; it returns id-addressed nodes you can patch with DocEdit/DocWrite. Never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or edit these formats — that loses the lossless id-map and corrupts the file.\",\n\t\t\t\"Flow: scan first, edit second. To understand a document, start with DocRead readonly:true — an analysis-only projection that strips node ids and is much cheaper in tokens. Only do a full (writable) DocRead when you actually intend to edit, since that view carries the whole id-map and is token-heavy.\",\n\t\t\t\"Read once, then edit. A writable DocRead establishes the id-map; DocEdit/DocWrite re-extract on their own, so do not re-run DocRead between edits. If a patch targets stale ids the edit fails and returns the current structure with fresh ids to re-issue against.\",\n\t\t],\n\t\tparameters: docReadSchema,\n\t\tasync execute(_toolCallId, { path, readonly }: DocReadToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst envelope = await extractDocument(absolutePath, cwd, signal, {\n\t\t\t\treadonly,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderEnvelopeText(envelope, readonly) }],\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: envelope.source.type,\n\t\t\t\t\tfidelity: envelope.fidelity,\n\t\t\t\t\twritable: envelope.writable,\n\t\t\t\t\tnodeCount: countNodes(envelope.structure),\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(formatDocReadCall(args));\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(formatDocReadResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocReadTool(cwd: string, options?: DocReadToolOptions): AgentTool<typeof docReadSchema> {\n\treturn wrapToolDefinition(createDocReadToolDefinition(cwd, options));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"docread.js","sourceRoot":"","sources":["../../../src/core/tools/docread.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport {\n\tDOCREAD_MAX_RENDER_TOKENS,\n\ttype DocNode,\n\ttype Envelope,\n\textractDocument,\n\trenderDocNodeLines,\n\ttruncateRenderToTokenBudget,\n} from \"./filetools-shared.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docReadSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to extract (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\treadonly: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Analysis-only projection: strips node ids for a smaller view that CANNOT be edited. Omit (default false) when you intend to DocEdit/DocWrite afterwards.\",\n\t\t}),\n\t),\n});\n\nexport type DocReadToolInput = Static<typeof docReadSchema>;\n\nexport interface DocReadToolDetails {\n\ttype?: string;\n\tfidelity?: string;\n\twritable?: boolean;\n\tnodeCount?: number;\n}\n\nexport interface DocReadToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\nfunction countNodes(nodes: DocNode[]): number {\n\tlet total = 0;\n\tfor (const node of nodes) {\n\t\ttotal += 1 + (node.children ? countNodes(node.children) : 0);\n\t}\n\treturn total;\n}\n\n/**\n * Render the envelope as compact, id-addressed text the model edits against.\n * Each line carries the node id so DocEdit/DocWrite patches can target it.\n *\n * The filetools binary has no pagination, so a dense document can project into\n * a huge dump. We truncate the rendered view to a token budget and append an\n * actionable notice instead of flooding the model context.\n */\nexport function renderEnvelopeText(envelope: Envelope, readonly: boolean | undefined): string {\n\tconst header =\n\t\t`document ${envelope.source.path} [${envelope.source.type}, ${envelope.fidelity}, ` +\n\t\t`${envelope.writable ? \"writable\" : \"read-only\"}]`;\n\tconst lines: string[] = [header, \"\", ...renderDocNodeLines(envelope.structure)];\n\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\n\tconst hint = readonly\n\t\t? \"narrow to a smaller or more targeted file\"\n\t\t: \"re-run with readonly:true for a smaller analysis-only view, or target a smaller file\";\n\treturn (\n\t\t`${text}\\n\\n[Truncated: document exceeds the ~${DOCREAD_MAX_RENDER_TOKENS} token render budget; ` +\n\t\t`${droppedLines} more node line${droppedLines === 1 ? \"\" : \"s\"} omitted. The ids shown are still valid for ` +\n\t\t`DocEdit/DocWrite — ${hint}.]`\n\t);\n}\n\nfunction formatDocReadCall(args: { path?: string; readonly?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocRead \")) + appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.readonly) text += appTheme.fg(\"muted\", \" (readonly)\");\n\treturn text;\n}\n\nfunction formatDocReadResult(\n\tresult: { content: Array<{ type: string; text?: string }>; details?: DocReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocReadToolDefinition(\n\tcwd: string,\n\toptions?: DocReadToolOptions,\n): ToolDefinition<typeof docReadSchema, DocReadToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocRead\",\n\t\tlabel: \"DocRead\",\n\t\tdescription:\n\t\t\t\"Extract a structured or binary document (XML, drawio, docx/xlsx/pptx, PDF) into editable, id-addressed JSON the agent can patch losslessly. Each node has a stable #id; edit with DocEdit (in place) or DocWrite (to a new path), passing a patch that targets those ids. This is the canonical way to read and edit these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or rewrite them — that loses the lossless id-map and corrupts formatting. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Extract a structured/binary document into editable, id-addressed JSON\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocRead to open structured/binary documents (XML, drawio, docx/xlsx/pptx, PDF) instead of read; it returns id-addressed nodes you can patch with DocEdit/DocWrite. Never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or edit these formats — that loses the lossless id-map and corrupts the file.\",\n\t\t\t\"Flow: scan first, edit second. To understand a document, start with DocRead readonly:true — an analysis-only projection that strips node ids and is much cheaper in tokens. Only do a full (writable) DocRead when you actually intend to edit, since that view carries the whole id-map and is token-heavy.\",\n\t\t\t\"Read once, then edit. A writable DocRead establishes the id-map; DocEdit/DocWrite re-extract on their own, so do not re-run DocRead between edits. If a patch targets stale ids the edit fails and returns the current structure with fresh ids to re-issue against.\",\n\t\t],\n\t\tparameters: docReadSchema,\n\t\tasync execute(_toolCallId, { path, readonly }: DocReadToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst envelope = await extractDocument(absolutePath, cwd, signal, {\n\t\t\t\treadonly,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderEnvelopeText(envelope, readonly) }],\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: envelope.source.type,\n\t\t\t\t\tfidelity: envelope.fidelity,\n\t\t\t\t\twritable: envelope.writable,\n\t\t\t\t\tnodeCount: countNodes(envelope.structure),\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(formatDocReadCall(args));\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(formatDocReadResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocReadTool(cwd: string, options?: DocReadToolOptions): AgentTool<typeof docReadSchema> {\n\treturn wrapToolDefinition(createDocReadToolDefinition(cwd, options));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"docscan.d.ts","sourceRoot":"","sources":["../../../src/core/tools/docscan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,KAAK,QAAQ,EAA6C,MAAM,uBAAuB,CAAC;AAKjG,QAAA,MAAM,aAAa;;;;EAMjB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IAClC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CA2BrD;AAgCD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC1B,cAAc,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAoCtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport { type ScanView, scanDocument, truncateRenderToTokenBudget } from \"./filetools-shared.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docScanSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to scan (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\toffset: Type.Optional(Type.Number({ description: \"Skip the first N blocks (pagination). Default 0.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of blocks to return. Default: all remaining.\" })),\n});\n\nexport type DocScanToolInput = Static<typeof docScanSchema>;\n\nexport interface DocScanToolDetails {\n\tfileType?: string;\n\treturned?: number;\n\ttotal?: number;\n}\n\nexport interface DocScanToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/**\n * Render a scan manifest as compact, id-addressed preview lines. Each line\n * carries the block id (feeds DocPeek/DocGrep) plus a section label, token\n * estimate, and a short preview — structure without hydrating full content.\n */\nexport function renderScanView(view: ScanView): string {\n\tconst header =\n\t\t`document ${view.file_type} — ${view.returned}/${view.total} blocks ` +\n\t\t`(offset ${view.offset}, ~${view.total_tokens} tok total)`;\n\tconst lines: string[] = [header, \"\"];\n\tfor (const block of view.blocks) {\n\t\tconst section = block.section_name ? ` ${block.section_name}#${block.section_number}` : \"\";\n\t\tconst preview = block.preview ? ` :: ${JSON.stringify(block.preview)}` : \"\";\n\t\tlines.push(`#${block.id} [${block.block_type}]${section} ~${block.token_estimate}tok${preview}`);\n\t}\n\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tconst seen = view.offset + view.returned;\n\tconst remaining = view.total - seen;\n\tconst parts = [text];\n\tif (droppedLines > 0) {\n\t\tparts.push(\n\t\t\t`\\n[Truncated: ${droppedLines} more block line${droppedLines === 1 ? \"\" : \"s\"} omitted from this render. ` +\n\t\t\t\t`Re-run with a tighter limit, or DocGrep/DocPeek to target.]`,\n\t\t);\n\t}\n\tif (remaining > 0) {\n\t\tparts.push(\n\t\t\t`\\n[${remaining} more block${remaining === 1 ? \"\" : \"s\"} not shown — re-run with offset:${seen} to continue.]`,\n\t\t);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\nfunction formatDocScanCall(args: { path?: string; offset?: number; limit?: number } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocScan \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst range: string[] = [];\n\tif (args?.offset !== undefined) range.push(`offset ${args.offset}`);\n\tif (args?.limit !== undefined) range.push(`limit ${args.limit}`);\n\tif (range.length > 0) text += appTheme.fg(\"muted\", ` (${range.join(\", \")})`);\n\treturn text;\n}\n\nfunction formatDocScanResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocScanToolDefinition(\n\tcwd: string,\n\toptions?: DocScanToolOptions,\n): ToolDefinition<typeof docScanSchema, DocScanToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocScan\",\n\t\tlabel: \"DocScan\",\n\t\tdescription:\n\t\t\t\"Cheaply outline a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) without hydrating it: returns a paginated manifest of blocks, each with a structural-path id, type, section label, token estimate, and a short preview. This is the cheap first step of the token-sensitive loop — far smaller than a full DocRead. Pass the path ids it returns to DocPeek to hydrate just those blocks (the hydrated nodes carry the editable el_ #ids for DocEdit). Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Outline a structured/binary document into a cheap, paginated block manifest\",\n\t\tpromptGuidelines: [\n\t\t\t\"Start here for large structured/binary documents instead of a full DocRead: DocScan returns a paginated outline (structural-path block ids + previews) that is much cheaper in tokens. Page through it with offset/limit.\",\n\t\t\t\"Flow: DocScan to see structure → DocPeek the path ids you want (hydrates them and reveals their editable el_ #ids) → DocEdit. Or jump straight in with DocGrep, which finds blocks by text and returns editable el_ #ids directly.\",\n\t\t],\n\t\tparameters: docScanSchema,\n\t\tasync execute(_toolCallId, { path, offset, limit }: DocScanToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await scanDocument(absolutePath, cwd, signal, {\n\t\t\t\toffset,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderScanView(view) }],\n\t\t\t\tdetails: { fileType: view.file_type, returned: view.returned, total: view.total },\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(formatDocScanCall(args));\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(formatDocScanResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocScanTool(cwd: string, options?: DocScanToolOptions): AgentTool<typeof docScanSchema> {\n\treturn wrapToolDefinition(createDocScanToolDefinition(cwd, options));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"docscan.js","sourceRoot":"","sources":["../../../src/core/tools/docscan.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport { type ScanView, scanDocument, truncateRenderToTokenBudget } from \"./filetools-shared.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docScanSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to scan (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\toffset: Type.Optional(Type.Number({ description: \"Skip the first N blocks (pagination). Default 0.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of blocks to return. Default: all remaining.\" })),\n});\n\nexport type DocScanToolInput = Static<typeof docScanSchema>;\n\nexport interface DocScanToolDetails {\n\tfileType?: string;\n\treturned?: number;\n\ttotal?: number;\n}\n\nexport interface DocScanToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/**\n * Render a scan manifest as compact, id-addressed preview lines. Each line\n * carries the block id (feeds DocPeek/DocGrep) plus a section label, token\n * estimate, and a short preview — structure without hydrating full content.\n */\nexport function renderScanView(view: ScanView): string {\n\tconst header =\n\t\t`document ${view.file_type} — ${view.returned}/${view.total} blocks ` +\n\t\t`(offset ${view.offset}, ~${view.total_tokens} tok total)`;\n\tconst lines: string[] = [header, \"\"];\n\tfor (const block of view.blocks) {\n\t\tconst section = block.section_name ? ` ${block.section_name}#${block.section_number}` : \"\";\n\t\tconst preview = block.preview ? ` :: ${JSON.stringify(block.preview)}` : \"\";\n\t\tlines.push(`#${block.id} [${block.block_type}]${section} ~${block.token_estimate}tok${preview}`);\n\t}\n\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tconst seen = view.offset + view.returned;\n\tconst remaining = view.total - seen;\n\tconst parts = [text];\n\tif (droppedLines > 0) {\n\t\tparts.push(\n\t\t\t`\\n[Truncated: ${droppedLines} more block line${droppedLines === 1 ? \"\" : \"s\"} omitted from this render. ` +\n\t\t\t\t`Re-run with a tighter limit, or DocGrep/DocPeek to target.]`,\n\t\t);\n\t}\n\tif (remaining > 0) {\n\t\tparts.push(\n\t\t\t`\\n[${remaining} more block${remaining === 1 ? \"\" : \"s\"} not shown — re-run with offset:${seen} to continue.]`,\n\t\t);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\nfunction formatDocScanCall(args: { path?: string; offset?: number; limit?: number } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocScan \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst range: string[] = [];\n\tif (args?.offset !== undefined) range.push(`offset ${args.offset}`);\n\tif (args?.limit !== undefined) range.push(`limit ${args.limit}`);\n\tif (range.length > 0) text += appTheme.fg(\"muted\", ` (${range.join(\", \")})`);\n\treturn text;\n}\n\nfunction formatDocScanResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocScanToolDefinition(\n\tcwd: string,\n\toptions?: DocScanToolOptions,\n): ToolDefinition<typeof docScanSchema, DocScanToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocScan\",\n\t\tlabel: \"DocScan\",\n\t\tdescription:\n\t\t\t\"Cheaply outline a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) without hydrating it: returns a paginated manifest of blocks, each with a structural-path id, type, section label, token estimate, and a short preview. This is the cheap first step of the token-sensitive loop — far smaller than a full DocRead. Pass the path ids it returns to DocPeek to hydrate just those blocks (the hydrated nodes carry the editable el_ #ids for DocEdit). Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Outline a structured/binary document into a cheap, paginated block manifest\",\n\t\tpromptGuidelines: [\n\t\t\t\"Start here for large structured/binary documents instead of a full DocRead: DocScan returns a paginated outline (structural-path block ids + previews) that is much cheaper in tokens. Page through it with offset/limit.\",\n\t\t\t\"Flow: DocScan to see structure → DocPeek the path ids you want (hydrates them and reveals their editable el_ #ids) → DocEdit. Or jump straight in with DocGrep, which finds blocks by text and returns editable el_ #ids directly.\",\n\t\t],\n\t\tparameters: docScanSchema,\n\t\tasync execute(_toolCallId, { path, offset, limit }: DocScanToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await scanDocument(absolutePath, cwd, signal, {\n\t\t\t\toffset,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderScanView(view) }],\n\t\t\t\tdetails: { fileType: view.file_type, returned: view.returned, total: view.total },\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(formatDocScanCall(args));\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(formatDocScanResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocScanTool(cwd: string, options?: DocScanToolOptions): AgentTool<typeof docScanSchema> {\n\treturn wrapToolDefinition(createDocScanToolDefinition(cwd, options));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"docwrite.d.ts","sourceRoot":"","sources":["../../../src/core/tools/docwrite.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAQ7D,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQlB,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE9D,MAAM,WAAW,mBAAmB;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,mBAAmB;IACnC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAmBD,wBAAgB,4BAA4B,CAC3C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,mBAAmB,GAC3B,cAAc,CAAC,OAAO,cAAc,EAAE,mBAAmB,GAAG,SAAS,CAAC,CA+DxE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC,OAAO,cAAc,CAAC,CAE/G","sourcesContent":["import { mkdir as fsMkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Container, Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { renderEnvelopeText } from \"./docread.js\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nimport { patchOpsSchema, reconstructDocument, StalePatchError, toPatch } from \"./filetools-shared.js\";\nimport { resolveReadPath, resolveToCwd } from \"./path-utils.js\";\nimport { invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docWriteSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the SOURCE document. Must have been opened with DocRead first. Left untouched.\",\n\t}),\n\tout: Type.String({\n\t\tdescription: \"Output path for the reconstructed document (relative or absolute). Created/overwritten.\",\n\t}),\n\tpatch: patchOpsSchema,\n});\n\nexport type DocWriteToolInput = Static<typeof docWriteSchema>;\n\nexport interface DocWriteToolDetails {\n\tops?: number;\n\tout?: string;\n}\n\nexport interface DocWriteToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\nfunction formatDocWriteCall(args: { path?: string; out?: string; patch?: unknown[] } | undefined): string {\n\tconst path = str(args?.path);\n\tconst out = str(args?.out);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tconst outDisplay =\n\t\tout === null ? invalidArgText(appTheme) : out ? shortenPath(out) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text =\n\t\tappTheme.fg(\"toolTitle\", appTheme.bold(\"DocWrite \")) +\n\t\tappTheme.fg(\"accent\", pathDisplay) +\n\t\tappTheme.fg(\"muted\", \" -> \") +\n\t\tappTheme.fg(\"accent\", outDisplay);\n\tconst ops = Array.isArray(args?.patch) ? args.patch.length : undefined;\n\tif (ops !== undefined) text += appTheme.fg(\"muted\", ` (${ops} op${ops === 1 ? \"\" : \"s\"})`);\n\treturn text;\n}\n\nexport function createDocWriteToolDefinition(\n\tcwd: string,\n\toptions?: DocWriteToolOptions,\n): ToolDefinition<typeof docWriteSchema, DocWriteToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocWrite\",\n\t\tlabel: \"DocWrite\",\n\t\tdescription:\n\t\t\t\"Apply an id-based patch to a structured/binary document and write the result to a NEW path, leaving the source untouched (save-as). Targets node ids from a DocRead extract of the source; if the cache is missing or the source changed on disk (e.g. an external script rewrote it) it is re-extracted automatically, so a separate DocRead is not required. If the patch references ids that no longer exist, the call fails and returns the current structure with fresh ids so you can re-issue. This is the canonical way to rewrite these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to produce the output — that bypasses the lossless id-map and corrupts the file. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Reconstruct a patched structured/binary document to a new path\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocWrite to save an edited document to a different file: pass the source path (opened with DocRead), an `out` path, and an id-based patch. The source is left unchanged.\",\n\t\t\t\"Keep the patch minimal and scan before you write: prefer a DocRead readonly:true glimpse to plan the change, and avoid re-running a full writable DocRead between writes — it auto-extracts the source and is token-heavy.\",\n\t\t],\n\t\tparameters: docWriteSchema,\n\t\tasync execute(_toolCallId, { path, out, patch }: DocWriteToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst outPath = resolveToCwd(out, cwd);\n\n\t\t\treturn withFileMutationQueue(outPath, async () => {\n\t\t\t\tawait fsMkdir(dirname(outPath), { recursive: true });\n\t\t\t\ttry {\n\t\t\t\t\tawait reconstructDocument(absolutePath, toPatch(patch), outPath, cwd, signal, {\n\t\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof StalePatchError) {\n\t\t\t\t\t\t// The source was rewritten out-of-band: the cache auto-refreshed\n\t\t\t\t\t\t// but the patch targets ids that no longer exist. Surface the\n\t\t\t\t\t\t// current structure so the agent can re-issue without a DocRead.\n\t\t\t\t\t\tthrow new Error(`${err.message}\\n\\n${renderEnvelopeText(err.envelope, false)}`);\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `Wrote ${patch.length} op${patch.length === 1 ? \"\" : \"s\"} from ${path} to ${out}.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { ops: patch.length, out },\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(formatDocWriteCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, _options, _theme, context) {\n\t\t\tif (!context.isError) {\n\t\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\t\tcomponent.clear();\n\t\t\t\treturn component;\n\t\t\t}\n\t\t\tconst output = (result.content as Array<{ type: string; text?: string }>)\n\t\t\t\t.filter((c) => c.type === \"text\")\n\t\t\t\t.map((c) => c.text || \"\")\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(output ? `\\n${appTheme.fg(\"error\", output)}` : \"\");\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocWriteTool(cwd: string, options?: DocWriteToolOptions): AgentTool<typeof docWriteSchema> {\n\treturn wrapToolDefinition(createDocWriteToolDefinition(cwd, options));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"docwrite.js","sourceRoot":"","sources":["../../../src/core/tools/docwrite.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir as fsMkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Container, Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { theme as appTheme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { renderEnvelopeText } from \"./docread.js\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nimport { patchOpsSchema, reconstructDocument, StalePatchError, toPatch } from \"./filetools-shared.js\";\nimport { resolveReadPath, resolveToCwd } from \"./path-utils.js\";\nimport { invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\n\nconst docWriteSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the SOURCE document. Must have been opened with DocRead first. Left untouched.\",\n\t}),\n\tout: Type.String({\n\t\tdescription: \"Output path for the reconstructed document (relative or absolute). Created/overwritten.\",\n\t}),\n\tpatch: patchOpsSchema,\n});\n\nexport type DocWriteToolInput = Static<typeof docWriteSchema>;\n\nexport interface DocWriteToolDetails {\n\tops?: number;\n\tout?: string;\n}\n\nexport interface DocWriteToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\nfunction formatDocWriteCall(args: { path?: string; out?: string; patch?: unknown[] } | undefined): string {\n\tconst path = str(args?.path);\n\tconst out = str(args?.out);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tconst outDisplay =\n\t\tout === null ? invalidArgText(appTheme) : out ? shortenPath(out) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text =\n\t\tappTheme.fg(\"toolTitle\", appTheme.bold(\"DocWrite \")) +\n\t\tappTheme.fg(\"accent\", pathDisplay) +\n\t\tappTheme.fg(\"muted\", \" -> \") +\n\t\tappTheme.fg(\"accent\", outDisplay);\n\tconst ops = Array.isArray(args?.patch) ? args.patch.length : undefined;\n\tif (ops !== undefined) text += appTheme.fg(\"muted\", ` (${ops} op${ops === 1 ? \"\" : \"s\"})`);\n\treturn text;\n}\n\nexport function createDocWriteToolDefinition(\n\tcwd: string,\n\toptions?: DocWriteToolOptions,\n): ToolDefinition<typeof docWriteSchema, DocWriteToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocWrite\",\n\t\tlabel: \"DocWrite\",\n\t\tdescription:\n\t\t\t\"Apply an id-based patch to a structured/binary document and write the result to a NEW path, leaving the source untouched (save-as). Targets node ids from a DocRead extract of the source; if the cache is missing or the source changed on disk (e.g. an external script rewrote it) it is re-extracted automatically, so a separate DocRead is not required. If the patch references ids that no longer exist, the call fails and returns the current structure with fresh ids so you can re-issue. This is the canonical way to rewrite these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to produce the output — that bypasses the lossless id-map and corrupts the file. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Reconstruct a patched structured/binary document to a new path\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocWrite to save an edited document to a different file: pass the source path (opened with DocRead), an `out` path, and an id-based patch. The source is left unchanged.\",\n\t\t\t\"Keep the patch minimal and scan before you write: prefer a DocRead readonly:true glimpse to plan the change, and avoid re-running a full writable DocRead between writes — it auto-extracts the source and is token-heavy.\",\n\t\t],\n\t\tparameters: docWriteSchema,\n\t\tasync execute(_toolCallId, { path, out, patch }: DocWriteToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst outPath = resolveToCwd(out, cwd);\n\n\t\t\treturn withFileMutationQueue(outPath, async () => {\n\t\t\t\tawait fsMkdir(dirname(outPath), { recursive: true });\n\t\t\t\ttry {\n\t\t\t\t\tawait reconstructDocument(absolutePath, toPatch(patch), outPath, cwd, signal, {\n\t\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof StalePatchError) {\n\t\t\t\t\t\t// The source was rewritten out-of-band: the cache auto-refreshed\n\t\t\t\t\t\t// but the patch targets ids that no longer exist. Surface the\n\t\t\t\t\t\t// current structure so the agent can re-issue without a DocRead.\n\t\t\t\t\t\tthrow new Error(`${err.message}\\n\\n${renderEnvelopeText(err.envelope, false)}`);\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `Wrote ${patch.length} op${patch.length === 1 ? \"\" : \"s\"} from ${path} to ${out}.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { ops: patch.length, out },\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(formatDocWriteCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, _options, _theme, context) {\n\t\t\tif (!context.isError) {\n\t\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\t\tcomponent.clear();\n\t\t\t\treturn component;\n\t\t\t}\n\t\t\tconst output = (result.content as Array<{ type: string; text?: string }>)\n\t\t\t\t.filter((c) => c.type === \"text\")\n\t\t\t\t.map((c) => c.text || \"\")\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(output ? `\\n${appTheme.fg(\"error\", output)}` : \"\");\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocWriteTool(cwd: string, options?: DocWriteToolOptions): AgentTool<typeof docWriteSchema> {\n\treturn wrapToolDefinition(createDocWriteToolDefinition(cwd, options));\n}\n"]}
@@ -1,53 +0,0 @@
1
- /**
2
- * Lossless output compression utilities for tool outputs.
3
- *
4
- * All compression is strictly lossless - no useful information is removed.
5
- * Compression is command-aware where possible, and general-purpose otherwise.
6
- */
7
- /**
8
- * Collapse 3+ consecutive blank lines to 2 (preserves paragraph separation).
9
- */
10
- export declare function collapseBlankLines(text: string): string;
11
- /**
12
- * Strip trailing whitespace from each line.
13
- */
14
- export declare function stripTrailingWhitespace(text: string): string;
15
- /**
16
- * Remove duplicate consecutive lines (keeps first occurrence).
17
- */
18
- export declare function removeDuplicateLines(text: string): string;
19
- /**
20
- * Apply general lossless compression to any output.
21
- * Single-pass implementation for efficiency.
22
- */
23
- export declare function compressGeneral(text: string): string;
24
- /**
25
- * Apply all compression to a bash command output.
26
- * This is the main entry point for bash output compression.
27
- *
28
- * @param command - The bash command that was executed
29
- * @param output - The raw output from the command
30
- * @returns Compressed output (lossless)
31
- */
32
- export declare function compressBashOutput(command: string, output: string): string;
33
- /**
34
- * Apply compression to grep output.
35
- * This strips redundant context and normalizes output.
36
- */
37
- export declare function compressGrepOutput(output: string): string;
38
- /**
39
- * Apply compression to read output.
40
- * This normalizes whitespace but preserves content.
41
- */
42
- export declare function compressReadOutput(output: string): string;
43
- /**
44
- * Apply compression to find output.
45
- * This normalizes paths and removes duplicates.
46
- */
47
- export declare function compressFindOutput(output: string): string;
48
- /**
49
- * Apply compression to ls output.
50
- * This normalizes formatting.
51
- */
52
- export declare function compressLsOutput(output: string): string;
53
- //# sourceMappingURL=output-compression.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"output-compression.d.ts","sourceRoot":"","sources":["../../../src/core/tools/output-compression.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAazD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqBpD;AAuSD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAkB1E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKvD","sourcesContent":["/**\n * Lossless output compression utilities for tool outputs.\n *\n * All compression is strictly lossless - no useful information is removed.\n * Compression is command-aware where possible, and general-purpose otherwise.\n */\n\n/** Minimum output size (in bytes) to apply compression. Below this, overhead exceeds savings. */\nconst MIN_COMPRESSION_SIZE = 1024; // 1KB\n\n// ============================================================================\n// General Compression (applied to all outputs)\n// ============================================================================\n\n/**\n * Collapse 3+ consecutive blank lines to 2 (preserves paragraph separation).\n */\nexport function collapseBlankLines(text: string): string {\n\treturn text.replace(/\\n{3,}/g, \"\\n\\n\");\n}\n\n/**\n * Strip trailing whitespace from each line.\n */\nexport function stripTrailingWhitespace(text: string): string {\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.map((line) => line.trimEnd())\n\t\t.join(\"\\n\");\n}\n\n/**\n * Remove duplicate consecutive lines (keeps first occurrence).\n */\nexport function removeDuplicateLines(text: string): string {\n\tconst lines = text.split(\"\\n\");\n\tconst result: string[] = [];\n\tlet prevLine: string | undefined;\n\n\tfor (const line of lines) {\n\t\tif (line !== prevLine) {\n\t\t\tresult.push(line);\n\t\t\tprevLine = line;\n\t\t}\n\t}\n\n\treturn result.join(\"\\n\");\n}\n\n/**\n * Apply general lossless compression to any output.\n * Single-pass implementation for efficiency.\n */\nexport function compressGeneral(text: string): string {\n\tconst lines = text.split(\"\\n\");\n\tconst result: string[] = [];\n\tlet blankCount = 0;\n\n\tfor (const line of lines) {\n\t\tconst trimmed = line.trimEnd();\n\n\t\tif (trimmed === \"\") {\n\t\t\tblankCount++;\n\t\t\t// Allow at most 2 consecutive blank lines\n\t\t\tif (blankCount <= 2) {\n\t\t\t\tresult.push(trimmed);\n\t\t\t}\n\t\t} else {\n\t\t\tblankCount = 0;\n\t\t\tresult.push(trimmed);\n\t\t}\n\t}\n\n\treturn result.join(\"\\n\");\n}\n\n// ============================================================================\n// Command-Specific Compression (bash only)\n// ============================================================================\n\n/**\n * Detect the primary command from a bash command string.\n */\nfunction detectCommand(command: string): string {\n\tconst trimmed = command.trim();\n\t// Strip leading env vars (FOO=bar command)\n\tconst withoutEnv = trimmed.replace(/^[A-Z_]+=\\S+\\s+/, \"\");\n\t// Strip leading sudo\n\tconst withoutSudo = withoutEnv.replace(/^sudo\\s+/, \"\");\n\t// Get first word (the actual command)\n\tconst firstWord = withoutSudo.split(/\\s+/)[0] ?? \"\";\n\t// Strip path prefix if any\n\treturn firstWord.split(\"/\").pop() ?? \"\";\n}\n\n/**\n * Compress npm/yarn/pnpm install output.\n * - Remove download progress lines\n * - Collapse \"added N packages\" summaries\n */\nfunction compressNpmInstall(output: string): string {\n\tconst lines = output.split(\"\\n\");\n\tconst result: string[] = [];\n\n\tfor (const line of lines) {\n\t\t// Skip download progress (e.g., \"fetchMetadata: ...\", \"reify: ...\")\n\t\tif (/^(fetchMetadata|reify|audit|idealTree|sill|warn)\\b/.test(line)) {\n\t\t\tcontinue;\n\t\t}\n\t\t// Skip verbose fetch/cache lines\n\t\tif (/^\\s*(http|https|fetch|cache|tarball|extract)\\b/.test(line)) {\n\t\t\tcontinue;\n\t\t}\n\t\t// Keep everything else (errors, warnings, summaries)\n\t\tresult.push(line);\n\t}\n\n\treturn result.join(\"\\n\");\n}\n\n/**\n * Compress git diff output.\n * - Strip file headers (diff --git, index, ---, +++)\n * - Collapse unchanged context lines\n */\nfunction compressGitDiff(output: string): string {\n\tconst lines = output.split(\"\\n\");\n\tconst result: string[] = [];\n\tlet contextCount = 0;\n\n\tfor (const line of lines) {\n\t\t// Skip git diff metadata\n\t\tif (/^(diff --git|index [0-9a-f]+|--- a\\/|\\+\\+\\+ b\\/)/.test(line)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Count context lines (lines starting with space)\n\t\tif (line.startsWith(\" \") && !line.startsWith(\" \")) {\n\t\t\tcontextCount++;\n\t\t\t// Only show first 2 context lines per hunk, then skip\n\t\t\tif (contextCount > 2) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t} else {\n\t\t\tcontextCount = 0;\n\t\t}\n\n\t\tresult.push(line);\n\t}\n\n\treturn result.join(\"\\n\");\n}\n\n/**\n * Compress cargo/rustc test output.\n * - Collapse passing tests, keep failures\n */\nfunction compressCargoTest(output: string): string {\n\tconst lines = output.split(\"\\n\");\n\tconst result: string[] = [];\n\tlet passingCount = 0;\n\n\tfor (const line of lines) {\n\t\t// Count passing test lines (e.g., \"test foo ... ok\")\n\t\tif (/^test\\s+.+\\s+\\.\\.\\.\\s+ok\\s*$/.test(line)) {\n\t\t\tpassingCount++;\n\t\t\tcontinue;\n\t\t}\n\t\t// Count ignored tests\n\t\tif (/^test\\s+.+\\s+\\.\\.\\.\\s+ignored\\s*$/.test(line)) {\n\t\t\tcontinue;\n\t\t}\n\t\t// Show test summary line\n\t\tif (/^test result:/.test(line)) {\n\t\t\tresult.push(line);\n\t\t\tcontinue;\n\t\t}\n\t\t// Keep failures, errors, and everything else\n\t\tif (passingCount > 0 && line === \"\") {\n\t\t\t// Add summary before blank line\n\t\t\tresult.push(` (${passingCount} passing tests omitted)`);\n\t\t\tpassingCount = 0;\n\t\t}\n\t\tresult.push(line);\n\t}\n\n\t// Handle case where output ends with passing tests\n\tif (passingCount > 0) {\n\t\tresult.push(` (${passingCount} passing tests omitted)`);\n\t}\n\n\treturn result.join(\"\\n\");\n}\n\n/**\n * Compress docker build output.\n * - Strip layer download progress\n * - Keep build steps and errors\n */\nfunction compressDockerBuild(output: string): string {\n\tconst lines = output.split(\"\\n\");\n\tconst result: string[] = [];\n\n\tfor (const line of lines) {\n\t\t// Skip download progress (e.g., \"Downloading layer...\")\n\t\tif (/^(Downloading|Pulling|Extracting|Waiting|Verifying)/.test(line)) {\n\t\t\tcontinue;\n\t\t}\n\t\t// Skip progress bars\n\t\tif (/[\\u2588\\u2591\\u2592]{10,}/.test(line)) {\n\t\t\tcontinue;\n\t\t}\n\t\t// Keep build steps (FROM, RUN, COPY, etc.) and errors\n\t\tresult.push(line);\n\t}\n\n\treturn result.join(\"\\n\");\n}\n\n/**\n * Compress jest/mocha test output.\n * - Collapse passing tests\n * - Keep failures\n */\nfunction compressJsTest(output: string): string {\n\tconst lines = output.split(\"\\n\");\n\tconst result: string[] = [];\n\tlet passingCount = 0;\n\n\tfor (const line of lines) {\n\t\t// Skip passing test indicators (✓, ✔, ○)\n\t\tif (/^\\s*[✓✔○●]\\s+/.test(line)) {\n\t\t\tpassingCount++;\n\t\t\tcontinue;\n\t\t}\n\t\t// Skip passing test lines (e.g., \" PASS src/foo.test.ts\")\n\t\tif (/^\\s*PASS\\s+/.test(line)) {\n\t\t\tpassingCount++;\n\t\t\tcontinue;\n\t\t}\n\t\t// Show test summary\n\t\tif (/^(Tests|Test Suites):/.test(line)) {\n\t\t\tresult.push(line);\n\t\t\tcontinue;\n\t\t}\n\t\t// Keep failures (×, ✗, FAIL) and everything else\n\t\tif (passingCount > 0 && (line.includes(\"FAIL\") || line.includes(\"×\") || line.includes(\"✗\"))) {\n\t\t\tresult.push(` (${passingCount} passing tests omitted)`);\n\t\t\tpassingCount = 0;\n\t\t}\n\t\tresult.push(line);\n\t}\n\n\tif (passingCount > 0) {\n\t\tresult.push(` (${passingCount} passing tests omitted)`);\n\t}\n\n\treturn result.join(\"\\n\");\n}\n\n/**\n * Compress go test output.\n * - Collapse passing tests\n * - Keep failures\n */\nfunction compressGoTest(output: string): string {\n\tconst lines = output.split(\"\\n\");\n\tconst result: string[] = [];\n\tlet passingCount = 0;\n\n\tfor (const line of lines) {\n\t\t// Skip passing test lines (e.g., \"--- PASS: TestFoo (0.00s)\")\n\t\tif (/^---\\s+PASS:/.test(line)) {\n\t\t\tpassingCount++;\n\t\t\tcontinue;\n\t\t}\n\t\t// Skip PASS lines\n\t\tif (/^PASS$/.test(line)) {\n\t\t\tcontinue;\n\t\t}\n\t\t// Show test summary\n\t\tif (/^(ok|FAIL)\\s+/.test(line)) {\n\t\t\tresult.push(line);\n\t\t\tcontinue;\n\t\t}\n\t\t// Keep failures and everything else\n\t\tif (passingCount > 0 && line.includes(\"FAIL\")) {\n\t\t\tresult.push(` (${passingCount} passing tests omitted)`);\n\t\t\tpassingCount = 0;\n\t\t}\n\t\tresult.push(line);\n\t}\n\n\tif (passingCount > 0) {\n\t\tresult.push(` (${passingCount} passing tests omitted)`);\n\t}\n\n\treturn result.join(\"\\n\");\n}\n\n/**\n * Apply command-specific compression based on the detected command.\n */\nfunction compressCommandSpecific(command: string, output: string): string {\n\tconst cmd = detectCommand(command);\n\n\tswitch (cmd) {\n\t\tcase \"npm\":\n\t\tcase \"yarn\":\n\t\tcase \"pnpm\":\n\t\t\t// Check if it's an install/add command\n\t\t\tif (/\\b(install|add|i)\\b/.test(command)) {\n\t\t\t\treturn compressNpmInstall(output);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"git\":\n\t\t\t// Check if it's a diff command\n\t\t\tif (/\\bdiff\\b/.test(command)) {\n\t\t\t\treturn compressGitDiff(output);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"cargo\":\n\t\t\t// Check if it's a test command\n\t\t\tif (/\\btest\\b/.test(command)) {\n\t\t\t\treturn compressCargoTest(output);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"docker\":\n\t\t\t// Check if it's a build command\n\t\t\tif (/\\bbuild\\b/.test(command)) {\n\t\t\t\treturn compressDockerBuild(output);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"jest\":\n\t\tcase \"mocha\":\n\t\tcase \"vitest\":\n\t\tcase \"pytest\":\n\t\t\treturn compressJsTest(output);\n\t\tcase \"go\":\n\t\t\t// Check if it's a test command\n\t\t\tif (/\\btest\\b/.test(command)) {\n\t\t\t\treturn compressGoTest(output);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\n\treturn output;\n}\n\n/**\n * Strip common noise patterns from any bash output.\n * This is applied to all commands regardless of detection.\n */\nfunction stripNoisePatterns(text: string): string {\n\treturn (\n\t\ttext\n\t\t\t// Strip npm warnings (keep errors)\n\t\t\t.replace(/^npm (warn|notice) .+$/gm, \"\")\n\t\t\t// Strip yarn warnings\n\t\t\t.replace(/^warning .+$/gm, \"\")\n\t\t\t// Strip pnpm warnings\n\t\t\t.replace(/^pnpm (warn|notice) .+$/gm, \"\")\n\t\t\t// Strip common shell warnings\n\t\t\t.replace(/^bash: .+ warning: .+$/gm, \"\")\n\t\t\t// Strip \"The command completed with non-zero exit status\" noise\n\t\t\t.replace(/^The command exited with exit code .+$/gm, \"\")\n\t);\n}\n\n/**\n * Apply all compression to a bash command output.\n * This is the main entry point for bash output compression.\n *\n * @param command - The bash command that was executed\n * @param output - The raw output from the command\n * @returns Compressed output (lossless)\n */\nexport function compressBashOutput(command: string, output: string): string {\n\t// Skip compression for small outputs (overhead > savings)\n\tif (Buffer.byteLength(output, \"utf-8\") < MIN_COMPRESSION_SIZE) {\n\t\treturn output;\n\t}\n\n\tlet result = output;\n\n\t// Phase 1: Strip noise patterns\n\tresult = stripNoisePatterns(result);\n\n\t// Phase 2: Command-specific compression\n\tresult = compressCommandSpecific(command, result);\n\n\t// Phase 3: General compression\n\tresult = compressGeneral(result);\n\n\treturn result;\n}\n\n/**\n * Apply compression to grep output.\n * This strips redundant context and normalizes output.\n */\nexport function compressGrepOutput(output: string): string {\n\tif (Buffer.byteLength(output, \"utf-8\") < MIN_COMPRESSION_SIZE) {\n\t\treturn output;\n\t}\n\treturn compressGeneral(output);\n}\n\n/**\n * Apply compression to read output.\n * This normalizes whitespace but preserves content.\n */\nexport function compressReadOutput(output: string): string {\n\t// For read, we only do light compression - no line collapsing\n\tif (Buffer.byteLength(output, \"utf-8\") < MIN_COMPRESSION_SIZE) {\n\t\treturn output;\n\t}\n\treturn stripTrailingWhitespace(output);\n}\n\n/**\n * Apply compression to find output.\n * This normalizes paths and removes duplicates.\n */\nexport function compressFindOutput(output: string): string {\n\tif (Buffer.byteLength(output, \"utf-8\") < MIN_COMPRESSION_SIZE) {\n\t\treturn output;\n\t}\n\treturn compressGeneral(output);\n}\n\n/**\n * Apply compression to ls output.\n * This normalizes formatting.\n */\nexport function compressLsOutput(output: string): string {\n\tif (Buffer.byteLength(output, \"utf-8\") < MIN_COMPRESSION_SIZE) {\n\t\treturn output;\n\t}\n\treturn compressGeneral(output);\n}\n"]}