homegraph 0.9.10 → 1.1.1

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 (436) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +243 -193
  3. package/dist/bin/fatal-handler.d.ts +20 -0
  4. package/dist/bin/fatal-handler.d.ts.map +1 -0
  5. package/dist/bin/fatal-handler.js +118 -0
  6. package/dist/bin/fatal-handler.js.map +1 -0
  7. package/dist/bin/homegraph.d.ts +6 -6
  8. package/dist/bin/homegraph.js +532 -109
  9. package/dist/bin/homegraph.js.map +1 -1
  10. package/dist/bin/node-version-check.d.ts +4 -4
  11. package/dist/bin/node-version-check.js +12 -12
  12. package/dist/bin/uninstall.d.ts +1 -1
  13. package/dist/bin/uninstall.js +1 -1
  14. package/dist/context/index.d.ts.map +1 -1
  15. package/dist/context/index.js +8 -1
  16. package/dist/context/index.js.map +1 -1
  17. package/dist/db/index.d.ts +22 -1
  18. package/dist/db/index.d.ts.map +1 -1
  19. package/dist/db/index.js +48 -2
  20. package/dist/db/index.js.map +1 -1
  21. package/dist/db/migrations.d.ts +1 -1
  22. package/dist/db/migrations.d.ts.map +1 -1
  23. package/dist/db/migrations.js +26 -17
  24. package/dist/db/migrations.js.map +1 -1
  25. package/dist/db/queries.d.ts +21 -1
  26. package/dist/db/queries.d.ts.map +1 -1
  27. package/dist/db/queries.js +180 -137
  28. package/dist/db/queries.js.map +1 -1
  29. package/dist/db/schema.sql +152 -151
  30. package/dist/db/sqlite-adapter.d.ts +1 -1
  31. package/dist/db/sqlite-adapter.js +3 -3
  32. package/dist/directory.d.ts +87 -6
  33. package/dist/directory.d.ts.map +1 -1
  34. package/dist/directory.js +319 -57
  35. package/dist/directory.js.map +1 -1
  36. package/dist/errors.d.ts +15 -15
  37. package/dist/errors.js +20 -20
  38. package/dist/extraction/astro-extractor.d.ts +79 -0
  39. package/dist/extraction/astro-extractor.d.ts.map +1 -0
  40. package/dist/extraction/astro-extractor.js +320 -0
  41. package/dist/extraction/astro-extractor.js.map +1 -0
  42. package/dist/extraction/context.d.ts +1 -1
  43. package/dist/extraction/context.js +1 -1
  44. package/dist/extraction/extraction-version.d.ts +2 -2
  45. package/dist/extraction/extraction-version.d.ts.map +1 -1
  46. package/dist/extraction/extraction-version.js +2 -2
  47. package/dist/extraction/extraction-version.js.map +1 -1
  48. package/dist/extraction/function-ref.d.ts +118 -0
  49. package/dist/extraction/function-ref.d.ts.map +1 -0
  50. package/dist/extraction/function-ref.js +727 -0
  51. package/dist/extraction/function-ref.js.map +1 -0
  52. package/dist/extraction/generated-detection.d.ts.map +1 -1
  53. package/dist/extraction/generated-detection.js +3 -0
  54. package/dist/extraction/generated-detection.js.map +1 -1
  55. package/dist/extraction/grammars.d.ts +15 -5
  56. package/dist/extraction/grammars.d.ts.map +1 -1
  57. package/dist/extraction/grammars.js +44 -10
  58. package/dist/extraction/grammars.js.map +1 -1
  59. package/dist/extraction/index.d.ts +37 -0
  60. package/dist/extraction/index.d.ts.map +1 -1
  61. package/dist/extraction/index.js +562 -70
  62. package/dist/extraction/index.js.map +1 -1
  63. package/dist/extraction/languages/arkts-viewtree.d.ts +22 -0
  64. package/dist/extraction/languages/arkts-viewtree.d.ts.map +1 -0
  65. package/dist/extraction/languages/arkts-viewtree.js +133 -0
  66. package/dist/extraction/languages/arkts-viewtree.js.map +1 -0
  67. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  68. package/dist/extraction/languages/arkts.js +211 -20
  69. package/dist/extraction/languages/arkts.js.map +1 -1
  70. package/dist/extraction/languages/c-cpp.d.ts +8 -0
  71. package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  72. package/dist/extraction/languages/c-cpp.js +104 -2
  73. package/dist/extraction/languages/c-cpp.js.map +1 -1
  74. package/dist/extraction/languages/csharp.d.ts.map +1 -1
  75. package/dist/extraction/languages/csharp.js +58 -3
  76. package/dist/extraction/languages/csharp.js.map +1 -1
  77. package/dist/extraction/languages/dart.d.ts.map +1 -1
  78. package/dist/extraction/languages/dart.js +183 -1
  79. package/dist/extraction/languages/dart.js.map +1 -1
  80. package/dist/extraction/languages/go.d.ts.map +1 -1
  81. package/dist/extraction/languages/go.js +37 -0
  82. package/dist/extraction/languages/go.js.map +1 -1
  83. package/dist/extraction/languages/index.d.ts.map +1 -1
  84. package/dist/extraction/languages/index.js +2 -0
  85. package/dist/extraction/languages/index.js.map +1 -1
  86. package/dist/extraction/languages/java.d.ts.map +1 -1
  87. package/dist/extraction/languages/java.js +241 -0
  88. package/dist/extraction/languages/java.js.map +1 -1
  89. package/dist/extraction/languages/javascript.d.ts.map +1 -1
  90. package/dist/extraction/languages/javascript.js +16 -0
  91. package/dist/extraction/languages/javascript.js.map +1 -1
  92. package/dist/extraction/languages/kotlin.d.ts.map +1 -1
  93. package/dist/extraction/languages/kotlin.js +94 -0
  94. package/dist/extraction/languages/kotlin.js.map +1 -1
  95. package/dist/extraction/languages/objc.d.ts.map +1 -1
  96. package/dist/extraction/languages/objc.js +42 -0
  97. package/dist/extraction/languages/objc.js.map +1 -1
  98. package/dist/extraction/languages/pascal.d.ts.map +1 -1
  99. package/dist/extraction/languages/pascal.js +11 -0
  100. package/dist/extraction/languages/pascal.js.map +1 -1
  101. package/dist/extraction/languages/php.d.ts.map +1 -1
  102. package/dist/extraction/languages/php.js +77 -1
  103. package/dist/extraction/languages/php.js.map +1 -1
  104. package/dist/extraction/languages/r.d.ts +3 -0
  105. package/dist/extraction/languages/r.d.ts.map +1 -0
  106. package/dist/extraction/languages/r.js +314 -0
  107. package/dist/extraction/languages/r.js.map +1 -0
  108. package/dist/extraction/languages/rust.d.ts.map +1 -1
  109. package/dist/extraction/languages/rust.js +29 -0
  110. package/dist/extraction/languages/rust.js.map +1 -1
  111. package/dist/extraction/languages/scala.d.ts.map +1 -1
  112. package/dist/extraction/languages/scala.js +44 -9
  113. package/dist/extraction/languages/scala.js.map +1 -1
  114. package/dist/extraction/languages/swift.d.ts.map +1 -1
  115. package/dist/extraction/languages/swift.js +61 -0
  116. package/dist/extraction/languages/swift.js.map +1 -1
  117. package/dist/extraction/languages/typescript.d.ts +13 -0
  118. package/dist/extraction/languages/typescript.d.ts.map +1 -1
  119. package/dist/extraction/languages/typescript.js +38 -0
  120. package/dist/extraction/languages/typescript.js.map +1 -1
  121. package/dist/extraction/liquid-extractor.d.ts.map +1 -1
  122. package/dist/extraction/liquid-extractor.js +4 -1
  123. package/dist/extraction/liquid-extractor.js.map +1 -1
  124. package/dist/extraction/parse-worker.js +4 -1
  125. package/dist/extraction/parse-worker.js.map +1 -1
  126. package/dist/extraction/svelte-extractor.d.ts.map +1 -1
  127. package/dist/extraction/svelte-extractor.js +6 -3
  128. package/dist/extraction/svelte-extractor.js.map +1 -1
  129. package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
  130. package/dist/extraction/tree-sitter-helpers.js +59 -10
  131. package/dist/extraction/tree-sitter-helpers.js.map +1 -1
  132. package/dist/extraction/tree-sitter-types.d.ts +29 -0
  133. package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  134. package/dist/extraction/tree-sitter.d.ts +192 -0
  135. package/dist/extraction/tree-sitter.d.ts.map +1 -1
  136. package/dist/extraction/tree-sitter.js +1553 -45
  137. package/dist/extraction/tree-sitter.js.map +1 -1
  138. package/dist/extraction/vue-extractor.d.ts.map +1 -1
  139. package/dist/extraction/vue-extractor.js +6 -3
  140. package/dist/extraction/vue-extractor.js.map +1 -1
  141. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  142. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  143. package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
  144. package/dist/graph/traversal.d.ts.map +1 -1
  145. package/dist/graph/traversal.js +11 -2
  146. package/dist/graph/traversal.js.map +1 -1
  147. package/dist/index.d.ts +64 -23
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +137 -41
  150. package/dist/index.js.map +1 -1
  151. package/dist/installer/config-writer.d.ts +1 -1
  152. package/dist/installer/config-writer.js +1 -1
  153. package/dist/installer/index.d.ts +4 -4
  154. package/dist/installer/index.d.ts.map +1 -1
  155. package/dist/installer/index.js +100 -73
  156. package/dist/installer/index.js.map +1 -1
  157. package/dist/installer/instructions-template.d.ts +34 -11
  158. package/dist/installer/instructions-template.d.ts.map +1 -1
  159. package/dist/installer/instructions-template.js +44 -12
  160. package/dist/installer/instructions-template.js.map +1 -1
  161. package/dist/installer/targets/antigravity.d.ts +6 -6
  162. package/dist/installer/targets/antigravity.js +14 -14
  163. package/dist/installer/targets/claude.d.ts +19 -13
  164. package/dist/installer/targets/claude.d.ts.map +1 -1
  165. package/dist/installer/targets/claude.js +97 -29
  166. package/dist/installer/targets/claude.js.map +1 -1
  167. package/dist/installer/targets/codebuddy.d.ts +17 -0
  168. package/dist/installer/targets/codebuddy.d.ts.map +1 -0
  169. package/dist/installer/targets/codebuddy.js +150 -0
  170. package/dist/installer/targets/codebuddy.js.map +1 -0
  171. package/dist/installer/targets/codex.js +5 -7
  172. package/dist/installer/targets/codex.js.map +1 -1
  173. package/dist/installer/targets/cursor.d.ts +1 -1
  174. package/dist/installer/targets/cursor.js +7 -7
  175. package/dist/installer/targets/deveco.d.ts +23 -0
  176. package/dist/installer/targets/deveco.d.ts.map +1 -0
  177. package/dist/installer/targets/deveco.js +217 -0
  178. package/dist/installer/targets/deveco.js.map +1 -0
  179. package/dist/installer/targets/gemini.js +5 -7
  180. package/dist/installer/targets/gemini.js.map +1 -1
  181. package/dist/installer/targets/hermes.js +15 -15
  182. package/dist/installer/targets/kiro.d.ts +1 -1
  183. package/dist/installer/targets/kiro.js +4 -4
  184. package/dist/installer/targets/opencode.d.ts +9 -1
  185. package/dist/installer/targets/opencode.d.ts.map +1 -1
  186. package/dist/installer/targets/opencode.js +92 -41
  187. package/dist/installer/targets/opencode.js.map +1 -1
  188. package/dist/installer/targets/registry.d.ts.map +1 -1
  189. package/dist/installer/targets/registry.js +4 -0
  190. package/dist/installer/targets/registry.js.map +1 -1
  191. package/dist/installer/targets/shared.d.ts +28 -4
  192. package/dist/installer/targets/shared.d.ts.map +1 -1
  193. package/dist/installer/targets/shared.js +32 -15
  194. package/dist/installer/targets/shared.js.map +1 -1
  195. package/dist/installer/targets/types.d.ts +9 -2
  196. package/dist/installer/targets/types.d.ts.map +1 -1
  197. package/dist/mcp/daemon-manager.d.ts +42 -0
  198. package/dist/mcp/daemon-manager.d.ts.map +1 -0
  199. package/dist/mcp/daemon-manager.js +129 -0
  200. package/dist/mcp/daemon-manager.js.map +1 -0
  201. package/dist/mcp/daemon-paths.d.ts +1 -1
  202. package/dist/mcp/daemon-paths.js +3 -3
  203. package/dist/mcp/daemon-registry.d.ts +47 -0
  204. package/dist/mcp/daemon-registry.d.ts.map +1 -0
  205. package/dist/mcp/daemon-registry.js +229 -0
  206. package/dist/mcp/daemon-registry.js.map +1 -0
  207. package/dist/mcp/daemon.d.ts.map +1 -1
  208. package/dist/mcp/daemon.js +27 -6
  209. package/dist/mcp/daemon.js.map +1 -1
  210. package/dist/mcp/dynamic-boundaries.d.ts +41 -0
  211. package/dist/mcp/dynamic-boundaries.d.ts.map +1 -0
  212. package/dist/mcp/dynamic-boundaries.js +359 -0
  213. package/dist/mcp/dynamic-boundaries.js.map +1 -0
  214. package/dist/mcp/engine.d.ts +4 -4
  215. package/dist/mcp/engine.d.ts.map +1 -1
  216. package/dist/mcp/engine.js +32 -24
  217. package/dist/mcp/engine.js.map +1 -1
  218. package/dist/mcp/index.d.ts +8 -7
  219. package/dist/mcp/index.d.ts.map +1 -1
  220. package/dist/mcp/index.js +39 -18
  221. package/dist/mcp/index.js.map +1 -1
  222. package/dist/mcp/liveness-watchdog.d.ts +18 -0
  223. package/dist/mcp/liveness-watchdog.d.ts.map +1 -0
  224. package/dist/mcp/liveness-watchdog.js +207 -0
  225. package/dist/mcp/liveness-watchdog.js.map +1 -0
  226. package/dist/mcp/proxy.d.ts +6 -0
  227. package/dist/mcp/proxy.d.ts.map +1 -1
  228. package/dist/mcp/proxy.js +75 -18
  229. package/dist/mcp/proxy.js.map +1 -1
  230. package/dist/mcp/server-instructions.d.ts +22 -7
  231. package/dist/mcp/server-instructions.d.ts.map +1 -1
  232. package/dist/mcp/server-instructions.js +91 -59
  233. package/dist/mcp/server-instructions.js.map +1 -1
  234. package/dist/mcp/session.d.ts +3 -1
  235. package/dist/mcp/session.d.ts.map +1 -1
  236. package/dist/mcp/session.js +43 -7
  237. package/dist/mcp/session.js.map +1 -1
  238. package/dist/mcp/stdin-teardown.d.ts +27 -0
  239. package/dist/mcp/stdin-teardown.d.ts.map +1 -0
  240. package/dist/mcp/stdin-teardown.js +49 -0
  241. package/dist/mcp/stdin-teardown.js.map +1 -0
  242. package/dist/mcp/tools.d.ts +137 -16
  243. package/dist/mcp/tools.d.ts.map +1 -1
  244. package/dist/mcp/tools.js +1271 -219
  245. package/dist/mcp/tools.js.map +1 -1
  246. package/dist/mcp/transport.d.ts +1 -1
  247. package/dist/mcp/transport.d.ts.map +1 -1
  248. package/dist/mcp/transport.js +20 -4
  249. package/dist/mcp/transport.js.map +1 -1
  250. package/dist/mcp/version.d.ts +1 -1
  251. package/dist/mcp/version.js +2 -2
  252. package/dist/project-config.d.ts +36 -0
  253. package/dist/project-config.d.ts.map +1 -0
  254. package/dist/project-config.js +235 -0
  255. package/dist/project-config.js.map +1 -0
  256. package/dist/reasoning/config.d.ts +45 -0
  257. package/dist/reasoning/config.d.ts.map +1 -0
  258. package/dist/reasoning/config.js +171 -0
  259. package/dist/reasoning/config.js.map +1 -0
  260. package/dist/reasoning/credentials.d.ts +5 -0
  261. package/dist/reasoning/credentials.d.ts.map +1 -0
  262. package/dist/reasoning/credentials.js +83 -0
  263. package/dist/reasoning/credentials.js.map +1 -0
  264. package/dist/reasoning/login.d.ts +21 -0
  265. package/dist/reasoning/login.d.ts.map +1 -0
  266. package/dist/reasoning/login.js +85 -0
  267. package/dist/reasoning/login.js.map +1 -0
  268. package/dist/reasoning/reasoner.d.ts +43 -0
  269. package/dist/reasoning/reasoner.d.ts.map +1 -0
  270. package/dist/reasoning/reasoner.js +308 -0
  271. package/dist/reasoning/reasoner.js.map +1 -0
  272. package/dist/resolution/c-fnptr-synthesizer.d.ts +33 -0
  273. package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -0
  274. package/dist/resolution/c-fnptr-synthesizer.js +352 -0
  275. package/dist/resolution/c-fnptr-synthesizer.js.map +1 -0
  276. package/dist/resolution/callback-synthesizer.d.ts +6 -1
  277. package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  278. package/dist/resolution/callback-synthesizer.js +1197 -1
  279. package/dist/resolution/callback-synthesizer.js.map +1 -1
  280. package/dist/resolution/frameworks/arkts-entry.d.ts +12 -0
  281. package/dist/resolution/frameworks/arkts-entry.d.ts.map +1 -0
  282. package/dist/resolution/frameworks/arkts-entry.js +214 -0
  283. package/dist/resolution/frameworks/arkts-entry.js.map +1 -0
  284. package/dist/resolution/frameworks/arkts-napi.d.ts +3 -0
  285. package/dist/resolution/frameworks/arkts-napi.d.ts.map +1 -0
  286. package/dist/resolution/frameworks/arkts-napi.js +166 -0
  287. package/dist/resolution/frameworks/arkts-napi.js.map +1 -0
  288. package/dist/resolution/frameworks/astro.d.ts +9 -0
  289. package/dist/resolution/frameworks/astro.d.ts.map +1 -0
  290. package/dist/resolution/frameworks/astro.js +169 -0
  291. package/dist/resolution/frameworks/astro.js.map +1 -0
  292. package/dist/resolution/frameworks/goframe.d.ts +41 -0
  293. package/dist/resolution/frameworks/goframe.d.ts.map +1 -0
  294. package/dist/resolution/frameworks/goframe.js +112 -0
  295. package/dist/resolution/frameworks/goframe.js.map +1 -0
  296. package/dist/resolution/frameworks/index.d.ts +3 -0
  297. package/dist/resolution/frameworks/index.d.ts.map +1 -1
  298. package/dist/resolution/frameworks/index.js +17 -1
  299. package/dist/resolution/frameworks/index.js.map +1 -1
  300. package/dist/resolution/frameworks/java.js +6 -1
  301. package/dist/resolution/frameworks/java.js.map +1 -1
  302. package/dist/resolution/frameworks/react.d.ts.map +1 -1
  303. package/dist/resolution/frameworks/react.js +32 -63
  304. package/dist/resolution/frameworks/react.js.map +1 -1
  305. package/dist/resolution/frameworks/svelte.js +6 -2
  306. package/dist/resolution/frameworks/svelte.js.map +1 -1
  307. package/dist/resolution/frameworks/vue.js +24 -27
  308. package/dist/resolution/frameworks/vue.js.map +1 -1
  309. package/dist/resolution/goframe-synthesizer.d.ts +28 -0
  310. package/dist/resolution/goframe-synthesizer.d.ts.map +1 -0
  311. package/dist/resolution/goframe-synthesizer.js +158 -0
  312. package/dist/resolution/goframe-synthesizer.js.map +1 -0
  313. package/dist/resolution/import-resolver.d.ts +10 -0
  314. package/dist/resolution/import-resolver.d.ts.map +1 -1
  315. package/dist/resolution/import-resolver.js +125 -2
  316. package/dist/resolution/import-resolver.js.map +1 -1
  317. package/dist/resolution/index.d.ts +37 -0
  318. package/dist/resolution/index.d.ts.map +1 -1
  319. package/dist/resolution/index.js +306 -3
  320. package/dist/resolution/index.js.map +1 -1
  321. package/dist/resolution/name-matcher.d.ts +41 -0
  322. package/dist/resolution/name-matcher.d.ts.map +1 -1
  323. package/dist/resolution/name-matcher.js +519 -14
  324. package/dist/resolution/name-matcher.js.map +1 -1
  325. package/dist/resolution/strip-comments.d.ts +1 -1
  326. package/dist/resolution/strip-comments.d.ts.map +1 -1
  327. package/dist/resolution/strip-comments.js +2 -0
  328. package/dist/resolution/strip-comments.js.map +1 -1
  329. package/dist/resolution/types.d.ts +20 -3
  330. package/dist/resolution/types.d.ts.map +1 -1
  331. package/dist/search/query-utils.d.ts +17 -1
  332. package/dist/search/query-utils.d.ts.map +1 -1
  333. package/dist/search/query-utils.js +79 -10
  334. package/dist/search/query-utils.js.map +1 -1
  335. package/dist/sync/git-hooks.d.ts +4 -4
  336. package/dist/sync/git-hooks.js +5 -5
  337. package/dist/sync/watcher.d.ts +69 -2
  338. package/dist/sync/watcher.d.ts.map +1 -1
  339. package/dist/sync/watcher.js +226 -21
  340. package/dist/sync/watcher.js.map +1 -1
  341. package/dist/sync/worktree.d.ts +3 -3
  342. package/dist/sync/worktree.js +5 -5
  343. package/dist/telemetry/index.d.ts +143 -0
  344. package/dist/telemetry/index.d.ts.map +1 -0
  345. package/dist/telemetry/index.js +541 -0
  346. package/dist/telemetry/index.js.map +1 -0
  347. package/dist/types.d.ts +18 -3
  348. package/dist/types.d.ts.map +1 -1
  349. package/dist/types.js +3 -1
  350. package/dist/types.js.map +1 -1
  351. package/dist/upgrade/index.d.ts.map +1 -1
  352. package/dist/upgrade/index.js +46 -10
  353. package/dist/upgrade/index.js.map +1 -1
  354. package/dist/utils.d.ts +46 -27
  355. package/dist/utils.d.ts.map +1 -1
  356. package/dist/utils.js +87 -53
  357. package/dist/utils.js.map +1 -1
  358. package/package.json +57 -57
  359. package/scripts/add-lang/bench.sh +60 -60
  360. package/scripts/add-lang/check-grammar.mjs +75 -75
  361. package/scripts/add-lang/dump-ast.mjs +103 -103
  362. package/scripts/add-lang/verify-extraction.mjs +70 -70
  363. package/scripts/agent-eval/ab-adoption.sh +91 -0
  364. package/scripts/agent-eval/ab-hook.sh +86 -0
  365. package/scripts/agent-eval/ab-impl.sh +78 -0
  366. package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -0
  367. package/scripts/agent-eval/ab-sufficiency.sh +78 -0
  368. package/scripts/agent-eval/arms-F.sh +21 -21
  369. package/scripts/agent-eval/arms-matrix.sh +37 -37
  370. package/scripts/agent-eval/audit.sh +68 -68
  371. package/scripts/agent-eval/bench-readme.sh +28 -28
  372. package/scripts/agent-eval/bench-why-repo.sh +22 -22
  373. package/scripts/agent-eval/block-read-hook.sh +19 -19
  374. package/scripts/agent-eval/hook-settings.json +15 -15
  375. package/scripts/agent-eval/itrun.sh +120 -120
  376. package/scripts/agent-eval/offload-eval-3arm.sh +72 -0
  377. package/scripts/agent-eval/offload-eval-cost.mjs +133 -0
  378. package/scripts/agent-eval/offload-eval-effort.mjs +108 -0
  379. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -0
  380. package/scripts/agent-eval/offload-eval-frontload.sh +47 -0
  381. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -0
  382. package/scripts/agent-eval/offload-eval-hook.mjs +84 -0
  383. package/scripts/agent-eval/offload-eval-judge.mjs +103 -0
  384. package/scripts/agent-eval/offload-eval-matrix.sh +20 -0
  385. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -0
  386. package/scripts/agent-eval/offload-eval-refs1.sh +50 -0
  387. package/scripts/agent-eval/offload-eval-setup.sh +24 -0
  388. package/scripts/agent-eval/offload-eval-styles.sh +72 -0
  389. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -0
  390. package/scripts/agent-eval/offload-eval.md +76 -0
  391. package/scripts/agent-eval/parse-arms.mjs +116 -116
  392. package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
  393. package/scripts/agent-eval/parse-run.mjs +45 -45
  394. package/scripts/agent-eval/parse-session.mjs +93 -93
  395. package/scripts/agent-eval/probe-context.mjs +21 -21
  396. package/scripts/agent-eval/probe-explore.mjs +40 -40
  397. package/scripts/agent-eval/probe-node.mjs +20 -20
  398. package/scripts/agent-eval/probe-sweep.mjs +119 -119
  399. package/scripts/agent-eval/probe-trace.mjs +20 -20
  400. package/scripts/agent-eval/redirect-read-hook.sh +38 -0
  401. package/scripts/agent-eval/run-agent.sh +34 -34
  402. package/scripts/agent-eval/run-all.sh +69 -67
  403. package/scripts/agent-eval/run-arms.sh +56 -56
  404. package/scripts/agent-eval/seq-matrix.mjs +137 -137
  405. package/scripts/build-bundle.sh +118 -118
  406. package/scripts/extract-release-notes.mjs +130 -130
  407. package/scripts/local-install.sh +41 -41
  408. package/scripts/npm-sdk.js +75 -75
  409. package/scripts/npm-shim.js +246 -246
  410. package/scripts/pack-npm.sh +119 -119
  411. package/scripts/prepare-release.mjs +270 -270
  412. package/scripts/qa_eval/README.md +400 -0
  413. package/scripts/qa_eval/agent_runner.py +526 -0
  414. package/scripts/qa_eval/data/.gitignore +4 -0
  415. package/scripts/qa_eval/data/test-set.jsonl +22 -0
  416. package/scripts/qa_eval/eval_metrics.py +233 -0
  417. package/scripts/qa_eval/external_agent.py +577 -0
  418. package/scripts/qa_eval/llm_config.py +92 -0
  419. package/scripts/qa_eval/memory_monitor.py +132 -0
  420. package/scripts/qa_eval/my_answer_accuracy.py +187 -0
  421. package/scripts/qa_eval/requirements.txt +2 -0
  422. package/scripts/qa_eval/run_pipeline.py +702 -0
  423. package/scripts/qa_eval/stats_efficiency.py +279 -0
  424. package/scripts/qa_eval/stats_scores.py +207 -0
  425. package/dist/bin/codegraph.d.ts +0 -26
  426. package/dist/bin/codegraph.d.ts.map +0 -1
  427. package/dist/bin/codegraph.js +0 -1572
  428. package/dist/bin/codegraph.js.map +0 -1
  429. package/dist/extraction/arkanalyzer-extractor.d.ts +0 -6
  430. package/dist/extraction/arkanalyzer-extractor.d.ts.map +0 -1
  431. package/dist/extraction/arkanalyzer-extractor.js +0 -11
  432. package/dist/extraction/arkanalyzer-extractor.js.map +0 -1
  433. package/dist/extraction/arkanalyzer-project.d.ts +0 -20
  434. package/dist/extraction/arkanalyzer-project.d.ts.map +0 -1
  435. package/dist/extraction/arkanalyzer-project.js +0 -596
  436. package/dist/extraction/arkanalyzer-project.js.map +0 -1
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * CodeGraph CLI
4
+ * HomeGraph CLI
5
5
  *
