@cdoing/core 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 (378) hide show
  1. package/dist/agents/coordinator.d.ts +114 -0
  2. package/dist/agents/coordinator.d.ts.map +1 -0
  3. package/dist/agents/coordinator.js +158 -0
  4. package/dist/agents/coordinator.js.map +1 -0
  5. package/dist/context-providers/clipboard.d.ts +13 -0
  6. package/dist/context-providers/clipboard.d.ts.map +1 -0
  7. package/dist/context-providers/clipboard.js +53 -0
  8. package/dist/context-providers/clipboard.js.map +1 -0
  9. package/dist/context-providers/codebase.d.ts +46 -0
  10. package/dist/context-providers/codebase.d.ts.map +1 -0
  11. package/dist/context-providers/codebase.js +273 -0
  12. package/dist/context-providers/codebase.js.map +1 -0
  13. package/dist/context-providers/diff.d.ts +18 -0
  14. package/dist/context-providers/diff.d.ts.map +1 -0
  15. package/dist/context-providers/diff.js +63 -0
  16. package/dist/context-providers/diff.js.map +1 -0
  17. package/dist/context-providers/docs.d.ts +21 -0
  18. package/dist/context-providers/docs.d.ts.map +1 -0
  19. package/dist/context-providers/docs.js +180 -0
  20. package/dist/context-providers/docs.js.map +1 -0
  21. package/dist/context-providers/file-include.d.ts +13 -0
  22. package/dist/context-providers/file-include.d.ts.map +1 -0
  23. package/dist/context-providers/file-include.js +82 -0
  24. package/dist/context-providers/file-include.js.map +1 -0
  25. package/dist/context-providers/folder.d.ts +19 -0
  26. package/dist/context-providers/folder.d.ts.map +1 -0
  27. package/dist/context-providers/folder.js +130 -0
  28. package/dist/context-providers/folder.js.map +1 -0
  29. package/dist/context-providers/git.d.ts +19 -0
  30. package/dist/context-providers/git.d.ts.map +1 -0
  31. package/dist/context-providers/git.js +74 -0
  32. package/dist/context-providers/git.js.map +1 -0
  33. package/dist/context-providers/index.d.ts +26 -0
  34. package/dist/context-providers/index.d.ts.map +1 -0
  35. package/dist/context-providers/index.js +37 -0
  36. package/dist/context-providers/index.js.map +1 -0
  37. package/dist/context-providers/open-files.d.ts +25 -0
  38. package/dist/context-providers/open-files.d.ts.map +1 -0
  39. package/dist/context-providers/open-files.js +134 -0
  40. package/dist/context-providers/open-files.js.map +1 -0
  41. package/dist/context-providers/problems.d.ts +24 -0
  42. package/dist/context-providers/problems.d.ts.map +1 -0
  43. package/dist/context-providers/problems.js +97 -0
  44. package/dist/context-providers/problems.js.map +1 -0
  45. package/dist/context-providers/registry.d.ts +61 -0
  46. package/dist/context-providers/registry.d.ts.map +1 -0
  47. package/dist/context-providers/registry.js +92 -0
  48. package/dist/context-providers/registry.js.map +1 -0
  49. package/dist/context-providers/terminal.d.ts +25 -0
  50. package/dist/context-providers/terminal.d.ts.map +1 -0
  51. package/dist/context-providers/terminal.js +55 -0
  52. package/dist/context-providers/terminal.js.map +1 -0
  53. package/dist/context-providers/tree.d.ts +29 -0
  54. package/dist/context-providers/tree.d.ts.map +1 -0
  55. package/dist/context-providers/tree.js +172 -0
  56. package/dist/context-providers/tree.js.map +1 -0
  57. package/dist/context-providers/types.d.ts +72 -0
  58. package/dist/context-providers/types.d.ts.map +1 -0
  59. package/dist/context-providers/types.js +10 -0
  60. package/dist/context-providers/types.js.map +1 -0
  61. package/dist/context-providers/url.d.ts +27 -0
  62. package/dist/context-providers/url.d.ts.map +1 -0
  63. package/dist/context-providers/url.js +131 -0
  64. package/dist/context-providers/url.js.map +1 -0
  65. package/dist/effort/index.d.ts +78 -0
  66. package/dist/effort/index.d.ts.map +1 -0
  67. package/dist/effort/index.js +146 -0
  68. package/dist/effort/index.js.map +1 -0
  69. package/dist/hooks/index.d.ts +47 -0
  70. package/dist/hooks/index.d.ts.map +1 -0
  71. package/dist/hooks/index.js +151 -0
  72. package/dist/hooks/index.js.map +1 -0
  73. package/dist/index.d.ts +75 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js +152 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/indexing/chunker.d.ts +25 -0
  78. package/dist/indexing/chunker.d.ts.map +1 -0
  79. package/dist/indexing/chunker.js +217 -0
  80. package/dist/indexing/chunker.js.map +1 -0
  81. package/dist/indexing/database.d.ts +49 -0
  82. package/dist/indexing/database.d.ts.map +1 -0
  83. package/dist/indexing/database.js +287 -0
  84. package/dist/indexing/database.js.map +1 -0
  85. package/dist/indexing/index.d.ts +9 -0
  86. package/dist/indexing/index.d.ts.map +1 -0
  87. package/dist/indexing/index.js +13 -0
  88. package/dist/indexing/index.js.map +1 -0
  89. package/dist/indexing/indexer.d.ts +63 -0
  90. package/dist/indexing/indexer.d.ts.map +1 -0
  91. package/dist/indexing/indexer.js +352 -0
  92. package/dist/indexing/indexer.js.map +1 -0
  93. package/dist/indexing/recent-edits-cache.d.ts +77 -0
  94. package/dist/indexing/recent-edits-cache.d.ts.map +1 -0
  95. package/dist/indexing/recent-edits-cache.js +123 -0
  96. package/dist/indexing/recent-edits-cache.js.map +1 -0
  97. package/dist/indexing/types.d.ts +39 -0
  98. package/dist/indexing/types.d.ts.map +1 -0
  99. package/dist/indexing/types.js +6 -0
  100. package/dist/indexing/types.js.map +1 -0
  101. package/dist/mcp/index.d.ts +33 -0
  102. package/dist/mcp/index.d.ts.map +1 -0
  103. package/dist/mcp/index.js +37 -0
  104. package/dist/mcp/index.js.map +1 -0
  105. package/dist/mcp/manager.d.ts +123 -0
  106. package/dist/mcp/manager.d.ts.map +1 -0
  107. package/dist/mcp/manager.js +331 -0
  108. package/dist/mcp/manager.js.map +1 -0
  109. package/dist/oauth.d.ts +33 -0
  110. package/dist/oauth.d.ts.map +1 -0
  111. package/dist/oauth.js +312 -0
  112. package/dist/oauth.js.map +1 -0
  113. package/dist/permissions/index.d.ts +216 -0
  114. package/dist/permissions/index.d.ts.map +1 -0
  115. package/dist/permissions/index.js +938 -0
  116. package/dist/permissions/index.js.map +1 -0
  117. package/dist/plan/index.d.ts +20 -0
  118. package/dist/plan/index.d.ts.map +1 -0
  119. package/dist/plan/index.js +24 -0
  120. package/dist/plan/index.js.map +1 -0
  121. package/dist/plan/manager.d.ts +101 -0
  122. package/dist/plan/manager.d.ts.map +1 -0
  123. package/dist/plan/manager.js +170 -0
  124. package/dist/plan/manager.js.map +1 -0
  125. package/dist/rules/index.d.ts +28 -0
  126. package/dist/rules/index.d.ts.map +1 -0
  127. package/dist/rules/index.js +31 -0
  128. package/dist/rules/index.js.map +1 -0
  129. package/dist/rules/manager.d.ts +77 -0
  130. package/dist/rules/manager.d.ts.map +1 -0
  131. package/dist/rules/manager.js +279 -0
  132. package/dist/rules/manager.js.map +1 -0
  133. package/dist/rules/types.d.ts +34 -0
  134. package/dist/rules/types.d.ts.map +1 -0
  135. package/dist/rules/types.js +9 -0
  136. package/dist/rules/types.js.map +1 -0
  137. package/dist/sandbox/filesystem.d.ts +20 -0
  138. package/dist/sandbox/filesystem.d.ts.map +1 -0
  139. package/dist/sandbox/filesystem.js +141 -0
  140. package/dist/sandbox/filesystem.js.map +1 -0
  141. package/dist/sandbox/index.d.ts +4 -0
  142. package/dist/sandbox/index.d.ts.map +1 -0
  143. package/dist/sandbox/index.js +8 -0
  144. package/dist/sandbox/index.js.map +1 -0
  145. package/dist/sandbox/manager.d.ts +47 -0
  146. package/dist/sandbox/manager.d.ts.map +1 -0
  147. package/dist/sandbox/manager.js +220 -0
  148. package/dist/sandbox/manager.js.map +1 -0
  149. package/dist/sandbox/network.d.ts +14 -0
  150. package/dist/sandbox/network.d.ts.map +1 -0
  151. package/dist/sandbox/network.js +87 -0
  152. package/dist/sandbox/network.js.map +1 -0
  153. package/dist/sandbox/types.d.ts +42 -0
  154. package/dist/sandbox/types.d.ts.map +1 -0
  155. package/dist/sandbox/types.js +25 -0
  156. package/dist/sandbox/types.js.map +1 -0
  157. package/dist/tools/ast-edit.d.ts +57 -0
  158. package/dist/tools/ast-edit.d.ts.map +1 -0
  159. package/dist/tools/ast-edit.js +443 -0
  160. package/dist/tools/ast-edit.js.map +1 -0
  161. package/dist/tools/code-verify.d.ts +8 -0
  162. package/dist/tools/code-verify.d.ts.map +1 -0
  163. package/dist/tools/code-verify.js +159 -0
  164. package/dist/tools/code-verify.js.map +1 -0
  165. package/dist/tools/codebase-search.d.ts +17 -0
  166. package/dist/tools/codebase-search.d.ts.map +1 -0
  167. package/dist/tools/codebase-search.js +104 -0
  168. package/dist/tools/codebase-search.js.map +1 -0
  169. package/dist/tools/file-delete.d.ts +26 -0
  170. package/dist/tools/file-delete.d.ts.map +1 -0
  171. package/dist/tools/file-delete.js +179 -0
  172. package/dist/tools/file-delete.js.map +1 -0
  173. package/dist/tools/file-edit.d.ts +10 -0
  174. package/dist/tools/file-edit.d.ts.map +1 -0
  175. package/dist/tools/file-edit.js +138 -0
  176. package/dist/tools/file-edit.js.map +1 -0
  177. package/dist/tools/file-read.d.ts +12 -0
  178. package/dist/tools/file-read.d.ts.map +1 -0
  179. package/dist/tools/file-read.js +211 -0
  180. package/dist/tools/file-read.js.map +1 -0
  181. package/dist/tools/file-run.d.ts +10 -0
  182. package/dist/tools/file-run.d.ts.map +1 -0
  183. package/dist/tools/file-run.js +179 -0
  184. package/dist/tools/file-run.js.map +1 -0
  185. package/dist/tools/file-write.d.ts +10 -0
  186. package/dist/tools/file-write.d.ts.map +1 -0
  187. package/dist/tools/file-write.js +134 -0
  188. package/dist/tools/file-write.js.map +1 -0
  189. package/dist/tools/glob-search.d.ts +8 -0
  190. package/dist/tools/glob-search.d.ts.map +1 -0
  191. package/dist/tools/glob-search.js +108 -0
  192. package/dist/tools/glob-search.js.map +1 -0
  193. package/dist/tools/grep-search.d.ts +8 -0
  194. package/dist/tools/grep-search.d.ts.map +1 -0
  195. package/dist/tools/grep-search.js +139 -0
  196. package/dist/tools/grep-search.js.map +1 -0
  197. package/dist/tools/list-dir.d.ts +16 -0
  198. package/dist/tools/list-dir.d.ts.map +1 -0
  199. package/dist/tools/list-dir.js +183 -0
  200. package/dist/tools/list-dir.js.map +1 -0
  201. package/dist/tools/multi-edit.d.ts +16 -0
  202. package/dist/tools/multi-edit.d.ts.map +1 -0
  203. package/dist/tools/multi-edit.js +163 -0
  204. package/dist/tools/multi-edit.js.map +1 -0
  205. package/dist/tools/notebook-edit.d.ts +31 -0
  206. package/dist/tools/notebook-edit.d.ts.map +1 -0
  207. package/dist/tools/notebook-edit.js +321 -0
  208. package/dist/tools/notebook-edit.js.map +1 -0
  209. package/dist/tools/registry.d.ts +16 -0
  210. package/dist/tools/registry.d.ts.map +1 -0
  211. package/dist/tools/registry.js +41 -0
  212. package/dist/tools/registry.js.map +1 -0
  213. package/dist/tools/shell-exec.d.ts +12 -0
  214. package/dist/tools/shell-exec.d.ts.map +1 -0
  215. package/dist/tools/shell-exec.js +261 -0
  216. package/dist/tools/shell-exec.js.map +1 -0
  217. package/dist/tools/sub-agent-manager.d.ts +57 -0
  218. package/dist/tools/sub-agent-manager.d.ts.map +1 -0
  219. package/dist/tools/sub-agent-manager.js +153 -0
  220. package/dist/tools/sub-agent-manager.js.map +1 -0
  221. package/dist/tools/sub-agent-status.d.ts +12 -0
  222. package/dist/tools/sub-agent-status.d.ts.map +1 -0
  223. package/dist/tools/sub-agent-status.js +59 -0
  224. package/dist/tools/sub-agent-status.js.map +1 -0
  225. package/dist/tools/sub-agent-terminate.d.ts +12 -0
  226. package/dist/tools/sub-agent-terminate.d.ts.map +1 -0
  227. package/dist/tools/sub-agent-terminate.js +55 -0
  228. package/dist/tools/sub-agent-terminate.js.map +1 -0
  229. package/dist/tools/sub-agent.d.ts +34 -0
  230. package/dist/tools/sub-agent.d.ts.map +1 -0
  231. package/dist/tools/sub-agent.js +140 -0
  232. package/dist/tools/sub-agent.js.map +1 -0
  233. package/dist/tools/system-info.d.ts +24 -0
  234. package/dist/tools/system-info.d.ts.map +1 -0
  235. package/dist/tools/system-info.js +220 -0
  236. package/dist/tools/system-info.js.map +1 -0
  237. package/dist/tools/todo.d.ts +16 -0
  238. package/dist/tools/todo.d.ts.map +1 -0
  239. package/dist/tools/todo.js +144 -0
  240. package/dist/tools/todo.js.map +1 -0
  241. package/dist/tools/types.d.ts +20 -0
  242. package/dist/tools/types.d.ts.map +1 -0
  243. package/dist/tools/types.js +3 -0
  244. package/dist/tools/types.js.map +1 -0
  245. package/dist/tools/view-diff.d.ts +11 -0
  246. package/dist/tools/view-diff.d.ts.map +1 -0
  247. package/dist/tools/view-diff.js +88 -0
  248. package/dist/tools/view-diff.js.map +1 -0
  249. package/dist/tools/view-repo-map.d.ts +18 -0
  250. package/dist/tools/view-repo-map.d.ts.map +1 -0
  251. package/dist/tools/view-repo-map.js +245 -0
  252. package/dist/tools/view-repo-map.js.map +1 -0
  253. package/dist/tools/web-fetch.d.ts +13 -0
  254. package/dist/tools/web-fetch.d.ts.map +1 -0
  255. package/dist/tools/web-fetch.js +106 -0
  256. package/dist/tools/web-fetch.js.map +1 -0
  257. package/dist/tools/web-search.d.ts +10 -0
  258. package/dist/tools/web-search.d.ts.map +1 -0
  259. package/dist/tools/web-search.js +106 -0
  260. package/dist/tools/web-search.js.map +1 -0
  261. package/dist/utils/gitignore.d.ts +10 -0
  262. package/dist/utils/gitignore.d.ts.map +1 -0
  263. package/dist/utils/gitignore.js +104 -0
  264. package/dist/utils/gitignore.js.map +1 -0
  265. package/dist/utils/lazy-apply.d.ts +45 -0
  266. package/dist/utils/lazy-apply.d.ts.map +1 -0
  267. package/dist/utils/lazy-apply.js +164 -0
  268. package/dist/utils/lazy-apply.js.map +1 -0
  269. package/dist/utils/memory.d.ts +36 -0
  270. package/dist/utils/memory.d.ts.map +1 -0
  271. package/dist/utils/memory.js +136 -0
  272. package/dist/utils/memory.js.map +1 -0
  273. package/dist/utils/path-matching.d.ts +24 -0
  274. package/dist/utils/path-matching.d.ts.map +1 -0
  275. package/dist/utils/path-matching.js +116 -0
  276. package/dist/utils/path-matching.js.map +1 -0
  277. package/dist/utils/path-safety.d.ts +13 -0
  278. package/dist/utils/path-safety.d.ts.map +1 -0
  279. package/dist/utils/path-safety.js +54 -0
  280. package/dist/utils/path-safety.js.map +1 -0
  281. package/dist/utils/project-config.d.ts +18 -0
  282. package/dist/utils/project-config.d.ts.map +1 -0
  283. package/dist/utils/project-config.js +76 -0
  284. package/dist/utils/project-config.js.map +1 -0
  285. package/dist/utils/search-match.d.ts +63 -0
  286. package/dist/utils/search-match.d.ts.map +1 -0
  287. package/dist/utils/search-match.js +426 -0
  288. package/dist/utils/search-match.js.map +1 -0
  289. package/dist/utils/shell-paths.d.ts +17 -0
  290. package/dist/utils/shell-paths.d.ts.map +1 -0
  291. package/dist/utils/shell-paths.js +107 -0
  292. package/dist/utils/shell-paths.js.map +1 -0
  293. package/dist/utils/streaming-diff.d.ts +45 -0
  294. package/dist/utils/streaming-diff.d.ts.map +1 -0
  295. package/dist/utils/streaming-diff.js +230 -0
  296. package/dist/utils/streaming-diff.js.map +1 -0
  297. package/dist/utils/todo.d.ts +47 -0
  298. package/dist/utils/todo.d.ts.map +1 -0
  299. package/dist/utils/todo.js +102 -0
  300. package/dist/utils/todo.js.map +1 -0
  301. package/package.json +23 -0
  302. package/src/agents/coordinator.ts +240 -0
  303. package/src/context-providers/clipboard.ts +48 -0
  304. package/src/context-providers/codebase.ts +274 -0
  305. package/src/context-providers/diff.ts +66 -0
  306. package/src/context-providers/docs.ts +160 -0
  307. package/src/context-providers/file-include.ts +54 -0
  308. package/src/context-providers/folder.ts +106 -0
  309. package/src/context-providers/git.ts +72 -0
  310. package/src/context-providers/index.ts +26 -0
  311. package/src/context-providers/open-files.ts +113 -0
  312. package/src/context-providers/problems.ts +100 -0
  313. package/src/context-providers/registry.ts +99 -0
  314. package/src/context-providers/terminal.ts +58 -0
  315. package/src/context-providers/tree.ts +161 -0
  316. package/src/context-providers/types.ts +84 -0
  317. package/src/context-providers/url.ts +138 -0
  318. package/src/effort/index.ts +177 -0
  319. package/src/hooks/index.ts +148 -0
  320. package/src/index.ts +114 -0
  321. package/src/indexing/README.md +267 -0
  322. package/src/indexing/chunker.ts +206 -0
  323. package/src/indexing/database.ts +299 -0
  324. package/src/indexing/index.ts +15 -0
  325. package/src/indexing/indexer.ts +383 -0
  326. package/src/indexing/recent-edits-cache.ts +150 -0
  327. package/src/indexing/types.ts +44 -0
  328. package/src/mcp/index.ts +33 -0
  329. package/src/mcp/manager.ts +385 -0
  330. package/src/oauth.ts +330 -0
  331. package/src/permissions/index.ts +1011 -0
  332. package/src/plan/index.ts +20 -0
  333. package/src/plan/manager.ts +233 -0
  334. package/src/rules/index.ts +28 -0
  335. package/src/rules/manager.ts +276 -0
  336. package/src/rules/types.ts +40 -0
  337. package/src/sandbox/filesystem.ts +135 -0
  338. package/src/sandbox/index.ts +9 -0
  339. package/src/sandbox/manager.ts +213 -0
  340. package/src/sandbox/network.ts +101 -0
  341. package/src/sandbox/types.ts +63 -0
  342. package/src/tools/ast-edit.ts +493 -0
  343. package/src/tools/code-verify.ts +143 -0
  344. package/src/tools/codebase-search.ts +117 -0
  345. package/src/tools/file-delete.ts +155 -0
  346. package/src/tools/file-edit.ts +115 -0
  347. package/src/tools/file-read.ts +195 -0
  348. package/src/tools/file-run.ts +158 -0
  349. package/src/tools/file-write.ts +104 -0
  350. package/src/tools/glob-search.ts +80 -0
  351. package/src/tools/grep-search.ts +120 -0
  352. package/src/tools/list-dir.ts +172 -0
  353. package/src/tools/multi-edit.ts +138 -0
  354. package/src/tools/notebook-edit.ts +342 -0
  355. package/src/tools/registry.ts +43 -0
  356. package/src/tools/shell-exec.ts +251 -0
  357. package/src/tools/sub-agent-manager.ts +183 -0
  358. package/src/tools/sub-agent-status.ts +67 -0
  359. package/src/tools/sub-agent-terminate.ts +62 -0
  360. package/src/tools/sub-agent.ts +162 -0
  361. package/src/tools/system-info.ts +248 -0
  362. package/src/tools/todo.ts +149 -0
  363. package/src/tools/types.ts +21 -0
  364. package/src/tools/view-diff.ts +99 -0
  365. package/src/tools/view-repo-map.ts +249 -0
  366. package/src/tools/web-fetch.ts +118 -0
  367. package/src/tools/web-search.ts +129 -0
  368. package/src/utils/gitignore.ts +73 -0
  369. package/src/utils/lazy-apply.ts +189 -0
  370. package/src/utils/memory.ts +124 -0
  371. package/src/utils/path-matching.ts +84 -0
  372. package/src/utils/path-safety.ts +19 -0
  373. package/src/utils/project-config.ts +41 -0
  374. package/src/utils/search-match.ts +495 -0
  375. package/src/utils/shell-paths.ts +79 -0
  376. package/src/utils/streaming-diff.ts +260 -0
  377. package/src/utils/todo.ts +115 -0
  378. package/tsconfig.json +18 -0
