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
@@ -1,193 +1,272 @@
1
- import { EventChannels, getGlobalEventBus } from '../agent/event-bus.js'
2
- import type { Session } from '../agent/session.js'
3
- import type { Config } from '../config/index.js'
4
-
5
- /**
6
- * Bridge between Session/EventBus and WebSocket.
7
- * Listens to EventBus events and forwards them as JSON messages.
8
- */
9
-
10
- /** Strip ANSI escape codes from a string (terminal colors are meaningless in the browser) */
11
- function stripAnsi(text: string): string {
12
- return text.replace(/\x1b\[[0-9;]*m/g, '')
13
- }
14
-
15
- export interface WsMessage {
16
- type: string
17
- [key: string]: unknown
18
- }
19
-
20
- export type SendFn = (msg: WsMessage) => void
21
-
22
- const WS_PROTOCOL_VERSION = 1
23
-
24
- export function startSessionBridge(
25
- session: Session,
26
- config: Config,
27
- send: SendFn,
28
- ): { close: () => void; sendMessage: (text: string) => Promise<void> } {
29
- const bus = getGlobalEventBus()
30
-
31
- // Send initial handshake with current token stats
32
- send({
33
- type: 'hello',
34
- version: WS_PROTOCOL_VERSION,
35
- mode: config.mode,
36
- model: config.model,
37
- provider: config.provider,
38
- totalIn: session.totalInputTokens,
39
- totalOut: session.totalOutputTokens,
40
- totalApi: session.totalApiCalls,
41
- totalCacheHit: session.totalCacheHitTokens || undefined,
42
- totalCacheMiss: session.totalCacheMissTokens || undefined,
43
- })
44
-
45
- // ── Subscribe to EventBus ──
46
-
47
- const unsubTurnStart = bus.on(EventChannels.TURN_START, data => {
48
- const d = data as { prompt?: string }
49
- send({ type: 'turn_start', prompt: d.prompt || '' })
50
- })
51
-
52
- const unsubToolCall = bus.on(EventChannels.TOOL_CALL, data => {
53
- const d = data as { name: string; input: Record<string, unknown>; id: string }
54
- send({ type: 'tool_call', name: d.name, input: d.input, id: d.id })
55
- })
56
-
57
- const unsubToolResult = bus.on(EventChannels.TOOL_RESULT, data => {
58
- const d = data as { name: string; id: string; output: string }
59
- send({
60
- type: 'tool_result',
61
- name: d.name,
62
- id: d.id,
63
- success: true,
64
- output: d.name === 'edit' ? d.output : stripAnsi(d.output),
65
- })
66
- })
67
-
68
- const unsubToolError = bus.on(EventChannels.TOOL_ERROR, data => {
69
- const d = data as { name: string; id: string; error: string }
70
- send({ type: 'tool_result', name: d.name, id: d.id, success: false, error: stripAnsi(d.error) })
71
- })
72
-
73
- const unsubTurnEnd = bus.on(EventChannels.TURN_END, data => {
74
- const d = data as { iterations: number; toolCallCount: number }
75
- send({ type: 'turn_end', iterations: d.iterations, toolCallCount: d.toolCallCount })
76
- })
77
-
78
- const unsubThinking = bus.on(EventChannels.THINKING, data => {
79
- const d = data as { text: string }
80
- send({ type: 'thinking', text: d.text })
81
- })
82
-
83
- const unsubThinkingEnd = bus.on(EventChannels.THINKING_END, () => {
84
- send({ type: 'thinking_end' })
85
- })
86
-
87
- const unsubCompaction = bus.on(EventChannels.COMPACTION_TRIGGERED, data => {
88
- const d = data as { before: number; after: number }
89
- send({ type: 'compaction', before: d.before, after: d.after })
90
- })
91
-
92
- const unsubTokenStats = bus.on(EventChannels.TOKEN_STATS, data => {
93
- const d = data as {
94
- turnIn: number
95
- turnOut: number
96
- totalIn: number
97
- totalOut: number
98
- turnApi: number
99
- totalApi: number
100
- turnCacheHit?: number
101
- turnCacheMiss?: number
102
- totalCacheHit?: number
103
- totalCacheMiss?: number
104
- }
105
- send({ type: 'token_stats', ...d })
106
- })
107
-
108
- // ── Handle incoming messages from client ──
109
-
110
- async function handleClientMessage(msg: WsMessage): Promise<void> {
111
- switch (msg.type) {
112
- case 'message': {
113
- const text = String(msg.text || '')
114
- if (!text.trim()) return
115
-
116
- // Handle slash commands
117
- if (text.startsWith('/')) {
118
- const parts = text.slice(1).split(/\s+/)
119
- const cmd = parts[0]
120
- const arg = parts.slice(1).join(' ')
121
-
122
- if (cmd === 'mode' && (arg === 'code' || arg === 'plan' || arg === 'ask')) {
123
- session.setMode(arg as 'code' | 'plan' | 'ask')
124
- send({ type: 'mode_changed', mode: arg })
125
- return
126
- }
127
-
128
- if (cmd === 'model' && arg) {
129
- session.config.model = arg
130
- session.setMode(session.config.mode)
131
- send({ type: 'model_changed', model: arg })
132
- return
133
- }
134
-
135
- if (cmd === 'help') {
136
- send({
137
- type: 'help',
138
- commands: [
139
- '/mode code|plan|ask - Switch mode',
140
- '/model <name> - Switch model',
141
- '/new - Start a new session',
142
- '/help - Show this help',
143
- ],
144
- })
145
- return
146
- }
147
-
148
- send({ type: 'error', message: `Unknown command: ${cmd}` })
149
- return
150
- }
151
-
152
- // Send user message to session
153
- try {
154
- await session.chat(text)
155
- send({ type: 'done', reason: 'stop' })
156
- } catch (err) {
157
- const errMsg = err instanceof Error ? err.message : String(err)
158
- send({ type: 'error', message: errMsg })
159
- send({ type: 'done', reason: 'error' })
160
- }
161
- return
162
- }
163
-
164
- case 'ping':
165
- send({ type: 'pong' })
166
- return
167
-
168
- case 'stop':
169
- session.stop()
170
- return
171
-
172
- default:
173
- send({ type: 'error', message: `Unknown message type: ${msg.type}` })
174
- }
175
- }
176
-
177
- return {
178
- close: () => {
179
- unsubTurnStart()
180
- unsubToolCall()
181
- unsubToolResult()
182
- unsubToolError()
183
- unsubTurnEnd()
184
- unsubThinking()
185
- unsubThinkingEnd()
186
- unsubCompaction()
187
- unsubTokenStats()
188
- },
189
- sendMessage: async (text: string) => {
190
- await handleClientMessage({ type: 'message', text })
191
- },
192
- }
193
- }
1
+ import { EventChannels, getGlobalEventBus } from '../agent/event-bus.js'
2
+ import type { Session } from '../agent/session.js'
3
+ import type { Config } from '../config/index.js'
4
+
5
+ /**
6
+ * Bridge between Session/EventBus and WebSocket.
7
+ * Listens to EventBus events and forwards them as JSON messages.
8
+ */
9
+
10
+ /** Strip ANSI escape codes from a string (terminal colors are meaningless in the browser) */
11
+ function stripAnsi(text: string): string {
12
+ return text.replace(/\x1b\[[0-9;]*m/g, '')
13
+ }
14
+
15
+ export interface WsMessage {
16
+ type: string
17
+ [key: string]: unknown
18
+ }
19
+
20
+ export type SendFn = (msg: WsMessage) => void
21
+
22
+ const WS_PROTOCOL_VERSION = 1
23
+
24
+ export function startSessionBridge(
25
+ session: Session,
26
+ config: Config,
27
+ send: SendFn,
28
+ ): { close: () => void; sendMessage: (text: string) => Promise<void> } {
29
+ const bus = getGlobalEventBus()
30
+
31
+ // Send initial handshake with current token stats and session info
32
+ send({
33
+ type: 'hello',
34
+ version: WS_PROTOCOL_VERSION,
35
+ sessionId: session.sessionId,
36
+ sessionTitle: session.sessionTitle || undefined,
37
+ mode: config.mode,
38
+ model: config.model,
39
+ provider: config.provider,
40
+ totalIn: session.totalInputTokens,
41
+ totalOut: session.totalOutputTokens,
42
+ totalApi: session.totalApiCalls,
43
+ totalCacheHit: session.totalCacheHitTokens || undefined,
44
+ totalCacheMiss: session.totalCacheMissTokens || undefined,
45
+ })
46
+
47
+ // ── Subscribe to EventBus ──
48
+
49
+ const unsubTurnStart = bus.on(EventChannels.TURN_START, data => {
50
+ const d = data as { prompt?: string }
51
+ send({ type: 'turn_start', prompt: d.prompt || '' })
52
+ })
53
+
54
+ const unsubToolCall = bus.on(EventChannels.TOOL_CALL, data => {
55
+ const d = data as { name: string; input: Record<string, unknown>; id: string }
56
+ send({ type: 'tool_call', name: d.name, input: d.input, id: d.id })
57
+ })
58
+
59
+ const unsubToolResult = bus.on(EventChannels.TOOL_RESULT, data => {
60
+ const d = data as { name: string; id: string; output: string }
61
+ send({
62
+ type: 'tool_result',
63
+ name: d.name,
64
+ id: d.id,
65
+ success: true,
66
+ output: d.name === 'edit' ? d.output : stripAnsi(d.output),
67
+ })
68
+ })
69
+
70
+ const unsubToolError = bus.on(EventChannels.TOOL_ERROR, data => {
71
+ const d = data as { name: string; id: string; error: string }
72
+ send({ type: 'tool_result', name: d.name, id: d.id, success: false, error: stripAnsi(d.error) })
73
+ })
74
+
75
+ const unsubTurnEnd = bus.on(EventChannels.TURN_END, data => {
76
+ const d = data as { iterations: number; toolCallCount: number }
77
+ send({ type: 'turn_end', iterations: d.iterations, toolCallCount: d.toolCallCount })
78
+ })
79
+
80
+ const unsubThinking = bus.on(EventChannels.THINKING, data => {
81
+ const d = data as { text: string }
82
+ send({ type: 'thinking', text: d.text })
83
+ })
84
+
85
+ const unsubThinkingEnd = bus.on(EventChannels.THINKING_END, () => {
86
+ send({ type: 'thinking_end' })
87
+ })
88
+
89
+ const unsubCompaction = bus.on(EventChannels.COMPACTION_TRIGGERED, data => {
90
+ const d = data as { before: number; after: number }
91
+ send({ type: 'compaction', before: d.before, after: d.after })
92
+ })
93
+
94
+ const unsubTokenStats = bus.on(EventChannels.TOKEN_STATS, data => {
95
+ const d = data as {
96
+ turnIn: number
97
+ turnOut: number
98
+ totalIn: number
99
+ totalOut: number
100
+ turnApi: number
101
+ totalApi: number
102
+ turnCacheHit?: number
103
+ turnCacheMiss?: number
104
+ totalCacheHit?: number
105
+ totalCacheMiss?: number
106
+ }
107
+ send({ type: 'token_stats', ...d })
108
+ })
109
+
110
+ // ── Handle incoming messages from client ──
111
+
112
+ async function handleClientMessage(msg: WsMessage): Promise<void> {
113
+ switch (msg.type) {
114
+ case 'message': {
115
+ const text = String(msg.text || '')
116
+ if (!text.trim()) return
117
+
118
+ // Handle slash commands
119
+ if (text.startsWith('/')) {
120
+ const parts = text.slice(1).split(/\s+/)
121
+ const cmd = parts[0]
122
+ const arg = parts.slice(1).join(' ')
123
+
124
+ if (
125
+ cmd === 'mode' &&
126
+ (arg === 'code' || arg === 'plan' || arg === 'ask' || arg === 'loop')
127
+ ) {
128
+ session.setMode(arg as 'code' | 'plan' | 'ask' | 'loop')
129
+ send({ type: 'mode_changed', mode: arg })
130
+ return
131
+ }
132
+
133
+ if (cmd === 'model' && arg) {
134
+ session.config.model = arg
135
+ session.setMode(session.config.mode)
136
+ send({ type: 'model_changed', model: arg })
137
+ return
138
+ }
139
+
140
+ if (cmd === 'help') {
141
+ send({
142
+ type: 'help',
143
+ commands: [
144
+ '/mode code|plan|ask|loop - Switch mode',
145
+ '/model <name> - Switch model',
146
+ '/sessions - List saved sessions',
147
+ '/session - Show current session info',
148
+ '/session title <name> - Name current session',
149
+ '/session delete <id> - Delete a session',
150
+ '/fork - Fork a new session from current context',
151
+ '/new - Start a new session',
152
+ '/help - Show this help',
153
+ ],
154
+ })
155
+ return
156
+ }
157
+
158
+ if (cmd === 'sessions') {
159
+ const { Session } = await import('../agent/session.js')
160
+ const allSessions = Session.listSessions()
161
+ send({
162
+ type: 'sessions',
163
+ sessions: allSessions.map(s => ({
164
+ id: s.id,
165
+ cwd: s.cwd,
166
+ title: s.title,
167
+ messageCount: s.messageCount,
168
+ mode: s.mode,
169
+ model: s.model,
170
+ provider: s.provider,
171
+ totalInputTokens: s.totalInputTokens,
172
+ totalOutputTokens: s.totalOutputTokens,
173
+ totalApiCalls: s.totalApiCalls,
174
+ createdAt: s.createdAt,
175
+ updatedAt: s.updatedAt,
176
+ })),
177
+ })
178
+ return
179
+ }
180
+
181
+ if (cmd === 'session') {
182
+ if (arg === 'delete' || arg.startsWith('delete ')) {
183
+ const { Session } = await import('../agent/session.js')
184
+ const id = arg.slice(arg.startsWith('delete ') ? 7 : 6).trim()
185
+ const deleted = id ? Session.deleteSession(id) : false
186
+ send({ type: 'session_deleted', id, success: deleted })
187
+ } else if (arg.startsWith('title ')) {
188
+ const title = arg.slice(6).trim()
189
+ if (title) {
190
+ session.sessionTitle = title
191
+ session.save()
192
+ send({ type: 'session_titled', title })
193
+ } else {
194
+ send({ type: 'error', message: 'Usage: /session title <name>' })
195
+ }
196
+ } else if (arg === 'export') {
197
+ try {
198
+ const filePath = session.exportSession()
199
+ send({ type: 'session_exported', filePath })
200
+ } catch (err) {
201
+ send({ type: 'error', message: `Export failed: ${err}` })
202
+ }
203
+ } else {
204
+ send({
205
+ type: 'session_info',
206
+ id: session.sessionId,
207
+ title: session.sessionTitle || '(untitled)',
208
+ mode: session.config.mode,
209
+ model: session.config.model,
210
+ provider: session.config.provider,
211
+ messageCount: session.messages.length,
212
+ totalInputTokens: session.totalInputTokens,
213
+ totalOutputTokens: session.totalOutputTokens,
214
+ totalApiCalls: session.totalApiCalls,
215
+ createdAt: session.sessionCreatedAt,
216
+ })
217
+ }
218
+ return
219
+ }
220
+
221
+ if (cmd === 'fork') {
222
+ const forked = session.fork()
223
+ send({ type: 'session_forked', id: forked.sessionId, title: forked.sessionTitle })
224
+ return
225
+ }
226
+
227
+ send({ type: 'error', message: `Unknown command: ${cmd}` })
228
+ return
229
+ }
230
+
231
+ // Send user message to session
232
+ try {
233
+ await session.chat(text)
234
+ send({ type: 'done', reason: 'stop' })
235
+ } catch (err) {
236
+ const errMsg = err instanceof Error ? err.message : String(err)
237
+ send({ type: 'error', message: errMsg })
238
+ send({ type: 'done', reason: 'error' })
239
+ }
240
+ return
241
+ }
242
+
243
+ case 'ping':
244
+ send({ type: 'pong' })
245
+ return
246
+
247
+ case 'stop':
248
+ session.stop()
249
+ return
250
+
251
+ default:
252
+ send({ type: 'error', message: `Unknown message type: ${msg.type}` })
253
+ }
254
+ }
255
+
256
+ return {
257
+ close: () => {
258
+ unsubTurnStart()
259
+ unsubToolCall()
260
+ unsubToolResult()
261
+ unsubToolError()
262
+ unsubTurnEnd()
263
+ unsubThinking()
264
+ unsubThinkingEnd()
265
+ unsubCompaction()
266
+ unsubTokenStats()
267
+ },
268
+ sendMessage: async (text: string) => {
269
+ await handleClientMessage({ type: 'message', text })
270
+ },
271
+ }
272
+ }
package/AGENT.md DELETED
@@ -1,99 +0,0 @@
1
- # CLAUDE.md — lonny-agent
2
-
3
- This file provides guidance to AI coding agents working with this repository.
4
-
5
- ## Project Overview
6
-
7
- **lonny-agent** is a per-call-pricing-optimized AI coding assistant that runs in the terminal. It supports three modes (`code`, `plan`, `ask`), multiple LLM providers (Anthropic, OpenAI, Google, Ollama), and features a TUI built with `@earendil-works/pi-tui`.
8
-
9
- ### Key Architecture
10
-
11
- ```
12
- src/
13
- ├── agent/ # Core agent loop, session management, LLM providers
14
- │ ├── session.ts # Main session loop (message handling, tool dispatch)
15
- │ ├── llm.ts # LLM provider interface
16
- │ ├── event-bus.ts # Decoupled event system for TUI ↔ agent communication
17
- │ ├── compaction.ts # Context compaction (message history summarization)
18
- │ ├── prompt-builder.ts # System prompt construction
19
- │ └── providers/ # Anthropic, OpenAI, Google, Ollama
20
- ├── cli/ # CLI argument parsing (commander)
21
- ├── config/ # Configuration loading (env, file, defaults)
22
- ├── diff/ # File read tracking and edit validation
23
- ├── tools/ # Tool implementations (read, edit, bash, glob, grep, etc.)
24
- │ ├── registry.ts # ToolRegistry with plugin support
25
- │ ├── exec.ts # JavaScript sandbox executor (inspired by Codex CLI)
26
- │ └── types.ts # Tool interface definitions
27
- ├── tui/ # Terminal UI (landing page, chat display, status bar)
28
- └── index.ts # Entry point
29
- ```
30
-
31
- ### Core Design Decisions
32
-
33
- 1. **Per-call cost optimization**: System prompt tells the model to batch operations into as few API calls as possible
34
- 2. **Three modes**: `code` (direct editing), `plan` (analysis + plan document), `ask` (Q&A only)
35
- 3. **Event bus decoupling**: TUI and agent communicate through an event bus, not direct method calls
36
- 4. **Exec sandbox**: JavaScript VM sandbox lets the model orchestrate multi-step operations in one API call
37
- 5. **File read tracking**: Prevents editing files that haven't been read or were modified externally
38
- 6. **Context compaction**: Summarizes older conversation turns when token budget is exceeded
39
-
40
- ## Git Commit Convention
41
-
42
- Use **Conventional Commits**:
43
-
44
- ```
45
- <type>: <description>
46
- ```
47
-
48
- Types: `feat`, `fix`, `docs`, `chore`, `refactor`, `test`
49
-
50
- Examples:
51
- - `feat: add Tavily web search tool`
52
- - `fix: handle CRLF line endings in edit tool`
53
- - `chore: add Biome + husky code quality pipeline`
54
-
55
- ## Commands
56
-
57
- ```bash
58
- npm install # Install dependencies
59
- npm run dev # Dev mode (tsx watch)
60
- npm run build # Build (tsc)
61
- npm start # Run built version
62
- npm test # Run tests (vitest)
63
- npm test:watch # Watch mode tests
64
-
65
- # Lint & Format (Biome)
66
- npm run lint # Check only
67
- npm run lint:fix # Auto-fix
68
- npm run format # Format all
69
- npm run check # Lint + format check
70
- npm run check:fix # Lint + format auto-fix
71
- ```
72
-
73
- ## Code Quality
74
-
75
- - **Formatter**: Biome (2-space indent, 100 line width, single quotes, as-needed semicolons)
76
- - **Pre-commit**: husky + lint-staged (auto-fix staged files with Biome)
77
- - **TypeScript**: strict mode, no unchecked index access
78
- - **Testing**: vitest with `.test.ts` files co-located in `__tests__/` directories
79
-
80
- ## Architecture Notes
81
-
82
- ### Tool System
83
- - `ToolRegistry` (registry.ts) manages tool registration and dispatch
84
- - Tools implement `Tool` interface (definition + execute method)
85
- - Plugin system allows external tool registration via `registerPlugin()`
86
- - `exec` tool exposes all registered tools as `await tools.xxx(args)` in a sandboxed VM
87
-
88
- ### Session Flow
89
- 1. User sends message → `Session.chat()`
90
- 2. System prompt + message history + tool definitions → LLM provider
91
- 3. LLM streams response (text + tool calls)
92
- 4. Tool calls dispatched via `ToolRegistry.dispatch()`
93
- 5. Results appended to message history
94
- 6. Compaction triggered if token budget exceeded
95
-
96
- ### Testing
97
- - Unit tests: `src/**/__tests__/*.test.ts`
98
- - Mock strategy: mock only modules with side effects (network, filesystem)
99
- - Avoid mocking pure functions or data modules