@tyvm/knowhow 0.0.47 → 0.0.49

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 +39 -25
  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 +129 -67
  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 +8 -8
  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 +60 -70
  71. package/src/processors/TokenCompressor.ts +15 -14
  72. package/src/processors/ToolResponseCache.ts +20 -14
  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 +485 -0
  93. package/tests/processors/HarmonyToolProcessor.test.ts +490 -0
  94. package/tests/processors/TokenCompressor.test.ts +390 -0
  95. package/tests/processors/ToolResponseCache.test.ts +736 -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 +7 -2
  120. package/ts_build/src/agents/base/base.js +27 -21
  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 +62 -32
  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 +9 -13
  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 +45 -47
  309. package/ts_build/src/processors/CustomVariables.js.map +1 -1
  310. package/ts_build/src/processors/TokenCompressor.js +10 -13
  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 +18 -10
  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 +354 -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 +299 -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 +550 -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
@@ -0,0 +1,530 @@
1
+ import { PluginBase, PluginMeta } from "./PluginBase";
2
+ import { PluginContext } from "./types";
3
+ import { MinimalEmbedding } from "../types";
4
+ import { EventService } from "../services/EventService";
5
+ import { execSync } from "child_process";
6
+ import * as fs from "fs";
7
+ import * as path from "path";
8
+
9
+ export class GitPlugin extends PluginBase {
10
+ readonly meta: PluginMeta = {
11
+ key: "git",
12
+ name: "Git Plugin",
13
+ description: "Git tracking for agent modifications using .knowhow/.git",
14
+ };
15
+
16
+ private knowhowGitPath: string;
17
+ private knowhowDir: string;
18
+ private projectRoot: string;
19
+ private projectHasGit: boolean = false;
20
+ private eventService: EventService;
21
+ private currentTask: string | null = null;
22
+
23
+ constructor(context: PluginContext = {}) {
24
+ super(context);
25
+ this.projectRoot = process.cwd();
26
+ this.knowhowDir = path.join(this.projectRoot, ".knowhow");
27
+ this.knowhowGitPath = path.join(this.knowhowDir, ".git");
28
+ this.eventService = context.Events || new EventService();
29
+ this.setupEventListeners();
30
+ }
31
+
32
+ async call(input: string): Promise<string> {
33
+ // Get current project git status
34
+ const projectGitStatus = this.getProjectGitStatus();
35
+
36
+ return `Git Plugin:
37
+
38
+ - Current branch: ${this.getCurrentBranch()}
39
+ - Agent edit history is tracked separately in .knowhow/.git
40
+ - Use git commands with git --git-dir="${
41
+ this.knowhowGitPath
42
+ }" to view/revert your changes
43
+
44
+ PROJECT REPOSITORY STATUS:
45
+ ${projectGitStatus}
46
+
47
+ via git status
48
+
49
+ Note: The files shown above are files that have changed in the user's git repo. It is likely these files are relevant to the user's request as they've got changes recently.
50
+ Your modifications are automatically tracked separately and won't affect the user's git history.`;
51
+ }
52
+
53
+ private getProjectGitStatus(): string {
54
+ try {
55
+ // Get project git status
56
+ const status = execSync("git status --porcelain", {
57
+ cwd: this.projectRoot,
58
+ stdio: "pipe",
59
+ })
60
+ .toString()
61
+ .trim();
62
+
63
+ return status
64
+ ? `Modified files:\n${status}`
65
+ : "- No modified files (working tree clean)";
66
+ } catch (error) {
67
+ return `- Error reading project git status: ${
68
+ error instanceof Error ? error.message : "Unknown error"
69
+ }`;
70
+ }
71
+ }
72
+
73
+ async embed(input: string): Promise<MinimalEmbedding[]> {
74
+ return [];
75
+ }
76
+
77
+ private async initializeKnowhowRepo(): Promise<void> {
78
+ try {
79
+ // Create .knowhow directory if it doesn't exist
80
+ if (!fs.existsSync(this.knowhowDir)) {
81
+ fs.mkdirSync(this.knowhowDir, { recursive: true });
82
+ }
83
+
84
+ // Initialize git repo in .knowhow if not already initialized
85
+ if (!fs.existsSync(this.knowhowGitPath)) {
86
+ execSync("git init", { cwd: this.knowhowDir, stdio: "pipe" });
87
+
88
+ // Create initial .gitignore file in the .knowhow directory (not tracked by the repo)
89
+ const gitignorePath = path.join(this.knowhowDir, ".gitignore");
90
+ fs.writeFileSync(
91
+ gitignorePath,
92
+ "# Knowhow agent tracking repository\n"
93
+ );
94
+
95
+ const hasChanges = await this.hasChanges();
96
+ if (hasChanges) {
97
+ this.commit("Initial commit for agent tracking, with changes");
98
+ } else {
99
+ this.gitCommand(
100
+ 'commit --allow-empty -m "Initial commit for agent tracking, no changes"'
101
+ );
102
+ }
103
+ }
104
+
105
+ await this.setBranch("main");
106
+ } catch (error) {
107
+ console.error("Failed to initialize .knowhow git repository:", error);
108
+ }
109
+ }
110
+
111
+ private gitCommand(
112
+ command: string,
113
+ options: { stdio?: any } = { stdio: "pipe" }
114
+ ): string {
115
+ try {
116
+ const fullCommand = `git --git-dir="${this.knowhowGitPath}" --work-tree="${this.projectRoot}" ${command}`;
117
+ return execSync(fullCommand, {
118
+ cwd: this.projectRoot,
119
+ ...options,
120
+ }).toString();
121
+ } catch (error: any) {
122
+ // Re-throw with more context
123
+ const errorMessage = error.stderr
124
+ ? error.stderr.toString()
125
+ : error.message;
126
+ const newError = new Error(
127
+ `Git command failed: ${command}\nError: ${errorMessage}`
128
+ );
129
+ newError.stack = error.stack;
130
+ throw newError;
131
+ }
132
+ }
133
+
134
+ private safeGitCommand(
135
+ command: string,
136
+ options: { stdio?: any } = { stdio: "pipe" }
137
+ ): string | null {
138
+ try {
139
+ return this.gitCommand(command, options);
140
+ } catch (error) {
141
+ console.warn(`Safe git command failed: ${command}`, error);
142
+ return null;
143
+ }
144
+ }
145
+
146
+ private setupEventListeners(): void {
147
+ // Listen for file:post-edit events to auto-commit
148
+ this.eventService.on("file:post-edit", async (data: any) => {
149
+ if (this.isEnabled()) {
150
+ await this.autoCommit(data);
151
+ }
152
+ });
153
+
154
+ // Listen for agent newTask events to create new branches
155
+ this.eventService.on("agent:newTask", async (data: any) => {
156
+ if (this.isEnabled()) {
157
+ await this.ensureCleanState(data);
158
+ await this.handleNewTask(data);
159
+ }
160
+ });
161
+
162
+ // Listen for task completion events to squash merge
163
+ this.eventService.on("agent:taskComplete", async (data: any) => {
164
+ if (this.isEnabled()) {
165
+ await this.handleTaskComplete(data);
166
+ }
167
+ });
168
+ }
169
+
170
+ /**
171
+ * Gets the current branch name from the git repository
172
+ */
173
+ private getCurrentBranch(): string {
174
+ try {
175
+ return this.gitCommand("branch --show-current").trim() || "main";
176
+ } catch {
177
+ return "main";
178
+ }
179
+ }
180
+
181
+ private getRepoHash(): string | null {
182
+ let actualRepoHash: string | null = null;
183
+ try {
184
+ actualRepoHash = execSync("git rev-parse --short HEAD", {
185
+ cwd: this.projectRoot,
186
+ stdio: "pipe",
187
+ })
188
+ .toString()
189
+ .trim();
190
+ } catch {
191
+ // No actual git repo or no commits
192
+ actualRepoHash = null;
193
+ }
194
+ return actualRepoHash;
195
+ }
196
+
197
+ /**
198
+ * Ensures the .knowhow/.git repository is in a clean state before starting new tasks.
199
+ * This method commits any uncommitted changes and preserves work from any current branch.
200
+ */
201
+ private async ensureCleanState(taskData?: any): Promise<void> {
202
+ try {
203
+ // Initialize the repo if it doesn't exist
204
+ if (!fs.existsSync(this.knowhowGitPath)) {
205
+ await this.initializeKnowhowRepo();
206
+ return;
207
+ }
208
+
209
+ // Get the current HEAD commit hash from the actual repo (if it exists)
210
+ const actualRepoHash = this.getRepoHash();
211
+ console.log(`GitPlugin: Current branch is ${this.getCurrentBranch()}`);
212
+
213
+ // First, handle any uncommitted changes on the current branch
214
+ const hasChanges = await this.hasChanges();
215
+ if (hasChanges) {
216
+ try {
217
+ const message = actualRepoHash
218
+ ? `sync ${actualRepoHash}`
219
+ : `sync ${new Date().toISOString()}`;
220
+ await this.commitAll(message);
221
+ } catch (error) {
222
+ console.error("Failed to commit uncommitted changes:", error);
223
+ }
224
+ }
225
+
226
+ // If we're not on main, we need to merge the current branch into main to preserve work
227
+ const branchToMerge = this.getCurrentBranch();
228
+ if (this.getCurrentBranch() !== "main") {
229
+ await this.setBranch("main");
230
+ await this.squashMerge(branchToMerge);
231
+ }
232
+
233
+ await this.setBranch("main");
234
+ } catch (error) {
235
+ console.error("Failed to ensure clean state:", error);
236
+ }
237
+ }
238
+
239
+ async hasChanges() {
240
+ // Check if there are uncommitted changes in the .knowhow repo
241
+ let hasChanges = false;
242
+ try {
243
+ this.gitCommand("diff-index --quiet HEAD --");
244
+ } catch {
245
+ hasChanges = true;
246
+ }
247
+ return hasChanges;
248
+ }
249
+
250
+ async setBranch(branchName: string): Promise<void> {
251
+ if (!this.isEnabled()) return;
252
+
253
+ try {
254
+ // Check if branch exists
255
+ try {
256
+ this.gitCommand(`rev-parse --verify ${branchName}`);
257
+ // Branch exists, switch to it
258
+ this.gitCommand(`checkout ${branchName}`);
259
+ } catch {
260
+ // Branch doesn't exist, create and switch to it
261
+ this.gitCommand(`checkout -b ${branchName}`);
262
+ }
263
+ } catch (error) {
264
+ console.error(`GitPlugin: Failed to set branch ${branchName}:`);
265
+ }
266
+ }
267
+
268
+ async createBranch(branchName: string): Promise<void> {
269
+ if (!this.isEnabled()) return;
270
+
271
+ try {
272
+ this.gitCommand(`checkout -b ${branchName}`);
273
+ } catch (error) {
274
+ console.error(`GitPlugin: Failed to create branch ${branchName}:`);
275
+ }
276
+ }
277
+
278
+ async commit(message: string, files?: string[]): Promise<void> {
279
+ if (!this.isEnabled()) return;
280
+
281
+ const hasChanges = await this.hasChanges();
282
+
283
+ if (!hasChanges) {
284
+ return;
285
+ }
286
+
287
+ // Add files (or all if none specified)
288
+ if (files && files.length > 0) {
289
+ for (const file of files) {
290
+ try {
291
+ this.gitCommand(`add "${file}"`);
292
+ } catch (error) {
293
+ console.warn(`Failed to add file ${file}:`, error);
294
+ }
295
+ }
296
+ } else {
297
+ this.gitCommand("add -A");
298
+ }
299
+
300
+ // Ensure we have a valid HEAD before committing
301
+ this.ensureValidHead();
302
+
303
+ // Commit the changes
304
+ this.gitCommand(`commit -m "${message}"`);
305
+ }
306
+
307
+ async commitAll(message: string): Promise<void> {
308
+ if (!this.isEnabled()) return;
309
+
310
+ try {
311
+ this.gitCommand("add -A");
312
+ await this.commitWithEvents(message);
313
+ } catch (error) {
314
+ console.error("Failed to commit all changes:", error);
315
+ }
316
+ }
317
+
318
+ async commitWithEvents(message: string, files?: string[]): Promise<void> {
319
+ try {
320
+ const preCommitResults = await this.eventService.emitBlocking(
321
+ "git:pre-commit",
322
+ {
323
+ branch: this.getCurrentBranch(),
324
+ message,
325
+ files,
326
+ }
327
+ );
328
+
329
+ let enhancedMessage = message;
330
+
331
+ // Append pre-commit event results to message
332
+ if (preCommitResults && preCommitResults.length > 0) {
333
+ const resultMessages = preCommitResults
334
+ .filter((result) => result && typeof result === "string")
335
+ .join("\n");
336
+
337
+ if (resultMessages) {
338
+ enhancedMessage += "\n\n" + resultMessages;
339
+ }
340
+ }
341
+
342
+ await this.commit(enhancedMessage, files);
343
+
344
+ // Emit post-commit event
345
+ this.eventService.emit("git:post-commit", {
346
+ branch: this.getCurrentBranch(),
347
+ message: enhancedMessage,
348
+ files,
349
+ });
350
+
351
+ this.eventService.emit(
352
+ "agent:msg",
353
+ `GitPlugin::Commit: ${enhancedMessage} on branch: ${this.getCurrentBranch()}
354
+ You can access your change history via git --git-dir ${
355
+ this.knowhowGitPath
356
+ } log or other commands
357
+ This can be used to revert changes, or compare against previous states during a task.
358
+ `
359
+ );
360
+ } catch (error) {
361
+ console.error("Failed to commit with events:", error);
362
+ }
363
+ }
364
+
365
+ private ensureValidHead(): void {
366
+ try {
367
+ // Check if HEAD exists
368
+ this.gitCommand("rev-parse HEAD");
369
+ } catch {
370
+ // No HEAD exists, need to create initial commit
371
+ try {
372
+ this.gitCommand('commit --allow-empty -m "Initial empty commit"');
373
+ } catch (error) {
374
+ console.warn("Could not create initial commit:", error);
375
+ }
376
+ }
377
+ }
378
+
379
+ private async autoCommit(data: any): Promise<void> {
380
+ if (!this.isEnabled()) return;
381
+
382
+ try {
383
+ const { filePath, operation } = data;
384
+ if (!filePath) return;
385
+
386
+ // Create commit message based on operation
387
+ let message = `Auto-commit: ${operation || "modified"} ${filePath}`;
388
+
389
+ // Add current task context if available
390
+ if (this.currentTask) {
391
+ message = `[${this.currentTask}] ${message}`;
392
+ }
393
+
394
+ await this.commitAll(message);
395
+ } catch (error) {
396
+ console.error("Auto-commit failed:", error);
397
+ }
398
+ }
399
+
400
+ private async handleNewTask(data: {
401
+ taskId: string;
402
+ description: string;
403
+ }): Promise<void> {
404
+ if (!this.isEnabled()) return;
405
+
406
+ try {
407
+ const { taskId, description } = data;
408
+ if (!taskId) return;
409
+
410
+ // Create task-specific branch name
411
+ const branchName = `task/${taskId}`;
412
+
413
+ // Add to task stack
414
+ this.currentTask = taskId;
415
+
416
+ // Create new branch from current branch
417
+ await this.createBranch(branchName);
418
+
419
+ // Create initial commit for the task
420
+ const hasChanges = await this.hasChanges();
421
+ if (hasChanges) {
422
+ await this.commitWithEvents(
423
+ `[${taskId}] Start new task: ${description || taskId}`
424
+ );
425
+ }
426
+
427
+ console.log(`Created new task branch: ${branchName}`);
428
+ } catch (error) {
429
+ console.error("Failed to handle new task:", error);
430
+ }
431
+ }
432
+
433
+ private async handleTaskComplete(data: any): Promise<void> {
434
+ if (!this.isEnabled()) return;
435
+
436
+ try {
437
+ if (!this.currentTask) {
438
+ console.warn("No tasks in progress to complete");
439
+ return;
440
+ }
441
+
442
+ // Get current task
443
+ const completedTaskId = this.currentTask;
444
+ const completedBranch = this.getCurrentBranch();
445
+
446
+ // commit all changes before merge
447
+ await this.commitAll("Final commit before merging task");
448
+
449
+ // Switch to main branch
450
+ await this.setBranch("main");
451
+
452
+ const squashMessage = `[${completedTaskId}] Complete task: ${
453
+ data.answer ? data.answer.substring(0, 100) + "..." : completedTaskId
454
+ }`;
455
+ await this.squashMerge(completedBranch, squashMessage);
456
+
457
+ // Clear current task
458
+ this.currentTask = null;
459
+ } catch (error) {
460
+ console.error("Failed to handle task completion:", error);
461
+ }
462
+ }
463
+
464
+ async getGitStatus(): Promise<string> {
465
+ if (!this.isEnabled()) return "Git plugin not enabled";
466
+
467
+ try {
468
+ return this.gitCommand("status --porcelain");
469
+ } catch (error) {
470
+ return `Error getting git status: ${error}`;
471
+ }
472
+ }
473
+
474
+ async getGitLog(count: number = 10): Promise<string> {
475
+ if (!this.isEnabled()) return "Git plugin not enabled";
476
+
477
+ try {
478
+ return this.gitCommand(`log --oneline -${count}`);
479
+ } catch (error) {
480
+ return `Error getting git log: ${error}`;
481
+ }
482
+ }
483
+
484
+ async getBranches(): Promise<string[]> {
485
+ if (!this.isEnabled()) return [];
486
+
487
+ try {
488
+ const output = this.gitCommand("branch");
489
+ return output
490
+ .split("\n")
491
+ .map((line) => line.replace(/^\*?\s*/, "").trim())
492
+ .filter((line) => line.length > 0);
493
+ } catch (error) {
494
+ console.error("Error getting branches:", error);
495
+ return [];
496
+ }
497
+ }
498
+
499
+ // Manual git operations for advanced users
500
+ async manualCommit(message: string, files?: string[]): Promise<void> {
501
+ await this.commitWithEvents(message, files);
502
+ }
503
+
504
+ async manualBranch(branchName: string): Promise<void> {
505
+ await this.createBranch(branchName);
506
+ }
507
+
508
+ async squashMerge(
509
+ branchName: string,
510
+ message: string = "",
511
+ squash: boolean = true
512
+ ): Promise<void> {
513
+ if (!this.isEnabled()) return;
514
+
515
+ try {
516
+ const mergeCommand = squash
517
+ ? `merge --squash ${branchName}`
518
+ : `merge ${branchName}`;
519
+ this.gitCommand(mergeCommand);
520
+
521
+ if (squash) {
522
+ // Need to create commit after squash merge
523
+ message = message || `Squash merge ${branchName}`;
524
+ this.commitAll(message);
525
+ }
526
+ } catch (error) {
527
+ console.error(`Failed to merge ${branchName}:`, error);
528
+ }
529
+ }
530
+ }
@@ -0,0 +1,89 @@
1
+ import { getConfig } from "../config";
2
+ import { execCommand } from "../agents/tools";
3
+ import { PluginBase, PluginMeta } from "./PluginBase";
4
+
5
+ export class LinterPlugin extends PluginBase {
6
+ static readonly meta: PluginMeta = {
7
+ key: "linter",
8
+ name: "Linter Plugin",
9
+ requires: [],
10
+ };
11
+
12
+ meta = LinterPlugin.meta;
13
+
14
+ constructor(context) {
15
+ super(context);
16
+
17
+ // Subscribe to file:post-edit events
18
+ this.context.Events.onBlocking(
19
+ "file:post-edit",
20
+ this.handleFilePostEdit.bind(this)
21
+ );
22
+
23
+ this.context.Events.onBlocking(
24
+ "git:pre-commit",
25
+ this.handleFilesPreCommit.bind(this)
26
+ );
27
+ }
28
+
29
+ async embed() {
30
+ return [];
31
+ }
32
+
33
+ async call(userPrompt: string): Promise<string> {
34
+ return "";
35
+ }
36
+
37
+ async handleFilesPreCommit(payload: { files: string[] }): Promise<string> {
38
+ const { files = [] } = payload;
39
+ let lintResult = "";
40
+ for (const filePath of files) {
41
+ const result = await this.lintFile(filePath);
42
+ if (result) {
43
+ lintResult += `Results for ${filePath}:\n${result}\n\n`;
44
+ }
45
+ }
46
+ return lintResult || "[Build Stable] No linting issues found";
47
+ }
48
+
49
+ /**
50
+ * Handle file:post-edit events by linting the file
51
+ * @param payload The event payload containing filePath
52
+ * @returns The linting results as a string
53
+ */
54
+ async handleFilePostEdit(payload: { filePath: string }): Promise<string> {
55
+ const { filePath } = payload;
56
+ const lintResult = await this.lintFile(filePath);
57
+ return lintResult || "No linting issues found";
58
+ }
59
+
60
+ /**
61
+ * Lint a file and return the results
62
+ * @param filePath The path to the file to lint
63
+ * @returns The linting results as a string
64
+ */
65
+ async lintFile(filePath: string): Promise<string> {
66
+ const config = await getConfig();
67
+ const extension = filePath.split(".").pop();
68
+
69
+ if (config.lintCommands && config.lintCommands[extension]) {
70
+ let lintCommand = config.lintCommands[extension];
71
+ if (lintCommand.includes("$1")) {
72
+ lintCommand = lintCommand.replace("$1", filePath);
73
+ }
74
+
75
+ try {
76
+ const lintResult = await execCommand(`${lintCommand}`, -1);
77
+ if (lintResult) {
78
+ console.log("Lint Result:", lintResult);
79
+ }
80
+ return lintResult;
81
+ } catch (error) {
82
+ console.error("Linting failed:", error);
83
+ return `Linting failed: ${error}`;
84
+ }
85
+ }
86
+
87
+ return "";
88
+ }
89
+ }
@@ -1,11 +1,13 @@
1
1
  import { MinimalEmbedding } from "../types";
