lonny-agent 0.2.6 → 0.2.7

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 (475) hide show
  1. package/.github/workflows/ci.yml +21 -0
  2. package/AGENTS.md +106 -0
  3. package/CHANGELOG.md +24 -0
  4. package/dist/agent/__tests__/session-restore.test.d.ts +2 -0
  5. package/dist/agent/__tests__/session-restore.test.d.ts.map +1 -0
  6. package/dist/agent/__tests__/session-restore.test.js +260 -0
  7. package/dist/agent/__tests__/session-restore.test.js.map +1 -0
  8. package/dist/agent/commands.d.ts +26 -0
  9. package/dist/agent/commands.d.ts.map +1 -0
  10. package/dist/agent/commands.js +253 -0
  11. package/dist/agent/commands.js.map +1 -0
  12. package/dist/agent/compaction.js +8 -1
  13. package/dist/agent/compaction.js.map +1 -1
  14. package/dist/agent/index.d.ts +2 -1
  15. package/dist/agent/index.d.ts.map +1 -1
  16. package/dist/agent/index.js +2 -2
  17. package/dist/agent/index.js.map +1 -1
  18. package/dist/agent/memory.d.ts +12 -0
  19. package/dist/agent/memory.d.ts.map +1 -0
  20. package/dist/agent/memory.js +51 -0
  21. package/dist/agent/memory.js.map +1 -0
  22. package/dist/agent/prompt-builder.d.ts +6 -1
  23. package/dist/agent/prompt-builder.d.ts.map +1 -1
  24. package/dist/agent/prompt-builder.js +89 -26
  25. package/dist/agent/prompt-builder.js.map +1 -1
  26. package/dist/agent/providers/openai.d.ts +1 -0
  27. package/dist/agent/providers/openai.d.ts.map +1 -1
  28. package/dist/agent/providers/openai.js +16 -3
  29. package/dist/agent/providers/openai.js.map +1 -1
  30. package/dist/agent/session-chat.d.ts +3 -0
  31. package/dist/agent/session-chat.d.ts.map +1 -0
  32. package/dist/agent/session-chat.js +384 -0
  33. package/dist/agent/session-chat.js.map +1 -0
  34. package/dist/agent/session-display.d.ts +29 -0
  35. package/dist/agent/session-display.d.ts.map +1 -0
  36. package/dist/agent/session-display.js +179 -0
  37. package/dist/agent/session-display.js.map +1 -0
  38. package/dist/agent/session-persistence.d.ts +55 -0
  39. package/dist/agent/session-persistence.d.ts.map +1 -0
  40. package/dist/agent/session-persistence.js +101 -0
  41. package/dist/agent/session-persistence.js.map +1 -0
  42. package/dist/agent/session-utils.d.ts +5 -0
  43. package/dist/agent/session-utils.d.ts.map +1 -0
  44. package/dist/agent/session-utils.js +51 -0
  45. package/dist/agent/session-utils.js.map +1 -0
  46. package/dist/agent/session.d.ts +15 -17
  47. package/dist/agent/session.d.ts.map +1 -1
  48. package/dist/agent/session.js +226 -608
  49. package/dist/agent/session.js.map +1 -1
  50. package/dist/cli/index.d.ts +4 -0
  51. package/dist/cli/index.d.ts.map +1 -1
  52. package/dist/cli/index.js +67 -2
  53. package/dist/cli/index.js.map +1 -1
  54. package/dist/config/index.d.ts +2 -2
  55. package/dist/config/index.d.ts.map +1 -1
  56. package/dist/index.js +24 -3
  57. package/dist/index.js.map +1 -1
  58. package/dist/tools/__tests__/bash.test.js +168 -1
  59. package/dist/tools/__tests__/bash.test.js.map +1 -1
  60. package/dist/tools/__tests__/edit.test.js +253 -6
  61. package/dist/tools/__tests__/edit.test.js.map +1 -1
  62. package/dist/tools/__tests__/fetch.test.js +1 -1
  63. package/dist/tools/__tests__/fetch.test.js.map +1 -1
  64. package/dist/tools/__tests__/glob.test.js +1 -1
  65. package/dist/tools/__tests__/glob.test.js.map +1 -1
  66. package/dist/tools/__tests__/grep.test.js +1 -1
  67. package/dist/tools/__tests__/grep.test.js.map +1 -1
  68. package/dist/tools/__tests__/ls.test.js +1 -1
  69. package/dist/tools/__tests__/ls.test.js.map +1 -1
  70. package/dist/tools/__tests__/read.test.js +1 -1
  71. package/dist/tools/__tests__/read.test.js.map +1 -1
  72. package/dist/tools/__tests__/registry.test.js +313 -0
  73. package/dist/tools/__tests__/registry.test.js.map +1 -1
  74. package/dist/tools/__tests__/write_plan.test.js +1 -1
  75. package/dist/tools/__tests__/write_plan.test.js.map +1 -1
  76. package/dist/tools/bash.d.ts.map +1 -1
  77. package/dist/tools/bash.js +659 -39
  78. package/dist/tools/bash.js.map +1 -1
  79. package/dist/tools/codebase/ast/__tests__/ast-edit-demo.d.ts +2 -0
  80. package/dist/tools/codebase/ast/__tests__/ast-edit-demo.d.ts.map +1 -0
  81. package/dist/tools/codebase/ast/__tests__/ast-edit-demo.js +7 -0
  82. package/dist/tools/codebase/ast/__tests__/ast-edit-demo.js.map +1 -0
  83. package/dist/tools/codebase/ast/__tests__/ast-edit-final.d.ts +6 -0
  84. package/dist/tools/codebase/ast/__tests__/ast-edit-final.d.ts.map +1 -0
  85. package/dist/tools/codebase/ast/__tests__/ast-edit-final.js +11 -0
  86. package/dist/tools/codebase/ast/__tests__/ast-edit-final.js.map +1 -0
  87. package/dist/tools/codebase/ast/__tests__/ast-edit-test.d.ts +2 -0
  88. package/dist/tools/codebase/ast/__tests__/ast-edit-test.d.ts.map +1 -0
  89. package/dist/tools/codebase/ast/__tests__/ast-edit-test.js +9 -0
  90. package/dist/tools/codebase/ast/__tests__/ast-edit-test.js.map +1 -0
  91. package/dist/tools/codebase/ast/__tests__/integration.test.d.ts +2 -0
  92. package/dist/tools/codebase/ast/__tests__/integration.test.d.ts.map +1 -0
  93. package/dist/tools/codebase/ast/__tests__/integration.test.js +415 -0
  94. package/dist/tools/codebase/ast/__tests__/integration.test.js.map +1 -0
  95. package/dist/tools/codebase/ast/__tests__/tree-sitter.test.d.ts +2 -0
  96. package/dist/tools/codebase/ast/__tests__/tree-sitter.test.d.ts.map +1 -0
  97. package/dist/tools/codebase/ast/__tests__/tree-sitter.test.js +414 -0
  98. package/dist/tools/codebase/ast/__tests__/tree-sitter.test.js.map +1 -0
  99. package/dist/tools/codebase/ast/adapter.d.ts +23 -0
  100. package/dist/tools/codebase/ast/adapter.d.ts.map +1 -0
  101. package/dist/tools/codebase/ast/adapter.js +11 -0
  102. package/dist/tools/codebase/ast/adapter.js.map +1 -0
  103. package/dist/tools/codebase/ast/tools.d.ts +3 -0
  104. package/dist/tools/codebase/ast/tools.d.ts.map +1 -0
  105. package/dist/tools/codebase/ast/tools.js +286 -0
  106. package/dist/tools/codebase/ast/tools.js.map +1 -0
  107. package/dist/tools/codebase/ast/tree-sitter-adapter.d.ts +3 -0
  108. package/dist/tools/codebase/ast/tree-sitter-adapter.d.ts.map +1 -0
  109. package/dist/tools/codebase/ast/tree-sitter-adapter.js +412 -0
  110. package/dist/tools/codebase/ast/tree-sitter-adapter.js.map +1 -0
  111. package/dist/tools/codebase/ast/tree-sitter-converters.d.ts +4 -0
  112. package/dist/tools/codebase/ast/tree-sitter-converters.d.ts.map +1 -0
  113. package/dist/tools/codebase/ast/tree-sitter-converters.js +447 -0
  114. package/dist/tools/codebase/ast/tree-sitter-converters.js.map +1 -0
  115. package/dist/tools/codebase/ast/types.d.ts +103 -0
  116. package/dist/tools/codebase/ast/types.d.ts.map +1 -0
  117. package/dist/tools/codebase/ast/types.js +2 -0
  118. package/dist/tools/codebase/ast/types.js.map +1 -0
  119. package/dist/tools/codebase/ast/wasm/tree-sitter-python.wasm +0 -0
  120. package/dist/tools/codebase/ast/wasm/tree-sitter-tsx.wasm +0 -0
  121. package/dist/tools/codebase/ast/wasm/tree-sitter-typescript.wasm +0 -0
  122. package/dist/tools/codebase/ast/wasm/tree-sitter.wasm +0 -0
  123. package/dist/tools/codebase/ast/wasm/web-tree-sitter.wasm +0 -0
  124. package/dist/tools/codebase/find.d.ts +3 -0
  125. package/dist/tools/codebase/find.d.ts.map +1 -0
  126. package/dist/tools/codebase/find.js +61 -0
  127. package/dist/tools/codebase/find.js.map +1 -0
  128. package/dist/tools/codebase/glob.d.ts +3 -0
  129. package/dist/tools/codebase/glob.d.ts.map +1 -0
  130. package/dist/tools/codebase/glob.js +37 -0
  131. package/dist/tools/codebase/glob.js.map +1 -0
  132. package/dist/tools/codebase/grep.d.ts +3 -0
  133. package/dist/tools/codebase/grep.d.ts.map +1 -0
  134. package/dist/tools/codebase/grep.js +169 -0
  135. package/dist/tools/codebase/grep.js.map +1 -0
  136. package/dist/tools/codebase/ls.d.ts +3 -0
  137. package/dist/tools/codebase/ls.d.ts.map +1 -0
  138. package/dist/tools/codebase/ls.js +39 -0
  139. package/dist/tools/codebase/ls.js.map +1 -0
  140. package/dist/tools/codebase/read.d.ts +10 -0
  141. package/dist/tools/codebase/read.d.ts.map +1 -0
  142. package/dist/tools/codebase/read.js +81 -0
  143. package/dist/tools/codebase/read.js.map +1 -0
  144. package/dist/tools/delete_memory.d.ts +3 -0
  145. package/dist/tools/delete_memory.d.ts.map +1 -0
  146. package/dist/tools/delete_memory.js +46 -0
  147. package/dist/tools/delete_memory.js.map +1 -0
  148. package/dist/tools/edit/diff-compute.d.ts +4 -0
  149. package/dist/tools/edit/diff-compute.d.ts.map +1 -0
  150. package/dist/tools/edit/diff-compute.js +18 -0
  151. package/dist/tools/edit/diff-compute.js.map +1 -0
  152. package/dist/tools/edit/diff-render.d.ts +18 -0
  153. package/dist/tools/edit/diff-render.d.ts.map +1 -0
  154. package/dist/tools/edit/diff-render.js +128 -0
  155. package/dist/tools/edit/diff-render.js.map +1 -0
  156. package/dist/tools/edit/edit.d.ts +4 -0
  157. package/dist/tools/edit/edit.d.ts.map +1 -0
  158. package/dist/tools/edit/edit.js +440 -0
  159. package/dist/tools/edit/edit.js.map +1 -0
  160. package/dist/tools/edit/matcher.d.ts +24 -0
  161. package/dist/tools/edit/matcher.d.ts.map +1 -0
  162. package/dist/tools/edit/matcher.js +66 -0
  163. package/dist/tools/edit/matcher.js.map +1 -0
  164. package/dist/tools/edit/parser.d.ts +10 -0
  165. package/dist/tools/edit/parser.d.ts.map +1 -0
  166. package/dist/tools/edit/parser.js +120 -0
  167. package/dist/tools/edit/parser.js.map +1 -0
  168. package/dist/tools/edit/types.d.ts +16 -0
  169. package/dist/tools/edit/types.d.ts.map +1 -0
  170. package/dist/tools/edit/types.js +2 -0
  171. package/dist/tools/edit/types.js.map +1 -0
  172. package/dist/tools/edit/write_plan.d.ts +5 -0
  173. package/dist/tools/edit/write_plan.d.ts.map +1 -0
  174. package/dist/tools/edit/write_plan.js +98 -0
  175. package/dist/tools/edit/write_plan.js.map +1 -0
  176. package/dist/tools/edit.d.ts.map +1 -1
  177. package/dist/tools/edit.js +66 -1
  178. package/dist/tools/edit.js.map +1 -1
  179. package/dist/tools/execute/bash/constants.d.ts +24 -0
  180. package/dist/tools/execute/bash/constants.d.ts.map +1 -0
  181. package/dist/tools/execute/bash/constants.js +88 -0
  182. package/dist/tools/execute/bash/constants.js.map +1 -0
  183. package/dist/tools/execute/bash/errors.d.ts +39 -0
  184. package/dist/tools/execute/bash/errors.d.ts.map +1 -0
  185. package/dist/tools/execute/bash/errors.js +249 -0
  186. package/dist/tools/execute/bash/errors.js.map +1 -0
  187. package/dist/tools/execute/bash/execution.d.ts +18 -0
  188. package/dist/tools/execute/bash/execution.d.ts.map +1 -0
  189. package/dist/tools/execute/bash/execution.js +207 -0
  190. package/dist/tools/execute/bash/execution.js.map +1 -0
  191. package/dist/tools/execute/bash/index.d.ts +3 -0
  192. package/dist/tools/execute/bash/index.d.ts.map +1 -0
  193. package/dist/tools/execute/bash/index.js +117 -0
  194. package/dist/tools/execute/bash/index.js.map +1 -0
  195. package/dist/tools/execute/bash/platform.d.ts +6 -0
  196. package/dist/tools/execute/bash/platform.d.ts.map +1 -0
  197. package/dist/tools/execute/bash/platform.js +64 -0
  198. package/dist/tools/execute/bash/platform.js.map +1 -0
  199. package/dist/tools/execute/bash/security.d.ts +12 -0
  200. package/dist/tools/execute/bash/security.d.ts.map +1 -0
  201. package/dist/tools/execute/bash/security.js +26 -0
  202. package/dist/tools/execute/bash/security.js.map +1 -0
  203. package/dist/tools/execute/bash/validation.d.ts +16 -0
  204. package/dist/tools/execute/bash/validation.d.ts.map +1 -0
  205. package/dist/tools/execute/bash/validation.js +57 -0
  206. package/dist/tools/execute/bash/validation.js.map +1 -0
  207. package/dist/tools/execute/bash.d.ts +3 -0
  208. package/dist/tools/execute/bash.d.ts.map +1 -0
  209. package/dist/tools/execute/bash.js +728 -0
  210. package/dist/tools/execute/bash.js.map +1 -0
  211. package/dist/tools/execute/git.d.ts +3 -0
  212. package/dist/tools/execute/git.d.ts.map +1 -0
  213. package/dist/tools/execute/git.js +183 -0
  214. package/dist/tools/execute/git.js.map +1 -0
  215. package/dist/tools/execute/task_complete.d.ts +7 -0
  216. package/dist/tools/execute/task_complete.d.ts.map +1 -0
  217. package/dist/tools/execute/task_complete.js +38 -0
  218. package/dist/tools/execute/task_complete.js.map +1 -0
  219. package/dist/tools/fetch.d.ts.map +1 -1
  220. package/dist/tools/fetch.js +2 -0
  221. package/dist/tools/fetch.js.map +1 -1
  222. package/dist/tools/find.d.ts.map +1 -1
  223. package/dist/tools/find.js +2 -0
  224. package/dist/tools/find.js.map +1 -1
  225. package/dist/tools/git.d.ts.map +1 -1
  226. package/dist/tools/git.js +2 -0
  227. package/dist/tools/git.js.map +1 -1
  228. package/dist/tools/glob.d.ts.map +1 -1
  229. package/dist/tools/glob.js +2 -0
  230. package/dist/tools/glob.js.map +1 -1
  231. package/dist/tools/grep.d.ts.map +1 -1
  232. package/dist/tools/grep.js +2 -0
  233. package/dist/tools/grep.js.map +1 -1
  234. package/dist/tools/install/clawhub.d.ts +26 -0
  235. package/dist/tools/install/clawhub.d.ts.map +1 -0
  236. package/dist/tools/install/clawhub.js +182 -0
  237. package/dist/tools/install/clawhub.js.map +1 -0
  238. package/dist/tools/install/constants.d.ts +5 -0
  239. package/dist/tools/install/constants.d.ts.map +1 -0
  240. package/dist/tools/install/constants.js +5 -0
  241. package/dist/tools/install/constants.js.map +1 -0
  242. package/dist/tools/install/install_skill.d.ts +3 -0
  243. package/dist/tools/install/install_skill.d.ts.map +1 -0
  244. package/dist/tools/install/install_skill.js +132 -0
  245. package/dist/tools/install/install_skill.js.map +1 -0
  246. package/dist/tools/install/npm.d.ts +8 -0
  247. package/dist/tools/install/npm.d.ts.map +1 -0
  248. package/dist/tools/install/npm.js +52 -0
  249. package/dist/tools/install/npm.js.map +1 -0
  250. package/dist/tools/install/skill-content.d.ts +9 -0
  251. package/dist/tools/install/skill-content.d.ts.map +1 -0
  252. package/dist/tools/install/skill-content.js +89 -0
  253. package/dist/tools/install/skill-content.js.map +1 -0
  254. package/dist/tools/install_skill.d.ts.map +1 -1
  255. package/dist/tools/install_skill.js +2 -0
  256. package/dist/tools/install_skill.js.map +1 -1
  257. package/dist/tools/list_memory.d.ts +3 -0
  258. package/dist/tools/list_memory.d.ts.map +1 -0
  259. package/dist/tools/list_memory.js +55 -0
  260. package/dist/tools/list_memory.js.map +1 -0
  261. package/dist/tools/ls.d.ts.map +1 -1
  262. package/dist/tools/ls.js +2 -0
  263. package/dist/tools/ls.js.map +1 -1
  264. package/dist/tools/memory/delete_memory.d.ts +3 -0
  265. package/dist/tools/memory/delete_memory.d.ts.map +1 -0
  266. package/dist/tools/memory/delete_memory.js +46 -0
  267. package/dist/tools/memory/delete_memory.js.map +1 -0
  268. package/dist/tools/memory/list_memory.d.ts +3 -0
  269. package/dist/tools/memory/list_memory.d.ts.map +1 -0
  270. package/dist/tools/memory/list_memory.js +55 -0
  271. package/dist/tools/memory/list_memory.js.map +1 -0
  272. package/dist/tools/memory/save_memory.d.ts +3 -0
  273. package/dist/tools/memory/save_memory.d.ts.map +1 -0
  274. package/dist/tools/memory/save_memory.js +45 -0
  275. package/dist/tools/memory/save_memory.js.map +1 -0
  276. package/dist/tools/read.d.ts.map +1 -1
  277. package/dist/tools/read.js +2 -0
  278. package/dist/tools/read.js.map +1 -1
  279. package/dist/tools/registry.d.ts +7 -2
  280. package/dist/tools/registry.d.ts.map +1 -1
  281. package/dist/tools/registry.js +112 -17
  282. package/dist/tools/registry.js.map +1 -1
  283. package/dist/tools/save_memory.d.ts +3 -0
  284. package/dist/tools/save_memory.d.ts.map +1 -0
  285. package/dist/tools/save_memory.js +45 -0
  286. package/dist/tools/save_memory.js.map +1 -0
  287. package/dist/tools/search.d.ts.map +1 -1
  288. package/dist/tools/search.js +2 -0
  289. package/dist/tools/search.js.map +1 -1
  290. package/dist/tools/tree.d.ts +12 -0
  291. package/dist/tools/tree.d.ts.map +1 -0
  292. package/dist/tools/tree.js +87 -0
  293. package/dist/tools/tree.js.map +1 -0
  294. package/dist/tools/types.d.ts +12 -0
  295. package/dist/tools/types.d.ts.map +1 -1
  296. package/dist/tools/web/fetch.d.ts +3 -0
  297. package/dist/tools/web/fetch.d.ts.map +1 -0
  298. package/dist/tools/web/fetch.js +49 -0
  299. package/dist/tools/web/fetch.js.map +1 -0
  300. package/dist/tools/web/search.d.ts +3 -0
  301. package/dist/tools/web/search.d.ts.map +1 -0
  302. package/dist/tools/web/search.js +134 -0
  303. package/dist/tools/web/search.js.map +1 -0
  304. package/dist/tools/write_plan.d.ts.map +1 -1
  305. package/dist/tools/write_plan.js +2 -0
  306. package/dist/tools/write_plan.js.map +1 -1
  307. package/dist/tui/commands.d.ts +4 -0
  308. package/dist/tui/commands.d.ts.map +1 -0
  309. package/dist/tui/commands.js +118 -0
  310. package/dist/tui/commands.js.map +1 -0
  311. package/dist/tui/components/colors.d.ts +36 -0
  312. package/dist/tui/components/colors.d.ts.map +1 -0
  313. package/dist/tui/components/colors.js +48 -0
  314. package/dist/tui/components/colors.js.map +1 -0
  315. package/dist/tui/components/header-bar.d.ts +26 -0
  316. package/dist/tui/components/header-bar.d.ts.map +1 -0
  317. package/dist/tui/components/header-bar.js +78 -0
  318. package/dist/tui/components/header-bar.js.map +1 -0
  319. package/dist/tui/components/index.d.ts +9 -0
  320. package/dist/tui/components/index.d.ts.map +1 -0
  321. package/dist/tui/components/index.js +9 -0
  322. package/dist/tui/components/index.js.map +1 -0
  323. package/dist/tui/components/landing-screen.d.ts +12 -0
  324. package/dist/tui/components/landing-screen.d.ts.map +1 -0
  325. package/dist/tui/components/landing-screen.js +53 -0
  326. package/dist/tui/components/landing-screen.js.map +1 -0
  327. package/dist/tui/components/pixel-logo.d.ts +5 -0
  328. package/dist/tui/components/pixel-logo.d.ts.map +1 -0
  329. package/dist/tui/components/pixel-logo.js +27 -0
  330. package/dist/tui/components/pixel-logo.js.map +1 -0
  331. package/dist/tui/components/plan-utils.d.ts +11 -0
  332. package/dist/tui/components/plan-utils.d.ts.map +1 -0
  333. package/dist/tui/components/plan-utils.js +62 -0
  334. package/dist/tui/components/plan-utils.js.map +1 -0
  335. package/dist/tui/components/plans-list.d.ts +18 -0
  336. package/dist/tui/components/plans-list.d.ts.map +1 -0
  337. package/dist/tui/components/plans-list.js +46 -0
  338. package/dist/tui/components/plans-list.js.map +1 -0
  339. package/dist/tui/components/rich-footer.d.ts +29 -0
  340. package/dist/tui/components/rich-footer.d.ts.map +1 -0
  341. package/dist/tui/components/rich-footer.js +124 -0
  342. package/dist/tui/components/rich-footer.js.map +1 -0
  343. package/dist/tui/components/todo-panel.d.ts +14 -0
  344. package/dist/tui/components/todo-panel.d.ts.map +1 -0
  345. package/dist/tui/components/todo-panel.js +83 -0
  346. package/dist/tui/components/todo-panel.js.map +1 -0
  347. package/dist/tui/components.d.ts.map +1 -1
  348. package/dist/tui/components.js +14 -7
  349. package/dist/tui/components.js.map +1 -1
  350. package/dist/tui/index.d.ts +2 -1
  351. package/dist/tui/index.d.ts.map +1 -1
  352. package/dist/tui/index.js +99 -505
  353. package/dist/tui/index.js.map +1 -1
  354. package/dist/tui/overlays.d.ts +28 -0
  355. package/dist/tui/overlays.d.ts.map +1 -0
  356. package/dist/tui/overlays.js +154 -0
  357. package/dist/tui/overlays.js.map +1 -0
  358. package/dist/tui/themes.d.ts +5 -0
  359. package/dist/tui/themes.d.ts.map +1 -0
  360. package/dist/tui/themes.js +38 -0
  361. package/dist/tui/themes.js.map +1 -0
  362. package/dist/web/index.d.ts.map +1 -1
  363. package/dist/web/index.js +60 -122
  364. package/dist/web/index.js.map +1 -1
  365. package/dist/web/public/index.html +1 -1
  366. package/dist/web/public/messages.js +41 -25
  367. package/dist/web/public/state.js +72 -72
  368. package/dist/web/public/style.css +1126 -996
  369. package/dist/web/public/websocket.js +267 -267
  370. package/dist/web/session-bridge.d.ts.map +1 -1
  371. package/dist/web/session-bridge.js +82 -3
  372. package/dist/web/session-bridge.js.map +1 -1
  373. package/docs/ast-tools.md +117 -0
  374. package/package.json +60 -55
  375. package/scripts/check-line-count.mjs +53 -0
  376. package/scripts/copy-ast-wasm.mjs +32 -0
  377. package/src/agent/__tests__/session-restore.test.ts +284 -0
  378. package/src/agent/commands.ts +274 -0
  379. package/src/agent/compaction.ts +9 -2
  380. package/src/agent/index.ts +30 -25
  381. package/src/agent/memory.ts +60 -0
  382. package/src/agent/prompt-builder.ts +100 -26
  383. package/src/agent/providers/anthropic.ts +179 -179
  384. package/src/agent/providers/google.ts +210 -210
  385. package/src/agent/providers/ollama.ts +186 -186
  386. package/src/agent/providers/openai.ts +18 -3
  387. package/src/agent/session-chat.ts +480 -0
  388. package/src/agent/session-display.ts +195 -0
  389. package/src/agent/session-persistence.ts +146 -0
  390. package/src/agent/session-utils.ts +54 -0
  391. package/src/agent/session.ts +261 -718
  392. package/src/cli/index.ts +73 -4
  393. package/src/config/index.ts +342 -342
  394. package/src/index.ts +30 -3
  395. package/src/tools/__tests__/bash.test.ts +187 -1
  396. package/src/tools/__tests__/edit.test.ts +275 -11
  397. package/src/tools/__tests__/fetch.test.ts +1 -1
  398. package/src/tools/__tests__/glob.test.ts +1 -1
  399. package/src/tools/__tests__/grep.test.ts +1 -1
  400. package/src/tools/__tests__/ls.test.ts +1 -1
  401. package/src/tools/__tests__/read.test.ts +1 -1
  402. package/src/tools/__tests__/registry.test.ts +332 -0
  403. package/src/tools/__tests__/write_plan.test.ts +1 -1
  404. package/src/tools/codebase/ast/__tests__/integration.test.ts +452 -0
  405. package/src/tools/codebase/ast/__tests__/tree-sitter.test.ts +466 -0
  406. package/src/tools/codebase/ast/adapter.ts +44 -0
  407. package/src/tools/codebase/ast/tools.ts +322 -0
  408. package/src/tools/codebase/ast/tree-sitter-adapter.ts +468 -0
  409. package/src/tools/codebase/ast/tree-sitter-converters.ts +480 -0
  410. package/src/tools/codebase/ast/types.ts +102 -0
  411. package/src/tools/codebase/ast/wasm/tree-sitter-python.wasm +0 -0
  412. package/src/tools/codebase/ast/wasm/tree-sitter-tsx.wasm +0 -0
  413. package/src/tools/codebase/ast/wasm/tree-sitter-typescript.wasm +0 -0
  414. package/src/tools/codebase/ast/wasm/tree-sitter.wasm +0 -0
  415. package/src/tools/codebase/ast/wasm/web-tree-sitter.wasm +0 -0
  416. package/src/tools/{find.ts → codebase/find.ts} +4 -2
  417. package/src/tools/{glob.ts → codebase/glob.ts} +4 -2
  418. package/src/tools/{grep.ts → codebase/grep.ts} +4 -2
  419. package/src/tools/{ls.ts → codebase/ls.ts} +4 -2
  420. package/src/tools/{read.ts → codebase/read.ts} +5 -3
  421. package/src/tools/edit/diff-compute.ts +21 -0
  422. package/src/tools/edit/diff-render.ts +145 -0
  423. package/src/tools/edit/edit.ts +468 -0
  424. package/src/tools/edit/matcher.ts +70 -0
  425. package/src/tools/edit/parser.ts +131 -0
  426. package/src/tools/edit/types.ts +19 -0
  427. package/src/tools/{write_plan.ts → edit/write_plan.ts} +4 -2
  428. package/src/tools/execute/bash/constants.ts +93 -0
  429. package/src/tools/execute/bash/errors.ts +304 -0
  430. package/src/tools/execute/bash/execution.ts +211 -0
  431. package/src/tools/execute/bash/index.ts +131 -0
  432. package/src/tools/execute/bash/platform.ts +65 -0
  433. package/src/tools/execute/bash/security.ts +28 -0
  434. package/src/tools/execute/bash/validation.ts +78 -0
  435. package/src/tools/execute/git.ts +209 -0
  436. package/src/tools/execute/task_complete.ts +40 -0
  437. package/src/tools/install/clawhub.ts +222 -0
  438. package/src/tools/install/constants.ts +4 -0
  439. package/src/tools/install/install_skill.ts +150 -0
  440. package/src/tools/install/npm.ts +60 -0
  441. package/src/tools/install/skill-content.ts +108 -0
  442. package/src/tools/memory/delete_memory.ts +46 -0
  443. package/src/tools/memory/list_memory.ts +53 -0
  444. package/src/tools/memory/save_memory.ts +45 -0
  445. package/src/tools/registry.ts +119 -19
  446. package/src/tools/tree.ts +103 -0
  447. package/src/tools/types.ts +13 -0
  448. package/src/tools/{fetch.ts → web/fetch.ts} +4 -2
  449. package/src/tools/{search.ts → web/search.ts} +4 -2
  450. package/src/tui/commands.ts +135 -0
  451. package/src/tui/components/colors.ts +52 -0
  452. package/src/tui/components/header-bar.ts +88 -0
  453. package/src/tui/components/index.ts +8 -0
  454. package/src/tui/components/landing-screen.ts +67 -0
  455. package/src/tui/components/pixel-logo.ts +33 -0
  456. package/src/tui/components/plan-utils.ts +69 -0
  457. package/src/tui/components/plans-list.ts +55 -0
  458. package/src/tui/components/rich-footer.ts +146 -0
  459. package/src/tui/components/todo-panel.ts +95 -0
  460. package/src/tui/index.ts +335 -786
  461. package/src/tui/overlays.ts +203 -0
  462. package/src/tui/themes.ts +41 -0
  463. package/src/web/index.ts +64 -127
  464. package/src/web/public/index.html +1 -1
  465. package/src/web/public/messages.js +41 -25
  466. package/src/web/public/state.js +72 -72
  467. package/src/web/public/style.css +1126 -996
  468. package/src/web/public/websocket.js +267 -267
  469. package/src/web/session-bridge.ts +272 -193
  470. package/AGENT.md +0 -99
  471. package/src/tools/bash.ts +0 -125
  472. package/src/tools/edit.ts +0 -747
  473. package/src/tools/git.ts +0 -76
  474. package/src/tools/install_skill.ts +0 -539
  475. package/src/tui/components.ts +0 -635
