@tyvm/knowhow 0.0.47 → 0.0.48

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 (459) hide show
  1. package/benchmarks/results/27b0a06/2025-09-27/xai/xai-grok-code-fast-1.json +2909 -0
  2. package/benchmarks/results/4057aed/2025-08-14/anthropic/anthropic-claude-sonnet-4-20250514.json +1671 -0
  3. package/jest.config.js +2 -2
  4. package/package.json +8 -3
  5. package/src/agents/base/base.ts +30 -24
  6. package/src/agents/patcher/patcher.ts +26 -5
  7. package/src/agents/tools/agentCall.ts +4 -2
  8. package/src/agents/tools/aiClient.ts +3 -11
  9. package/src/agents/tools/ast/astAppendNode.ts +90 -0
  10. package/src/agents/tools/ast/astDeleteNode.ts +88 -0
  11. package/src/agents/tools/ast/astEditNode.ts +95 -0
  12. package/src/agents/tools/ast/astGetPathForLine.ts +73 -0
  13. package/src/agents/tools/ast/astListPaths.ts +66 -0
  14. package/src/agents/tools/ast/index.ts +7 -0
  15. package/src/agents/tools/callPlugin.ts +8 -2
  16. package/src/agents/tools/embeddingSearch.ts +2 -1
  17. package/src/agents/tools/execCommand.ts +239 -94
  18. package/src/agents/tools/fileSearch.ts +15 -17
  19. package/src/agents/tools/index.ts +1 -0
  20. package/src/agents/tools/language/definitions.ts +10 -2
  21. package/src/agents/tools/language/index.ts +3 -2
  22. package/src/agents/tools/lintFile.ts +4 -2
  23. package/src/agents/tools/list.ts +203 -62
  24. package/src/agents/tools/patch.ts +48 -14
  25. package/src/agents/tools/readBlocks.ts +34 -0
  26. package/src/agents/tools/readFile.ts +23 -0
  27. package/src/agents/tools/stringReplace.ts +33 -9
  28. package/src/agents/tools/writeFile.ts +55 -0
  29. package/src/agents/tools/ycmd/server.ts +14 -4
  30. package/src/chat/CliChatService.ts +6 -1
  31. package/src/chat/modules/AgentModule.ts +107 -64
  32. package/src/chat/modules/AskModule.ts +0 -1
  33. package/src/chat/modules/SetupModule.ts +4 -4
  34. package/src/chat/modules/SystemModule.ts +28 -5
  35. package/src/chat/types.ts +2 -0
  36. package/src/chat-old.ts +2 -2
  37. package/src/clients/anthropic.ts +22 -1
  38. package/src/clients/openai.ts +1 -1
  39. package/src/clients/xai.ts +15 -5
  40. package/src/config.ts +17 -5
  41. package/src/dataset/diffs/generate.ts +2 -2
  42. package/src/dataset/diffs/jsonl.ts +0 -1
  43. package/src/embeddings.ts +6 -4
  44. package/src/index.ts +11 -5
  45. package/src/plugins/GitPlugin.ts +530 -0
  46. package/src/plugins/LinterPlugin.ts +89 -0
  47. package/src/plugins/PluginBase.ts +4 -2
  48. package/src/plugins/asana.ts +4 -2
  49. package/src/plugins/downloader/plugin.ts +5 -2
  50. package/src/plugins/embedding.ts +24 -4
  51. package/src/plugins/figma.ts +7 -3
  52. package/src/plugins/github.ts +4 -2
  53. package/src/plugins/jira.ts +4 -2
  54. package/src/plugins/language.ts +134 -27
  55. package/src/plugins/linear.ts +4 -2
  56. package/src/plugins/notion.ts +4 -2
  57. package/src/plugins/plugins.ts +27 -16
  58. package/src/plugins/tree-sitter/editor.ts +369 -0
  59. package/src/plugins/tree-sitter/lang-packs/index.ts +23 -0
  60. package/src/plugins/tree-sitter/lang-packs/java.ts +59 -0
  61. package/src/plugins/tree-sitter/lang-packs/javascript.ts +57 -0
  62. package/src/plugins/tree-sitter/lang-packs/python.ts +45 -0
  63. package/src/plugins/tree-sitter/lang-packs/types.ts +79 -0
  64. package/src/plugins/tree-sitter/lang-packs/typescript.ts +49 -0
  65. package/src/plugins/tree-sitter/parser.ts +444 -0
  66. package/src/plugins/tree-sitter/simple-paths.ts +467 -0
  67. package/src/plugins/types.ts +11 -0
  68. package/src/plugins/url.ts +5 -3
  69. package/src/plugins/vim.ts +8 -5
  70. package/src/processors/CustomVariables.ts +19 -7
  71. package/src/processors/TokenCompressor.ts +13 -13
  72. package/src/processors/ToolResponseCache.ts +15 -6
  73. package/src/services/EmbeddingService.ts +18 -9
  74. package/src/services/EventService.ts +80 -0
  75. package/src/services/Mcp.ts +5 -0
  76. package/src/services/S3.ts +4 -3
  77. package/src/services/Tools.ts +125 -53
  78. package/src/services/index.ts +16 -11
  79. package/src/services/types.ts +3 -3
  80. package/src/types.ts +7 -2
  81. package/src/worker.ts +14 -1
  82. package/test-comprehensive.ts +31 -0
  83. package/tests/clients/AIClient.test.ts +490 -0
  84. package/tests/manual/agent-events/run-test.ts +203 -0
  85. package/tests/{integration → manual/file-edits}/figma.test.ts +1 -1
  86. package/tests/{integration → manual/file-edits}/fileblocks/readwrite.test.ts +7 -3
  87. package/tests/{integration → manual/file-edits}/patching.test.ts +11 -8
  88. package/tests/plugins/language/languagePlugin-content-triggers.test.ts +332 -0
  89. package/tests/plugins/language/languagePlugin-integration.test.ts +456 -0
  90. package/tests/plugins/language/languagePlugin.test.ts +363 -0
  91. package/tests/processors/Base64ImageDetector.test.ts +403 -0
  92. package/tests/processors/CustomVariables.test.ts +430 -0
  93. package/tests/processors/HarmonyToolProcessor.test.ts +490 -0
  94. package/tests/processors/TokenCompressor.test.ts +391 -0
  95. package/tests/processors/ToolResponseCache.test.ts +688 -0
  96. package/tests/services/Tools.test.ts +1339 -0
  97. package/tests/test.spec.ts +162 -117
  98. package/tests/tree-sitter/editor.test.ts +113 -0
  99. package/tests/tree-sitter/invalid.test.ts +299 -0
  100. package/tests/tree-sitter/paths/common-edits.test.ts +564 -0
  101. package/tests/tree-sitter/paths/debug-exact-position.test.ts +44 -0
  102. package/tests/tree-sitter/paths/debug-line-indexing.test.ts +49 -0
  103. package/tests/tree-sitter/paths/debug-paths.test.ts +90 -0
  104. package/tests/tree-sitter/paths/paths.test.ts +170 -0
  105. package/tests/tree-sitter/paths/simple-paths.test.ts +367 -0
  106. package/tests/tree-sitter/sample-after.ts +48 -0
  107. package/tests/tree-sitter/sample-before.ts +25 -0
  108. package/tests/tree-sitter/test-files/completely-broken.ts +7 -0
  109. package/tests/tree-sitter/test-files/duplicate-braces.ts +39 -0
  110. package/tests/tree-sitter/test-files/invalid-nesting.ts +39 -0
  111. package/tests/tree-sitter/test-files/malformed-signature.ts +39 -0
  112. package/tests/tree-sitter/test-files/mismatched-parens.ts +39 -0
  113. package/tests/tree-sitter/test-files/missing-semicolon.ts +39 -0
  114. package/tests/tree-sitter/test-files/partially-broken.ts +20 -0
  115. package/tests/tree-sitter/test-files/specific-errors.ts +14 -0
  116. package/tests/tree-sitter/test-files/unclosed-string.ts +39 -0
  117. package/tests/tree-sitter/tree-sitter.test.ts +251 -0
  118. package/ts_build/package.json +8 -3
  119. package/ts_build/src/agents/base/base.d.ts +2 -2
  120. package/ts_build/src/agents/base/base.js +24 -20
  121. package/ts_build/src/agents/base/base.js.map +1 -1
  122. package/ts_build/src/agents/patcher/patcher.js +26 -5
  123. package/ts_build/src/agents/patcher/patcher.js.map +1 -1
  124. package/ts_build/src/agents/tools/agentCall.js +2 -1
  125. package/ts_build/src/agents/tools/agentCall.js.map +1 -1
  126. package/ts_build/src/agents/tools/aiClient.d.ts +7 -8
  127. package/ts_build/src/agents/tools/aiClient.js.map +1 -1
  128. package/ts_build/src/agents/tools/ast/astAppendNode.d.ts +1 -0
  129. package/ts_build/src/agents/tools/ast/astAppendNode.js +96 -0
  130. package/ts_build/src/agents/tools/ast/astAppendNode.js.map +1 -0
  131. package/ts_build/src/agents/tools/ast/astDeleteNode.d.ts +1 -0
  132. package/ts_build/src/agents/tools/ast/astDeleteNode.js +94 -0
  133. package/ts_build/src/agents/tools/ast/astDeleteNode.js.map +1 -0
  134. package/ts_build/src/agents/tools/ast/astEditNode.d.ts +1 -0
  135. package/ts_build/src/agents/tools/ast/astEditNode.js +96 -0
  136. package/ts_build/src/agents/tools/ast/astEditNode.js.map +1 -0
  137. package/ts_build/src/agents/tools/ast/astGetPathForLine.d.ts +1 -0
  138. package/ts_build/src/agents/tools/ast/astGetPathForLine.js +78 -0
  139. package/ts_build/src/agents/tools/ast/astGetPathForLine.js.map +1 -0
  140. package/ts_build/src/agents/tools/ast/astListPaths.d.ts +1 -0
  141. package/ts_build/src/agents/tools/ast/astListPaths.js +78 -0
  142. package/ts_build/src/agents/tools/ast/astListPaths.js.map +1 -0
  143. package/ts_build/src/agents/tools/ast/index.d.ts +5 -0
  144. package/ts_build/src/agents/tools/ast/index.js +14 -0
  145. package/ts_build/src/agents/tools/ast/index.js.map +1 -0
  146. package/ts_build/src/agents/tools/astAppendNode.d.ts +1 -0
  147. package/ts_build/src/agents/tools/astAppendNode.js +98 -0
  148. package/ts_build/src/agents/tools/astAppendNode.js.map +1 -0
  149. package/ts_build/src/agents/tools/astDeleteNode.d.ts +1 -0
  150. package/ts_build/src/agents/tools/astDeleteNode.js +95 -0
  151. package/ts_build/src/agents/tools/astDeleteNode.js.map +1 -0
  152. package/ts_build/src/agents/tools/astEditNode.d.ts +1 -0
  153. package/ts_build/src/agents/tools/astEditNode.js +98 -0
  154. package/ts_build/src/agents/tools/astEditNode.js.map +1 -0
  155. package/ts_build/src/agents/tools/astGetPathForLine.d.ts +1 -0
  156. package/ts_build/src/agents/tools/astGetPathForLine.js +89 -0
  157. package/ts_build/src/agents/tools/astGetPathForLine.js.map +1 -0
  158. package/ts_build/src/agents/tools/astListPaths.d.ts +1 -0
  159. package/ts_build/src/agents/tools/astListPaths.js +82 -0
  160. package/ts_build/src/agents/tools/astListPaths.js.map +1 -0
  161. package/ts_build/src/agents/tools/callPlugin.js +4 -2
  162. package/ts_build/src/agents/tools/callPlugin.js.map +1 -1
  163. package/ts_build/src/agents/tools/embeddingSearch.js +3 -2
  164. package/ts_build/src/agents/tools/embeddingSearch.js.map +1 -1
  165. package/ts_build/src/agents/tools/execCommand.d.ts +2 -2
  166. package/ts_build/src/agents/tools/execCommand.js +201 -67
  167. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  168. package/ts_build/src/agents/tools/fileSearch.d.ts +1 -1
  169. package/ts_build/src/agents/tools/fileSearch.js +11 -15
  170. package/ts_build/src/agents/tools/fileSearch.js.map +1 -1
  171. package/ts_build/src/agents/tools/github/index.d.ts +1 -1
  172. package/ts_build/src/agents/tools/index.d.ts +1 -0
  173. package/ts_build/src/agents/tools/index.js +1 -0
  174. package/ts_build/src/agents/tools/index.js.map +1 -1
  175. package/ts_build/src/agents/tools/language/definitions.js +11 -2
  176. package/ts_build/src/agents/tools/language/definitions.js.map +1 -1
  177. package/ts_build/src/agents/tools/language/index.js +4 -3
  178. package/ts_build/src/agents/tools/language/index.js.map +1 -1
  179. package/ts_build/src/agents/tools/lintFile.js +4 -2
  180. package/ts_build/src/agents/tools/lintFile.js.map +1 -1
  181. package/ts_build/src/agents/tools/list.js +185 -49
  182. package/ts_build/src/agents/tools/list.js.map +1 -1
  183. package/ts_build/src/agents/tools/patch.js +33 -10
  184. package/ts_build/src/agents/tools/patch.js.map +1 -1
  185. package/ts_build/src/agents/tools/readBlocks.js +23 -0
  186. package/ts_build/src/agents/tools/readBlocks.js.map +1 -1
  187. package/ts_build/src/agents/tools/readFile.js +14 -0
  188. package/ts_build/src/agents/tools/readFile.js.map +1 -1
  189. package/ts_build/src/agents/tools/stringReplace.js +19 -2
  190. package/ts_build/src/agents/tools/stringReplace.js.map +1 -1
  191. package/ts_build/src/agents/tools/writeFile.js +40 -0
  192. package/ts_build/src/agents/tools/writeFile.js.map +1 -1
  193. package/ts_build/src/agents/tools/ycmd/server.js +5 -0
  194. package/ts_build/src/agents/tools/ycmd/server.js.map +1 -1
  195. package/ts_build/src/chat/CliChatService.d.ts +1 -0
  196. package/ts_build/src/chat/CliChatService.js +6 -2
  197. package/ts_build/src/chat/CliChatService.js.map +1 -1
  198. package/ts_build/src/chat/modules/AgentModule.d.ts +5 -1
  199. package/ts_build/src/chat/modules/AgentModule.js +53 -31
  200. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  201. package/ts_build/src/chat/modules/AskModule.js.map +1 -1
  202. package/ts_build/src/chat/modules/SetupModule.js +4 -3
  203. package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
  204. package/ts_build/src/chat/modules/SystemModule.js +19 -4
  205. package/ts_build/src/chat/modules/SystemModule.js.map +1 -1
  206. package/ts_build/src/chat/modules/index.d.ts +5 -0
  207. package/ts_build/src/chat/modules/index.js +14 -0
  208. package/ts_build/src/chat/modules/index.js.map +1 -0
  209. package/ts_build/src/chat/types.d.ts +2 -0
  210. package/ts_build/src/chat-old.js +3 -3
  211. package/ts_build/src/chat-old.js.map +1 -1
  212. package/ts_build/src/clients/anthropic.d.ts +1 -0
  213. package/ts_build/src/clients/anthropic.js +22 -1
  214. package/ts_build/src/clients/anthropic.js.map +1 -1
  215. package/ts_build/src/clients/openai.js +1 -1
  216. package/ts_build/src/clients/openai.js.map +1 -1
  217. package/ts_build/src/clients/xai.d.ts +7 -0
  218. package/ts_build/src/clients/xai.js +13 -4
  219. package/ts_build/src/clients/xai.js.map +1 -1
  220. package/ts_build/src/config.js +14 -3
  221. package/ts_build/src/config.js.map +1 -1
  222. package/ts_build/src/dataset/diffs/generate.js +2 -2
  223. package/ts_build/src/dataset/diffs/generate.js.map +1 -1
  224. package/ts_build/src/dataset/diffs/jsonl.js.map +1 -1
  225. package/ts_build/src/embeddings.js +7 -9
  226. package/ts_build/src/embeddings.js.map +1 -1
  227. package/ts_build/src/index.js +10 -10
  228. package/ts_build/src/index.js.map +1 -1
  229. package/ts_build/src/plugins/GitPlugin.d.ts +39 -0
  230. package/ts_build/src/plugins/GitPlugin.js +439 -0
  231. package/ts_build/src/plugins/GitPlugin.js.map +1 -0
  232. package/ts_build/src/plugins/LinterPlugin.d.ts +15 -0
  233. package/ts_build/src/plugins/LinterPlugin.js +65 -0
  234. package/ts_build/src/plugins/LinterPlugin.js.map +1 -0
  235. package/ts_build/src/plugins/PluginBase.d.ts +4 -3
  236. package/ts_build/src/plugins/PluginBase.js +3 -3
  237. package/ts_build/src/plugins/PluginBase.js.map +1 -1
  238. package/ts_build/src/plugins/asana.d.ts +3 -1
  239. package/ts_build/src/plugins/asana.js +3 -2
  240. package/ts_build/src/plugins/asana.js.map +1 -1
  241. package/ts_build/src/plugins/downloader/plugin.d.ts +3 -1
  242. package/ts_build/src/plugins/downloader/plugin.js +3 -2
  243. package/ts_build/src/plugins/downloader/plugin.js.map +1 -1
  244. package/ts_build/src/plugins/embedding.d.ts +5 -1
  245. package/ts_build/src/plugins/embedding.js +15 -3
  246. package/ts_build/src/plugins/embedding.js.map +1 -1
  247. package/ts_build/src/plugins/figma.d.ts +3 -1
  248. package/ts_build/src/plugins/figma.js +28 -4
  249. package/ts_build/src/plugins/figma.js.map +1 -1
  250. package/ts_build/src/plugins/github.d.ts +3 -1
  251. package/ts_build/src/plugins/github.js +3 -2
  252. package/ts_build/src/plugins/github.js.map +1 -1
  253. package/ts_build/src/plugins/jira.d.ts +3 -1
  254. package/ts_build/src/plugins/jira.js +3 -2
  255. package/ts_build/src/plugins/jira.js.map +1 -1
  256. package/ts_build/src/plugins/language.d.ts +7 -4
  257. package/ts_build/src/plugins/language.js +85 -20
  258. package/ts_build/src/plugins/language.js.map +1 -1
  259. package/ts_build/src/plugins/linear.d.ts +3 -1
  260. package/ts_build/src/plugins/linear.js +3 -2
  261. package/ts_build/src/plugins/linear.js.map +1 -1
  262. package/ts_build/src/plugins/notion.d.ts +3 -1
  263. package/ts_build/src/plugins/notion.js +3 -2
  264. package/ts_build/src/plugins/notion.js.map +1 -1
  265. package/ts_build/src/plugins/plugins.d.ts +4 -3
  266. package/ts_build/src/plugins/plugins.js +24 -14
  267. package/ts_build/src/plugins/plugins.js.map +1 -1
  268. package/ts_build/src/plugins/tree-sitter/editor.d.ts +34 -0
  269. package/ts_build/src/plugins/tree-sitter/editor.js +218 -0
  270. package/ts_build/src/plugins/tree-sitter/editor.js.map +1 -0
  271. package/ts_build/src/plugins/tree-sitter/human-readable-paths-new.d.ts +29 -0
  272. package/ts_build/src/plugins/tree-sitter/human-readable-paths-new.js +538 -0
  273. package/ts_build/src/plugins/tree-sitter/human-readable-paths-new.js.map +1 -0
  274. package/ts_build/src/plugins/tree-sitter/human-readable-paths.d.ts +22 -0
  275. package/ts_build/src/plugins/tree-sitter/human-readable-paths.js +332 -0
  276. package/ts_build/src/plugins/tree-sitter/human-readable-paths.js.map +1 -0
  277. package/ts_build/src/plugins/tree-sitter/lang-packs/index.d.ts +8 -0
  278. package/ts_build/src/plugins/tree-sitter/lang-packs/index.js +26 -0
  279. package/ts_build/src/plugins/tree-sitter/lang-packs/index.js.map +1 -0
  280. package/ts_build/src/plugins/tree-sitter/lang-packs/java.d.ts +2 -0
  281. package/ts_build/src/plugins/tree-sitter/lang-packs/java.js +61 -0
  282. package/ts_build/src/plugins/tree-sitter/lang-packs/java.js.map +1 -0
  283. package/ts_build/src/plugins/tree-sitter/lang-packs/javascript.d.ts +2 -0
  284. package/ts_build/src/plugins/tree-sitter/lang-packs/javascript.js +59 -0
  285. package/ts_build/src/plugins/tree-sitter/lang-packs/javascript.js.map +1 -0
  286. package/ts_build/src/plugins/tree-sitter/lang-packs/python.d.ts +2 -0
  287. package/ts_build/src/plugins/tree-sitter/lang-packs/python.js +47 -0
  288. package/ts_build/src/plugins/tree-sitter/lang-packs/python.js.map +1 -0
  289. package/ts_build/src/plugins/tree-sitter/lang-packs/types.d.ts +43 -0
  290. package/ts_build/src/plugins/tree-sitter/lang-packs/types.js +3 -0
  291. package/ts_build/src/plugins/tree-sitter/lang-packs/types.js.map +1 -0
  292. package/ts_build/src/plugins/tree-sitter/lang-packs/typescript.d.ts +2 -0
  293. package/ts_build/src/plugins/tree-sitter/lang-packs/typescript.js +50 -0
  294. package/ts_build/src/plugins/tree-sitter/lang-packs/typescript.js.map +1 -0
  295. package/ts_build/src/plugins/tree-sitter/parser.d.ts +75 -0
  296. package/ts_build/src/plugins/tree-sitter/parser.js +306 -0
  297. package/ts_build/src/plugins/tree-sitter/parser.js.map +1 -0
  298. package/ts_build/src/plugins/tree-sitter/simple-paths.d.ts +22 -0
  299. package/ts_build/src/plugins/tree-sitter/simple-paths.js +332 -0
  300. package/ts_build/src/plugins/tree-sitter/simple-paths.js.map +1 -0
  301. package/ts_build/src/plugins/types.d.ts +10 -0
  302. package/ts_build/src/plugins/url.d.ts +3 -2
  303. package/ts_build/src/plugins/url.js +3 -2
  304. package/ts_build/src/plugins/url.js.map +1 -1
  305. package/ts_build/src/plugins/vim.d.ts +4 -2
  306. package/ts_build/src/plugins/vim.js +6 -8
  307. package/ts_build/src/plugins/vim.js.map +1 -1
  308. package/ts_build/src/processors/CustomVariables.js +12 -3
  309. package/ts_build/src/processors/CustomVariables.js.map +1 -1
  310. package/ts_build/src/processors/TokenCompressor.js +8 -11
  311. package/ts_build/src/processors/TokenCompressor.js.map +1 -1
  312. package/ts_build/src/processors/ToolResponseCache.d.ts +2 -2
  313. package/ts_build/src/processors/ToolResponseCache.js +12 -2
  314. package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
  315. package/ts_build/src/services/EmbeddingService.d.ts +10 -1
  316. package/ts_build/src/services/EmbeddingService.js +12 -12
  317. package/ts_build/src/services/EmbeddingService.js.map +1 -1
  318. package/ts_build/src/services/EventService.d.ts +7 -0
  319. package/ts_build/src/services/EventService.js +49 -0
  320. package/ts_build/src/services/EventService.js.map +1 -1
  321. package/ts_build/src/services/Mcp.js +8 -0
  322. package/ts_build/src/services/Mcp.js.map +1 -1
  323. package/ts_build/src/services/S3.js +4 -3
  324. package/ts_build/src/services/S3.js.map +1 -1
  325. package/ts_build/src/services/Tools.d.ts +1 -0
  326. package/ts_build/src/services/Tools.js +97 -35
  327. package/ts_build/src/services/Tools.js.map +1 -1
  328. package/ts_build/src/services/index.d.ts +4 -5
  329. package/ts_build/src/services/index.js +14 -9
  330. package/ts_build/src/services/index.js.map +1 -1
  331. package/ts_build/src/services/types.js +3 -3
  332. package/ts_build/src/services/types.js.map +1 -1
  333. package/ts_build/src/types.d.ts +7 -1
  334. package/ts_build/src/types.js +4 -0
  335. package/ts_build/src/types.js.map +1 -1
  336. package/ts_build/src/worker.js +12 -1
  337. package/ts_build/src/worker.js.map +1 -1
  338. package/ts_build/tests/clients/AIClient.test.d.ts +1 -0
  339. package/ts_build/tests/clients/AIClient.test.js +377 -0
  340. package/ts_build/tests/clients/AIClient.test.js.map +1 -0
  341. package/ts_build/tests/languagePlugin.test.js +217 -11
  342. package/ts_build/tests/languagePlugin.test.js.map +1 -1
  343. package/ts_build/tests/manual/agent-events/event-handler-reliability.test.d.ts +1 -0
  344. package/ts_build/tests/manual/agent-events/event-handler-reliability.test.js +315 -0
  345. package/ts_build/tests/manual/agent-events/event-handler-reliability.test.js.map +1 -0
  346. package/ts_build/tests/manual/agent-events/run-test.d.ts +2 -0
  347. package/ts_build/tests/manual/agent-events/run-test.js +148 -0
  348. package/ts_build/tests/manual/agent-events/run-test.js.map +1 -0
  349. package/ts_build/tests/manual/file-edits/figma.test.d.ts +1 -0
  350. package/ts_build/tests/manual/file-edits/figma.test.js +47 -0
  351. package/ts_build/tests/manual/file-edits/figma.test.js.map +1 -0
  352. package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.d.ts +1 -0
  353. package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js +100 -0
  354. package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js.map +1 -0
  355. package/ts_build/tests/manual/file-edits/patching.test.d.ts +1 -0
  356. package/ts_build/tests/manual/file-edits/patching.test.js +119 -0
  357. package/ts_build/tests/manual/file-edits/patching.test.js.map +1 -0
  358. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.d.ts +1 -0
  359. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +277 -0
  360. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +1 -0
  361. package/ts_build/tests/plugins/language/languagePlugin-integration.test.d.ts +1 -0
  362. package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +331 -0
  363. package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +1 -0
  364. package/ts_build/tests/plugins/language/languagePlugin.test.d.ts +1 -0
  365. package/ts_build/tests/plugins/language/languagePlugin.test.js +286 -0
  366. package/ts_build/tests/plugins/language/languagePlugin.test.js.map +1 -0
  367. package/ts_build/tests/processors/Base64ImageDetector.test.d.ts +1 -0
  368. package/ts_build/tests/processors/Base64ImageDetector.test.js +351 -0
  369. package/ts_build/tests/processors/Base64ImageDetector.test.js.map +1 -0
  370. package/ts_build/tests/processors/CustomVariables.test.d.ts +1 -0
  371. package/ts_build/tests/processors/CustomVariables.test.js +351 -0
  372. package/ts_build/tests/processors/CustomVariables.test.js.map +1 -0
  373. package/ts_build/tests/processors/HarmonyToolProcessor.test.d.ts +1 -0
  374. package/ts_build/tests/processors/HarmonyToolProcessor.test.js +382 -0
  375. package/ts_build/tests/processors/HarmonyToolProcessor.test.js.map +1 -0
  376. package/ts_build/tests/processors/TokenCompressor.test.d.ts +1 -0
  377. package/ts_build/tests/processors/TokenCompressor.test.js +300 -0
  378. package/ts_build/tests/processors/TokenCompressor.test.js.map +1 -0
  379. package/ts_build/tests/processors/ToolResponseCache.test.d.ts +1 -0
  380. package/ts_build/tests/processors/ToolResponseCache.test.js +539 -0
  381. package/ts_build/tests/processors/ToolResponseCache.test.js.map +1 -0
  382. package/ts_build/tests/services/Plugins/plugin-event-integration.test.d.ts +1 -0
  383. package/ts_build/tests/services/Plugins/plugin-event-integration.test.js +232 -0
  384. package/ts_build/tests/services/Plugins/plugin-event-integration.test.js.map +1 -0
  385. package/ts_build/tests/services/Tools.test.d.ts +1 -0
  386. package/ts_build/tests/services/Tools.test.js +1059 -0
  387. package/ts_build/tests/services/Tools.test.js.map +1 -0
  388. package/ts_build/tests/test.spec.js +110 -68
  389. package/ts_build/tests/test.spec.js.map +1 -1
  390. package/ts_build/tests/tree-sitter/editor.test.d.ts +1 -0
  391. package/ts_build/tests/tree-sitter/editor.test.js +85 -0
  392. package/ts_build/tests/tree-sitter/editor.test.js.map +1 -0
  393. package/ts_build/tests/tree-sitter/invalid.test.d.ts +1 -0
  394. package/ts_build/tests/tree-sitter/invalid.test.js +198 -0
  395. package/ts_build/tests/tree-sitter/invalid.test.js.map +1 -0
  396. package/ts_build/tests/tree-sitter/paths/common-edits.test.d.ts +1 -0
  397. package/ts_build/tests/tree-sitter/paths/common-edits.test.js +347 -0
  398. package/ts_build/tests/tree-sitter/paths/common-edits.test.js.map +1 -0
  399. package/ts_build/tests/tree-sitter/paths/debug-exact-position.test.d.ts +1 -0
  400. package/ts_build/tests/tree-sitter/paths/debug-exact-position.test.js +35 -0
  401. package/ts_build/tests/tree-sitter/paths/debug-exact-position.test.js.map +1 -0
  402. package/ts_build/tests/tree-sitter/paths/debug-line-indexing.test.d.ts +1 -0
  403. package/ts_build/tests/tree-sitter/paths/debug-line-indexing.test.js +38 -0
  404. package/ts_build/tests/tree-sitter/paths/debug-line-indexing.test.js.map +1 -0
  405. package/ts_build/tests/tree-sitter/paths/debug-paths.test.d.ts +1 -0
  406. package/ts_build/tests/tree-sitter/paths/debug-paths.test.js +74 -0
  407. package/ts_build/tests/tree-sitter/paths/debug-paths.test.js.map +1 -0
  408. package/ts_build/tests/tree-sitter/paths/human-readable-paths.test.d.ts +1 -0
  409. package/ts_build/tests/tree-sitter/paths/human-readable-paths.test.js +302 -0
  410. package/ts_build/tests/tree-sitter/paths/human-readable-paths.test.js.map +1 -0
  411. package/ts_build/tests/tree-sitter/paths/paths.test.d.ts +1 -0
  412. package/ts_build/tests/tree-sitter/paths/paths.test.js +116 -0
  413. package/ts_build/tests/tree-sitter/paths/paths.test.js.map +1 -0
  414. package/ts_build/tests/tree-sitter/paths/simple-paths.test.d.ts +1 -0
  415. package/ts_build/tests/tree-sitter/paths/simple-paths.test.js +302 -0
  416. package/ts_build/tests/tree-sitter/paths/simple-paths.test.js.map +1 -0
  417. package/ts_build/tests/tree-sitter/sample-after.d.ts +11 -0
  418. package/ts_build/tests/tree-sitter/sample-after.js +44 -0
  419. package/ts_build/tests/tree-sitter/sample-after.js.map +1 -0
  420. package/ts_build/tests/tree-sitter/sample-before.d.ts +9 -0
  421. package/ts_build/tests/tree-sitter/sample-before.js +28 -0
  422. package/ts_build/tests/tree-sitter/sample-before.js.map +1 -0
  423. package/ts_build/tests/tree-sitter/test-files/completely-broken.d.ts +2 -0
  424. package/ts_build/tests/tree-sitter/test-files/completely-broken.js +17 -0
  425. package/ts_build/tests/tree-sitter/test-files/completely-broken.js.map +1 -0
  426. package/ts_build/tests/tree-sitter/test-files/duplicate-braces.d.ts +8 -0
  427. package/ts_build/tests/tree-sitter/test-files/duplicate-braces.js +38 -0
  428. package/ts_build/tests/tree-sitter/test-files/duplicate-braces.js.map +1 -0
  429. package/ts_build/tests/tree-sitter/test-files/invalid-nesting.d.ts +8 -0
  430. package/ts_build/tests/tree-sitter/test-files/invalid-nesting.js +38 -0
  431. package/ts_build/tests/tree-sitter/test-files/invalid-nesting.js.map +1 -0
  432. package/ts_build/tests/tree-sitter/test-files/malformed-signature.d.ts +8 -0
  433. package/ts_build/tests/tree-sitter/test-files/malformed-signature.js +38 -0
  434. package/ts_build/tests/tree-sitter/test-files/malformed-signature.js.map +1 -0
  435. package/ts_build/tests/tree-sitter/test-files/mismatched-parens.d.ts +10 -0
  436. package/ts_build/tests/tree-sitter/test-files/mismatched-parens.js +38 -0
  437. package/ts_build/tests/tree-sitter/test-files/mismatched-parens.js.map +1 -0
  438. package/ts_build/tests/tree-sitter/test-files/missing-semicolon.d.ts +8 -0
  439. package/ts_build/tests/tree-sitter/test-files/missing-semicolon.js +38 -0
  440. package/ts_build/tests/tree-sitter/test-files/missing-semicolon.js.map +1 -0
  441. package/ts_build/tests/tree-sitter/test-files/partially-broken.d.ts +6 -0
  442. package/ts_build/tests/tree-sitter/test-files/partially-broken.js +20 -0
  443. package/ts_build/tests/tree-sitter/test-files/partially-broken.js.map +1 -0
  444. package/ts_build/tests/tree-sitter/test-files/specific-errors.d.ts +7 -0
  445. package/ts_build/tests/tree-sitter/test-files/specific-errors.js +14 -0
  446. package/ts_build/tests/tree-sitter/test-files/specific-errors.js.map +1 -0
  447. package/ts_build/tests/tree-sitter/test-files/unclosed-string.d.ts +8 -0
  448. package/ts_build/tests/tree-sitter/test-files/unclosed-string.js +38 -0
  449. package/ts_build/tests/tree-sitter/test-files/unclosed-string.js.map +1 -0
  450. package/ts_build/tests/tree-sitter/tree-sitter.test.d.ts +1 -0
  451. package/ts_build/tests/tree-sitter/tree-sitter.test.js +185 -0
  452. package/ts_build/tests/tree-sitter/tree-sitter.test.js.map +1 -0
  453. package/tsconfig.json +2 -1
  454. package/tests/languagePlugin.test.ts +0 -74
  455. /package/src/chat/modules/{index.js → index.ts} +0 -0
  456. /package/tests/{integration → manual/file-edits}/patching/input.txt +0 -0
  457. /package/tests/{integration → manual/file-edits}/patching/output.txt +0 -0
  458. /package/tests/{integration → manual/file-edits}/patching/patch.txt +0 -0
  459. /package/tests/{integration → manual/file-edits}/patching/unseen.txt +0 -0
