@useconductor/conductor 1.0.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 (504) hide show
  1. package/.claude-plugin/marketplace.json +33 -0
  2. package/.claude-plugin/plugin.json +23 -0
  3. package/.eslintrc.json +23 -0
  4. package/.gitattributes +6 -0
  5. package/.github/FUNDING.yml +15 -0
  6. package/.github/ISSUE_TEMPLATE/bug_report.yml +91 -0
  7. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  8. package/.github/ISSUE_TEMPLATE/feature_request.yml +63 -0
  9. package/.github/ISSUE_TEMPLATE/plugin_request.yml +71 -0
  10. package/.github/README.md +13 -0
  11. package/.github/workflows/README.md +22 -0
  12. package/.github/workflows/auto-release.yml +112 -0
  13. package/.github/workflows/ci.yml +49 -0
  14. package/.github/workflows/claude-code-review.yml +44 -0
  15. package/.github/workflows/claude.yml +36 -0
  16. package/.github/workflows/sync-install.yml +47 -0
  17. package/.mcp.json +9 -0
  18. package/.prettierrc.json +7 -0
  19. package/C.png +0 -0
  20. package/CHANGELOG.md +74 -0
  21. package/CLAUDE.md +118 -0
  22. package/CONTRIBUTING.md +231 -0
  23. package/LICENSE +201 -0
  24. package/README.md +179 -0
  25. package/SECURITY.md +47 -0
  26. package/commands/conductor-setup.md +11 -0
  27. package/commands/conductor-status.md +7 -0
  28. package/dist/ai/base.d.ts +44 -0
  29. package/dist/ai/base.d.ts.map +1 -0
  30. package/dist/ai/base.js +47 -0
  31. package/dist/ai/base.js.map +1 -0
  32. package/dist/ai/claude.d.ts +11 -0
  33. package/dist/ai/claude.d.ts.map +1 -0
  34. package/dist/ai/claude.js +149 -0
  35. package/dist/ai/claude.js.map +1 -0
  36. package/dist/ai/gemini.d.ts +15 -0
  37. package/dist/ai/gemini.d.ts.map +1 -0
  38. package/dist/ai/gemini.js +156 -0
  39. package/dist/ai/gemini.js.map +1 -0
  40. package/dist/ai/maestro.d.ts +22 -0
  41. package/dist/ai/maestro.d.ts.map +1 -0
  42. package/dist/ai/maestro.js +142 -0
  43. package/dist/ai/maestro.js.map +1 -0
  44. package/dist/ai/manager.d.ts +47 -0
  45. package/dist/ai/manager.d.ts.map +1 -0
  46. package/dist/ai/manager.js +450 -0
  47. package/dist/ai/manager.js.map +1 -0
  48. package/dist/ai/ollama.d.ts +16 -0
  49. package/dist/ai/ollama.d.ts.map +1 -0
  50. package/dist/ai/ollama.js +151 -0
  51. package/dist/ai/ollama.js.map +1 -0
  52. package/dist/ai/openai.d.ts +11 -0
  53. package/dist/ai/openai.d.ts.map +1 -0
  54. package/dist/ai/openai.js +132 -0
  55. package/dist/ai/openai.js.map +1 -0
  56. package/dist/ai/openrouter.d.ts +11 -0
  57. package/dist/ai/openrouter.d.ts.map +1 -0
  58. package/dist/ai/openrouter.js +139 -0
  59. package/dist/ai/openrouter.js.map +1 -0
  60. package/dist/bot/slack.d.ts +17 -0
  61. package/dist/bot/slack.d.ts.map +1 -0
  62. package/dist/bot/slack.js +144 -0
  63. package/dist/bot/slack.js.map +1 -0
  64. package/dist/bot/telegram.d.ts +19 -0
  65. package/dist/bot/telegram.d.ts.map +1 -0
  66. package/dist/bot/telegram.js +157 -0
  67. package/dist/bot/telegram.js.map +1 -0
  68. package/dist/cli/commands/ai.d.ts +4 -0
  69. package/dist/cli/commands/ai.d.ts.map +1 -0
  70. package/dist/cli/commands/ai.js +161 -0
  71. package/dist/cli/commands/ai.js.map +1 -0
  72. package/dist/cli/commands/doctor.d.ts +18 -0
  73. package/dist/cli/commands/doctor.d.ts.map +1 -0
  74. package/dist/cli/commands/doctor.js +213 -0
  75. package/dist/cli/commands/doctor.js.map +1 -0
  76. package/dist/cli/commands/init.d.ts +15 -0
  77. package/dist/cli/commands/init.d.ts.map +1 -0
  78. package/dist/cli/commands/init.js +281 -0
  79. package/dist/cli/commands/init.js.map +1 -0
  80. package/dist/cli/commands/install.d.ts +16 -0
  81. package/dist/cli/commands/install.d.ts.map +1 -0
  82. package/dist/cli/commands/install.js +750 -0
  83. package/dist/cli/commands/install.js.map +1 -0
  84. package/dist/cli/commands/lifecycle.d.ts +4 -0
  85. package/dist/cli/commands/lifecycle.d.ts.map +1 -0
  86. package/dist/cli/commands/lifecycle.js +84 -0
  87. package/dist/cli/commands/lifecycle.js.map +1 -0
  88. package/dist/cli/commands/marketplace.d.ts +13 -0
  89. package/dist/cli/commands/marketplace.d.ts.map +1 -0
  90. package/dist/cli/commands/marketplace.js +197 -0
  91. package/dist/cli/commands/marketplace.js.map +1 -0
  92. package/dist/cli/commands/mcp.d.ts +6 -0
  93. package/dist/cli/commands/mcp.d.ts.map +1 -0
  94. package/dist/cli/commands/mcp.js +83 -0
  95. package/dist/cli/commands/mcp.js.map +1 -0
  96. package/dist/cli/commands/onboard.d.ts +10 -0
  97. package/dist/cli/commands/onboard.d.ts.map +1 -0
  98. package/dist/cli/commands/onboard.js +207 -0
  99. package/dist/cli/commands/onboard.js.map +1 -0
  100. package/dist/cli/commands/plugin-create.d.ts +13 -0
  101. package/dist/cli/commands/plugin-create.d.ts.map +1 -0
  102. package/dist/cli/commands/plugin-create.js +122 -0
  103. package/dist/cli/commands/plugin-create.js.map +1 -0
  104. package/dist/cli/commands/plugins.d.ts +5 -0
  105. package/dist/cli/commands/plugins.d.ts.map +1 -0
  106. package/dist/cli/commands/plugins.js +30 -0
  107. package/dist/cli/commands/plugins.js.map +1 -0
  108. package/dist/cli/commands/release.d.ts +13 -0
  109. package/dist/cli/commands/release.d.ts.map +1 -0
  110. package/dist/cli/commands/release.js +243 -0
  111. package/dist/cli/commands/release.js.map +1 -0
  112. package/dist/cli/commands/telegram.d.ts +3 -0
  113. package/dist/cli/commands/telegram.d.ts.map +1 -0
  114. package/dist/cli/commands/telegram.js +20 -0
  115. package/dist/cli/commands/telegram.js.map +1 -0
  116. package/dist/cli/index.d.ts +3 -0
  117. package/dist/cli/index.d.ts.map +1 -0
  118. package/dist/cli/index.js +402 -0
  119. package/dist/cli/index.js.map +1 -0
  120. package/dist/config/oauth.d.ts +8 -0
  121. package/dist/config/oauth.d.ts.map +1 -0
  122. package/dist/config/oauth.js +13 -0
  123. package/dist/config/oauth.js.map +1 -0
  124. package/dist/core/audit.d.ts +91 -0
  125. package/dist/core/audit.d.ts.map +1 -0
  126. package/dist/core/audit.js +233 -0
  127. package/dist/core/audit.js.map +1 -0
  128. package/dist/core/circuit-breaker.d.ts +56 -0
  129. package/dist/core/circuit-breaker.d.ts.map +1 -0
  130. package/dist/core/circuit-breaker.js +107 -0
  131. package/dist/core/circuit-breaker.js.map +1 -0
  132. package/dist/core/conductor.d.ts +44 -0
  133. package/dist/core/conductor.d.ts.map +1 -0
  134. package/dist/core/conductor.js +200 -0
  135. package/dist/core/conductor.js.map +1 -0
  136. package/dist/core/config.d.ts +66 -0
  137. package/dist/core/config.d.ts.map +1 -0
  138. package/dist/core/config.js +86 -0
  139. package/dist/core/config.js.map +1 -0
  140. package/dist/core/database.d.ts +59 -0
  141. package/dist/core/database.d.ts.map +1 -0
  142. package/dist/core/database.js +342 -0
  143. package/dist/core/database.js.map +1 -0
  144. package/dist/core/errors.d.ts +231 -0
  145. package/dist/core/errors.d.ts.map +1 -0
  146. package/dist/core/errors.js +254 -0
  147. package/dist/core/errors.js.map +1 -0
  148. package/dist/core/health.d.ts +72 -0
  149. package/dist/core/health.d.ts.map +1 -0
  150. package/dist/core/health.js +116 -0
  151. package/dist/core/health.js.map +1 -0
  152. package/dist/core/interfaces.d.ts +62 -0
  153. package/dist/core/interfaces.d.ts.map +1 -0
  154. package/dist/core/interfaces.js +8 -0
  155. package/dist/core/interfaces.js.map +1 -0
  156. package/dist/core/logger.d.ts +15 -0
  157. package/dist/core/logger.d.ts.map +1 -0
  158. package/dist/core/logger.js +30 -0
  159. package/dist/core/logger.js.map +1 -0
  160. package/dist/core/rbac.d.ts +132 -0
  161. package/dist/core/rbac.d.ts.map +1 -0
  162. package/dist/core/rbac.js +230 -0
  163. package/dist/core/rbac.js.map +1 -0
  164. package/dist/core/retry.d.ts +22 -0
  165. package/dist/core/retry.d.ts.map +1 -0
  166. package/dist/core/retry.js +41 -0
  167. package/dist/core/retry.js.map +1 -0
  168. package/dist/core/webhooks.d.ts +92 -0
  169. package/dist/core/webhooks.d.ts.map +1 -0
  170. package/dist/core/webhooks.js +176 -0
  171. package/dist/core/webhooks.js.map +1 -0
  172. package/dist/core/zero-config.d.ts +22 -0
  173. package/dist/core/zero-config.d.ts.map +1 -0
  174. package/dist/core/zero-config.js +59 -0
  175. package/dist/core/zero-config.js.map +1 -0
  176. package/dist/dashboard/cli.d.ts +6 -0
  177. package/dist/dashboard/cli.d.ts.map +1 -0
  178. package/dist/dashboard/cli.js +42 -0
  179. package/dist/dashboard/cli.js.map +1 -0
  180. package/dist/dashboard/index.html +3426 -0
  181. package/dist/dashboard/server.d.ts +7 -0
  182. package/dist/dashboard/server.d.ts.map +1 -0
  183. package/dist/dashboard/server.js +1427 -0
  184. package/dist/dashboard/server.js.map +1 -0
  185. package/dist/mcp/server.d.ts +27 -0
  186. package/dist/mcp/server.d.ts.map +1 -0
  187. package/dist/mcp/server.js +380 -0
  188. package/dist/mcp/server.js.map +1 -0
  189. package/dist/mcp/tools/misc.d.ts +15 -0
  190. package/dist/mcp/tools/misc.d.ts.map +1 -0
  191. package/dist/mcp/tools/misc.js +49 -0
  192. package/dist/mcp/tools/misc.js.map +1 -0
  193. package/dist/plugins/builtin/calculator.d.ts +11 -0
  194. package/dist/plugins/builtin/calculator.d.ts.map +1 -0
  195. package/dist/plugins/builtin/calculator.js +166 -0
  196. package/dist/plugins/builtin/calculator.js.map +1 -0
  197. package/dist/plugins/builtin/colors.d.ts +15 -0
  198. package/dist/plugins/builtin/colors.d.ts.map +1 -0
  199. package/dist/plugins/builtin/colors.js +193 -0
  200. package/dist/plugins/builtin/colors.js.map +1 -0
  201. package/dist/plugins/builtin/cron.d.ts +40 -0
  202. package/dist/plugins/builtin/cron.d.ts.map +1 -0
  203. package/dist/plugins/builtin/cron.js +578 -0
  204. package/dist/plugins/builtin/cron.js.map +1 -0
  205. package/dist/plugins/builtin/crypto.d.ts +11 -0
  206. package/dist/plugins/builtin/crypto.d.ts.map +1 -0
  207. package/dist/plugins/builtin/crypto.js +83 -0
  208. package/dist/plugins/builtin/crypto.js.map +1 -0
  209. package/dist/plugins/builtin/database.d.ts +29 -0
  210. package/dist/plugins/builtin/database.d.ts.map +1 -0
  211. package/dist/plugins/builtin/database.js +230 -0
  212. package/dist/plugins/builtin/database.js.map +1 -0
  213. package/dist/plugins/builtin/docker.d.ts +12 -0
  214. package/dist/plugins/builtin/docker.d.ts.map +1 -0
  215. package/dist/plugins/builtin/docker.js +436 -0
  216. package/dist/plugins/builtin/docker.js.map +1 -0
  217. package/dist/plugins/builtin/fun.d.ts +11 -0
  218. package/dist/plugins/builtin/fun.d.ts.map +1 -0
  219. package/dist/plugins/builtin/fun.js +114 -0
  220. package/dist/plugins/builtin/fun.js.map +1 -0
  221. package/dist/plugins/builtin/gcal.d.ts +38 -0
  222. package/dist/plugins/builtin/gcal.d.ts.map +1 -0
  223. package/dist/plugins/builtin/gcal.js +280 -0
  224. package/dist/plugins/builtin/gcal.js.map +1 -0
  225. package/dist/plugins/builtin/gdrive.d.ts +26 -0
  226. package/dist/plugins/builtin/gdrive.d.ts.map +1 -0
  227. package/dist/plugins/builtin/gdrive.js +295 -0
  228. package/dist/plugins/builtin/gdrive.js.map +1 -0
  229. package/dist/plugins/builtin/github-actions.d.ts +38 -0
  230. package/dist/plugins/builtin/github-actions.d.ts.map +1 -0
  231. package/dist/plugins/builtin/github-actions.js +629 -0
  232. package/dist/plugins/builtin/github-actions.js.map +1 -0
  233. package/dist/plugins/builtin/github.d.ts +26 -0
  234. package/dist/plugins/builtin/github.d.ts.map +1 -0
  235. package/dist/plugins/builtin/github.js +800 -0
  236. package/dist/plugins/builtin/github.js.map +1 -0
  237. package/dist/plugins/builtin/gmail.d.ts +50 -0
  238. package/dist/plugins/builtin/gmail.d.ts.map +1 -0
  239. package/dist/plugins/builtin/gmail.js +445 -0
  240. package/dist/plugins/builtin/gmail.js.map +1 -0
  241. package/dist/plugins/builtin/hash.d.ts +11 -0
  242. package/dist/plugins/builtin/hash.d.ts.map +1 -0
  243. package/dist/plugins/builtin/hash.js +95 -0
  244. package/dist/plugins/builtin/hash.js.map +1 -0
  245. package/dist/plugins/builtin/homekit.d.ts +53 -0
  246. package/dist/plugins/builtin/homekit.d.ts.map +1 -0
  247. package/dist/plugins/builtin/homekit.js +341 -0
  248. package/dist/plugins/builtin/homekit.js.map +1 -0
  249. package/dist/plugins/builtin/index.d.ts +4 -0
  250. package/dist/plugins/builtin/index.d.ts.map +1 -0
  251. package/dist/plugins/builtin/index.js +96 -0
  252. package/dist/plugins/builtin/index.js.map +1 -0
  253. package/dist/plugins/builtin/jira.d.ts +50 -0
  254. package/dist/plugins/builtin/jira.d.ts.map +1 -0
  255. package/dist/plugins/builtin/jira.js +353 -0
  256. package/dist/plugins/builtin/jira.js.map +1 -0
  257. package/dist/plugins/builtin/linear.d.ts +35 -0
  258. package/dist/plugins/builtin/linear.d.ts.map +1 -0
  259. package/dist/plugins/builtin/linear.js +397 -0
  260. package/dist/plugins/builtin/linear.js.map +1 -0
  261. package/dist/plugins/builtin/lumen.d.ts +21 -0
  262. package/dist/plugins/builtin/lumen.d.ts.map +1 -0
  263. package/dist/plugins/builtin/lumen.js +404 -0
  264. package/dist/plugins/builtin/lumen.js.map +1 -0
  265. package/dist/plugins/builtin/memory.d.ts +22 -0
  266. package/dist/plugins/builtin/memory.d.ts.map +1 -0
  267. package/dist/plugins/builtin/memory.js +184 -0
  268. package/dist/plugins/builtin/memory.js.map +1 -0
  269. package/dist/plugins/builtin/n8n.d.ts +60 -0
  270. package/dist/plugins/builtin/n8n.d.ts.map +1 -0
  271. package/dist/plugins/builtin/n8n.js +519 -0
  272. package/dist/plugins/builtin/n8n.js.map +1 -0
  273. package/dist/plugins/builtin/network.d.ts +11 -0
  274. package/dist/plugins/builtin/network.d.ts.map +1 -0
  275. package/dist/plugins/builtin/network.js +88 -0
  276. package/dist/plugins/builtin/network.js.map +1 -0
  277. package/dist/plugins/builtin/notes.d.ts +47 -0
  278. package/dist/plugins/builtin/notes.d.ts.map +1 -0
  279. package/dist/plugins/builtin/notes.js +641 -0
  280. package/dist/plugins/builtin/notes.js.map +1 -0
  281. package/dist/plugins/builtin/notion.d.ts +47 -0
  282. package/dist/plugins/builtin/notion.d.ts.map +1 -0
  283. package/dist/plugins/builtin/notion.js +317 -0
  284. package/dist/plugins/builtin/notion.js.map +1 -0
  285. package/dist/plugins/builtin/shell.d.ts +12 -0
  286. package/dist/plugins/builtin/shell.d.ts.map +1 -0
  287. package/dist/plugins/builtin/shell.js +310 -0
  288. package/dist/plugins/builtin/shell.js.map +1 -0
  289. package/dist/plugins/builtin/slack.d.ts +31 -0
  290. package/dist/plugins/builtin/slack.d.ts.map +1 -0
  291. package/dist/plugins/builtin/slack.js +295 -0
  292. package/dist/plugins/builtin/slack.js.map +1 -0
  293. package/dist/plugins/builtin/spotify.d.ts +55 -0
  294. package/dist/plugins/builtin/spotify.d.ts.map +1 -0
  295. package/dist/plugins/builtin/spotify.js +623 -0
  296. package/dist/plugins/builtin/spotify.js.map +1 -0
  297. package/dist/plugins/builtin/stripe.d.ts +35 -0
  298. package/dist/plugins/builtin/stripe.d.ts.map +1 -0
  299. package/dist/plugins/builtin/stripe.js +376 -0
  300. package/dist/plugins/builtin/stripe.js.map +1 -0
  301. package/dist/plugins/builtin/system.d.ts +11 -0
  302. package/dist/plugins/builtin/system.d.ts.map +1 -0
  303. package/dist/plugins/builtin/system.js +91 -0
  304. package/dist/plugins/builtin/system.js.map +1 -0
  305. package/dist/plugins/builtin/text-tools.d.ts +11 -0
  306. package/dist/plugins/builtin/text-tools.d.ts.map +1 -0
  307. package/dist/plugins/builtin/text-tools.js +146 -0
  308. package/dist/plugins/builtin/text-tools.js.map +1 -0
  309. package/dist/plugins/builtin/timezone.d.ts +13 -0
  310. package/dist/plugins/builtin/timezone.d.ts.map +1 -0
  311. package/dist/plugins/builtin/timezone.js +164 -0
  312. package/dist/plugins/builtin/timezone.js.map +1 -0
  313. package/dist/plugins/builtin/todoist.d.ts +49 -0
  314. package/dist/plugins/builtin/todoist.d.ts.map +1 -0
  315. package/dist/plugins/builtin/todoist.js +540 -0
  316. package/dist/plugins/builtin/todoist.js.map +1 -0
  317. package/dist/plugins/builtin/translate.d.ts +11 -0
  318. package/dist/plugins/builtin/translate.d.ts.map +1 -0
  319. package/dist/plugins/builtin/translate.js +42 -0
  320. package/dist/plugins/builtin/translate.js.map +1 -0
  321. package/dist/plugins/builtin/url-tools.d.ts +11 -0
  322. package/dist/plugins/builtin/url-tools.d.ts.map +1 -0
  323. package/dist/plugins/builtin/url-tools.js +70 -0
  324. package/dist/plugins/builtin/url-tools.js.map +1 -0
  325. package/dist/plugins/builtin/vercel.d.ts +55 -0
  326. package/dist/plugins/builtin/vercel.d.ts.map +1 -0
  327. package/dist/plugins/builtin/vercel.js +514 -0
  328. package/dist/plugins/builtin/vercel.js.map +1 -0
  329. package/dist/plugins/builtin/weather.d.ts +13 -0
  330. package/dist/plugins/builtin/weather.d.ts.map +1 -0
  331. package/dist/plugins/builtin/weather.js +103 -0
  332. package/dist/plugins/builtin/weather.js.map +1 -0
  333. package/dist/plugins/builtin/x.d.ts +54 -0
  334. package/dist/plugins/builtin/x.d.ts.map +1 -0
  335. package/dist/plugins/builtin/x.js +402 -0
  336. package/dist/plugins/builtin/x.js.map +1 -0
  337. package/dist/plugins/manager.d.ts +77 -0
  338. package/dist/plugins/manager.d.ts.map +1 -0
  339. package/dist/plugins/manager.js +141 -0
  340. package/dist/plugins/manager.js.map +1 -0
  341. package/dist/plugins/validation.d.ts +18 -0
  342. package/dist/plugins/validation.d.ts.map +1 -0
  343. package/dist/plugins/validation.js +81 -0
  344. package/dist/plugins/validation.js.map +1 -0
  345. package/dist/security/auth.d.ts +23 -0
  346. package/dist/security/auth.d.ts.map +1 -0
  347. package/dist/security/auth.js +56 -0
  348. package/dist/security/auth.js.map +1 -0
  349. package/dist/security/keychain.d.ts +60 -0
  350. package/dist/security/keychain.d.ts.map +1 -0
  351. package/dist/security/keychain.js +213 -0
  352. package/dist/security/keychain.js.map +1 -0
  353. package/dist/utils/google-auth.d.ts +21 -0
  354. package/dist/utils/google-auth.d.ts.map +1 -0
  355. package/dist/utils/google-auth.js +135 -0
  356. package/dist/utils/google-auth.js.map +1 -0
  357. package/dist/utils/retry.d.ts +5 -0
  358. package/dist/utils/retry.d.ts.map +1 -0
  359. package/dist/utils/retry.js +34 -0
  360. package/dist/utils/retry.js.map +1 -0
  361. package/docs/README.md +13 -0
  362. package/docs/api.md +210 -0
  363. package/docs/getting-started.md +100 -0
  364. package/docs/plugins.md +306 -0
  365. package/docs-site/.vitepress/config.ts +59 -0
  366. package/docs-site/README.md +12 -0
  367. package/docs-site/index.md +30 -0
  368. package/eslint.config.js +29 -0
  369. package/install.ps1 +334 -0
  370. package/install.sh +1119 -0
  371. package/local-install.sh +304 -0
  372. package/package.json +90 -0
  373. package/packages/README.md +11 -0
  374. package/packages/plugin-sdk/README.md +12 -0
  375. package/packages/plugin-sdk/package.json +22 -0
  376. package/packages/plugin-sdk/src/README.md +11 -0
  377. package/packages/plugin-sdk/src/index.ts +191 -0
  378. package/sdks/README.md +26 -0
  379. package/sdks/csharp/ConductorClient.cs +65 -0
  380. package/sdks/csharp/README.md +11 -0
  381. package/sdks/go/README.md +11 -0
  382. package/sdks/go/conductor.go +257 -0
  383. package/sdks/java/ConductorClient.java +27 -0
  384. package/sdks/java/README.md +11 -0
  385. package/sdks/php/README.md +11 -0
  386. package/sdks/php/src/Client.php +72 -0
  387. package/sdks/python/README.md +12 -0
  388. package/sdks/python/conductor/__init__.py +227 -0
  389. package/sdks/python/pyproject.toml +30 -0
  390. package/sdks/ruby/README.md +11 -0
  391. package/sdks/ruby/lib/conductor.rb +46 -0
  392. package/sdks/rust/Cargo.toml +14 -0
  393. package/sdks/rust/README.md +11 -0
  394. package/sdks/swift/README.md +11 -0
  395. package/sdks/swift/Sources/Conductor/ConductorClient.swift +65 -0
  396. package/skills/conductor-mcp/SKILL.md +38 -0
  397. package/src/README.md +20 -0
  398. package/src/ai/README.md +18 -0
  399. package/src/ai/base.ts +93 -0
  400. package/src/ai/claude.ts +162 -0
  401. package/src/ai/gemini.ts +188 -0
  402. package/src/ai/maestro.ts +168 -0
  403. package/src/ai/manager.ts +537 -0
  404. package/src/ai/ollama.ts +186 -0
  405. package/src/ai/openai.ts +147 -0
  406. package/src/ai/openrouter.ts +152 -0
  407. package/src/bot/README.md +12 -0
  408. package/src/bot/slack.ts +164 -0
  409. package/src/bot/telegram.ts +185 -0
  410. package/src/cli/README.md +24 -0
  411. package/src/cli/commands/README.md +20 -0
  412. package/src/cli/commands/ai.ts +170 -0
  413. package/src/cli/commands/doctor.ts +221 -0
  414. package/src/cli/commands/init.ts +348 -0
  415. package/src/cli/commands/install.ts +792 -0
  416. package/src/cli/commands/lifecycle.ts +95 -0
  417. package/src/cli/commands/marketplace.ts +253 -0
  418. package/src/cli/commands/mcp.ts +92 -0
  419. package/src/cli/commands/onboard.ts +248 -0
  420. package/src/cli/commands/plugin-create.ts +130 -0
  421. package/src/cli/commands/plugins.ts +36 -0
  422. package/src/cli/commands/release.ts +251 -0
  423. package/src/cli/commands/telegram.ts +25 -0
  424. package/src/cli/index.ts +450 -0
  425. package/src/config/README.md +11 -0
  426. package/src/config/oauth.ts +26 -0
  427. package/src/core/README.md +22 -0
  428. package/src/core/audit.ts +291 -0
  429. package/src/core/circuit-breaker.ts +129 -0
  430. package/src/core/conductor.ts +240 -0
  431. package/src/core/config.ts +149 -0
  432. package/src/core/database.ts +411 -0
  433. package/src/core/errors.ts +275 -0
  434. package/src/core/health.ts +159 -0
  435. package/src/core/interfaces.ts +75 -0
  436. package/src/core/logger.ts +33 -0
  437. package/src/core/rbac.ts +321 -0
  438. package/src/core/retry.ts +61 -0
  439. package/src/core/webhooks.ts +234 -0
  440. package/src/core/zero-config.ts +72 -0
  441. package/src/dashboard/README.md +15 -0
  442. package/src/dashboard/cli.ts +48 -0
  443. package/src/dashboard/index.html +3426 -0
  444. package/src/dashboard/server.ts +1544 -0
  445. package/src/mcp/README.md +20 -0
  446. package/src/mcp/server.ts +475 -0
  447. package/src/mcp/tools/README.md +11 -0
  448. package/src/mcp/tools/misc.ts +61 -0
  449. package/src/plugins/README.md +28 -0
  450. package/src/plugins/builtin/README.md +23 -0
  451. package/src/plugins/builtin/calculator.ts +178 -0
  452. package/src/plugins/builtin/colors.ts +201 -0
  453. package/src/plugins/builtin/cron.ts +649 -0
  454. package/src/plugins/builtin/crypto.ts +85 -0
  455. package/src/plugins/builtin/database.ts +235 -0
  456. package/src/plugins/builtin/docker.ts +426 -0
  457. package/src/plugins/builtin/fun.ts +118 -0
  458. package/src/plugins/builtin/gcal.ts +305 -0
  459. package/src/plugins/builtin/gdrive.ts +326 -0
  460. package/src/plugins/builtin/github-actions.ts +666 -0
  461. package/src/plugins/builtin/github.ts +912 -0
  462. package/src/plugins/builtin/gmail.ts +492 -0
  463. package/src/plugins/builtin/hash.ts +98 -0
  464. package/src/plugins/builtin/homekit.ts +389 -0
  465. package/src/plugins/builtin/index.ts +116 -0
  466. package/src/plugins/builtin/jira.ts +380 -0
  467. package/src/plugins/builtin/linear.ts +448 -0
  468. package/src/plugins/builtin/lumen.ts +497 -0
  469. package/src/plugins/builtin/memory.ts +200 -0
  470. package/src/plugins/builtin/n8n.ts +565 -0
  471. package/src/plugins/builtin/network.ts +92 -0
  472. package/src/plugins/builtin/notes.ts +689 -0
  473. package/src/plugins/builtin/notion.ts +348 -0
  474. package/src/plugins/builtin/shell.ts +334 -0
  475. package/src/plugins/builtin/slack.ts +327 -0
  476. package/src/plugins/builtin/spotify.ts +665 -0
  477. package/src/plugins/builtin/stripe.ts +388 -0
  478. package/src/plugins/builtin/system.ts +93 -0
  479. package/src/plugins/builtin/text-tools.ts +150 -0
  480. package/src/plugins/builtin/timezone.ts +173 -0
  481. package/src/plugins/builtin/todoist.ts +625 -0
  482. package/src/plugins/builtin/translate.ts +47 -0
  483. package/src/plugins/builtin/url-tools.ts +73 -0
  484. package/src/plugins/builtin/vercel.ts +546 -0
  485. package/src/plugins/builtin/weather.ts +112 -0
  486. package/src/plugins/builtin/x.ts +440 -0
  487. package/src/plugins/manager.ts +213 -0
  488. package/src/plugins/validation.ts +94 -0
  489. package/src/security/README.md +12 -0
  490. package/src/security/auth.ts +72 -0
  491. package/src/security/keychain.ts +226 -0
  492. package/src/utils/README.md +12 -0
  493. package/src/utils/google-auth.ts +159 -0
  494. package/src/utils/retry.ts +41 -0
  495. package/test-all.mjs +1256 -0
  496. package/test.mjs +633 -0
  497. package/tests/README.md +19 -0
  498. package/tests/calculator.test.ts +54 -0
  499. package/tests/docker.test.ts +42 -0
  500. package/tests/load.test.ts +129 -0
  501. package/tests/mcp.test.ts +14 -0
  502. package/tests/shell.test.ts +42 -0
  503. package/tsconfig.json +21 -0
  504. package/vitest.config.ts +14 -0