@@ -0,0 +1,108 @@
1
+ import { CLAWHUB_SITE } from './constants.js'
2
+
3
+ /** Sanitize a package name to a valid skill name (lowercase, digits, hyphens) */
4
+ export function sanitizeSkillName(name: string): string {
5
+ return name
6
+ .toLowerCase()
7
+ .replace(/@/g, '')
8
+ .replace(/\//g, '-')
9
+ .replace(/[^a-z0-9-]/g, '')
10
+ .replace(/-+/g, '-')
11
+ .replace(/^-|-$/g, '')
12
+ }
13
+
14
+ /** Generate a usage guide snippet from the readme */
15
+ export function extractUsageGuide(readme: string): string {
16
+ // Try to extract code examples from the readme
17
+ const codeBlocks: string[] = []
18
+ const blockRegex = /```(?:js|javascript|ts|typescript|bash)\n([\s\S]*?)```/g
19
+ let match: RegExpExecArray | null = blockRegex.exec(readme)
20
+ while (match !== null) {
21
+ const block = match[1].trim()
22
+ if (block.length > 0 && block.length < 1000) {
23
+ codeBlocks.push(block)
24
+ }
25
+ match = blockRegex.exec(readme)
26
+ }
27
+ return codeBlocks.slice(0, 3).join('\n\n')
28
+ }
29
+
30
+ /** Generate the skill markdown content (npm package) */
31
+ export function generateSkillContent(
32
+ packageName: string,
33
+ description: string,
34
+ usageGuide: string,
35
+ ): string {
36
+ const installCmd = `npm install ${packageName}`
37
+
38
+ let content = `---
39
+ name: ${sanitizeSkillName(packageName)}
40
+ description: ${description}
41
+ ---
42
+
43
+ # ${packageName}
44
+
45
+ ${description}
46
+
47
+ ## Installation
48
+
49
+ This package is already installed in the project via \`${installCmd}\`.
50
+
51
+ ## Usage
52
+
53
+ You can import and use this package in your code:
54
+
55
+ \`\`\`typescript
56
+ import ${packageName.replace(/@/, '').replace(/[/-]/g, '_')} from '${packageName}'
57
+ \`\`\`
58
+ `
59
+
60
+ if (usageGuide) {
61
+ content += `\n## Examples\n\n${usageGuide}\n`
62
+ }
63
+
64
+ content += `
65
+ ## Notes
66
+
67
+ - This skill was automatically installed. The package is available as a project dependency.
68
+ - Refer to the package's npm page or repository for full documentation.
69
+ `
70
+
71
+ return content
72
+ }
73
+
74
+ /** Generate the skill markdown content (ClawHub skill) */
75
+ export function generateClawHubSkillContent(
76
+ slug: string,
77
+ displayName: string,
78
+ summary: string,
79
+ clawhubContent: string,
80
+ ): string {
81
+ // If the ZIP contains a SKILL.md, use it directly
82
+ // Otherwise, generate a wrapper skill file
83
+ let content = `---
84
+ name: ${sanitizeSkillName(slug)}
85
+ description: ${summary || displayName}
86
+ clawhub: ${slug}
87
+ ---
88
+
89
+ # ${displayName}
90
+
91
+ ${summary || `ClawHub skill: ${slug}`}
92
+
93
+ `
94
+
95
+ if (clawhubContent) {
96
+ content += `${clawhubContent}\n`
97
+ }
98
+
99
+ content += `
100
+ ## Notes
101
+
102
+ - This skill was installed from [ClawHub](${CLAWHUB_SITE}/${slug}).
103
+ - Source: ${CLAWHUB_SITE}/${slug}
104
+ - The skill instructions are loaded automatically on the next turn.
105
+ `
106
+
107
+ return content
108
+ }
@@ -0,0 +1,46 @@
1
+ import * as fs from 'node:fs'
2
+ import * as path from 'node:path'
3
+ import { fmtErr } from '../errors.js'
4
+ import type { Tool, ToolResult } from '../types.js'
5
+
6
+ export function createDeleteMemoryTool(cwd: string): Tool {
7
+ return {
8
+ definition: {
9
+ name: 'delete_memory',
10
+ category: 'Memory',
11
+ group: 'Manage',
12
+ description:
13
+ 'Delete a memory entry by id or filename under .lonny/memory (id or file parameter)',
14
+ parameters: {
15
+ id: {
16
+ type: 'string',
17
+ description: 'Memory id (filename without .json) or relative filename',
18
+ required: true,
19
+ },
20
+ },
21
+ },
22
+ async execute(input): Promise<ToolResult> {
23
+ try {
24
+ const id = (input as any).id || input
25
+ if (typeof id !== 'string' || !id)
26
+ return { success: false, output: '', error: 'id is required (string)' }
27
+ const dir = path.resolve(cwd, '.lonny', 'memory')
28
+ const candidates = [id, `${id}.json`]
29
+ for (const c of candidates) {
30
+ const p = path.join(dir, c)
31
+ try {
32
+ if (fs.existsSync(p)) {
33
+ fs.unlinkSync(p)
34
+ return { success: true, output: `Deleted memory ${c}` }
35
+ }
36
+ } catch (e) {
37
+ return { success: false, output: '', error: fmtErr(e) }
38
+ }
39
+ }
40
+ return { success: false, output: '', error: `Memory not found: ${id}` }
41
+ } catch (err) {
42
+ return { success: false, output: '', error: fmtErr(err) }
43
+ }
44
+ },
45
+ }
46
+ }
@@ -0,0 +1,53 @@
1
+ import * as fs from 'node:fs'
2
+ import * as path from 'node:path'
3
+ import { fmtErr } from '../errors.js'
4
+ import type { Tool, ToolResult } from '../types.js'
5
+
6
+ export function createListMemoryTool(cwd: string): Tool {
7
+ return {
8
+ definition: {
9
+ name: 'list_memory',
10
+ category: 'Memory',
11
+ group: 'Query',
12
+ description: 'List memory entries stored under .lonny/memory (optional limit param)',
13
+ parameters: {
14
+ limit: {
15
+ type: 'number',
16
+ description: 'Maximum number of entries to return',
17
+ required: false,
18
+ },
19
+ },
20
+ },
21
+ async execute(input): Promise<ToolResult> {
22
+ try {
23
+ const limit = typeof (input as any).limit === 'number' ? (input as any).limit : undefined
24
+ const dir = path.resolve(cwd, '.lonny', 'memory')
25
+ if (!fs.existsSync(dir)) return { success: true, output: 'No memories found' }
26
+ const files = fs.readdirSync(dir).filter(f => f.endsWith('.json'))
27
+ const entries: { id: string; createdAt: string; preview: string; tags?: string[] }[] = []
28
+ for (const f of files) {
29
+ try {
30
+ const data = JSON.parse(fs.readFileSync(path.join(dir, f), 'utf-8'))
31
+ entries.push({
32
+ id: data.id || f.replace(/\.json$/, ''),
33
+ createdAt: data.createdAt || '',
34
+ preview: (data.content || '').replace(/\n/g, ' ').slice(0, 200),
35
+ tags: Array.isArray(data.tags) ? data.tags : undefined,
36
+ })
37
+ } catch {
38
+ // ignore corrupted
39
+ }
40
+ }
41
+ // sort by createdAt desc
42
+ entries.sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1))
43
+ const out = entries.slice(0, limit || entries.length).map(e => {
44
+ const tagStr = e.tags ? ` [tags: ${e.tags.join(',')}]` : ''
45
+ return `${e.id} ${e.createdAt} ${e.preview}${tagStr}`
46
+ })
47
+ return { success: true, output: out.join('\n') }
48
+ } catch (err) {
49
+ return { success: false, output: '', error: fmtErr(err) }
50
+ }
51
+ },
52
+ }
53
+ }
@@ -0,0 +1,45 @@
1
+ import * as fs from 'node:fs'
2
+ import * as path from 'node:path'
3
+ import { fmtErr } from '../errors.js'
4
+ import type { Tool, ToolResult } from '../types.js'
5
+
6
+ export function createSaveMemoryTool(cwd: string): Tool {
7
+ return {
8
+ definition: {
9
+ name: 'save_memory',
10
+ category: 'Memory',
11
+ group: 'Write',
12
+ description:
13
+ 'Save a memory entry to .lonny/memory as a JSON file (content: string, tags?: string[])',
14
+ parameters: {
15
+ content: { type: 'string', description: 'Memory text', required: true },
16
+ tags: { type: 'array', description: 'Optional tags', required: false },
17
+ },
18
+ },
19
+ async execute(input): Promise<ToolResult> {
20
+ try {
21
+ const content = (input as any).content || input
22
+ const tags = (input as any).tags
23
+ if (typeof content !== 'string' || !content) {
24
+ return { success: false, output: '', error: 'content is required (string)' }
25
+ }
26
+ const id = String(Date.now()) + '-' + Math.random().toString(36).slice(2, 8)
27
+ const entry = {
28
+ id,
29
+ createdAt: new Date().toISOString(),
30
+ content,
31
+ tags: Array.isArray(tags) ? tags : undefined,
32
+ }
33
+ const dir = path.resolve(cwd, '.lonny', 'memory')
34
+ try {
35
+ fs.mkdirSync(dir, { recursive: true })
36
+ } catch {}
37
+ const file = path.join(dir, `${id}.json`)
38
+ fs.writeFileSync(file, JSON.stringify(entry, null, 2), 'utf-8')
39
+ return { success: true, output: `Saved memory ${id}` }
40
+ } catch (err) {
41
+ return { success: false, output: '', error: fmtErr(err) }
42
+ }
43
+ },
44
+ }
45
+ }
@@ -1,22 +1,33 @@
1
1
  import type { FileReadTracker } from '../diff/apply.js'
