homegraph 0.9.9

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 (549) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +709 -0
  3. package/dist/bin/codegraph.d.ts +26 -0
  4. package/dist/bin/codegraph.d.ts.map +1 -0
  5. package/dist/bin/codegraph.js +1572 -0
  6. package/dist/bin/codegraph.js.map +1 -0
  7. package/dist/bin/homegraph.d.ts +26 -0
  8. package/dist/bin/homegraph.d.ts.map +1 -0
  9. package/dist/bin/homegraph.js +1572 -0
  10. package/dist/bin/homegraph.js.map +1 -0
  11. package/dist/bin/node-version-check.d.ts +37 -0
  12. package/dist/bin/node-version-check.d.ts.map +1 -0
  13. package/dist/bin/node-version-check.js +79 -0
  14. package/dist/bin/node-version-check.js.map +1 -0
  15. package/dist/bin/uninstall.d.ts +14 -0
  16. package/dist/bin/uninstall.d.ts.map +1 -0
  17. package/dist/bin/uninstall.js +36 -0
  18. package/dist/bin/uninstall.js.map +1 -0
  19. package/dist/context/formatter.d.ts +30 -0
  20. package/dist/context/formatter.d.ts.map +1 -0
  21. package/dist/context/formatter.js +263 -0
  22. package/dist/context/formatter.js.map +1 -0
  23. package/dist/context/index.d.ts +119 -0
  24. package/dist/context/index.d.ts.map +1 -0
  25. package/dist/context/index.js +1289 -0
  26. package/dist/context/index.js.map +1 -0
  27. package/dist/context/markers.d.ts +19 -0
  28. package/dist/context/markers.d.ts.map +1 -0
  29. package/dist/context/markers.js +22 -0
  30. package/dist/context/markers.js.map +1 -0
  31. package/dist/db/index.d.ts +101 -0
  32. package/dist/db/index.d.ts.map +1 -0
  33. package/dist/db/index.js +250 -0
  34. package/dist/db/index.js.map +1 -0
  35. package/dist/db/migrations.d.ts +44 -0
  36. package/dist/db/migrations.d.ts.map +1 -0
  37. package/dist/db/migrations.js +131 -0
  38. package/dist/db/migrations.js.map +1 -0
  39. package/dist/db/queries.d.ts +386 -0
  40. package/dist/db/queries.d.ts.map +1 -0
  41. package/dist/db/queries.js +1562 -0
  42. package/dist/db/queries.js.map +1 -0
  43. package/dist/db/schema.sql +151 -0
  44. package/dist/db/sqlite-adapter.d.ts +53 -0
  45. package/dist/db/sqlite-adapter.d.ts.map +1 -0
  46. package/dist/db/sqlite-adapter.js +117 -0
  47. package/dist/db/sqlite-adapter.js.map +1 -0
  48. package/dist/directory.d.ts +57 -0
  49. package/dist/directory.d.ts.map +1 -0
  50. package/dist/directory.js +253 -0
  51. package/dist/directory.js.map +1 -0
  52. package/dist/errors.d.ts +136 -0
  53. package/dist/errors.d.ts.map +1 -0
  54. package/dist/errors.js +219 -0
  55. package/dist/errors.js.map +1 -0
  56. package/dist/extraction/arkanalyzer-extractor.d.ts +6 -0
  57. package/dist/extraction/arkanalyzer-extractor.d.ts.map +1 -0
  58. package/dist/extraction/arkanalyzer-extractor.js +11 -0
  59. package/dist/extraction/arkanalyzer-extractor.js.map +1 -0
  60. package/dist/extraction/arkanalyzer-project.d.ts +20 -0
  61. package/dist/extraction/arkanalyzer-project.d.ts.map +1 -0
  62. package/dist/extraction/arkanalyzer-project.js +596 -0
  63. package/dist/extraction/arkanalyzer-project.js.map +1 -0
  64. package/dist/extraction/context.d.ts +12 -0
  65. package/dist/extraction/context.d.ts.map +1 -0
  66. package/dist/extraction/context.js +29 -0
  67. package/dist/extraction/context.js.map +1 -0
  68. package/dist/extraction/dfm-extractor.d.ts +31 -0
  69. package/dist/extraction/dfm-extractor.d.ts.map +1 -0
  70. package/dist/extraction/dfm-extractor.js +151 -0
  71. package/dist/extraction/dfm-extractor.js.map +1 -0
  72. package/dist/extraction/extraction-version.d.ts +25 -0
  73. package/dist/extraction/extraction-version.d.ts.map +1 -0
  74. package/dist/extraction/extraction-version.js +28 -0
  75. package/dist/extraction/extraction-version.js.map +1 -0
  76. package/dist/extraction/generated-detection.d.ts +30 -0
  77. package/dist/extraction/generated-detection.d.ts.map +1 -0
  78. package/dist/extraction/generated-detection.js +80 -0
  79. package/dist/extraction/generated-detection.js.map +1 -0
  80. package/dist/extraction/grammars.d.ts +108 -0
  81. package/dist/extraction/grammars.d.ts.map +1 -0
  82. package/dist/extraction/grammars.js +465 -0
  83. package/dist/extraction/grammars.js.map +1 -0
  84. package/dist/extraction/index.d.ts +138 -0
  85. package/dist/extraction/index.d.ts.map +1 -0
  86. package/dist/extraction/index.js +1396 -0
  87. package/dist/extraction/index.js.map +1 -0
  88. package/dist/extraction/languages/arkts.d.ts +18 -0
  89. package/dist/extraction/languages/arkts.d.ts.map +1 -0
  90. package/dist/extraction/languages/arkts.js +878 -0
  91. package/dist/extraction/languages/arkts.js.map +1 -0
  92. package/dist/extraction/languages/c-cpp.d.ts +4 -0
  93. package/dist/extraction/languages/c-cpp.d.ts.map +1 -0
  94. package/dist/extraction/languages/c-cpp.js +173 -0
  95. package/dist/extraction/languages/c-cpp.js.map +1 -0
  96. package/dist/extraction/languages/csharp.d.ts +25 -0
  97. package/dist/extraction/languages/csharp.d.ts.map +1 -0
  98. package/dist/extraction/languages/csharp.js +120 -0
  99. package/dist/extraction/languages/csharp.js.map +1 -0
  100. package/dist/extraction/languages/dart.d.ts +3 -0
  101. package/dist/extraction/languages/dart.d.ts.map +1 -0
  102. package/dist/extraction/languages/dart.js +192 -0
  103. package/dist/extraction/languages/dart.js.map +1 -0
  104. package/dist/extraction/languages/go.d.ts +3 -0
  105. package/dist/extraction/languages/go.d.ts.map +1 -0
  106. package/dist/extraction/languages/go.js +74 -0
  107. package/dist/extraction/languages/go.js.map +1 -0
  108. package/dist/extraction/languages/index.d.ts +10 -0
  109. package/dist/extraction/languages/index.d.ts.map +1 -0
  110. package/dist/extraction/languages/index.js +51 -0
  111. package/dist/extraction/languages/index.js.map +1 -0
  112. package/dist/extraction/languages/java.d.ts +3 -0
  113. package/dist/extraction/languages/java.d.ts.map +1 -0
  114. package/dist/extraction/languages/java.js +74 -0
  115. package/dist/extraction/languages/java.js.map +1 -0
  116. package/dist/extraction/languages/javascript.d.ts +3 -0
  117. package/dist/extraction/languages/javascript.d.ts.map +1 -0
  118. package/dist/extraction/languages/javascript.js +90 -0
  119. package/dist/extraction/languages/javascript.js.map +1 -0
  120. package/dist/extraction/languages/kotlin.d.ts +3 -0
  121. package/dist/extraction/languages/kotlin.d.ts.map +1 -0
  122. package/dist/extraction/languages/kotlin.js +285 -0
  123. package/dist/extraction/languages/kotlin.js.map +1 -0
  124. package/dist/extraction/languages/lua.d.ts +3 -0
  125. package/dist/extraction/languages/lua.d.ts.map +1 -0
  126. package/dist/extraction/languages/lua.js +150 -0
  127. package/dist/extraction/languages/lua.js.map +1 -0
  128. package/dist/extraction/languages/luau.d.ts +3 -0
  129. package/dist/extraction/languages/luau.d.ts.map +1 -0
  130. package/dist/extraction/languages/luau.js +37 -0
  131. package/dist/extraction/languages/luau.js.map +1 -0
  132. package/dist/extraction/languages/objc.d.ts +3 -0
  133. package/dist/extraction/languages/objc.d.ts.map +1 -0
  134. package/dist/extraction/languages/objc.js +133 -0
  135. package/dist/extraction/languages/objc.js.map +1 -0
  136. package/dist/extraction/languages/pascal.d.ts +3 -0
  137. package/dist/extraction/languages/pascal.d.ts.map +1 -0
  138. package/dist/extraction/languages/pascal.js +66 -0
  139. package/dist/extraction/languages/pascal.js.map +1 -0
  140. package/dist/extraction/languages/php.d.ts +3 -0
  141. package/dist/extraction/languages/php.d.ts.map +1 -0
  142. package/dist/extraction/languages/php.js +120 -0
  143. package/dist/extraction/languages/php.js.map +1 -0
  144. package/dist/extraction/languages/python.d.ts +3 -0
  145. package/dist/extraction/languages/python.d.ts.map +1 -0
  146. package/dist/extraction/languages/python.js +56 -0
  147. package/dist/extraction/languages/python.js.map +1 -0
  148. package/dist/extraction/languages/ruby.d.ts +3 -0
  149. package/dist/extraction/languages/ruby.d.ts.map +1 -0
  150. package/dist/extraction/languages/ruby.js +149 -0
  151. package/dist/extraction/languages/ruby.js.map +1 -0
  152. package/dist/extraction/languages/rust.d.ts +3 -0
  153. package/dist/extraction/languages/rust.d.ts.map +1 -0
  154. package/dist/extraction/languages/rust.js +113 -0
  155. package/dist/extraction/languages/rust.js.map +1 -0
  156. package/dist/extraction/languages/scala.d.ts +3 -0
  157. package/dist/extraction/languages/scala.d.ts.map +1 -0
  158. package/dist/extraction/languages/scala.js +174 -0
  159. package/dist/extraction/languages/scala.js.map +1 -0
  160. package/dist/extraction/languages/swift.d.ts +3 -0
  161. package/dist/extraction/languages/swift.d.ts.map +1 -0
  162. package/dist/extraction/languages/swift.js +91 -0
  163. package/dist/extraction/languages/swift.js.map +1 -0
  164. package/dist/extraction/languages/typescript.d.ts +3 -0
  165. package/dist/extraction/languages/typescript.d.ts.map +1 -0
  166. package/dist/extraction/languages/typescript.js +129 -0
  167. package/dist/extraction/languages/typescript.js.map +1 -0
  168. package/dist/extraction/liquid-extractor.d.ts +59 -0
  169. package/dist/extraction/liquid-extractor.d.ts.map +1 -0
  170. package/dist/extraction/liquid-extractor.js +354 -0
  171. package/dist/extraction/liquid-extractor.js.map +1 -0
  172. package/dist/extraction/mybatis-extractor.d.ts +48 -0
  173. package/dist/extraction/mybatis-extractor.d.ts.map +1 -0
  174. package/dist/extraction/mybatis-extractor.js +198 -0
  175. package/dist/extraction/mybatis-extractor.js.map +1 -0
  176. package/dist/extraction/parse-worker.d.ts +8 -0
  177. package/dist/extraction/parse-worker.d.ts.map +1 -0
  178. package/dist/extraction/parse-worker.js +94 -0
  179. package/dist/extraction/parse-worker.js.map +1 -0
  180. package/dist/extraction/razor-extractor.d.ts +42 -0
  181. package/dist/extraction/razor-extractor.d.ts.map +1 -0
  182. package/dist/extraction/razor-extractor.js +285 -0
  183. package/dist/extraction/razor-extractor.js.map +1 -0
  184. package/dist/extraction/svelte-extractor.d.ts +56 -0
  185. package/dist/extraction/svelte-extractor.d.ts.map +1 -0
  186. package/dist/extraction/svelte-extractor.js +272 -0
  187. package/dist/extraction/svelte-extractor.js.map +1 -0
  188. package/dist/extraction/tree-sitter-helpers.d.ts +28 -0
  189. package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -0
  190. package/dist/extraction/tree-sitter-helpers.js +103 -0
  191. package/dist/extraction/tree-sitter-helpers.js.map +1 -0
  192. package/dist/extraction/tree-sitter-types.d.ts +210 -0
  193. package/dist/extraction/tree-sitter-types.d.ts.map +1 -0
  194. package/dist/extraction/tree-sitter-types.js +10 -0
  195. package/dist/extraction/tree-sitter-types.js.map +1 -0
  196. package/dist/extraction/tree-sitter.d.ts +455 -0
  197. package/dist/extraction/tree-sitter.d.ts.map +1 -0
  198. package/dist/extraction/tree-sitter.js +4089 -0
  199. package/dist/extraction/tree-sitter.js.map +1 -0
  200. package/dist/extraction/vue-extractor.d.ts +51 -0
  201. package/dist/extraction/vue-extractor.d.ts.map +1 -0
  202. package/dist/extraction/vue-extractor.js +251 -0
  203. package/dist/extraction/vue-extractor.js.map +1 -0
  204. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  205. package/dist/extraction/wasm/tree-sitter-lua.wasm +0 -0
  206. package/dist/extraction/wasm/tree-sitter-luau.wasm +0 -0
  207. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  208. package/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
  209. package/dist/extraction/wasm-runtime-flags.d.ts +38 -0
  210. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -0
  211. package/dist/extraction/wasm-runtime-flags.js +106 -0
  212. package/dist/extraction/wasm-runtime-flags.js.map +1 -0
  213. package/dist/graph/index.d.ts +8 -0
  214. package/dist/graph/index.d.ts.map +1 -0
  215. package/dist/graph/index.js +13 -0
  216. package/dist/graph/index.js.map +1 -0
  217. package/dist/graph/queries.d.ts +106 -0
  218. package/dist/graph/queries.d.ts.map +1 -0
  219. package/dist/graph/queries.js +339 -0
  220. package/dist/graph/queries.js.map +1 -0
  221. package/dist/graph/traversal.d.ts +127 -0
  222. package/dist/graph/traversal.d.ts.map +1 -0
  223. package/dist/graph/traversal.js +531 -0
  224. package/dist/graph/traversal.js.map +1 -0
  225. package/dist/index.d.ts +522 -0
  226. package/dist/index.d.ts.map +1 -0
  227. package/dist/index.js +947 -0
  228. package/dist/index.js.map +1 -0
  229. package/dist/installer/config-writer.d.ts +28 -0
  230. package/dist/installer/config-writer.d.ts.map +1 -0
  231. package/dist/installer/config-writer.js +91 -0
  232. package/dist/installer/config-writer.js.map +1 -0
  233. package/dist/installer/index.d.ts +100 -0
  234. package/dist/installer/index.d.ts.map +1 -0
  235. package/dist/installer/index.js +497 -0
  236. package/dist/installer/index.js.map +1 -0
  237. package/dist/installer/instructions-template.d.ts +18 -0
  238. package/dist/installer/instructions-template.d.ts.map +1 -0
  239. package/dist/installer/instructions-template.js +21 -0
  240. package/dist/installer/instructions-template.js.map +1 -0
  241. package/dist/installer/targets/antigravity.d.ts +57 -0
  242. package/dist/installer/targets/antigravity.d.ts.map +1 -0
  243. package/dist/installer/targets/antigravity.js +308 -0
  244. package/dist/installer/targets/antigravity.js.map +1 -0
  245. package/dist/installer/targets/claude.d.ts +56 -0
  246. package/dist/installer/targets/claude.d.ts.map +1 -0
  247. package/dist/installer/targets/claude.js +388 -0
  248. package/dist/installer/targets/claude.js.map +1 -0
  249. package/dist/installer/targets/codex.d.ts +18 -0
  250. package/dist/installer/targets/codex.d.ts.map +1 -0
  251. package/dist/installer/targets/codex.js +187 -0
  252. package/dist/installer/targets/codex.js.map +1 -0
  253. package/dist/installer/targets/cursor.d.ts +35 -0
  254. package/dist/installer/targets/cursor.d.ts.map +1 -0
  255. package/dist/installer/targets/cursor.js +254 -0
  256. package/dist/installer/targets/cursor.js.map +1 -0
  257. package/dist/installer/targets/gemini.d.ts +26 -0
  258. package/dist/installer/targets/gemini.d.ts.map +1 -0
  259. package/dist/installer/targets/gemini.js +167 -0
  260. package/dist/installer/targets/gemini.js.map +1 -0
  261. package/dist/installer/targets/hermes.d.ts +18 -0
  262. package/dist/installer/targets/hermes.d.ts.map +1 -0
  263. package/dist/installer/targets/hermes.js +359 -0
  264. package/dist/installer/targets/hermes.js.map +1 -0
  265. package/dist/installer/targets/kiro.d.ts +27 -0
  266. package/dist/installer/targets/kiro.d.ts.map +1 -0
  267. package/dist/installer/targets/kiro.js +178 -0
  268. package/dist/installer/targets/kiro.js.map +1 -0
  269. package/dist/installer/targets/opencode.d.ts +30 -0
  270. package/dist/installer/targets/opencode.d.ts.map +1 -0
  271. package/dist/installer/targets/opencode.js +237 -0
  272. package/dist/installer/targets/opencode.js.map +1 -0
  273. package/dist/installer/targets/registry.d.ts +35 -0
  274. package/dist/installer/targets/registry.d.ts.map +1 -0
  275. package/dist/installer/targets/registry.js +91 -0
  276. package/dist/installer/targets/registry.js.map +1 -0
  277. package/dist/installer/targets/shared.d.ts +77 -0
  278. package/dist/installer/targets/shared.d.ts.map +1 -0
  279. package/dist/installer/targets/shared.js +247 -0
  280. package/dist/installer/targets/shared.js.map +1 -0
  281. package/dist/installer/targets/toml.d.ts +52 -0
  282. package/dist/installer/targets/toml.d.ts.map +1 -0
  283. package/dist/installer/targets/toml.js +147 -0
  284. package/dist/installer/targets/toml.js.map +1 -0
  285. package/dist/installer/targets/types.d.ts +101 -0
  286. package/dist/installer/targets/types.d.ts.map +1 -0
  287. package/dist/installer/targets/types.js +16 -0
  288. package/dist/installer/targets/types.js.map +1 -0
  289. package/dist/mcp/daemon-paths.d.ts +46 -0
  290. package/dist/mcp/daemon-paths.d.ts.map +1 -0
  291. package/dist/mcp/daemon-paths.js +125 -0
  292. package/dist/mcp/daemon-paths.js.map +1 -0
  293. package/dist/mcp/daemon.d.ts +220 -0
  294. package/dist/mcp/daemon.d.ts.map +1 -0
  295. package/dist/mcp/daemon.js +616 -0
  296. package/dist/mcp/daemon.js.map +1 -0
  297. package/dist/mcp/engine.d.ts +105 -0
  298. package/dist/mcp/engine.d.ts.map +1 -0
  299. package/dist/mcp/engine.js +270 -0
  300. package/dist/mcp/engine.js.map +1 -0
  301. package/dist/mcp/index.d.ts +112 -0
  302. package/dist/mcp/index.d.ts.map +1 -0
  303. package/dist/mcp/index.js +478 -0
  304. package/dist/mcp/index.js.map +1 -0
  305. package/dist/mcp/ppid-watchdog.d.ts +44 -0
  306. package/dist/mcp/ppid-watchdog.d.ts.map +1 -0
  307. package/dist/mcp/ppid-watchdog.js +27 -0
  308. package/dist/mcp/ppid-watchdog.js.map +1 -0
  309. package/dist/mcp/proxy.d.ts +81 -0
  310. package/dist/mcp/proxy.d.ts.map +1 -0
  311. package/dist/mcp/proxy.js +584 -0
  312. package/dist/mcp/proxy.js.map +1 -0
  313. package/dist/mcp/server-instructions.d.ts +19 -0
  314. package/dist/mcp/server-instructions.d.ts.map +1 -0
  315. package/dist/mcp/server-instructions.js +74 -0
  316. package/dist/mcp/server-instructions.js.map +1 -0
  317. package/dist/mcp/session.d.ts +77 -0
  318. package/dist/mcp/session.d.ts.map +1 -0
  319. package/dist/mcp/session.js +294 -0
  320. package/dist/mcp/session.js.map +1 -0
  321. package/dist/mcp/tools.d.ts +413 -0
  322. package/dist/mcp/tools.d.ts.map +1 -0
  323. package/dist/mcp/tools.js +3049 -0
  324. package/dist/mcp/tools.js.map +1 -0
  325. package/dist/mcp/transport.d.ts +188 -0
  326. package/dist/mcp/transport.d.ts.map +1 -0
  327. package/dist/mcp/transport.js +343 -0
  328. package/dist/mcp/transport.js.map +1 -0
  329. package/dist/mcp/version.d.ts +19 -0
  330. package/dist/mcp/version.d.ts.map +1 -0
  331. package/dist/mcp/version.js +71 -0
  332. package/dist/mcp/version.js.map +1 -0
  333. package/dist/resolution/callback-synthesizer.d.ts +10 -0
  334. package/dist/resolution/callback-synthesizer.d.ts.map +1 -0
  335. package/dist/resolution/callback-synthesizer.js +1818 -0
  336. package/dist/resolution/callback-synthesizer.js.map +1 -0
  337. package/dist/resolution/frameworks/cargo-workspace.d.ts +18 -0
  338. package/dist/resolution/frameworks/cargo-workspace.d.ts.map +1 -0
  339. package/dist/resolution/frameworks/cargo-workspace.js +225 -0
  340. package/dist/resolution/frameworks/cargo-workspace.js.map +1 -0
  341. package/dist/resolution/frameworks/csharp.d.ts +8 -0
  342. package/dist/resolution/frameworks/csharp.d.ts.map +1 -0
  343. package/dist/resolution/frameworks/csharp.js +241 -0
  344. package/dist/resolution/frameworks/csharp.js.map +1 -0
  345. package/dist/resolution/frameworks/drupal.d.ts +51 -0
  346. package/dist/resolution/frameworks/drupal.d.ts.map +1 -0
  347. package/dist/resolution/frameworks/drupal.js +367 -0
  348. package/dist/resolution/frameworks/drupal.js.map +1 -0
  349. package/dist/resolution/frameworks/expo-modules.d.ts +3 -0
  350. package/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
  351. package/dist/resolution/frameworks/expo-modules.js +148 -0
  352. package/dist/resolution/frameworks/expo-modules.js.map +1 -0
  353. package/dist/resolution/frameworks/express.d.ts +8 -0
  354. package/dist/resolution/frameworks/express.d.ts.map +1 -0
  355. package/dist/resolution/frameworks/express.js +308 -0
  356. package/dist/resolution/frameworks/express.js.map +1 -0
  357. package/dist/resolution/frameworks/fabric.d.ts +3 -0
  358. package/dist/resolution/frameworks/fabric.d.ts.map +1 -0
  359. package/dist/resolution/frameworks/fabric.js +354 -0
  360. package/dist/resolution/frameworks/fabric.js.map +1 -0
  361. package/dist/resolution/frameworks/go.d.ts +8 -0
  362. package/dist/resolution/frameworks/go.d.ts.map +1 -0
  363. package/dist/resolution/frameworks/go.js +161 -0
  364. package/dist/resolution/frameworks/go.js.map +1 -0
  365. package/dist/resolution/frameworks/index.d.ts +48 -0
  366. package/dist/resolution/frameworks/index.d.ts.map +1 -0
  367. package/dist/resolution/frameworks/index.js +161 -0
  368. package/dist/resolution/frameworks/index.js.map +1 -0
  369. package/dist/resolution/frameworks/java.d.ts +8 -0
  370. package/dist/resolution/frameworks/java.d.ts.map +1 -0
  371. package/dist/resolution/frameworks/java.js +504 -0
  372. package/dist/resolution/frameworks/java.js.map +1 -0
  373. package/dist/resolution/frameworks/laravel.d.ts +13 -0
  374. package/dist/resolution/frameworks/laravel.d.ts.map +1 -0
  375. package/dist/resolution/frameworks/laravel.js +257 -0
  376. package/dist/resolution/frameworks/laravel.js.map +1 -0
  377. package/dist/resolution/frameworks/nestjs.d.ts +26 -0
  378. package/dist/resolution/frameworks/nestjs.d.ts.map +1 -0
  379. package/dist/resolution/frameworks/nestjs.js +698 -0
  380. package/dist/resolution/frameworks/nestjs.js.map +1 -0
  381. package/dist/resolution/frameworks/play.d.ts +19 -0
  382. package/dist/resolution/frameworks/play.d.ts.map +1 -0
  383. package/dist/resolution/frameworks/play.js +111 -0
  384. package/dist/resolution/frameworks/play.js.map +1 -0
  385. package/dist/resolution/frameworks/python.d.ts +10 -0
  386. package/dist/resolution/frameworks/python.d.ts.map +1 -0
  387. package/dist/resolution/frameworks/python.js +400 -0
  388. package/dist/resolution/frameworks/python.js.map +1 -0
  389. package/dist/resolution/frameworks/react-native.d.ts +3 -0
  390. package/dist/resolution/frameworks/react-native.d.ts.map +1 -0
  391. package/dist/resolution/frameworks/react-native.js +410 -0
  392. package/dist/resolution/frameworks/react-native.js.map +1 -0
  393. package/dist/resolution/frameworks/react.d.ts +8 -0
  394. package/dist/resolution/frameworks/react.d.ts.map +1 -0
  395. package/dist/resolution/frameworks/react.js +365 -0
  396. package/dist/resolution/frameworks/react.js.map +1 -0
  397. package/dist/resolution/frameworks/ruby.d.ts +8 -0
  398. package/dist/resolution/frameworks/ruby.d.ts.map +1 -0
  399. package/dist/resolution/frameworks/ruby.js +302 -0
  400. package/dist/resolution/frameworks/ruby.js.map +1 -0
  401. package/dist/resolution/frameworks/rust.d.ts +8 -0
  402. package/dist/resolution/frameworks/rust.d.ts.map +1 -0
  403. package/dist/resolution/frameworks/rust.js +304 -0
  404. package/dist/resolution/frameworks/rust.js.map +1 -0
  405. package/dist/resolution/frameworks/svelte.d.ts +9 -0
  406. package/dist/resolution/frameworks/svelte.d.ts.map +1 -0
  407. package/dist/resolution/frameworks/svelte.js +249 -0
  408. package/dist/resolution/frameworks/svelte.js.map +1 -0
  409. package/dist/resolution/frameworks/swift-objc.d.ts +37 -0
  410. package/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
  411. package/dist/resolution/frameworks/swift-objc.js +252 -0
  412. package/dist/resolution/frameworks/swift-objc.js.map +1 -0
  413. package/dist/resolution/frameworks/swift.d.ts +10 -0
  414. package/dist/resolution/frameworks/swift.d.ts.map +1 -0
  415. package/dist/resolution/frameworks/swift.js +400 -0
  416. package/dist/resolution/frameworks/swift.js.map +1 -0
  417. package/dist/resolution/frameworks/vue.d.ts +9 -0
  418. package/dist/resolution/frameworks/vue.d.ts.map +1 -0
  419. package/dist/resolution/frameworks/vue.js +306 -0
  420. package/dist/resolution/frameworks/vue.js.map +1 -0
  421. package/dist/resolution/go-module.d.ts +26 -0
  422. package/dist/resolution/go-module.d.ts.map +1 -0
  423. package/dist/resolution/go-module.js +78 -0
  424. package/dist/resolution/go-module.js.map +1 -0
  425. package/dist/resolution/import-resolver.d.ts +68 -0
  426. package/dist/resolution/import-resolver.d.ts.map +1 -0
  427. package/dist/resolution/import-resolver.js +1726 -0
  428. package/dist/resolution/import-resolver.js.map +1 -0
  429. package/dist/resolution/index.d.ts +159 -0
  430. package/dist/resolution/index.d.ts.map +1 -0
  431. package/dist/resolution/index.js +1025 -0
  432. package/dist/resolution/index.js.map +1 -0
  433. package/dist/resolution/lru-cache.d.ts +24 -0
  434. package/dist/resolution/lru-cache.d.ts.map +1 -0
  435. package/dist/resolution/lru-cache.js +62 -0
  436. package/dist/resolution/lru-cache.js.map +1 -0
  437. package/dist/resolution/name-matcher.d.ts +52 -0
  438. package/dist/resolution/name-matcher.d.ts.map +1 -0
  439. package/dist/resolution/name-matcher.js +707 -0
  440. package/dist/resolution/name-matcher.js.map +1 -0
  441. package/dist/resolution/path-aliases.d.ts +68 -0
  442. package/dist/resolution/path-aliases.d.ts.map +1 -0
  443. package/dist/resolution/path-aliases.js +238 -0
  444. package/dist/resolution/path-aliases.js.map +1 -0
  445. package/dist/resolution/strip-comments.d.ts +27 -0
  446. package/dist/resolution/strip-comments.d.ts.map +1 -0
  447. package/dist/resolution/strip-comments.js +441 -0
  448. package/dist/resolution/strip-comments.js.map +1 -0
  449. package/dist/resolution/swift-objc-bridge.d.ts +134 -0
  450. package/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
  451. package/dist/resolution/swift-objc-bridge.js +256 -0
  452. package/dist/resolution/swift-objc-bridge.js.map +1 -0
  453. package/dist/resolution/types.d.ts +216 -0
  454. package/dist/resolution/types.d.ts.map +1 -0
  455. package/dist/resolution/types.js +8 -0
  456. package/dist/resolution/types.js.map +1 -0
  457. package/dist/resolution/workspace-packages.d.ts +48 -0
  458. package/dist/resolution/workspace-packages.d.ts.map +1 -0
  459. package/dist/resolution/workspace-packages.js +208 -0
  460. package/dist/resolution/workspace-packages.js.map +1 -0
  461. package/dist/search/query-parser.d.ts +57 -0
  462. package/dist/search/query-parser.d.ts.map +1 -0
  463. package/dist/search/query-parser.js +177 -0
  464. package/dist/search/query-parser.js.map +1 -0
  465. package/dist/search/query-utils.d.ts +71 -0
  466. package/dist/search/query-utils.d.ts.map +1 -0
  467. package/dist/search/query-utils.js +380 -0
  468. package/dist/search/query-utils.js.map +1 -0
  469. package/dist/sync/git-hooks.d.ts +45 -0
  470. package/dist/sync/git-hooks.d.ts.map +1 -0
  471. package/dist/sync/git-hooks.js +225 -0
  472. package/dist/sync/git-hooks.js.map +1 -0
  473. package/dist/sync/index.d.ts +19 -0
  474. package/dist/sync/index.d.ts.map +1 -0
  475. package/dist/sync/index.js +35 -0
  476. package/dist/sync/index.js.map +1 -0
  477. package/dist/sync/watch-policy.d.ts +48 -0
  478. package/dist/sync/watch-policy.d.ts.map +1 -0
  479. package/dist/sync/watch-policy.js +124 -0
  480. package/dist/sync/watch-policy.js.map +1 -0
  481. package/dist/sync/watcher.d.ts +283 -0
  482. package/dist/sync/watcher.d.ts.map +1 -0
  483. package/dist/sync/watcher.js +606 -0
  484. package/dist/sync/watcher.js.map +1 -0
  485. package/dist/sync/worktree.d.ts +54 -0
  486. package/dist/sync/worktree.d.ts.map +1 -0
  487. package/dist/sync/worktree.js +137 -0
  488. package/dist/sync/worktree.js.map +1 -0
  489. package/dist/types.d.ts +377 -0
  490. package/dist/types.d.ts.map +1 -0
  491. package/dist/types.js +80 -0
  492. package/dist/types.js.map +1 -0
  493. package/dist/ui/glyphs.d.ts +42 -0
  494. package/dist/ui/glyphs.d.ts.map +1 -0
  495. package/dist/ui/glyphs.js +78 -0
  496. package/dist/ui/glyphs.js.map +1 -0
  497. package/dist/ui/shimmer-progress.d.ts +11 -0
  498. package/dist/ui/shimmer-progress.d.ts.map +1 -0
  499. package/dist/ui/shimmer-progress.js +90 -0
  500. package/dist/ui/shimmer-progress.js.map +1 -0
  501. package/dist/ui/shimmer-worker.d.ts +2 -0
  502. package/dist/ui/shimmer-worker.d.ts.map +1 -0
  503. package/dist/ui/shimmer-worker.js +118 -0
  504. package/dist/ui/shimmer-worker.js.map +1 -0
  505. package/dist/ui/types.d.ts +17 -0
  506. package/dist/ui/types.d.ts.map +1 -0
  507. package/dist/ui/types.js +3 -0
  508. package/dist/ui/types.js.map +1 -0
  509. package/dist/upgrade/index.d.ts +132 -0
  510. package/dist/upgrade/index.d.ts.map +1 -0
  511. package/dist/upgrade/index.js +462 -0
  512. package/dist/upgrade/index.js.map +1 -0
  513. package/dist/utils.d.ts +205 -0
  514. package/dist/utils.d.ts.map +1 -0
  515. package/dist/utils.js +549 -0
  516. package/dist/utils.js.map +1 -0
  517. package/package.json +57 -0
  518. package/scripts/add-lang/bench.sh +60 -0
  519. package/scripts/add-lang/check-grammar.mjs +75 -0
  520. package/scripts/add-lang/dump-ast.mjs +103 -0
  521. package/scripts/add-lang/verify-extraction.mjs +70 -0
  522. package/scripts/agent-eval/arms-F.sh +21 -0
  523. package/scripts/agent-eval/arms-matrix.sh +37 -0
  524. package/scripts/agent-eval/audit.sh +68 -0
  525. package/scripts/agent-eval/bench-readme.sh +28 -0
  526. package/scripts/agent-eval/bench-why-repo.sh +22 -0
  527. package/scripts/agent-eval/block-read-hook.sh +19 -0
  528. package/scripts/agent-eval/hook-settings.json +15 -0
  529. package/scripts/agent-eval/itrun.sh +120 -0
  530. package/scripts/agent-eval/parse-arms.mjs +116 -0
  531. package/scripts/agent-eval/parse-bench-readme.mjs +84 -0
  532. package/scripts/agent-eval/parse-run.mjs +45 -0
  533. package/scripts/agent-eval/parse-session.mjs +93 -0
  534. package/scripts/agent-eval/probe-context.mjs +21 -0
  535. package/scripts/agent-eval/probe-explore.mjs +40 -0
  536. package/scripts/agent-eval/probe-node.mjs +20 -0
  537. package/scripts/agent-eval/probe-sweep.mjs +119 -0
  538. package/scripts/agent-eval/probe-trace.mjs +20 -0
  539. package/scripts/agent-eval/run-agent.sh +34 -0
  540. package/scripts/agent-eval/run-all.sh +67 -0
  541. package/scripts/agent-eval/run-arms.sh +56 -0
  542. package/scripts/agent-eval/seq-matrix.mjs +137 -0
  543. package/scripts/build-bundle.sh +118 -0
  544. package/scripts/extract-release-notes.mjs +130 -0
  545. package/scripts/local-install.sh +41 -0
  546. package/scripts/npm-sdk.js +75 -0
  547. package/scripts/npm-shim.js +246 -0
  548. package/scripts/pack-npm.sh +119 -0
  549. package/scripts/prepare-release.mjs +270 -0
