@travisennis/acai 0.0.8 → 0.0.10

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 (386) hide show
  1. package/README.md +48 -729
  2. package/bin/acai +52 -0
  3. package/dist/agent/index.d.ts +12 -2
  4. package/dist/agent/index.d.ts.map +1 -1
  5. package/dist/agent/index.js +378 -168
  6. package/dist/agent/sub-agent.d.ts +23 -0
  7. package/dist/agent/sub-agent.d.ts.map +1 -0
  8. package/dist/agent/sub-agent.js +109 -0
  9. package/dist/cli/index.d.ts +26 -0
  10. package/dist/cli/index.d.ts.map +1 -0
  11. package/dist/{cli.js → cli/index.js} +84 -76
  12. package/dist/cli/stdin.d.ts +9 -0
  13. package/dist/cli/stdin.d.ts.map +1 -0
  14. package/dist/cli/stdin.js +37 -0
  15. package/dist/commands/copy/index.js +2 -2
  16. package/dist/commands/copy/utils.d.ts.map +1 -1
  17. package/dist/commands/copy/utils.js +15 -13
  18. package/dist/commands/generate-rules/index.d.ts +1 -1
  19. package/dist/commands/generate-rules/index.d.ts.map +1 -1
  20. package/dist/commands/generate-rules/index.js +16 -100
  21. package/dist/commands/generate-rules/service.d.ts +21 -0
  22. package/dist/commands/generate-rules/service.d.ts.map +1 -0
  23. package/dist/commands/generate-rules/service.js +103 -0
  24. package/dist/commands/handoff/index.js +2 -2
  25. package/dist/commands/health/index.js +1 -1
  26. package/dist/commands/health/utils.d.ts.map +1 -1
  27. package/dist/commands/health/utils.js +6 -0
  28. package/dist/commands/history/index.d.ts +1 -1
  29. package/dist/commands/history/index.d.ts.map +1 -1
  30. package/dist/commands/history/index.js +17 -18
  31. package/dist/commands/history/types.d.ts +38 -0
  32. package/dist/commands/history/types.d.ts.map +1 -1
  33. package/dist/commands/history/utils.d.ts.map +1 -1
  34. package/dist/commands/history/utils.js +63 -58
  35. package/dist/commands/init/index.d.ts.map +1 -1
  36. package/dist/commands/init/index.js +3 -8
  37. package/dist/commands/init-project/index.d.ts.map +1 -1
  38. package/dist/commands/init-project/index.js +3 -3
  39. package/dist/commands/init-project/utils.d.ts.map +1 -1
  40. package/dist/commands/init-project/utils.js +10 -2
  41. package/dist/commands/list-tools/index.d.ts.map +1 -1
  42. package/dist/commands/list-tools/index.js +7 -31
  43. package/dist/commands/manager.d.ts +2 -2
  44. package/dist/commands/manager.d.ts.map +1 -1
  45. package/dist/commands/manager.js +57 -33
  46. package/dist/commands/model/index.d.ts.map +1 -1
  47. package/dist/commands/model/index.js +20 -151
  48. package/dist/commands/model/model-panel.d.ts +4 -0
  49. package/dist/commands/model/model-panel.d.ts.map +1 -0
  50. package/dist/commands/model/model-panel.js +144 -0
  51. package/dist/commands/paste/index.d.ts.map +1 -1
  52. package/dist/commands/paste/index.js +59 -62
  53. package/dist/commands/paste/utils.d.ts.map +1 -1
  54. package/dist/commands/paste/utils.js +88 -58
  55. package/dist/commands/pickup/index.d.ts.map +1 -1
  56. package/dist/commands/pickup/index.js +6 -3
  57. package/dist/commands/pickup/utils.js +3 -3
  58. package/dist/commands/resources/index.d.ts.map +1 -1
  59. package/dist/commands/resources/index.js +33 -50
  60. package/dist/commands/review/index.d.ts.map +1 -1
  61. package/dist/commands/review/index.js +3 -117
  62. package/dist/commands/review/review-panel.d.ts +3 -0
  63. package/dist/commands/review/review-panel.d.ts.map +1 -0
  64. package/dist/commands/review/review-panel.js +186 -0
  65. package/dist/commands/review/utils.d.ts +9 -0
  66. package/dist/commands/review/utils.d.ts.map +1 -1
  67. package/dist/commands/review/utils.js +127 -68
  68. package/dist/commands/session/index.d.ts +1 -1
  69. package/dist/commands/session/index.d.ts.map +1 -1
  70. package/dist/commands/session/index.js +134 -112
  71. package/dist/commands/session/types.d.ts +7 -0
  72. package/dist/commands/session/types.d.ts.map +1 -1
  73. package/dist/commands/share/html-renderer.d.ts +25 -0
  74. package/dist/commands/share/html-renderer.d.ts.map +1 -0
  75. package/dist/commands/share/html-renderer.js +384 -0
  76. package/dist/commands/share/index.d.ts +3 -0
  77. package/dist/commands/share/index.d.ts.map +1 -0
  78. package/dist/commands/share/index.js +122 -0
  79. package/dist/commands/shell/index.d.ts.map +1 -1
  80. package/dist/commands/shell/index.js +16 -1
  81. package/dist/commands/types.d.ts +2 -2
  82. package/dist/commands/types.d.ts.map +1 -1
  83. package/dist/{config.d.ts → config/index.d.ts} +20 -9
  84. package/dist/config/index.d.ts.map +1 -0
  85. package/dist/{config.js → config/index.js} +43 -42
  86. package/dist/execution/index.d.ts.map +1 -1
  87. package/dist/execution/index.js +75 -55
  88. package/dist/index.d.ts +1 -0
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +170 -127
  91. package/dist/middleware/cache.d.ts.map +1 -1
  92. package/dist/middleware/cache.js +18 -36
  93. package/dist/models/ai-config.d.ts +1 -0
  94. package/dist/models/ai-config.d.ts.map +1 -1
  95. package/dist/models/ai-config.js +4 -3
  96. package/dist/models/anthropic-provider.d.ts +2 -5
  97. package/dist/models/anthropic-provider.d.ts.map +1 -1
  98. package/dist/models/anthropic-provider.js +3 -70
  99. package/dist/models/deepseek-provider.d.ts +1 -0
  100. package/dist/models/deepseek-provider.d.ts.map +1 -1
  101. package/dist/models/google-provider.d.ts +2 -3
  102. package/dist/models/google-provider.d.ts.map +1 -1
  103. package/dist/models/google-provider.js +0 -26
  104. package/dist/models/groq-provider.d.ts +1 -0
  105. package/dist/models/groq-provider.d.ts.map +1 -1
  106. package/dist/models/manager.d.ts +13 -2
  107. package/dist/models/manager.d.ts.map +1 -1
  108. package/dist/models/manager.js +20 -8
  109. package/dist/models/openai-provider.d.ts +5 -5
  110. package/dist/models/openai-provider.d.ts.map +1 -1
  111. package/dist/models/openai-provider.js +27 -40
  112. package/dist/models/opencode-zen-provider.d.ts +8 -3
  113. package/dist/models/opencode-zen-provider.d.ts.map +1 -1
  114. package/dist/models/opencode-zen-provider.js +68 -11
  115. package/dist/models/openrouter-provider.d.ts +24 -30
  116. package/dist/models/openrouter-provider.d.ts.map +1 -1
  117. package/dist/models/openrouter-provider.js +92 -177
  118. package/dist/models/providers.d.ts +1 -1
  119. package/dist/models/providers.d.ts.map +1 -1
  120. package/dist/models/xai-provider.d.ts +4 -3
  121. package/dist/models/xai-provider.d.ts.map +1 -1
  122. package/dist/models/xai-provider.js +18 -18
  123. package/dist/modes/manager.d.ts +23 -0
  124. package/dist/modes/manager.d.ts.map +1 -0
  125. package/dist/modes/manager.js +77 -0
  126. package/dist/modes/prompts.d.ts +2 -0
  127. package/dist/modes/prompts.d.ts.map +1 -0
  128. package/dist/modes/prompts.js +143 -0
  129. package/dist/prompts/mentions.d.ts +11 -0
  130. package/dist/prompts/mentions.d.ts.map +1 -0
  131. package/dist/{mentions.js → prompts/mentions.js} +21 -80
  132. package/dist/prompts/system-prompt.d.ts +26 -0
  133. package/dist/prompts/system-prompt.d.ts.map +1 -0
  134. package/dist/{prompts.js → prompts/system-prompt.js} +50 -22
  135. package/dist/repl/index.d.ts +174 -0
  136. package/dist/repl/index.d.ts.map +1 -0
  137. package/dist/{repl-new.js → repl/index.js} +399 -76
  138. package/dist/repl/project-status.d.ts +1 -0
  139. package/dist/repl/project-status.d.ts.map +1 -1
  140. package/dist/repl/project-status.js +4 -1
  141. package/dist/sessions/manager.d.ts +93 -1
  142. package/dist/sessions/manager.d.ts.map +1 -1
  143. package/dist/sessions/manager.js +264 -9
  144. package/dist/sessions/summary.d.ts +4 -0
  145. package/dist/sessions/summary.d.ts.map +1 -0
  146. package/dist/sessions/summary.js +30 -0
  147. package/dist/{skills.d.ts → skills/index.d.ts} +14 -2
  148. package/dist/skills/index.d.ts.map +1 -0
  149. package/dist/skills/index.js +294 -0
  150. package/dist/subagents/index.d.ts +15 -0
  151. package/dist/subagents/index.d.ts.map +1 -0
  152. package/dist/subagents/index.js +231 -0
  153. package/dist/terminal/control.d.ts +1 -1
  154. package/dist/terminal/control.d.ts.map +1 -1
  155. package/dist/terminal/control.js +30 -9
  156. package/dist/terminal/east-asian-width.d.ts.map +1 -1
  157. package/dist/terminal/east-asian-width.js +404 -351
  158. package/dist/terminal/keys.d.ts +17 -0
  159. package/dist/terminal/keys.d.ts.map +1 -1
  160. package/dist/terminal/keys.js +37 -0
  161. package/dist/terminal/select-prompt.d.ts.map +1 -1
  162. package/dist/terminal/select-prompt.js +24 -12
  163. package/dist/terminal/string-width.d.ts.map +1 -1
  164. package/dist/terminal/string-width.js +25 -27
  165. package/dist/terminal/style.d.ts.map +1 -1
  166. package/dist/terminal/style.js +4 -7
  167. package/dist/terminal/supports-color.d.ts.map +1 -1
  168. package/dist/terminal/supports-color.js +41 -27
  169. package/dist/terminal/table/cell.d.ts +12 -0
  170. package/dist/terminal/table/cell.d.ts.map +1 -1
  171. package/dist/terminal/table/cell.js +40 -25
  172. package/dist/terminal/table/layout-manager.d.ts.map +1 -1
  173. package/dist/terminal/table/layout-manager.js +100 -68
  174. package/dist/terminal/table/utils.d.ts.map +1 -1
  175. package/dist/terminal/table/utils.js +17 -10
  176. package/dist/terminal/wrap-ansi.d.ts.map +1 -1
  177. package/dist/terminal/wrap-ansi.js +172 -103
  178. package/dist/tokens/tracker.d.ts +1 -0
  179. package/dist/tokens/tracker.d.ts.map +1 -1
  180. package/dist/tokens/tracker.js +3 -0
  181. package/dist/tools/agent.d.ts +27 -0
  182. package/dist/tools/agent.d.ts.map +1 -0
  183. package/dist/tools/agent.js +81 -0
  184. package/dist/tools/bash.d.ts +4 -3
  185. package/dist/tools/bash.d.ts.map +1 -1
  186. package/dist/tools/bash.js +343 -121
  187. package/dist/tools/code-search.d.ts +41 -0
  188. package/dist/tools/code-search.d.ts.map +1 -0
  189. package/dist/tools/code-search.js +195 -0
  190. package/dist/tools/directory-tree.d.ts +3 -3
  191. package/dist/tools/directory-tree.d.ts.map +1 -1
  192. package/dist/tools/directory-tree.js +8 -5
  193. package/dist/tools/dynamic-tool-loader.d.ts +2 -5
  194. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  195. package/dist/tools/dynamic-tool-loader.js +20 -4
  196. package/dist/tools/edit-file.d.ts +7 -7
  197. package/dist/tools/edit-file.d.ts.map +1 -1
  198. package/dist/tools/edit-file.js +164 -66
  199. package/dist/tools/glob.d.ts +6 -6
  200. package/dist/tools/glob.d.ts.map +1 -1
  201. package/dist/tools/glob.js +95 -55
  202. package/dist/tools/grep.d.ts +15 -12
  203. package/dist/tools/grep.d.ts.map +1 -1
  204. package/dist/tools/grep.js +300 -192
  205. package/dist/tools/index.d.ts +143 -5
  206. package/dist/tools/index.d.ts.map +1 -1
  207. package/dist/tools/index.js +39 -24
  208. package/dist/tools/ls.d.ts +2 -2
  209. package/dist/tools/ls.d.ts.map +1 -1
  210. package/dist/tools/ls.js +7 -5
  211. package/dist/tools/read-file.d.ts +3 -3
  212. package/dist/tools/read-file.d.ts.map +1 -1
  213. package/dist/tools/read-file.js +74 -34
  214. package/dist/tools/save-file.d.ts +3 -3
  215. package/dist/tools/save-file.d.ts.map +1 -1
  216. package/dist/tools/save-file.js +11 -11
  217. package/dist/tools/skill.d.ts +23 -0
  218. package/dist/tools/skill.d.ts.map +1 -0
  219. package/dist/tools/skill.js +65 -0
  220. package/dist/tools/think.d.ts.map +1 -1
  221. package/dist/tools/think.js +2 -9
  222. package/dist/tools/utils.d.ts +2 -0
  223. package/dist/tools/utils.d.ts.map +1 -1
  224. package/dist/tools/utils.js +12 -0
  225. package/dist/tools/web-fetch.d.ts +62 -0
  226. package/dist/tools/web-fetch.d.ts.map +1 -0
  227. package/dist/tools/web-fetch.js +429 -0
  228. package/dist/tools/web-search.d.ts +62 -0
  229. package/dist/tools/web-search.d.ts.map +1 -0
  230. package/dist/tools/web-search.js +226 -0
  231. package/dist/tui/autocomplete/attachment-provider.d.ts +3 -6
  232. package/dist/tui/autocomplete/attachment-provider.d.ts.map +1 -1
  233. package/dist/tui/autocomplete/attachment-provider.js +25 -78
  234. package/dist/tui/autocomplete/base-provider.d.ts +1 -0
  235. package/dist/tui/autocomplete/base-provider.d.ts.map +1 -1
  236. package/dist/tui/autocomplete/combined-provider.d.ts +1 -4
  237. package/dist/tui/autocomplete/combined-provider.d.ts.map +1 -1
  238. package/dist/tui/autocomplete/combined-provider.js +3 -17
  239. package/dist/tui/autocomplete/command-provider.d.ts +1 -0
  240. package/dist/tui/autocomplete/command-provider.d.ts.map +1 -1
  241. package/dist/tui/autocomplete/command-provider.js +3 -0
  242. package/dist/tui/autocomplete/file-search-provider.d.ts +2 -1
  243. package/dist/tui/autocomplete/file-search-provider.d.ts.map +1 -1
  244. package/dist/tui/autocomplete/file-search-provider.js +36 -16
  245. package/dist/tui/autocomplete/skill-provider.d.ts +17 -0
  246. package/dist/tui/autocomplete/skill-provider.d.ts.map +1 -0
  247. package/dist/tui/autocomplete/skill-provider.js +49 -0
  248. package/dist/tui/autocomplete.d.ts +2 -2
  249. package/dist/tui/autocomplete.d.ts.map +1 -1
  250. package/dist/tui/autocomplete.js +3 -5
  251. package/dist/tui/components/assistant-message.d.ts.map +1 -1
  252. package/dist/tui/components/assistant-message.js +0 -4
  253. package/dist/tui/components/editor.d.ts +21 -2
  254. package/dist/tui/components/editor.d.ts.map +1 -1
  255. package/dist/tui/components/editor.js +228 -236
  256. package/dist/tui/components/footer.d.ts +6 -4
  257. package/dist/tui/components/footer.d.ts.map +1 -1
  258. package/dist/tui/components/footer.js +49 -25
  259. package/dist/tui/components/markdown.d.ts +8 -5
  260. package/dist/tui/components/markdown.d.ts.map +1 -1
  261. package/dist/tui/components/markdown.js +57 -39
  262. package/dist/tui/components/modal.d.ts.map +1 -1
  263. package/dist/tui/components/modal.js +35 -33
  264. package/dist/tui/components/notification.d.ts +13 -2
  265. package/dist/tui/components/notification.d.ts.map +1 -1
  266. package/dist/tui/components/notification.js +37 -2
  267. package/dist/tui/components/progress-bar.js +1 -1
  268. package/dist/tui/components/select-list.d.ts +1 -0
  269. package/dist/tui/components/select-list.d.ts.map +1 -1
  270. package/dist/tui/components/select-list.js +14 -11
  271. package/dist/tui/components/text.d.ts +16 -0
  272. package/dist/tui/components/text.d.ts.map +1 -1
  273. package/dist/tui/components/text.js +72 -57
  274. package/dist/tui/components/thinking-block.d.ts +9 -0
  275. package/dist/tui/components/thinking-block.d.ts.map +1 -1
  276. package/dist/tui/components/thinking-block.js +43 -11
  277. package/dist/tui/components/tool-execution.d.ts +5 -1
  278. package/dist/tui/components/tool-execution.d.ts.map +1 -1
  279. package/dist/tui/components/tool-execution.js +19 -10
  280. package/dist/tui/components/user-message.d.ts.map +1 -1
  281. package/dist/tui/components/user-message.js +0 -3
  282. package/dist/tui/components/welcome.js +2 -2
  283. package/dist/tui/editor-launcher.d.ts +13 -0
  284. package/dist/tui/editor-launcher.d.ts.map +1 -0
  285. package/dist/tui/editor-launcher.js +39 -0
  286. package/dist/tui/index.d.ts +3 -1
  287. package/dist/tui/index.d.ts.map +1 -1
  288. package/dist/tui/index.js +1 -0
  289. package/dist/tui/terminal.d.ts +27 -0
  290. package/dist/tui/terminal.d.ts.map +1 -1
  291. package/dist/tui/terminal.js +144 -15
  292. package/dist/tui/tui.d.ts +43 -0
  293. package/dist/tui/tui.d.ts.map +1 -1
  294. package/dist/tui/tui.js +172 -41
  295. package/dist/utils/bash/parse.d.ts +19 -0
  296. package/dist/utils/bash/parse.d.ts.map +1 -0
  297. package/dist/utils/bash/parse.js +223 -0
  298. package/dist/utils/bash/quote.d.ts +6 -0
  299. package/dist/utils/bash/quote.d.ts.map +1 -0
  300. package/dist/utils/bash/quote.js +23 -0
  301. package/dist/utils/bash.d.ts.map +1 -1
  302. package/dist/utils/bash.js +211 -126
  303. package/dist/utils/command-protection.d.ts +28 -0
  304. package/dist/utils/command-protection.d.ts.map +1 -0
  305. package/dist/utils/command-protection.js +324 -0
  306. package/dist/utils/dedent.d.ts.map +1 -0
  307. package/dist/utils/env-expand.d.ts +2 -0
  308. package/dist/utils/env-expand.d.ts.map +1 -0
  309. package/dist/utils/env-expand.js +8 -0
  310. package/dist/utils/filesystem/path-display.d.ts +11 -0
  311. package/dist/utils/filesystem/path-display.d.ts.map +1 -0
  312. package/dist/utils/filesystem/path-display.js +32 -0
  313. package/dist/utils/filesystem/security.d.ts +2 -2
  314. package/dist/utils/filesystem/security.d.ts.map +1 -1
  315. package/dist/utils/filesystem/security.js +32 -31
  316. package/dist/utils/formatting.d.ts.map +1 -0
  317. package/dist/{formatting.js → utils/formatting.js} +1 -1
  318. package/dist/utils/git.d.ts +4 -0
  319. package/dist/utils/git.d.ts.map +1 -1
  320. package/dist/utils/git.js +30 -0
  321. package/dist/utils/glob.d.ts +1 -1
  322. package/dist/utils/glob.d.ts.map +1 -1
  323. package/dist/utils/logger.d.ts.map +1 -0
  324. package/dist/{logger.js → utils/logger.js} +1 -1
  325. package/dist/utils/parsing.d.ts.map +1 -0
  326. package/dist/utils/process.d.ts.map +1 -1
  327. package/dist/utils/process.js +90 -37
  328. package/dist/utils/templates.d.ts +2 -0
  329. package/dist/utils/templates.d.ts.map +1 -0
  330. package/dist/utils/templates.js +24 -0
  331. package/dist/utils/version.d.ts.map +1 -0
  332. package/dist/{version.js → utils/version.js} +1 -1
  333. package/package.json +34 -25
  334. package/dist/cli.d.ts +0 -23
  335. package/dist/cli.d.ts.map +0 -1
  336. package/dist/commands/exit/index.d.ts +0 -10
  337. package/dist/commands/exit/index.d.ts.map +0 -1
  338. package/dist/commands/exit/index.js +0 -21
  339. package/dist/commands/exit/types.d.ts +0 -8
  340. package/dist/commands/exit/types.d.ts.map +0 -1
  341. package/dist/commands/exit/types.js +0 -1
  342. package/dist/commands/exit/utils.d.ts +0 -2
  343. package/dist/commands/exit/utils.d.ts.map +0 -1
  344. package/dist/commands/exit/utils.js +0 -13
  345. package/dist/commands/prompt/index.d.ts +0 -5
  346. package/dist/commands/prompt/index.d.ts.map +0 -1
  347. package/dist/commands/prompt/index.js +0 -126
  348. package/dist/commands/prompt/types.d.ts +0 -15
  349. package/dist/commands/prompt/types.d.ts.map +0 -1
  350. package/dist/commands/prompt/types.js +0 -1
  351. package/dist/commands/prompt/utils.d.ts +0 -12
  352. package/dist/commands/prompt/utils.d.ts.map +0 -1
  353. package/dist/commands/prompt/utils.js +0 -107
  354. package/dist/commands/reset/index.d.ts +0 -3
  355. package/dist/commands/reset/index.d.ts.map +0 -1
  356. package/dist/commands/reset/index.js +0 -25
  357. package/dist/commands/reset/types.d.ts +0 -1
  358. package/dist/commands/reset/types.d.ts.map +0 -1
  359. package/dist/commands/reset/types.js +0 -3
  360. package/dist/commands/save/index.d.ts +0 -3
  361. package/dist/commands/save/index.d.ts.map +0 -1
  362. package/dist/commands/save/index.js +0 -19
  363. package/dist/config.d.ts.map +0 -1
  364. package/dist/dedent.d.ts.map +0 -1
  365. package/dist/formatting.d.ts.map +0 -1
  366. package/dist/logger.d.ts.map +0 -1
  367. package/dist/mentions.d.ts +0 -14
  368. package/dist/mentions.d.ts.map +0 -1
  369. package/dist/parsing.d.ts.map +0 -1
  370. package/dist/prompts.d.ts +0 -10
  371. package/dist/prompts.d.ts.map +0 -1
  372. package/dist/repl-new.d.ts +0 -62
  373. package/dist/repl-new.d.ts.map +0 -1
  374. package/dist/skills.d.ts.map +0 -1
  375. package/dist/skills.js +0 -233
  376. package/dist/tui/autocomplete/path-provider.d.ts +0 -21
  377. package/dist/tui/autocomplete/path-provider.d.ts.map +0 -1
  378. package/dist/tui/autocomplete/path-provider.js +0 -164
  379. package/dist/version.d.ts.map +0 -1
  380. /package/dist/{dedent.d.ts → utils/dedent.d.ts} +0 -0
  381. /package/dist/{dedent.js → utils/dedent.js} +0 -0
  382. /package/dist/{formatting.d.ts → utils/formatting.d.ts} +0 -0
  383. /package/dist/{logger.d.ts → utils/logger.d.ts} +0 -0
  384. /package/dist/{parsing.d.ts → utils/parsing.d.ts} +0 -0
  385. /package/dist/{parsing.js → utils/parsing.js} +0 -0
  386. /package/dist/{version.d.ts → utils/version.d.ts} +0 -0