6
- * Command-line interface for CodeGraph code intelligence.
6
+ * Command-line interface for HomeGraph code intelligence.
7
7
  *
8
8
  * Usage:
9
9
  * homegraph Run interactive installer (when no args)
10
10
  * homegraph install Run interactive installer
11
- * homegraph uninstall Remove CodeGraph from your agents
12
- * homegraph init [path] Initialize CodeGraph in a project
13
- * homegraph uninit [path] Remove CodeGraph from a project
11
+ * homegraph uninstall Remove HomeGraph from your agents
12
+ * homegraph init [path] Initialize HomeGraph in a project
13
+ * homegraph uninit [path] Remove HomeGraph from a project
14
14
  * homegraph index [path] Index all files in the project
15
15
  * homegraph sync [path] Sync changes since last index
16
16
  * homegraph status [path] Show index status
@@ -21,7 +21,7 @@
21
21
  * homegraph callees <symbol> Find what a function/method calls
22
22
  * homegraph impact <symbol> Analyze what code is affected by changing a symbol
23
23
  * homegraph affected [files] Find test files affected by changes
24
- * homegraph upgrade [version] Update CodeGraph to the latest release
24
+ * homegraph upgrade [version] Update HomeGraph to the latest release
25
25
  */
26
26
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
27
27
  if (k2 === undefined) k2 = k;