@@ -0,0 +1,348 @@
1
+ /**
2
+ * Notion Plugin
3
+ *
4
+ * Search, read, and create pages and databases in Notion.
5
+ * Requires a Notion Integration API key.
6
+ *
7
+ * Setup:
8
+ * 1. Go to https://www.notion.so/my-integrations and create an integration
9
+ * 2. Copy the "Internal Integration Token" (starts with ntn_)
10
+ * 3. Share each workspace page/db you want to access with your integration
11
+ * 4. Run: conductor plugins config notion token <YOUR_TOKEN>
12
+ * OR set it during install when prompted
13
+ *
14
+ * Stored in keychain as: notion / api_key
15
+ */
16
+
17
+ import { Plugin, PluginTool } from '../manager.js';
18
+ import { Conductor } from '../../core/conductor.js';
19
+ import { Keychain } from '../../security/keychain.js';
20
+
21
+ const NOTION_BASE = 'https://api.notion.com/v1';
22
+ const NOTION_VERSION = '2022-06-28';
23
+
24
+ export class NotionPlugin implements Plugin {
25
+ name = 'notion';
26
+ description = 'Read, search, and create Notion pages and databases — requires Notion API key';
27
+ version = '1.0.0';
28
+
29
+ configSchema = {
30
+ fields: [
31
+ {
32
+ key: 'api_key',
33
+ label: 'Internal Integration Token',
34
+ type: 'password' as const,
35
+ required: true,
36
+ secret: true,
37
+ service: 'notion',
38
+ description: 'Copy your token (starts with ntn_) from Notion Developer portal.',
39
+ },
40
+ ],
41
+ setupInstructions:
42
+ '1. Visit Notion Settings > My integrations. 2. Create a new "Internal Integration". 3. Copy the token. 4. Ensure you "Connect" the integration to the pages you want Conductor to access.',
43
+ };
44
+
45
+ private keychain!: Keychain;
46
+
47
+ async initialize(conductor: Conductor): Promise<void> {
48
+ this.keychain = new Keychain(conductor.getConfig().getConfigDir());
49
+ }
50
+
51
+ isConfigured(): boolean {
52
+ return true;
53
+ }
54
+
55
+ private async getToken(): Promise<string> {
56
+ const token = await this.keychain.get('notion', 'api_key');
57
+ if (!token) {
58
+ throw new Error(
59
+ 'Notion not configured. Get your integration token from https://www.notion.so/my-integrations\n' +
60
+ 'Then run: conductor plugins config notion token <YOUR_TOKEN>',
61
+ );
62
+ }
63
+ return token;
64
+ }
65
+
66
+ private async notionFetch(
67
+ path: string,
68
+ options: {
69
+ method?: string;
70
+ body?: any;
71
+ } = {},
72
+ ): Promise<any> {
73
+ const token = await this.getToken();
74
+ const res = await fetch(`${NOTION_BASE}${path}`, {
75
+ method: options.method ?? 'GET',
76
+ headers: {
77
+ Authorization: `Bearer ${token}`,
78
+ 'Content-Type': 'application/json',
79
+ 'Notion-Version': NOTION_VERSION,
80
+ },
81
+ body: options.body ? JSON.stringify(options.body) : undefined,
82
+ });
83
+ if (!res.ok) {
84
+ const err = (await res.json().catch(() => ({ message: res.statusText }))) as any;
85
+ throw new Error(`Notion API ${res.status}: ${err.message ?? res.statusText}`);
86
+ }
87
+ return res.json();
88
+ }
89
+
90
+ /** Extract plain text from Notion rich_text blocks */
91
+ private richText(blocks: any[]): string {
92
+ return (blocks ?? []).map((b: any) => b.plain_text ?? '').join('');
93
+ }
94
+
95
+ /** Extract plain text from a block's content */
96
+ private blockText(block: any): string {
97
+ const type = block.type;
98
+ const content = block[type];
99
+ if (!content) return '';
100
+ if (content.rich_text) return this.richText(content.rich_text);
101
+ return '';
102
+ }
103
+
104
+ /** Format a page for clean output */
105
+ private formatPage(page: any) {
106
+ const props = page.properties ?? {};
107
+ const titleProp: any = props.title ?? props.Name ?? Object.values(props).find((p: any) => p.type === 'title') ?? {};
108
+ const title = this.richText(titleProp.title ?? []);
109
+ return {
110
+ id: page.id,
111
+ title: title || '(Untitled)',
112
+ url: page.url ?? '',
113
+ createdTime: page.created_time ?? '',
114
+ lastEditedTime: page.last_edited_time ?? '',
115
+ archived: page.archived ?? false,
116
+ parent:
117
+ page.parent?.type === 'database_id'
118
+ ? { type: 'database', id: page.parent.database_id }
119
+ : page.parent?.type === 'page_id'
120
+ ? { type: 'page', id: page.parent.page_id }
121
+ : { type: 'workspace' },
122
+ };
123
+ }
124
+
125
+ getTools(): PluginTool[] {
126
+ return [
127
+ // ── notion_search ───────────────────────────────────────────────────────
128
+ {
129
+ name: 'notion_search',
130
+ description: 'Search Notion pages and databases by title',
131
+ inputSchema: {
132
+ type: 'object',
133
+ properties: {
134
+ query: { type: 'string', description: 'Search term' },
135
+ filter: {
136
+ type: 'string',
137
+ enum: ['page', 'database'],
138
+ description: 'Filter to only pages or only databases',
139
+ },
140
+ maxResults: { type: 'number', description: 'Max results (default: 10)' },
141
+ },
142
+ required: ['query'],
143
+ },
144
+ handler: async ({ query, filter, maxResults = 10 }: any) => {
145
+ const body: any = { query, page_size: Math.min(maxResults, 100) };
146
+ if (filter) body.filter = { value: filter, property: 'object' };
147
+
148
+ const res = await this.notionFetch('/search', { method: 'POST', body });
149
+ return {
150
+ count: res.results?.length ?? 0,
151
+ results: (res.results ?? []).map((r: any) => ({
152
+ ...this.formatPage(r),
153
+ type: r.object,
154
+ })),
155
+ };
156
+ },
157
+ },
158
+
159
+ // ── notion_get_page ─────────────────────────────────────────────────────
160
+ {
161
+ name: 'notion_get_page',
162
+ description: 'Get metadata and properties of a Notion page',
163
+ inputSchema: {
164
+ type: 'object',
165
+ properties: {
166
+ pageId: {
167
+ type: 'string',
168
+ description: 'Notion page ID or URL',
169
+ },
170
+ },
171
+ required: ['pageId'],
172
+ },
173
+ handler: async ({ pageId }: any) => {
174
+ // Accept full URLs — extract ID from them
175
+ const id = pageId.includes('notion.so')
176
+ ? (pageId.split('/').pop()?.split('?')[0]?.replace(/-/g, '').slice(-32) ?? pageId)
177
+ : pageId;
178
+ const page = await this.notionFetch(`/pages/${id}`);
179
+ return this.formatPage(page);
180
+ },
181
+ },
182
+
183
+ // ── notion_read_page ────────────────────────────────────────────────────
184
+ {
185
+ name: 'notion_read_page',
186
+ description: 'Read the full text content of a Notion page (blocks)',
187
+ inputSchema: {
188
+ type: 'object',
189
+ properties: {
190
+ pageId: { type: 'string', description: 'Notion page ID or URL' },
191
+ maxChars: { type: 'number', description: 'Max characters (default: 8000)' },
192
+ },
193
+ required: ['pageId'],
194
+ },
195
+ handler: async ({ pageId, maxChars = 8000 }: any) => {
196
+ const id = pageId.includes('notion.so')
197
+ ? (pageId.split('/').pop()?.split('?')[0]?.replace(/-/g, '').slice(-32) ?? pageId)
198
+ : pageId;
199
+
200
+ const [page, blocks] = await Promise.all([
201
+ this.notionFetch(`/pages/${id}`),
202
+ this.notionFetch(`/blocks/${id}/children?page_size=100`),
203
+ ]);
204
+
205
+ const lines = (blocks.results ?? [])
206
+ .map((b: any) => {
207
+ const text = this.blockText(b);
208
+ const type = b.type;
209
+ if (type === 'heading_1') return `# ${text}`;
210
+ if (type === 'heading_2') return `## ${text}`;
211
+ if (type === 'heading_3') return `### ${text}`;
212
+ if (type === 'bulleted_list_item') return `• ${text}`;
213
+ if (type === 'numbered_list_item') return `1. ${text}`;
214
+ if (type === 'to_do') return `[${b.to_do?.checked ? 'x' : ' '}] ${text}`;
215
+ if (type === 'divider') return '---';
216
+ if (type === 'code')
217
+ return `\`\`\`${b.code?.language ?? ''}\n${this.richText(b.code?.rich_text ?? [])}\n\`\`\``;
218
+ return text;
219
+ })
220
+ .filter(Boolean)
221
+ .join('\n');
222
+
223
+ return {
224
+ ...this.formatPage(page),
225
+ content: lines.slice(0, maxChars),
226
+ truncated: lines.length > maxChars,
227
+ blockCount: blocks.results?.length ?? 0,
228
+ };
229
+ },
230
+ },
231
+
232
+ // ── notion_create_page ──────────────────────────────────────────────────
233
+ {
234
+ name: 'notion_create_page',
235
+ description: 'Create a new Notion page',
236
+ inputSchema: {
237
+ type: 'object',
238
+ properties: {
239
+ title: { type: 'string', description: 'Page title' },
240
+ content: { type: 'string', description: 'Plain text content for the page body' },
241
+ parentPageId: {
242
+ type: 'string',
243
+ description: 'Parent page ID — page will be created as a child',
244
+ },
245
+ parentDatabaseId: {
246
+ type: 'string',
247
+ description: 'Parent database ID — page will be created as a database entry',
248
+ },
249
+ },
250
+ required: ['title'],
251
+ },
252
+ handler: async ({ title, content, parentPageId, parentDatabaseId }: any) => {
253
+ if (!parentPageId && !parentDatabaseId) {
254
+ throw new Error('Provide either parentPageId or parentDatabaseId.');
255
+ }
256
+
257
+ const parent = parentDatabaseId ? { database_id: parentDatabaseId } : { page_id: parentPageId };
258
+
259
+ const titleProp = parentDatabaseId
260
+ ? { Name: { title: [{ text: { content: title } }] } }
261
+ : { title: { title: [{ text: { content: title } }] } };
262
+
263
+ const children = content
264
+ ? content
265
+ .split('\n')
266
+ .filter(Boolean)
267
+ .map((line: string) => ({
268
+ object: 'block',
269
+ type: 'paragraph',
270
+ paragraph: { rich_text: [{ text: { content: line } }] },
271
+ }))
272
+ : [];
273
+
274
+ const page = await this.notionFetch('/pages', {
275
+ method: 'POST',
276
+ body: { parent, properties: titleProp, children },
277
+ });
278
+
279
+ return { created: true, ...this.formatPage(page) };
280
+ },
281
+ },
282
+
283
+ // ── notion_append_to_page ───────────────────────────────────────────────
284
+ {
285
+ name: 'notion_append_to_page',
286
+ description: 'Append text content to the end of an existing Notion page',
287
+ inputSchema: {
288
+ type: 'object',
289
+ properties: {
290
+ pageId: { type: 'string', description: 'Page ID to append to' },
291
+ content: { type: 'string', description: 'Text to append' },
292
+ },
293
+ required: ['pageId', 'content'],
294
+ },
295
+ handler: async ({ pageId, content }: any) => {
296
+ const children = content
297
+ .split('\n')
298
+ .filter(Boolean)
299
+ .map((line: string) => ({
300
+ object: 'block',
301
+ type: 'paragraph',
302
+ paragraph: { rich_text: [{ text: { content: line } }] },
303
+ }));
304
+
305
+ await this.notionFetch(`/blocks/${pageId}/children`, {
306
+ method: 'PATCH',
307
+ body: { children },
308
+ });
309
+
310
+ return { appended: true, pageId, linesAdded: children.length };
311
+ },
312
+ },
313
+
314
+ // ── notion_query_database ───────────────────────────────────────────────
315
+ {
316
+ name: 'notion_query_database',
317
+ description: 'Query a Notion database and return its entries',
318
+ inputSchema: {
319
+ type: 'object',
320
+ properties: {
321
+ databaseId: { type: 'string', description: 'Database ID' },
322
+ maxResults: { type: 'number', description: 'Max entries to return (default: 20)' },
323
+ filter: {
324
+ type: 'object',
325
+ description: 'Notion filter object (optional)',
326
+ },
327
+ },
328
+ required: ['databaseId'],
329
+ },
330
+ handler: async ({ databaseId, maxResults = 20, filter }: any) => {
331
+ const body: any = { page_size: Math.min(maxResults, 100) };
332
+ if (filter) body.filter = filter;
333
+
334
+ const res = await this.notionFetch(`/databases/${databaseId}/query`, {
335
+ method: 'POST',
336
+ body,
337
+ });
338
+
339
+ return {
340
+ count: res.results?.length ?? 0,
341
+ hasMore: res.has_more ?? false,
342
+ entries: (res.results ?? []).map(this.formatPage.bind(this)),
343
+ };
344
+ },
345
+ },
346
+ ];
347
+ }
348
+ }
@@ -0,0 +1,334 @@
1
+ import { Plugin, PluginTool } from '../manager.js';
2
+ import { Conductor } from '../../core/conductor.js';
3
+ import { execFile } from 'child_process';
4
+ import { promisify } from 'util';
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
7
+
8
+ const execFileAsync = promisify(execFile);
9
+
10
+ // Whitelist of safe commands — no shell interpretation
11
+ const SAFE_COMMANDS = new Set([
12
+ 'ls',
13
+ 'cat',
14
+ 'head',
15
+ 'tail',
16
+ 'wc',
17
+ 'grep',
18
+ 'find',
19
+ 'stat',
20
+ 'file',
21
+ 'pwd',
22
+ 'whoami',
23
+ 'date',
24
+ 'uptime',
25
+ 'df',
26
+ 'du',
27
+ 'free',
28
+ 'top',
29
+ 'git',
30
+ 'node',
31
+ 'npm',
32
+ 'pnpm',
33
+ 'yarn',
34
+ 'python',
35
+ 'python3',
36
+ 'pip',
37
+ 'pip3',
38
+ 'make',
39
+ 'cmake',
40
+ 'cargo',
41
+ 'go',
42
+ 'rustc',
43
+ 'gcc',
44
+ 'clang',
45
+ 'curl',
46
+ 'wget',
47
+ 'ssh',
48
+ 'scp',
49
+ 'rsync',
50
+ 'docker',
51
+ 'docker-compose',
52
+ 'kubectl',
53
+ 'helm',
54
+ 'terraform',
55
+ 'ansible',
56
+ 'vault',
57
+ 'psql',
58
+ 'mysql',
59
+ 'mongosh',
60
+ 'redis-cli',
61
+ 'jq',
62
+ 'yq',
63
+ 'sed',
64
+ 'awk',
65
+ 'cut',
66
+ 'sort',
67
+ 'uniq',
68
+ 'tr',
69
+ 'xargs',
70
+ 'zip',
71
+ 'unzip',
72
+ 'tar',
73
+ 'gzip',
74
+ 'chmod',
75
+ 'chown',
76
+ 'mkdir',
77
+ 'rmdir',
78
+ 'cp',
79
+ 'mv',
80
+ 'rm',
81
+ 'touch',
82
+ 'ln',
83
+ 'diff',
84
+ 'patch',
85
+ 'md5sum',
86
+ 'sha256sum',
87
+ 'sha1sum',
88
+ ]);
89
+
90
+ // Dangerous patterns that are never allowed even with approval
91
+ const DANGEROUS_PATTERNS = [
92
+ /\brm\s+-rf\s+\/\b/,
93
+ /\bmkfs\b/,
94
+ /\bdd\s+if\b/,
95
+ /\bchmod\s+[0-7]*777\s+\/\b/,
96
+ /\bchown\s+-R\s+\S+\s+\/\b/,
97
+ /\b:\(\)\{\s*:\|:\s*&\s*\}\s*;:\b/, // fork bomb
98
+ /\/dev\/(zero|null|random|urandom)/,
99
+ /\bnc\s+-[el]/, // netcat listener
100
+ /\bpython.*-c.*import.*socket/,
101
+ /\bbash\s+-i/,
102
+ /\beval\b/,
103
+ /\bcurl.*\|\s*(ba)?sh\b/,
104
+ /\bwget.*-O-.*\|\s*(ba)?sh\b/,
105
+ ];
106
+
107
+ function isDangerous(cmd: string): { safe: boolean; reason?: string } {
108
+ for (const pattern of DANGEROUS_PATTERNS) {
109
+ if (pattern.test(cmd)) {
110
+ return { safe: false, reason: `Command matches dangerous pattern: ${pattern.source}` };
111
+ }
112
+ }
113
+ return { safe: true };
114
+ }
115
+
116
+ function validatePathArg(arg: string): string {
117
+ const resolved = path.resolve(arg);
118
+ if (resolved.includes('..') && !resolved.startsWith(process.cwd())) {
119
+ throw new Error(
120
+ `COND-FS-001: Path traversal detected: ${arg}. Paths must be within the current working directory.`,
121
+ );
122
+ }
123
+ return resolved;
124
+ }
125
+
126
+ export class ShellPlugin implements Plugin {
127
+ name = 'shell';
128
+ description = 'Safe shell command execution with approval workflow and path validation';
129
+ version = '1.0.0';
130
+
131
+ async initialize(_conductor: Conductor): Promise<void> {}
132
+ isConfigured(): boolean {
133
+ return true;
134
+ }
135
+
136
+ private async runCommand(
137
+ cmd: string,
138
+ args: string[],
139
+ cwd?: string,
140
+ ): Promise<{ stdout: string; stderr: string; exitCode: number }> {
141
+ const workingDir = cwd ? validatePathArg(cwd) : process.cwd();
142
+ try {
143
+ const { stdout, stderr } = await execFileAsync(cmd, args, {
144
+ timeout: 120000,
145
+ maxBuffer: 10 * 1024 * 1024, // 10MB
146
+ cwd: workingDir,
147
+ });
148
+ return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode: 0 };
149
+ } catch (err: unknown) {
150
+ if (err && typeof err === 'object' && 'code' in err) {
151
+ const e = err as { code?: number; stdout?: string; stderr?: string };
152
+ return {
153
+ stdout: (e.stdout ?? '').trim(),
154
+ stderr: (e.stderr ?? '').trim(),
155
+ exitCode: e.code ?? 1,
156
+ };
157
+ }
158
+ throw err;
159
+ }
160
+ }
161
+
162
+ getTools(): PluginTool[] {
163
+ return [
164
+ {
165
+ name: 'shell_run',
166
+ description:
167
+ 'Run a shell command. Commands are validated against a safety whitelist. Dangerous commands are blocked entirely.',
168
+ inputSchema: {
169
+ type: 'object',
170
+ properties: {
171
+ command: { type: 'string', description: 'Command to run (e.g. "ls -la")' },
172
+ cwd: { type: 'string', description: 'Working directory (must be within current project)' },
173
+ },
174
+ required: ['command'],
175
+ },
176
+ handler: async (input: { command: string; cwd?: string }) => {
177
+ const parts = input.command.trim().split(/\s+/);
178
+ const cmd = parts[0];
179
+
180
+ if (!cmd) throw new Error('COND-SYS-001: Empty command provided to shell executor.');
181
+ if (!SAFE_COMMANDS.has(cmd)) {
182
+ throw new Error(
183
+ `COND-SEC-001: Command "${cmd}" is not in the safe command whitelist. Allowed commands: ${Array.from(SAFE_COMMANDS).sort().join(', ')}. Review the whitelist in shell.ts for approved commands.`,
184
+ );
185
+ }
186
+
187
+ const safety = isDangerous(input.command);
188
+ if (!safety.safe)
189
+ throw new Error(
190
+ `COND-SEC-002: ${safety.reason ?? 'Command blocked by safety check'}. Review DANGEROUS_PATTERNS in shell.ts for blocked patterns.`,
191
+ );
192
+
193
+ const result = await this.runCommand(cmd, parts.slice(1), input.cwd);
194
+ return {
195
+ command: input.command,
196
+ cwd: input.cwd ?? process.cwd(),
197
+ exit_code: result.exitCode,
198
+ stdout: result.stdout,
199
+ stderr: result.stderr,
200
+ };
201
+ },
202
+ requiresApproval: true,
203
+ },
204
+ {
205
+ name: 'shell_read_file',
206
+ description: 'Read the contents of a file',
207
+ inputSchema: {
208
+ type: 'object',
209
+ properties: {
210
+ path: { type: 'string', description: 'File path to read' },
211
+ limit: { type: 'number', description: 'Maximum bytes to read', default: 100000 },
212
+ },
213
+ required: ['path'],
214
+ },
215
+ handler: async (input: { path: string; limit?: number }) => {
216
+ const filePath = validatePathArg(input.path);
217
+ const stat = await fs.stat(filePath);
218
+ if (!stat.isFile())
219
+ throw new Error(`COND-FS-002: Not a file: ${input.path}. Verify the path exists and is a regular file.`);
220
+ const limit = input.limit ?? 100000;
221
+ if (stat.size > limit)
222
+ throw new Error(
223
+ `COND-FS-003: File too large (${stat.size} bytes). Limit: ${limit} bytes. Use shell_run with head command for large files, or increase the limit parameter.`,
224
+ );
225
+ const content = await fs.readFile(filePath, 'utf-8');
226
+ return { path: input.path, size: stat.size, content };
227
+ },
228
+ },
229
+ {
230
+ name: 'shell_write_file',
231
+ description: 'Write content to a file. Creates parent directories if needed.',
232
+ inputSchema: {
233
+ type: 'object',
234
+ properties: {
235
+ path: { type: 'string', description: 'File path to write' },
236
+ content: { type: 'string', description: 'Content to write' },
237
+ },
238
+ required: ['path', 'content'],
239
+ },
240
+ handler: async (input: { path: string; content: string }) => {
241
+ const filePath = validatePathArg(input.path);
242
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
243
+ await fs.writeFile(filePath, input.content, 'utf-8');
244
+ return { path: input.path, bytes_written: Buffer.byteLength(input.content, 'utf-8') };
245
+ },
246
+ requiresApproval: true,
247
+ },
248
+ {
249
+ name: 'shell_list_dir',
250
+ description: 'List directory contents',
251
+ inputSchema: {
252
+ type: 'object',
253
+ properties: {
254
+ path: { type: 'string', description: 'Directory path', default: '.' },
255
+ recursive: { type: 'boolean', description: 'List recursively', default: false },
256
+ },
257
+ },
258
+ handler: async (input: { path?: string; recursive?: boolean; pattern?: string }) => {
259
+ const dirPath = validatePathArg(input.path ?? '.');
260
+ const stat = await fs.stat(dirPath);
261
+ if (!stat.isDirectory())
262
+ throw new Error(`COND-FS-004: Not a directory: ${input.path}. Verify the path exists and is a directory.`);
263
+ if (input.recursive) {
264
+ const { glob } = await import('glob');
265
+ const matches = await glob(input.pattern ?? '**/*', { cwd: dirPath, nodir: false });
266
+ return {
267
+ path: input.path ?? '.',
268
+ pattern: input.pattern ?? '**/*',
269
+ entries: matches.slice(0, 500),
270
+ truncated: matches.length > 500,
271
+ };
272
+ }
273
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
274
+ return {
275
+ path: input.path ?? '.',
276
+ entries: entries.map((e) => ({
277
+ name: e.name,
278
+ type: e.isDirectory() ? 'directory' : e.isFile() ? 'file' : 'other',
279
+ })),
280
+ };
281
+ },
282
+ },
283
+ {
284
+ name: 'shell_search_files',
285
+ description: 'Search for files by name pattern',
286
+ inputSchema: {
287
+ type: 'object',
288
+ properties: {
289
+ path: { type: 'string', description: 'Directory to search in', default: '.' },
290
+ pattern: { type: 'string', description: 'Glob pattern (e.g. "*.ts", "**/*.test.ts")' },
291
+ },
292
+ required: ['pattern'],
293
+ },
294
+ handler: async (input: { pattern: string; path?: string }) => {
295
+ const dirPath = validatePathArg(input.path ?? '.');
296
+ const { glob } = await import('glob');
297
+ const matches = await glob(input.pattern, { cwd: dirPath, nodir: false });
298
+ return {
299
+ path: input.path ?? '.',
300
+ pattern: input.pattern,
301
+ matches: matches.slice(0, 200),
302
+ truncated: matches.length > 200,
303
+ };
304
+ },
305
+ },
306
+ {
307
+ name: 'shell_search_content',
308
+ description: 'Search file contents using grep',
309
+ inputSchema: {
310
+ type: 'object',
311
+ properties: {
312
+ pattern: { type: 'string', description: 'Regex pattern to search for' },
313
+ path: { type: 'string', description: 'Directory to search in', default: '.' },
314
+ include: { type: 'string', description: 'File glob to include (e.g. "*.ts")' },
315
+ },
316
+ required: ['pattern'],
317
+ },
318
+ handler: async (input: { pattern: string; path?: string; include?: string }) => {
319
+ const dirPath = validatePathArg(input.path ?? '.');
320
+ const args = ['-rn', '--color=never', input.pattern, dirPath];
321
+ if (input.include) args.push('--include', input.include);
322
+ const result = await this.runCommand('grep', args);
323
+ if (result.exitCode === 1) return { pattern: input.pattern, matches: [] };
324
+ if (result.exitCode > 1)
325
+ throw new Error(
326
+ `COND-SYS-002: Grep command failed with exit code ${result.exitCode}. Error: ${result.stderr}`,
327
+ );
328
+ const lines = result.stdout.split('\n').slice(0, 100);
329
+ return { pattern: input.pattern, matches: lines, truncated: result.stdout.split('\n').length > 100 };
330
+ },
331
+ },
332
+ ];
333
+ }
334
+ }