2
- import { bashTool } from './bash.js'
3
- import { createEditTool } from './edit.js'
2
+ import { createAstTools } from './codebase/ast/tools.js'
3
+ import { createFindTool } from './codebase/find.js'
4
+ import { globTool } from './codebase/glob.js'
5
+ import { createGrepTool } from './codebase/grep.js'
6
+ import { createLsTool } from './codebase/ls.js'
7
+ import { createReadTool } from './codebase/read.js'
8
+ import { createEditTool } from './edit/edit.js'
9
+ import { createWritePlanTool } from './edit/write_plan.js'
4
10
  import { fmtErr } from './errors.js'
5
- import { fetchTool } from './fetch.js'
6
- import { createFindTool } from './find.js'
7
- import { createGitTool } from './git.js'
8
- import { globTool } from './glob.js'
9
- import { createGrepTool } from './grep.js'
10
- import { createInstallSkillTool } from './install_skill.js'
11
- import { createLsTool } from './ls.js'
12
- import { createReadTool } from './read.js'
13
- import { searchTool } from './search.js'
11
+ import { bashTool } from './execute/bash/index.js'
12
+ import { createGitTool } from './execute/git.js'
13
+ import { taskCompleteTool } from './execute/task_complete.js'
14
+ import { createInstallSkillTool } from './install/install_skill.js'
15
+ import { createDeleteMemoryTool } from './memory/delete_memory.js'
16
+ import { createListMemoryTool } from './memory/list_memory.js'
17
+ import { createSaveMemoryTool } from './memory/save_memory.js'
14
18
  import type { Tool, ToolCall, ToolDefinition, ToolResult } from './types.js'