@@ -0,0 +1,1572 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * CodeGraph CLI
5
+ *
6
+ * Command-line interface for CodeGraph code intelligence.
7
+ *
8
+ * Usage:
9
+ * codegraph Run interactive installer (when no args)
10
+ * codegraph install Run interactive installer
11
+ * codegraph uninstall Remove CodeGraph from your agents
12
+ * codegraph init [path] Initialize CodeGraph in a project
13
+ * codegraph uninit [path] Remove CodeGraph from a project
14
+ * codegraph index [path] Index all files in the project
15
+ * codegraph sync [path] Sync changes since last index
16
+ * codegraph status [path] Show index status
17
+ * codegraph query <search> Search for symbols
18
+ * codegraph files [options] Show project file structure
19
+ * codegraph context <task> Build context for a task
20
+ * codegraph callers <symbol> Find what calls a function/method
21
+ * codegraph callees <symbol> Find what a function/method calls
22
+ * codegraph impact <symbol> Analyze what code is affected by changing a symbol
23
+ * codegraph affected [files] Find test files affected by changes
24
+ * codegraph upgrade [version] Update CodeGraph to the latest release
25
+ */
26
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ var desc = Object.getOwnPropertyDescriptor(m, k);
29
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
30
+ desc = { enumerable: true, get: function() { return m[k]; } };
31
+ }
32
+ Object.defineProperty(o, k2, desc);
33
+ }) : (function(o, m, k, k2) {
34
+ if (k2 === undefined) k2 = k;
35
+ o[k2] = m[k];
36
+ }));
37
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
38
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
39
+ }) : function(o, v) {
40
+ o["default"] = v;
41
+ });
42
+ var __importStar = (this && this.__importStar) || (function () {
43
+ var ownKeys = function(o) {
44
+ ownKeys = Object.getOwnPropertyNames || function (o) {
45
+ var ar = [];
46
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
47
+ return ar;
48
+ };
49
+ return ownKeys(o);
50
+ };
51
+ return function (mod) {
52
+ if (mod && mod.__esModule) return mod;
53
+ var result = {};
54
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
55
+ __setModuleDefault(result, mod);
56
+ return result;
57
+ };
58
+ })();
59
+ Object.defineProperty(exports, "__esModule", { value: true });
60
+ const commander_1 = require("commander");
61
+ const path = __importStar(require("path"));
62
+ const fs = __importStar(require("fs"));
63
+ const directory_1 = require("../directory");
64
+ const worktree_1 = require("../sync/worktree");
65
+ const shimmer_progress_1 = require("../ui/shimmer-progress");
66
+ const glyphs_1 = require("../ui/glyphs");
67
+ const node_version_check_1 = require("./node-version-check");
68
+ const wasm_runtime_flags_1 = require("../extraction/wasm-runtime-flags");
69
+ const extraction_version_1 = require("../extraction/extraction-version");
70
+ // Lazy-load heavy modules (CodeGraph, runInstaller) to keep CLI startup fast.
71
+ async function loadCodeGraph() {
72
+ try {
73
+ return await Promise.resolve().then(() => __importStar(require('../index')));
74
+ }
75
+ catch (err) {
76
+ const msg = err instanceof Error ? err.message : String(err);
77
+ console.error(`\x1b[31m${(0, glyphs_1.getGlyphs)().err}\x1b[0m Failed to load CodeGraph modules.`);
78
+ console.error(`\n Node: ${process.version} Platform: ${process.platform} ${process.arch}`);
79
+ console.error(`\n Error: ${msg}`);
80
+ console.error('\n Try reinstalling with: npm install -g @colbymchenry/codegraph\n');
81
+ process.exit(1);
82
+ }
83
+ }
84
+ // Dynamic import helper — tsc compiles import() to require() in CJS mode,
85
+ // which fails for ESM-only packages. This bypasses the transformation.
86
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
87
+ const importESM = new Function('specifier', 'return import(specifier)');
88
+ // Block CodeGraph on Node.js 25.x — V8's turboshaft WASM JIT has a Zone
89
+ // allocator bug that reliably crashes when compiling tree-sitter
90
+ // grammars (see #54, #81, #140). The previous behaviour was a soft
91
+ // console.warn that scrolls off-screen before the OOM crash 30 seconds
92
+ // later, leading to a steady stream of "what is this OOM" reports.
93
+ // Hard-exit before any WASM work; allow override via env var for users
94
+ // who patched V8 themselves or want to test a future fix.
95
+ const nodeVersion = process.versions.node;
96
+ const nodeMajor = parseInt(nodeVersion.split('.')[0] ?? '0', 10);
97
+ if (nodeMajor >= 25) {
98
+ process.stderr.write((0, node_version_check_1.buildNode25BlockBanner)(nodeVersion) + '\n');
99
+ if (!process.env.CODEGRAPH_ALLOW_UNSAFE_NODE) {
100
+ process.exit(1);
101
+ }
102
+ // Override active — banner shown for visibility, continuing.
103
+ }
104
+ // Enforce the supported Node floor. `engines` in package.json only *warns* on
105
+ // install (unless engine-strict), so hard-block here to actually keep users off
106
+ // unsupported versions. Mirrors the 25+ block above. See package.json `engines`.
107
+ if (nodeMajor < node_version_check_1.MIN_NODE_MAJOR) {
108
+ process.stderr.write((0, node_version_check_1.buildNodeTooOldBanner)(nodeVersion) + '\n');
109
+ if (!process.env.CODEGRAPH_ALLOW_UNSAFE_NODE) {
110
+ process.exit(1);
111
+ }
112
+ // Override active — banner shown for visibility, continuing.
113
+ }
114
+ // Re-exec with V8's `--liftoff-only` if it isn't already set, so tree-sitter's
115
+ // large WASM grammars never hit the turboshaft Zone OOM (`Fatal process out of
116
+ // memory: Zone`) on Node >= 22. No-op under the bundled launcher, which already
117
+ // passes the flag. Must run before any grammar (in the parse worker, which
118
+ // inherits this process's flags) is compiled. See ../extraction/wasm-runtime-flags.
119
+ (0, wasm_runtime_flags_1.relaunchWithWasmRuntimeFlagsIfNeeded)(__filename);
120
+ // Check if running with no arguments - run installer
121
+ if (process.argv.length === 2) {
122
+ Promise.resolve().then(() => __importStar(require('../installer'))).then(({ runInstaller }) => runInstaller()).catch((err) => {
123
+ console.error('Installation failed:', err instanceof Error ? err.message : String(err));
124
+ process.exit(1);
125
+ });
126
+ }
127
+ else {
128
+ // Normal CLI flow
129
+ main();
130
+ }
131
+ process.on('uncaughtException', (error) => {
132
+ console.error('[CodeGraph] Uncaught exception:', error);
133
+ });
134
+ process.on('unhandledRejection', (reason) => {
135
+ console.error('[CodeGraph] Unhandled rejection:', reason);
136
+ });
137
+ function main() {
138
+ const program = new commander_1.Command();
139
+ // Version from package.json
140
+ const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf-8'));
141
+ // =============================================================================
142
+ // ANSI Color Helpers (avoid chalk ESM issues)
143
+ // =============================================================================
144
+ const colors = {
145
+ reset: '\x1b[0m',
146
+ bold: '\x1b[1m',
147
+ dim: '\x1b[2m',
148
+ red: '\x1b[31m',
149
+ green: '\x1b[32m',
150
+ yellow: '\x1b[33m',
151
+ blue: '\x1b[34m',
152
+ cyan: '\x1b[36m',
153
+ white: '\x1b[37m',
154
+ gray: '\x1b[90m',
155
+ };
156
+ const chalk = {
157
+ bold: (s) => `${colors.bold}${s}${colors.reset}`,
158
+ dim: (s) => `${colors.dim}${s}${colors.reset}`,
159
+ red: (s) => `${colors.red}${s}${colors.reset}`,
160
+ green: (s) => `${colors.green}${s}${colors.reset}`,
161
+ yellow: (s) => `${colors.yellow}${s}${colors.reset}`,
162
+ blue: (s) => `${colors.blue}${s}${colors.reset}`,
163
+ cyan: (s) => `${colors.cyan}${s}${colors.reset}`,
164
+ white: (s) => `${colors.white}${s}${colors.reset}`,
165
+ gray: (s) => `${colors.gray}${s}${colors.reset}`,
166
+ };
167
+ program
168
+ .name('codegraph')
169
+ .description('Code intelligence and knowledge graph for any codebase')
170
+ .version(packageJson.version);
171
+ // =============================================================================
172
+ // Helper Functions
173
+ // =============================================================================
174
+ /**
175
+ * Resolve project path from argument or current directory
176
+ * Walks up parent directories to find nearest initialized CodeGraph project
177
+ * (must have .codegraph/codegraph.db, not just .codegraph/lessons.db)
178
+ */
179
+ function resolveProjectPath(pathArg) {
180
+ const absolutePath = path.resolve(pathArg || process.cwd());
181
+ // If exact path is initialized (has codegraph.db), use it
182
+ if ((0, directory_1.isInitialized)(absolutePath)) {
183
+ return absolutePath;
184
+ }
185
+ // Walk up to find nearest parent with CodeGraph initialized
186
+ // Note: findNearestCodeGraphRoot finds any .codegraph folder, but we need one with codegraph.db
187
+ let current = absolutePath;
188
+ const root = path.parse(current).root;
189
+ while (current !== root) {
190
+ const parent = path.dirname(current);
191
+ if (parent === current)
192
+ break;
193
+ current = parent;
194
+ if ((0, directory_1.isInitialized)(current)) {
195
+ return current;
196
+ }
197
+ }
198
+ // Not found - return original path (will fail later with helpful error)
199
+ return absolutePath;
200
+ }
201
+ /**
202
+ * Format a number with commas
203
+ */
204
+ function formatNumber(n) {
205
+ return n.toLocaleString();
206
+ }
207
+ /**
208
+ * Format duration in milliseconds to human readable
209
+ */
210
+ function formatDuration(ms) {
211
+ if (ms < 1000) {
212
+ return `${ms}ms`;
213
+ }
214
+ const seconds = ms / 1000;
215
+ if (seconds < 60) {
216
+ return `${seconds.toFixed(1)}s`;
217
+ }
218
+ const minutes = Math.floor(seconds / 60);
219
+ const remainingSeconds = seconds % 60;
220
+ return `${minutes}m ${remainingSeconds.toFixed(0)}s`;
221
+ }
222
+ // Shimmer progress renderer (runs in a worker thread for smooth animation)
223
+ // Imported at top of file from '../ui/shimmer-progress'
224
+ /**
225
+ * Create a plain-text progress callback for --verbose mode.
226
+ * No animations, no ANSI tricks — just timestamped lines to stdout.
227
+ */
228
+ function createVerboseProgress() {
229
+ let lastPhase = '';
230
+ let lastPct = -1;
231
+ const startTime = Date.now();
232
+ return (progress) => {
233
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
234
+ if (progress.phase !== lastPhase) {
235
+ lastPhase = progress.phase;
236
+ lastPct = -1;
237
+ console.log(`[${elapsed}s] Phase: ${progress.phase}`);
238
+ }
239
+ if (progress.total > 0) {
240
+ const pct = Math.floor((progress.current / progress.total) * 100);
241
+ // Log every 5% to keep output manageable
242
+ if (pct >= lastPct + 5 || progress.current === progress.total) {
243
+ lastPct = pct;
244
+ console.log(`[${elapsed}s] ${progress.current}/${progress.total} (${pct}%)${progress.currentFile ? ` ${(0, glyphs_1.getGlyphs)().dash} ${progress.currentFile}` : ''}`);
245
+ }
246
+ }
247
+ else if (progress.current > 0) {
248
+ // Scanning phase (no total yet) — log periodically
249
+ if (progress.current % 1000 === 0 || progress.current === 1) {
250
+ console.log(`[${elapsed}s] ${formatNumber(progress.current)} files found`);
251
+ }
252
+ }
253
+ };
254
+ }
255
+ /**
256
+ * Print success message
257
+ */
258
+ function success(message) {
259
+ console.log(chalk.green((0, glyphs_1.getGlyphs)().ok) + ' ' + message);
260
+ }
261
+ /**
262
+ * Print error message
263
+ */
264
+ function error(message) {
265
+ console.error(chalk.red((0, glyphs_1.getGlyphs)().err) + ' ' + message);
266
+ }
267
+ /**
268
+ * Print info message
269
+ */
270
+ function info(message) {
271
+ console.log(chalk.blue((0, glyphs_1.getGlyphs)().info) + ' ' + message);
272
+ }
273
+ /**
274
+ * Print warning message
275
+ */
276
+ function warn(message) {
277
+ console.log(chalk.yellow((0, glyphs_1.getGlyphs)().warn) + ' ' + message);
278
+ }
279
+ /**
280
+ * Print indexing results using clack log methods
281
+ */
282
+ function printIndexResult(clack, result, projectPath) {
283
+ const hasErrors = result.filesErrored > 0;
284
+ // Surface non-file-level failures (e.g. lock-acquisition failure
285
+ // when another indexer is running) before the file-count branches.
286
+ // Without this the CLI falls through to "No files found to index",
287
+ // which is actively misleading — the index DID run, it just couldn't
288
+ // get the lock.
289
+ //
290
+ // If success is false but no severity:'error' entry exists in
291
+ // `result.errors` (degenerate case — shouldn't happen in practice
292
+ // but worth guarding because the result shape is plumbed through
293
+ // multiple call sites), fall back to a generic message rather than
294
+ // continuing to the misleading "No files found" branch or throwing.
295
+ if (!result.success && !hasErrors && result.filesIndexed === 0) {
296
+ const generic = result.errors.find((e) => e.severity === 'error');
297
+ clack.log.error(generic?.message ?? `Indexing failed ${(0, glyphs_1.getGlyphs)().dash} no further details available`);
298
+ return;
299
+ }
300
+ if (result.filesIndexed > 0) {
301
+ if (hasErrors) {
302
+ clack.log.success(`Indexed ${formatNumber(result.filesIndexed)} files (${formatNumber(result.filesErrored)} could not be parsed)`);
303
+ }
304
+ else {
305
+ clack.log.success(`Indexed ${formatNumber(result.filesIndexed)} files`);
306
+ }
307
+ clack.log.info(`${formatNumber(result.nodesCreated)} nodes, ${formatNumber(result.edgesCreated)} edges in ${formatDuration(result.durationMs)}`);
308
+ }
309
+ else if (hasErrors) {
310
+ clack.log.error(`Indexing failed ${(0, glyphs_1.getGlyphs)().dash} all ${formatNumber(result.filesErrored)} files had errors`);
311
+ }
312
+ else {
313
+ clack.log.warn('No files found to index');
314
+ }
315
+ if (hasErrors) {
316
+ const errorsByCode = new Map();
317
+ for (const err of result.errors) {
318
+ if (err.severity === 'error') {
319
+ const code = err.code || 'unknown';
320
+ errorsByCode.set(code, (errorsByCode.get(code) || 0) + 1);
321
+ }
322
+ }
323
+ const codeLabels = {
324
+ parse_error: 'files failed to parse',
325
+ read_error: 'files could not be read',
326
+ size_exceeded: 'files exceeded size limit',
327
+ path_traversal: 'blocked paths',
328
+ unsupported_language: 'unsupported language',
329
+ parser_error: 'parser initialization failures',
330
+ };
331
+ const breakdown = Array.from(errorsByCode)
332
+ .map(([code, count]) => `${formatNumber(count)} ${codeLabels[code] || code}`)
333
+ .join('\n');
334
+ clack.note(breakdown, 'Error breakdown');
335
+ if (projectPath) {
336
+ writeErrorLog(projectPath, result.errors);
337
+ clack.log.info('See .codegraph/errors.log for details');
338
+ }
339
+ if (result.filesIndexed > 0) {
340
+ clack.log.info(`The index is fully usable ${(0, glyphs_1.getGlyphs)().dash} only the failed files are missing.`);
341
+ }
342
+ }
343
+ else if (projectPath) {
344
+ const logPath = path.join(projectPath, '.codegraph', 'errors.log');
345
+ if (fs.existsSync(logPath)) {
346
+ fs.unlinkSync(logPath);
347
+ }
348
+ }
349
+ }
350
+ /**
351
+ * Write detailed error log to .codegraph/errors.log
352
+ */
353
+ function writeErrorLog(projectPath, errors) {
354
+ const cgDir = path.join(projectPath, '.codegraph');
355
+ if (!fs.existsSync(cgDir))
356
+ return;
357
+ const logPath = path.join(cgDir, 'errors.log');
358
+ // Group errors by file path
359
+ const errorsByFile = new Map();
360
+ const noFileErrors = [];
361
+ for (const err of errors) {
362
+ if (err.severity !== 'error')
363
+ continue;
364
+ if (err.filePath) {
365
+ let list = errorsByFile.get(err.filePath);
366
+ if (!list) {
367
+ list = [];
368
+ errorsByFile.set(err.filePath, list);
369
+ }
370
+ list.push({ message: err.message, code: err.code });
371
+ }
372
+ else {
373
+ noFileErrors.push({ message: err.message, code: err.code });
374
+ }
375
+ }
376
+ const lines = [
377
+ `CodeGraph Error Log - ${new Date().toISOString()}`,
378
+ `${errorsByFile.size} files with errors`,
379
+ '',
380
+ ];
381
+ for (const [filePath, fileErrors] of errorsByFile) {
382
+ for (const err of fileErrors) {
383
+ lines.push(`${filePath}: ${err.message}`);
384
+ }
385
+ }
386
+ for (const err of noFileErrors) {
387
+ lines.push(err.message);
388
+ }
389
+ fs.writeFileSync(logPath, lines.join('\n') + '\n');
390
+ }
391
+ // =============================================================================
392
+ // Commands
393
+ // =============================================================================
394
+ /**
395
+ * codegraph init [path]
396
+ */
397
+ program
398
+ .command('init [path]')
399
+ .description('Initialize CodeGraph in a project directory and build the initial index')
400
+ .option('-i, --index', 'Deprecated: indexing now runs by default; flag accepted for backward compatibility')
401
+ .option('-v, --verbose', 'Show detailed worker lifecycle and memory info')
402
+ .action(async (pathArg, options) => {
403
+ const projectPath = path.resolve(pathArg || process.cwd());
404
+ const clack = await importESM('@clack/prompts');
405
+ clack.intro('Initializing CodeGraph');
406
+ try {
407
+ if ((0, directory_1.isInitialized)(projectPath)) {
408
+ clack.log.warn(`Already initialized in ${projectPath}`);
409
+ clack.log.info('Use "codegraph index" to re-index or "codegraph sync" to update');
410
+ try {
411
+ const { offerWatchFallback } = await Promise.resolve().then(() => __importStar(require('../installer')));
412
+ await offerWatchFallback(clack, projectPath);
413
+ }
414
+ catch { /* non-fatal */ }
415
+ clack.outro('');
416
+ return;
417
+ }
418
+ const { default: CodeGraph } = await loadCodeGraph();
419
+ const cg = await CodeGraph.init(projectPath, { index: false });
420
+ clack.log.success(`Initialized in ${projectPath}`);
421
+ // Indexing runs by default now. The legacy -i/--index flag is still
422
+ // accepted (so existing muscle memory and scripts don't break) but is a
423
+ // no-op — initializing always builds the initial index.
424
+ let result;
425
+ if (options.verbose) {
426
+ result = await cg.indexAll({
427
+ onProgress: createVerboseProgress(),
428
+ verbose: true,
429
+ });
430
+ }
431
+ else {
432
+ process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
433
+ const progress = (0, shimmer_progress_1.createShimmerProgress)();
434
+ result = await cg.indexAll({
435
+ onProgress: progress.onProgress,
436
+ });
437
+ await progress.stop();
438
+ }
439
+ printIndexResult(clack, result, projectPath);
440
+ try {
441
+ const { offerWatchFallback } = await Promise.resolve().then(() => __importStar(require('../installer')));
442
+ await offerWatchFallback(clack, projectPath);
443
+ }
444
+ catch { /* non-fatal */ }
445
+ clack.outro('Done');
446
+ cg.destroy();
447
+ }
448
+ catch (err) {
449
+ clack.log.error(`Failed: ${err instanceof Error ? err.message : String(err)}`);
450
+ process.exit(1);
451
+ }
452
+ });
453
+ /**
454
+ * codegraph uninit [path]
455
+ */
456
+ program
457
+ .command('uninit [path]')
458
+ .description('Remove CodeGraph from a project (deletes .codegraph/ directory)')
459
+ .option('-f, --force', 'Skip confirmation prompt')
460
+ .action(async (pathArg, options) => {
461
+ const projectPath = resolveProjectPath(pathArg);
462
+ try {
463
+ if (!(0, directory_1.isInitialized)(projectPath)) {
464
+ warn(`CodeGraph is not initialized in ${projectPath}`);
465
+ return;
466
+ }
467
+ if (!options.force) {
468
+ // Confirm with user
469
+ const readline = await Promise.resolve().then(() => __importStar(require('readline')));
470
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
471
+ const answer = await new Promise((resolve) => {
472
+ rl.question(chalk.yellow(`${(0, glyphs_1.getGlyphs)().warn} This will permanently delete all CodeGraph data. Continue? (y/N) `), resolve);
473
+ });
474
+ rl.close();
475
+ if (answer.toLowerCase() !== 'y') {
476
+ info('Cancelled');
477
+ return;
478
+ }
479
+ }
480
+ const { default: CodeGraph } = await loadCodeGraph();
481
+ const cg = CodeGraph.openSync(projectPath);
482
+ cg.uninitialize();
483
+ // Clean up any git sync hooks we installed (no-op if none / not a repo).
484
+ try {
485
+ const { removeGitSyncHook } = await Promise.resolve().then(() => __importStar(require('../sync/git-hooks')));
486
+ const removed = removeGitSyncHook(projectPath);
487
+ if (removed.installed.length > 0) {
488
+ info(`Removed git ${removed.installed.join(', ')} sync hook${removed.installed.length > 1 ? 's' : ''}`);
489
+ }
490
+ }
491
+ catch { /* non-fatal */ }
492
+ success(`Removed CodeGraph from ${projectPath}`);
493
+ }
494
+ catch (err) {
495
+ error(`Failed to uninitialize: ${err instanceof Error ? err.message : String(err)}`);
496
+ process.exit(1);
497
+ }
498
+ });
499
+ /**
500
+ * codegraph index [path]
501
+ */
502
+ program
503
+ .command('index [path]')
504
+ .description('Index all files in the project')
505
+ .option('-f, --force', 'Force full re-index even if already indexed')
506
+ .option('-q, --quiet', 'Suppress progress output')
507
+ .option('-v, --verbose', 'Show detailed worker lifecycle and memory info')
508
+ .action(async (pathArg, options) => {
509
+ const projectPath = resolveProjectPath(pathArg);
510
+ try {
511
+ if (!(0, directory_1.isInitialized)(projectPath)) {
512
+ error(`CodeGraph not initialized in ${projectPath}`);
513
+ info('Run "codegraph init" first');
514
+ process.exit(1);
515
+ }
516
+ const { default: CodeGraph } = await loadCodeGraph();
517
+ const cg = await CodeGraph.open(projectPath);
518
+ if (options.quiet) {
519
+ // Quiet mode: no UI, just run
520
+ if (options.force)
521
+ cg.clear();
522
+ const result = await cg.indexAll();
523
+ if (!result.success)
524
+ process.exit(1);
525
+ cg.destroy();
526
+ return;
527
+ }
528
+ const clack = await importESM('@clack/prompts');
529
+ clack.intro('Indexing project');
530
+ if (options.force) {
531
+ cg.clear();
532
+ clack.log.info('Cleared existing index');
533
+ }
534
+ let result;
535
+ if (options.verbose) {
536
+ result = await cg.indexAll({
537
+ onProgress: createVerboseProgress(),
538
+ verbose: true,
539
+ });
540
+ }
541
+ else {
542
+ process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
543
+ const progress = (0, shimmer_progress_1.createShimmerProgress)();
544
+ result = await cg.indexAll({
545
+ onProgress: progress.onProgress,
546
+ });
547
+ await progress.stop();
548
+ }
549
+ printIndexResult(clack, result, projectPath);
550
+ if (!result.success) {
551
+ process.exit(1);
552
+ }
553
+ clack.outro('Done');
554
+ cg.destroy();
555
+ }
556
+ catch (err) {
557
+ error(`Failed to index: ${err instanceof Error ? err.message : String(err)}`);
558
+ process.exit(1);
559
+ }
560
+ });
561
+ /**
562
+ * codegraph sync [path]
563
+ */
564
+ program
565
+ .command('sync [path]')
566
+ .description('Sync changes since last index')
567
+ .option('-q, --quiet', 'Suppress output (for git hooks)')
568
+ .action(async (pathArg, options) => {
569
+ const projectPath = resolveProjectPath(pathArg);
570
+ try {
571
+ if (!(0, directory_1.isInitialized)(projectPath)) {
572
+ if (!options.quiet) {
573
+ error(`CodeGraph not initialized in ${projectPath}`);
574
+ }
575
+ process.exit(1);
576
+ }
577
+ const { default: CodeGraph } = await loadCodeGraph();
578
+ const cg = await CodeGraph.open(projectPath);
579
+ if (options.quiet) {
580
+ await cg.sync();
581
+ cg.destroy();
582
+ return;
583
+ }
584
+ const clack = await importESM('@clack/prompts');
585
+ clack.intro('Syncing CodeGraph');
586
+ process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
587
+ const progress = (0, shimmer_progress_1.createShimmerProgress)();
588
+ const result = await cg.sync({
589
+ onProgress: progress.onProgress,
590
+ });
591
+ await progress.stop();
592
+ const totalChanges = result.filesAdded + result.filesModified + result.filesRemoved;
593
+ if (totalChanges === 0) {
594
+ clack.log.info('Already up to date');
595
+ }
596
+ else {
597
+ clack.log.success(`Synced ${formatNumber(totalChanges)} changed files`);
598
+ const details = [];
599
+ if (result.filesAdded > 0)
600
+ details.push(`Added: ${result.filesAdded}`);
601
+ if (result.filesModified > 0)
602
+ details.push(`Modified: ${result.filesModified}`);
603
+ if (result.filesRemoved > 0)
604
+ details.push(`Removed: ${result.filesRemoved}`);
605
+ clack.log.info(`${details.join(', ')} ${(0, glyphs_1.getGlyphs)().dash} ${formatNumber(result.nodesUpdated)} nodes in ${formatDuration(result.durationMs)}`);
606
+ }
607
+ clack.outro('Done');
608
+ cg.destroy();
609
+ }
610
+ catch (err) {
611
+ if (!options.quiet) {
612
+ error(`Failed to sync: ${err instanceof Error ? err.message : String(err)}`);
613
+ }
614
+ process.exit(1);
615
+ }
616
+ });
617
+ /**
618
+ * codegraph status [path]
619
+ */
620
+ program
621
+ .command('status [path]')
622
+ .description('Show index status and statistics')
623
+ .option('-j, --json', 'Output as JSON')
624
+ .action(async (pathArg, options) => {
625
+ const projectPath = resolveProjectPath(pathArg);
626
+ // The directory the user actually ran from, before walking up to the index
627
+ // root. Used to detect when the resolved index lives in a different git
628
+ // working tree (e.g. a nested worktree borrowing the main checkout's index).
629
+ const startPath = path.resolve(pathArg || process.cwd());
630
+ const worktreeMismatch = (0, worktree_1.detectWorktreeIndexMismatch)(startPath, projectPath);
631
+ try {
632
+ if (!(0, directory_1.isInitialized)(projectPath)) {
633
+ if (options.json) {
634
+ console.log(JSON.stringify({
635
+ initialized: false,
636
+ version: packageJson.version,
637
+ projectPath,
638
+ indexPath: (0, directory_1.getCodeGraphDir)(projectPath),
639
+ lastIndexed: null,
640
+ }));
641
+ return;
642
+ }
643
+ console.log(chalk.bold('\nCodeGraph Status\n'));
644
+ info(`Project: ${projectPath}`);
645
+ warn('Not initialized');
646
+ info('Run "codegraph init" to initialize');
647
+ return;
648
+ }
649
+ const { default: CodeGraph } = await loadCodeGraph();
650
+ const cg = await CodeGraph.open(projectPath);
651
+ const stats = cg.getStats();
652
+ const changes = cg.getChangedFiles();
653
+ const backend = cg.getBackend();
654
+ const journalMode = cg.getJournalMode();
655
+ const buildInfo = cg.getIndexBuildInfo();
656
+ const reindexRecommended = cg.isIndexStale();
657
+ // JSON output mode
658
+ if (options.json) {
659
+ const lastIndexedMs = cg.getLastIndexedAt();
660
+ console.log(JSON.stringify({
661
+ initialized: true,
662
+ version: packageJson.version,
663
+ projectPath,
664
+ indexPath: (0, directory_1.getCodeGraphDir)(projectPath),
665
+ lastIndexed: lastIndexedMs != null ? new Date(lastIndexedMs).toISOString() : null,
666
+ fileCount: stats.fileCount,
667
+ nodeCount: stats.nodeCount,
668
+ edgeCount: stats.edgeCount,
669
+ dbSizeBytes: stats.dbSizeBytes,
670
+ backend,
671
+ journalMode,
672
+ nodesByKind: stats.nodesByKind,
673
+ languages: Object.entries(stats.filesByLanguage).filter(([, count]) => count > 0).map(([lang]) => lang),
674
+ pendingChanges: {
675
+ added: changes.added.length,
676
+ modified: changes.modified.length,
677
+ removed: changes.removed.length,
678
+ },
679
+ worktreeMismatch: worktreeMismatch
680
+ ? { worktreeRoot: worktreeMismatch.worktreeRoot, indexRoot: worktreeMismatch.indexRoot }
681
+ : null,
682
+ index: {
683
+ builtWithVersion: buildInfo.version,
684
+ builtWithExtractionVersion: buildInfo.extractionVersion,
685
+ currentExtractionVersion: extraction_version_1.EXTRACTION_VERSION,
686
+ reindexRecommended,
687
+ },
688
+ }));
689
+ cg.destroy();
690
+ return;
691
+ }
692
+ console.log(chalk.bold('\nCodeGraph Status\n'));
693
+ // Project info
694
+ console.log(chalk.cyan('Project:'), projectPath);
695
+ if (worktreeMismatch) {
696
+ warn((0, worktree_1.worktreeMismatchWarning)(worktreeMismatch));
697
+ }
698
+ console.log();
699
+ // Index stats
700
+ console.log(chalk.bold('Index Statistics:'));
701
+ console.log(` Files: ${formatNumber(stats.fileCount)}`);
702
+ console.log(` Nodes: ${formatNumber(stats.nodeCount)}`);
703
+ console.log(` Edges: ${formatNumber(stats.edgeCount)}`);
704
+ console.log(` DB Size: ${(stats.dbSizeBytes / 1024 / 1024).toFixed(2)} MB`);
705
+ // Surface the active SQLite backend (node:sqlite — Node's built-in real
706
+ // SQLite, full WAL + FTS5, no native build).
707
+ const backendLabel = chalk.green(`node:sqlite ${(0, glyphs_1.getGlyphs)().dash} built-in (full WAL)`);
708
+ console.log(` Backend: ${backendLabel}`);
709
+ // Effective journal mode: 'wal' means concurrent reads never block on a
710
+ // writer; anything else means they can ("database is locked"). node:sqlite
711
+ // supports WAL everywhere, so a non-wal mode means the filesystem can't
712
+ // (network mounts, WSL2 /mnt). See issue #238.
713
+ const journalLabel = journalMode === 'wal'
714
+ ? chalk.green('wal')
715
+ : chalk.yellow(`${journalMode || 'unknown'} ${(0, glyphs_1.getGlyphs)().dash} WAL inactive; reads can block on writes`);
716
+ console.log(` Journal: ${journalLabel}`);
717
+ console.log();
718
+ // Node breakdown
719
+ console.log(chalk.bold('Nodes by Kind:'));
720
+ const nodesByKind = Object.entries(stats.nodesByKind)
721
+ .filter(([, count]) => count > 0)
722
+ .sort((a, b) => b[1] - a[1]);
723
+ for (const [kind, count] of nodesByKind) {
724
+ console.log(` ${kind.padEnd(15)} ${formatNumber(count)}`);
725
+ }
726
+ console.log();
727
+ // Language breakdown
728
+ console.log(chalk.bold('Files by Language:'));
729
+ const filesByLang = Object.entries(stats.filesByLanguage)
730
+ .filter(([, count]) => count > 0)
731
+ .sort((a, b) => b[1] - a[1]);
732
+ for (const [lang, count] of filesByLang) {
733
+ console.log(` ${lang.padEnd(15)} ${formatNumber(count)}`);
734
+ }
735
+ console.log();
736
+ // Pending changes
737
+ const totalChanges = changes.added.length + changes.modified.length + changes.removed.length;
738
+ if (totalChanges > 0) {
739
+ console.log(chalk.bold('Pending Changes:'));
740
+ if (changes.added.length > 0) {
741
+ console.log(` Added: ${changes.added.length} files`);
742
+ }
743
+ if (changes.modified.length > 0) {
744
+ console.log(` Modified: ${changes.modified.length} files`);
745
+ }
746
+ if (changes.removed.length > 0) {
747
+ console.log(` Removed: ${changes.removed.length} files`);
748
+ }
749
+ info('Run "codegraph sync" to update the index');
750
+ }
751
+ else {
752
+ success('Index is up to date');
753
+ }
754
+ console.log();
755
+ // Re-index hint: the index was built by an older engine than the one now
756
+ // running, so a rebuild would add data a migration can't backfill.
757
+ if (reindexRecommended) {
758
+ const builtWith = buildInfo.version ? `v${buildInfo.version.replace(/^v/, '')}` : 'an earlier version';
759
+ warn(`Index was built by ${builtWith}; re-index to pick up this engine's improvements.`);
760
+ info('Run "codegraph index -f" (full rebuild) or "codegraph sync"');
761
+ console.log();
762
+ }
763
+ cg.destroy();
764
+ }
765
+ catch (err) {
766
+ error(`Failed to get status: ${err instanceof Error ? err.message : String(err)}`);
767
+ process.exit(1);
768
+ }
769
+ });
770
+ /**
771
+ * codegraph query <search>
772
+ */
773
+ program
774
+ .command('query <search>')
775
+ .description('Search for symbols in the codebase')
776
+ .option('-p, --path <path>', 'Project path')
777
+ .option('-l, --limit <number>', 'Maximum results', '10')
778
+ .option('-k, --kind <kind>', 'Filter by node kind (function, class, etc.)')
779
+ .option('-j, --json', 'Output as JSON')
780
+ .action(async (search, options) => {
781
+ const projectPath = resolveProjectPath(options.path);
782
+ try {
783
+ if (!(0, directory_1.isInitialized)(projectPath)) {
784
+ error(`CodeGraph not initialized in ${projectPath}`);
785
+ process.exit(1);
786
+ }
787
+ const { default: CodeGraph } = await loadCodeGraph();
788
+ const cg = await CodeGraph.open(projectPath);
789
+ const limit = parseInt(options.limit || '10', 10);
790
+ const rawResults = cg.searchNodes(search, {
791
+ limit,
792
+ kinds: options.kind ? [options.kind] : undefined,
793
+ });
794
+ // Mirror the MCP search down-rank so the CLI also surfaces the
795
+ // hand-written implementation before protobuf/gRPC scaffolding
796
+ // when both share a name. See extraction/generated-detection.ts.
797
+ const { isGeneratedFile } = await Promise.resolve().then(() => __importStar(require('../extraction/generated-detection')));
798
+ const results = [...rawResults].sort((a, b) => {
799
+ const aGen = isGeneratedFile(a.node.filePath) ? 1 : 0;
800
+ const bGen = isGeneratedFile(b.node.filePath) ? 1 : 0;
801
+ return aGen - bGen;
802
+ });
803
+ if (options.json) {
804
+ console.log(JSON.stringify(results, null, 2));
805
+ }
806
+ else {
807
+ if (results.length === 0) {
808
+ info(`No results found for "${search}"`);
809
+ }
810
+ else {
811
+ console.log(chalk.bold(`\nSearch Results for "${search}":\n`));
812
+ for (const result of results) {
813
+ const node = result.node;
814
+ const location = `${node.filePath}:${node.startLine}`;
815
+ const score = chalk.dim(`(${(result.score * 100).toFixed(0)}%)`);
816
+ console.log(chalk.cyan(node.kind.padEnd(12)) +
817
+ chalk.white(node.name) +
818
+ ' ' + score);
819
+ console.log(chalk.dim(` ${location}`));
820
+ if (node.signature) {
821
+ console.log(chalk.dim(` ${node.signature}`));
822
+ }
823
+ console.log();
824
+ }
825
+ }
826
+ }
827
+ cg.destroy();
828
+ }
829
+ catch (err) {
830
+ error(`Search failed: ${err instanceof Error ? err.message : String(err)}`);
831
+ process.exit(1);
832
+ }
833
+ });
834
+ /**
835
+ * codegraph files [path]
836
+ */
837
+ program
838
+ .command('files')
839
+ .description('Show project file structure from the index')
840
+ .option('-p, --path <path>', 'Project path')
841
+ .option('--filter <dir>', 'Filter to files under this directory')
842
+ .option('--pattern <glob>', 'Filter files matching this glob pattern')
843
+ .option('--format <format>', 'Output format (tree, flat, grouped)', 'tree')
844
+ .option('--max-depth <number>', 'Maximum directory depth for tree format')
845
+ .option('--no-metadata', 'Hide file metadata (language, symbol count)')
846
+ .option('-j, --json', 'Output as JSON')
847
+ .action(async (options) => {
848
+ const projectPath = resolveProjectPath(options.path);
849
+ try {
850
+ if (!(0, directory_1.isInitialized)(projectPath)) {
851
+ error(`CodeGraph not initialized in ${projectPath}`);
852
+ process.exit(1);
853
+ }
854
+ const { default: CodeGraph } = await loadCodeGraph();
855
+ const cg = await CodeGraph.open(projectPath);
856
+ let files = cg.getFiles();
857
+ if (files.length === 0) {
858
+ info('No files indexed. Run "codegraph index" first.');
859
+ cg.destroy();
860
+ return;
861
+ }
862
+ // Filter by path prefix
863
+ if (options.filter) {
864
+ const filter = options.filter;
865
+ files = files.filter(f => f.path.startsWith(filter) || f.path.startsWith('./' + filter));
866
+ }
867
+ // Filter by glob pattern
868
+ if (options.pattern) {
869
+ const regex = globToRegex(options.pattern);
870
+ files = files.filter(f => regex.test(f.path));
871
+ }
872
+ if (files.length === 0) {
873
+ info('No files found matching the criteria.');
874
+ cg.destroy();
875
+ return;
876
+ }
877
+ // JSON output
878
+ if (options.json) {
879
+ const output = files.map(f => ({
880
+ path: f.path,
881
+ language: f.language,
882
+ nodeCount: f.nodeCount,
883
+ size: f.size,
884
+ }));
885
+ console.log(JSON.stringify(output, null, 2));
886
+ cg.destroy();
887
+ return;
888
+ }
889
+ const includeMetadata = options.metadata !== false;
890
+ const format = options.format || 'tree';
891
+ const maxDepth = options.maxDepth ? parseInt(options.maxDepth, 10) : undefined;
892
+ // Format output
893
+ switch (format) {
894
+ case 'flat':
895
+ console.log(chalk.bold(`\nFiles (${files.length}):\n`));
896
+ for (const file of files.sort((a, b) => a.path.localeCompare(b.path))) {
897
+ if (includeMetadata) {
898
+ console.log(` ${file.path} ${chalk.dim(`(${file.language}, ${file.nodeCount} symbols)`)}`);
899
+ }
900
+ else {
901
+ console.log(` ${file.path}`);
902
+ }
903
+ }
904
+ break;
905
+ case 'grouped':
906
+ console.log(chalk.bold(`\nFiles by Language (${files.length} total):\n`));
907
+ const byLang = new Map();
908
+ for (const file of files) {
909
+ const existing = byLang.get(file.language) || [];
910
+ existing.push(file);
911
+ byLang.set(file.language, existing);
912
+ }
913
+ const sortedLangs = [...byLang.entries()].sort((a, b) => b[1].length - a[1].length);
914
+ for (const [lang, langFiles] of sortedLangs) {
915
+ console.log(chalk.cyan(`${lang} (${langFiles.length}):`));
916
+ for (const file of langFiles.sort((a, b) => a.path.localeCompare(b.path))) {
917
+ if (includeMetadata) {
918
+ console.log(` ${file.path} ${chalk.dim(`(${file.nodeCount} symbols)`)}`);
919
+ }
920
+ else {
921
+ console.log(` ${file.path}`);
922
+ }
923
+ }
924
+ console.log();
925
+ }
926
+ break;
927
+ case 'tree':
928
+ default:
929
+ console.log(chalk.bold(`\nProject Structure (${files.length} files):\n`));
930
+ printFileTree(files, includeMetadata, maxDepth, chalk);
931
+ break;
932
+ }
933
+ console.log();
934
+ cg.destroy();
935
+ }
936
+ catch (err) {
937
+ error(`Failed to list files: ${err instanceof Error ? err.message : String(err)}`);
938
+ process.exit(1);
939
+ }
940
+ });
941
+ /**
942
+ * Convert glob pattern to regex
943
+ */
944
+ function globToRegex(pattern) {
945
+ const escaped = pattern
946
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
947
+ .replace(/\*\*/g, '{{GLOBSTAR}}')
948
+ .replace(/\*/g, '[^/]*')
949
+ .replace(/\?/g, '[^/]')
950
+ .replace(/\{\{GLOBSTAR\}\}/g, '.*');
951
+ return new RegExp(escaped);
952
+ }
953
+ /**
954
+ * Print files as a tree
955
+ */
956
+ function printFileTree(files, includeMetadata, maxDepth, chalk) {
957
+ const root = { name: '', children: new Map() };
958
+ for (const file of files) {
959
+ const parts = file.path.split('/');
960
+ let current = root;
961
+ for (let i = 0; i < parts.length; i++) {
962
+ const part = parts[i];
963
+ if (!part)
964
+ continue;
965
+ if (!current.children.has(part)) {
966
+ current.children.set(part, { name: part, children: new Map() });
967
+ }
968
+ current = current.children.get(part);
969
+ if (i === parts.length - 1) {
970
+ current.file = { language: file.language, nodeCount: file.nodeCount };
971
+ }
972
+ }
973
+ }
974
+ const renderNode = (node, prefix, isLast, depth) => {
975
+ if (maxDepth !== undefined && depth > maxDepth)
976
+ return;
977
+ const glyphs = (0, glyphs_1.getGlyphs)();
978
+ const connector = isLast ? glyphs.treeLast : glyphs.treeBranch;
979
+ const childPrefix = isLast ? ' ' : glyphs.treePipe;
980
+ if (node.name) {
981
+ let line = prefix + connector + node.name;
982
+ if (node.file && includeMetadata) {
983
+ line += chalk.dim(` (${node.file.language}, ${node.file.nodeCount} symbols)`);
984
+ }
985
+ console.log(line);
986
+ }
987
+ const children = [...node.children.values()];
988
+ children.sort((a, b) => {
989
+ const aIsDir = a.children.size > 0 && !a.file;
990
+ const bIsDir = b.children.size > 0 && !b.file;
991
+ if (aIsDir !== bIsDir)
992
+ return aIsDir ? -1 : 1;
993
+ return a.name.localeCompare(b.name);
994
+ });
995
+ for (let i = 0; i < children.length; i++) {
996
+ const child = children[i];
997
+ const nextPrefix = node.name ? prefix + childPrefix : prefix;
998
+ renderNode(child, nextPrefix, i === children.length - 1, depth + 1);
999
+ }
1000
+ };
1001
+ renderNode(root, '', true, 0);
1002
+ }
1003
+ /**
1004
+ * codegraph serve
1005
+ */
1006
+ program
1007
+ .command('serve')
1008
+ .description('Start CodeGraph as an MCP server for AI assistants')
1009
+ .option('-p, --path <path>', 'Project path (optional for MCP mode, uses rootUri from client)')
1010
+ .option('--mcp', 'Run as MCP server (stdio transport)')
1011
+ .option('--no-watch', 'Disable the file watcher (no auto-sync; useful on slow filesystems like WSL2 /mnt drives)')
1012
+ .action(async (options) => {
1013
+ const projectPath = options.path ? resolveProjectPath(options.path) : undefined;
1014
+ // Commander sets watch=false when --no-watch is passed. Route it through
1015
+ // the same env-var chokepoint the watcher and MCP server already honor.
1016
+ if (options.watch === false) {
1017
+ process.env.CODEGRAPH_NO_WATCH = '1';
1018
+ }
1019
+ try {
1020
+ if (options.mcp) {
1021
+ // Start MCP server - it handles initialization lazily based on rootUri from client
1022
+ const { MCPServer } = await Promise.resolve().then(() => __importStar(require('../mcp/index')));
1023
+ const server = new MCPServer(projectPath);
1024
+ await server.start();
1025
+ // Server will run until terminated
1026
+ }
1027
+ else {
1028
+ // Default: show info about MCP mode.
1029
+ // Use stderr so stdout stays clean for any piped/stdio usage.
1030
+ console.error(chalk.bold('\nCodeGraph MCP Server\n'));
1031
+ console.error(chalk.blue((0, glyphs_1.getGlyphs)().info) + ' Use --mcp flag to start the MCP server');
1032
+ console.error('\nTo use with Claude Code, add to your MCP configuration:');
1033
+ console.error(chalk.dim(`
1034
+ {
1035
+ "mcpServers": {
1036
+ "codegraph": {
1037
+ "command": "codegraph",
1038
+ "args": ["serve", "--mcp"]
1039
+ }
1040
+ }
1041
+ }
1042
+ `));
1043
+ console.error('Available tools:');
1044
+ console.error(chalk.cyan(' codegraph_explore') + ' - Primary: source of the relevant symbols for any question');
1045
+ console.error(chalk.cyan(' codegraph_search') + ' - Search for code symbols');
1046
+ console.error(chalk.cyan(' codegraph_callers') + ' - Find callers of a symbol');
1047
+ console.error(chalk.cyan(' codegraph_callees') + ' - Find what a symbol calls');
1048
+ console.error(chalk.cyan(' codegraph_impact') + ' - Analyze impact of changes');
1049
+ console.error(chalk.cyan(' codegraph_node') + ' - Get symbol details');
1050
+ console.error(chalk.cyan(' codegraph_files') + ' - Get project file structure');
1051
+ console.error(chalk.cyan(' codegraph_status') + ' - Get index status');
1052
+ }
1053
+ }
1054
+ catch (err) {
1055
+ error(`Failed to start server: ${err instanceof Error ? err.message : String(err)}`);
1056
+ process.exit(1);
1057
+ }
1058
+ });
1059
+ /**
1060
+ * codegraph unlock [path]
1061
+ */
1062
+ program
1063
+ .command('unlock [path]')
1064
+ .description('Remove a stale lock file that is blocking indexing')
1065
+ .action(async (pathArg) => {
1066
+ const projectPath = resolveProjectPath(pathArg);
1067
+ try {
1068
+ if (!(0, directory_1.isInitialized)(projectPath)) {
1069
+ error(`CodeGraph not initialized in ${projectPath}`);
1070
+ return;
1071
+ }
1072
+ const lockPath = path.join((0, directory_1.getCodeGraphDir)(projectPath), 'codegraph.lock');
1073
+ if (!fs.existsSync(lockPath)) {
1074
+ info(`No lock file found ${(0, glyphs_1.getGlyphs)().dash} nothing to do`);
1075
+ return;
1076
+ }
1077
+ fs.unlinkSync(lockPath);
1078
+ success('Removed lock file. You can now run indexing again.');
1079
+ }
1080
+ catch (err) {
1081
+ error(`Failed to remove lock: ${err instanceof Error ? err.message : String(err)}`);
1082
+ process.exit(1);
1083
+ }
1084
+ });
1085
+ /**
1086
+ * codegraph callers <symbol>
1087
+ *
1088
+ * CLI parity with the MCP graph tools (codegraph_callers/callees/impact) so the
1089
+ * traversal queries work in scripts, CI, and git hooks without a running MCP
1090
+ * server.
1091
+ */
1092
+ program
1093
+ .command('callers <symbol>')
1094
+ .description('Find all functions/methods that call a specific symbol')
1095
+ .option('-p, --path <path>', 'Project path')
1096
+ .option('-l, --limit <number>', 'Maximum results', '20')
1097
+ .option('-j, --json', 'Output as JSON')
1098
+ .action(async (symbol, options) => {
1099
+ const projectPath = resolveProjectPath(options.path);
1100
+ try {
1101
+ if (!(0, directory_1.isInitialized)(projectPath)) {
1102
+ error(`CodeGraph not initialized in ${projectPath}`);
1103
+ process.exit(1);
1104
+ }
1105
+ const { default: CodeGraph } = await loadCodeGraph();
1106
+ const cg = await CodeGraph.open(projectPath);
1107
+ const limit = parseInt(options.limit || '20', 10);
1108
+ const matches = cg.searchNodes(symbol, { limit: 50 });
1109
+ if (matches.length === 0) {
1110
+ info(`Symbol "${symbol}" not found`);
1111
+ cg.destroy();
1112
+ return;
1113
+ }
1114
+ const seen = new Set();
1115
+ const allCallers = [];
1116
+ for (const match of matches) {
1117
+ const exactMatch = match.node.name === symbol || match.node.name.endsWith(`.${symbol}`) || match.node.name.endsWith(`::${symbol}`);
1118
+ if (!exactMatch && matches.length > 1)
1119
+ continue;
1120
+ for (const c of cg.getCallers(match.node.id)) {
1121
+ if (!seen.has(c.node.id)) {
1122
+ seen.add(c.node.id);
1123
+ allCallers.push({ name: c.node.name, kind: c.node.kind, filePath: c.node.filePath, startLine: c.node.startLine });
1124
+ }
1125
+ }
1126
+ }
1127
+ // Fallback: if exact filter removed everything, use the top match
1128
+ if (allCallers.length === 0 && matches[0]) {
1129
+ for (const c of cg.getCallers(matches[0].node.id)) {
1130
+ if (!seen.has(c.node.id)) {
1131
+ seen.add(c.node.id);
1132
+ allCallers.push({ name: c.node.name, kind: c.node.kind, filePath: c.node.filePath, startLine: c.node.startLine });
1133
+ }
1134
+ }
1135
+ }
1136
+ const limited = allCallers.slice(0, limit);
1137
+ if (options.json) {
1138
+ console.log(JSON.stringify({ symbol, callers: limited }, null, 2));
1139
+ }
1140
+ else if (limited.length === 0) {
1141
+ info(`No callers found for "${symbol}"`);
1142
+ }
1143
+ else {
1144
+ console.log(chalk.bold(`\nCallers of "${symbol}" (${limited.length}):\n`));
1145
+ for (const node of limited) {
1146
+ const loc = node.startLine ? `:${node.startLine}` : '';
1147
+ console.log(chalk.cyan(node.kind.padEnd(12)) +
1148
+ chalk.white(node.name));
1149
+ console.log(chalk.dim(` ${node.filePath}${loc}`));
1150
+ console.log();
1151
+ }
1152
+ }
1153
+ cg.destroy();
1154
+ }
1155
+ catch (err) {
1156
+ error(`callers failed: ${err instanceof Error ? err.message : String(err)}`);
1157
+ process.exit(1);
1158
+ }
1159
+ });
1160
+ /**
1161
+ * codegraph callees <symbol>
1162
+ */
1163
+ program
1164
+ .command('callees <symbol>')
1165
+ .description('Find all functions/methods that a specific symbol calls')
1166
+ .option('-p, --path <path>', 'Project path')
1167
+ .option('-l, --limit <number>', 'Maximum results', '20')
1168
+ .option('-j, --json', 'Output as JSON')
1169
+ .action(async (symbol, options) => {
1170
+ const projectPath = resolveProjectPath(options.path);
1171
+ try {
1172
+ if (!(0, directory_1.isInitialized)(projectPath)) {
1173
+ error(`CodeGraph not initialized in ${projectPath}`);
1174
+ process.exit(1);
1175
+ }
1176
+ const { default: CodeGraph } = await loadCodeGraph();
1177
+ const cg = await CodeGraph.open(projectPath);
1178
+ const limit = parseInt(options.limit || '20', 10);
1179
+ const matches = cg.searchNodes(symbol, { limit: 50 });
1180
+ if (matches.length === 0) {
1181
+ info(`Symbol "${symbol}" not found`);
1182
+ cg.destroy();
1183
+ return;
1184
+ }
1185
+ const seen = new Set();
1186
+ const allCallees = [];
1187
+ for (const match of matches) {
1188
+ const exactMatch = match.node.name === symbol || match.node.name.endsWith(`.${symbol}`) || match.node.name.endsWith(`::${symbol}`);
1189
+ if (!exactMatch && matches.length > 1)
1190
+ continue;
1191
+ for (const c of cg.getCallees(match.node.id)) {
1192
+ if (!seen.has(c.node.id)) {
1193
+ seen.add(c.node.id);
1194
+ allCallees.push({ name: c.node.name, kind: c.node.kind, filePath: c.node.filePath, startLine: c.node.startLine });
1195
+ }
1196
+ }
1197
+ }
1198
+ if (allCallees.length === 0 && matches[0]) {
1199
+ for (const c of cg.getCallees(matches[0].node.id)) {
1200
+ if (!seen.has(c.node.id)) {
1201
+ seen.add(c.node.id);
1202
+ allCallees.push({ name: c.node.name, kind: c.node.kind, filePath: c.node.filePath, startLine: c.node.startLine });
1203
+ }
1204
+ }
1205
+ }
1206
+ const limited = allCallees.slice(0, limit);
1207
+ if (options.json) {
1208
+ console.log(JSON.stringify({ symbol, callees: limited }, null, 2));
1209
+ }
1210
+ else if (limited.length === 0) {
1211
+ info(`No callees found for "${symbol}"`);
1212
+ }
1213
+ else {
1214
+ console.log(chalk.bold(`\nCallees of "${symbol}" (${limited.length}):\n`));
1215
+ for (const node of limited) {
1216
+ const loc = node.startLine ? `:${node.startLine}` : '';
1217
+ console.log(chalk.cyan(node.kind.padEnd(12)) +
1218
+ chalk.white(node.name));
1219
+ console.log(chalk.dim(` ${node.filePath}${loc}`));
1220
+ console.log();
1221
+ }
1222
+ }
1223
+ cg.destroy();
1224
+ }
1225
+ catch (err) {
1226
+ error(`callees failed: ${err instanceof Error ? err.message : String(err)}`);
1227
+ process.exit(1);
1228
+ }
1229
+ });
1230
+ /**
1231
+ * codegraph impact <symbol>
1232
+ */
1233
+ program
1234
+ .command('impact <symbol>')
1235
+ .description('Analyze what code is affected by changing a symbol')
1236
+ .option('-p, --path <path>', 'Project path')
1237
+ .option('-d, --depth <number>', 'Traversal depth', '2')
1238
+ .option('-j, --json', 'Output as JSON')
1239
+ .action(async (symbol, options) => {
1240
+ const projectPath = resolveProjectPath(options.path);
1241
+ try {
1242
+ if (!(0, directory_1.isInitialized)(projectPath)) {
1243
+ error(`CodeGraph not initialized in ${projectPath}`);
1244
+ process.exit(1);
1245
+ }
1246
+ const { default: CodeGraph } = await loadCodeGraph();
1247
+ const cg = await CodeGraph.open(projectPath);
1248
+ const depth = Math.min(Math.max(parseInt(options.depth || '2', 10), 1), 10);
1249
+ const matches = cg.searchNodes(symbol, { limit: 50 });
1250
+ if (matches.length === 0) {
1251
+ info(`Symbol "${symbol}" not found`);
1252
+ cg.destroy();
1253
+ return;
1254
+ }
1255
+ // Merge impact subgraphs across all exact-matching symbols
1256
+ const mergedNodes = new Map();
1257
+ const seenEdges = new Set();
1258
+ let edgeCount = 0;
1259
+ for (const match of matches) {
1260
+ const exactMatch = match.node.name === symbol || match.node.name.endsWith(`.${symbol}`) || match.node.name.endsWith(`::${symbol}`);
1261
+ if (!exactMatch && matches.length > 1)
1262
+ continue;
1263
+ const impact = cg.getImpactRadius(match.node.id, depth);
1264
+ for (const [id, n] of impact.nodes) {
1265
+ mergedNodes.set(id, { name: n.name, kind: n.kind, filePath: n.filePath, startLine: n.startLine });
1266
+ }
1267
+ for (const e of impact.edges) {
1268
+ const key = `${e.source}->${e.target}:${e.kind}`;
1269
+ if (!seenEdges.has(key)) {
1270
+ seenEdges.add(key);
1271
+ edgeCount++;
1272
+ }
1273
+ }
1274
+ }
1275
+ // Fallback to top match if exact filter removed everything
1276
+ if (mergedNodes.size === 0 && matches[0]) {
1277
+ const impact = cg.getImpactRadius(matches[0].node.id, depth);
1278
+ for (const [id, n] of impact.nodes) {
1279
+ mergedNodes.set(id, { name: n.name, kind: n.kind, filePath: n.filePath, startLine: n.startLine });
1280
+ }
1281
+ edgeCount = impact.edges.length;
1282
+ }
1283
+ if (options.json) {
1284
+ console.log(JSON.stringify({
1285
+ symbol,
1286
+ depth,
1287
+ nodeCount: mergedNodes.size,
1288
+ edgeCount,
1289
+ affected: Array.from(mergedNodes.values()),
1290
+ }, null, 2));
1291
+ }
1292
+ else if (mergedNodes.size === 0) {
1293
+ info(`No affected symbols found for "${symbol}"`);
1294
+ }
1295
+ else {
1296
+ console.log(chalk.bold(`\nImpact of changing "${symbol}" — ${mergedNodes.size} affected symbols:\n`));
1297
+ // Group by file
1298
+ const byFile = new Map();
1299
+ for (const node of mergedNodes.values()) {
1300
+ const list = byFile.get(node.filePath) || [];
1301
+ list.push({ name: node.name, kind: node.kind, startLine: node.startLine });
1302
+ byFile.set(node.filePath, list);
1303
+ }
1304
+ for (const [file, nodes] of byFile) {
1305
+ console.log(chalk.cyan(file));
1306
+ for (const node of nodes) {
1307
+ const loc = node.startLine ? `:${node.startLine}` : '';
1308
+ console.log(` ${chalk.dim(node.kind.padEnd(12))}${node.name}${chalk.dim(loc)}`);
1309
+ }
1310
+ console.log();
1311
+ }
1312
+ }
1313
+ cg.destroy();
1314
+ }
1315
+ catch (err) {
1316
+ error(`impact failed: ${err instanceof Error ? err.message : String(err)}`);
1317
+ process.exit(1);
1318
+ }
1319
+ });
1320
+ /**
1321
+ * codegraph affected [files...]
1322
+ *
1323
+ * Find test files affected by the given source files.
1324
+ * Traces dependency edges transitively to find test files that depend on changed code.
1325
+ *
1326
+ * Usage:
1327
+ * git diff --name-only | codegraph affected --stdin
1328
+ * codegraph affected src/lib/components/Editor.svelte src/routes/+page.svelte
1329
+ */
1330
+ program
1331
+ .command('affected [files...]')
1332
+ .description('Find test files affected by changed source files')
1333
+ .option('-p, --path <path>', 'Project path')
1334
+ .option('--stdin', 'Read file list from stdin (one per line)')
1335
+ .option('-d, --depth <number>', 'Max dependency traversal depth', '5')
1336
+ .option('-f, --filter <glob>', 'Custom glob filter for test files (e.g. "e2e/*.spec.ts")')
1337
+ .option('-j, --json', 'Output as JSON')
1338
+ .option('-q, --quiet', 'Only output file paths, no decoration')
1339
+ .action(async (fileArgs, options) => {
1340
+ const projectPath = resolveProjectPath(options.path);
1341
+ try {
1342
+ if (!(0, directory_1.isInitialized)(projectPath)) {
1343
+ error(`CodeGraph not initialized in ${projectPath}`);
1344
+ process.exit(1);
1345
+ }
1346
+ // Collect changed files from args or stdin
1347
+ let changedFiles = [...(fileArgs || [])];
1348
+ if (options.stdin) {
1349
+ const stdinData = fs.readFileSync(0, 'utf-8');
1350
+ const stdinFiles = stdinData.split('\n').map(f => f.trim()).filter(Boolean);
1351
+ changedFiles.push(...stdinFiles);
1352
+ }
1353
+ if (changedFiles.length === 0) {
1354
+ if (!options.quiet)
1355
+ info('No files provided. Use file arguments or --stdin.');
1356
+ process.exit(0);
1357
+ }
1358
+ const { default: CodeGraph } = await loadCodeGraph();
1359
+ const cg = await CodeGraph.open(projectPath);
1360
+ const maxDepth = parseInt(options.depth || '5', 10);
1361
+ // Common test file patterns
1362
+ const defaultTestPatterns = [
1363
+ /\.spec\./,
1364
+ /\.test\./,
1365
+ /\/__tests__\//,
1366
+ /\/tests?\//,
1367
+ /\/e2e\//,
1368
+ /\/spec\//,
1369
+ ];
1370
+ // Custom filter pattern
1371
+ let customFilter = null;
1372
+ if (options.filter) {
1373
+ // Convert glob to regex: ** → .+, * → [^/]*, . → \.
1374
+ const regex = options.filter
1375
+ .replace(/[+[\]{}()^$|\\]/g, '\\$&')
1376
+ .replace(/\./g, '\\.')
1377
+ .replace(/\*\*/g, '.+')
1378
+ .replace(/\*/g, '[^/]*');
1379
+ customFilter = new RegExp(regex);
1380
+ }
1381
+ function isTestFile(filePath) {
1382
+ if (customFilter)
1383
+ return customFilter.test(filePath);
1384
+ return defaultTestPatterns.some(p => p.test(filePath));
1385
+ }
1386
+ // BFS to find all transitive dependents of changed files, filtered to test files
1387
+ const affectedTests = new Set();
1388
+ const allDependents = new Set();
1389
+ for (const file of changedFiles) {
1390
+ // If the changed file is itself a test file, include it
1391
+ if (isTestFile(file)) {
1392
+ affectedTests.add(file);
1393
+ continue;
1394
+ }
1395
+ // BFS through dependents
1396
+ const queue = [{ file, depth: 0 }];
1397
+ const visited = new Set();
1398
+ visited.add(file);
1399
+ while (queue.length > 0) {
1400
+ const current = queue.shift();
1401
+ if (current.depth >= maxDepth)
1402
+ continue;
1403
+ const dependents = cg.getFileDependents(current.file);
1404
+ for (const dep of dependents) {
1405
+ if (visited.has(dep))
1406
+ continue;
1407
+ visited.add(dep);
1408
+ allDependents.add(dep);
1409
+ if (isTestFile(dep)) {
1410
+ affectedTests.add(dep);
1411
+ }
1412
+ else {
1413
+ queue.push({ file: dep, depth: current.depth + 1 });
1414
+ }
1415
+ }
1416
+ }
1417
+ }
1418
+ const sortedTests = Array.from(affectedTests).sort();
1419
+ // Output
1420
+ if (options.json) {
1421
+ console.log(JSON.stringify({
1422
+ changedFiles,
1423
+ affectedTests: sortedTests,
1424
+ totalDependentsTraversed: allDependents.size,
1425
+ }, null, 2));
1426
+ }
1427
+ else if (options.quiet) {
1428
+ for (const t of sortedTests)
1429
+ console.log(t);
1430
+ }
1431
+ else {
1432
+ if (sortedTests.length === 0) {
1433
+ info('No test files affected by the changed files.');
1434
+ }
1435
+ else {
1436
+ console.log(chalk.bold(`\nAffected test files (${sortedTests.length}):\n`));
1437
+ for (const t of sortedTests) {
1438
+ console.log(' ' + chalk.cyan(t));
1439
+ }
1440
+ console.log();
1441
+ }
1442
+ }
1443
+ cg.destroy();
1444
+ }
1445
+ catch (err) {
1446
+ error(`Affected analysis failed: ${err instanceof Error ? err.message : String(err)}`);
1447
+ process.exit(1);
1448
+ }
1449
+ });
1450
+ /**
1451
+ * codegraph install
1452
+ */
1453
+ program
1454
+ .command('install')
1455
+ .description('Install codegraph MCP server into one or more agents (Claude Code, Cursor, Codex CLI, opencode, Hermes Agent)')
1456
+ .option('-t, --target <ids>', 'Target agent(s): comma-separated ids, or "auto"|"all"|"none". Default: prompt')
1457
+ .option('-l, --location <where>', 'Install location: "global" or "local". Default: prompt')
1458
+ .option('-y, --yes', 'Non-interactive: defaults to --location=global --target=auto, auto-allow on')
1459
+ .option('--no-permissions', 'Skip writing the auto-allow permissions list (Claude Code only)')
1460
+ .option('--print-config <id>', 'Print MCP config snippet for the named agent and exit (no file writes)')
1461
+ .action(async (opts) => {
1462
+ if (opts.printConfig) {
1463
+ const { getTarget, listTargetIds } = await Promise.resolve().then(() => __importStar(require('../installer/targets/registry')));
1464
+ const target = getTarget(opts.printConfig);
1465
+ if (!target) {
1466
+ const known = listTargetIds().join(', ');
1467
+ error(`Unknown target "${opts.printConfig}". Known: ${known}.`);
1468
+ process.exit(1);
1469
+ }
1470
+ const loc = (opts.location === 'local' ? 'local' : 'global');
1471
+ process.stdout.write(target.printConfig(loc));
1472
+ return;
1473
+ }
1474
+ const { runInstallerWithOptions } = await Promise.resolve().then(() => __importStar(require('../installer')));
1475
+ if (opts.location && opts.location !== 'global' && opts.location !== 'local') {
1476
+ error(`--location must be "global" or "local" (got "${opts.location}").`);
1477
+ process.exit(1);
1478
+ }
1479
+ try {
1480
+ // Commander's `--no-permissions` makes `opts.permissions === false`;
1481
+ // omitting the flag leaves it `true` (the positive-form default).
1482
+ // We MUST treat the default-true as "user did not override — let
1483
+ // the orchestrator prompt" and only forward an explicit `false`
1484
+ // (or `true` when --yes implies it). Otherwise the auto-allow
1485
+ // prompt is silently skipped on every interactive run.
1486
+ const explicitNoPermissions = opts.permissions === false;
1487
+ const autoAllow = explicitNoPermissions
1488
+ ? false
1489
+ : opts.yes
1490
+ ? true
1491
+ : undefined;
1492
+ await runInstallerWithOptions({
1493
+ target: opts.target,
1494
+ location: opts.location,
1495
+ autoAllow,
1496
+ yes: opts.yes,
1497
+ });
1498
+ }
1499
+ catch (err) {
1500
+ error(err instanceof Error ? err.message : String(err));
1501
+ process.exit(1);
1502
+ }
1503
+ });
1504
+ /**
1505
+ * codegraph uninstall
1506
+ *
1507
+ * Inverse of `install`. Removes the codegraph MCP server entry,
1508
+ * instructions block, and permissions from every agent (or a
1509
+ * `--target` subset). Prompts global-vs-local when not given. Does NOT
1510
+ * delete the `.codegraph/` index — that's `codegraph uninit`.
1511
+ */
1512
+ program
1513
+ .command('uninstall')
1514
+ .description('Remove codegraph from your agents (Claude Code, Cursor, Codex CLI, opencode, Hermes Agent)')
1515
+ .option('-t, --target <ids>', 'Target agent(s): comma-separated ids, or "all". Default: all')
1516
+ .option('-l, --location <where>', 'Uninstall location: "global" or "local". Default: prompt')
1517
+ .option('-y, --yes', 'Non-interactive: defaults to --location=global --target=all')
1518
+ .action(async (opts) => {
1519
+ const { runUninstaller } = await Promise.resolve().then(() => __importStar(require('../installer')));
1520
+ if (opts.location && opts.location !== 'global' && opts.location !== 'local') {
1521
+ error(`--location must be "global" or "local" (got "${opts.location}").`);
1522
+ process.exit(1);
1523
+ }
1524
+ try {
1525
+ await runUninstaller({
1526
+ target: opts.target,
1527
+ location: opts.location,
1528
+ yes: opts.yes,
1529
+ });
1530
+ }
1531
+ catch (err) {
1532
+ error(err instanceof Error ? err.message : String(err));
1533
+ process.exit(1);
1534
+ }
1535
+ });
1536
+ /**
1537
+ * codegraph upgrade [version]
1538
+ *
1539
+ * Self-update, however CodeGraph was installed (bundle via install.sh/.ps1,
1540
+ * npm-global, npx, or a source checkout). See ../upgrade for the detection and
1541
+ * per-method upgrade logic.
1542
+ */
1543
+ program
1544
+ .command('upgrade [version]')
1545
+ .description('Update CodeGraph to the latest release (or a specific version)')
1546
+ .option('--check', 'Check whether an update is available without installing')
1547
+ .option('-f, --force', 'Reinstall even if already on the target version')
1548
+ .action(async (versionArg, options) => {
1549
+ const up = await Promise.resolve().then(() => __importStar(require('../upgrade')));
1550
+ const method = up.detectInstallMethod({
1551
+ filename: __filename,
1552
+ platform: process.platform,
1553
+ cwd: process.cwd(),
1554
+ });
1555
+ const pin = versionArg || process.env.CODEGRAPH_VERSION || undefined;
1556
+ const code = await up.runUpgrade({ version: pin, check: options.check, force: options.force }, {
1557
+ currentVersion: packageJson.version,
1558
+ method,
1559
+ resolveLatest: () => up.resolveLatestVersion(),
1560
+ run: up.defaultRun,
1561
+ hasCommand: up.hasCommand,
1562
+ log: (m) => console.log(m),
1563
+ warn: (m) => warn(m),
1564
+ error: (m) => error(m),
1565
+ platform: process.platform,
1566
+ });
1567
+ process.exit(code);
1568
+ });
1569
+ // Parse and run
1570
+ program.parse();
1571
+ } // end main()
1572
+ //# sourceMappingURL=codegraph.js.map