package/jest.config.js CHANGED
@@ -12,8 +12,8 @@ module.exports = {
12
12
  ],
13
13
  },
14
14
  testEnvironment: 'node',
15
- testRegex: '/tests/.*\.(test|spec)?\.(ts|tsx|js)$',
15
+ testRegex: '/tests/.*\.(test|spec)\.(ts|tsx|js)$',
16
16
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
17
17
  modulePathIgnorePatterns: ["ts_build", "benchmarks"],
18
- testPathIgnorePatterns: ["<rootDir>/benchmarks/"]
18
+ testPathIgnorePatterns: ["<rootDir>/benchmarks/", "<rootDir>/tests/manual/"],
19
19
  };
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@tyvm/knowhow",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "description": "ai cli with plugins and agents",
5
5
  "main": "ts_build/src/index.js",
6
6
  "bin": {
7
7
  "knowhow": "ts_build/src/cli.js"
8
8
  },
9
9
  "scripts": {
10
- "test": "jest --detectOpenHandles --forceExit --testTimeout 300000",
10
+ "test": "jest --testTimeout 300000",
11
11
  "test:debug": "node --inspect-brk ../../node_modules/jest/bin/jest.js --detectOpenHandles --forceExit --testTimeout 300000",
12
12
  "compile": "tsc",
13
13
  "start": "npm run compile && node ts_build/src/server/index.js",
@@ -41,7 +41,7 @@
41
41
  "@anthropic-ai/sdk": "^0.39.0",
42
42
  "@aws-sdk/client-s3": "^3.588.0",
43
43
  "@google/genai": "^0.14.1",
44
- "@inquirer/editor": "^1.2.13",
44
+ "@inquirer/editor": "^4.2.18",
45
45
  "@linear/sdk": "^12.0.0",
46
46
  "@modelcontextprotocol/sdk": "^1.13.3",
47
47
  "@notionhq/client": "^2.2.14",
@@ -56,11 +56,13 @@
56
56
  "express": "^4.19.2",
57
57
  "figma-js": "^1.16.1-0",
58
58
  "gitignore-to-glob": "^0.3.0",
59
+ "glob": "11.0.3",
59
60
  "ink": "^6.0.1",
60
61
  "isolated-vm": "^5.0.4",
61
62
  "jira-client": "^8.2.2",
62
63
  "marked": "^10.0.0",
63
64
  "marked-terminal": "^6.2.0",
65
+ "minimatch": "^10.0.3",
64
66
  "morgan": "^1.10.0",
65
67
  "node-fetch": "^3.2.3",
66
68
  "node-jq": "^6.0.1",
@@ -77,6 +79,9 @@
77
79
  "puppeteer-extra-plugin-stealth": "^2.11.2",
78
80
  "react": "^19.1.0",
79
81
  "source-map-support": "^0.5.21",
82
+ "tree-sitter": "^0.21.1",
83
+ "tree-sitter-javascript": "^0.23.1",
84
+ "tree-sitter-typescript": "^0.23.1",
80
85
  "typescript": "^4.6.3",
81
86
  "ws": "^8.18.1",
82
87
  "youtube-dl-exec": "^2.5.5",
@@ -55,6 +55,7 @@ export abstract class BaseAgent implements IAgent {
55
55
  protected pendingUserMessages = [] as Message[];
56
56
  protected taskBreakdown = "";
57
57
  protected summaries = [] as string[];
58
+ protected currentTaskId: string | null = null;
58
59
 
59
60
  public agentEvents = new EventEmitter();
60
61
  public eventTypes = {
@@ -87,6 +88,15 @@ export abstract class BaseAgent implements IAgent {
87
88
  if (!this.events) {
88
89
  throw new Error("EventService is required for BaseAgent");
89
90
  }
91
+
92
+ // Subscribe to "agent:msg" events for dynamic context loading
93
+ this.events.on("agent:msg", (eventData: any) => {
94
+ const message = {
95
+ role: "user",
96
+ content: JSON.stringify(eventData),
97
+ } as Message;
98
+ this.addPendingUserMessage(message);
99
+ });
90
100
  }
91
101
 
92
102
  setMaxTurns(maxTurns: number | null) {
@@ -101,7 +111,7 @@ export abstract class BaseAgent implements IAgent {
101
111
  this.maxRunTimeMs = maxRunTimeMs;
102
112
  }
103
113
 
104
- newTask() {
114
+ newTask(taskId?: string) {
105
115
  this.currentThread = 0;
106
116
  this.threads = [];
107
117
  this.taskBreakdown = "";
@@ -110,6 +120,13 @@ export abstract class BaseAgent implements IAgent {
110
120
  this.status = "in_progress";
111
121
  this.turnCount = 0;
112
122
  this.startTimeMs = Date.now();
123
+ this.currentTaskId = taskId || this.startTimeMs.toString();
124
+
125
+ // Emit event for plugin integration
126
+ const id = taskId || this.startTimeMs.toString();
127
+ this.events.emit("agent:newTask", {
128
+ taskId: id,
129
+ });
113
130
  }
114
131
 
115
132
  register() {
@@ -143,6 +160,7 @@ export abstract class BaseAgent implements IAgent {
143
160
 
144
161
  setModel(value: string) {
145
162
  this.modelName = value;
163
+ this.client = null; // Reset client to force re-fetch
146
164
  }
147
165
 
148
166
  getProvider() {
@@ -151,6 +169,7 @@ export abstract class BaseAgent implements IAgent {
151
169
 
152
170
  setProvider(value: keyof typeof Clients.clients) {
153
171
  this.provider = value;
172
+ this.client = null; // Reset client to force re-fetch
154
173
  }
155
174
 
156
175
  getClient() {
@@ -416,27 +435,6 @@ export abstract class BaseAgent implements IAgent {
416
435
  });
417
436
  }
418
437
 
419
- async resume(resumeReason: string) {
420
- const reason = resumeReason ? `Reason for resuming: ${resumeReason}` : "";
421
-
422
- // Create resume prompt
423
- const resumePrompt = `We are resuming a previously started task. Here's the context:
424
- ORIGINAL REQUEST:
425
- ${this.taskBreakdown}
426
-
427
- LAST Progress State:
428
- ${JSON.stringify(this.threads[this.currentThread], null, 2)}
429
-
430
- Please continue from where you left off and complete the original request.
431
- ${reason}
432
-
433
- `;
434
-
435
- const lastThread = this.threads[this.currentThread] || [];
436
- this.status = "in_progress";
437
- this.call(resumePrompt, lastThread);
438
- }
439
-
440
438
  async kill() {
441
439
  console.log("Killing agent");
442
440
  this.agentEvents.emit(this.eventTypes.kill, this);
@@ -564,6 +562,14 @@ ${reason}
564
562
  );
565
563
 
566
564
  if (finalMessage) {
565
+ // Emit task completion event for plugins (like GitPlugin)
566
+ this.events.emit("agent:taskComplete", {
567
+ taskId:
568
+ this.currentTaskId ||
569
+ this.startTimeMs?.toString() ||
570
+ Date.now().toString(),
571
+ result: finalMessage.content || "Done",
572
+ });
567
573
  const doneMsg = finalMessage.content || "Done";
568
574
  this.agentEvents.emit(this.eventTypes.done, doneMsg);
569
575
  this.status = this.eventTypes.done;
@@ -620,7 +626,7 @@ ${reason}
620
626
 
621
627
  if (
622
628
  this.getMessagesLength(messages) > compressThreshold &&
623
- messages.length > 10
629
+ messages.length > 20
624
630
  ) {
625
631
  const taskBreakdown = await this.getTaskBreakdown(messages);
626
632
  console.log(
@@ -702,7 +708,7 @@ ${reason}
702
708
 
703
709
  addPendingUserMessage(message: Message) {
704
710
  if (this.status === this.eventTypes.done) {
705
- this.resume(JSON.stringify(message.content));
711
+ console.warn("Agent is done, cannot take more messages");
706
712
  } else {
707
713
  this.pendingUserMessages.push(message);
708
714
  }
@@ -79,11 +79,9 @@ export class PatchingAgent extends BaseAgent {
79
79
  super(context);
80
80
 
81
81
  this.setModelPreferences([
82
- { model: Models.anthropic.Sonnet4, provider: "anthropic" },
83
- {
84
- model: Models.openai.GPT_41_Mini,
85
- provider: "openai",
86
- },
82
+ { model: Models.anthropic.Sonnet4_5, provider: "anthropic" },
83
+ { model: Models.xai.GrokCodeFast, provider: "xai" },
84
+ { model: Models.openai.GPT_5, provider: "openai" },
87
85
  ]);
88
86
  }
89
87
 
@@ -102,6 +100,29 @@ export class PatchingAgent extends BaseAgent {
102
100
  This helps ensure accurate modifications and can suggest fixes for compilation errors.
103
101
 
104
102
  IF you fail twice to patch a file, you may switch using writeFileChunk to rewrite the whole file.
103
+
104
+ If you need to know about a type, you should use the ycmd completion tool to discovery the properties, and fallback to reading the source files if the ycmd tools are not available.
105
+
106
+ # Debugging Workflow
107
+ If a build or test command fails due to compilation errors:
108
+
109
+ ALWAYS start by running ycmdDiagnostics on the file with errors to get a structured list of issues.
110
+
111
+ Address the errors one at a time, from top to bottom.
112
+
113
+ For each error, use ycmdGoTo to find the correct definition or readFile on the relevant source file to understand the correct implementation.
114
+
115
+ If an error is related to properties not being named correctly, you can use ycmdCompletion to get suggestions for the correct property or method names.
116
+
117
+ Apply a small, targeted patch to fix only that single error.
118
+
119
+ After every 2-3 fixes, run ycmdDiagnostics again to confirm progress.
120
+
121
+ # Test Writing Workflow
122
+ When writing tests, you proceed incrementally, writing one test, verifying it compiles and works before moving on to the next test.
123
+ You ALWAYS get to a stable state with tests compiling / running before adding the next test.
124
+ When writing tests, you never change the source code to pass the test, you always change the test to match the existing source code.
125
+
105
126
  `,
106
127
  },
107
128
  { role: "user", content: userInput },
@@ -1,10 +1,12 @@
1
1
  import { getConfig } from "../../config";
2
- import { ToolsService } from "../../services";
2
+ import { services, ToolsService } from "../../services";
3
3
 
4
4
  export async function agentCall(agentName: string, userInput: string) {
5
5
  return new Promise(async (resolve, reject) => {
6
6
  const config = await getConfig();
7
- const toolService = this as ToolsService;
7
+ const toolService = (
8
+ this instanceof ToolsService ? this : services().Tools
9
+ ) as ToolsService;
8
10
 
9
11
  const { Events, Plugins } = toolService.getContext();
10
12
 
@@ -9,7 +9,6 @@ import {
9
9
  import { services } from "../../services";
10
10
 
11
11
  export function createAiCompletion(
12
- this: ToolsService,
13
12
  provider: string,
14
13
  options: CompletionOptions
15
14
  ): Promise<CompletionResponse> {
@@ -29,7 +28,6 @@ export function createAiCompletion(
29
28
  }
30
29
 
31
30
  export function createEmbedding(
32
- this: ToolsService,
33
31
  provider: string,
34
32
  options: EmbeddingOptions
35
33
  ): Promise<EmbeddingResponse> {
@@ -49,7 +47,6 @@ export function createEmbedding(
49
47
  }
50
48
 
51
49
  export async function listModelsForProvider(
52
- this: ToolsService,
53
50
  provider: string
54
51
  ): Promise<string[]> {
55
52
  // Get context from bound ToolsService
@@ -68,7 +65,6 @@ export async function listModelsForProvider(
68
65
  }
69
66
 
70
67
  export async function listAllModels(
71
- this: ToolsService
72
68
  ): Promise<Record<string, string[]>> {
73
69
  // Get context from bound ToolsService
74
70
  const toolService = (
@@ -85,7 +81,7 @@ export async function listAllModels(
85
81
  return contextClients.listAllModels();
86
82
  }
87
83
 
88
- export async function listAllProviders(this: ToolsService): Promise<string[]> {
84
+ export async function listAllProviders(): Promise<string[]> {
89
85
  // Get context from bound ToolsService
90
86
  const toolService = (
91
87
  this instanceof ToolsService ? this : services().Tools
@@ -101,9 +97,7 @@ export async function listAllProviders(this: ToolsService): Promise<string[]> {
101
97
  return contextClients.listAllProviders();
102
98
  }
103
99
 
104
- export async function listAllCompletionModels(
105
- this: ToolsService
106
- ): Promise<Record<string, string[]>> {
100
+ export async function listAllCompletionModels(): Promise<Record<string, string[]>> {
107
101
  // Get context from bound ToolsService
108
102
  const toolService = (
109
103
  this instanceof ToolsService ? this : services().Tools
@@ -119,9 +113,7 @@ export async function listAllCompletionModels(
119
113
  return contextClients.listAllCompletionModels();
120
114
  }
121
115
 
122
- export async function listAllEmbeddingModels(
123
- this: ToolsService
124
- ): Promise<Record<string, string[]>> {
116
+ export async function listAllEmbeddingModels(): Promise<Record<string, string[]>> {
125
117
  // Get context from bound ToolsService
126
118
  const toolService = (
127
119
  this instanceof ToolsService ? this : services().Tools
@@ -0,0 +1,90 @@
1
+ import * as fs from "fs";
2
+ import { fileExists } from "../../../utils";
3
+ import { services, ToolsService } from "../../../services";
4
+ import { LanguageAgnosticParser } from "../../../plugins/tree-sitter/parser";
5
+ import { TreeEditor } from "../../../plugins/tree-sitter/editor";
6
+
7
+ /**
8
+ * Append a child node to a specific path in a file using tree-sitter AST parsing
9
+ */
10
+ export async function astAppendNode(filePath: string, parentPath: string, newContent: string): Promise<string> {
11
+ // Get context from bound ToolsService
12
+ const toolService = (
13
+ this instanceof ToolsService ? this : services().Tools
14
+ ) as ToolsService;
15
+
16
+ const context = toolService.getContext();
17
+
18
+ const exists = await fileExists(filePath);
19
+ if (!exists) {
20
+ throw new Error(`File not found: ${filePath}`);
21
+ }
22
+
23
+ // Read original content for event emission
24
+ let originalContent = "";
25
+ try {
26
+ originalContent = fs.readFileSync(filePath, "utf8");
27
+ } catch (error) {
28
+ throw new Error(`Failed to read file ${filePath}: ${error.message}`);
29
+ }
30
+
31
+ // Emit pre-edit blocking event
32
+ if (context.Events) {
33
+ await context.Events.emitBlocking("file:pre-edit", {
34
+ filePath,
35
+ operation: "ast-append-node",
36
+ content: newContent,
37
+ originalContent,
38
+ astParentPath: parentPath,
39
+ });
40
+ }
41
+
42
+ try {
43
+ if (!LanguageAgnosticParser.supportsFile(filePath)) {
44
+ throw new Error(`Unsupported file type for AST parsing: ${filePath}`);
45
+ }
46
+
47
+ const parser = LanguageAgnosticParser.createParserForFile(filePath);
48
+ const editor = new TreeEditor(parser, originalContent);
49
+ const updatedEditor = editor.appendChild(parentPath, newContent);
50
+ const updatedContent = updatedEditor.getCurrentText();
51
+
52
+ // Write the updated content back to the file
53
+ fs.writeFileSync(filePath, updatedContent, "utf8");
54
+
55
+ // Emit post-edit blocking event (only on success)
56
+ let eventResults: any[] = [];
57
+ if (context.Events) {
58
+ eventResults = await context.Events.emitBlocking("file:post-edit", {
59
+ filePath,
60
+ operation: "ast-append-node",
61
+ content: newContent,
62
+ originalContent,
63
+ updatedContent,
64
+ astParentPath: parentPath,
65
+ success: true,
66
+ });
67
+ }
68
+
69
+ const result = {
70
+ file: filePath,
71
+ parentPath,
72
+ action: "appendChild",
73
+ success: true,
74
+ message: `Successfully appended child node to path: ${parentPath}`,
75
+ };
76
+
77
+ // Format event results
78
+ let eventResultsText = "";
79
+ if (eventResults && eventResults.length > 0) {
80
+ eventResultsText =
81
+ "\n\nAdditional Information:\n" +
82
+ JSON.stringify(eventResults, null, 2);
83
+ }
84
+
85
+ return JSON.stringify(result, null, 2) + eventResultsText;
86
+ } catch (error: any) {
87
+ // Do NOT emit post-edit event on error
88
+ throw new Error(`Failed to append node in ${filePath}: ${error.message}`);
89
+ }
90
+ }
@@ -0,0 +1,88 @@
1
+ import * as fs from "fs";
2
+ import { fileExists } from "../../../utils";
3
+ import { services, ToolsService } from "../../../services";
4
+ import { LanguageAgnosticParser } from "../../../plugins/tree-sitter/parser";
5
+ import { TreeEditor } from "../../../plugins/tree-sitter/editor";
6
+
7
+ /**
8
+ * Delete a node at a specific path in a file using tree-sitter AST parsing
9
+ */
10
+ export async function astDeleteNode(filePath: string, path: string): Promise<string> {
11
+ // Get context from bound ToolsService
12
+ const toolService = (
13
+ this instanceof ToolsService ? this : services().Tools
14
+ ) as ToolsService;
15
+
16
+ const context = toolService.getContext();
17
+
18
+ const exists = await fileExists(filePath);
19
+ if (!exists) {
20
+ throw new Error(`File not found: ${filePath}`);
21
+ }
22
+
23
+ // Read original content for event emission
24
+ let originalContent = "";
25
+ try {
26
+ originalContent = fs.readFileSync(filePath, "utf8");
27
+ } catch (error) {
28
+ throw new Error(`Failed to read file ${filePath}: ${error.message}`);
29
+ }
30
+
31
+ // Emit pre-edit blocking event
32
+ if (context.Events) {
33
+ await context.Events.emitBlocking("file:pre-edit", {
34
+ filePath,
35
+ operation: "ast-delete-node",
36
+ originalContent,
37
+ astPath: path,
38
+ });
39
+ }
40
+
41
+ try {
42
+ if (!LanguageAgnosticParser.supportsFile(filePath)) {
43
+ throw new Error(`Unsupported file type for AST parsing: ${filePath}`);
44
+ }
45
+
46
+ const parser = LanguageAgnosticParser.createParserForFile(filePath);
47
+ const editor = new TreeEditor(parser, originalContent);
48
+ const updatedEditor = editor.deleteNodeByPath(path);
49
+ const updatedContent = updatedEditor.getCurrentText();
50
+
51
+ // Write the updated content back to the file
52
+ fs.writeFileSync(filePath, updatedContent, "utf8");
53
+
54
+ // Emit post-edit blocking event (only on success)
55
+ let eventResults: any[] = [];
56
+ if (context.Events) {
57
+ eventResults = await context.Events.emitBlocking("file:post-edit", {
58
+ filePath,
59
+ operation: "ast-delete-node",
60
+ originalContent,
61
+ updatedContent,
62
+ astPath: path,
63
+ success: true,
64
+ });
65
+ }
66
+
67
+ const result = {
68
+ file: filePath,
69
+ path,
70
+ action: "delete",
71
+ success: true,
72
+ message: `Successfully deleted node at path: ${path}`,
73
+ };
74
+
75
+ // Format event results
76
+ let eventResultsText = "";
77
+ if (eventResults && eventResults.length > 0) {
78
+ eventResultsText =
79
+ "\n\nAdditional Information:\n" +
80
+ JSON.stringify(eventResults, null, 2);
81
+ }
82
+
83
+ return JSON.stringify(result, null, 2) + eventResultsText;
84
+ } catch (error: any) {
85
+ // Do NOT emit post-edit event on error
86
+ throw new Error(`Failed to delete node in ${filePath}: ${error.message}`);
87
+ }
88
+ }
@@ -0,0 +1,95 @@
1
+ import * as fs from "fs";
2
+ import { fileExists } from "../../../utils";
3
+ import { services, ToolsService } from "../../../services";
4
+ import { LanguageAgnosticParser } from "../../../plugins/tree-sitter/parser";
5
+ import { TreeEditor } from "../../../plugins/tree-sitter/editor";
6
+
7
+ /**
8
+ * Update a node at a specific path in a file using tree-sitter AST parsing
9
+ */
10
+ export async function astEditNode(
11
+ filePath: string,
12
+ path: string,
13
+ newContent: string
14
+ ): Promise<string> {
15
+ // Get context from bound ToolsService
16
+ const toolService = (
17
+ this instanceof ToolsService ? this : services().Tools
18
+ ) as ToolsService;
19
+
20
+ const context = toolService.getContext();
21
+
22
+ const exists = await fileExists(filePath);
23
+ if (!exists) {
24
+ throw new Error(`File not found: ${filePath}`);
25
+ }
26
+
27
+ // Read original content for event emission
28
+ let originalContent = "";
29
+ try {
30
+ originalContent = fs.readFileSync(filePath, "utf8");
31
+ } catch (error) {
32
+ throw new Error(`Failed to read file ${filePath}: ${error.message}`);
33
+ }
34
+
35
+ // Emit pre-edit blocking event
36
+ if (context.Events) {
37
+ await context.Events.emitBlocking("file:pre-edit", {
38
+ filePath,
39
+ operation: "ast-edit-node",
40
+ content: newContent,
41
+ originalContent,
42
+ astPath: path,
43
+ });
44
+ }
45
+
46
+ try {
47
+ if (!LanguageAgnosticParser.supportsFile(filePath)) {
48
+ throw new Error(`Unsupported file type for AST parsing: ${filePath}`);
49
+ }
50
+
51
+ const parser = LanguageAgnosticParser.createParserForFile(filePath);
52
+ const editor = new TreeEditor(parser, originalContent);
53
+ const updatedEditor = editor.updateNodeByPath(path, newContent);
54
+ const updatedContent = updatedEditor.getCurrentText();
55
+
56
+ // Write the updated content back to the file
57
+ fs.writeFileSync(filePath, updatedContent, "utf8");
58
+
59
+ // Emit post-edit blocking event
60
+ let eventResults: any[] = [];
61
+ if (context.Events) {
62
+ eventResults = await context.Events.emitBlocking("file:post-edit", {
63
+ filePath,
64
+ operation: "ast-edit-node",
65
+ content: newContent,
66
+ originalContent,
67
+ updatedContent,
68
+ astPath: path,
69
+ success: true,
70
+ });
71
+ }
72
+
73
+ const result = {
74
+ file: filePath,
75
+ path,
76
+ action: "update",
77
+ success: true,
78
+ message: `Successfully updated node at path: ${path}`,
79
+ };
80
+
81
+ // Format event results
82
+ let eventResultsText = "";
83
+ if (eventResults && eventResults.length > 0) {
84
+ eventResultsText =
85
+ "\n\nAdditional Information:\n" +
86
+ JSON.stringify(eventResults, null, 2);
87
+ }
88
+
89
+ return JSON.stringify(result, null, 2) + eventResultsText;
90
+ } catch (error: any) {
91
+ // Do NOT emit post-edit event on error
92
+
93
+ throw new Error(`Failed to edit node in ${filePath}: ${error.message}`);
94
+ }
95
+ }
@@ -0,0 +1,73 @@
1
+ import * as fs from "fs";
2
+ import { fileExists } from "../../../utils";
3
+ import { services, ToolsService } from "../../../services";
4
+ import { LanguageAgnosticParser } from "../../../plugins/tree-sitter/parser";
5
+ import { TreeEditor } from "../../../plugins/tree-sitter/editor";
6
+
7
+ /**
8
+ * Get the AST path for a specific line of text in a file using tree-sitter parsing
9
+ */
10
+ export async function astGetPathForLine(
11
+ filePath: string,
12
+ searchText: string
13
+ ): Promise<string> {
14
+ // Get context from bound ToolsService
15
+ const toolService = (
16
+ this instanceof ToolsService ? this : services().Tools
17
+ ) as ToolsService;
18
+
19
+ const context = toolService.getContext();
20
+
21
+ // Emit pre-action event
22
+ if (context.Events) {
23
+ await context.Events.emitBlocking("ast:pre-get-path-for-line", {
24
+ filePath,
25
+ searchText,
26
+ });
27
+ }
28
+
29
+ const exists = await fileExists(filePath);
30
+ if (!exists) {
31
+ throw new Error(`File not found: ${filePath}`);
32
+ }
33
+
34
+ try {
35
+ const content = fs.readFileSync(filePath, "utf8");
36
+
37
+ if (!LanguageAgnosticParser.supportsFile(filePath)) {
38
+ throw new Error(`Unsupported file type for AST parsing: ${filePath}`);
39
+ }
40
+
41
+ const parser = LanguageAgnosticParser.createParserForFile(filePath);
42
+ const tree = parser.parseString(content);
43
+ const pathLocations = parser.findPathsForLine(tree, searchText);
44
+
45
+ // Emit post-action event
46
+ if (context.Events) {
47
+ await context.Events.emitNonBlocking("ast:post-get-path-for-line", {
48
+ filePath,
49
+ searchText,
50
+ pathCount: pathLocations.length,
51
+ });
52
+ }
53
+
54
+ const result = {
55
+ file: filePath,
56
+ searchText,
57
+ language: parser.getLanguage(),
58
+ totalMatches: pathLocations.length,
59
+ matches: pathLocations.map((loc) => ({
60
+ path: loc.path,
61
+ line: loc.row + 1, // Convert from 0-based to 1-based line numbering
62
+ column: loc.column + 1, // Convert from 0-based to 1-based column numbering
63
+ text: loc.text,
64
+ })),
65
+ };
66
+
67
+ return JSON.stringify(result, null, 2);
68
+ } catch (error: any) {
69
+ throw new Error(
70
+ `Failed to get path for line in ${filePath}: ${error.message}`
71
+ );
72
+ }
73
+ }