15
- import { createWritePlanTool } from './write_plan.js'
19
+ import { fetchTool } from './web/fetch.js'
20
+ import { searchTool } from './web/search.js'
21
+
22
+ /**
23
+ * Tools in this set are passed directly to the LLM API's `tools` parameter.
24
+ * All other tools must be invoked via the `tool()` gateway.
25
+ */
26
+ const CORE_TOOL_NAMES = new Set(['read', 'edit', 'bash', 'glob', 'grep', 'task_complete'])
16
27
 
17
28
  /**
18
29
  * Normalize tool input to prevent common LLM call misuses.
19
- * The LLM sometimes passes parameters in the wrong format this function
30
+ * The LLM sometimes passes parameters in the wrong format �?this function
20
31
  * auto-corrects those patterns so tools work reliably.
21
32
  *
22
33
  * Common misuses handled:
@@ -75,7 +86,7 @@ export interface ToolContext {
75
86
  cwd: string
76
87
  autoApprove: boolean
77
88
  applier: FileReadTracker
78
- mode: 'code' | 'plan' | 'ask'
89
+ mode: 'code' | 'plan' | 'ask' | 'loop'
79
90
  onPlanWritten?: (display: string) => void
80
91
  }
81
92
 
@@ -93,14 +104,66 @@ export class ToolRegistry {
93
104
  private tools: Map<string, Tool> = new Map()
94
105
  private context: ToolContext
95
106
  private plugins: Map<string, ToolPlugin> = new Map()
107
+ private gatewayTool: Tool
96
108
 
97
109
  constructor(context: ToolContext) {
98
110
  this.context = context
111
+ this.gatewayTool = this.createGatewayTool()
99
112
  this.registerBuiltins()
100
113
  }
101
114
 
115
+ /** Create the `tool()` gateway that proxies calls to extended (non-core) tools */
116
+ private createGatewayTool(): Tool {
117
+ const dispatch = this.dispatch.bind(this)
118
+ return {
119
+ definition: {
120
+ name: 'tool',
121
+ description: `Invoke an extended tool. Use this for tools not in the direct-access core set.
122
+
123
+ The core tools are: read, edit, bash, glob, grep �?use them directly.
124
+ For everything else, call tool() with the tool name and its parameters.
125
+
126
+ Examples:
127
+ tool({ name: "git", params: { command: "status" } })
128
+ tool({ name: "ls", params: { path: "src" } })
129
+ tool({ name: "find", params: { pattern: "*.ts" } })
130
+ tool({ name: "fetch", params: { url: "https://example.com" } })`,
131
+ parameters: {
132
+ name: {
133
+ type: 'string',
134
+ description: 'The extended tool name to invoke',
135
+ required: true,
136
+ },
137
+ params: {
138
+ type: 'object',
139
+ description: 'Tool-specific parameters as a JSON object',
140
+ required: true,
141
+ },
142
+ },
143
+ },
144
+ async execute(input) {
145
+ const name = input.name as string | undefined
146
+ if (!name || typeof name !== 'string') {
147
+ return { success: false, output: '', error: 'tool() requires a "name" field (string)' }
148
+ }
149
+ if (name === 'tool') {
150
+ return { success: false, output: '', error: 'Cannot call tool() recursively' }
151
+ }
152
+ const call: ToolCall = {
153
+ id: `gateway-${Date.now()}`,
154
+ name,
155
+ input: (input.params || {}) as Record<string, unknown>,
156
+ }
157
+ return dispatch(call)
158
+ },
159
+ }
160
+ }
161
+
102
162
  /** Register all built-in tools */