2
- import { Plugin, PluginMeta } from "./types";
2
+ import { Plugin, PluginContext, PluginMeta } from "./types";
3
3
 
4
4
  export abstract class PluginBase implements Plugin {
5
5
  /** Manual on/off toggle (default ON) */
6
6
  private active = true;
7
7
 
8
- constructor(public readonly meta: PluginMeta) {}
8
+ abstract readonly meta: PluginMeta;
9
+
10
+ constructor(protected context: PluginContext = {}) {}
9
11
 
10
12
  /* ------------------------------------------------------------------ */
11
13
  /** Public helpers called by PluginService -------------------------- */
@@ -1,5 +1,6 @@
1
1
  import { PluginBase, PluginMeta } from "./PluginBase";
2
2
  import { Embeddable, MinimalEmbedding } from "../types";
3
+ import { PluginContext } from "./types";
3
4
 
4
5
  export class AsanaPlugin extends PluginBase {
5
6
  static readonly meta: PluginMeta = {
@@ -8,10 +9,11 @@ export class AsanaPlugin extends PluginBase {
8
9
  requires: ["ASANA_TOKEN"]
9
10
  };
10
11
 
12
+ meta = AsanaPlugin.meta;
11
13
  private asanaClient = require("asana").ApiClient.instance;
12
14
 
13
- constructor() {
14
- super(AsanaPlugin.meta);
15
+ constructor(context: PluginContext) {
16
+ super(context);
15
17
 
16
18
  if (!this.isEnabled()) return;
17
19
 
@@ -1,6 +1,7 @@
1
1
  import fs from "fs";
2
2
  import { PluginBase, PluginMeta } from "../PluginBase";
3
3
  import { MinimalEmbedding } from "../../types";
4
+ import { PluginContext } from "../types";
4
5
  import { convertToText, processVideo } from "../../conversion";
5
6
  import { services } from "../../services";
6
7
 
@@ -11,8 +12,10 @@ export class DownloaderPlugin extends PluginBase {
11
12
  requires: [],
12
13
  };
13
14
 
14
- constructor() {
15
- super(DownloaderPlugin.meta);
15
+ meta = DownloaderPlugin.meta;
16
+
17
+ constructor(context: PluginContext) {
18
+ super(context);
16
19
  }
17
20
 
18
21
  skipExt = ["jpg", "jpeg", "png", "gif"];