@@ -0,0 +1,251 @@
1
+ import { exec } from "child_process";
2
+ import * as os from "os";
3
+ import type { BaseTool, ToolDefinition, ToolResult } from "./types";
4
+ import type { SandboxManager } from "../sandbox";
5
+ import type { PermissionManager } from "../permissions";
6
+ import { extractShellPaths } from "../utils/shell-paths";
7
+
8
+ const IS_WINDOWS = os.platform() === "win32";
9
+
10
+ /**
11
+ * Get the shell command and args for the current platform.
12
+ * - Windows: PowerShell (more capable than cmd.exe)
13
+ * - macOS: user's shell with login flag (loads .zshrc/.bashrc for PATH, nvm, pyenv, etc.)
14
+ * - Linux: user's shell with login flag
15
+ */
16
+ function getShellCommand(command: string): { shell: string; args: string[] } {
17
+ if (IS_WINDOWS) {
18
+ return {
19
+ shell: "powershell.exe",
20
+ args: ["-NoLogo", "-ExecutionPolicy", "Bypass", "-Command", command],
21
+ };
22
+ }
23
+ const userShell = process.env.SHELL || (os.platform() === "darwin" ? "/bin/zsh" : "/bin/bash");
24
+ return { shell: userShell, args: ["-l", "-c", command] };
25
+ }
26
+
27
+ /** For exec() — the shell to use */
28
+ const SHELL = IS_WINDOWS ? "powershell.exe" : process.env.SHELL || "/bin/sh";
29
+
30
+ /** Color-supporting environment variables */
31
+ const COLOR_ENV = {
32
+ FORCE_COLOR: "1",
33
+ COLORTERM: "truecolor",
34
+ TERM: "xterm-256color",
35
+ CLICOLOR: "1",
36
+ CLICOLOR_FORCE: "1",
37
+ };
38
+
39
+ /** Absolute danger — always blocked regardless of permissions */
40
+ const ALWAYS_BLOCKED = [
41
+ // Unix — catastrophic filesystem destruction
42
+ "rm -rf /",
43
+ "rm -rf ~",
44
+ "rm -rf /*",
45
+ "rm -rf ~/*",
46
+ "rm -rf $HOME",
47
+ "mkfs",
48
+ "dd if=",
49
+ ":(){", // fork bomb
50
+ // Windows — catastrophic filesystem destruction
51
+ "rd /s /q C:\\",
52
+ "del /f /s /q C:\\",
53
+ "format C:",
54
+ "rd /s /q %systemroot%",
55
+ ];
56
+
57
+ /** Destructive patterns for elevated permission message */
58
+ const DESTRUCTIVE_PATTERNS = [
59
+ // File deletion (Unix)
60
+ /\brm\s/, /\brm$/, /\brmdir\s/, /\bunlink\s/, /\bshred\s/,
61
+ // File deletion (Windows)
62
+ /\bdel\s/, /\brd\s/, /\berase\s/,
63
+ // Git destructive operations
64
+ /\bgit\s+clean\b/,
65
+ /\bgit\s+reset\s+--hard\b/,
66
+ /\bgit\s+push\s+.*--force\b/, /\bgit\s+push\s+-f\b/,
67
+ /\bgit\s+checkout\s+--\s/, /\bgit\s+restore\s/,
68
+ /\bgit\s+branch\s+-[dD]\b/,
69
+ /\bgit\s+rebase\b/,
70
+ /\bgit\s+stash\s+drop\b/,
71
+ // Process killing
72
+ /\bkill\s+-9\b/, /\bkillall\b/, /\bpkill\b/,
73
+ // Permission changes
74
+ /\bchmod\s+777\b/, /\bchmod\s+-R\b/, /\bchown\s+-R\b/,
75
+ // Database destructive (SQL injection risk via shell)
76
+ /\bDROP\s+(TABLE|DATABASE)\b/i, /\bTRUNCATE\s+TABLE\b/i, /\bDELETE\s+FROM\b/i,
77
+ // Disk/system
78
+ /\bdd\s/, /\bmv\s+\//, /\bsudo\s/,
79
+ // Docker destructive
80
+ /\bdocker\s+(rm|rmi|system\s+prune)\b/,
81
+ // npm/package destructive
82
+ /\bnpm\s+unpublish\b/,
83
+ ];
84
+
85
+
86
+ export class ShellExecTool implements BaseTool {
87
+ definition: ToolDefinition = {
88
+ name: "shell_exec",
89
+ description:
90
+ `Execute a shell command and return its output. Use for builds, tests, git commands, etc. Requires user permission before execution.
91
+
92
+ All file paths in commands are checked against permission rules:
93
+ - Read paths (cat, less, grep, etc.) are checked against Read deny rules.
94
+ - Write paths (cp, mv, redirect >, tee, etc.) are checked against Edit deny rules.
95
+ - Delete paths (rm, rmdir, unlink, etc.) are checked against Delete deny rules.
96
+ - Destructive commands are flagged as high-risk in the permission prompt.
97
+
98
+ Commands are also subject to sandbox restrictions.`,
99
+ inputSchema: {
100
+ type: "object",
101
+ properties: {
102
+ command: { type: "string", description: "The shell command to execute" },
103
+ timeout: { type: "number", description: "Timeout in ms. Default: 120000" },
104
+ background: {
105
+ type: "boolean",
106
+ description: "Run in background. Returns immediately with PID. Use for servers/watchers. Default: false.",
107
+ },
108
+ env_vars: {
109
+ type: "object",
110
+ description: "Environment variables to set (e.g., {\"PORT\": \"3001\", \"DEBUG\": \"app:*\"})",
111
+ additionalProperties: { type: "string" },
112
+ },
113
+ debug: {
114
+ type: "boolean",
115
+ description: "Enable debug/verbose mode. Sets DEBUG=*, NODE_DEBUG=*, RUST_BACKTRACE=1, PYTHONTRACEBACK=1. Default: false",
116
+ },
117
+ dangerouslyDisableSandbox: {
118
+ type: "boolean",
119
+ description: "Set to true to run this command outside the sandbox. Requires permission approval.",
120
+ },
121
+ },
122
+ required: ["command"],
123
+ },
124
+ requiresPermission: true,
125
+ permissionMessage: (input) => {
126
+ const cmd = String(input.command || "");
127
+ if (DESTRUCTIVE_PATTERNS.some((p) => p.test(cmd))) {
128
+ return `⚠ DESTRUCTIVE command: ${cmd}`;
129
+ }
130
+ return `Run command: ${cmd}`;
131
+ },
132
+ };
133
+
134
+ private workingDir: string;
135
+ private sandboxManager?: SandboxManager;
136
+ private permissionManager?: PermissionManager;
137
+
138
+ constructor(workingDir: string, sandboxManager?: SandboxManager, permissionManager?: PermissionManager) {
139
+ this.workingDir = workingDir;
140
+ this.sandboxManager = sandboxManager;
141
+ this.permissionManager = permissionManager;
142
+ }
143
+
144
+ async execute(input: Record<string, unknown>): Promise<ToolResult> {
145
+ const command = input.command as string;
146
+ const timeout = (input.timeout as number) || 120000;
147
+ const dangerouslyDisableSandbox = (input.dangerouslyDisableSandbox as boolean) || false;
148
+
149
+ // Always-blocked patterns (catastrophic destruction)
150
+ for (const pat of ALWAYS_BLOCKED) {
151
+ if (command.includes(pat))
152
+ return { success: false, output: "", error: `Blocked dangerous pattern: ${pat}` };
153
+ }
154
+
155
+ // ── Permission-based path checks ────────────────────────────────────────
156
+ if (this.permissionManager) {
157
+ const paths = extractShellPaths(command, this.workingDir);
158
+
159
+ // Check read paths against Read deny rules
160
+ for (const p of paths.read) {
161
+ const result = this.permissionManager.checkPathPermission(p, "Read");
162
+ if (result === "deny") {
163
+ return { success: false, output: "", error: `Permission denied: read access to "${p}" is blocked by settings rules` };
164
+ }
165
+ }
166
+
167
+ // Check write paths against Edit deny rules
168
+ for (const p of paths.write) {
169
+ const result = this.permissionManager.checkPathPermission(p, "Edit");
170
+ if (result === "deny") {
171
+ return { success: false, output: "", error: `Permission denied: write access to "${p}" is blocked by settings rules` };
172
+ }
173
+ }
174
+
175
+ // Check delete paths against Delete deny rules
176
+ for (const p of paths.delete) {
177
+ const result = this.permissionManager.checkPathPermission(p, "Delete");
178
+ if (result === "deny") {
179
+ return { success: false, output: "", error: `Permission denied: delete access to "${p}" is blocked by settings rules` };
180
+ }
181
+ }
182
+ }
183
+
184
+ // ── Sandbox checks ──────────────────────────────────────────────────────
185
+ if (this.sandboxManager) {
186
+ const check = this.sandboxManager.checkShellCommand(command, dangerouslyDisableSandbox);
187
+ if (!check.allowed) {
188
+ return { success: false, output: "", error: check.reason || "Sandbox: command blocked" };
189
+ }
190
+ }
191
+
192
+ // Build environment
193
+ const env = this.sandboxManager ? this.sandboxManager.getShellEnv() : { ...process.env };
194
+
195
+ // Merge user-provided env vars
196
+ const envVars = input.env_vars as Record<string, string> | undefined;
197
+ if (envVars && typeof envVars === "object") {
198
+ for (const [key, val] of Object.entries(envVars)) {
199
+ env[key] = String(val);
200
+ }
201
+ }
202
+
203
+ // Debug mode
204
+ if (input.debug) {
205
+ env.DEBUG = env.DEBUG || "*";
206
+ env.NODE_DEBUG = env.NODE_DEBUG || "*";
207
+ env.RUST_BACKTRACE = env.RUST_BACKTRACE || "1";
208
+ env.PYTHONTRACEBACK = env.PYTHONTRACEBACK || "1";
209
+ env.PYTHONFAULTHANDLER = env.PYTHONFAULTHANDLER || "1";
210
+ }
211
+
212
+ const background = (input.background as boolean) || false;
213
+
214
+ // Merge color env for better terminal output
215
+ Object.assign(env, COLOR_ENV);
216
+
217
+ // Background mode: spawn detached, return immediately with PID
218
+ if (background) {
219
+ const { spawn } = require("child_process") as typeof import("child_process");
220
+ const { shell, args } = getShellCommand(command);
221
+ const child = spawn(shell, args, {
222
+ cwd: this.workingDir,
223
+ env,
224
+ detached: !IS_WINDOWS,
225
+ stdio: "ignore",
226
+ });
227
+ child.unref();
228
+ return { success: true, output: `Started in background (PID: ${child.pid})` };
229
+ }
230
+
231
+ return new Promise((resolve) => {
232
+ exec(command, { cwd: this.workingDir, timeout, maxBuffer: 10 * 1024 * 1024, env, shell: SHELL },
233
+ (error, stdout, stderr) => {
234
+ const outputParts: string[] = [];
235
+ if (stdout) outputParts.push(stdout.trimEnd());
236
+ if (stderr) outputParts.push(`STDERR:\n${stderr.trimEnd()}`);
237
+ const output = outputParts.join("\n\n") || "(no output)";
238
+
239
+ if (error?.killed) {
240
+ return resolve({ success: false, output, error: `Timed out after ${timeout}ms` });
241
+ }
242
+
243
+ if (error) {
244
+ resolve({ success: false, output, error: `Exit code: ${error.code}` });
245
+ } else {
246
+ resolve({ success: true, output });
247
+ }
248
+ });
249
+ });
250
+ }
251
+ }
@@ -0,0 +1,183 @@
1
+ /**
2
+ * SubAgentManager — Tracks all spawned sub-agents.
3
+ *
4
+ * Provides lifecycle management: spawn with custom timeout,
5
+ * check status/output, and terminate running agents.
6
+ */
7
+
8
+ export type SubAgentStatus = "running" | "completed" | "failed" | "terminated" | "timed_out";
9
+
10
+ export interface SubAgentEntry {
11
+ id: string;
12
+ task: string;
13
+ status: SubAgentStatus;
14
+ output: string;
15
+ error?: string;
16
+ startedAt: number;
17
+ finishedAt?: number;
18
+ /** AbortController to cancel a running agent */
19
+ abort?: AbortController;
20
+ }
21
+
22
+ export class SubAgentManager {
23
+ private agents: Map<string, SubAgentEntry> = new Map();
24
+ private idCounter = 0;
25
+
26
+ /** Generate a unique agent ID */
27
+ private nextId(): string {
28
+ this.idCounter++;
29
+ return `agent_${this.idCounter}_${Date.now().toString(36)}`;
30
+ }
31
+
32
+ /**
33
+ * Spawn a sub-agent. Runs in background — returns the ID immediately.
34
+ * The caller provides runnerFn which actually executes the agent.
35
+ */
36
+ spawn(
37
+ task: string,
38
+ runnerFn: (signal: AbortSignal) => Promise<string>,
39
+ timeoutMs?: number,
40
+ ): string {
41
+ const id = this.nextId();
42
+ const abort = new AbortController();
43
+
44
+ const entry: SubAgentEntry = {
45
+ id,
46
+ task,
47
+ status: "running",
48
+ output: "",
49
+ startedAt: Date.now(),
50
+ abort,
51
+ };
52
+ this.agents.set(id, entry);
53
+
54
+ // Set up timeout if requested
55
+ let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
56
+ if (timeoutMs && timeoutMs > 0) {
57
+ timeoutHandle = setTimeout(() => {
58
+ if (entry.status === "running") {
59
+ entry.status = "timed_out";
60
+ entry.error = `Timed out after ${timeoutMs}ms`;
61
+ entry.finishedAt = Date.now();
62
+ abort.abort();
63
+ }
64
+ }, timeoutMs);
65
+ }
66
+
67
+ // Run the agent in background
68
+ runnerFn(abort.signal)
69
+ .then((result) => {
70
+ if (entry.status === "running") {
71
+ entry.status = "completed";
72
+ entry.output = result;
73
+ entry.finishedAt = Date.now();
74
+ }
75
+ })
76
+ .catch((err) => {
77
+ if (entry.status === "running") {
78
+ const msg = err instanceof Error ? err.message : String(err);
79
+ if (msg === "__cancelled__" || abort.signal.aborted) {
80
+ // Only set terminated if not already timed_out
81
+ if (entry.status === "running") {
82
+ entry.status = "terminated";
83
+ entry.error = "Terminated by user";
84
+ entry.finishedAt = Date.now();
85
+ }
86
+ } else {
87
+ entry.status = "failed";
88
+ entry.error = msg;
89
+ entry.finishedAt = Date.now();
90
+ }
91
+ }
92
+ })
93
+ .finally(() => {
94
+ if (timeoutHandle) clearTimeout(timeoutHandle);
95
+ delete entry.abort; // clean up reference
96
+ });
97
+
98
+ return id;
99
+ }
100
+
101
+ /**
102
+ * Spawn and wait — runs synchronously (blocks until done or timeout).
103
+ * Used when the LLM does NOT request background mode.
104
+ */
105
+ async spawnAndWait(
106
+ task: string,
107
+ runnerFn: (signal: AbortSignal) => Promise<string>,
108
+ timeoutMs?: number,
109
+ ): Promise<SubAgentEntry> {
110
+ const id = this.spawn(task, runnerFn, timeoutMs);
111
+ const entry = this.agents.get(id)!;
112
+
113
+ // Poll until done (the promise is already running)
114
+ await new Promise<void>((resolve) => {
115
+ const check = () => {
116
+ if (entry.status !== "running") {
117
+ resolve();
118
+ } else {
119
+ setTimeout(check, 50);
120
+ }
121
+ };
122
+ check();
123
+ });
124
+
125
+ return entry;
126
+ }
127
+
128
+ /** Get a specific agent's info */
129
+ get(id: string): SubAgentEntry | undefined {
130
+ return this.agents.get(id);
131
+ }
132
+
133
+ /** Get status of a specific agent */
134
+ getStatus(id: string): { id: string; status: SubAgentStatus; task: string; output: string; error?: string; durationMs?: number } | null {
135
+ const entry = this.agents.get(id);
136
+ if (!entry) return null;
137
+
138
+ const durationMs = entry.finishedAt
139
+ ? entry.finishedAt - entry.startedAt
140
+ : Date.now() - entry.startedAt;
141
+
142
+ return {
143
+ id: entry.id,
144
+ status: entry.status,
145
+ task: entry.task,
146
+ output: entry.output,
147
+ error: entry.error,
148
+ durationMs,
149
+ };
150
+ }
151
+
152
+ /** List all agents with their statuses */
153
+ listAll(): Array<{ id: string; task: string; status: SubAgentStatus; durationMs: number }> {
154
+ return Array.from(this.agents.values()).map((entry) => ({
155
+ id: entry.id,
156
+ task: entry.task,
157
+ status: entry.status,
158
+ durationMs: entry.finishedAt
159
+ ? entry.finishedAt - entry.startedAt
160
+ : Date.now() - entry.startedAt,
161
+ }));
162
+ }
163
+
164
+ /** Terminate a running agent */
165
+ terminate(id: string): boolean {
166
+ const entry = this.agents.get(id);
167
+ if (!entry || entry.status !== "running") return false;
168
+
169
+ entry.status = "terminated";
170
+ entry.error = "Terminated by user";
171
+ entry.finishedAt = Date.now();
172
+ if (entry.abort) {
173
+ entry.abort.abort();
174
+ delete entry.abort;
175
+ }
176
+ return true;
177
+ }
178
+
179
+ /** Check if any agents are still running */
180
+ hasRunning(): boolean {
181
+ return Array.from(this.agents.values()).some((e) => e.status === "running");
182
+ }
183
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Sub-Agent Status Tool — check status and output of spawned sub-agents.
3
+ */
4
+
5
+ import type { BaseTool, ToolDefinition, ToolResult } from "./types";
6
+ import type { SubAgentManager } from "./sub-agent-manager";
7
+
8
+ export class SubAgentStatusTool implements BaseTool {
9
+ definition: ToolDefinition = {
10
+ name: "sub_agent_status",
11
+ description:
12
+ "Check the status and output of a background sub-agent by its ID, or list all sub-agents. Use this to poll for completion of background sub-agents.",
13
+ inputSchema: {
14
+ type: "object",
15
+ properties: {
16
+ agent_id: {
17
+ type: "string",
18
+ description:
19
+ "The ID of the sub-agent to check. Omit to list all sub-agents.",
20
+ },
21
+ },
22
+ required: [],
23
+ },
24
+ requiresPermission: false,
25
+ };
26
+
27
+ private manager: SubAgentManager;
28
+
29
+ constructor(manager: SubAgentManager) {
30
+ this.manager = manager;
31
+ }
32
+
33
+ async execute(input: Record<string, unknown>): Promise<ToolResult> {
34
+ const agentId = input.agent_id as string | undefined;
35
+
36
+ if (agentId) {
37
+ // Get specific agent status
38
+ const status = this.manager.getStatus(agentId);
39
+ if (!status) {
40
+ return {
41
+ success: false,
42
+ output: "",
43
+ error: `No sub-agent found with ID "${agentId}". Use sub_agent_status without an agent_id to list all agents.`,
44
+ };
45
+ }
46
+
47
+ return {
48
+ success: true,
49
+ output: JSON.stringify(status, null, 2),
50
+ };
51
+ }
52
+
53
+ // List all agents
54
+ const all = this.manager.listAll();
55
+ if (all.length === 0) {
56
+ return {
57
+ success: true,
58
+ output: "No sub-agents have been spawned yet.",
59
+ };
60
+ }
61
+
62
+ return {
63
+ success: true,
64
+ output: JSON.stringify(all, null, 2),
65
+ };
66
+ }
67
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Sub-Agent Terminate Tool — stop a running sub-agent.
3
+ */
4
+
5
+ import type { BaseTool, ToolDefinition, ToolResult } from "./types";
6
+ import type { SubAgentManager } from "./sub-agent-manager";
7
+
8
+ export class SubAgentTerminateTool implements BaseTool {
9
+ definition: ToolDefinition = {
10
+ name: "sub_agent_terminate",
11
+ description:
12
+ "Terminate a running sub-agent by its ID. Use this to stop a long-running or stuck background sub-agent.",
13
+ inputSchema: {
14
+ type: "object",
15
+ properties: {
16
+ agent_id: {
17
+ type: "string",
18
+ description: "The ID of the sub-agent to terminate",
19
+ },
20
+ },
21
+ required: ["agent_id"],
22
+ },
23
+ requiresPermission: false,
24
+ };
25
+
26
+ private manager: SubAgentManager;
27
+
28
+ constructor(manager: SubAgentManager) {
29
+ this.manager = manager;
30
+ }
31
+
32
+ async execute(input: Record<string, unknown>): Promise<ToolResult> {
33
+ const agentId = input.agent_id as string;
34
+
35
+ if (!agentId) {
36
+ return { success: false, output: "", error: "agent_id is required" };
37
+ }
38
+
39
+ const terminated = this.manager.terminate(agentId);
40
+
41
+ if (!terminated) {
42
+ const status = this.manager.getStatus(agentId);
43
+ if (!status) {
44
+ return {
45
+ success: false,
46
+ output: "",
47
+ error: `No sub-agent found with ID "${agentId}".`,
48
+ };
49
+ }
50
+ return {
51
+ success: false,
52
+ output: "",
53
+ error: `Sub-agent "${agentId}" is not running (status: ${status.status}). Only running agents can be terminated.`,
54
+ };
55
+ }
56
+
57
+ return {
58
+ success: true,
59
+ output: `Sub-agent "${agentId}" has been terminated.`,
60
+ };
61
+ }
62
+ }