@@ -65,16 +65,18 @@ const worktree_1 = require("../sync/worktree");
65
65
  const shimmer_progress_1 = require("../ui/shimmer-progress");
66
66
  const glyphs_1 = require("../ui/glyphs");
67
67
  const node_version_check_1 = require("./node-version-check");
68
+ const fatal_handler_1 = require("./fatal-handler");
68
69
  const wasm_runtime_flags_1 = require("../extraction/wasm-runtime-flags");
69
70
  const extraction_version_1 = require("../extraction/extraction-version");
70
- // Lazy-load heavy modules (CodeGraph, runInstaller) to keep CLI startup fast.
71
- async function loadCodeGraph() {
71
+ const telemetry_1 = require("../telemetry");
72
+ // Lazy-load heavy modules (HomeGraph, runInstaller) to keep CLI startup fast.
73
+ async function loadHomeGraph() {
72
74
  try {
73
75
  return await Promise.resolve().then(() => __importStar(require('../index')));
74
76
  }
75
77
  catch (err) {
76
78
  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.`);
79
+ console.error(`\x1b[31m${(0, glyphs_1.getGlyphs)().err}\x1b[0m Failed to load HomeGraph modules.`);
78
80
  console.error(`\n Node: ${process.version} Platform: ${process.platform} ${process.arch}`);
79
81
  console.error(`\n Error: ${msg}`);
80
82
  console.error('\n Try reinstalling with: npm install -g homegraph\n');
@@ -85,7 +87,7 @@ async function loadCodeGraph() {
85
87
  // which fails for ESM-only packages. This bypasses the transformation.
86
88
  // eslint-disable-next-line @typescript-eslint/no-implied-eval
87
89
  const importESM = new Function('specifier', 'return import(specifier)');
88
- // Block CodeGraph on Node.js 25.x — V8's turboshaft WASM JIT has a Zone
90
+ // Block HomeGraph on Node.js 25.x — V8's turboshaft WASM JIT has a Zone
89
91
  // allocator bug that reliably crashes when compiling tree-sitter
90
92
  // grammars (see #54, #81, #140). The previous behaviour was a soft
91
93
  // console.warn that scrolls off-screen before the OOM crash 30 seconds
@@ -117,6 +119,12 @@ if (nodeMajor < node_version_check_1.MIN_NODE_MAJOR) {
117
119
  // passes the flag. Must run before any grammar (in the parse worker, which
118
120
  // inherits this process's flags) is compiled. See ../extraction/wasm-runtime-flags.
119
121
  (0, wasm_runtime_flags_1.relaunchWithWasmRuntimeFlagsIfNeeded)(__filename);
122
+ // Last-resort fatal handlers: log a bounded line and exit non-zero. A fault
123
+ // that reaches here escaped every boundary, so the process is in an undefined
124
+ // state — keeping it alive is what let the detached MCP daemon orphan and pin a
125
+ // CPU core with no recovery (#799, #850). Installed before the command branch
126
+ // so it also covers a synchronous throw during startup. See ./fatal-handler.
127
+ (0, fatal_handler_1.installFatalHandlers)();
120
128
  // Check if running with no arguments - run installer
121
129
  if (process.argv.length === 2) {
122
130
  Promise.resolve().then(() => __importStar(require('../installer'))).then(({ runInstaller }) => runInstaller()).catch((err) => {
@@ -128,16 +136,21 @@ else {
128
136
  // Normal CLI flow
129
137
  main();
130
138
  }
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
139
  function main() {
138
140
  const program = new commander_1.Command();
139
141
  // Version from package.json
140
142
  const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf-8'));
143
+ // Make the version trivial to reach. commander's `.version()` (below) wires up
144
+ // `--version` and `-V`; intercept the spellings it can't — lowercase `-v` and
145
+ // single-dash `-version` — before any parsing. (commander's version short flag
146
+ // is the capital `-V`, and its parser rejects a multi-character single-dash
147
+ // flag.) The bare `homegraph version` subcommand is registered further down so
148
+ // the affordance also shows up in `homegraph --help`.
149
+ const firstArg = process.argv[2];
150
+ if (firstArg === '-v' || firstArg === '-version') {
151
+ console.log(packageJson.version);
152
+ return;
153
+ }
141
154
  // =============================================================================
142
155
  // ANSI Color Helpers (avoid chalk ESM issues)
143
156
  // =============================================================================
@@ -168,12 +181,36 @@ function main() {
168
181
  .name('homegraph')
169
182
  .description('Code intelligence and knowledge graph for any codebase')
170
183
  .version(packageJson.version);
184
+ // Anonymous usage telemetry (see TELEMETRY.md): record the invoked subcommand
185
+ // NAME only — never arguments or paths. Counts buffer locally; network sends
186
+ // piggyback on commands that run long anyway (quick commands only append to
187
+ // the local buffer at exit, costing nothing).
188
+ // install/uninstall are absent on purpose: the installer flushes at its own
189
+ // end, AFTER its consent prompt — a flush here would fire the first-run
190
+ // notice before the user ever sees the toggle.
191
+ const TELEMETRY_FLUSH_COMMANDS = new Set(['init', 'uninit', 'index', 'sync', 'upgrade']);
192
+ program.hook('preAction', (_thisCommand, actionCommand) => {
193
+ try {
194
+ // The detached daemon re-invokes `serve --mcp` internally — not a user action.
195
+ if (process.env.HOMEGRAPH_DAEMON_INTERNAL)
196
+ return;
197
+ const name = actionCommand.name();
198
+ if (name === 'telemetry')
199
+ return; // managing telemetry is not usage
200
+ (0, telemetry_1.getTelemetry)().recordUsage('cli_command', name, true);
201
+ if (TELEMETRY_FLUSH_COMMANDS.has(name))
202
+ (0, telemetry_1.getTelemetry)().maybeFlush();
203
+ }
204
+ catch {
205
+ /* telemetry must never break the CLI */
206
+ }
207
+ });
171
208
  // =============================================================================
172
209
  // Helper Functions
173
210
  // =============================================================================
174
211
  /**
175
212
  * Resolve project path from argument or current directory
176
- * Walks up parent directories to find nearest initialized CodeGraph project
213
+ * Walks up parent directories to find nearest initialized HomeGraph project
177
214
  * (must have .homegraph/homegraph.db, not just .homegraph/lessons.db)
178
215
  */
179
216
  function resolveProjectPath(pathArg) {
@@ -182,8 +219,8 @@ function main() {
182
219
  if ((0, directory_1.isInitialized)(absolutePath)) {
183
220
  return absolutePath;
184
221
  }
185
- // Walk up to find nearest parent with CodeGraph initialized
186
- // Note: findNearestCodeGraphRoot finds any .homegraph folder, but we need one with homegraph.db
222
+ // Walk up to find nearest parent with HomeGraph initialized
223
+ // Note: findNearestHomeGraphRoot finds any .homegraph folder, but we need one with homegraph.db
187
224
  let current = absolutePath;
188
225
  const root = path.parse(current).root;
189
226
  while (current !== root) {
@@ -341,7 +378,7 @@ function main() {
341
378
  }
342
379
  }
343
380
  else if (projectPath) {
344
- const logPath = path.join(projectPath, '.homegraph', 'errors.log');
381
+ const logPath = path.join((0, directory_1.getHomeGraphDir)(projectPath), 'errors.log');
345
382
  if (fs.existsSync(logPath)) {
346
383
  fs.unlinkSync(logPath);
347
384
  }
@@ -351,7 +388,7 @@ function main() {
351
388
  * Write detailed error log to .homegraph/errors.log
352
389
  */
353
390
  function writeErrorLog(projectPath, errors) {
354
- const cgDir = path.join(projectPath, '.homegraph');
391
+ const cgDir = (0, directory_1.getHomeGraphDir)(projectPath);
355
392
  if (!fs.existsSync(cgDir))
356
393
  return;
357
394
  const logPath = path.join(cgDir, 'errors.log');
@@ -374,7 +411,7 @@ function main() {
374
411
  }
375
412
  }
376
413
  const lines = [
377
- `CodeGraph Error Log - ${new Date().toISOString()}`,
414
+ `HomeGraph Error Log - ${new Date().toISOString()}`,
378
415
  `${errorsByFile.size} files with errors`,
379
416
  '',
380
417
  ];
@@ -388,22 +425,43 @@ function main() {
388
425
  }
389
426
  fs.writeFileSync(logPath, lines.join('\n') + '\n');
390
427
  }
428
+ /**
429
+ * Telemetry for a completed full index (see TELEMETRY.md). The bounded flush
430
+ * keeps init/index responsive (these commands just ran for seconds anyway)
431
+ * while delivering the event promptly.
432
+ */
433
+ async function recordIndexTelemetry(cg, result) {
434
+ (0, telemetry_1.recordIndexEvent)(cg, result);
435
+ await (0, telemetry_1.getTelemetry)().flushNow();
436
+ }
391
437
  // =============================================================================
392
438
  // Commands
393
439
  // =============================================================================
394
440
  /**
395
- * codegraph init [path]
441
+ * homegraph init [path]
396
442
  */
397
443
  program
398
444
  .command('init [path]')
399
- .description('Initialize CodeGraph in a project directory and build the initial index')
445
+ .description('Initialize HomeGraph in a project directory and build the initial index')
400
446
  .option('-i, --index', 'Deprecated: indexing now runs by default; flag accepted for backward compatibility')
447
+ .option('-f, --force', 'Initialize even if the path looks like your home directory or a filesystem root')
401
448
  .option('-v, --verbose', 'Show detailed worker lifecycle and memory info')
402
449
  .action(async (pathArg, options) => {
403
450
  const projectPath = path.resolve(pathArg || process.cwd());
404
451
  const clack = await importESM('@clack/prompts');
405
- clack.intro('Initializing CodeGraph');
452
+ clack.intro('Initializing HomeGraph');
406
453
  try {
454
+ // Refuse to index your home directory / a filesystem root — it pulls in
455
+ // caches, other projects, and your whole tree (a multi-GB index + watcher
456
+ // churn, and on pre-1.0 macOS a machine-crashing fd blowup, #845).
457
+ const unsafe = (0, directory_1.unsafeIndexRootReason)(projectPath);
458
+ if (unsafe && !options.force) {
459
+ clack.log.error(`Refusing to initialize in ${projectPath} — it looks like ${unsafe}.`);
460
+ clack.log.info('Run this inside a specific project directory, or pass --force if you really mean to index everything under it.');
461
+ clack.outro('');
462
+ process.exitCode = 1;
463
+ return;
464
+ }
407
465
  if ((0, directory_1.isInitialized)(projectPath)) {
408
466
  clack.log.warn(`Already initialized in ${projectPath}`);
409
467
  clack.log.info('Use "homegraph index" to re-index or "homegraph sync" to update');
@@ -415,8 +473,8 @@ function main() {
415
473
  clack.outro('');
416
474
  return;
417
475
  }
418
- const { default: CodeGraph } = await loadCodeGraph();
419
- const cg = await CodeGraph.init(projectPath, { index: false });
476
+ const { default: HomeGraph } = await loadHomeGraph();
477
+ const cg = await HomeGraph.init(projectPath, { index: false });
420
478
  clack.log.success(`Initialized in ${projectPath}`);
421
479
  // Indexing runs by default now. The legacy -i/--index flag is still
422
480
  // accepted (so existing muscle memory and scripts don't break) but is a
@@ -437,6 +495,7 @@ function main() {
437
495
  await progress.stop();
438
496
  }
439
497
  printIndexResult(clack, result, projectPath);
498
+ await recordIndexTelemetry(cg, result);
440
499
  try {
441
500
  const { offerWatchFallback } = await Promise.resolve().then(() => __importStar(require('../installer')));
442
501
  await offerWatchFallback(clack, projectPath);
@@ -451,17 +510,17 @@ function main() {
451
510
  }
452
511
  });
453
512
  /**
454
- * codegraph uninit [path]
513
+ * homegraph uninit [path]
455
514
  */
456
515
  program
457
516
  .command('uninit [path]')
458
- .description('Remove CodeGraph from a project (deletes .homegraph/ directory)')
517
+ .description('Remove HomeGraph from a project (deletes .homegraph/ directory)')
459
518
  .option('-f, --force', 'Skip confirmation prompt')
460
519
  .action(async (pathArg, options) => {
461
520
  const projectPath = resolveProjectPath(pathArg);
462
521
  try {
463
522
  if (!(0, directory_1.isInitialized)(projectPath)) {
464
- warn(`CodeGraph is not initialized in ${projectPath}`);
523
+ warn(`HomeGraph is not initialized in ${projectPath}`);
465
524
  return;
466
525
  }
467
526
  if (!options.force) {
@@ -469,7 +528,7 @@ function main() {
469
528
  const readline = await Promise.resolve().then(() => __importStar(require('readline')));
470
529
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
471
530
  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);
531
+ rl.question(chalk.yellow(`${(0, glyphs_1.getGlyphs)().warn} This will permanently delete all HomeGraph data. Continue? (y/N) `), resolve);
473
532
  });
474
533
  rl.close();
475
534
  if (answer.toLowerCase() !== 'y') {
@@ -477,8 +536,8 @@ function main() {
477
536
  return;
478
537
  }
479
538
  }
480
- const { default: CodeGraph } = await loadCodeGraph();
481
- const cg = CodeGraph.openSync(projectPath);
539
+ const { default: HomeGraph } = await loadHomeGraph();
540
+ const cg = HomeGraph.openSync(projectPath);
482
541
  cg.uninitialize();
483
542
  // Clean up any git sync hooks we installed (no-op if none / not a repo).
484
543
  try {
@@ -489,7 +548,14 @@ function main() {
489
548
  }
490
549
  }
491
550
  catch { /* non-fatal */ }
492
- success(`Removed CodeGraph from ${projectPath}`);
551
+ success(`Removed HomeGraph from ${projectPath}`);
552
+ // Churn signal — and flush now, since after an uninit there may be no
553
+ // "next run" to deliver it.
554
+ try {
555
+ (0, telemetry_1.getTelemetry)().recordLifecycle('uninstall', {});
556
+ await (0, telemetry_1.getTelemetry)().flushNow();
557
+ }
558
+ catch { /* non-fatal */ }
493
559
  }
494
560
  catch (err) {
495
561
  error(`Failed to uninitialize: ${err instanceof Error ? err.message : String(err)}`);
@@ -497,28 +563,35 @@ function main() {
497
563
  }
498
564
  });
499
565
  /**
500
- * codegraph index [path]
566
+ * homegraph index [path]
501
567
  */
502
568
  program
503
569
  .command('index [path]')
504
- .description('Index all files in the project')
505
- .option('-f, --force', 'Force full re-index even if already indexed')
570
+ .description('Rebuild the full index from scratch (same result as a fresh init)')
571
+ .option('-f, --force', 'Index even if the path looks like your home directory or a filesystem root')
506
572
  .option('-q, --quiet', 'Suppress progress output')
507
573
  .option('-v, --verbose', 'Show detailed worker lifecycle and memory info')
508
574
  .action(async (pathArg, options) => {
509
575
  const projectPath = resolveProjectPath(pathArg);
510
576
  try {
577
+ // Don't (re)index your home directory / a filesystem root (#845). --force
578
+ // doubles as the override.
579
+ const unsafe = (0, directory_1.unsafeIndexRootReason)(projectPath);
580
+ if (unsafe && !options.force) {
581
+ error(`Refusing to index ${projectPath} — it looks like ${unsafe}. Pass --force to override.`);
582
+ process.exit(1);
583
+ }
511
584
  if (!(0, directory_1.isInitialized)(projectPath)) {
512
- error(`CodeGraph not initialized in ${projectPath}`);
585
+ error(`HomeGraph not initialized in ${projectPath}`);
513
586
  info('Run "homegraph init" first');
514
587
  process.exit(1);
515
588
  }
516
- const { default: CodeGraph } = await loadCodeGraph();
517
- const cg = await CodeGraph.open(projectPath);
589
+ const { default: HomeGraph } = await loadHomeGraph();
590
+ const cg = await HomeGraph.open(projectPath);
518
591
  if (options.quiet) {
519
- // Quiet mode: no UI, just run
520
- if (options.force)
521
- cg.clear();
592
+ // Quiet mode: no UI, just run. `index` is a full re-index, so clear the
593
+ // existing graph and rebuild from scratch (see the note below — #874).
594
+ cg.clear();
522
595
  const result = await cg.indexAll();
523
596
  if (!result.success)
524
597
  process.exit(1);
@@ -527,10 +600,12 @@ function main() {
527
600
  }
528
601
  const clack = await importESM('@clack/prompts');
529
602
  clack.intro('Indexing project');
530
- if (options.force) {
531
- cg.clear();
532
- clack.log.info('Cleared existing index');
533
- }
603
+ // `index` is a FULL re-index: clear the existing graph and rebuild it from
604
+ // scratch so the result is identical to a fresh `init`. Without the clear,
605
+ // indexAll() skips every unchanged file by its content hash and reports
606
+ // "0 nodes, 0 edges" against the already-populated graph — which reads as
607
+ // "index wiped my index" (#874). For fast incremental updates use `sync`.
608
+ cg.clear();
534
609
  let result;
535
610
  if (options.verbose) {
536
611
  result = await cg.indexAll({
@@ -547,6 +622,7 @@ function main() {
547
622
  await progress.stop();
548
623
  }
549
624
  printIndexResult(clack, result, projectPath);
625
+ await recordIndexTelemetry(cg, result);
550
626
  if (!result.success) {
551
627
  process.exit(1);
552
628
  }
@@ -559,7 +635,7 @@ function main() {
559
635
  }
560
636
  });
561
637
  /**
562
- * codegraph sync [path]
638
+ * homegraph sync [path]
563
639
  */
564
640
  program
565
641
  .command('sync [path]')
@@ -570,19 +646,19 @@ function main() {
570
646
  try {
571
647
  if (!(0, directory_1.isInitialized)(projectPath)) {
572
648
  if (!options.quiet) {
573
- error(`CodeGraph not initialized in ${projectPath}`);
649
+ error(`HomeGraph not initialized in ${projectPath}`);
574
650
  }
575
651
  process.exit(1);
576
652
  }
577
- const { default: CodeGraph } = await loadCodeGraph();
578
- const cg = await CodeGraph.open(projectPath);
653
+ const { default: HomeGraph } = await loadHomeGraph();
654
+ const cg = await HomeGraph.open(projectPath);
579
655
  if (options.quiet) {
580
656
  await cg.sync();
581
657
  cg.destroy();
582
658
  return;
583
659
  }
584
660
  const clack = await importESM('@clack/prompts');
585
- clack.intro('Syncing CodeGraph');
661
+ clack.intro('Syncing HomeGraph');
586
662
  process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
587
663
  const progress = (0, shimmer_progress_1.createShimmerProgress)();
588
664
  const result = await cg.sync({
@@ -615,7 +691,7 @@ function main() {
615
691
  }
616
692
  });
617
693
  /**
618
- * codegraph status [path]
694
+ * homegraph status [path]
619
695
  */
620
696
  program
621
697
  .command('status [path]')
@@ -635,19 +711,19 @@ function main() {
635
711
  initialized: false,
636
712
  version: packageJson.version,
637
713
  projectPath,
638
- indexPath: (0, directory_1.getCodeGraphDir)(projectPath),
714
+ indexPath: (0, directory_1.getHomeGraphDir)(projectPath),
639
715
  lastIndexed: null,
640
716
  }));
641
717
  return;
642
718
  }
643
- console.log(chalk.bold('\nCodeGraph Status\n'));
719
+ console.log(chalk.bold('\nHomeGraph Status\n'));
644
720
  info(`Project: ${projectPath}`);
645
721
  warn('Not initialized');
646
722
  info('Run "homegraph init" to initialize');
647
723
  return;
648
724
  }
649
- const { default: CodeGraph } = await loadCodeGraph();
650
- const cg = await CodeGraph.open(projectPath);
725
+ const { default: HomeGraph } = await loadHomeGraph();
726
+ const cg = await HomeGraph.open(projectPath);
651
727
  const stats = cg.getStats();
652
728
  const changes = cg.getChangedFiles();
653
729
  const backend = cg.getBackend();
@@ -661,7 +737,7 @@ function main() {
661
737
  initialized: true,
662
738
  version: packageJson.version,
663
739
  projectPath,
664
- indexPath: (0, directory_1.getCodeGraphDir)(projectPath),
740
+ indexPath: (0, directory_1.getHomeGraphDir)(projectPath),
665
741
  lastIndexed: lastIndexedMs != null ? new Date(lastIndexedMs).toISOString() : null,
666
742
  fileCount: stats.fileCount,
667
743
  nodeCount: stats.nodeCount,
@@ -689,7 +765,7 @@ function main() {
689
765
  cg.destroy();
690
766
  return;
691
767
  }
692
- console.log(chalk.bold('\nCodeGraph Status\n'));
768
+ console.log(chalk.bold('\nHomeGraph Status\n'));
693
769
  // Project info
694
770
  console.log(chalk.cyan('Project:'), projectPath);
695
771
  if (worktreeMismatch) {
@@ -757,7 +833,7 @@ function main() {
757
833
  if (reindexRecommended) {
758
834
  const builtWith = buildInfo.version ? `v${buildInfo.version.replace(/^v/, '')}` : 'an earlier version';
759
835
  warn(`Index was built by ${builtWith}; re-index to pick up this engine's improvements.`);
760
- info('Run "homegraph index -f" (full rebuild) or "homegraph sync"');
836
+ info('Run "homegraph index" (full rebuild) or "homegraph sync"');
761
837
  console.log();
762
838
  }
763
839
  cg.destroy();
@@ -768,7 +844,7 @@ function main() {
768
844
  }
769
845
  });
770
846
  /**
771
- * codegraph query <search>
847
+ * homegraph query <search>
772
848
  */
773
849
  program
774
850
  .command('query <search>')
@@ -781,11 +857,11 @@ function main() {
781
857
  const projectPath = resolveProjectPath(options.path);
782
858
  try {
783
859
  if (!(0, directory_1.isInitialized)(projectPath)) {
784
- error(`CodeGraph not initialized in ${projectPath}`);
860
+ error(`HomeGraph not initialized in ${projectPath}`);
785
861
  process.exit(1);
786
862
  }
787
- const { default: CodeGraph } = await loadCodeGraph();
788
- const cg = await CodeGraph.open(projectPath);
863
+ const { default: HomeGraph } = await loadHomeGraph();
864
+ const cg = await HomeGraph.open(projectPath);
789
865
  const limit = parseInt(options.limit || '10', 10);
790
866
  const rawResults = cg.searchNodes(search, {
791
867
  limit,
@@ -832,7 +908,205 @@ function main() {
832
908
  }
833
909
  });
834
910
  /**
835
- * codegraph files [path]
911
+ * homegraph explore <query...>
912
+ *
913
+ * The CLI face of the MCP homegraph_explore tool — same handler, same
914
+ * output (source of the relevant symbols grouped by file + the call path
915
+ * among them). Exists so agents WITHOUT the MCP tools — Task-tool
916
+ * subagents (which don't inherit MCP tools, #704) and non-MCP harnesses —
917
+ * can reach the graph through a plain shell command.
918
+ */
919
+ program
920
+ .command('explore <query...>')
921
+ .description('Explore an area: relevant symbols\' source + call paths in one shot (same output as the homegraph_explore MCP tool)')
922
+ .option('-p, --path <path>', 'Project path')
923
+ .option('--max-files <number>', 'Maximum number of files to include source from')
924
+ .action(async (queryParts, options) => {
925
+ const projectPath = resolveProjectPath(options.path);
926
+ try {
927
+ if (!(0, directory_1.isInitialized)(projectPath)) {
928
+ error(`HomeGraph isn't available here — no .homegraph/ index exists in ${projectPath}. If you are an AI agent: continue with your usual tools; indexing is the user's decision, do not run it yourself. (The project owner can enable HomeGraph with 'homegraph init'.)`);
929
+ process.exit(1);
930
+ }
931
+ const { default: HomeGraph } = await loadHomeGraph();
932
+ const cg = await HomeGraph.open(projectPath);
933
+ const { ToolHandler } = await Promise.resolve().then(() => __importStar(require('../mcp/tools')));
934
+ const handler = new ToolHandler(cg);
935
+ const args = { query: queryParts.join(' ') };
936
+ if (options.maxFiles)
937
+ args.maxFiles = parseInt(options.maxFiles, 10);
938
+ const result = await handler.execute('homegraph_explore', args);
939
+ console.log(result.content[0]?.text ?? '');
940
+ cg.destroy();
941
+ if (result.isError)
942
+ process.exit(1);
943
+ }
944
+ catch (err) {
945
+ error(`Explore failed: ${err instanceof Error ? err.message : String(err)}`);
946
+ process.exit(1);
947
+ }
948
+ });
949
+ /**
950
+ * homegraph prompt-hook (hidden)
951
+ *
952
+ * A Claude Code `UserPromptSubmit` hook entry point. Reads `{prompt, cwd}` JSON
953
+ * on stdin; for a structural/flow/impact prompt it runs `homegraph_explore` on
954
+ * the indexed project and prints the result to stdout, which Claude injects into
955
+ * the agent's context — so the agent's reflex grep/read has nothing left to find
956
+ * and reliably uses HomeGraph (the adoption problem). Installed by the installer
957
+ * into Claude's settings.json (opt-in, default-yes).
958
+ *
959
+ * LOAD-BEARING: this must NEVER break the user's prompt. Every failure path —
960
+ * kill-switch, non-structural prompt, no index, engine error — exits 0 with no
961
+ * output. The only effect is additive context when it can confidently provide it.
962
+ */
963
+ program
964
+ .command('prompt-hook', { hidden: true })
965
+ .description('Claude UserPromptSubmit hook: inject HomeGraph context for structural prompts (reads {prompt,cwd} JSON on stdin)')
966
+ .action(async () => {
967
+ try {
968
+ // Kill-switch: lets a user disable the nudge without uninstalling /
969
+ // editing settings.json (CI, low-power machines, personal preference).
970
+ if (process.env.HOMEGRAPH_NO_PROMPT_HOOK === '1' || process.env.HOMEGRAPH_PROMPT_HOOK === '0')
971
+ return;
972
+ if (process.stdin.isTTY)
973
+ return; // invoked by hand, no piped payload
974
+ const raw = await new Promise((resolve) => {
975
+ let data = '';
976
+ process.stdin.setEncoding('utf8');
977
+ process.stdin.on('data', (c) => { data += c; });
978
+ process.stdin.on('end', () => resolve(data));
979
+ process.stdin.on('error', () => resolve(data));
980
+ });
981
+ let input = {};
982
+ try {
983
+ input = JSON.parse(raw);
984
+ }
985
+ catch {
986
+ return;
987
+ }
988
+ const prompt = String(input.prompt || '');
989
+ // Gate: only structural / flow / impact / where-how prompts get context.
990
+ // A cheap regex keeps every other prompt ("fix this typo") a zero-cost
991
+ // no-op so we never add latency where there's no structural answer to give.
992
+ const STRUCTURAL = /\b(how|where|trace|flow|path|reach(?:es|ed)?|call(?:s|ed|er|ers|ee)?|depend|impact|affect|wired?|connect|implement|architect|structure|breaks?|what calls|why does)\b/i;
993
+ if (!prompt || !STRUCTURAL.test(prompt))
994
+ return;
995
+ // Decide what to inject, shaped by WHERE the index(es) are: the nearest
996
+ // indexed ancestor of cwd, or — when cwd is an un-indexed workspace root
997
+ // whose indexed project(s) live in sub-dirs (the monorepo case, #964) —
998
+ // the sub-project the prompt points at, plus a `projectPath` nudge for any
999
+ // others. Without the down-scan the hook injected nothing at a monorepo
1000
+ // root (it only walked up), so the validated adoption lever never fired
1001
+ // exactly where the agent most needs it.
1002
+ const plan = (0, directory_1.planFrontload)(String(input.cwd || process.cwd()), prompt);
1003
+ if (!plan.exploreRoot && plan.nudgeProjects.length === 0)
1004
+ return; // nothing reachable — the agent's normal tools apply
1005
+ // A "pass projectPath" line for indexed sub-projects we did NOT front-load.
1006
+ // Follow-up homegraph_explore calls against a sub-project (cwd isn't its
1007
+ // index root) need an explicit projectPath, so spell it out.
1008
+ const nudge = (projects, lead) => `${lead}\n${projects.map((p) => ` - projectPath: "${p}"`).join('\n')}\n`;
1009
+ if (plan.exploreRoot) {
1010
+ const { default: HomeGraph } = await loadHomeGraph();
1011
+ const cg = await HomeGraph.open(plan.exploreRoot);
1012
+ try {
1013
+ const { ToolHandler } = await Promise.resolve().then(() => __importStar(require('../mcp/tools')));
1014
+ const handler = new ToolHandler(cg);
1015
+ const result = await handler.execute('homegraph_explore', { query: prompt });
1016
+ const text = result.content[0]?.text ?? '';
1017
+ if (!result.isError && text.trim()) {
1018
+ // Cap the injection so a large-repo explore can't flood the prompt.
1019
+ const MAX = 16000;
1020
+ const body = text.length > MAX ? `${text.slice(0, MAX)}\n…(truncated; call homegraph_explore for the rest)` : text;
1021
+ // For a front-loaded SUB-project, a follow-up explore needs its path.
1022
+ const more = plan.viaSubScan
1023
+ ? `call homegraph_explore with projectPath: "${plan.exploreRoot}" for more`
1024
+ : 'call homegraph_explore for more';
1025
+ const others = plan.nudgeProjects.length
1026
+ ? `\n${nudge(plan.nudgeProjects, 'Other indexed projects in this workspace — pass projectPath to query them:')}`
1027
+ : '';
1028
+ process.stdout.write(`<homegraph_context note="Structural context from HomeGraph for this prompt — treat returned source as already read; ${more}.">\n${body}${others}\n</homegraph_context>\n`);
1029
+ }
1030
+ }
1031
+ finally {
1032
+ cg.destroy();
1033
+ }
1034
+ }
1035
+ else {
1036
+ // Several indexed sub-projects, none a clear match — don't guess; tell
1037
+ // the agent they exist and how to query one.
1038
+ process.stdout.write(`<homegraph_context note="HomeGraph is available for this workspace's indexed sub-projects — query one by passing projectPath to homegraph_explore.">\n` +
1039
+ nudge(plan.nudgeProjects, "This workspace's HomeGraph indexes live in sub-projects. To use HomeGraph, call homegraph_explore with the projectPath of the relevant one:") +
1040
+ `</homegraph_context>\n`);
1041
+ }
1042
+ }
1043
+ catch {
1044
+ // Degradable by contract: never surface an error to the prompt pipeline.
1045
+ }
1046
+ });
1047
+ /**
1048
+ * homegraph node <name>
1049
+ *
1050
+ * The CLI face of the MCP homegraph_node tool: one symbol's source +
1051
+ * caller/callee trail, or a whole file with line numbers + dependents
1052
+ * (Read-parity). Same subagent/non-MCP rationale as `explore`.
1053
+ */
1054
+ program
1055
+ .command('node <name>')
1056
+ .description('One symbol\'s source + caller/callee trail, or read a file with line numbers + dependents (same output as the homegraph_node MCP tool)')
1057
+ .option('-p, --path <path>', 'Project path')
1058
+ .option('-f, --file <file>', 'Treat as file mode (or disambiguate a symbol to this file)')
1059
+ .option('--offset <number>', 'File mode: 1-based start line')
1060
+ .option('--limit <number>', 'File mode: maximum lines')
1061
+ .option('--symbols-only', 'File mode: just the symbol map + dependents')
1062
+ .action(async (name, options) => {
1063
+ const projectPath = resolveProjectPath(options.path);
1064
+ try {
1065
+ if (!(0, directory_1.isInitialized)(projectPath)) {
1066
+ error(`HomeGraph isn't available here — no .homegraph/ index exists in ${projectPath}. If you are an AI agent: continue with your usual tools; indexing is the user's decision, do not run it yourself. (The project owner can enable HomeGraph with 'homegraph init'.)`);
1067
+ process.exit(1);
1068
+ }
1069
+ const { default: HomeGraph } = await loadHomeGraph();
1070
+ const cg = await HomeGraph.open(projectPath);
1071
+ const { ToolHandler } = await Promise.resolve().then(() => __importStar(require('../mcp/tools')));
1072
+ const handler = new ToolHandler(cg);
1073
+ // A name with a path separator is a file read; otherwise a symbol
1074
+ // (use --file for basename-only file reads or to pin an overload).
1075
+ // Both separators: Windows users type src\auth\session.ts. Symbols
1076
+ // never contain either ('/' isn't an identifier char anywhere we
1077
+ // index; C++ scope is '::', JS members '.').
1078
+ const args = {};
1079
+ if (options.file) {
1080
+ args.file = options.file;
1081
+ if (name && name !== options.file)
1082
+ args.symbol = name;
1083
+ }
1084
+ else if (name.includes('/') || name.includes('\\')) {
1085
+ args.file = name.replace(/\\/g, '/');
1086
+ }
1087
+ else {
1088
+ args.symbol = name;
1089
+ args.includeCode = true;
1090
+ }
1091
+ if (options.offset)
1092
+ args.offset = parseInt(options.offset, 10);
1093
+ if (options.limit)
1094
+ args.limit = parseInt(options.limit, 10);
1095
+ if (options.symbolsOnly)
1096
+ args.symbolsOnly = true;
1097
+ const result = await handler.execute('homegraph_node', args);
1098
+ console.log(result.content[0]?.text ?? '');
1099
+ cg.destroy();
1100
+ if (result.isError)
1101
+ process.exit(1);
1102
+ }
1103
+ catch (err) {
1104
+ error(`Node lookup failed: ${err instanceof Error ? err.message : String(err)}`);
1105
+ process.exit(1);
1106
+ }
1107
+ });
1108
+ /**
1109
+ * homegraph files [path]
836
1110
  */
837
1111
  program
838
1112
  .command('files')
@@ -848,11 +1122,11 @@ function main() {
848
1122
  const projectPath = resolveProjectPath(options.path);
849
1123
  try {
850
1124
  if (!(0, directory_1.isInitialized)(projectPath)) {
851
- error(`CodeGraph not initialized in ${projectPath}`);
1125
+ error(`HomeGraph not initialized in ${projectPath}`);
852
1126
  process.exit(1);
853
1127
  }
854
- const { default: CodeGraph } = await loadCodeGraph();
855
- const cg = await CodeGraph.open(projectPath);
1128
+ const { default: HomeGraph } = await loadHomeGraph();
1129
+ const cg = await HomeGraph.open(projectPath);
856
1130
  let files = cg.getFiles();
857
1131
  if (files.length === 0) {
858
1132
  info('No files indexed. Run "homegraph index" first.');
@@ -938,6 +1212,24 @@ function main() {
938
1212
  process.exit(1);
939
1213
  }
940
1214
  });
1215
+ /**
1216
+ * Normalize a user-supplied file path to the project-relative, forward-slash
1217
+ * form HomeGraph stores in the index. Accepts an absolute path, a `./`-prefixed
1218
+ * path, or Windows back-slashes; an empty string when the input is blank. Used
1219
+ * by `homegraph affected` so `./src/x.ts`, `/abs/repo/src/x.ts`, and
1220
+ * `src/x.ts` all match the same indexed file. (#825)
1221
+ */
1222
+ function normalizeIndexPath(filePath, projectPath) {
1223
+ let f = filePath.trim();
1224
+ if (!f)
1225
+ return '';
1226
+ if (path.isAbsolute(f))
1227
+ f = path.relative(projectPath, f);
1228
+ // Collapse `.`/`..` segments, then force forward slashes and drop a leading
1229
+ // `./` (path.normalize already strips it on POSIX; explicit for Windows).
1230
+ f = path.normalize(f).replace(/\\/g, '/').replace(/^\.\//, '');
1231
+ return f;
1232
+ }
941
1233
  /**
942
1234
  * Convert glob pattern to regex
943
1235
  */
@@ -1001,11 +1293,66 @@ function main() {
1001
1293
  renderNode(root, '', true, 0);
1002
1294
  }
1003
1295
  /**
1004
- * codegraph serve
1296
+ * homegraph daemon — interactive manager for the background daemons. Arrow keys
1297
+ * to pick one (the current project's daemon floats to the top, auto-selected),
1298
+ * enter to stop it. Falls back to a plain list when output isn't a TTY.
1299
+ */
1300
+ program
1301
+ .command('daemon')
1302
+ .aliases(['daemons'])
1303
+ .description('Manage running HomeGraph background daemons — pick one and press enter to stop it')
1304
+ .action(async () => {
1305
+ const { listDaemons, stopDaemonAt, stopAllDaemons } = await Promise.resolve().then(() => __importStar(require('../mcp/daemon-registry')));
1306
+ const { runDaemonPicker } = await Promise.resolve().then(() => __importStar(require('../mcp/daemon-manager')));
1307
+ const daemons = listDaemons();
1308
+ if (daemons.length === 0) {
1309
+ info('No HomeGraph daemons running.');
1310
+ return;
1311
+ }
1312
+ // No TTY (piped / CI / non-interactive) — can't do arrow-key selection, so
1313
+ // just print what's running instead of crashing on a prompt with no input.
1314
+ if (!process.stdout.isTTY || !process.stdin.isTTY) {
1315
+ for (const d of daemons) {
1316
+ console.log(`pid ${d.pid} v${d.version} up ${formatDuration(Date.now() - d.startedAt)} ${d.root}`);
1317
+ }
1318
+ return;
1319
+ }
1320
+ // The current project's daemon floats to the top and is pre-selected.
1321
+ let cwdRoot = null;
1322
+ const found = (0, directory_1.findNearestHomeGraphRoot)(process.cwd());
1323
+ if (found) {
1324
+ try {
1325
+ cwdRoot = fs.realpathSync(found);
1326
+ }
1327
+ catch {
1328
+ cwdRoot = found;
1329
+ }
1330
+ }
1331
+ const clack = await importESM('@clack/prompts');
1332
+ clack.intro('HomeGraph daemons');
1333
+ await runDaemonPicker({
1334
+ list: listDaemons,
1335
+ stop: stopDaemonAt,
1336
+ stopAll: stopAllDaemons,
1337
+ cwdRoot,
1338
+ now: () => Date.now(),
1339
+ select: (opts) => clack.select(opts),
1340
+ isCancel: (v) => clack.isCancel(v),
1341
+ note: (m) => clack.log.success(m),
1342
+ done: (m) => clack.outro(m),
1343
+ });
1344
+ });
1345
+ /**
1346
+ * homegraph serve
1005
1347
  */
1006
1348
  program
1007
- .command('serve')
1008
- .description('Start CodeGraph as an MCP server for AI assistants')
1349
+ // Hidden from `--help`: this is the stdio entry point an AI agent launches
1350
+ // for itself (the installer wires `args: ['serve','--mcp']` into every
1351
+ // agent's MCP config), not a command a human runs. It still works when
1352
+ // invoked — hiding only removes it from the listing. See the interactive-TTY
1353
+ // guard below, which explains this to anyone who runs it by hand.
1354
+ .command('serve', { hidden: true })
1355
+ .description('Start HomeGraph as an MCP server for AI assistants')
1009
1356
  .option('-p, --path <path>', 'Project path (optional for MCP mode, uses rootUri from client)')
1010
1357
  .option('--mcp', 'Run as MCP server (stdio transport)')
1011
1358
  .option('--no-watch', 'Disable the file watcher (no auto-sync; useful on slow filesystems like WSL2 /mnt drives)')
@@ -1018,6 +1365,22 @@ function main() {
1018
1365
  }
1019
1366
  try {
1020
1367
  if (options.mcp) {
1368
+ // `serve --mcp` is the stdio MCP server an AI agent launches for itself,
1369
+ // not a command to run by hand. A human in a terminal would otherwise
1370
+ // see it hang waiting for JSON-RPC on stdin, which reads as broken. If
1371
+ // stdin is an interactive TTY, explain instead of hanging. The agent's
1372
+ // pipe and the detached daemon both have a non-TTY stdin, so this only
1373
+ // ever fires for a person who typed it.
1374
+ if (process.stdin.isTTY && !process.env.HOMEGRAPH_DAEMON_INTERNAL) {
1375
+ console.error(chalk.bold('\nHomeGraph MCP server\n'));
1376
+ console.error("This is the MCP server your AI agent (Claude Code, Cursor, Codex, opencode, …)");
1377
+ console.error("starts automatically — you don't run it yourself.");
1378
+ console.error(`\nIt's already wired up by ${chalk.cyan('homegraph install')}. To check on things:`);
1379
+ console.error(` ${chalk.cyan('homegraph status')} ${chalk.dim('— is this project indexed and healthy?')}`);
1380
+ console.error(` ${chalk.cyan('homegraph daemon')} ${chalk.dim('— list or stop background MCP servers')}`);
1381
+ console.error(chalk.dim('\n(Running it directly only does something when an MCP client drives it over stdin.)'));
1382
+ return;
1383
+ }
1021
1384
  // Start MCP server - it handles initialization lazily based on rootUri from client
1022
1385
  const { MCPServer } = await Promise.resolve().then(() => __importStar(require('../mcp/index')));
1023
1386
  const server = new MCPServer(projectPath);
@@ -1027,18 +1390,18 @@ function main() {
1027
1390
  else {
1028
1391
  // Default: show info about MCP mode.
1029
1392
  // Use stderr so stdout stays clean for any piped/stdio usage.
1030
- console.error(chalk.bold('\nCodeGraph MCP Server\n'));
1393
+ console.error(chalk.bold('\nHomeGraph MCP Server\n'));
1031
1394
  console.error(chalk.blue((0, glyphs_1.getGlyphs)().info) + ' Use --mcp flag to start the MCP server');
1032
1395
  console.error('\nTo use with Claude Code, add to your MCP configuration:');
1033
- console.error(chalk.dim(`
1034
- {
1035
- "mcpServers": {
1036
- "homegraph": {
1037
- "command": "homegraph",
1038
- "args": ["serve", "--mcp"]
1039
- }
1040
- }
1041
- }
1396
+ console.error(chalk.dim(`
1397
+ {
1398
+ "mcpServers": {
1399
+ "homegraph": {
1400
+ "command": "homegraph",
1401
+ "args": ["serve", "--mcp"]
1402
+ }
1403
+ }
1404
+ }
1042
1405
  `));
1043
1406
  console.error('Available tools:');
1044
1407
  console.error(chalk.cyan(' homegraph_explore') + ' - Primary: source of the relevant symbols for any question');
@@ -1057,7 +1420,7 @@ function main() {
1057
1420
  }
1058
1421
  });
1059
1422
  /**
1060
- * codegraph unlock [path]
1423
+ * homegraph unlock [path]
1061
1424
  */
1062
1425
  program
1063
1426
  .command('unlock [path]')
@@ -1066,10 +1429,10 @@ function main() {
1066
1429
  const projectPath = resolveProjectPath(pathArg);
1067
1430
  try {
1068
1431
  if (!(0, directory_1.isInitialized)(projectPath)) {
1069
- error(`CodeGraph not initialized in ${projectPath}`);
1432
+ error(`HomeGraph not initialized in ${projectPath}`);
1070
1433
  return;
1071
1434
  }
1072
- const lockPath = path.join((0, directory_1.getCodeGraphDir)(projectPath), 'homegraph.lock');
1435
+ const lockPath = path.join((0, directory_1.getHomeGraphDir)(projectPath), 'homegraph.lock');
1073
1436
  if (!fs.existsSync(lockPath)) {
1074
1437
  info(`No lock file found ${(0, glyphs_1.getGlyphs)().dash} nothing to do`);
1075
1438
  return;
@@ -1083,7 +1446,7 @@ function main() {
1083
1446
  }
1084
1447
  });
1085
1448
  /**
1086
- * codegraph callers <symbol>
1449
+ * homegraph callers <symbol>
1087
1450
  *
1088
1451
  * CLI parity with the MCP graph tools (homegraph_callers/callees/impact) so the
1089
1452
  * traversal queries work in scripts, CI, and git hooks without a running MCP
@@ -1099,11 +1462,11 @@ function main() {
1099
1462
  const projectPath = resolveProjectPath(options.path);
1100
1463
  try {
1101
1464
  if (!(0, directory_1.isInitialized)(projectPath)) {
1102
- error(`CodeGraph not initialized in ${projectPath}`);
1465
+ error(`HomeGraph not initialized in ${projectPath}`);
1103
1466
  process.exit(1);
1104
1467
  }
1105
- const { default: CodeGraph } = await loadCodeGraph();
1106
- const cg = await CodeGraph.open(projectPath);
1468
+ const { default: HomeGraph } = await loadHomeGraph();
1469
+ const cg = await HomeGraph.open(projectPath);
1107
1470
  const limit = parseInt(options.limit || '20', 10);
1108
1471
  const matches = cg.searchNodes(symbol, { limit: 50 });
1109
1472
  if (matches.length === 0) {
@@ -1158,7 +1521,7 @@ function main() {
1158
1521
  }
1159
1522
  });
1160
1523
  /**
1161
- * codegraph callees <symbol>
1524
+ * homegraph callees <symbol>
1162
1525
  */
1163
1526
  program
1164
1527
  .command('callees <symbol>')
@@ -1170,11 +1533,11 @@ function main() {
1170
1533
  const projectPath = resolveProjectPath(options.path);
1171
1534
  try {
1172
1535
  if (!(0, directory_1.isInitialized)(projectPath)) {
1173
- error(`CodeGraph not initialized in ${projectPath}`);
1536
+ error(`HomeGraph not initialized in ${projectPath}`);
1174
1537
  process.exit(1);
1175
1538
  }
1176
- const { default: CodeGraph } = await loadCodeGraph();
1177
- const cg = await CodeGraph.open(projectPath);
1539
+ const { default: HomeGraph } = await loadHomeGraph();
1540
+ const cg = await HomeGraph.open(projectPath);
1178
1541
  const limit = parseInt(options.limit || '20', 10);
1179
1542
  const matches = cg.searchNodes(symbol, { limit: 50 });
1180
1543
  if (matches.length === 0) {
@@ -1228,7 +1591,7 @@ function main() {
1228
1591
  }
1229
1592
  });
1230
1593
  /**
1231
- * codegraph impact <symbol>
1594
+ * homegraph impact <symbol>
1232
1595
  */
1233
1596
  program
1234
1597
  .command('impact <symbol>')
@@ -1240,11 +1603,11 @@ function main() {
1240
1603
  const projectPath = resolveProjectPath(options.path);
1241
1604
  try {
1242
1605
  if (!(0, directory_1.isInitialized)(projectPath)) {
1243
- error(`CodeGraph not initialized in ${projectPath}`);
1606
+ error(`HomeGraph not initialized in ${projectPath}`);
1244
1607
  process.exit(1);
1245
1608
  }
1246
- const { default: CodeGraph } = await loadCodeGraph();
1247
- const cg = await CodeGraph.open(projectPath);
1609
+ const { default: HomeGraph } = await loadHomeGraph();
1610
+ const cg = await HomeGraph.open(projectPath);
1248
1611
  const depth = Math.min(Math.max(parseInt(options.depth || '2', 10), 1), 10);
1249
1612
  const matches = cg.searchNodes(symbol, { limit: 50 });
1250
1613
  if (matches.length === 0) {
@@ -1318,13 +1681,13 @@ function main() {
1318
1681
  }
1319
1682
  });
1320
1683
  /**
1321
- * codegraph affected [files...]
1684
+ * homegraph affected [files...]
1322
1685
  *
1323
1686
  * Find test files affected by the given source files.
1324
1687
  * Traces dependency edges transitively to find test files that depend on changed code.
1325
1688
  *
1326
1689
  * Usage:
1327
- * git diff --name-only | codegraph affected --stdin
1690
+ * git diff --name-only | homegraph affected --stdin
1328
1691
  * homegraph affected src/lib/components/Editor.svelte src/routes/+page.svelte
1329
1692
  */
1330
1693
  program
@@ -1340,7 +1703,7 @@ function main() {
1340
1703
  const projectPath = resolveProjectPath(options.path);
1341
1704
  try {
1342
1705
  if (!(0, directory_1.isInitialized)(projectPath)) {
1343
- error(`CodeGraph not initialized in ${projectPath}`);
1706
+ error(`HomeGraph not initialized in ${projectPath}`);
1344
1707
  process.exit(1);
1345
1708
  }
1346
1709
  // Collect changed files from args or stdin
@@ -1350,13 +1713,20 @@ function main() {
1350
1713
  const stdinFiles = stdinData.split('\n').map(f => f.trim()).filter(Boolean);
1351
1714
  changedFiles.push(...stdinFiles);
1352
1715
  }
1716
+ // Normalize inputs to the project-relative, forward-slash form the index
1717
+ // stores. Without this, `affected ./src/x.ts`, an absolute path (what a
1718
+ // wrapping script often passes), or a Windows back-slash path silently
1719
+ // matches nothing and reports 0 affected tests. (#825)
1720
+ changedFiles = changedFiles
1721
+ .map((f) => normalizeIndexPath(f, projectPath))
1722
+ .filter(Boolean);
1353
1723
  if (changedFiles.length === 0) {
1354
1724
  if (!options.quiet)
1355
1725
  info('No files provided. Use file arguments or --stdin.');
1356
1726
  process.exit(0);
1357
1727
  }
1358
- const { default: CodeGraph } = await loadCodeGraph();
1359
- const cg = await CodeGraph.open(projectPath);
1728
+ const { default: HomeGraph } = await loadHomeGraph();
1729
+ const cg = await HomeGraph.open(projectPath);
1360
1730
  const maxDepth = parseInt(options.depth || '5', 10);
1361
1731
  // Common test file patterns
1362
1732
  const defaultTestPatterns = [
@@ -1448,11 +1818,11 @@ function main() {
1448
1818
  }
1449
1819
  });
1450
1820
  /**
1451
- * codegraph install
1821
+ * homegraph install
1452
1822
  */
1453
1823
  program
1454
1824
  .command('install')
1455
- .description('Install codegraph MCP server into one or more agents (Claude Code, Cursor, Codex CLI, opencode, Hermes Agent)')
1825
+ .description('Install homegraph MCP server into one or more agents (Claude Code, Cursor, Codex CLI, opencode, DevEco Code, CodeBuddy, Hermes Agent)')
1456
1826
  .option('-t, --target <ids>', 'Target agent(s): comma-separated ids, or "auto"|"all"|"none". Default: prompt')
1457
1827
  .option('-l, --location <where>', 'Install location: "global" or "local". Default: prompt')
1458
1828
  .option('-y, --yes', 'Non-interactive: defaults to --location=global --target=auto, auto-allow on')
@@ -1502,16 +1872,16 @@ function main() {
1502
1872
  }
1503
1873
  });
1504
1874
  /**
1505
- * codegraph uninstall
1875
+ * homegraph uninstall
1506
1876
  *
1507
- * Inverse of `install`. Removes the codegraph MCP server entry,
1877
+ * Inverse of `install`. Removes the homegraph MCP server entry,
1508
1878
  * instructions block, and permissions from every agent (or a
1509
1879
  * `--target` subset). Prompts global-vs-local when not given. Does NOT
1510
1880
  * delete the `.homegraph/` index — that's `homegraph uninit`.
1511
1881
  */
1512
1882
  program
1513
1883
  .command('uninstall')
1514
- .description('Remove codegraph from your agents (Claude Code, Cursor, Codex CLI, opencode, Hermes Agent)')
1884
+ .description('Remove homegraph from your agents (Claude Code, Cursor, Codex CLI, opencode, DevEco Code, CodeBuddy, Hermes Agent)')
1515
1885
  .option('-t, --target <ids>', 'Target agent(s): comma-separated ids, or "all". Default: all')
1516
1886
  .option('-l, --location <where>', 'Uninstall location: "global" or "local". Default: prompt')
1517
1887
  .option('-y, --yes', 'Non-interactive: defaults to --location=global --target=all')
@@ -1534,15 +1904,54 @@ function main() {
1534
1904
  }
1535
1905
  });
1536
1906
  /**
1537
- * codegraph upgrade [version]
1907
+ * homegraph telemetry [on|off|status]
1908
+ */
1909
+ program
1910
+ .command('telemetry [action]')
1911
+ .description('Show or change anonymous usage telemetry (status, on, off)')
1912
+ .action((action) => {
1913
+ const t = (0, telemetry_1.getTelemetry)();
1914
+ if (action === 'on' || action === 'off') {
1915
+ t.setEnabled(action === 'on', 'cli');
1916
+ if (action === 'on') {
1917
+ success('Telemetry enabled — anonymous usage stats only (no code, paths, or names).');
1918
+ }
1919
+ else {
1920
+ success('Telemetry disabled. Buffered, unsent data was deleted.');
1921
+ }
1922
+ const effective = t.getStatus();
1923
+ if (effective.decidedBy === 'DO_NOT_TRACK' || effective.decidedBy === 'HOMEGRAPH_TELEMETRY') {
1924
+ warn(`The ${effective.decidedBy} environment variable overrides this choice — ` +
1925
+ `effective state right now: ${effective.enabled ? 'enabled' : 'disabled'}.`);
1926
+ }
1927
+ return;
1928
+ }
1929
+ if (action !== undefined && action !== 'status') {
1930
+ error(`Unknown action: ${action} (expected status, on, or off)`);
1931
+ process.exit(1);
1932
+ }
1933
+ const s = t.getStatus();
1934
+ const decidedBy = {
1935
+ DO_NOT_TRACK: 'DO_NOT_TRACK environment variable',
1936
+ HOMEGRAPH_TELEMETRY: 'HOMEGRAPH_TELEMETRY environment variable',
1937
+ config: 'your saved choice',
1938
+ default: 'default',
1939
+ };
1940
+ console.log(`\nTelemetry: ${s.enabled ? chalk.green('enabled') : chalk.yellow('disabled')} ${chalk.dim(`(${decidedBy[s.decidedBy]})`)}`);
1941
+ console.log(`Machine ID: ${s.machineId ?? chalk.dim('(random UUID, created on first use)')}`);
1942
+ console.log(`Config: ${s.configPath}`);
1943
+ console.log(chalk.dim(`\nExactly what is collected (and never collected): ${telemetry_1.TELEMETRY_DOCS}\n`));
1944
+ });
1945
+ /**
1946
+ * homegraph upgrade [version]
1538
1947
  *
1539
- * Self-update, however CodeGraph was installed (bundle via install.sh/.ps1,
1948
+ * Self-update, however HomeGraph was installed (bundle via install.sh/.ps1,
1540
1949
  * npm-global, npx, or a source checkout). See ../upgrade for the detection and
1541
1950
  * per-method upgrade logic.
1542
1951
  */
1543
1952
  program
1544
1953
  .command('upgrade [version]')
1545
- .description('Update CodeGraph to the latest release (or a specific version)')
1954
+ .description('Update HomeGraph to the latest release (or a specific version)')
1546
1955
  .option('--check', 'Check whether an update is available without installing')
1547
1956
  .option('-f, --force', 'Reinstall even if already on the target version')
1548
1957
  .action(async (versionArg, options) => {
@@ -1566,6 +1975,20 @@ function main() {
1566
1975
  });
1567
1976
  process.exit(code);
1568
1977
  });
1978
+ /**
1979
+ * homegraph version
1980
+ *
1981
+ * The bare-noun form of `--version`. commander already provides `--version`
1982
+ * and `-V`, and the `-v` / `-version` spellings are intercepted before parse
1983
+ * (see top of main). This subcommand makes `homegraph version` work and lists
1984
+ * the version affordance in `homegraph --help`.
1985
+ */
1986
+ program
1987
+ .command('version')
1988
+ .description('Print the installed HomeGraph version (also: -v, --version)')
1989
+ .action(() => {
1990
+ console.log(packageJson.version);
1991
+ });
1569
1992
  // Parse and run
1570
1993
  program.parse();
1571
1994
  } // end main()