@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,161 @@
1
+ /**
2
+ * Tree Context Provider — @tree
3
+ *
4
+ * Generates a file tree visualization of the workspace.
5
+ * Helps the AI understand the project structure at a glance.
6
+ *
7
+ * Usage:
8
+ * @tree → full tree (default depth 3)
9
+ * @tree src → tree of a subdirectory
10
+ * @tree 5 → custom depth
11
+ *
12
+ * How it works:
13
+ * 1. Walks the directory recursively up to the configured depth
14
+ * 2. Respects .gitignore patterns
15
+ * 3. Formats as an ASCII tree (like the `tree` command)
16
+ *
17
+ * Learning note: We use recursion with a depth limit to prevent
18
+ * scanning massive directories. The .gitignore filtering ensures
19
+ * we don't include node_modules, dist, etc.
20
+ */
21
+
22
+ import * as fs from "fs";
23
+ import * as path from "path";
24
+ import type { ContextProvider, ContextResult, ContextResolveOptions } from "./types";
25
+
26
+ /** Default max depth for tree traversal */
27
+ const DEFAULT_DEPTH = 3;
28
+
29
+ /** Max items to include in the tree output */
30
+ const MAX_ITEMS = 500;
31
+
32
+ /** Directories to always skip (even without .gitignore) */
33
+ const ALWAYS_SKIP = new Set([
34
+ "node_modules", ".git", ".next", ".nuxt", "__pycache__",
35
+ ".cache", ".turbo", "dist", "build", ".DS_Store",
36
+ "coverage", ".nyc_output", ".pytest_cache", "venv",
37
+ ".venv", "env", ".env", ".tox",
38
+ ]);
39
+
40
+ export class TreeContextProvider implements ContextProvider {
41
+ id = "tree";
42
+ trigger = "@tree";
43
+ description = "Show workspace file tree structure";
44
+ requiresArg = false;
45
+
46
+ async resolve(arg?: string, options?: ContextResolveOptions): Promise<ContextResult> {
47
+ const workingDir = options?.workingDir || process.cwd();
48
+
49
+ // Parse argument: could be a path, a depth number, or "path depth"
50
+ let targetDir = workingDir;
51
+ let maxDepth = DEFAULT_DEPTH;
52
+
53
+ if (arg) {
54
+ const parts = arg.trim().split(/\s+/);
55
+ for (const part of parts) {
56
+ const num = parseInt(part, 10);
57
+ if (!isNaN(num) && num > 0 && num <= 10) {
58
+ maxDepth = num;
59
+ } else {
60
+ // Treat as a subdirectory path
61
+ const resolved = path.resolve(workingDir, part);
62
+ if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
63
+ targetDir = resolved;
64
+ }
65
+ }
66
+ }
67
+ }
68
+
69
+ // Build the tree
70
+ let itemCount = 0;
71
+ const lines: string[] = [];
72
+ const rootName = path.basename(targetDir);
73
+ lines.push(rootName + "/");
74
+
75
+ buildTree(targetDir, "", maxDepth, 0, lines, { count: 0, max: MAX_ITEMS });
76
+ itemCount = lines.length - 1; // Subtract the root line
77
+
78
+ const treeOutput = lines.join("\n");
79
+ const relativePath = path.relative(workingDir, targetDir) || ".";
80
+
81
+ return {
82
+ label: `File Tree: ${relativePath}`,
83
+ content: `## File Tree: ${relativePath} (depth: ${maxDepth})\n\n\`\`\`\n${treeOutput}\n\`\`\``,
84
+ metadata: {
85
+ source: targetDir,
86
+ truncated: itemCount >= MAX_ITEMS,
87
+ itemCount,
88
+ },
89
+ };
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Recursively build an ASCII tree representation.
95
+ *
96
+ * Uses box-drawing characters for a clean visual:
97
+ * ├── file.ts
98
+ * ├── src/
99
+ * │ ├── index.ts
100
+ * │ └── utils/
101
+ * └── package.json
102
+ *
103
+ * Learning note: The `prefix` parameter builds up as we recurse deeper,
104
+ * adding "│ " or " " to maintain the visual tree structure.
105
+ */
106
+ function buildTree(
107
+ dir: string,
108
+ prefix: string,
109
+ maxDepth: number,
110
+ currentDepth: number,
111
+ lines: string[],
112
+ counter: { count: number; max: number },
113
+ ): void {
114
+ if (currentDepth >= maxDepth || counter.count >= counter.max) return;
115
+
116
+ let entries: fs.Dirent[];
117
+ try {
118
+ entries = fs.readdirSync(dir, { withFileTypes: true });
119
+ } catch {
120
+ return; // Permission denied or other read errors
121
+ }
122
+
123
+ // Filter out hidden/ignored directories and sort (dirs first, then files)
124
+ const filtered = entries
125
+ .filter((e) => !e.name.startsWith(".") || e.name === ".cdoing")
126
+ .filter((e) => !ALWAYS_SKIP.has(e.name))
127
+ .sort((a, b) => {
128
+ // Directories first, then alphabetical
129
+ if (a.isDirectory() && !b.isDirectory()) return -1;
130
+ if (!a.isDirectory() && b.isDirectory()) return 1;
131
+ return a.name.localeCompare(b.name);
132
+ });
133
+
134
+ for (let i = 0; i < filtered.length; i++) {
135
+ if (counter.count >= counter.max) {
136
+ lines.push(`${prefix}... [truncated at ${counter.max} items]`);
137
+ return;
138
+ }
139
+
140
+ const entry = filtered[i];
141
+ const isLast = i === filtered.length - 1;
142
+ const connector = isLast ? "└── " : "├── ";
143
+ const childPrefix = isLast ? " " : "│ ";
144
+
145
+ if (entry.isDirectory()) {
146
+ lines.push(`${prefix}${connector}${entry.name}/`);
147
+ counter.count++;
148
+ buildTree(
149
+ path.join(dir, entry.name),
150
+ prefix + childPrefix,
151
+ maxDepth,
152
+ currentDepth + 1,
153
+ lines,
154
+ counter,
155
+ );
156
+ } else {
157
+ lines.push(`${prefix}${connector}${entry.name}`);
158
+ counter.count++;
159
+ }
160
+ }
161
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Context Provider Types — Defines the contract for all context providers.
3
+ *
4
+ * Learning note: Using interfaces (not classes) keeps this flexible.
5
+ * Any object that satisfies these shapes can be a context provider,
6
+ * whether it's a simple object literal or a full class instance.
7
+ */
8
+
9
+ /**
10
+ * The result returned by a context provider after resolving.
11
+ * Contains the formatted content ready to inject into the prompt.
12
+ */
13
+ export interface ContextResult {
14
+ /** Human-readable label shown in the UI (e.g., "Terminal Output") */
15
+ label: string;
16
+
17
+ /** The actual content to inject into the conversation */
18
+ content: string;
19
+
20
+ /** Optional metadata for display purposes */
21
+ metadata?: {
22
+ source?: string; // Where the content came from
23
+ truncated?: boolean; // Whether the content was trimmed
24
+ itemCount?: number; // Number of items (files, diagnostics, etc.)
25
+ };
26
+ }
27
+
28
+ /**
29
+ * A context provider resolves an @ mention into content.
30
+ *
31
+ * Example: "@terminal" → last terminal output
32
+ * "@url https://example.com" → fetched page content
33
+ */
34
+ export interface ContextProvider {
35
+ /** Unique identifier (e.g., "terminal", "open", "url") */
36
+ id: string;
37
+
38
+ /** The @ trigger keyword (e.g., "@terminal") */
39
+ trigger: string;
40
+
41
+ /** Short description shown in autocomplete */
42
+ description: string;
43
+
44
+ /**
45
+ * Whether this provider needs an argument after the trigger.
46
+ * E.g., "@url" needs a URL, but "@terminal" doesn't.
47
+ */
48
+ requiresArg: boolean;
49
+
50
+ /**
51
+ * Resolve the context — fetch the actual content.
52
+ *
53
+ * @param arg - Optional argument (e.g., URL for @url provider)
54
+ * @param options - Runtime context (working dir, VS Code API, etc.)
55
+ * @returns The resolved context content
56
+ */
57
+ resolve(arg?: string, options?: ContextResolveOptions): Promise<ContextResult>;
58
+ }
59
+
60
+ /**
61
+ * Options passed to context providers at resolve time.
62
+ * Provides access to runtime environment without tight coupling.
63
+ */
64
+ export interface ContextResolveOptions {
65
+ /** Current working directory */
66
+ workingDir?: string;
67
+
68
+ /** Open file paths (for @open provider) */
69
+ openFiles?: string[];
70
+
71
+ /** Recent terminal output (for @terminal provider) */
72
+ terminalOutput?: string;
73
+
74
+ /** Diagnostics/problems (for @problems provider) */
75
+ diagnostics?: Array<{
76
+ file: string;
77
+ line: number;
78
+ severity: "error" | "warning" | "info" | "hint";
79
+ message: string;
80
+ }>;
81
+
82
+ /** Max content length (chars) before truncation */
83
+ maxContentLength?: number;
84
+ }
@@ -0,0 +1,138 @@
1
+ /**
2
+ * URL Context Provider — @url
3
+ *
4
+ * Fetches a web page and converts it to clean markdown for context.
5
+ * Reuses the existing web_fetch tool logic under the hood.
6
+ *
7
+ * Usage: @url https://docs.example.com/api
8
+ *
9
+ * How it works:
10
+ * 1. User types @url followed by a URL
11
+ * 2. We fetch the page HTML
12
+ * 3. Strip tags, scripts, styles → extract readable text
13
+ * 4. Format as markdown and inject into the conversation
14
+ *
15
+ * Learning note: This provider REQUIRES an argument (the URL).
16
+ * The `requiresArg` flag tells the UI to keep the input open
17
+ * until the user provides the URL after the @ trigger.
18
+ */
19
+
20
+ import type { ContextProvider, ContextResult, ContextResolveOptions } from "./types";
21
+
22
+ /** Max chars for fetched content */
23
+ const DEFAULT_MAX_CHARS = 15000;
24
+
25
+ export class UrlContextProvider implements ContextProvider {
26
+ id = "url";
27
+ trigger = "@url";
28
+ description = "Fetch and attach web page content";
29
+ requiresArg = true;
30
+
31
+ async resolve(arg?: string, options?: ContextResolveOptions): Promise<ContextResult> {
32
+ if (!arg || !arg.trim()) {
33
+ return {
34
+ label: "URL",
35
+ content: "[Please provide a URL after @url, e.g.: @url https://docs.example.com]",
36
+ metadata: { source: "web" },
37
+ };
38
+ }
39
+
40
+ const url = arg.trim();
41
+ const maxChars = options?.maxContentLength ?? DEFAULT_MAX_CHARS;
42
+
43
+ try {
44
+ // Fetch the URL content
45
+ const response = await fetch(url, {
46
+ headers: {
47
+ "User-Agent": "Cdoing-Agent/1.0 (Context Fetcher)",
48
+ "Accept": "text/html,text/plain,application/json",
49
+ },
50
+ signal: AbortSignal.timeout(15000), // 15 second timeout
51
+ });
52
+
53
+ if (!response.ok) {
54
+ return {
55
+ label: `URL: ${url}`,
56
+ content: `[Failed to fetch ${url}: HTTP ${response.status} ${response.statusText}]`,
57
+ metadata: { source: "web" },
58
+ };
59
+ }
60
+
61
+ const contentType = response.headers.get("content-type") || "";
62
+ let body = await response.text();
63
+
64
+ // Convert HTML to readable text
65
+ if (contentType.includes("html")) {
66
+ body = htmlToText(body);
67
+ }
68
+
69
+ // Truncate if needed
70
+ let truncated = false;
71
+ if (body.length > maxChars) {
72
+ body = body.substring(0, maxChars);
73
+ truncated = true;
74
+ }
75
+
76
+ return {
77
+ label: `URL: ${url}`,
78
+ content: `## Web Content: ${url}\n\n${body}${truncated ? "\n\n... [content truncated]" : ""}`,
79
+ metadata: {
80
+ source: url,
81
+ truncated,
82
+ },
83
+ };
84
+ } catch (err) {
85
+ const message = err instanceof Error ? err.message : String(err);
86
+ return {
87
+ label: `URL: ${url}`,
88
+ content: `[Error fetching ${url}: ${message}]`,
89
+ metadata: { source: "web" },
90
+ };
91
+ }
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Convert HTML to readable plain text.
97
+ * Strips tags, scripts, styles, and normalizes whitespace.
98
+ *
99
+ * Learning note: This is a simple regex-based approach that works
100
+ * well enough for most pages. For production, you'd use a proper
101
+ * HTML parser like cheerio or jsdom.
102
+ */
103
+ function htmlToText(html: string): string {
104
+ return html
105
+ // Remove script and style blocks entirely
106
+ .replace(/<script[\s\S]*?<\/script>/gi, "")
107
+ .replace(/<style[\s\S]*?<\/style>/gi, "")
108
+ .replace(/<noscript[\s\S]*?<\/noscript>/gi, "")
109
+ // Convert common elements to markdown equivalents
110
+ .replace(/<h1[^>]*>(.*?)<\/h1>/gi, "\n# $1\n")
111
+ .replace(/<h2[^>]*>(.*?)<\/h2>/gi, "\n## $1\n")
112
+ .replace(/<h3[^>]*>(.*?)<\/h3>/gi, "\n### $1\n")
113
+ .replace(/<h[4-6][^>]*>(.*?)<\/h[4-6]>/gi, "\n#### $1\n")
114
+ .replace(/<li[^>]*>(.*?)<\/li>/gi, "- $1\n")
115
+ .replace(/<br\s*\/?>/gi, "\n")
116
+ .replace(/<p[^>]*>/gi, "\n")
117
+ .replace(/<\/p>/gi, "\n")
118
+ .replace(/<code[^>]*>(.*?)<\/code>/gi, "`$1`")
119
+ .replace(/<pre[^>]*>(.*?)<\/pre>/gis, "\n```\n$1\n```\n")
120
+ .replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, "[$2]($1)")
121
+ .replace(/<strong[^>]*>(.*?)<\/strong>/gi, "**$1**")
122
+ .replace(/<b[^>]*>(.*?)<\/b>/gi, "**$1**")
123
+ .replace(/<em[^>]*>(.*?)<\/em>/gi, "*$1*")
124
+ .replace(/<i[^>]*>(.*?)<\/i>/gi, "*$1*")
125
+ // Strip remaining HTML tags
126
+ .replace(/<[^>]+>/g, "")
127
+ // Decode common HTML entities
128
+ .replace(/&amp;/g, "&")
129
+ .replace(/&lt;/g, "<")
130
+ .replace(/&gt;/g, ">")
131
+ .replace(/&quot;/g, '"')
132
+ .replace(/&#39;/g, "'")
133
+ .replace(/&nbsp;/g, " ")
134
+ // Normalize whitespace
135
+ .replace(/\n{3,}/g, "\n\n")
136
+ .replace(/[ \t]+/g, " ")
137
+ .trim();
138
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Effort Level Control — Adjusts how deeply the agent analyzes requests.
3
+ *
4
+ * Inspired by Claude Code's --effort flag and Cursor's MAX mode.
5
+ *
6
+ * Effort levels:
7
+ * - low: Quick responses, minimal analysis. Good for simple questions.
8
+ * - medium: Default. Balanced analysis and speed.
9
+ * - high: Deep analysis, reads more files, considers edge cases.
10
+ * - max: Extended thinking, comprehensive analysis, multiple passes.
11
+ *
12
+ * How it affects behavior:
13
+ * - System prompt instructions change based on level
14
+ * - Temperature may be adjusted
15
+ * - Token limits are scaled
16
+ * - The agent is instructed to use more/fewer tools
17
+ *
18
+ * Learning note: This is essentially a UX abstraction over multiple
19
+ * model parameters. Instead of asking users to tweak temperature,
20
+ * max tokens, and system prompt, they just say "try harder" or
21
+ * "be quick about it".
22
+ */
23
+
24
+ /**
25
+ * Available effort levels, from quickest to most thorough.
26
+ */
27
+ export type EffortLevel = "low" | "medium" | "high" | "max";
28
+
29
+ /**
30
+ * Configuration values for each effort level.
31
+ */
32
+ export interface EffortConfig {
33
+ /** How this level affects the system prompt */
34
+ systemPromptAddition: string;
35
+
36
+ /** Temperature override (null = use default) */
37
+ temperature: number | null;
38
+
39
+ /** Max tokens multiplier (1.0 = default) */
40
+ maxTokensMultiplier: number;
41
+
42
+ /** Max agent turns multiplier */
43
+ maxTurnsMultiplier: number;
44
+
45
+ /** Human-readable description */
46
+ description: string;
47
+ }
48
+
49
+ /**
50
+ * Predefined configurations for each effort level.
51
+ *
52
+ * Learning note: These are tuned to balance speed vs thoroughness.
53
+ * Lower effort = faster, cheaper, more concise.
54
+ * Higher effort = slower, more expensive, more comprehensive.
55
+ */
56
+ const EFFORT_CONFIGS: Record<EffortLevel, EffortConfig> = {
57
+ low: {
58
+ systemPromptAddition: [
59
+ "# Effort: Low",
60
+ "Be very concise. Give the shortest correct answer.",
61
+ "- Skip detailed explanations unless asked",
62
+ "- Use the fewest tools possible",
63
+ "- Don't read files you don't need",
64
+ "- One-sentence summaries are fine",
65
+ "- Prefer quick fixes over comprehensive solutions",
66
+ ].join("\n"),
67
+ temperature: null,
68
+ maxTokensMultiplier: 0.5,
69
+ maxTurnsMultiplier: 0.5,
70
+ description: "Quick, minimal analysis",
71
+ },
72
+
73
+ medium: {
74
+ systemPromptAddition: "", // Default behavior, no additions needed
75
+ temperature: null,
76
+ maxTokensMultiplier: 1.0,
77
+ maxTurnsMultiplier: 1.0,
78
+ description: "Balanced (default)",
79
+ },
80
+
81
+ high: {
82
+ systemPromptAddition: [
83
+ "# Effort: High",
84
+ "Take extra care with this task. Be thorough.",
85
+ "- Read all relevant files before making changes",
86
+ "- Consider edge cases and error scenarios",
87
+ "- Verify your changes compile/run correctly",
88
+ "- Explain your reasoning for non-obvious decisions",
89
+ "- Search for related code that might need updating",
90
+ ].join("\n"),
91
+ temperature: null,
92
+ maxTokensMultiplier: 1.5,
93
+ maxTurnsMultiplier: 2.0,
94
+ description: "Deep analysis, thorough",
95
+ },
96
+
97
+ max: {
98
+ systemPromptAddition: [
99
+ "# Effort: Maximum",
100
+ "This is a critical task. Use maximum thoroughness.",
101
+ "- Exhaustively search the codebase for context",
102
+ "- Read ALL related files, tests, and documentation",
103
+ "- Consider architectural implications",
104
+ "- Check for breaking changes across the project",
105
+ "- Run tests and verify everything works",
106
+ "- Think step-by-step before making changes",
107
+ "- Consider multiple approaches and pick the best one",
108
+ "- Add proper error handling and edge case coverage",
109
+ ].join("\n"),
110
+ temperature: null,
111
+ maxTokensMultiplier: 2.0,
112
+ maxTurnsMultiplier: 3.0,
113
+ description: "Maximum thoroughness, extended thinking",
114
+ },
115
+ };
116
+
117
+ /**
118
+ * Manages the current effort level and provides configuration.
119
+ */
120
+ export class EffortManager {
121
+ private level: EffortLevel = "medium";
122
+
123
+ /**
124
+ * Set the effort level.
125
+ */
126
+ setLevel(level: EffortLevel): void {
127
+ if (!EFFORT_CONFIGS[level]) {
128
+ throw new Error(`Invalid effort level: ${level}. Use: low, medium, high, max`);
129
+ }
130
+ this.level = level;
131
+ }
132
+
133
+ /**
134
+ * Get the current effort level.
135
+ */
136
+ getLevel(): EffortLevel {
137
+ return this.level;
138
+ }
139
+
140
+ /**
141
+ * Get the configuration for the current effort level.
142
+ */
143
+ getConfig(): EffortConfig {
144
+ return EFFORT_CONFIGS[this.level];
145
+ }
146
+
147
+ /**
148
+ * Get the system prompt addition for the current level.
149
+ * Returns empty string for medium (default) level.
150
+ */
151
+ getSystemPromptAddition(): string {
152
+ return EFFORT_CONFIGS[this.level].systemPromptAddition;
153
+ }
154
+
155
+ /**
156
+ * Get all available levels with descriptions.
157
+ * Useful for displaying in help or settings UI.
158
+ */
159
+ static getAllLevels(): Array<{ level: EffortLevel; description: string }> {
160
+ return Object.entries(EFFORT_CONFIGS).map(([level, config]) => ({
161
+ level: level as EffortLevel,
162
+ description: config.description,
163
+ }));
164
+ }
165
+
166
+ /**
167
+ * Parse an effort level from a string (case-insensitive).
168
+ * Returns null if the string is not a valid level.
169
+ */
170
+ static parse(input: string): EffortLevel | null {
171
+ const normalized = input.toLowerCase().trim();
172
+ if (normalized in EFFORT_CONFIGS) {
173
+ return normalized as EffortLevel;
174
+ }
175
+ return null;
176
+ }
177
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Hooks System — run user-configured shell commands before/after tool execution.
3
+ *
4
+ * Configuration stored in ~/.cdoing/hooks.json or .cdoing/hooks.json (project-level).
5
+ *
6
+ * Example hooks.json:
7
+ * {
8
+ * "hooks": [
9
+ * { "event": "pre:file_write", "command": "echo 'Writing file: {{file_path}}'" },
10
+ * { "event": "post:shell_exec", "command": "echo 'Command finished'" },
11
+ * { "event": "pre:*", "command": "echo 'Tool called: {{tool_name}}'" }
12
+ * ]
13
+ * }
14
+ */
15
+
16
+ import * as fs from "fs";
17
+ import * as path from "path";
18
+ import * as os from "os";
19
+ import { exec } from "child_process";
20
+
21
+ export interface HookDefinition {
22
+ /** Event pattern: "pre:tool_name", "post:tool_name", "pre:*", "post:*" */
23
+ event: string;
24
+ /** Shell command to execute. Supports {{variable}} placeholders. */
25
+ command: string;
26
+ /** Timeout in ms (default: 10000) */
27
+ timeout?: number;
28
+ }
29
+
30
+ export interface HookResult {
31
+ hook: HookDefinition;
32
+ success: boolean;
33
+ output: string;
34
+ error?: string;
35
+ }
36
+
37
+ export class HookManager {
38
+ private hooks: HookDefinition[] = [];
39
+ private workingDir: string;
40
+
41
+ constructor(workingDir: string) {
42
+ this.workingDir = workingDir;
43
+ this.loadHooks();
44
+ }
45
+
46
+ setWorkingDir(dir: string): void {
47
+ this.workingDir = dir;
48
+ this.loadHooks();
49
+ }
50
+
51
+ private loadHooks(): void {
52
+ this.hooks = [];
53
+
54
+ // Load global hooks
55
+ const globalFile = path.join(os.homedir(), ".cdoing", "hooks.json");
56
+ this.loadFromFile(globalFile);
57
+
58
+ // Load project hooks (overrides/supplements global)
59
+ const projectFile = path.join(this.workingDir, ".cdoing", "hooks.json");
60
+ this.loadFromFile(projectFile);
61
+ }
62
+
63
+ private loadFromFile(filePath: string): void {
64
+ try {
65
+ if (fs.existsSync(filePath)) {
66
+ const data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
67
+ if (Array.isArray(data.hooks)) {
68
+ this.hooks.push(...data.hooks);
69
+ }
70
+ }
71
+ } catch {
72
+ // skip invalid files
73
+ }
74
+ }
75
+
76
+ /** Find hooks matching a given event */
77
+ private findHooks(event: string): HookDefinition[] {
78
+ const [phase, toolName] = event.split(":");
79
+ return this.hooks.filter((h) => {
80
+ const [hPhase, hTool] = h.event.split(":");
81
+ return hPhase === phase && (hTool === "*" || hTool === toolName);
82
+ });
83
+ }
84
+
85
+ /** Run all hooks for an event */
86
+ async runHooks(
87
+ event: string,
88
+ variables: Record<string, string>
89
+ ): Promise<HookResult[]> {
90
+ const matching = this.findHooks(event);
91
+ if (matching.length === 0) return [];
92
+
93
+ const results: HookResult[] = [];
94
+ for (const hook of matching) {
95
+ const result = await this.executeHook(hook, variables);
96
+ results.push(result);
97
+ }
98
+ return results;
99
+ }
100
+
101
+ /** Execute a single hook */
102
+ private executeHook(
103
+ hook: HookDefinition,
104
+ variables: Record<string, string>
105
+ ): Promise<HookResult> {
106
+ // Replace {{variable}} placeholders
107
+ let command = hook.command;
108
+ for (const [key, value] of Object.entries(variables)) {
109
+ command = command.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
110
+ }
111
+
112
+ const timeout = hook.timeout || 10000;
113
+
114
+ return new Promise((resolve) => {
115
+ exec(command, {
116
+ cwd: this.workingDir,
117
+ timeout,
118
+ maxBuffer: 1024 * 1024,
119
+ env: { ...process.env },
120
+ }, (error, stdout, stderr) => {
121
+ if (error) {
122
+ resolve({
123
+ hook,
124
+ success: false,
125
+ output: stdout || "",
126
+ error: stderr || error.message,
127
+ });
128
+ } else {
129
+ resolve({
130
+ hook,
131
+ success: true,
132
+ output: (stdout || "").trim(),
133
+ });
134
+ }
135
+ });
136
+ });
137
+ }
138
+
139
+ /** Check if any hooks are configured */
140
+ hasHooks(): boolean {
141
+ return this.hooks.length > 0;
142
+ }
143
+
144
+ /** Get all configured hooks */
145
+ getHooks(): ReadonlyArray<HookDefinition> {
146
+ return this.hooks;
147
+ }
148
+ }