103
163
  private registerBuiltins(): void {
164
+ // Register the gateway tool first so it's always available
165
+ this.register(this.gatewayTool)
166
+
104
167
  // ask mode: only fetch and search
105
168
  if (this.context.mode === 'ask') {
106
169
  this.register(fetchTool)
@@ -116,26 +179,43 @@ export class ToolRegistry {
116
179
  this.register(fetchTool)
117
180
  this.register(searchTool)
118
181
 
119
- if (this.context.mode === 'code') {
120
- // Code mode: full toolset including write operations
182
+ if (this.context.mode === 'code' || this.context.mode === 'loop') {
183
+ // Code/Loop mode: full toolset including write operations
121
184
  this.register(bashTool)
122
185
  this.register(createGitTool(this.context.cwd))
123
186
  this.register(createInstallSkillTool(this.context.cwd))
124
187
  this.register(createEditTool(this.context.applier, this.context.cwd))
188
+ // Register save_memory tool (simple on-disk writer)
189
+ try {
190
+ this.register(createSaveMemoryTool(this.context.cwd))
191
+ this.register(createListMemoryTool(this.context.cwd))
192
+ this.register(createDeleteMemoryTool(this.context.cwd))
193
+ } catch (err) {
194
+ // If for some reason the tool can't be created, ignore — not critical
195
+ console.error('[ToolRegistry] Failed to register memory tools:', err)
196
+ }
197
+ // Register AST tools (ast_query, ast_edit)
198
+ for (const tool of createAstTools()) {
199
+ this.register(tool)
200
+ }
201
+
202
+ // Register task_complete tool so the model can explicitly signal completion
203
+ // (most useful in loop mode, but available in code mode too)
204
+ this.register(taskCompleteTool)
125
205
  } else {
126
206
  // Plan mode: read-only investigation + write_plan
127
207
  this.register(createWritePlanTool(this.context.cwd, this.context.onPlanWritten))
128
208
  }
129
209
  }
130
210
 
131
- setMode(mode: 'code' | 'plan' | 'ask'): void {
211
+ setMode(mode: 'code' | 'plan' | 'ask' | 'loop'): void {
132
212
  // Update context.mode FIRST so registerBuiltins() and mode-based logic
133
213
  // use the NEW mode, not the stale one (fixes bug when switching from
134
214
  // ask→code or plan→code where all tools would be missing)
135
215
  this.context.mode = mode
136
216
 
137
- if (mode === 'code') {
138
- // Re-register all built-in tools for code mode
217
+ if (mode === 'code' || mode === 'loop') {
218
+ // Code/Loop mode: Re-register all built-in tools for full toolset
139
219
  this.tools.clear()
140
220
  this.registerBuiltins()
141
221
  } else if (mode === 'plan') {
@@ -199,6 +279,26 @@ export class ToolRegistry {
199
279
  return Array.from(this.tools.values()).map(t => t.definition)
200
280
  }
201
281
 
282
+ /** Get definitions for the core tool set + gateway (for LLM API's tools parameter) */
283
+ getCoreDefinitions(): ToolDefinition[] {
284
+ // Ask mode has only 2 tools �?pass them directly, no gateway needed
285
+ if (this.context.mode === 'ask') {
286
+ return Array.from(this.tools.values())
287
+ .filter(t => t.definition.name !== 'tool')
288
+ .map(t => t.definition)
289
+ }
290
+
291
+ const core: ToolDefinition[] = []
292
+ for (const [name, tool] of this.tools) {
293
+ if (CORE_TOOL_NAMES.has(name)) {
294
+ core.push(tool.definition)
295
+ }
296
+ }
297
+ // Always include the gateway tool so the model can reach extended tools
298
+ core.push(this.gatewayTool.definition)
299
+ return core
300
+ }
301
+
202
302
  async dispatch(call: ToolCall): Promise<ToolResult> {
203
303
  const tool = this.tools.get(call.name)
204
304
  if (!tool) {
@@ -0,0 +1,103 @@
1
+ import type { ToolDefinition, ToolTreeNode } from './types.js'
2
+
3
+ function normalizeLabel(value: string | undefined, fallback: string): string {
4
+ const trimmed = value?.trim()
5
+ return trimmed && trimmed !== 'Unclassified' ? trimmed : fallback
6
+ }
7
+
8
+ function createToolNode(def: ToolDefinition, depth: number): ToolTreeNode {
9
+ return {
10
+ type: 'tool',
11
+ name: def.name,
12
+ description: def.description,
13
+ toolName: def.name,
14
+ depth,
15
+ }
16
+ }
17
+
18
+ export function buildToolTree(definitions: ToolDefinition[]): ToolTreeNode[] {
19
+ const root: ToolTreeNode[] = []
20
+ const groups = new Map<string, ToolTreeNode>()
21
+
22
+ function getOrCreate(parts: string[], depth: number): ToolTreeNode {
23
+ const key = parts.join('/')
24
+ let node = groups.get(key)
25
+ if (!node) {
26
+ node = {
27
+ type: 'group',
28
+ name: parts[parts.length - 1] || 'Other',
29
+ children: [],
30
+ depth,
31
+ }
32
+ groups.set(key, node)
33
+
34
+ if (parts.length === 1) {
35
+ root.push(node)
36
+ } else {
37
+ const parent = groups.get(parts.slice(0, -1).join('/'))
38
+ parent?.children?.push(node)
39
+ }
40
+ }
41
+ return node
42
+ }
43
+
44
+ for (const def of definitions) {
45
+ const category = normalizeLabel(def.category, 'Other')
46
+ const rawGroup = normalizeLabel(def.group, 'Unclassified')
47
+
48
+ // Build path: category first, then split group by '/' for multi-level nesting
49
+ const parts = [category]
50
+ if (rawGroup && rawGroup !== 'Unclassified') {
51
+ parts.push(
52
+ ...rawGroup
53
+ .split('/')
54
+ .map(p => p.trim())
55
+ .filter(Boolean),
56
+ )
57
+ }
58
+
59
+ // Create all intermediate group nodes (parents before children)
60
+ for (let i = 1; i <= parts.length; i++) {
61
+ const node = getOrCreate(parts.slice(0, i), i - 1)
62
+ if (i === parts.length) {
63
+ node.children?.push(createToolNode(def, i))
64
+ }
65
+ }
66
+ }
67
+
68
+ return root
69
+ }
70
+
71
+ /**
72
+ * Format the tool tree for inclusion in the system prompt.
73
+ *
74
+ * @param definitions - All tool definitions (for building the full tree)
75
+ * @param coreNames - Optional set of core tool names. When provided, tools NOT
76
+ * in this set are annotated with "(via tool)" to indicate they require the
77
+ * `tool()` gateway.
78
+ */
79
+ export function formatToolTreeForPrompt(
80
+ definitions: ToolDefinition[],
81
+ coreNames?: Set<string>,
82
+ ): string {
83
+ const lines: string[] = []
84
+
85
+ function render(node: ToolTreeNode, level: number): void {
86
+ const indent = ' '.repeat(level)
87
+ if (node.type === 'group') {
88
+ lines.push(`${indent}- ${node.name}`)
89
+ } else {
90
+ const suffix = coreNames && !coreNames.has(node.name) ? ' (via tool gateway)' : ''
91
+ lines.push(`${indent}- \`${node.name}\`: ${node.description || ''}${suffix}`)
92
+ }
93
+ for (const child of node.children || []) {
94
+ render(child, level + 1)
95
+ }
96
+ }
97
+
98
+ for (const node of buildToolTree(definitions)) {
99
+ render(node, 0)
100
+ }
101
+
102
+ return lines.join('\n')
103
+ }
@@ -9,6 +9,10 @@ export interface ToolDefinition {
9
9
  name: string
10
10
  description: string
11
11
  parameters: Record<string, ToolParameter>
12
+ /** Top-level category used for hierarchical tool trees, e.g. "File I/O". */
13
+ category?: string
14
+ /** Second-level group used for hierarchical tool trees, e.g. "Read". */
15
+ group?: string
12
16
  }
13
17
 
14
18
  export interface ToolCall {
@@ -27,3 +31,12 @@ export interface Tool {
27
31
  definition: ToolDefinition
28
32
  execute(input: Record<string, unknown>): Promise<ToolResult>
29
33
  }
34
+
35
+ export interface ToolTreeNode {
36
+ type: 'group' | 'tool'
37
+ name: string
38
+ description?: string
39
+ children?: ToolTreeNode[]
40
+ toolName?: string
41
+ depth: number
42
+ }
@@ -1,9 +1,11 @@
1
- import { fmtErr } from './errors.js'
2
- import type { Tool, ToolResult } from './types.js'
1
+ import { fmtErr } from '../errors.js'
2
+ import type { Tool, ToolResult } from '../types.js'
3
3
 
4
4
  export const fetchTool: Tool = {
5
5
  definition: {
6
6
  name: 'fetch',
7
+ category: 'Web',
8
+ group: 'Fetch',
7
9
  description: 'Fetch content from a URL. Returns the response body as text.',
8
10
  parameters: {
9
11
  url: { type: 'string', description: 'URL to fetch', required: true },
@@ -1,8 +1,8 @@
1
1
  import * as fs from 'node:fs'
2
2
  import * as os from 'node:os'
3
3
  import * as path from 'node:path'
4
- import { fmtErr } from './errors.js'
5
- import type { Tool, ToolResult } from './types.js'
4
+ import { fmtErr } from '../errors.js'
5
+ import type { Tool, ToolResult } from '../types.js'
6
6
 
7
7
  interface TavilyConfig {
8
8
  tavilyApiKey?: string
@@ -30,6 +30,8 @@ const TAVILY_API_URL = 'https://api.tavily.com/search'
30
30
  export const searchTool: Tool = {
31
31
  definition: {
32
32
  name: 'search',
33
+ category: 'Web',
34
+ group: 'Search Engine',
33
35
  description:
34
36
  'Search the web using the Tavily search engine. Returns a summary answer and a list of relevant results with titles, URLs, and content snippets.',
35
37
  parameters: {