@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,20 @@
1
+ /**
2
+ * Plan Mode — Read-only planning before execution.
3
+ *
4
+ * When activated (/plan command), the agent:
5
+ * 1. Analyzes the request using read-only tools (file_read, grep, glob)
6
+ * 2. Generates a step-by-step implementation plan as markdown
7
+ * 3. Presents the plan for user review
8
+ * 4. User can approve, edit, or reject before execution
9
+ *
10
+ * The plan is stored as a structured object so it can be:
11
+ * - Displayed as an interactive checklist in VS Code
12
+ * - Edited by the user before approval
13
+ * - Executed step-by-step with progress tracking
14
+ *
15
+ * Learning note: Plan mode is a form of "chain of thought" for the AI.
16
+ * By forcing the agent to plan before acting, it produces better results
17
+ * and gives the user a chance to course-correct before any files change.
18
+ */
19
+
20
+ export { PlanManager, type Plan, type PlanStep, type PlanStatus } from "./manager";
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Plan Manager — Creates, stores, and executes implementation plans.
3
+ *
4
+ * A plan is a structured breakdown of what the agent intends to do.
5
+ * Each step has a description, status, and optional tool call info.
6
+ *
7
+ * Learning note: This follows the Command Pattern — each plan step
8
+ * is a serializable command that can be reviewed before execution.
9
+ */
10
+
11
+ /**
12
+ * Status of the overall plan.
13
+ */
14
+ export type PlanStatus = "drafting" | "pending_approval" | "approved" | "executing" | "completed" | "rejected";
15
+
16
+ /**
17
+ * A single step in the plan.
18
+ */
19
+ export interface PlanStep {
20
+ /** Step number (1-based) */
21
+ number: number;
22
+
23
+ /** What this step will do (human-readable) */
24
+ description: string;
25
+
26
+ /** Which tool to use (e.g., "file_edit", "shell_exec") */
27
+ tool?: string;
28
+
29
+ /** Target file or resource */
30
+ target?: string;
31
+
32
+ /** Current status of this step */
33
+ status: "pending" | "in_progress" | "completed" | "skipped";
34
+
35
+ /** Optional details or notes */
36
+ details?: string;
37
+ }
38
+
39
+ /**
40
+ * A complete implementation plan.
41
+ */
42
+ export interface Plan {
43
+ /** Unique plan ID */
44
+ id: string;
45
+
46
+ /** One-line summary of what the plan achieves */
47
+ summary: string;
48
+
49
+ /** Ordered list of steps */
50
+ steps: PlanStep[];
51
+
52
+ /** Current plan status */
53
+ status: PlanStatus;
54
+
55
+ /** When the plan was created */
56
+ createdAt: number;
57
+
58
+ /** The original user request that generated this plan */
59
+ originalRequest: string;
60
+ }
61
+
62
+ export class PlanManager {
63
+ /** The current active plan (only one at a time) */
64
+ private currentPlan: Plan | null = null;
65
+
66
+ /**
67
+ * Create a new plan from the agent's analysis.
68
+ *
69
+ * @param request - The original user request
70
+ * @param summary - One-line summary
71
+ * @param steps - Ordered list of step descriptions
72
+ * @returns The created plan
73
+ */
74
+ createPlan(request: string, summary: string, steps: string[]): Plan {
75
+ this.currentPlan = {
76
+ id: `plan_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
77
+ summary,
78
+ steps: steps.map((desc, i) => ({
79
+ number: i + 1,
80
+ description: desc,
81
+ status: "pending",
82
+ })),
83
+ status: "pending_approval",
84
+ createdAt: Date.now(),
85
+ originalRequest: request,
86
+ };
87
+
88
+ return this.currentPlan;
89
+ }
90
+
91
+ /**
92
+ * Get the current active plan.
93
+ */
94
+ getCurrentPlan(): Plan | null {
95
+ return this.currentPlan;
96
+ }
97
+
98
+ /**
99
+ * Approve the plan for execution.
100
+ */
101
+ approvePlan(): boolean {
102
+ if (!this.currentPlan || this.currentPlan.status !== "pending_approval") {
103
+ return false;
104
+ }
105
+ this.currentPlan.status = "approved";
106
+ return true;
107
+ }
108
+
109
+ /**
110
+ * Reject the plan.
111
+ */
112
+ rejectPlan(): boolean {
113
+ if (!this.currentPlan) return false;
114
+ this.currentPlan.status = "rejected";
115
+ return true;
116
+ }
117
+
118
+ /**
119
+ * Mark the plan as executing.
120
+ */
121
+ startExecution(): boolean {
122
+ if (!this.currentPlan || this.currentPlan.status !== "approved") {
123
+ return false;
124
+ }
125
+ this.currentPlan.status = "executing";
126
+ return true;
127
+ }
128
+
129
+ /**
130
+ * Update a step's status.
131
+ */
132
+ updateStep(stepNumber: number, status: PlanStep["status"], details?: string): boolean {
133
+ if (!this.currentPlan) return false;
134
+
135
+ const step = this.currentPlan.steps.find((s) => s.number === stepNumber);
136
+ if (!step) return false;
137
+
138
+ step.status = status;
139
+ if (details) step.details = details;
140
+
141
+ // Check if all steps are completed
142
+ const allDone = this.currentPlan.steps.every(
143
+ (s) => s.status === "completed" || s.status === "skipped"
144
+ );
145
+ if (allDone) {
146
+ this.currentPlan.status = "completed";
147
+ }
148
+
149
+ return true;
150
+ }
151
+
152
+ /**
153
+ * Format the plan as markdown for display.
154
+ *
155
+ * Learning note: We use checkbox syntax (- [ ] / - [x]) so the
156
+ * plan looks like an interactive checklist in the chat.
157
+ */
158
+ formatPlan(): string {
159
+ if (!this.currentPlan) return "No active plan.";
160
+
161
+ const plan = this.currentPlan;
162
+ const lines: string[] = [
163
+ `## Plan: ${plan.summary}`,
164
+ "",
165
+ `**Status:** ${this.formatStatus(plan.status)}`,
166
+ "",
167
+ ];
168
+
169
+ for (const step of plan.steps) {
170
+ const checkbox = step.status === "completed" ? "[x]"
171
+ : step.status === "skipped" ? "[-]"
172
+ : step.status === "in_progress" ? "[~]"
173
+ : "[ ]";
174
+
175
+ let line = `${step.number}. ${checkbox} ${step.description}`;
176
+ if (step.tool) line += ` _(${step.tool})_`;
177
+ if (step.target) line += ` → \`${step.target}\``;
178
+ lines.push(line);
179
+
180
+ if (step.details) {
181
+ lines.push(` _${step.details}_`);
182
+ }
183
+ }
184
+
185
+ return lines.join("\n");
186
+ }
187
+
188
+ /**
189
+ * Get the plan as a system prompt addition.
190
+ * Used to guide the agent during execution.
191
+ */
192
+ getPlanPrompt(): string {
193
+ if (!this.currentPlan) return "";
194
+
195
+ const plan = this.currentPlan;
196
+ const stepList = plan.steps
197
+ .map((s) => `${s.number}. [${s.status}] ${s.description}`)
198
+ .join("\n");
199
+
200
+ return [
201
+ "# Active Plan",
202
+ "",
203
+ `Goal: ${plan.summary}`,
204
+ "",
205
+ "Steps:",
206
+ stepList,
207
+ "",
208
+ "Execute the next pending step. After completing each step, update its status.",
209
+ "If a step fails, explain why and suggest alternatives.",
210
+ ].join("\n");
211
+ }
212
+
213
+ /**
214
+ * Clear the current plan.
215
+ */
216
+ clearPlan(): void {
217
+ this.currentPlan = null;
218
+ }
219
+
220
+ /**
221
+ * Format a plan status as a human-readable string.
222
+ */
223
+ private formatStatus(status: PlanStatus): string {
224
+ switch (status) {
225
+ case "drafting": return "Drafting...";
226
+ case "pending_approval": return "Waiting for approval";
227
+ case "approved": return "Approved";
228
+ case "executing": return "Executing...";
229
+ case "completed": return "Completed";
230
+ case "rejected": return "Rejected";
231
+ }
232
+ }
233
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Project Rules — Hierarchical rule system for project-specific AI behavior.
3
+ *
4
+ * Similar to Cursor's .cursor/rules/ and Claude Code's CLAUDE.md,
5
+ * but with glob-based path scoping.
6
+ *
7
+ * Rule hierarchy (highest priority first):
8
+ * 1. Path-specific rules (.cdoing/rules/*.md with glob patterns)
9
+ * 2. Project rules (.cdoing/config.md or CDOING.md)
10
+ * 3. Global rules (~/.cdoing/rules/*.md)
11
+ *
12
+ * Each rule file is a markdown file with optional frontmatter:
13
+ *
14
+ * ---
15
+ * globs: ["*.ts", "src/api/**"]
16
+ * description: Rules for TypeScript API files
17
+ * ---
18
+ *
19
+ * Always use async/await instead of callbacks.
20
+ * Prefer named exports over default exports.
21
+ *
22
+ * Learning note: Glob-based scoping lets you have different coding
23
+ * standards for different parts of your project. For example, strict
24
+ * type rules for API code but relaxed rules for scripts.
25
+ */
26
+
27
+ export { RulesManager } from "./manager";
28
+ export type { Rule, RuleSource } from "./types";
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Rules Manager — Loads, caches, and resolves project rules.
3
+ *
4
+ * Scans rule directories in priority order and returns rules
5
+ * that match the current file context.
6
+ *
7
+ * Learning note: The manager uses lazy loading — rules are only
8
+ * read from disk when first needed, then cached until the file
9
+ * system changes. This prevents slow startup on large projects.
10
+ */
11
+
12
+ import * as fs from "fs";
13
+ import * as path from "path";
14
+ import * as os from "os";
15
+ import { minimatch } from "minimatch";
16
+ import type { Rule, RuleSource, RuleFrontmatter } from "./types";
17
+
18
+ export class RulesManager {
19
+ /** Cached rules, indexed by source directory */
20
+ private cache = new Map<string, Rule[]>();
21
+
22
+ /** Working directory (project root) */
23
+ private workingDir: string;
24
+
25
+ constructor(workingDir: string) {
26
+ this.workingDir = workingDir;
27
+ }
28
+
29
+ /**
30
+ * Get all rules that apply to a given file path.
31
+ * Rules are returned in priority order (most specific first).
32
+ *
33
+ * @param filePath - The file being edited/created (for glob matching)
34
+ * @returns Array of matching rules
35
+ */
36
+ getRulesForFile(filePath?: string): Rule[] {
37
+ const allRules = this.loadAllRules();
38
+
39
+ if (!filePath) {
40
+ // No file context — return all rules without glob restrictions
41
+ return allRules.filter((r) => r.globs.length === 0);
42
+ }
43
+
44
+ // Resolve to relative path for glob matching
45
+ const relativePath = path.isAbsolute(filePath)
46
+ ? path.relative(this.workingDir, filePath)
47
+ : filePath;
48
+
49
+ return allRules.filter((rule) => {
50
+ // Rules without globs apply to everything
51
+ if (rule.globs.length === 0) return true;
52
+
53
+ // Check if any glob pattern matches the file
54
+ return rule.globs.some((glob) => this.matchGlob(relativePath, glob));
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Get all rules formatted as a single string for the system prompt.
60
+ *
61
+ * @param filePath - Optional file context for filtering
62
+ * @returns Formatted rules text, or empty string if no rules
63
+ */
64
+ formatForPrompt(filePath?: string): string {
65
+ const rules = this.getRulesForFile(filePath);
66
+ if (rules.length === 0) return "";
67
+
68
+ const sections = rules.map((rule) => {
69
+ const header = rule.description
70
+ ? `### ${rule.description}`
71
+ : `### Rule from ${path.basename(rule.filePath)}`;
72
+
73
+ const scope = rule.globs.length > 0
74
+ ? `_Applies to: ${rule.globs.join(", ")}_\n`
75
+ : "";
76
+
77
+ return `${header}\n${scope}\n${rule.content}`;
78
+ });
79
+
80
+ return `# Project Rules\n\n${sections.join("\n\n---\n\n")}`;
81
+ }
82
+
83
+ /**
84
+ * Load all rules from all sources.
85
+ * Results are cached — call invalidateCache() to refresh.
86
+ */
87
+ private loadAllRules(): Rule[] {
88
+ const rules: Rule[] = [];
89
+
90
+ // 1. Global rules (~/.cdoing/rules/)
91
+ const globalDir = path.join(os.homedir(), ".cdoing", "rules");
92
+ rules.push(...this.loadRulesFromDir(globalDir, "global"));
93
+
94
+ // 2. Project rules (.cdoing/rules/)
95
+ const projectDir = path.join(this.workingDir, ".cdoing", "rules");
96
+ rules.push(...this.loadRulesFromDir(projectDir, "path-specific"));
97
+
98
+ return rules;
99
+ }
100
+
101
+ /**
102
+ * Load rules from a directory of markdown files.
103
+ *
104
+ * Learning note: Each .md file in the rules directory becomes a rule.
105
+ * YAML frontmatter is parsed for glob patterns and descriptions.
106
+ */
107
+ private loadRulesFromDir(dir: string, source: RuleSource): Rule[] {
108
+ // Check cache
109
+ const cached = this.cache.get(dir);
110
+ if (cached) return cached;
111
+
112
+ const rules: Rule[] = [];
113
+
114
+ if (!fs.existsSync(dir)) {
115
+ this.cache.set(dir, rules);
116
+ return rules;
117
+ }
118
+
119
+ let entries: string[];
120
+ try {
121
+ entries = fs.readdirSync(dir).filter((f) => f.endsWith(".md"));
122
+ } catch {
123
+ this.cache.set(dir, rules);
124
+ return rules;
125
+ }
126
+
127
+ for (const file of entries) {
128
+ const filePath = path.join(dir, file);
129
+ try {
130
+ const content = fs.readFileSync(filePath, "utf-8");
131
+ const parsed = this.parseRuleFile(content);
132
+
133
+ rules.push({
134
+ source,
135
+ filePath,
136
+ globs: parsed.globs,
137
+ description: parsed.description || file.replace(/\.md$/, ""),
138
+ content: parsed.content,
139
+ });
140
+ } catch {
141
+ // Skip unreadable files
142
+ }
143
+ }
144
+
145
+ this.cache.set(dir, rules);
146
+ return rules;
147
+ }
148
+
149
+ /**
150
+ * Parse a rule markdown file, extracting frontmatter and content.
151
+ *
152
+ * Frontmatter format:
153
+ * ---
154
+ * globs: ["*.ts", "src/**"]
155
+ * description: TypeScript coding rules
156
+ * ---
157
+ *
158
+ * Learning note: We use a simple regex-based parser instead of
159
+ * a YAML library to avoid adding dependencies. This handles
160
+ * the common cases well enough.
161
+ */
162
+ private parseRuleFile(raw: string): { globs: string[]; description: string; content: string } {
163
+ const frontmatterMatch = raw.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
164
+
165
+ if (!frontmatterMatch) {
166
+ // No frontmatter — entire file is content
167
+ return { globs: [], description: "", content: raw.trim() };
168
+ }
169
+
170
+ const [, frontmatterStr, content] = frontmatterMatch;
171
+
172
+ // Simple key-value parsing for frontmatter
173
+ let globs: string[] = [];
174
+ let description = "";
175
+
176
+ for (const line of frontmatterStr.split("\n")) {
177
+ const globMatch = line.match(/^globs:\s*\[(.+)\]$/);
178
+ if (globMatch) {
179
+ // Parse glob array: ["*.ts", "src/**"]
180
+ globs = globMatch[1]
181
+ .split(",")
182
+ .map((g) => g.trim().replace(/^["']|["']$/g, ""))
183
+ .filter(Boolean);
184
+ }
185
+
186
+ const globSingle = line.match(/^globs:\s*["'](.+)["']$/);
187
+ if (globSingle) {
188
+ globs = [globSingle[1]];
189
+ }
190
+
191
+ const descMatch = line.match(/^description:\s*(.+)$/);
192
+ if (descMatch) {
193
+ description = descMatch[1].trim().replace(/^["']|["']$/g, "");
194
+ }
195
+ }
196
+
197
+ return { globs, description, content: content.trim() };
198
+ }
199
+
200
+ /**
201
+ * Check if a file path matches a glob pattern.
202
+ * Uses minimatch for proper glob matching.
203
+ */
204
+ private matchGlob(filePath: string, pattern: string): boolean {
205
+ try {
206
+ return minimatch(filePath, pattern, { matchBase: true });
207
+ } catch {
208
+ // If minimatch isn't available, fall back to simple extension matching
209
+ if (pattern.startsWith("*.")) {
210
+ const ext = pattern.slice(1); // e.g., ".ts"
211
+ return filePath.endsWith(ext);
212
+ }
213
+ return filePath.includes(pattern);
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Format rules for CLI display, showing file paths and sources.
219
+ */
220
+ formatForDisplay(): string {
221
+ const allRules = this.loadAllRules();
222
+ if (allRules.length === 0) return "No rules defined.";
223
+
224
+ const globalDir = path.join(os.homedir(), ".cdoing", "rules");
225
+ const projectDir = path.join(this.workingDir, ".cdoing", "rules");
226
+
227
+ const lines: string[] = ["# Rules\n"];
228
+
229
+ // Group by source
230
+ const globalRules = allRules.filter((r) => r.source === "global");
231
+ const projectRules = allRules.filter((r) => r.source === "path-specific");
232
+
233
+ if (globalRules.length > 0) {
234
+ lines.push(`## Global rules (${globalDir}/)`);
235
+ for (const rule of globalRules) {
236
+ const globs = rule.globs.length > 0 ? ` [${rule.globs.join(", ")}]` : "";
237
+ lines.push(` - ${rule.filePath}${globs}`);
238
+ }
239
+ lines.push("");
240
+ } else {
241
+ lines.push(`## Global rules — none found`);
242
+ lines.push(` Directory: ${globalDir}/`);
243
+ lines.push("");
244
+ }
245
+
246
+ if (projectRules.length > 0) {
247
+ lines.push(`## Project rules (${projectDir}/)`);
248
+ for (const rule of projectRules) {
249
+ const globs = rule.globs.length > 0 ? ` [${rule.globs.join(", ")}]` : "";
250
+ lines.push(` - ${rule.filePath}${globs}`);
251
+ }
252
+ lines.push("");
253
+ } else {
254
+ lines.push(`## Project rules — none found`);
255
+ lines.push(` Directory: ${projectDir}/`);
256
+ lines.push("");
257
+ }
258
+
259
+ return lines.join("\n");
260
+ }
261
+
262
+ /**
263
+ * Clear the rule cache (call after file changes).
264
+ */
265
+ invalidateCache(): void {
266
+ this.cache.clear();
267
+ }
268
+
269
+ /**
270
+ * Update the working directory.
271
+ */
272
+ setWorkingDir(dir: string): void {
273
+ this.workingDir = dir;
274
+ this.invalidateCache();
275
+ }
276
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Rule Types — Shared type definitions for the rules system.
3
+ *
4
+ * Learning note: Separating types from implementation keeps
5
+ * the codebase clean and prevents circular imports.
6
+ */
7
+
8
+ /**
9
+ * A single rule definition loaded from a .md file.
10
+ */
11
+ export interface Rule {
12
+ /** Where the rule was loaded from */
13
+ source: RuleSource;
14
+
15
+ /** Absolute path to the rule file */
16
+ filePath: string;
17
+
18
+ /** Glob patterns this rule applies to (empty = applies to all files) */
19
+ globs: string[];
20
+
21
+ /** Human-readable description of what the rule enforces */
22
+ description: string;
23
+
24
+ /** The actual rule content (markdown text) */
25
+ content: string;
26
+ }
27
+
28
+ /**
29
+ * Where a rule was loaded from — determines priority.
30
+ * path-specific > project > global
31
+ */
32
+ export type RuleSource = "global" | "project" | "path-specific";
33
+
34
+ /**
35
+ * Frontmatter parsed from a rule markdown file.
36
+ */
37
+ export interface RuleFrontmatter {
38
+ globs?: string | string[];
39
+ description?: string;
40
+ }