atena-cli 0.1.0

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/LICENSE +21 -0
  2. package/README.md +210 -0
  3. package/dist/agent.d.ts +44 -0
  4. package/dist/agent.d.ts.map +1 -0
  5. package/dist/agent.js +731 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/agents.d.ts +33 -0
  8. package/dist/agents.d.ts.map +1 -0
  9. package/dist/agents.js +162 -0
  10. package/dist/agents.js.map +1 -0
  11. package/dist/autocomplete.d.ts +4 -0
  12. package/dist/autocomplete.d.ts.map +1 -0
  13. package/dist/autocomplete.js +96 -0
  14. package/dist/autocomplete.js.map +1 -0
  15. package/dist/cli/commands/connect.d.ts +3 -0
  16. package/dist/cli/commands/connect.d.ts.map +1 -0
  17. package/dist/cli/commands/connect.js +31 -0
  18. package/dist/cli/commands/connect.js.map +1 -0
  19. package/dist/cli/commands/deploy.d.ts +3 -0
  20. package/dist/cli/commands/deploy.d.ts.map +1 -0
  21. package/dist/cli/commands/deploy.js +26 -0
  22. package/dist/cli/commands/deploy.js.map +1 -0
  23. package/dist/cli/commands/login.d.ts +3 -0
  24. package/dist/cli/commands/login.d.ts.map +1 -0
  25. package/dist/cli/commands/login.js +46 -0
  26. package/dist/cli/commands/login.js.map +1 -0
  27. package/dist/cli/commands/vault.d.ts +3 -0
  28. package/dist/cli/commands/vault.d.ts.map +1 -0
  29. package/dist/cli/commands/vault.js +73 -0
  30. package/dist/cli/commands/vault.js.map +1 -0
  31. package/dist/cli/index.d.ts +3 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +309 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/cli/init/setup.d.ts +3 -0
  36. package/dist/cli/init/setup.d.ts.map +1 -0
  37. package/dist/cli/init/setup.js +74 -0
  38. package/dist/cli/init/setup.js.map +1 -0
  39. package/dist/cli/menus.d.ts +2 -0
  40. package/dist/cli/menus.d.ts.map +1 -0
  41. package/dist/cli/menus.js +111 -0
  42. package/dist/cli/menus.js.map +1 -0
  43. package/dist/cli/postinstall.d.ts +9 -0
  44. package/dist/cli/postinstall.d.ts.map +1 -0
  45. package/dist/cli/postinstall.js +81 -0
  46. package/dist/cli/postinstall.js.map +1 -0
  47. package/dist/cli/realtime-input.d.ts +4 -0
  48. package/dist/cli/realtime-input.d.ts.map +1 -0
  49. package/dist/cli/realtime-input.js +268 -0
  50. package/dist/cli/realtime-input.js.map +1 -0
  51. package/dist/cli/setup.d.ts +26 -0
  52. package/dist/cli/setup.d.ts.map +1 -0
  53. package/dist/cli/setup.js +202 -0
  54. package/dist/cli/setup.js.map +1 -0
  55. package/dist/cli/themes.d.ts +30 -0
  56. package/dist/cli/themes.d.ts.map +1 -0
  57. package/dist/cli/themes.js +225 -0
  58. package/dist/cli/themes.js.map +1 -0
  59. package/dist/cli/ui.d.ts +70 -0
  60. package/dist/cli/ui.d.ts.map +1 -0
  61. package/dist/cli/ui.js +455 -0
  62. package/dist/cli/ui.js.map +1 -0
  63. package/dist/commands.d.ts +16 -0
  64. package/dist/commands.d.ts.map +1 -0
  65. package/dist/commands.js +230 -0
  66. package/dist/commands.js.map +1 -0
  67. package/dist/config.d.ts +42 -0
  68. package/dist/config.d.ts.map +1 -0
  69. package/dist/config.js +140 -0
  70. package/dist/config.js.map +1 -0
  71. package/dist/context.d.ts +23 -0
  72. package/dist/context.d.ts.map +1 -0
  73. package/dist/context.js +80 -0
  74. package/dist/context.js.map +1 -0
  75. package/dist/core/agent.d.ts +94 -0
  76. package/dist/core/agent.d.ts.map +1 -0
  77. package/dist/core/agent.js +1280 -0
  78. package/dist/core/agent.js.map +1 -0
  79. package/dist/core/agents/enterprise/backend.d.ts +3 -0
  80. package/dist/core/agents/enterprise/backend.d.ts.map +1 -0
  81. package/dist/core/agents/enterprise/backend.js +35 -0
  82. package/dist/core/agents/enterprise/backend.js.map +1 -0
  83. package/dist/core/agents/enterprise/cloud.d.ts +3 -0
  84. package/dist/core/agents/enterprise/cloud.d.ts.map +1 -0
  85. package/dist/core/agents/enterprise/cloud.js +35 -0
  86. package/dist/core/agents/enterprise/cloud.js.map +1 -0
  87. package/dist/core/agents/enterprise/datascience.d.ts +3 -0
  88. package/dist/core/agents/enterprise/datascience.d.ts.map +1 -0
  89. package/dist/core/agents/enterprise/datascience.js +35 -0
  90. package/dist/core/agents/enterprise/datascience.js.map +1 -0
  91. package/dist/core/agents/enterprise/design.d.ts +3 -0
  92. package/dist/core/agents/enterprise/design.d.ts.map +1 -0
  93. package/dist/core/agents/enterprise/design.js +35 -0
  94. package/dist/core/agents/enterprise/design.js.map +1 -0
  95. package/dist/core/agents/enterprise/devops.d.ts +3 -0
  96. package/dist/core/agents/enterprise/devops.d.ts.map +1 -0
  97. package/dist/core/agents/enterprise/devops.js +35 -0
  98. package/dist/core/agents/enterprise/devops.js.map +1 -0
  99. package/dist/core/agents/enterprise/finance.d.ts +3 -0
  100. package/dist/core/agents/enterprise/finance.d.ts.map +1 -0
  101. package/dist/core/agents/enterprise/finance.js +35 -0
  102. package/dist/core/agents/enterprise/finance.js.map +1 -0
  103. package/dist/core/agents/enterprise/frontend.d.ts +3 -0
  104. package/dist/core/agents/enterprise/frontend.d.ts.map +1 -0
  105. package/dist/core/agents/enterprise/frontend.js +35 -0
  106. package/dist/core/agents/enterprise/frontend.js.map +1 -0
  107. package/dist/core/agents/enterprise/hr.d.ts +3 -0
  108. package/dist/core/agents/enterprise/hr.d.ts.map +1 -0
  109. package/dist/core/agents/enterprise/hr.js +35 -0
  110. package/dist/core/agents/enterprise/hr.js.map +1 -0
  111. package/dist/core/agents/enterprise/index.d.ts +4 -0
  112. package/dist/core/agents/enterprise/index.d.ts.map +1 -0
  113. package/dist/core/agents/enterprise/index.js +44 -0
  114. package/dist/core/agents/enterprise/index.js.map +1 -0
  115. package/dist/core/agents/enterprise/legal.d.ts +3 -0
  116. package/dist/core/agents/enterprise/legal.d.ts.map +1 -0
  117. package/dist/core/agents/enterprise/legal.js +35 -0
  118. package/dist/core/agents/enterprise/legal.js.map +1 -0
  119. package/dist/core/agents/enterprise/marketing.d.ts +3 -0
  120. package/dist/core/agents/enterprise/marketing.d.ts.map +1 -0
  121. package/dist/core/agents/enterprise/marketing.js +35 -0
  122. package/dist/core/agents/enterprise/marketing.js.map +1 -0
  123. package/dist/core/agents/enterprise/pm.d.ts +3 -0
  124. package/dist/core/agents/enterprise/pm.d.ts.map +1 -0
  125. package/dist/core/agents/enterprise/pm.js +35 -0
  126. package/dist/core/agents/enterprise/pm.js.map +1 -0
  127. package/dist/core/agents/enterprise/product.d.ts +3 -0
  128. package/dist/core/agents/enterprise/product.d.ts.map +1 -0
  129. package/dist/core/agents/enterprise/product.js +35 -0
  130. package/dist/core/agents/enterprise/product.js.map +1 -0
  131. package/dist/core/agents/enterprise/qa.d.ts +3 -0
  132. package/dist/core/agents/enterprise/qa.d.ts.map +1 -0
  133. package/dist/core/agents/enterprise/qa.js +35 -0
  134. package/dist/core/agents/enterprise/qa.js.map +1 -0
  135. package/dist/core/agents/enterprise/sales.d.ts +3 -0
  136. package/dist/core/agents/enterprise/sales.d.ts.map +1 -0
  137. package/dist/core/agents/enterprise/sales.js +35 -0
  138. package/dist/core/agents/enterprise/sales.js.map +1 -0
  139. package/dist/core/agents/enterprise/security.d.ts +3 -0
  140. package/dist/core/agents/enterprise/security.d.ts.map +1 -0
  141. package/dist/core/agents/enterprise/security.js +36 -0
  142. package/dist/core/agents/enterprise/security.js.map +1 -0
  143. package/dist/core/agents/enterprise/support.d.ts +3 -0
  144. package/dist/core/agents/enterprise/support.d.ts.map +1 -0
  145. package/dist/core/agents/enterprise/support.js +35 -0
  146. package/dist/core/agents/enterprise/support.js.map +1 -0
  147. package/dist/core/agents.d.ts +84 -0
  148. package/dist/core/agents.d.ts.map +1 -0
  149. package/dist/core/agents.js +266 -0
  150. package/dist/core/agents.js.map +1 -0
  151. package/dist/core/analytics.d.ts +21 -0
  152. package/dist/core/analytics.d.ts.map +1 -0
  153. package/dist/core/analytics.js +57 -0
  154. package/dist/core/analytics.js.map +1 -0
  155. package/dist/core/auth.d.ts +43 -0
  156. package/dist/core/auth.d.ts.map +1 -0
  157. package/dist/core/auth.js +110 -0
  158. package/dist/core/auth.js.map +1 -0
  159. package/dist/core/code_indexer.d.ts +14 -0
  160. package/dist/core/code_indexer.d.ts.map +1 -0
  161. package/dist/core/code_indexer.js +52 -0
  162. package/dist/core/code_indexer.js.map +1 -0
  163. package/dist/core/commands.d.ts +16 -0
  164. package/dist/core/commands.d.ts.map +1 -0
  165. package/dist/core/commands.js +285 -0
  166. package/dist/core/commands.js.map +1 -0
  167. package/dist/core/consensus.d.ts +25 -0
  168. package/dist/core/consensus.d.ts.map +1 -0
  169. package/dist/core/consensus.js +49 -0
  170. package/dist/core/consensus.js.map +1 -0
  171. package/dist/core/context.d.ts +23 -0
  172. package/dist/core/context.d.ts.map +1 -0
  173. package/dist/core/context.js +82 -0
  174. package/dist/core/context.js.map +1 -0
  175. package/dist/core/eden-ai-sdk.d.ts +11 -0
  176. package/dist/core/eden-ai-sdk.d.ts.map +1 -0
  177. package/dist/core/eden-ai-sdk.js +158 -0
  178. package/dist/core/eden-ai-sdk.js.map +1 -0
  179. package/dist/core/events.d.ts +64 -0
  180. package/dist/core/events.d.ts.map +1 -0
  181. package/dist/core/events.js +18 -0
  182. package/dist/core/events.js.map +1 -0
  183. package/dist/core/groq-client.d.ts +7 -0
  184. package/dist/core/groq-client.d.ts.map +1 -0
  185. package/dist/core/groq-client.js +112 -0
  186. package/dist/core/groq-client.js.map +1 -0
  187. package/dist/core/mcp.d.ts +51 -0
  188. package/dist/core/mcp.d.ts.map +1 -0
  189. package/dist/core/mcp.js +201 -0
  190. package/dist/core/mcp.js.map +1 -0
  191. package/dist/core/memory.d.ts +20 -0
  192. package/dist/core/memory.d.ts.map +1 -0
  193. package/dist/core/memory.js +61 -0
  194. package/dist/core/memory.js.map +1 -0
  195. package/dist/core/model-profiles.d.ts +62 -0
  196. package/dist/core/model-profiles.d.ts.map +1 -0
  197. package/dist/core/model-profiles.js +841 -0
  198. package/dist/core/model-profiles.js.map +1 -0
  199. package/dist/core/moonshot-client.d.ts +7 -0
  200. package/dist/core/moonshot-client.d.ts.map +1 -0
  201. package/dist/core/moonshot-client.js +102 -0
  202. package/dist/core/moonshot-client.js.map +1 -0
  203. package/dist/core/nexus.d.ts +16 -0
  204. package/dist/core/nexus.d.ts.map +1 -0
  205. package/dist/core/nexus.js +31 -0
  206. package/dist/core/nexus.js.map +1 -0
  207. package/dist/core/notifications.d.ts +16 -0
  208. package/dist/core/notifications.d.ts.map +1 -0
  209. package/dist/core/notifications.js +26 -0
  210. package/dist/core/notifications.js.map +1 -0
  211. package/dist/core/ollama-client.d.ts +16 -0
  212. package/dist/core/ollama-client.d.ts.map +1 -0
  213. package/dist/core/ollama-client.js +138 -0
  214. package/dist/core/ollama-client.js.map +1 -0
  215. package/dist/core/orchestrator.d.ts +96 -0
  216. package/dist/core/orchestrator.d.ts.map +1 -0
  217. package/dist/core/orchestrator.js +801 -0
  218. package/dist/core/orchestrator.js.map +1 -0
  219. package/dist/core/permissions.d.ts +34 -0
  220. package/dist/core/permissions.d.ts.map +1 -0
  221. package/dist/core/permissions.js +224 -0
  222. package/dist/core/permissions.js.map +1 -0
  223. package/dist/core/providers.d.ts +22 -0
  224. package/dist/core/providers.d.ts.map +1 -0
  225. package/dist/core/providers.js +81 -0
  226. package/dist/core/providers.js.map +1 -0
  227. package/dist/core/researcher.d.ts +24 -0
  228. package/dist/core/researcher.d.ts.map +1 -0
  229. package/dist/core/researcher.js +97 -0
  230. package/dist/core/researcher.js.map +1 -0
  231. package/dist/core/sandbox.d.ts +22 -0
  232. package/dist/core/sandbox.d.ts.map +1 -0
  233. package/dist/core/sandbox.js +79 -0
  234. package/dist/core/sandbox.js.map +1 -0
  235. package/dist/core/scavenger.d.ts +5 -0
  236. package/dist/core/scavenger.d.ts.map +1 -0
  237. package/dist/core/scavenger.js +51 -0
  238. package/dist/core/scavenger.js.map +1 -0
  239. package/dist/core/server.d.ts +21 -0
  240. package/dist/core/server.d.ts.map +1 -0
  241. package/dist/core/server.js +776 -0
  242. package/dist/core/server.js.map +1 -0
  243. package/dist/core/sessions.d.ts +54 -0
  244. package/dist/core/sessions.d.ts.map +1 -0
  245. package/dist/core/sessions.js +182 -0
  246. package/dist/core/sessions.js.map +1 -0
  247. package/dist/core/setup.d.ts +12 -0
  248. package/dist/core/setup.d.ts.map +1 -0
  249. package/dist/core/setup.js +70 -0
  250. package/dist/core/setup.js.map +1 -0
  251. package/dist/core/skills.d.ts +17 -0
  252. package/dist/core/skills.d.ts.map +1 -0
  253. package/dist/core/skills.js +123 -0
  254. package/dist/core/skills.js.map +1 -0
  255. package/dist/core/stats.d.ts +54 -0
  256. package/dist/core/stats.d.ts.map +1 -0
  257. package/dist/core/stats.js +221 -0
  258. package/dist/core/stats.js.map +1 -0
  259. package/dist/core/swarm_manager.d.ts +20 -0
  260. package/dist/core/swarm_manager.d.ts.map +1 -0
  261. package/dist/core/swarm_manager.js +48 -0
  262. package/dist/core/swarm_manager.js.map +1 -0
  263. package/dist/core/system.d.ts +39 -0
  264. package/dist/core/system.d.ts.map +1 -0
  265. package/dist/core/system.js +129 -0
  266. package/dist/core/system.js.map +1 -0
  267. package/dist/core/tasks.d.ts +24 -0
  268. package/dist/core/tasks.d.ts.map +1 -0
  269. package/dist/core/tasks.js +66 -0
  270. package/dist/core/tasks.js.map +1 -0
  271. package/dist/core/telegram.d.ts +9 -0
  272. package/dist/core/telegram.d.ts.map +1 -0
  273. package/dist/core/telegram.js +49 -0
  274. package/dist/core/telegram.js.map +1 -0
  275. package/dist/core/tools/acquire_skill.d.ts +3 -0
  276. package/dist/core/tools/acquire_skill.d.ts.map +1 -0
  277. package/dist/core/tools/acquire_skill.js +30 -0
  278. package/dist/core/tools/acquire_skill.js.map +1 -0
  279. package/dist/core/tools/agent_tools.d.ts +4 -0
  280. package/dist/core/tools/agent_tools.d.ts.map +1 -0
  281. package/dist/core/tools/agent_tools.js +117 -0
  282. package/dist/core/tools/agent_tools.js.map +1 -0
  283. package/dist/core/tools/code_search.d.ts +3 -0
  284. package/dist/core/tools/code_search.d.ts.map +1 -0
  285. package/dist/core/tools/code_search.js +43 -0
  286. package/dist/core/tools/code_search.js.map +1 -0
  287. package/dist/core/tools/craft_tool.d.ts +3 -0
  288. package/dist/core/tools/craft_tool.d.ts.map +1 -0
  289. package/dist/core/tools/craft_tool.js +32 -0
  290. package/dist/core/tools/craft_tool.js.map +1 -0
  291. package/dist/core/tools/discord.d.ts +3 -0
  292. package/dist/core/tools/discord.d.ts.map +1 -0
  293. package/dist/core/tools/discord.js +206 -0
  294. package/dist/core/tools/discord.js.map +1 -0
  295. package/dist/core/tools/dynamic/registry.d.ts +15 -0
  296. package/dist/core/tools/dynamic/registry.d.ts.map +1 -0
  297. package/dist/core/tools/dynamic/registry.js +59 -0
  298. package/dist/core/tools/dynamic/registry.js.map +1 -0
  299. package/dist/core/tools/github.d.ts +3 -0
  300. package/dist/core/tools/github.d.ts.map +1 -0
  301. package/dist/core/tools/github.js +357 -0
  302. package/dist/core/tools/github.js.map +1 -0
  303. package/dist/core/tools/google.d.ts +3 -0
  304. package/dist/core/tools/google.d.ts.map +1 -0
  305. package/dist/core/tools/google.js +409 -0
  306. package/dist/core/tools/google.js.map +1 -0
  307. package/dist/core/tools/index.d.ts +4 -0
  308. package/dist/core/tools/index.d.ts.map +1 -0
  309. package/dist/core/tools/index.js +2338 -0
  310. package/dist/core/tools/index.js.map +1 -0
  311. package/dist/core/tools/optimize_prompt.d.ts +3 -0
  312. package/dist/core/tools/optimize_prompt.d.ts.map +1 -0
  313. package/dist/core/tools/optimize_prompt.js +43 -0
  314. package/dist/core/tools/optimize_prompt.js.map +1 -0
  315. package/dist/core/tools/predict_healing.d.ts +3 -0
  316. package/dist/core/tools/predict_healing.d.ts.map +1 -0
  317. package/dist/core/tools/predict_healing.js +34 -0
  318. package/dist/core/tools/predict_healing.js.map +1 -0
  319. package/dist/core/tools/sage_memory.d.ts +3 -0
  320. package/dist/core/tools/sage_memory.d.ts.map +1 -0
  321. package/dist/core/tools/sage_memory.js +29 -0
  322. package/dist/core/tools/sage_memory.js.map +1 -0
  323. package/dist/core/tools/self_heal.d.ts +3 -0
  324. package/dist/core/tools/self_heal.d.ts.map +1 -0
  325. package/dist/core/tools/self_heal.js +46 -0
  326. package/dist/core/tools/self_heal.js.map +1 -0
  327. package/dist/core/tools/send_briefing.d.ts +3 -0
  328. package/dist/core/tools/send_briefing.d.ts.map +1 -0
  329. package/dist/core/tools/send_briefing.js +31 -0
  330. package/dist/core/tools/send_briefing.js.map +1 -0
  331. package/dist/core/tools/slack.d.ts +3 -0
  332. package/dist/core/tools/slack.d.ts.map +1 -0
  333. package/dist/core/tools/slack.js +256 -0
  334. package/dist/core/tools/slack.js.map +1 -0
  335. package/dist/core/tools/telegram.d.ts +3 -0
  336. package/dist/core/tools/telegram.d.ts.map +1 -0
  337. package/dist/core/tools/telegram.js +211 -0
  338. package/dist/core/tools/telegram.js.map +1 -0
  339. package/dist/core/tools/vox.d.ts +3 -0
  340. package/dist/core/tools/vox.d.ts.map +1 -0
  341. package/dist/core/tools/vox.js +29 -0
  342. package/dist/core/tools/vox.js.map +1 -0
  343. package/dist/core/types/index.d.ts +164 -0
  344. package/dist/core/types/index.d.ts.map +1 -0
  345. package/dist/core/types/index.js +3 -0
  346. package/dist/core/types/index.js.map +1 -0
  347. package/dist/core/vault.d.ts +20 -0
  348. package/dist/core/vault.d.ts.map +1 -0
  349. package/dist/core/vault.js +91 -0
  350. package/dist/core/vault.js.map +1 -0
  351. package/dist/core/verify_v3.d.ts +2 -0
  352. package/dist/core/verify_v3.d.ts.map +1 -0
  353. package/dist/core/verify_v3.js +38 -0
  354. package/dist/core/verify_v3.js.map +1 -0
  355. package/dist/core/verify_v3_5.d.ts +2 -0
  356. package/dist/core/verify_v3_5.d.ts.map +1 -0
  357. package/dist/core/verify_v3_5.js +56 -0
  358. package/dist/core/verify_v3_5.js.map +1 -0
  359. package/dist/core/verify_v4.d.ts +2 -0
  360. package/dist/core/verify_v4.d.ts.map +1 -0
  361. package/dist/core/verify_v4.js +42 -0
  362. package/dist/core/verify_v4.js.map +1 -0
  363. package/dist/core/verify_v5.d.ts +2 -0
  364. package/dist/core/verify_v5.d.ts.map +1 -0
  365. package/dist/core/verify_v5.js +53 -0
  366. package/dist/core/verify_v5.js.map +1 -0
  367. package/dist/core/verify_v6.d.ts +2 -0
  368. package/dist/core/verify_v6.d.ts.map +1 -0
  369. package/dist/core/verify_v6.js +42 -0
  370. package/dist/core/verify_v6.js.map +1 -0
  371. package/dist/core/verify_v7.d.ts +2 -0
  372. package/dist/core/verify_v7.d.ts.map +1 -0
  373. package/dist/core/verify_v7.js +29 -0
  374. package/dist/core/verify_v7.js.map +1 -0
  375. package/dist/core/verify_v8.d.ts +2 -0
  376. package/dist/core/verify_v8.d.ts.map +1 -0
  377. package/dist/core/verify_v8.js +32 -0
  378. package/dist/core/verify_v8.js.map +1 -0
  379. package/dist/core/workflows.d.ts +24 -0
  380. package/dist/core/workflows.d.ts.map +1 -0
  381. package/dist/core/workflows.js +47 -0
  382. package/dist/core/workflows.js.map +1 -0
  383. package/dist/core/workspaces.d.ts +13 -0
  384. package/dist/core/workspaces.d.ts.map +1 -0
  385. package/dist/core/workspaces.js +45 -0
  386. package/dist/core/workspaces.js.map +1 -0
  387. package/dist/enquirer-input.d.ts +3 -0
  388. package/dist/enquirer-input.d.ts.map +1 -0
  389. package/dist/enquirer-input.js +112 -0
  390. package/dist/enquirer-input.js.map +1 -0
  391. package/dist/index.d.ts +3 -0
  392. package/dist/index.d.ts.map +1 -0
  393. package/dist/index.js +241 -0
  394. package/dist/index.js.map +1 -0
  395. package/dist/mcp.d.ts +51 -0
  396. package/dist/mcp.d.ts.map +1 -0
  397. package/dist/mcp.js +201 -0
  398. package/dist/mcp.js.map +1 -0
  399. package/dist/ollama-client.d.ts +15 -0
  400. package/dist/ollama-client.d.ts.map +1 -0
  401. package/dist/ollama-client.js +95 -0
  402. package/dist/ollama-client.js.map +1 -0
  403. package/dist/permissions.d.ts +34 -0
  404. package/dist/permissions.d.ts.map +1 -0
  405. package/dist/permissions.js +224 -0
  406. package/dist/permissions.js.map +1 -0
  407. package/dist/realtime-input.d.ts +2 -0
  408. package/dist/realtime-input.d.ts.map +1 -0
  409. package/dist/realtime-input.js +308 -0
  410. package/dist/realtime-input.js.map +1 -0
  411. package/dist/server.d.ts +20 -0
  412. package/dist/server.d.ts.map +1 -0
  413. package/dist/server.js +203 -0
  414. package/dist/server.js.map +1 -0
  415. package/dist/sessions.d.ts +50 -0
  416. package/dist/sessions.d.ts.map +1 -0
  417. package/dist/sessions.js +181 -0
  418. package/dist/sessions.js.map +1 -0
  419. package/dist/simple-input.d.ts +2 -0
  420. package/dist/simple-input.d.ts.map +1 -0
  421. package/dist/simple-input.js +83 -0
  422. package/dist/simple-input.js.map +1 -0
  423. package/dist/skills.d.ts +17 -0
  424. package/dist/skills.d.ts.map +1 -0
  425. package/dist/skills.js +194 -0
  426. package/dist/skills.js.map +1 -0
  427. package/dist/stats.d.ts +54 -0
  428. package/dist/stats.d.ts.map +1 -0
  429. package/dist/stats.js +220 -0
  430. package/dist/stats.js.map +1 -0
  431. package/dist/tools/discord.d.ts +3 -0
  432. package/dist/tools/discord.d.ts.map +1 -0
  433. package/dist/tools/discord.js +206 -0
  434. package/dist/tools/discord.js.map +1 -0
  435. package/dist/tools/github.d.ts +3 -0
  436. package/dist/tools/github.d.ts.map +1 -0
  437. package/dist/tools/github.js +357 -0
  438. package/dist/tools/github.js.map +1 -0
  439. package/dist/tools/google.d.ts +3 -0
  440. package/dist/tools/google.d.ts.map +1 -0
  441. package/dist/tools/google.js +409 -0
  442. package/dist/tools/google.js.map +1 -0
  443. package/dist/tools/index.d.ts +4 -0
  444. package/dist/tools/index.d.ts.map +1 -0
  445. package/dist/tools/index.js +2139 -0
  446. package/dist/tools/index.js.map +1 -0
  447. package/dist/tools/slack.d.ts +3 -0
  448. package/dist/tools/slack.d.ts.map +1 -0
  449. package/dist/tools/slack.js +256 -0
  450. package/dist/tools/slack.js.map +1 -0
  451. package/dist/tools/telegram.d.ts +3 -0
  452. package/dist/tools/telegram.d.ts.map +1 -0
  453. package/dist/tools/telegram.js +211 -0
  454. package/dist/tools/telegram.js.map +1 -0
  455. package/dist/types/index.d.ts +152 -0
  456. package/dist/types/index.d.ts.map +1 -0
  457. package/dist/types/index.js +3 -0
  458. package/dist/types/index.js.map +1 -0
  459. package/dist/ui.d.ts +101 -0
  460. package/dist/ui.d.ts.map +1 -0
  461. package/dist/ui.js +317 -0
  462. package/dist/ui.js.map +1 -0
  463. package/dist/web/src/lib/utils.d.ts +3 -0
  464. package/dist/web/src/lib/utils.d.ts.map +1 -0
  465. package/dist/web/src/lib/utils.js +6 -0
  466. package/dist/web/src/lib/utils.js.map +1 -0
  467. package/dist/web/src/main.d.ts +2 -0
  468. package/dist/web/src/main.d.ts.map +1 -0
  469. package/dist/web/src/main.js +5 -0
  470. package/dist/web/src/main.js.map +1 -0
  471. package/dist/web/vite.config.d.ts +3 -0
  472. package/dist/web/vite.config.d.ts.map +1 -0
  473. package/dist/web/vite.config.js +12 -0
  474. package/dist/web/vite.config.js.map +1 -0
  475. package/package.json +83 -0