@@ -0,0 +1,109 @@
1
+ import { generateText, stepCountIs } from "ai";
2
+ import { config } from "../config/index.js";
3
+ import { AiConfig } from "../models/ai-config.js";
4
+ import { getLanguageModel, getModelMetadata } from "../models/manager.js";
5
+ import { initTools } from "../tools/index.js";
6
+ import { toAiSdkTools } from "../tools/utils.js";
7
+ export class SubAgent {
8
+ workspace;
9
+ constructor(options) {
10
+ this.workspace = options.workspace;
11
+ }
12
+ async execute({ model, system, prompt, abortSignal, allowedTools, timeout, }) {
13
+ try {
14
+ const { tools, abortSignal: combinedSignal, timeoutId, } = await this.prepareExecution({
15
+ allowedTools,
16
+ timeout,
17
+ abortSignal,
18
+ });
19
+ try {
20
+ const result = await this.runGenerateText({
21
+ model,
22
+ system,
23
+ prompt,
24
+ tools,
25
+ abortSignal: combinedSignal,
26
+ });
27
+ return result.text;
28
+ }
29
+ finally {
30
+ if (timeoutId) {
31
+ clearTimeout(timeoutId);
32
+ }
33
+ }
34
+ }
35
+ catch (error) {
36
+ throw this.transformError(error);
37
+ }
38
+ }
39
+ async prepareExecution({ allowedTools, timeout, abortSignal, }) {
40
+ let tools = await initTools({
41
+ workspace: this.workspace,
42
+ });
43
+ tools = this.filterTools(tools, allowedTools);
44
+ const { signal: timeoutSignal, timeoutId } = this.createTimeoutSignal(timeout);
45
+ const combinedSignal = this.combineAbortSignals(timeoutSignal, abortSignal);
46
+ return { tools, abortSignal: combinedSignal, timeoutId };
47
+ }
48
+ filterTools(tools, allowedTools) {
49
+ if (!allowedTools || allowedTools.length === 0) {
50
+ return tools;
51
+ }
52
+ const filteredTools = {};
53
+ for (const [key, value] of Object.entries(tools)) {
54
+ if (allowedTools.includes(key)) {
55
+ filteredTools[key] = value;
56
+ }
57
+ }
58
+ return filteredTools;
59
+ }
60
+ createTimeoutSignal(timeout) {
61
+ if (!timeout || timeout <= 0) {
62
+ return { signal: undefined, timeoutId: undefined };
63
+ }
64
+ const controller = new AbortController();
65
+ const timeoutId = setTimeout(() => {
66
+ controller.abort(new Error(`SubAgent timed out after ${timeout} seconds`));
67
+ }, timeout * 1000);
68
+ return { signal: controller.signal, timeoutId };
69
+ }
70
+ combineAbortSignals(timeoutSignal, abortSignal) {
71
+ const signals = [timeoutSignal, abortSignal].filter((s) => s != null);
72
+ if (signals.length === 0) {
73
+ return undefined;
74
+ }
75
+ if (signals.length === 1) {
76
+ return signals[0];
77
+ }
78
+ return AbortSignal.any(signals);
79
+ }
80
+ async runGenerateText({ model, system, prompt, tools, abortSignal, }) {
81
+ const modelConfig = getModelMetadata({ model });
82
+ const aiConfig = new AiConfig({
83
+ modelMetadata: modelConfig,
84
+ prompt,
85
+ });
86
+ const stateDir = await config.app.ensurePath("audit");
87
+ return generateText({
88
+ model: getLanguageModel({ model, app: "subagent", stateDir }),
89
+ maxOutputTokens: aiConfig.maxOutputTokens(),
90
+ system,
91
+ prompt,
92
+ temperature: aiConfig.temperature(),
93
+ topP: aiConfig.topP(),
94
+ stopWhen: stepCountIs(100),
95
+ providerOptions: aiConfig.providerOptions(),
96
+ tools: toAiSdkTools(tools),
97
+ abortSignal,
98
+ });
99
+ }
100
+ transformError(error) {
101
+ if (error.name === "AbortError" || error.name === "TimeoutError") {
102
+ if (error.message.includes("timed out")) {
103
+ return new Error(error.message);
104
+ }
105
+ return new Error(`SubAgent execution was aborted: ${error.message}`);
106
+ }
107
+ return error;
108
+ }
109
+ }
@@ -0,0 +1,26 @@
1
+ import type { WorkspaceContext } from "../index.ts";
2
+ import type { ModelManager } from "../models/manager.js";
3
+ import type { PromptManager } from "../prompts/manager.ts";
4
+ import type { SessionManager } from "../sessions/manager.ts";
5
+ import type { TokenCounter } from "../tokens/counter.ts";
6
+ import type { TokenTracker } from "../tokens/tracker.ts";
7
+ interface CliOptions {
8
+ sessionManager: SessionManager;
9
+ promptManager: PromptManager;
10
+ modelManager: ModelManager;
11
+ tokenTracker: TokenTracker;
12
+ tokenCounter: TokenCounter;
13
+ workspace: WorkspaceContext;
14
+ noSession?: boolean;
15
+ }
16
+ export declare class Cli {
17
+ private options;
18
+ constructor(options: CliOptions);
19
+ run(): Promise<void>;
20
+ private setupSignalHandlers;
21
+ private initializeAiConfig;
22
+ private handleAbort;
23
+ private handleError;
24
+ }
25
+ export {};
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/cli/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMzD,UAAU,UAAU;IAClB,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;IAC3B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,GAAG;IACd,OAAO,CAAC,OAAO,CAAa;gBAChB,OAAO,EAAE,UAAU;IAIzB,GAAG;IAiFT,OAAO,CAAC,mBAAmB;YAab,kBAAkB;YA8BlB,WAAW;IAYzB,OAAO,CAAC,WAAW;CAQpB"}
@@ -1,121 +1,121 @@
1
- import { generateText, NoSuchToolError, Output, stepCountIs, tool, } from "ai";
2
- import { logger } from "./logger.js";
3
- import { AiConfig } from "./models/ai-config.js";
4
- import { systemPrompt } from "./prompts.js";
5
- import { BashTool } from "./tools/bash.js";
6
- import { EditFileTool } from "./tools/edit-file.js";
7
- import { GlobTool } from "./tools/glob.js";
8
- import { GrepTool } from "./tools/grep.js";
9
- import { initTools } from "./tools/index.js";
10
- import { ReadFileTool } from "./tools/read-file.js";
11
- const activeTools = [
12
- EditFileTool.name,
13
- ReadFileTool.name,
14
- BashTool.name,
15
- GrepTool.name,
16
- GlobTool.name,
17
- ];
1
+ import { generateText, NoSuchToolError, Output, stepCountIs, } from "ai";
2
+ import { config } from "../config/index.js";
3
+ import { AiConfig } from "../models/ai-config.js";
4
+ import { systemPrompt } from "../prompts/system-prompt.js";
5
+ import { printExitSummary } from "../sessions/summary.js";
6
+ import { initTools } from "../tools/index.js";
7
+ import { toAiSdkTools } from "../tools/utils.js";
8
+ import { logger } from "../utils/logger.js";
18
9
  export class Cli {
19
10
  options;
20
- skillsEnabled;
21
11
  constructor(options) {
22
12
  this.options = options;
23
- this.skillsEnabled = options.skillsEnabled ?? true;
24
13
  }
25
14
  async run() {
26
- const { promptManager, modelManager, tokenTracker, messageHistory } = this.options;
15
+ const { promptManager, modelManager, tokenTracker, sessionManager } = this.options;
27
16
  const abortController = new AbortController();
28
17
  const { signal } = abortController;
29
- const cb = () => {
30
- abortController.abort();
31
- };
32
- // Handle Ctrl+C (SIGINT)
33
- process.on("SIGINT", cb);
18
+ const { cleanup } = this.setupSignalHandlers(abortController);
34
19
  const langModel = modelManager.getModel("cli");
35
20
  const modelConfig = modelManager.getModelMetadata("cli");
36
21
  const userPrompt = promptManager.get();
37
22
  const userMsg = promptManager.getUserMessage();
38
- messageHistory.appendUserMessage(userMsg);
39
- const finalSystemPrompt = await systemPrompt({
40
- activeTools,
41
- allowedDirs: this.options.workspace.allowedDirs,
42
- skillsEnabled: this.skillsEnabled,
43
- });
44
- const aiConfig = new AiConfig({
45
- modelMetadata: modelConfig,
46
- prompt: userPrompt,
47
- });
48
- const tools = await initTools({
49
- workspace: this.options.workspace,
23
+ sessionManager.appendUserMessage(userMsg);
24
+ const { aiConfig, finalSystemPrompt, tools } = await this.initializeAiConfig({
25
+ userPrompt,
26
+ modelConfig,
50
27
  });
51
- // Cleanup function to remove signal handler
52
- const cleanup = () => {
53
- process.removeListener("SIGINT", cb);
54
- };
55
28
  try {
56
29
  const result = await generateText({
57
30
  model: langModel,
58
31
  maxOutputTokens: aiConfig.maxOutputTokens(),
59
32
  system: finalSystemPrompt,
60
- messages: messageHistory.get(),
33
+ messages: sessionManager.get(),
61
34
  temperature: aiConfig.temperature(),
62
35
  topP: aiConfig.topP(),
63
36
  stopWhen: stepCountIs(200),
64
37
  maxRetries: 2,
65
38
  providerOptions: aiConfig.providerOptions(),
66
- tools: Object.fromEntries(Object.entries(tools).map((t) => [
67
- t[0],
68
- tool({
69
- ...t[1]["toolDef"],
70
- execute: t[1]["execute"],
71
- }),
72
- ])),
73
- activeTools,
39
+ tools: toAiSdkTools(tools),
74
40
  // biome-ignore lint/style/useNamingConvention: third-party controlled
75
41
  experimental_repairToolCall: toolCallRepair(modelManager),
76
42
  abortSignal: signal,
77
43
  });
78
44
  if (result.response.messages.length > 0) {
79
- messageHistory.appendResponseMessages(result.response.messages);
45
+ sessionManager.appendResponseMessages(result.response.messages);
80
46
  }
81
47
  // this tracks the usage of every step in the call to streamText. it's a cumulative usage.
82
48
  tokenTracker.trackUsage("cli", result.usage);
83
- await messageHistory.save();
49
+ if (!this.options.noSession) {
50
+ await sessionManager.save();
51
+ }
84
52
  process.stdout.end(result.text.endsWith("\n") ? result.text : `${result.text}\n`);
53
+ if (!sessionManager.isEmpty()) {
54
+ printExitSummary(sessionManager, this.options.noSession);
55
+ }
85
56
  cleanup();
57
+ process.exit(0);
86
58
  }
87
59
  catch (e) {
88
- // Always cleanup signal handler
89
60
  cleanup();
90
- // Check if it's an abort error or if the signal was aborted
91
61
  const isAbortError = (e instanceof Error &&
92
62
  (e.name === "AbortError" ||
93
63
  e.message.includes("aborted") ||
94
64
  e.message.includes("No output generated"))) ||
95
65
  signal.aborted;
96
66
  if (isAbortError) {
97
- logger.info("CLI execution interrupted by user");
98
- // Try to save message history before exiting
99
- try {
100
- await messageHistory.save();
101
- }
102
- catch (_saveError) {
103
- // Ignore save errors on abort
104
- logger.warn("Failed to save message history on interrupt");
105
- }
106
- process.exit(0); // Exit gracefully
67
+ await this.handleAbort();
107
68
  }
108
69
  else {
109
- if (e instanceof Error) {
110
- logger.error(e);
111
- }
112
- else {
113
- logger.error(JSON.stringify(e, null, 2));
114
- }
115
- process.exit(1);
70
+ this.handleError(e);
116
71
  }
117
72
  }
118
73
  }
74
+ setupSignalHandlers(abortController) {
75
+ const cb = abortController.abort.bind(abortController);
76
+ process.on("SIGINT", cb);
77
+ const cleanup = () => {
78
+ process.removeListener("SIGINT", cb);
79
+ };
80
+ return { cleanup };
81
+ }
82
+ async initializeAiConfig({ userPrompt, modelConfig, }) {
83
+ const cliConfig = await config.getConfig();
84
+ const finalSystemPromptResult = await systemPrompt({
85
+ allowedDirs: this.options.workspace.allowedDirs,
86
+ logsPath: cliConfig.logs?.path,
87
+ });
88
+ const finalSystemPrompt = finalSystemPromptResult.prompt;
89
+ const aiConfig = new AiConfig({
90
+ modelMetadata: modelConfig,
91
+ prompt: userPrompt,
92
+ });
93
+ const tools = await initTools({
94
+ workspace: this.options.workspace,
95
+ });
96
+ return { aiConfig, finalSystemPrompt, tools };
97
+ }
98
+ async handleAbort() {
99
+ logger.info("CLI execution interrupted by user");
100
+ if (!this.options.noSession) {
101
+ try {
102
+ await this.options.sessionManager.save();
103
+ }
104
+ catch {
105
+ logger.warn("Failed to save message history on interrupt");
106
+ }
107
+ }
108
+ process.exit(0);
109
+ }
110
+ handleError(e) {
111
+ if (e instanceof Error) {
112
+ logger.error(e);
113
+ }
114
+ else {
115
+ logger.error(JSON.stringify(e, null, 2));
116
+ }
117
+ process.exit(1);
118
+ }
119
119
  }
120
120
  const toolCallRepair = (modelManager) => {
121
121
  const fn = async ({ toolCall, tools, inputSchema, error, }) => {
@@ -130,11 +130,19 @@ const toolCallRepair = (modelManager) => {
130
130
  schema: tool.inputSchema,
131
131
  }),
132
132
  prompt: [
133
- `The model tried to call the tool "${toolCall.toolName}" with the following arguments:`,
134
- JSON.stringify(toolCall.input),
135
- "The tool accepts the following schema:",
136
- JSON.stringify(inputSchema(toolCall)),
137
- "Please fix the arguments.",
133
+ `The model tried to call the tool "${toolCall.toolName}" but the input did not match the expected schema.`,
134
+ "",
135
+ "<invalid_input>",
136
+ JSON.stringify(toolCall.input, null, 2),
137
+ "</invalid_input>",
138
+ "",
139
+ "<expected_schema>",
140
+ JSON.stringify(await inputSchema({ toolName: toolCall.toolName }), null, 2),
141
+ "</expected_schema>",
142
+ "",
143
+ "If any field is missing or undefined in the corrected input, you MUST explicitly set its value to null. Do NOT omit fields - every field in the schema must be present, even if with a null value.",
144
+ "",
145
+ "Return a corrected version of the input that conforms to the expected schema.",
138
146
  ].join("\n"),
139
147
  });
140
148
  return { ...toolCall, args: JSON.stringify(repairedArgs) };
@@ -0,0 +1,9 @@
1
+ export declare const STDIN_SOFT_LIMIT: number;
2
+ export declare const STDIN_HARD_LIMIT: number;
3
+ export interface StdinResult {
4
+ content: string | null;
5
+ sizeBytes: number;
6
+ wasPiped: boolean;
7
+ }
8
+ export declare function readStdinWithLimits(): Promise<StdinResult>;
9
+ //# sourceMappingURL=stdin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../../source/cli/stdin.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,QAAY,CAAC;AAC1C,eAAO,MAAM,gBAAgB,QAAa,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,WAAW,CAAC,CA2ChE"}
@@ -0,0 +1,37 @@
1
+ import { text } from "node:stream/consumers";
2
+ export const STDIN_SOFT_LIMIT = 50 * 1024; // 50KB
3
+ export const STDIN_HARD_LIMIT = 200 * 1024; // 200KB
4
+ export async function readStdinWithLimits() {
5
+ if (process.stdin.isTTY) {
6
+ return { content: null, sizeBytes: 0, wasPiped: false };
7
+ }
8
+ // Check if stdin is a pipe (piped input) vs just not a TTY
9
+ // When stdin is a TTY or a pipe, we can read from it
10
+ // When stdin is neither (e.g., running in background without TTY or pipe), treat as empty
11
+ const isPipe = process.stdin.readableObjectMode ||
12
+ // @ts-expect-error - _isStdio is internal
13
+ process.stdin._isStdio;
14
+ // Check if stdin has data by attempting a non-blocking read
15
+ // If stdin is not a pipe and not a TTY, treat it as empty (no input)
16
+ if (!isPipe) {
17
+ return { content: null, sizeBytes: 0, wasPiped: false };
18
+ }
19
+ try {
20
+ const content = await text(process.stdin);
21
+ const sizeBytes = Buffer.byteLength(content, "utf8");
22
+ if (sizeBytes > STDIN_HARD_LIMIT) {
23
+ const sizeKb = Math.round(sizeBytes / 1024);
24
+ console.error(`Error: Input exceeds ${STDIN_HARD_LIMIT / 1024}KB size limit (${sizeKb}KB provided).`);
25
+ process.exit(1);
26
+ }
27
+ if (sizeBytes > STDIN_SOFT_LIMIT) {
28
+ const sizeKb = Math.round(sizeBytes / 1024);
29
+ console.error(`Warning: Input is ${sizeKb}KB. Large inputs may increase latency and costs.`);
30
+ }
31
+ return { content, sizeBytes, wasPiped: true };
32
+ }
33
+ catch (error) {
34
+ console.error(`Error reading stdin: ${error.message}`);
35
+ return { content: null, sizeBytes: 0, wasPiped: true };
36
+ }
37
+ }
@@ -10,8 +10,8 @@ export function copyCommand(options) {
10
10
  return [];
11
11
  },
12
12
  async handle(_args, { tui, container, editor, }) {
13
- const { sessionManager: messageHistory } = options;
14
- const history = messageHistory.get();
13
+ const { sessionManager } = options;
14
+ const history = sessionManager.get();
15
15
  container.addChild(new Spacer(1));
16
16
  const lastText = extractLastAssistantText(history);
17
17
  if (!lastText) {
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../source/commands/copy/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,IAAI,CAAC;AAEjD,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,YAAY,EAAE,GACvB,MAAM,GAAG,IAAI,CAoBf"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../source/commands/copy/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,IAAI,CAAC;AAYjD,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,YAAY,EAAE,GACvB,MAAM,GAAG,IAAI,CAUf"}
@@ -1,22 +1,24 @@
1
+ function findLastNonEmptyText(content) {
2
+ for (let j = content.length - 1; j >= 0; j--) {
3
+ const part = content[j];
4
+ if (part?.type !== "text")
5
+ continue;
6
+ const text = part.text;
7
+ if (typeof text === "string" && text.trim().length > 0)
8
+ return text;
9
+ }
10
+ return null;
11
+ }
1
12
  export function extractLastAssistantText(messages) {
2
13
  for (let i = messages.length - 1; i >= 0; i--) {
3
14
  const msg = messages[i];
4
- if (!msg)
5
- continue;
6
- if (msg.role !== "assistant")
15
+ if (msg?.role !== "assistant")
7
16
  continue;
8
17
  if (!("content" in msg) || !Array.isArray(msg.content))
9
18
  continue;
10
- for (let j = msg.content.length - 1; j >= 0; j--) {
11
- const part = msg.content[j];
12
- if (part != null &&
13
- part.type === "text" &&
14
- typeof part.text === "string") {
15
- const text = part.text;
16
- if (text.trim().length > 0)
17
- return text;
18
- }
19
- }
19
+ const text = findLastNonEmptyText(msg.content);
20
+ if (text !== null)
21
+ return text;
20
22
  }
21
23
  return null;
22
24
  }
@@ -1,3 +1,3 @@
1
1
  import type { CommandOptions, ReplCommand } from "../types.ts";
2
- export declare const generateRulesCommand: ({ sessionManager: messageHistory, modelManager, tokenTracker, config, workspace, }: CommandOptions) => ReplCommand;
2
+ export declare const generateRulesCommand: ({ sessionManager, modelManager, tokenTracker, config, workspace, }: CommandOptions) => ReplCommand;
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/generate-rules/index.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/D,eAAO,MAAM,oBAAoB,GAAI,oFAMlC,cAAc,KAAG,WA+HnB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/generate-rules/index.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/D,eAAO,MAAM,oBAAoB,GAAI,oEAMlC,cAAc,KAAG,WA4HnB,CAAC"}
@@ -1,18 +1,16 @@
1
- import { generateText } from "ai";
2
- import { logger } from "../../logger.js";
3
- import { systemPrompt } from "../../prompts.js";
4
- import { createUserMessage } from "../../sessions/manager.js";
5
- import { getTerminalSize, isArrowDown, isArrowUp, isEnter, isEscape, } from "../../terminal/control.js";
1
+ import { getTerminalSize, isArrowDown, isArrowUp, isEnter, isEscape, isShiftTab, isTab, } from "../../terminal/control.js";
6
2
  import style from "../../terminal/style.js";
7
3
  import { Container, Input, Spacer, Text, } from "../../tui/index.js";
4
+ import { logger } from "../../utils/logger.js";
5
+ import { generateRulesFromSession } from "./service.js";
8
6
  import { hideRuleSelector } from "./utils.js";
9
- export const generateRulesCommand = ({ sessionManager: messageHistory, modelManager, tokenTracker, config, workspace, }) => {
7
+ export const generateRulesCommand = ({ sessionManager, modelManager, tokenTracker, config, workspace, }) => {
10
8
  return {
11
9
  command: "/generate-rules",
12
10
  description: "Analyzes the current conversation to generate and save new interaction rules, then displays them.",
13
11
  getSubCommands: () => Promise.resolve([]),
14
12
  async handle(_args, { tui, container, inputContainer, editor, }) {
15
- if (messageHistory.isEmpty()) {
13
+ if (sessionManager.isEmpty()) {
16
14
  container.addChild(new Text(style.yellow("Cannot generate rules from an empty conversation."), 1, 0));
17
15
  tui.requestRender();
18
16
  editor.setText("");
@@ -21,9 +19,9 @@ export const generateRulesCommand = ({ sessionManager: messageHistory, modelMana
21
19
  container.addChild(new Text("Analyzing conversation to generate rules...", 0, 1));
22
20
  tui.requestRender();
23
21
  try {
24
- const newRules = await analyzeConversation({
22
+ const { rules: newRules } = await generateRulesFromSession({
25
23
  modelManager,
26
- messages: messageHistory.get(),
24
+ messages: sessionManager.get(),
27
25
  tokenTracker,
28
26
  config,
29
27
  workspace,
@@ -40,13 +38,13 @@ export const generateRulesCommand = ({ sessionManager: messageHistory, modelMana
40
38
  }
41
39
  else {
42
40
  try {
43
- const existingRules = await config.readProjectLearnedRulesFile();
41
+ const existingRules = await config.readLearnedRulesFile();
44
42
  const rulesToAdd = selectedRules.join("\n");
45
- const updatedProjectRules = existingRules.endsWith("\n") || existingRules.length === 0
43
+ const updatedRules = existingRules.endsWith("\n") || existingRules.length === 0
46
44
  ? `${existingRules}${rulesToAdd}`
47
45
  : `${existingRules}\n${rulesToAdd}`;
48
- await config.writeProjectLearnedRulesFile(updatedProjectRules);
49
- container.addChild(new Text(style.green("Selected rules saved to project learned rules."), 2, 0));
46
+ await config.writeLearnedRulesFile(updatedRules);
47
+ container.addChild(new Text(style.green("Selected rules saved to learned rules."), 2, 0));
50
48
  container.addChild(new Text(style.dim("Saved rules:"), 3, 0));
51
49
  selectedRules.forEach((rule, index) => {
52
50
  container.addChild(new Text(`- ${rule}`, 4 + index, 0));
@@ -79,91 +77,6 @@ export const generateRulesCommand = ({ sessionManager: messageHistory, modelMana
79
77
  },
80
78
  };
81
79
  };
82
- async function analyzeConversation({ modelManager, messages, tokenTracker, config: configManager, workspace, }) {
83
- const learnedRules = await configManager.readCachedLearnedRulesFile();
84
- messages.push(createUserMessage([
85
- `Analyze this conversation based on the system instructions. Identify points where the user made significant corrections revealing general principles for agent improvement. Infer concise, broadly applicable rules (Always/Never) based *only* on these corrections.
86
-
87
- **Key Requirements:**
88
- - Focus on *generalizable* rules applicable to future, different tasks.
89
- - Avoid rules tied to the specifics of *this* conversation.
90
- - Ensure rules don't already exist in <existing-rules>.
91
- - If no *new, general* rules can be inferred, return an empty list or response.
92
- - Return *only* the Markdown list of rules, with no preamble or explanation.
93
-
94
- <existing-rules>
95
- ${learnedRules}
96
- </existing-rules>`,
97
- ]));
98
- const systemPromptText = await createSystemPrompt(configManager, workspace);
99
- const { text, usage } = await generateText({
100
- model: modelManager.getModel("conversation-analyzer"),
101
- maxOutputTokens: 8192,
102
- system: systemPromptText,
103
- messages: messages,
104
- });
105
- tokenTracker.trackUsage("conversation-analyzer", usage);
106
- const potentialRulesText = text.trim();
107
- if (!potentialRulesText || potentialRulesText.length === 0) {
108
- return [];
109
- }
110
- const potentialRulesList = potentialRulesText
111
- .split("\n")
112
- .map((rule) => rule.trim())
113
- .filter((rule) => rule.length > 0);
114
- if (potentialRulesList.length === 0) {
115
- return [];
116
- }
117
- const updatedRules = learnedRules.endsWith("\n") || learnedRules.length === 0
118
- ? `${learnedRules}${potentialRulesList.join("\n")}`
119
- : `${learnedRules}\n${potentialRulesList.join("\n")}`;
120
- await configManager.writeCachedLearnedRulesFile(updatedRules);
121
- return potentialRulesList;
122
- }
123
- async function createSystemPrompt(configManager, workspace) {
124
- const projectConfig = await configManager.getConfig();
125
- const sys = await systemPrompt({
126
- activeTools: projectConfig.tools.activeTools,
127
- includeRules: true,
128
- allowedDirs: workspace.allowedDirs,
129
- });
130
- return `You are an expert analyst reviewing conversations between a coding agent and a software engineer. Your goal is to identify instances where the engineer corrected the agent's approach or understanding in a way that reveals a *generalizable principle* for improving the agent's future behavior across *different* tasks.
131
-
132
- **Your Task:**
133
- 1. Analyze the conversation provided.
134
- 2. Identify significant corrections or redirections from the engineer. Ignore minor clarifications or task-specific adjustments.
135
- 3. For each significant correction, infer a *single, concise, broadly applicable, actionable rule* (starting with 'Always' or 'Never') that captures the underlying principle the agent should follow in the future.
136
- 4. Ensure the rule is general enough to be useful in various scenarios, not just the specific context of this conversation.
137
- 5. Provide a brief, illustrative quote or example from the conversation in parentheses after the rule.
138
- 6. List only the inferred rules in Markdown bullet points. Do not include explanations, summaries, or conversational filler.
139
-
140
- **Crucially, AVOID generating rules that are:**
141
- - Overly specific to the files, functions, or variables discussed (e.g., "Always check for null in the 'processUserData' function"). Instead, generalize (e.g., "Always validate data from external sources before processing").
142
- - Merely restatements of the task requirements.
143
- - Too narrow to be useful outside the immediate context.
144
- - Related to minor typos or formatting preferences unless they represent a consistent pattern requested by the user.
145
-
146
- **Good General Rule Examples:**
147
- <examples>
148
- - Always ask for clarification if the user's request is ambiguous.
149
- - Never make assumptions about file paths without confirmation.
150
- - Always follow the user's explicitly stated formatting preferences.
151
- - Never provide incomplete code snippets without indicating they are partial.
152
- - Always check for potential null or undefined values before accessing properties.
153
- </examples>
154
-
155
- **Bad Specific Rule Examples (Avoid These):**
156
- <bad-examples>
157
- - Always use 'const' instead of 'let' for the 'userId' variable in 'auth.ts'.
158
- - Never forget to pass the 'config' object to the 'initializeDb' function.
159
- - Always add a try-catch block around the 'api.fetchData()' call in 'dataService.ts'.
160
- </bad-examples>
161
-
162
- This is the original system prompt the agent operated under:
163
- <systemPrompt>
164
- ${sys}
165
- </systemPrompt>`;
166
- }
167
80
  class RuleSelectorComponent extends Container {
168
81
  searchInput;
169
82
  listContainer;
@@ -246,12 +159,15 @@ class RuleSelectorComponent extends Container {
246
159
  this.listContainer.addChild(new Text(style.gray(" No matching rules"), 0, 0));
247
160
  }
248
161
  }
162
+ wantsNavigationKeys() {
163
+ return true;
164
+ }
249
165
  handleInput(keyData) {
250
- if (isArrowUp(keyData)) {
166
+ if (isArrowUp(keyData) || isShiftTab(keyData)) {
251
167
  this.selectedIndex = Math.max(0, this.selectedIndex - 1);
252
168
  this.updateList();
253
169
  }
254
- else if (isArrowDown(keyData)) {
170
+ else if (isArrowDown(keyData) || isTab(keyData)) {
255
171
  this.selectedIndex = Math.min(this.filteredRules.length - 1, this.selectedIndex + 1);
256
172
  this.updateList();
257
173
  }
@@ -0,0 +1,21 @@
1
+ import { type ModelMessage } from "ai";
2
+ import type { ConfigManager } from "../../config/index.ts";
3
+ import type { WorkspaceContext } from "../../index.ts";
4
+ import type { ModelManager } from "../../models/manager.ts";
5
+ import type { TokenTracker } from "../../tokens/tracker.ts";
6
+ export interface GenerateRulesOptions {
7
+ modelManager: ModelManager;
8
+ messages: ModelMessage[];
9
+ tokenTracker: TokenTracker;
10
+ config: ConfigManager;
11
+ workspace: WorkspaceContext;
12
+ }
13
+ export interface GenerateRulesResult {
14
+ rules: string[];
15
+ }
16
+ /**
17
+ * Analyzes conversation and generates rules without UI interaction.
18
+ * Returns the list of generated rules.
19
+ */
20
+ export declare function generateRulesFromSession(options: GenerateRulesOptions): Promise<GenerateRulesResult>;
21
+ //# sourceMappingURL=service.d.ts.map