@@ -0,0 +1,2139 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { spawn } from 'node:child_process';
3
+ import path from 'node:path';
4
+ import { execSync } from 'node:child_process';
5
+ import { slackTools } from './slack.js';
6
+ import { googleTools } from './google.js';
7
+ import { githubTools } from './github.js';
8
+ import { discordTools } from './discord.js';
9
+ import { telegramTools } from './telegram.js';
10
+ import { colors } from '../ui.js';
11
+ // File operations tool
12
+ const readFileTool = {
13
+ definition: {
14
+ name: 'read_file',
15
+ description: 'Read the contents of a file at the specified path. Returns the file content as text.',
16
+ parameters: {
17
+ type: 'object',
18
+ properties: {
19
+ file_path: {
20
+ type: 'string',
21
+ description: 'The absolute path to the file to read',
22
+ },
23
+ offset: {
24
+ type: 'number',
25
+ description: 'Optional line offset to start reading from (1-indexed)',
26
+ },
27
+ limit: {
28
+ type: 'number',
29
+ description: 'Optional maximum number of lines to read',
30
+ },
31
+ },
32
+ required: ['file_path'],
33
+ },
34
+ },
35
+ handler: async (args) => {
36
+ try {
37
+ const filePath = String(args.file_path);
38
+ const offset = args.offset ? Number(args.offset) : undefined;
39
+ const limit = args.limit ? Number(args.limit) : undefined;
40
+ let content = await fs.readFile(filePath, 'utf8');
41
+ if (offset !== undefined || limit !== undefined) {
42
+ const lines = content.split('\n');
43
+ const start = offset ? Math.max(0, offset - 1) : 0;
44
+ const end = limit ? Math.min(lines.length, start + limit) : lines.length;
45
+ content = lines.slice(start, end).join('\n');
46
+ }
47
+ return {
48
+ status: 'success',
49
+ output: content,
50
+ metadata: { file_path: filePath },
51
+ };
52
+ }
53
+ catch (err) {
54
+ return {
55
+ status: 'error',
56
+ error: err instanceof Error ? err.message : String(err),
57
+ };
58
+ }
59
+ },
60
+ };
61
+ // Write file tool
62
+ const writeFileTool = {
63
+ definition: {
64
+ name: 'write_file',
65
+ description: 'Write content to a file at the specified path. Creates the file if it does not exist.',
66
+ parameters: {
67
+ type: 'object',
68
+ properties: {
69
+ file_path: {
70
+ type: 'string',
71
+ description: 'The absolute path to the file to write',
72
+ },
73
+ content: {
74
+ type: 'string',
75
+ description: 'The content to write to the file',
76
+ },
77
+ },
78
+ required: ['file_path', 'content'],
79
+ },
80
+ },
81
+ handler: async (args) => {
82
+ try {
83
+ let filePath = String(args.file_path);
84
+ const content = String(args.content);
85
+ // Fix paths that reference non-existent home directories
86
+ if (filePath.startsWith('/home/user') || filePath.startsWith('/root')) {
87
+ const relativePath = filePath.replace(/^\/home\/user\//, '').replace(/^\/root\//, '');
88
+ filePath = path.join(process.cwd(), relativePath);
89
+ }
90
+ // Ensure directory exists
91
+ const dir = path.dirname(filePath);
92
+ try {
93
+ await fs.mkdir(dir, { recursive: true });
94
+ }
95
+ catch (mkdirErr) {
96
+ // If we can't create the directory, fallback to current directory
97
+ if (mkdirErr.code === 'EACCES' || mkdirErr.code === 'EPERM') {
98
+ const basename = path.basename(filePath);
99
+ filePath = path.join(process.cwd(), basename);
100
+ }
101
+ }
102
+ await fs.writeFile(filePath, content, 'utf8');
103
+ return {
104
+ status: 'success',
105
+ output: `File written successfully: ${filePath}`,
106
+ metadata: { file_path: filePath, bytes: content.length },
107
+ };
108
+ }
109
+ catch (err) {
110
+ return {
111
+ status: 'error',
112
+ error: err instanceof Error ? err.message : String(err),
113
+ };
114
+ }
115
+ },
116
+ };
117
+ // Edit file tool (search and replace)
118
+ const editFileTool = {
119
+ definition: {
120
+ name: 'edit_file',
121
+ description: 'Edit a file by replacing occurrences of old_string with new_string.',
122
+ parameters: {
123
+ type: 'object',
124
+ properties: {
125
+ file_path: {
126
+ type: 'string',
127
+ description: 'The absolute path to the file to edit',
128
+ },
129
+ old_string: {
130
+ type: 'string',
131
+ description: 'The text to search for and replace',
132
+ },
133
+ new_string: {
134
+ type: 'string',
135
+ description: 'The replacement text',
136
+ },
137
+ replace_all: {
138
+ type: 'boolean',
139
+ description: 'If true, replace all occurrences instead of just the first one',
140
+ },
141
+ },
142
+ required: ['file_path', 'old_string', 'new_string'],
143
+ },
144
+ },
145
+ handler: async (args) => {
146
+ try {
147
+ const filePath = String(args.file_path);
148
+ const oldString = String(args.old_string);
149
+ const newString = String(args.new_string);
150
+ const replaceAll = Boolean(args.replace_all);
151
+ const content = await fs.readFile(filePath, 'utf8');
152
+ if (!content.includes(oldString)) {
153
+ return {
154
+ status: 'error',
155
+ error: `Could not find the string to replace in ${filePath}`,
156
+ };
157
+ }
158
+ const newContent = replaceAll
159
+ ? content.split(oldString).join(newString)
160
+ : content.replace(oldString, newString);
161
+ await fs.writeFile(filePath, newContent, 'utf8');
162
+ return {
163
+ status: 'success',
164
+ output: `File edited successfully: ${filePath}`,
165
+ metadata: { file_path: filePath, replacements: replaceAll ? 'all' : 'first' },
166
+ };
167
+ }
168
+ catch (err) {
169
+ return {
170
+ status: 'error',
171
+ error: err instanceof Error ? err.message : String(err),
172
+ };
173
+ }
174
+ },
175
+ };
176
+ // List directory tool
177
+ const listDirTool = {
178
+ definition: {
179
+ name: 'list_dir',
180
+ description: 'List files and directories at the specified path. Returns file names, sizes, and modification times.',
181
+ parameters: {
182
+ type: 'object',
183
+ properties: {
184
+ directory_path: {
185
+ type: 'string',
186
+ description: 'The absolute path to the directory to list',
187
+ },
188
+ recursive: {
189
+ type: 'boolean',
190
+ description: 'If true, list recursively',
191
+ },
192
+ },
193
+ required: ['directory_path'],
194
+ },
195
+ },
196
+ handler: async (args) => {
197
+ try {
198
+ const dirPath = String(args.directory_path);
199
+ const recursive = Boolean(args.recursive);
200
+ const entries = [];
201
+ if (recursive) {
202
+ const walk = async (currentPath, prefix) => {
203
+ const items = await fs.readdir(currentPath, { withFileTypes: true });
204
+ for (const item of items) {
205
+ const fullPath = path.join(currentPath, item.name);
206
+ const stat = await fs.stat(fullPath);
207
+ const size = stat.isFile() ? ` (${stat.size} bytes)` : ' (dir)';
208
+ entries.push(`${prefix}${item.name}${size}`);
209
+ if (item.isDirectory()) {
210
+ await walk(fullPath, prefix + ' ');
211
+ }
212
+ }
213
+ };
214
+ await walk(dirPath, '');
215
+ }
216
+ else {
217
+ const items = await fs.readdir(dirPath, { withFileTypes: true });
218
+ for (const item of items) {
219
+ const fullPath = path.join(dirPath, item.name);
220
+ const stat = await fs.stat(fullPath);
221
+ const size = stat.isFile() ? ` (${stat.size} bytes)` : ' (dir)';
222
+ entries.push(`${item.name}${size}`);
223
+ }
224
+ }
225
+ return {
226
+ status: 'success',
227
+ output: entries.join('\n'),
228
+ metadata: { directory: dirPath, count: entries.length },
229
+ };
230
+ }
231
+ catch (err) {
232
+ return {
233
+ status: 'error',
234
+ error: err instanceof Error ? err.message : String(err),
235
+ };
236
+ }
237
+ },
238
+ };
239
+ // Grep search tool
240
+ const grepSearchTool = {
241
+ definition: {
242
+ name: 'grep_search',
243
+ description: 'Search for text patterns in files using ripgrep-style matching.',
244
+ parameters: {
245
+ type: 'object',
246
+ properties: {
247
+ query: {
248
+ type: 'string',
249
+ description: 'The search pattern or text to find',
250
+ },
251
+ path: {
252
+ type: 'string',
253
+ description: 'The directory or file path to search in',
254
+ },
255
+ file_pattern: {
256
+ type: 'string',
257
+ description: 'Optional glob pattern to filter files (e.g., "*.ts", "*.js")',
258
+ },
259
+ case_sensitive: {
260
+ type: 'boolean',
261
+ description: 'If false, perform case-insensitive search',
262
+ },
263
+ fixed_strings: {
264
+ type: 'boolean',
265
+ description: 'If true, treat query as literal string instead of regex',
266
+ },
267
+ },
268
+ required: ['query', 'path'],
269
+ },
270
+ },
271
+ handler: async (args) => {
272
+ try {
273
+ const query = String(args.query);
274
+ const searchPath = String(args.path);
275
+ const filePattern = args.file_pattern ? String(args.file_pattern) : undefined;
276
+ const caseSensitive = args.case_sensitive !== false;
277
+ const fixedStrings = Boolean(args.fixed_strings);
278
+ // Build grep/ripgrep command
279
+ const args_list = [];
280
+ if (!caseSensitive)
281
+ args_list.push('-i');
282
+ if (fixedStrings)
283
+ args_list.push('-F');
284
+ if (filePattern) {
285
+ args_list.push('--include', filePattern);
286
+ }
287
+ args_list.push(query, searchPath);
288
+ const result = execSync(`rg ${args_list.join(' ')} 2>/dev/null || grep -r ${args_list.join(' ')} 2>/dev/null || echo "No matches found"`, {
289
+ encoding: 'utf8',
290
+ maxBuffer: 1024 * 1024,
291
+ });
292
+ const lines = result.trim().split('\n').filter(Boolean);
293
+ const truncated = lines.length > 50;
294
+ const output = truncated ? lines.slice(0, 50).join('\n') + '\n... (truncated)' : result;
295
+ return {
296
+ status: 'success',
297
+ output,
298
+ metadata: {
299
+ matches: lines.length,
300
+ truncated,
301
+ },
302
+ };
303
+ }
304
+ catch (err) {
305
+ return {
306
+ status: 'error',
307
+ error: err instanceof Error ? err.message : String(err),
308
+ };
309
+ }
310
+ },
311
+ };
312
+ // Run command tool - improved with better output handling and suggestions
313
+ const runCommandTool = {
314
+ definition: {
315
+ name: 'run_command',
316
+ description: 'Execute a shell command. Returns stdout and stderr output. Shows suggestions if command fails or has no output.',
317
+ parameters: {
318
+ type: 'object',
319
+ properties: {
320
+ command: {
321
+ type: 'string',
322
+ description: 'The command to execute',
323
+ },
324
+ cwd: {
325
+ type: 'string',
326
+ description: 'Optional working directory for the command',
327
+ },
328
+ timeout_sec: {
329
+ type: 'number',
330
+ description: 'Optional timeout in seconds (default: 60)',
331
+ },
332
+ },
333
+ required: ['command'],
334
+ },
335
+ },
336
+ handler: async (args) => {
337
+ try {
338
+ const command = String(args.command);
339
+ const cwd = args.cwd ? String(args.cwd) : process.cwd();
340
+ const timeoutSec = args.timeout_sec ? Number(args.timeout_sec) : 60;
341
+ return new Promise((resolve) => {
342
+ // Stop spinner so we don't clobber live output
343
+ console.log(); // Add a newline before output
344
+ const child = spawn('bash', ['-c', command], {
345
+ cwd,
346
+ stdio: ['inherit', 'pipe', 'pipe'],
347
+ });
348
+ let stdout = '';
349
+ let stderr = '';
350
+ let timeout = null;
351
+ if (timeoutSec > 0) {
352
+ timeout = setTimeout(() => {
353
+ child.kill('SIGTERM');
354
+ setTimeout(() => {
355
+ if (!child.killed)
356
+ child.kill('SIGKILL');
357
+ }, 5000);
358
+ }, timeoutSec * 1000);
359
+ }
360
+ child.stdout?.on('data', (data) => {
361
+ process.stdout.write(colors.muted(String(data)));
362
+ stdout += String(data);
363
+ });
364
+ child.stderr?.on('data', (data) => {
365
+ process.stderr.write(colors.error(String(data)));
366
+ stderr += String(data);
367
+ });
368
+ child.on('close', (code) => {
369
+ if (timeout)
370
+ clearTimeout(timeout);
371
+ console.log(); // End visual block of command stream
372
+ const isError = code !== 0;
373
+ const hasStdout = stdout.trim().length > 0;
374
+ const hasStderr = stderr.trim().length > 0;
375
+ // Build comprehensive output
376
+ let output = '';
377
+ let suggestions = [];
378
+ if (hasStdout) {
379
+ output += stdout;
380
+ }
381
+ if (hasStderr) {
382
+ if (output)
383
+ output += '\n\n';
384
+ output += `STDERR:\n${stderr}`;
385
+ }
386
+ // Handle silent success cases (mkdir, touch, etc.)
387
+ if (!isError && !hasStdout && !hasStderr) {
388
+ // Check what command was run and provide context
389
+ const cmdBase = command.trim().split(' ')[0];
390
+ const silentCommands = ['mkdir', 'touch', 'rm', 'cp', 'mv', 'chmod', 'chown'];
391
+ if (silentCommands.includes(cmdBase)) {
392
+ output = `✓ Comando ejecutado exitosamente (sin output)`;
393
+ // Show what was created/modified
394
+ if (cmdBase === 'mkdir') {
395
+ const match = command.match(/mkdir\s+-?p?\s+(.*)/);
396
+ if (match) {
397
+ output += `\nDirectorios creados: ${match[1]}`;
398
+ }
399
+ }
400
+ }
401
+ else {
402
+ output = '(comando completado sin output)';
403
+ }
404
+ }
405
+ // Generate suggestions for common errors
406
+ if (isError) {
407
+ const errorText = stderr.toLowerCase();
408
+ if (errorText.includes('command not found') || errorText.includes('no such file')) {
409
+ suggestions.push('Verifica que el comando esté instalado: `which <comando>`');
410
+ suggestions.push('Alternativa: Instala con tu package manager (apt, npm, etc.)');
411
+ }
412
+ if (errorText.includes('permission denied') || errorText.includes('eacces')) {
413
+ suggestions.push('Intenta con sudo o verifica permisos: `ls -la`');
414
+ suggestions.push('Alternativa: Cambia permisos con `chmod` o cambia de directorio');
415
+ }
416
+ if (errorText.includes('file exists') || errorText.includes('eexist')) {
417
+ suggestions.push('El archivo/directorio ya existe');
418
+ suggestions.push('Alternativa: Usa `-f` (force) o elimina primero con `rm`');
419
+ }
420
+ if (errorText.includes('no such file or directory')) {
421
+ suggestions.push('Verifica que la ruta existe con `ls -la`');
422
+ suggestions.push('Alternativa: Crea directorios padre primero con `mkdir -p`');
423
+ }
424
+ if (errorText.includes('connection refused') || errorText.includes('timeout')) {
425
+ suggestions.push('Verifica conectividad de red');
426
+ suggestions.push('Alternativa: Revisa firewall o intenta más tarde');
427
+ }
428
+ if (suggestions.length === 0) {
429
+ suggestions.push('Verifica el comando con `--help` o man pages');
430
+ suggestions.push('Alternativa: Busca ejemplos en documentación oficial');
431
+ }
432
+ }
433
+ // Build final response
434
+ let finalOutput = output;
435
+ if (suggestions.length > 0) {
436
+ finalOutput += '\n\n💡 Sugerencias:\n' + suggestions.map(s => ` • ${s}`).join('\n');
437
+ }
438
+ resolve({
439
+ status: isError ? 'error' : 'success',
440
+ output: finalOutput || '(no output)',
441
+ error: isError ? `Exit code: ${code}` : undefined,
442
+ metadata: {
443
+ exit_code: code,
444
+ stdout_length: stdout.length,
445
+ stderr_length: stderr.length,
446
+ command: command.slice(0, 100), // Truncate for safety
447
+ suggestions_count: suggestions.length,
448
+ },
449
+ });
450
+ });
451
+ child.on('error', (err) => {
452
+ if (timeout)
453
+ clearTimeout(timeout);
454
+ resolve({
455
+ status: 'error',
456
+ output: '',
457
+ error: `Failed to execute: ${err.message}\n\n💡 Sugerencias:\n • Verifica que el shell esté disponible\n • Alternativa: Intenta con el comando completo (ej: /bin/ls)`,
458
+ });
459
+ });
460
+ });
461
+ }
462
+ catch (err) {
463
+ return {
464
+ status: 'error',
465
+ output: '',
466
+ error: err instanceof Error ? err.message : String(err),
467
+ };
468
+ }
469
+ },
470
+ };
471
+ // Find files by name tool
472
+ const findByNameTool = {
473
+ definition: {
474
+ name: 'find_by_name',
475
+ description: 'Find files and directories by name pattern.',
476
+ parameters: {
477
+ type: 'object',
478
+ properties: {
479
+ pattern: {
480
+ type: 'string',
481
+ description: 'The glob pattern to match (e.g., "*.ts", "package.json")',
482
+ },
483
+ directory: {
484
+ type: 'string',
485
+ description: 'The directory to search in',
486
+ },
487
+ max_depth: {
488
+ type: 'number',
489
+ description: 'Maximum directory depth to search',
490
+ },
491
+ },
492
+ required: ['pattern', 'directory'],
493
+ },
494
+ },
495
+ handler: async (args) => {
496
+ try {
497
+ const pattern = String(args.pattern);
498
+ const directory = String(args.directory);
499
+ const maxDepth = args.max_depth ? Number(args.max_depth) : undefined;
500
+ let command = `find "${directory}" -name "${pattern}" -type f`;
501
+ if (maxDepth) {
502
+ command += ` -maxdepth ${maxDepth}`;
503
+ }
504
+ const result = execSync(command, { encoding: 'utf8' });
505
+ const files = result.trim().split('\n').filter(Boolean);
506
+ return {
507
+ status: 'success',
508
+ output: files.join('\n') || '(no files found)',
509
+ metadata: { count: files.length },
510
+ };
511
+ }
512
+ catch (err) {
513
+ return {
514
+ status: 'error',
515
+ error: err instanceof Error ? err.message : String(err),
516
+ };
517
+ }
518
+ },
519
+ };
520
+ // View URL content tool
521
+ const viewUrlTool = {
522
+ definition: {
523
+ name: 'view_url',
524
+ description: 'Fetch and view content from a URL.',
525
+ parameters: {
526
+ type: 'object',
527
+ properties: {
528
+ url: {
529
+ type: 'string',
530
+ description: 'The URL to fetch',
531
+ },
532
+ },
533
+ required: ['url'],
534
+ },
535
+ },
536
+ handler: async (args) => {
537
+ try {
538
+ const url = String(args.url);
539
+ const response = await fetch(url);
540
+ if (!response.ok) {
541
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
542
+ }
543
+ const content = await response.text();
544
+ const truncated = content.length > 10000;
545
+ const output = truncated ? content.slice(0, 10000) + '\n... (truncated)' : content;
546
+ return {
547
+ status: 'success',
548
+ output,
549
+ metadata: {
550
+ url,
551
+ content_type: response.headers.get('content-type'),
552
+ content_length: content.length,
553
+ truncated,
554
+ },
555
+ };
556
+ }
557
+ catch (err) {
558
+ return {
559
+ status: 'error',
560
+ error: err instanceof Error ? err.message : String(err),
561
+ };
562
+ }
563
+ },
564
+ };
565
+ // Ask user question tool
566
+ const askUserTool = {
567
+ definition: {
568
+ name: 'ask_user',
569
+ description: 'Ask the user a question with predefined options.',
570
+ parameters: {
571
+ type: 'object',
572
+ properties: {
573
+ question: {
574
+ type: 'string',
575
+ description: 'The question to ask',
576
+ },
577
+ options: {
578
+ type: 'array',
579
+ description: 'Array of option objects with label and description',
580
+ items: {
581
+ type: 'object',
582
+ properties: {
583
+ label: { type: 'string' },
584
+ description: { type: 'string' },
585
+ },
586
+ },
587
+ },
588
+ allow_multiple: {
589
+ type: 'boolean',
590
+ description: 'Allow selecting multiple options',
591
+ },
592
+ },
593
+ required: ['question', 'options'],
594
+ },
595
+ },
596
+ handler: (args) => {
597
+ const question = String(args.question);
598
+ const options = Array.isArray(args.options) ? args.options : [];
599
+ const allowMultiple = Boolean(args.allow_multiple);
600
+ const formatted = options.map((opt, i) => {
601
+ const o = opt;
602
+ return `${i + 1}. ${o.label || '?'}: ${o.description || ''}`;
603
+ }).join('\n');
604
+ return {
605
+ status: 'success',
606
+ output: `USER QUESTION: ${question}\n\nOptions (${allowMultiple ? 'select multiple' : 'select one'}):\n${formatted}\n\nPlease respond with the number(s) of your choice.`,
607
+ metadata: { requires_user_input: true },
608
+ };
609
+ },
610
+ };
611
+ // Create memory tool
612
+ const createMemoryTool = {
613
+ definition: {
614
+ name: 'create_memory',
615
+ description: 'Save important context to the memory database.',
616
+ parameters: {
617
+ type: 'object',
618
+ properties: {
619
+ content: {
620
+ type: 'string',
621
+ description: 'The content to remember',
622
+ },
623
+ tags: {
624
+ type: 'array',
625
+ description: 'Tags to associate with the memory',
626
+ items: { type: 'string' },
627
+ },
628
+ title: {
629
+ type: 'string',
630
+ description: 'Title for the memory',
631
+ },
632
+ },
633
+ required: ['content', 'title'],
634
+ },
635
+ },
636
+ handler: (args) => {
637
+ const content = String(args.content);
638
+ const title = String(args.title);
639
+ const tags = Array.isArray(args.tags) ? args.tags : [];
640
+ // In a real implementation, this would write to a database
641
+ // For now, we just acknowledge the memory was created
642
+ return {
643
+ status: 'success',
644
+ output: `Memory saved: "${title}"\n\n${content}\n\nTags: ${tags.join(', ') || 'none'}`,
645
+ metadata: { title, tags },
646
+ };
647
+ },
648
+ };
649
+ // Vision/Image analysis tool - analyze images using Ollama vision models
650
+ const analyzeImageTool = {
651
+ definition: {
652
+ name: 'analyze_image',
653
+ description: 'Analyze an image file using vision AI. Returns a description of what the image contains.',
654
+ parameters: {
655
+ type: 'object',
656
+ properties: {
657
+ image_path: {
658
+ type: 'string',
659
+ description: 'The absolute path to the image file',
660
+ },
661
+ prompt: {
662
+ type: 'string',
663
+ description: 'Optional specific question about the image (default: "Describe this image in detail")',
664
+ },
665
+ },
666
+ required: ['image_path'],
667
+ },
668
+ },
669
+ handler: async (args) => {
670
+ try {
671
+ const imagePath = String(args.image_path);
672
+ const prompt = args.prompt ? String(args.prompt) : 'Describe this image in detail';
673
+ // Read image as base64
674
+ const imageBuffer = await fs.readFile(imagePath);
675
+ const base64Image = imageBuffer.toString('base64');
676
+ // Determine mime type from extension
677
+ const ext = path.extname(imagePath).toLowerCase();
678
+ const mimeType = ext === '.png' ? 'image/png' :
679
+ ext === '.gif' ? 'image/gif' :
680
+ ext === '.webp' ? 'image/webp' : 'image/jpeg';
681
+ // Call Ollama with vision capabilities
682
+ const ollamaUrl = process.env.OLLAMA_HOST || 'http://localhost:11434';
683
+ const model = process.env.VISION_MODEL || 'llava';
684
+ const response = await fetch(`${ollamaUrl}/api/generate`, {
685
+ method: 'POST',
686
+ headers: { 'Content-Type': 'application/json' },
687
+ body: JSON.stringify({
688
+ model,
689
+ prompt,
690
+ images: [base64Image],
691
+ stream: false,
692
+ }),
693
+ });
694
+ if (!response.ok) {
695
+ throw new Error(`Ollama API error: ${response.status}`);
696
+ }
697
+ const result = await response.json();
698
+ return {
699
+ status: 'success',
700
+ output: result.response,
701
+ metadata: { image_path: imagePath, model, prompt },
702
+ };
703
+ }
704
+ catch (err) {
705
+ return {
706
+ status: 'error',
707
+ error: err instanceof Error ? err.message : String(err),
708
+ };
709
+ }
710
+ },
711
+ };
712
+ // Text embedding tool - generate embeddings for text similarity
713
+ const embeddingTool = {
714
+ definition: {
715
+ name: 'generate_embedding',
716
+ description: 'Generate vector embeddings for text using Ollama. Useful for semantic search and similarity comparisons.',
717
+ parameters: {
718
+ type: 'object',
719
+ properties: {
720
+ text: {
721
+ type: 'string',
722
+ description: 'The text to generate embeddings for',
723
+ },
724
+ model: {
725
+ type: 'string',
726
+ description: 'Embedding model to use (default: nomic-embed-text)',
727
+ },
728
+ },
729
+ required: ['text'],
730
+ },
731
+ },
732
+ handler: async (args) => {
733
+ try {
734
+ const text = String(args.text);
735
+ const model = args.model ? String(args.model) : 'nomic-embed-text';
736
+ const ollamaUrl = process.env.OLLAMA_HOST || 'http://localhost:11434';
737
+ const response = await fetch(`${ollamaUrl}/api/embeddings`, {
738
+ method: 'POST',
739
+ headers: { 'Content-Type': 'application/json' },
740
+ body: JSON.stringify({
741
+ model,
742
+ prompt: text,
743
+ }),
744
+ });
745
+ if (!response.ok) {
746
+ throw new Error(`Ollama API error: ${response.status}`);
747
+ }
748
+ const result = await response.json();
749
+ return {
750
+ status: 'success',
751
+ output: `Generated ${result.embedding.length} dimensional embedding`,
752
+ metadata: {
753
+ embedding: result.embedding,
754
+ dimensions: result.embedding.length,
755
+ model,
756
+ text_preview: text.slice(0, 100) + (text.length > 100 ? '...' : ''),
757
+ },
758
+ };
759
+ }
760
+ catch (err) {
761
+ return {
762
+ status: 'error',
763
+ error: err instanceof Error ? err.message : String(err),
764
+ };
765
+ }
766
+ },
767
+ };
768
+ // Web search/research tool - search the web using various search APIs
769
+ const webSearchTool = {
770
+ definition: {
771
+ name: 'web_search',
772
+ description: 'Search the web for information. Uses DuckDuckGo or other search providers.',
773
+ parameters: {
774
+ type: 'object',
775
+ properties: {
776
+ query: {
777
+ type: 'string',
778
+ description: 'The search query',
779
+ },
780
+ num_results: {
781
+ type: 'number',
782
+ description: 'Number of results to return (default: 5, max: 10)',
783
+ },
784
+ },
785
+ required: ['query'],
786
+ },
787
+ },
788
+ handler: async (args) => {
789
+ try {
790
+ const query = encodeURIComponent(String(args.query));
791
+ const numResults = Math.min(args.num_results ? Number(args.num_results) : 5, 10);
792
+ // Try DuckDuckGo HTML first
793
+ try {
794
+ const response = await fetch(`https://html.duckduckgo.com/html/?q=${query}`, {
795
+ headers: {
796
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
797
+ },
798
+ });
799
+ if (response.ok) {
800
+ const html = await response.text();
801
+ // Parse results from HTML
802
+ const results = [];
803
+ // Simple regex-based extraction
804
+ const resultBlocks = html.match(/<div class="result[^"]*">[\s\S]*?<\/div>/g) || [];
805
+ for (const block of resultBlocks.slice(0, numResults)) {
806
+ const titleMatch = block.match(/<a[^>]*class="result__a"[^>]*>([\s\S]*?)<\/a>/);
807
+ const urlMatch = block.match(/<a[^>]*href="([^"]*)"/);
808
+ const snippetMatch = block.match(/<a[^>]*class="result__snippet"[^>]*>([\s\S]*?)<\/a>/);
809
+ if (titleMatch && urlMatch) {
810
+ results.push({
811
+ title: titleMatch[1].replace(/<[^>]*>/g, '').trim(),
812
+ url: urlMatch[1],
813
+ snippet: snippetMatch ? snippetMatch[1].replace(/<[^>]*>/g, '').trim() : '',
814
+ });
815
+ }
816
+ }
817
+ if (results.length > 0) {
818
+ const formatted = results.map((r, i) => `${i + 1}. ${r.title}\n URL: ${r.url}\n ${r.snippet}`).join('\n\n');
819
+ return {
820
+ status: 'success',
821
+ output: formatted,
822
+ metadata: { results_count: results.length, source: 'duckduckgo' },
823
+ };
824
+ }
825
+ }
826
+ }
827
+ catch {
828
+ // Fallback to alternative search or error
829
+ }
830
+ return {
831
+ status: 'error',
832
+ error: 'Web search failed. The search service may be unavailable or rate-limited.',
833
+ };
834
+ }
835
+ catch (err) {
836
+ return {
837
+ status: 'error',
838
+ error: err instanceof Error ? err.message : String(err),
839
+ };
840
+ }
841
+ },
842
+ };
843
+ // Browser automation tool - fetch and extract content from web pages
844
+ const browserTool = {
845
+ definition: {
846
+ name: 'browse_webpage',
847
+ description: 'Fetch a webpage and extract its main content, removing ads and navigation. Useful for reading articles.',
848
+ parameters: {
849
+ type: 'object',
850
+ properties: {
851
+ url: {
852
+ type: 'string',
853
+ description: 'The URL to browse',
854
+ },
855
+ extract_main_content: {
856
+ type: 'boolean',
857
+ description: 'Extract main content only (default: true)',
858
+ },
859
+ },
860
+ required: ['url'],
861
+ },
862
+ },
863
+ handler: async (args) => {
864
+ try {
865
+ const url = String(args.url);
866
+ const extractMain = args.extract_main_content !== false;
867
+ const response = await fetch(url, {
868
+ headers: {
869
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
870
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
871
+ 'Accept-Language': 'en-US,en;q=0.5',
872
+ },
873
+ });
874
+ if (!response.ok) {
875
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
876
+ }
877
+ const html = await response.text();
878
+ if (!extractMain) {
879
+ // Return raw HTML (truncated)
880
+ const truncated = html.length > 10000 ? html.slice(0, 10000) + '\n... (truncated)' : html;
881
+ return {
882
+ status: 'success',
883
+ output: truncated,
884
+ metadata: { url, content_length: html.length, truncated: html.length > 10000 },
885
+ };
886
+ }
887
+ // Extract title
888
+ const titleMatch = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
889
+ const title = titleMatch ? titleMatch[1].trim() : 'No title';
890
+ // Extract main content - remove scripts, styles, nav, etc.
891
+ let content = html
892
+ .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
893
+ .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
894
+ .replace(/<nav[^>]*>[\s\S]*?<\/nav>/gi, '')
895
+ .replace(/<header[^>]*>[\s\S]*?<\/header>/gi, '')
896
+ .replace(/<footer[^>]*>[\s\S]*?<\/footer>/gi, '')
897
+ .replace(/<aside[^>]*>[\s\S]*?<\/aside>/gi, '')
898
+ .replace(/<[^>]*>/g, ' ') // Remove remaining tags
899
+ .replace(/\s+/g, ' ') // Normalize whitespace
900
+ .trim();
901
+ // Truncate if too long
902
+ const maxLength = 8000;
903
+ const truncated = content.length > maxLength;
904
+ if (truncated) {
905
+ content = content.slice(0, maxLength) + '\n... (content truncated)';
906
+ }
907
+ return {
908
+ status: 'success',
909
+ output: `Title: ${title}\n\nContent:\n${content}`,
910
+ metadata: {
911
+ url,
912
+ title,
913
+ content_length: content.length,
914
+ truncated,
915
+ },
916
+ };
917
+ }
918
+ catch (err) {
919
+ return {
920
+ status: 'error',
921
+ error: err instanceof Error ? err.message : String(err),
922
+ };
923
+ }
924
+ },
925
+ };
926
+ // Code execution tool - run code in various languages
927
+ const codeExecutionTool = {
928
+ definition: {
929
+ name: 'execute_code',
930
+ description: 'Execute code in various programming languages (JavaScript, Python, Bash). Returns stdout, stderr, and exit code.',
931
+ parameters: {
932
+ type: 'object',
933
+ properties: {
934
+ code: {
935
+ type: 'string',
936
+ description: 'The code to execute',
937
+ },
938
+ language: {
939
+ type: 'string',
940
+ description: 'Programming language (javascript, python, bash/shell)',
941
+ enum: ['javascript', 'python', 'bash', 'shell'],
942
+ },
943
+ timeout_sec: {
944
+ type: 'number',
945
+ description: 'Timeout in seconds (default: 30)',
946
+ },
947
+ },
948
+ required: ['code', 'language'],
949
+ },
950
+ },
951
+ handler: async (args) => {
952
+ try {
953
+ const code = String(args.code);
954
+ const language = String(args.language).toLowerCase();
955
+ const timeoutSec = args.timeout_sec ? Number(args.timeout_sec) : 30;
956
+ let command;
957
+ let args_list;
958
+ switch (language) {
959
+ case 'javascript':
960
+ case 'js':
961
+ command = 'node';
962
+ args_list = ['-e', code];
963
+ break;
964
+ case 'python':
965
+ case 'py':
966
+ command = 'python3';
967
+ args_list = ['-c', code];
968
+ break;
969
+ case 'bash':
970
+ case 'shell':
971
+ case 'sh':
972
+ command = 'bash';
973
+ args_list = ['-c', code];
974
+ break;
975
+ default:
976
+ return {
977
+ status: 'error',
978
+ error: `Unsupported language: ${language}. Supported: javascript, python, bash`,
979
+ };
980
+ }
981
+ return new Promise((resolve) => {
982
+ const child = spawn(command, args_list, {
983
+ stdio: ['ignore', 'pipe', 'pipe'],
984
+ });
985
+ let stdout = '';
986
+ let stderr = '';
987
+ let timeout = null;
988
+ if (timeoutSec > 0) {
989
+ timeout = setTimeout(() => {
990
+ child.kill('SIGTERM');
991
+ setTimeout(() => {
992
+ if (!child.killed)
993
+ child.kill('SIGKILL');
994
+ }, 5000);
995
+ }, timeoutSec * 1000);
996
+ }
997
+ child.stdout?.on('data', (data) => {
998
+ stdout += String(data);
999
+ });
1000
+ child.stderr?.on('data', (data) => {
1001
+ stderr += String(data);
1002
+ });
1003
+ child.on('close', (code) => {
1004
+ if (timeout)
1005
+ clearTimeout(timeout);
1006
+ const output = stdout || stderr || '(no output)';
1007
+ const isError = code !== 0;
1008
+ resolve({
1009
+ status: isError ? 'error' : 'success',
1010
+ output,
1011
+ error: isError ? `Exit code: ${code}${stderr ? '\n' + stderr : ''}` : undefined,
1012
+ metadata: {
1013
+ language,
1014
+ exit_code: code,
1015
+ stdout_length: stdout.length,
1016
+ stderr_length: stderr.length,
1017
+ },
1018
+ });
1019
+ });
1020
+ child.on('error', (err) => {
1021
+ if (timeout)
1022
+ clearTimeout(timeout);
1023
+ resolve({
1024
+ status: 'error',
1025
+ error: `Failed to execute: ${err.message}`,
1026
+ });
1027
+ });
1028
+ });
1029
+ }
1030
+ catch (err) {
1031
+ return {
1032
+ status: 'error',
1033
+ error: err instanceof Error ? err.message : String(err),
1034
+ };
1035
+ }
1036
+ },
1037
+ };
1038
+ // Semantic search tool - search within files using embeddings
1039
+ const semanticSearchTool = {
1040
+ definition: {
1041
+ name: 'semantic_search',
1042
+ description: 'Search for semantically similar content in files. Uses embeddings to find conceptually related content, not just keyword matches.',
1043
+ parameters: {
1044
+ type: 'object',
1045
+ properties: {
1046
+ query: {
1047
+ type: 'string',
1048
+ description: 'The semantic query (what concept you are looking for)',
1049
+ },
1050
+ directory: {
1051
+ type: 'string',
1052
+ description: 'Directory to search in',
1053
+ },
1054
+ file_pattern: {
1055
+ type: 'string',
1056
+ description: 'File pattern to limit search (e.g., "*.md", "*.txt")',
1057
+ },
1058
+ top_k: {
1059
+ type: 'number',
1060
+ description: 'Number of top results to return (default: 5)',
1061
+ },
1062
+ },
1063
+ required: ['query', 'directory'],
1064
+ },
1065
+ },
1066
+ handler: async (args) => {
1067
+ try {
1068
+ const query = String(args.query);
1069
+ const directory = String(args.directory);
1070
+ const filePattern = args.file_pattern ? String(args.file_pattern) : '*';
1071
+ const topK = args.top_k ? Number(args.top_k) : 5;
1072
+ // For now, fallback to grep-based semantic-ish search
1073
+ // In a full implementation, this would use embeddings
1074
+ const keywords = query.toLowerCase().split(/\s+/).filter(w => w.length > 3);
1075
+ const pattern = keywords.join('|');
1076
+ if (!pattern) {
1077
+ return {
1078
+ status: 'error',
1079
+ error: 'Query too short for semantic search',
1080
+ };
1081
+ }
1082
+ try {
1083
+ const command = `find "${directory}" -name "${filePattern}" -type f -exec grep -l -i -E "${pattern}" {} \\; 2>/dev/null | head -20`;
1084
+ const files = execSync(command, { encoding: 'utf8', timeout: 30000 }).trim().split('\n').filter(Boolean);
1085
+ if (files.length === 0) {
1086
+ return {
1087
+ status: 'success',
1088
+ output: 'No files found matching the semantic query.',
1089
+ metadata: { query, directory, matches: 0 },
1090
+ };
1091
+ }
1092
+ // Get excerpts from each file
1093
+ const results = [];
1094
+ for (const file of files.slice(0, topK)) {
1095
+ try {
1096
+ const content = await fs.readFile(file, 'utf8');
1097
+ // Find relevant excerpt
1098
+ const lines = content.split('\n');
1099
+ for (let i = 0; i < lines.length; i++) {
1100
+ const line = lines[i].toLowerCase();
1101
+ if (keywords.some(k => line.includes(k))) {
1102
+ const excerpt = lines.slice(Math.max(0, i - 2), i + 3).join('\n');
1103
+ results.push(`File: ${file}\n${excerpt}\n---`);
1104
+ break;
1105
+ }
1106
+ }
1107
+ }
1108
+ catch {
1109
+ // Skip files that can't be read
1110
+ }
1111
+ }
1112
+ return {
1113
+ status: 'success',
1114
+ output: results.join('\n\n') || 'Found files but could not extract excerpts.',
1115
+ metadata: {
1116
+ query,
1117
+ directory,
1118
+ files_searched: files.length,
1119
+ results_returned: results.length,
1120
+ },
1121
+ };
1122
+ }
1123
+ catch (err) {
1124
+ return {
1125
+ status: 'error',
1126
+ error: `Search failed: ${err instanceof Error ? err.message : String(err)}`,
1127
+ };
1128
+ }
1129
+ }
1130
+ catch (err) {
1131
+ return {
1132
+ status: 'error',
1133
+ error: err instanceof Error ? err.message : String(err),
1134
+ };
1135
+ }
1136
+ },
1137
+ };
1138
+ // Git tools - various git operations
1139
+ const gitStatusTool = {
1140
+ definition: {
1141
+ name: 'git_status',
1142
+ description: 'Check git repository status. Shows modified, staged, and untracked files.',
1143
+ parameters: {
1144
+ type: 'object',
1145
+ properties: {
1146
+ repository_path: {
1147
+ type: 'string',
1148
+ description: 'Path to the git repository (default: current directory)',
1149
+ },
1150
+ },
1151
+ required: [],
1152
+ },
1153
+ },
1154
+ handler: async (args) => {
1155
+ try {
1156
+ const repoPath = args.repository_path ? String(args.repository_path) : process.cwd();
1157
+ const result = execSync('git status -sb', {
1158
+ cwd: repoPath,
1159
+ encoding: 'utf8',
1160
+ timeout: 10000,
1161
+ });
1162
+ return {
1163
+ status: 'success',
1164
+ output: result.trim() || 'No changes',
1165
+ metadata: { repository: repoPath },
1166
+ };
1167
+ }
1168
+ catch (err) {
1169
+ return {
1170
+ status: 'error',
1171
+ error: `Not a git repository or git not available: ${err instanceof Error ? err.message : String(err)}`,
1172
+ };
1173
+ }
1174
+ },
1175
+ };
1176
+ const gitDiffTool = {
1177
+ definition: {
1178
+ name: 'git_diff',
1179
+ description: 'Show git diff for modified files. Can show staged or unstaged changes.',
1180
+ parameters: {
1181
+ type: 'object',
1182
+ properties: {
1183
+ repository_path: {
1184
+ type: 'string',
1185
+ description: 'Path to the git repository',
1186
+ },
1187
+ staged: {
1188
+ type: 'boolean',
1189
+ description: 'Show staged changes instead of unstaged',
1190
+ },
1191
+ file_path: {
1192
+ type: 'string',
1193
+ description: 'Show diff for specific file only',
1194
+ },
1195
+ },
1196
+ required: [],
1197
+ },
1198
+ },
1199
+ handler: async (args) => {
1200
+ try {
1201
+ const repoPath = args.repository_path ? String(args.repository_path) : process.cwd();
1202
+ const staged = Boolean(args.staged);
1203
+ const filePath = args.file_path ? String(args.file_path) : undefined;
1204
+ let command = 'git diff';
1205
+ if (staged)
1206
+ command += ' --cached';
1207
+ if (filePath)
1208
+ command += ` -- "${filePath}"`;
1209
+ const result = execSync(command, {
1210
+ cwd: repoPath,
1211
+ encoding: 'utf8',
1212
+ timeout: 10000,
1213
+ });
1214
+ return {
1215
+ status: 'success',
1216
+ output: result.trim() || 'No changes',
1217
+ metadata: { repository: repoPath, staged, file: filePath },
1218
+ };
1219
+ }
1220
+ catch (err) {
1221
+ return {
1222
+ status: 'error',
1223
+ error: err instanceof Error ? err.message : String(err),
1224
+ };
1225
+ }
1226
+ },
1227
+ };
1228
+ const gitLogTool = {
1229
+ definition: {
1230
+ name: 'git_log',
1231
+ description: 'Show git commit history with customizable format.',
1232
+ parameters: {
1233
+ type: 'object',
1234
+ properties: {
1235
+ repository_path: {
1236
+ type: 'string',
1237
+ description: 'Path to the git repository',
1238
+ },
1239
+ num_commits: {
1240
+ type: 'number',
1241
+ description: 'Number of commits to show (default: 10)',
1242
+ },
1243
+ oneline: {
1244
+ type: 'boolean',
1245
+ description: 'Show one line per commit',
1246
+ },
1247
+ },
1248
+ required: [],
1249
+ },
1250
+ },
1251
+ handler: async (args) => {
1252
+ try {
1253
+ const repoPath = args.repository_path ? String(args.repository_path) : process.cwd();
1254
+ const numCommits = args.num_commits ? Number(args.num_commits) : 10;
1255
+ const oneline = Boolean(args.oneline);
1256
+ let command = `git log -n ${numCommits}`;
1257
+ if (oneline)
1258
+ command += ' --oneline';
1259
+ const result = execSync(command, {
1260
+ cwd: repoPath,
1261
+ encoding: 'utf8',
1262
+ timeout: 10000,
1263
+ });
1264
+ return {
1265
+ status: 'success',
1266
+ output: result.trim(),
1267
+ metadata: { repository: repoPath, commits_shown: numCommits },
1268
+ };
1269
+ }
1270
+ catch (err) {
1271
+ return {
1272
+ status: 'error',
1273
+ error: err instanceof Error ? err.message : String(err),
1274
+ };
1275
+ }
1276
+ },
1277
+ };
1278
+ // HTTP API tool - make HTTP requests
1279
+ const httpRequestTool = {
1280
+ definition: {
1281
+ name: 'http_request',
1282
+ description: 'Make HTTP requests (GET, POST, PUT, DELETE, PATCH). Supports JSON body and custom headers.',
1283
+ parameters: {
1284
+ type: 'object',
1285
+ properties: {
1286
+ url: {
1287
+ type: 'string',
1288
+ description: 'The URL to request',
1289
+ },
1290
+ method: {
1291
+ type: 'string',
1292
+ description: 'HTTP method',
1293
+ enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
1294
+ },
1295
+ headers: {
1296
+ type: 'object',
1297
+ description: 'Custom headers as key-value pairs',
1298
+ },
1299
+ body: {
1300
+ type: 'string',
1301
+ description: 'Request body (for POST, PUT, PATCH)',
1302
+ },
1303
+ body_json: {
1304
+ type: 'object',
1305
+ description: 'JSON body as object (will be serialized)',
1306
+ },
1307
+ },
1308
+ required: ['url'],
1309
+ },
1310
+ },
1311
+ handler: async (args) => {
1312
+ try {
1313
+ const url = String(args.url);
1314
+ const method = args.method ? String(args.method).toUpperCase() : 'GET';
1315
+ const headers = args.headers || {};
1316
+ let body;
1317
+ if (args.body_json) {
1318
+ body = JSON.stringify(args.body_json);
1319
+ headers['Content-Type'] = headers['Content-Type'] || 'application/json';
1320
+ }
1321
+ else if (args.body) {
1322
+ body = String(args.body);
1323
+ }
1324
+ const response = await fetch(url, {
1325
+ method,
1326
+ headers,
1327
+ body: body && method !== 'GET' && method !== 'HEAD' ? body : undefined,
1328
+ });
1329
+ const responseBody = await response.text();
1330
+ const truncated = responseBody.length > 10000;
1331
+ const output = truncated ? responseBody.slice(0, 10000) + '\n... (truncated)' : responseBody;
1332
+ // Try to parse as JSON for metadata
1333
+ let jsonBody = null;
1334
+ try {
1335
+ jsonBody = JSON.parse(responseBody);
1336
+ }
1337
+ catch {
1338
+ // Not JSON
1339
+ }
1340
+ // Collect headers
1341
+ const headersObj = {};
1342
+ response.headers.forEach((value, key) => {
1343
+ headersObj[key] = value;
1344
+ });
1345
+ return {
1346
+ status: response.ok ? 'success' : 'error',
1347
+ output,
1348
+ error: response.ok ? undefined : `HTTP ${response.status}: ${response.statusText}`,
1349
+ metadata: {
1350
+ status: response.status,
1351
+ statusText: response.statusText,
1352
+ headers: headersObj,
1353
+ body_truncated: truncated,
1354
+ body_length: responseBody.length,
1355
+ json_parsed: jsonBody !== null,
1356
+ },
1357
+ };
1358
+ }
1359
+ catch (err) {
1360
+ return {
1361
+ status: 'error',
1362
+ error: err instanceof Error ? err.message : String(err),
1363
+ };
1364
+ }
1365
+ },
1366
+ };
1367
+ // JSON/YAML tools - parsing and conversion
1368
+ const parseJsonTool = {
1369
+ definition: {
1370
+ name: 'parse_json',
1371
+ description: 'Parse and validate JSON. Returns formatted JSON or error details.',
1372
+ parameters: {
1373
+ type: 'object',
1374
+ properties: {
1375
+ text: {
1376
+ type: 'string',
1377
+ description: 'JSON text to parse',
1378
+ },
1379
+ file_path: {
1380
+ type: 'string',
1381
+ description: 'Path to JSON file (alternative to text)',
1382
+ },
1383
+ format_output: {
1384
+ type: 'boolean',
1385
+ description: 'Format output with indentation (default: true)',
1386
+ },
1387
+ },
1388
+ required: [],
1389
+ },
1390
+ },
1391
+ handler: async (args) => {
1392
+ try {
1393
+ let text;
1394
+ if (args.file_path) {
1395
+ text = await fs.readFile(String(args.file_path), 'utf8');
1396
+ }
1397
+ else if (args.text) {
1398
+ text = String(args.text);
1399
+ }
1400
+ else {
1401
+ return {
1402
+ status: 'error',
1403
+ error: 'Either text or file_path must be provided',
1404
+ };
1405
+ }
1406
+ const parsed = JSON.parse(text);
1407
+ const formatOutput = args.format_output !== false;
1408
+ const output = formatOutput ? JSON.stringify(parsed, null, 2) : JSON.stringify(parsed);
1409
+ // Get type info
1410
+ const type = Array.isArray(parsed) ? 'array' : typeof parsed;
1411
+ const keys = type === 'object' && parsed !== null ? Object.keys(parsed) : null;
1412
+ return {
1413
+ status: 'success',
1414
+ output,
1415
+ metadata: {
1416
+ type,
1417
+ keys: keys,
1418
+ length: Array.isArray(parsed) ? parsed.length : undefined,
1419
+ },
1420
+ };
1421
+ }
1422
+ catch (err) {
1423
+ return {
1424
+ status: 'error',
1425
+ error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`,
1426
+ };
1427
+ }
1428
+ },
1429
+ };
1430
+ const jsonToYamlTool = {
1431
+ definition: {
1432
+ name: 'convert_json_yaml',
1433
+ description: 'Convert between JSON and YAML formats.',
1434
+ parameters: {
1435
+ type: 'object',
1436
+ properties: {
1437
+ input: {
1438
+ type: 'string',
1439
+ description: 'Input text (JSON or YAML)',
1440
+ },
1441
+ file_path: {
1442
+ type: 'string',
1443
+ description: 'Path to file (alternative to input)',
1444
+ },
1445
+ to: {
1446
+ type: 'string',
1447
+ description: 'Target format',
1448
+ enum: ['json', 'yaml'],
1449
+ },
1450
+ },
1451
+ required: ['to'],
1452
+ },
1453
+ },
1454
+ handler: async (args) => {
1455
+ try {
1456
+ const targetFormat = String(args.to).toLowerCase();
1457
+ let input;
1458
+ if (args.file_path) {
1459
+ input = await fs.readFile(String(args.file_path), 'utf8');
1460
+ }
1461
+ else if (args.input) {
1462
+ input = String(args.input);
1463
+ }
1464
+ else {
1465
+ return {
1466
+ status: 'error',
1467
+ error: 'Either input or file_path must be provided',
1468
+ };
1469
+ }
1470
+ // Detect input format and parse
1471
+ let data;
1472
+ try {
1473
+ data = JSON.parse(input);
1474
+ }
1475
+ catch {
1476
+ // Try YAML-like parsing (simplified - just handles basic cases)
1477
+ // For full YAML support, would need js-yaml library
1478
+ const lines = input.split('\n');
1479
+ data = {};
1480
+ let currentKey = '';
1481
+ for (const line of lines) {
1482
+ const match = line.match(/^(\w+):\s*(.*)$/);
1483
+ if (match) {
1484
+ currentKey = match[1];
1485
+ data[currentKey] = match[2] || '';
1486
+ }
1487
+ }
1488
+ }
1489
+ let output;
1490
+ if (targetFormat === 'json') {
1491
+ output = JSON.stringify(data, null, 2);
1492
+ }
1493
+ else {
1494
+ // Simple YAML serialization
1495
+ output = Object.entries(data)
1496
+ .map(([k, v]) => `${k}: ${typeof v === 'string' ? v : JSON.stringify(v)}`)
1497
+ .join('\n');
1498
+ }
1499
+ return {
1500
+ status: 'success',
1501
+ output,
1502
+ metadata: { source_format: targetFormat === 'json' ? 'yaml' : 'json', target_format: targetFormat },
1503
+ };
1504
+ }
1505
+ catch (err) {
1506
+ return {
1507
+ status: 'error',
1508
+ error: err instanceof Error ? err.message : String(err),
1509
+ };
1510
+ }
1511
+ },
1512
+ };
1513
+ // File diff tool - compare two files
1514
+ const diffFilesTool = {
1515
+ definition: {
1516
+ name: 'diff_files',
1517
+ description: 'Compare two files and show differences. Uses unified diff format.',
1518
+ parameters: {
1519
+ type: 'object',
1520
+ properties: {
1521
+ file1: {
1522
+ type: 'string',
1523
+ description: 'Path to first file',
1524
+ },
1525
+ file2: {
1526
+ type: 'string',
1527
+ description: 'Path to second file',
1528
+ },
1529
+ unified_lines: {
1530
+ type: 'number',
1531
+ description: 'Number of context lines (default: 3)',
1532
+ },
1533
+ },
1534
+ required: ['file1', 'file2'],
1535
+ },
1536
+ },
1537
+ handler: async (args) => {
1538
+ try {
1539
+ const file1 = String(args.file1);
1540
+ const file2 = String(args.file2);
1541
+ const context = args.unified_lines ? Number(args.unified_lines) : 3;
1542
+ const content1 = await fs.readFile(file1, 'utf8');
1543
+ const content2 = await fs.readFile(file2, 'utf8');
1544
+ // Simple line-by-line diff
1545
+ const lines1 = content1.split('\n');
1546
+ const lines2 = content2.split('\n');
1547
+ const diff = [];
1548
+ const maxLen = Math.max(lines1.length, lines2.length);
1549
+ for (let i = 0; i < maxLen; i++) {
1550
+ const line1 = lines1[i];
1551
+ const line2 = lines2[i];
1552
+ if (line1 !== line2) {
1553
+ if (line1 !== undefined)
1554
+ diff.push(`-${line1}`);
1555
+ if (line2 !== undefined)
1556
+ diff.push(`+${line2}`);
1557
+ }
1558
+ else {
1559
+ diff.push(` ${line1}`);
1560
+ }
1561
+ }
1562
+ const output = diff.slice(0, 200).join('\n'); // Limit output
1563
+ const truncated = diff.length > 200;
1564
+ return {
1565
+ status: 'success',
1566
+ output: truncated ? output + '\n... (truncated)' : output,
1567
+ metadata: { file1, file2, differences: diff.length },
1568
+ };
1569
+ }
1570
+ catch (err) {
1571
+ return {
1572
+ status: 'error',
1573
+ error: err instanceof Error ? err.message : String(err),
1574
+ };
1575
+ }
1576
+ },
1577
+ };
1578
+ // Compression tools - create/extract archives
1579
+ const createArchiveTool = {
1580
+ definition: {
1581
+ name: 'create_archive',
1582
+ description: 'Create a zip or tar archive from files or directories.',
1583
+ parameters: {
1584
+ type: 'object',
1585
+ properties: {
1586
+ output_path: {
1587
+ type: 'string',
1588
+ description: 'Path for the output archive',
1589
+ },
1590
+ source_paths: {
1591
+ type: 'array',
1592
+ description: 'Array of file or directory paths to include',
1593
+ items: { type: 'string' },
1594
+ },
1595
+ format: {
1596
+ type: 'string',
1597
+ description: 'Archive format',
1598
+ enum: ['zip', 'tar', 'tar.gz', 'tgz'],
1599
+ },
1600
+ },
1601
+ required: ['output_path', 'source_paths'],
1602
+ },
1603
+ },
1604
+ handler: async (args) => {
1605
+ try {
1606
+ const outputPath = String(args.output_path);
1607
+ const sourcePaths = Array.isArray(args.source_paths) ? args.source_paths.map(String) : [];
1608
+ const format = args.format ? String(args.format) : 'zip';
1609
+ let command;
1610
+ const sources = sourcePaths.map(p => `"${p}"`).join(' ');
1611
+ switch (format) {
1612
+ case 'zip':
1613
+ command = `zip -r "${outputPath}" ${sources}`;
1614
+ break;
1615
+ case 'tar':
1616
+ command = `tar -cf "${outputPath}" ${sources}`;
1617
+ break;
1618
+ case 'tar.gz':
1619
+ case 'tgz':
1620
+ command = `tar -czf "${outputPath}" ${sources}`;
1621
+ break;
1622
+ default:
1623
+ return {
1624
+ status: 'error',
1625
+ error: `Unsupported format: ${format}`,
1626
+ };
1627
+ }
1628
+ execSync(command, { timeout: 60000 });
1629
+ const stats = await fs.stat(outputPath);
1630
+ return {
1631
+ status: 'success',
1632
+ output: `Archive created: ${outputPath} (${(stats.size / 1024).toFixed(2)} KB)`,
1633
+ metadata: { output_path: outputPath, format, files_included: sourcePaths.length, size_bytes: stats.size },
1634
+ };
1635
+ }
1636
+ catch (err) {
1637
+ return {
1638
+ status: 'error',
1639
+ error: err instanceof Error ? err.message : String(err),
1640
+ };
1641
+ }
1642
+ },
1643
+ };
1644
+ const extractArchiveTool = {
1645
+ definition: {
1646
+ name: 'extract_archive',
1647
+ description: 'Extract a zip or tar archive.',
1648
+ parameters: {
1649
+ type: 'object',
1650
+ properties: {
1651
+ archive_path: {
1652
+ type: 'string',
1653
+ description: 'Path to the archive file',
1654
+ },
1655
+ output_directory: {
1656
+ type: 'string',
1657
+ description: 'Directory to extract to (default: same as archive)',
1658
+ },
1659
+ },
1660
+ required: ['archive_path'],
1661
+ },
1662
+ },
1663
+ handler: async (args) => {
1664
+ try {
1665
+ const archivePath = String(args.archive_path);
1666
+ const outputDir = args.output_directory ? String(args.output_directory) : path.dirname(archivePath);
1667
+ // Detect format from extension
1668
+ const ext = path.extname(archivePath).toLowerCase();
1669
+ const baseName = path.basename(archivePath);
1670
+ let command;
1671
+ if (ext === '.zip') {
1672
+ command = `unzip -o "${archivePath}" -d "${outputDir}"`;
1673
+ }
1674
+ else if (ext === '.gz' || baseName.endsWith('.tar.gz') || baseName.endsWith('.tgz')) {
1675
+ command = `tar -xzf "${archivePath}" -C "${outputDir}"`;
1676
+ }
1677
+ else if (ext === '.tar') {
1678
+ command = `tar -xf "${archivePath}" -C "${outputDir}"`;
1679
+ }
1680
+ else {
1681
+ return {
1682
+ status: 'error',
1683
+ error: `Could not detect archive format from: ${archivePath}`,
1684
+ };
1685
+ }
1686
+ execSync(command, { timeout: 60000 });
1687
+ return {
1688
+ status: 'success',
1689
+ output: `Archive extracted to: ${outputDir}`,
1690
+ metadata: { archive: archivePath, output_directory: outputDir },
1691
+ };
1692
+ }
1693
+ catch (err) {
1694
+ return {
1695
+ status: 'error',
1696
+ error: err instanceof Error ? err.message : String(err),
1697
+ };
1698
+ }
1699
+ },
1700
+ };
1701
+ // PDF text extraction tool
1702
+ const extractPdfTool = {
1703
+ definition: {
1704
+ name: 'extract_pdf_text',
1705
+ description: 'Extract text content from a PDF file. Requires pdftotext or similar tool.',
1706
+ parameters: {
1707
+ type: 'object',
1708
+ properties: {
1709
+ pdf_path: {
1710
+ type: 'string',
1711
+ description: 'Path to the PDF file',
1712
+ },
1713
+ page_range: {
1714
+ type: 'string',
1715
+ description: 'Page range to extract (e.g., "1-5" or "1,3,5", default: all)',
1716
+ },
1717
+ },
1718
+ required: ['pdf_path'],
1719
+ },
1720
+ },
1721
+ handler: async (args) => {
1722
+ try {
1723
+ const pdfPath = String(args.pdf_path);
1724
+ const pageRange = args.page_range ? String(args.page_range) : undefined;
1725
+ let command = `pdftotext -layout`;
1726
+ if (pageRange) {
1727
+ command += ` -f ${pageRange.split('-')[0]} -l ${pageRange.split('-')[1] || pageRange.split('-')[0]}`;
1728
+ }
1729
+ command += ` "${pdfPath}" -`; // Output to stdout
1730
+ const output = execSync(command, { encoding: 'utf8', timeout: 30000 });
1731
+ const truncated = output.length > 15000;
1732
+ return {
1733
+ status: 'success',
1734
+ output: truncated ? output.slice(0, 15000) + '\n... (truncated)' : output,
1735
+ metadata: { pdf_path: pdfPath, page_range: pageRange, text_length: output.length, truncated },
1736
+ };
1737
+ }
1738
+ catch (err) {
1739
+ // Fallback: try Python with PyPDF2
1740
+ try {
1741
+ const pythonScript = `
1742
+ import sys
1743
+ from PyPDF2 import PdfReader
1744
+ reader = PdfReader("${args.pdf_path}")
1745
+ text = ""
1746
+ for page in reader.pages:
1747
+ text += page.extract_text() + "\\n"
1748
+ print(text)
1749
+ `;
1750
+ const output = execSync(`python3 -c "${pythonScript}"`, { encoding: 'utf8', timeout: 30000 });
1751
+ return {
1752
+ status: 'success',
1753
+ output,
1754
+ metadata: { pdf_path: args.pdf_path, method: 'pypdf2' },
1755
+ };
1756
+ }
1757
+ catch {
1758
+ return {
1759
+ status: 'error',
1760
+ error: `Failed to extract PDF text. Ensure pdftotext (poppler-utils) or PyPDF2 is installed. Original error: ${err instanceof Error ? err.message : String(err)}`,
1761
+ };
1762
+ }
1763
+ }
1764
+ },
1765
+ };
1766
+ // Network tools - ping, port check, DNS
1767
+ const pingTool = {
1768
+ definition: {
1769
+ name: 'ping_host',
1770
+ description: 'Ping a host to check network connectivity.',
1771
+ parameters: {
1772
+ type: 'object',
1773
+ properties: {
1774
+ host: {
1775
+ type: 'string',
1776
+ description: 'Hostname or IP to ping',
1777
+ },
1778
+ count: {
1779
+ type: 'number',
1780
+ description: 'Number of pings (default: 4)',
1781
+ },
1782
+ },
1783
+ required: ['host'],
1784
+ },
1785
+ },
1786
+ handler: async (args) => {
1787
+ try {
1788
+ const host = String(args.host);
1789
+ const count = args.count ? Number(args.count) : 4;
1790
+ const output = execSync(`ping -c ${count} "${host}"`, {
1791
+ encoding: 'utf8',
1792
+ timeout: 30000,
1793
+ });
1794
+ return {
1795
+ status: 'success',
1796
+ output,
1797
+ metadata: { host, count },
1798
+ };
1799
+ }
1800
+ catch (err) {
1801
+ // ping returns non-zero on some failures but still has output
1802
+ const output = err.stdout;
1803
+ if (output) {
1804
+ return {
1805
+ status: 'error',
1806
+ output,
1807
+ error: 'Host unreachable or ping failed',
1808
+ metadata: { host: args.host },
1809
+ };
1810
+ }
1811
+ return {
1812
+ status: 'error',
1813
+ error: err instanceof Error ? err.message : String(err),
1814
+ };
1815
+ }
1816
+ },
1817
+ };
1818
+ const checkPortTool = {
1819
+ definition: {
1820
+ name: 'check_port',
1821
+ description: 'Check if a port is open on a host.',
1822
+ parameters: {
1823
+ type: 'object',
1824
+ properties: {
1825
+ host: {
1826
+ type: 'string',
1827
+ description: 'Hostname or IP',
1828
+ },
1829
+ port: {
1830
+ type: 'number',
1831
+ description: 'Port number to check',
1832
+ },
1833
+ timeout_sec: {
1834
+ type: 'number',
1835
+ description: 'Timeout in seconds (default: 5)',
1836
+ },
1837
+ },
1838
+ required: ['host', 'port'],
1839
+ },
1840
+ },
1841
+ handler: async (args) => {
1842
+ try {
1843
+ const host = String(args.host);
1844
+ const port = Number(args.port);
1845
+ const timeout = args.timeout_sec ? Number(args.timeout_sec) : 5;
1846
+ // Try using nc (netcat)
1847
+ try {
1848
+ execSync(`nc -z -w ${timeout} "${host}" ${port}`, { timeout: timeout * 1000 + 1000 });
1849
+ return {
1850
+ status: 'success',
1851
+ output: `Port ${port} on ${host} is OPEN`,
1852
+ metadata: { host, port, open: true },
1853
+ };
1854
+ }
1855
+ catch {
1856
+ return {
1857
+ status: 'success',
1858
+ output: `Port ${port} on ${host} is CLOSED or filtered`,
1859
+ metadata: { host, port, open: false },
1860
+ };
1861
+ }
1862
+ }
1863
+ catch (err) {
1864
+ return {
1865
+ status: 'error',
1866
+ error: err instanceof Error ? err.message : String(err),
1867
+ };
1868
+ }
1869
+ },
1870
+ };
1871
+ // Docker tool - manage containers
1872
+ const dockerTool = {
1873
+ definition: {
1874
+ name: 'docker',
1875
+ description: 'Run Docker commands. Supports ps, images, logs, exec, run, build.',
1876
+ parameters: {
1877
+ type: 'object',
1878
+ properties: {
1879
+ command: {
1880
+ type: 'string',
1881
+ description: 'Docker command (ps, images, logs, exec, run, build, stop, rm)',
1882
+ enum: ['ps', 'images', 'logs', 'exec', 'run', 'build', 'stop', 'rm', 'compose-up', 'compose-down'],
1883
+ },
1884
+ container: {
1885
+ type: 'string',
1886
+ description: 'Container name or ID (for logs, exec, stop, rm)',
1887
+ },
1888
+ args: {
1889
+ type: 'string',
1890
+ description: 'Additional arguments',
1891
+ },
1892
+ },
1893
+ required: ['command'],
1894
+ },
1895
+ },
1896
+ handler: async (args) => {
1897
+ try {
1898
+ const command = String(args.command);
1899
+ const container = args.container ? String(args.container) : '';
1900
+ const extraArgs = args.args ? String(args.args) : '';
1901
+ let dockerCmd;
1902
+ switch (command) {
1903
+ case 'ps':
1904
+ dockerCmd = 'docker ps -a';
1905
+ break;
1906
+ case 'images':
1907
+ dockerCmd = 'docker images';
1908
+ break;
1909
+ case 'logs':
1910
+ if (!container)
1911
+ return { status: 'error', error: 'Container name required for logs' };
1912
+ dockerCmd = `docker logs --tail 100 ${container}`;
1913
+ break;
1914
+ case 'exec':
1915
+ if (!container)
1916
+ return { status: 'error', error: 'Container name required for exec' };
1917
+ dockerCmd = `docker exec ${container} ${extraArgs || 'sh'}`;
1918
+ break;
1919
+ case 'stop':
1920
+ if (!container)
1921
+ return { status: 'error', error: 'Container name required for stop' };
1922
+ dockerCmd = `docker stop ${container}`;
1923
+ break;
1924
+ case 'rm':
1925
+ if (!container)
1926
+ return { status: 'error', error: 'Container name required for rm' };
1927
+ dockerCmd = `docker rm ${container}`;
1928
+ break;
1929
+ case 'compose-up':
1930
+ dockerCmd = 'docker compose up -d';
1931
+ break;
1932
+ case 'compose-down':
1933
+ dockerCmd = 'docker compose down';
1934
+ break;
1935
+ default:
1936
+ dockerCmd = `docker ${command} ${extraArgs}`;
1937
+ }
1938
+ const output = execSync(dockerCmd, { encoding: 'utf8', timeout: 60000 });
1939
+ return {
1940
+ status: 'success',
1941
+ output: output.trim(),
1942
+ metadata: { command: dockerCmd },
1943
+ };
1944
+ }
1945
+ catch (err) {
1946
+ return {
1947
+ status: 'error',
1948
+ error: err instanceof Error ? err.message : String(err),
1949
+ };
1950
+ }
1951
+ },
1952
+ };
1953
+ // CSV processing tool
1954
+ const csvTool = {
1955
+ definition: {
1956
+ name: 'process_csv',
1957
+ description: 'Process CSV files - view, filter, convert to JSON, get statistics.',
1958
+ parameters: {
1959
+ type: 'object',
1960
+ properties: {
1961
+ file_path: {
1962
+ type: 'string',
1963
+ description: 'Path to CSV file',
1964
+ },
1965
+ action: {
1966
+ type: 'string',
1967
+ description: 'Action to perform',
1968
+ enum: ['view', 'head', 'stats', 'to_json'],
1969
+ },
1970
+ limit: {
1971
+ type: 'number',
1972
+ description: 'Number of rows to show (default: 10)',
1973
+ },
1974
+ },
1975
+ required: ['file_path', 'action'],
1976
+ },
1977
+ },
1978
+ handler: async (args) => {
1979
+ try {
1980
+ const filePath = String(args.file_path);
1981
+ const action = String(args.action);
1982
+ const limit = args.limit ? Number(args.limit) : 10;
1983
+ const content = await fs.readFile(filePath, 'utf8');
1984
+ const lines = content.split('\n').filter(l => l.trim());
1985
+ if (lines.length === 0) {
1986
+ return { status: 'error', error: 'Empty CSV file' };
1987
+ }
1988
+ const headers = lines[0].split(',').map(h => h.trim());
1989
+ switch (action) {
1990
+ case 'head':
1991
+ case 'view': {
1992
+ const rows = lines.slice(1, limit + 1).map(line => {
1993
+ const cells = line.split(',').map(c => c.trim());
1994
+ return cells.map((c, i) => `${headers[i]}: ${c}`).join(' | ');
1995
+ });
1996
+ return {
1997
+ status: 'success',
1998
+ output: `Headers: ${headers.join(', ')}\n\n${rows.join('\n')}`,
1999
+ metadata: { total_rows: lines.length - 1, shown: rows.length },
2000
+ };
2001
+ }
2002
+ case 'stats': {
2003
+ const colStats = {};
2004
+ headers.forEach(h => colStats[h] = { count: 0, unique: new Set(), numeric: [] });
2005
+ for (const line of lines.slice(1)) {
2006
+ const cells = line.split(',').map(c => c.trim());
2007
+ cells.forEach((cell, i) => {
2008
+ const h = headers[i];
2009
+ colStats[h].count++;
2010
+ colStats[h].unique.add(cell);
2011
+ const num = parseFloat(cell);
2012
+ if (!isNaN(num))
2013
+ colStats[h].numeric.push(num);
2014
+ });
2015
+ }
2016
+ const stats = headers.map(h => {
2017
+ const s = colStats[h];
2018
+ const numericInfo = s.numeric.length > 0
2019
+ ? ` | min: ${Math.min(...s.numeric)} | max: ${Math.max(...s.numeric)} | avg: ${(s.numeric.reduce((a, b) => a + b, 0) / s.numeric.length).toFixed(2)}`
2020
+ : '';
2021
+ return `${h}: ${s.count} rows, ${s.unique.size} unique${numericInfo}`;
2022
+ });
2023
+ return {
2024
+ status: 'success',
2025
+ output: stats.join('\n'),
2026
+ metadata: { columns: headers.length, rows: lines.length - 1 },
2027
+ };
2028
+ }
2029
+ case 'to_json': {
2030
+ const rows = lines.slice(1).map(line => {
2031
+ const cells = line.split(',').map(c => c.trim());
2032
+ const obj = {};
2033
+ headers.forEach((h, i) => obj[h] = cells[i] || '');
2034
+ return obj;
2035
+ });
2036
+ return {
2037
+ status: 'success',
2038
+ output: JSON.stringify(rows, null, 2),
2039
+ metadata: { rows: rows.length },
2040
+ };
2041
+ }
2042
+ default:
2043
+ return { status: 'error', error: `Unknown action: ${action}` };
2044
+ }
2045
+ }
2046
+ catch (err) {
2047
+ return {
2048
+ status: 'error',
2049
+ error: err instanceof Error ? err.message : String(err),
2050
+ };
2051
+ }
2052
+ },
2053
+ };
2054
+ // SQLite database tool
2055
+ const sqliteTool = {
2056
+ definition: {
2057
+ name: 'query_sqlite',
2058
+ description: 'Execute SQL queries on SQLite databases.',
2059
+ parameters: {
2060
+ type: 'object',
2061
+ properties: {
2062
+ database_path: {
2063
+ type: 'string',
2064
+ description: 'Path to SQLite database file',
2065
+ },
2066
+ query: {
2067
+ type: 'string',
2068
+ description: 'SQL query to execute',
2069
+ },
2070
+ },
2071
+ required: ['database_path', 'query'],
2072
+ },
2073
+ },
2074
+ handler: async (args) => {
2075
+ try {
2076
+ const dbPath = String(args.database_path);
2077
+ const query = String(args.query);
2078
+ const output = execSync(`sqlite3 "${dbPath}" "${query.replace(/"/g, '""')}"`, {
2079
+ encoding: 'utf8',
2080
+ timeout: 30000,
2081
+ });
2082
+ return {
2083
+ status: 'success',
2084
+ output: output.trim(),
2085
+ metadata: { database: dbPath, query },
2086
+ };
2087
+ }
2088
+ catch (err) {
2089
+ return {
2090
+ status: 'error',
2091
+ error: err instanceof Error ? err.message : String(err),
2092
+ };
2093
+ }
2094
+ },
2095
+ };
2096
+ // Export all tools
2097
+ export const tools = [
2098
+ // Core file/system tools
2099
+ readFileTool,
2100
+ writeFileTool,
2101
+ editFileTool,
2102
+ listDirTool,
2103
+ grepSearchTool,
2104
+ runCommandTool,
2105
+ findByNameTool,
2106
+ viewUrlTool,
2107
+ askUserTool,
2108
+ createMemoryTool,
2109
+ analyzeImageTool,
2110
+ embeddingTool,
2111
+ webSearchTool,
2112
+ browserTool,
2113
+ codeExecutionTool,
2114
+ semanticSearchTool,
2115
+ gitStatusTool,
2116
+ gitDiffTool,
2117
+ gitLogTool,
2118
+ httpRequestTool,
2119
+ parseJsonTool,
2120
+ jsonToYamlTool,
2121
+ diffFilesTool,
2122
+ createArchiveTool,
2123
+ extractArchiveTool,
2124
+ extractPdfTool,
2125
+ pingTool,
2126
+ checkPortTool,
2127
+ dockerTool,
2128
+ csvTool,
2129
+ sqliteTool,
2130
+ // API integrations
2131
+ ...slackTools,
2132
+ ...googleTools,
2133
+ ...githubTools,
2134
+ ...discordTools,
2135
+ ...telegramTools,
2136
+ ];
2137
+ // Create a map for quick lookup
2138
+ export const toolMap = new Map(tools.map(t => [t.definition.name, t]));
2139
+ //# sourceMappingURL=index.js.map