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.
- package/LICENSE +21 -21
- package/README.md +243 -193
- package/dist/bin/fatal-handler.d.ts +20 -0
- package/dist/bin/fatal-handler.d.ts.map +1 -0
- package/dist/bin/fatal-handler.js +118 -0
- package/dist/bin/fatal-handler.js.map +1 -0
- package/dist/bin/homegraph.d.ts +6 -6
- package/dist/bin/homegraph.js +532 -109
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/bin/node-version-check.d.ts +4 -4
- package/dist/bin/node-version-check.js +12 -12
- package/dist/bin/uninstall.d.ts +1 -1
- package/dist/bin/uninstall.js +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +8 -1
- package/dist/context/index.js.map +1 -1
- package/dist/db/index.d.ts +22 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +48 -2
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +26 -17
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts +21 -1
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +180 -137
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.sql +152 -151
- package/dist/db/sqlite-adapter.d.ts +1 -1
- package/dist/db/sqlite-adapter.js +3 -3
- package/dist/directory.d.ts +87 -6
- package/dist/directory.d.ts.map +1 -1
- package/dist/directory.js +319 -57
- package/dist/directory.js.map +1 -1
- package/dist/errors.d.ts +15 -15
- package/dist/errors.js +20 -20
- package/dist/extraction/astro-extractor.d.ts +79 -0
- package/dist/extraction/astro-extractor.d.ts.map +1 -0
- package/dist/extraction/astro-extractor.js +320 -0
- package/dist/extraction/astro-extractor.js.map +1 -0
- package/dist/extraction/context.d.ts +1 -1
- package/dist/extraction/context.js +1 -1
- package/dist/extraction/extraction-version.d.ts +2 -2
- package/dist/extraction/extraction-version.d.ts.map +1 -1
- package/dist/extraction/extraction-version.js +2 -2
- package/dist/extraction/extraction-version.js.map +1 -1
- package/dist/extraction/function-ref.d.ts +118 -0
- package/dist/extraction/function-ref.d.ts.map +1 -0
- package/dist/extraction/function-ref.js +727 -0
- package/dist/extraction/function-ref.js.map +1 -0
- package/dist/extraction/generated-detection.d.ts.map +1 -1
- package/dist/extraction/generated-detection.js +3 -0
- package/dist/extraction/generated-detection.js.map +1 -1
- package/dist/extraction/grammars.d.ts +15 -5
- package/dist/extraction/grammars.d.ts.map +1 -1
- package/dist/extraction/grammars.js +44 -10
- package/dist/extraction/grammars.js.map +1 -1
- package/dist/extraction/index.d.ts +37 -0
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +562 -70
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/arkts-viewtree.d.ts +22 -0
- package/dist/extraction/languages/arkts-viewtree.d.ts.map +1 -0
- package/dist/extraction/languages/arkts-viewtree.js +133 -0
- package/dist/extraction/languages/arkts-viewtree.js.map +1 -0
- package/dist/extraction/languages/arkts.d.ts.map +1 -1
- package/dist/extraction/languages/arkts.js +211 -20
- package/dist/extraction/languages/arkts.js.map +1 -1
- package/dist/extraction/languages/c-cpp.d.ts +8 -0
- package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/dist/extraction/languages/c-cpp.js +104 -2
- package/dist/extraction/languages/c-cpp.js.map +1 -1
- package/dist/extraction/languages/csharp.d.ts.map +1 -1
- package/dist/extraction/languages/csharp.js +58 -3
- package/dist/extraction/languages/csharp.js.map +1 -1
- package/dist/extraction/languages/dart.d.ts.map +1 -1
- package/dist/extraction/languages/dart.js +183 -1
- package/dist/extraction/languages/dart.js.map +1 -1
- package/dist/extraction/languages/go.d.ts.map +1 -1
- package/dist/extraction/languages/go.js +37 -0
- package/dist/extraction/languages/go.js.map +1 -1
- package/dist/extraction/languages/index.d.ts.map +1 -1
- package/dist/extraction/languages/index.js +2 -0
- package/dist/extraction/languages/index.js.map +1 -1
- package/dist/extraction/languages/java.d.ts.map +1 -1
- package/dist/extraction/languages/java.js +241 -0
- package/dist/extraction/languages/java.js.map +1 -1
- package/dist/extraction/languages/javascript.d.ts.map +1 -1
- package/dist/extraction/languages/javascript.js +16 -0
- package/dist/extraction/languages/javascript.js.map +1 -1
- package/dist/extraction/languages/kotlin.d.ts.map +1 -1
- package/dist/extraction/languages/kotlin.js +94 -0
- package/dist/extraction/languages/kotlin.js.map +1 -1
- package/dist/extraction/languages/objc.d.ts.map +1 -1
- package/dist/extraction/languages/objc.js +42 -0
- package/dist/extraction/languages/objc.js.map +1 -1
- package/dist/extraction/languages/pascal.d.ts.map +1 -1
- package/dist/extraction/languages/pascal.js +11 -0
- package/dist/extraction/languages/pascal.js.map +1 -1
- package/dist/extraction/languages/php.d.ts.map +1 -1
- package/dist/extraction/languages/php.js +77 -1
- package/dist/extraction/languages/php.js.map +1 -1
- package/dist/extraction/languages/r.d.ts +3 -0
- package/dist/extraction/languages/r.d.ts.map +1 -0
- package/dist/extraction/languages/r.js +314 -0
- package/dist/extraction/languages/r.js.map +1 -0
- package/dist/extraction/languages/rust.d.ts.map +1 -1
- package/dist/extraction/languages/rust.js +29 -0
- package/dist/extraction/languages/rust.js.map +1 -1
- package/dist/extraction/languages/scala.d.ts.map +1 -1
- package/dist/extraction/languages/scala.js +44 -9
- package/dist/extraction/languages/scala.js.map +1 -1
- package/dist/extraction/languages/swift.d.ts.map +1 -1
- package/dist/extraction/languages/swift.js +61 -0
- package/dist/extraction/languages/swift.js.map +1 -1
- package/dist/extraction/languages/typescript.d.ts +13 -0
- package/dist/extraction/languages/typescript.d.ts.map +1 -1
- package/dist/extraction/languages/typescript.js +38 -0
- package/dist/extraction/languages/typescript.js.map +1 -1
- package/dist/extraction/liquid-extractor.d.ts.map +1 -1
- package/dist/extraction/liquid-extractor.js +4 -1
- package/dist/extraction/liquid-extractor.js.map +1 -1
- package/dist/extraction/parse-worker.js +4 -1
- package/dist/extraction/parse-worker.js.map +1 -1
- package/dist/extraction/svelte-extractor.d.ts.map +1 -1
- package/dist/extraction/svelte-extractor.js +6 -3
- package/dist/extraction/svelte-extractor.js.map +1 -1
- package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
- package/dist/extraction/tree-sitter-helpers.js +59 -10
- package/dist/extraction/tree-sitter-helpers.js.map +1 -1
- package/dist/extraction/tree-sitter-types.d.ts +29 -0
- package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.d.ts +192 -0
- package/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.js +1553 -45
- package/dist/extraction/tree-sitter.js.map +1 -1
- package/dist/extraction/vue-extractor.d.ts.map +1 -1
- package/dist/extraction/vue-extractor.js +6 -3
- package/dist/extraction/vue-extractor.js.map +1 -1
- package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
- package/dist/graph/traversal.d.ts.map +1 -1
- package/dist/graph/traversal.js +11 -2
- package/dist/graph/traversal.js.map +1 -1
- package/dist/index.d.ts +64 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +137 -41
- package/dist/index.js.map +1 -1
- package/dist/installer/config-writer.d.ts +1 -1
- package/dist/installer/config-writer.js +1 -1
- package/dist/installer/index.d.ts +4 -4
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +100 -73
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/instructions-template.d.ts +34 -11
- package/dist/installer/instructions-template.d.ts.map +1 -1
- package/dist/installer/instructions-template.js +44 -12
- package/dist/installer/instructions-template.js.map +1 -1
- package/dist/installer/targets/antigravity.d.ts +6 -6
- package/dist/installer/targets/antigravity.js +14 -14
- package/dist/installer/targets/claude.d.ts +19 -13
- package/dist/installer/targets/claude.d.ts.map +1 -1
- package/dist/installer/targets/claude.js +97 -29
- package/dist/installer/targets/claude.js.map +1 -1
- package/dist/installer/targets/codebuddy.d.ts +17 -0
- package/dist/installer/targets/codebuddy.d.ts.map +1 -0
- package/dist/installer/targets/codebuddy.js +150 -0
- package/dist/installer/targets/codebuddy.js.map +1 -0
- package/dist/installer/targets/codex.js +5 -7
- package/dist/installer/targets/codex.js.map +1 -1
- package/dist/installer/targets/cursor.d.ts +1 -1
- package/dist/installer/targets/cursor.js +7 -7
- package/dist/installer/targets/deveco.d.ts +23 -0
- package/dist/installer/targets/deveco.d.ts.map +1 -0
- package/dist/installer/targets/deveco.js +217 -0
- package/dist/installer/targets/deveco.js.map +1 -0
- package/dist/installer/targets/gemini.js +5 -7
- package/dist/installer/targets/gemini.js.map +1 -1
- package/dist/installer/targets/hermes.js +15 -15
- package/dist/installer/targets/kiro.d.ts +1 -1
- package/dist/installer/targets/kiro.js +4 -4
- package/dist/installer/targets/opencode.d.ts +9 -1
- package/dist/installer/targets/opencode.d.ts.map +1 -1
- package/dist/installer/targets/opencode.js +92 -41
- package/dist/installer/targets/opencode.js.map +1 -1
- package/dist/installer/targets/registry.d.ts.map +1 -1
- package/dist/installer/targets/registry.js +4 -0
- package/dist/installer/targets/registry.js.map +1 -1
- package/dist/installer/targets/shared.d.ts +28 -4
- package/dist/installer/targets/shared.d.ts.map +1 -1
- package/dist/installer/targets/shared.js +32 -15
- package/dist/installer/targets/shared.js.map +1 -1
- package/dist/installer/targets/types.d.ts +9 -2
- package/dist/installer/targets/types.d.ts.map +1 -1
- package/dist/mcp/daemon-manager.d.ts +42 -0
- package/dist/mcp/daemon-manager.d.ts.map +1 -0
- package/dist/mcp/daemon-manager.js +129 -0
- package/dist/mcp/daemon-manager.js.map +1 -0
- package/dist/mcp/daemon-paths.d.ts +1 -1
- package/dist/mcp/daemon-paths.js +3 -3
- package/dist/mcp/daemon-registry.d.ts +47 -0
- package/dist/mcp/daemon-registry.d.ts.map +1 -0
- package/dist/mcp/daemon-registry.js +229 -0
- package/dist/mcp/daemon-registry.js.map +1 -0
- package/dist/mcp/daemon.d.ts.map +1 -1
- package/dist/mcp/daemon.js +27 -6
- package/dist/mcp/daemon.js.map +1 -1
- package/dist/mcp/dynamic-boundaries.d.ts +41 -0
- package/dist/mcp/dynamic-boundaries.d.ts.map +1 -0
- package/dist/mcp/dynamic-boundaries.js +359 -0
- package/dist/mcp/dynamic-boundaries.js.map +1 -0
- package/dist/mcp/engine.d.ts +4 -4
- package/dist/mcp/engine.d.ts.map +1 -1
- package/dist/mcp/engine.js +32 -24
- package/dist/mcp/engine.js.map +1 -1
- package/dist/mcp/index.d.ts +8 -7
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +39 -18
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/liveness-watchdog.d.ts +18 -0
- package/dist/mcp/liveness-watchdog.d.ts.map +1 -0
- package/dist/mcp/liveness-watchdog.js +207 -0
- package/dist/mcp/liveness-watchdog.js.map +1 -0
- package/dist/mcp/proxy.d.ts +6 -0
- package/dist/mcp/proxy.d.ts.map +1 -1
- package/dist/mcp/proxy.js +75 -18
- package/dist/mcp/proxy.js.map +1 -1
- package/dist/mcp/server-instructions.d.ts +22 -7
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +91 -59
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/session.d.ts +3 -1
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +43 -7
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/stdin-teardown.d.ts +27 -0
- package/dist/mcp/stdin-teardown.d.ts.map +1 -0
- package/dist/mcp/stdin-teardown.js +49 -0
- package/dist/mcp/stdin-teardown.js.map +1 -0
- package/dist/mcp/tools.d.ts +137 -16
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +1271 -219
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/transport.d.ts +1 -1
- package/dist/mcp/transport.d.ts.map +1 -1
- package/dist/mcp/transport.js +20 -4
- package/dist/mcp/transport.js.map +1 -1
- package/dist/mcp/version.d.ts +1 -1
- package/dist/mcp/version.js +2 -2
- package/dist/project-config.d.ts +36 -0
- package/dist/project-config.d.ts.map +1 -0
- package/dist/project-config.js +235 -0
- package/dist/project-config.js.map +1 -0
- package/dist/reasoning/config.d.ts +45 -0
- package/dist/reasoning/config.d.ts.map +1 -0
- package/dist/reasoning/config.js +171 -0
- package/dist/reasoning/config.js.map +1 -0
- package/dist/reasoning/credentials.d.ts +5 -0
- package/dist/reasoning/credentials.d.ts.map +1 -0
- package/dist/reasoning/credentials.js +83 -0
- package/dist/reasoning/credentials.js.map +1 -0
- package/dist/reasoning/login.d.ts +21 -0
- package/dist/reasoning/login.d.ts.map +1 -0
- package/dist/reasoning/login.js +85 -0
- package/dist/reasoning/login.js.map +1 -0
- package/dist/reasoning/reasoner.d.ts +43 -0
- package/dist/reasoning/reasoner.d.ts.map +1 -0
- package/dist/reasoning/reasoner.js +308 -0
- package/dist/reasoning/reasoner.js.map +1 -0
- package/dist/resolution/c-fnptr-synthesizer.d.ts +33 -0
- package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -0
- package/dist/resolution/c-fnptr-synthesizer.js +352 -0
- package/dist/resolution/c-fnptr-synthesizer.js.map +1 -0
- package/dist/resolution/callback-synthesizer.d.ts +6 -1
- package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/dist/resolution/callback-synthesizer.js +1197 -1
- package/dist/resolution/callback-synthesizer.js.map +1 -1
- package/dist/resolution/frameworks/arkts-entry.d.ts +12 -0
- package/dist/resolution/frameworks/arkts-entry.d.ts.map +1 -0
- package/dist/resolution/frameworks/arkts-entry.js +214 -0
- package/dist/resolution/frameworks/arkts-entry.js.map +1 -0
- package/dist/resolution/frameworks/arkts-napi.d.ts +3 -0
- package/dist/resolution/frameworks/arkts-napi.d.ts.map +1 -0
- package/dist/resolution/frameworks/arkts-napi.js +166 -0
- package/dist/resolution/frameworks/arkts-napi.js.map +1 -0
- package/dist/resolution/frameworks/astro.d.ts +9 -0
- package/dist/resolution/frameworks/astro.d.ts.map +1 -0
- package/dist/resolution/frameworks/astro.js +169 -0
- package/dist/resolution/frameworks/astro.js.map +1 -0
- package/dist/resolution/frameworks/goframe.d.ts +41 -0
- package/dist/resolution/frameworks/goframe.d.ts.map +1 -0
- package/dist/resolution/frameworks/goframe.js +112 -0
- package/dist/resolution/frameworks/goframe.js.map +1 -0
- package/dist/resolution/frameworks/index.d.ts +3 -0
- package/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/dist/resolution/frameworks/index.js +17 -1
- package/dist/resolution/frameworks/index.js.map +1 -1
- package/dist/resolution/frameworks/java.js +6 -1
- package/dist/resolution/frameworks/java.js.map +1 -1
- package/dist/resolution/frameworks/react.d.ts.map +1 -1
- package/dist/resolution/frameworks/react.js +32 -63
- package/dist/resolution/frameworks/react.js.map +1 -1
- package/dist/resolution/frameworks/svelte.js +6 -2
- package/dist/resolution/frameworks/svelte.js.map +1 -1
- package/dist/resolution/frameworks/vue.js +24 -27
- package/dist/resolution/frameworks/vue.js.map +1 -1
- package/dist/resolution/goframe-synthesizer.d.ts +28 -0
- package/dist/resolution/goframe-synthesizer.d.ts.map +1 -0
- package/dist/resolution/goframe-synthesizer.js +158 -0
- package/dist/resolution/goframe-synthesizer.js.map +1 -0
- package/dist/resolution/import-resolver.d.ts +10 -0
- package/dist/resolution/import-resolver.d.ts.map +1 -1
- package/dist/resolution/import-resolver.js +125 -2
- package/dist/resolution/import-resolver.js.map +1 -1
- package/dist/resolution/index.d.ts +37 -0
- package/dist/resolution/index.d.ts.map +1 -1
- package/dist/resolution/index.js +306 -3
- package/dist/resolution/index.js.map +1 -1
- package/dist/resolution/name-matcher.d.ts +41 -0
- package/dist/resolution/name-matcher.d.ts.map +1 -1
- package/dist/resolution/name-matcher.js +519 -14
- package/dist/resolution/name-matcher.js.map +1 -1
- package/dist/resolution/strip-comments.d.ts +1 -1
- package/dist/resolution/strip-comments.d.ts.map +1 -1
- package/dist/resolution/strip-comments.js +2 -0
- package/dist/resolution/strip-comments.js.map +1 -1
- package/dist/resolution/types.d.ts +20 -3
- package/dist/resolution/types.d.ts.map +1 -1
- package/dist/search/query-utils.d.ts +17 -1
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +79 -10
- package/dist/search/query-utils.js.map +1 -1
- package/dist/sync/git-hooks.d.ts +4 -4
- package/dist/sync/git-hooks.js +5 -5
- package/dist/sync/watcher.d.ts +69 -2
- package/dist/sync/watcher.d.ts.map +1 -1
- package/dist/sync/watcher.js +226 -21
- package/dist/sync/watcher.js.map +1 -1
- package/dist/sync/worktree.d.ts +3 -3
- package/dist/sync/worktree.js +5 -5
- package/dist/telemetry/index.d.ts +143 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +541 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/types.d.ts +18 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -1
- package/dist/types.js.map +1 -1
- package/dist/upgrade/index.d.ts.map +1 -1
- package/dist/upgrade/index.js +46 -10
- package/dist/upgrade/index.js.map +1 -1
- package/dist/utils.d.ts +46 -27
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +87 -53
- package/dist/utils.js.map +1 -1
- package/package.json +57 -57
- package/scripts/add-lang/bench.sh +60 -60
- package/scripts/add-lang/check-grammar.mjs +75 -75
- package/scripts/add-lang/dump-ast.mjs +103 -103
- package/scripts/add-lang/verify-extraction.mjs +70 -70
- package/scripts/agent-eval/ab-adoption.sh +91 -0
- package/scripts/agent-eval/ab-hook.sh +86 -0
- package/scripts/agent-eval/ab-impl.sh +78 -0
- package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -0
- package/scripts/agent-eval/ab-sufficiency.sh +78 -0
- package/scripts/agent-eval/arms-F.sh +21 -21
- package/scripts/agent-eval/arms-matrix.sh +37 -37
- package/scripts/agent-eval/audit.sh +68 -68
- package/scripts/agent-eval/bench-readme.sh +28 -28
- package/scripts/agent-eval/bench-why-repo.sh +22 -22
- package/scripts/agent-eval/block-read-hook.sh +19 -19
- package/scripts/agent-eval/hook-settings.json +15 -15
- package/scripts/agent-eval/itrun.sh +120 -120
- package/scripts/agent-eval/offload-eval-3arm.sh +72 -0
- package/scripts/agent-eval/offload-eval-cost.mjs +133 -0
- package/scripts/agent-eval/offload-eval-effort.mjs +108 -0
- package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -0
- package/scripts/agent-eval/offload-eval-frontload.sh +47 -0
- package/scripts/agent-eval/offload-eval-ground-truth.json +18 -0
- package/scripts/agent-eval/offload-eval-hook.mjs +84 -0
- package/scripts/agent-eval/offload-eval-judge.mjs +103 -0
- package/scripts/agent-eval/offload-eval-matrix.sh +20 -0
- package/scripts/agent-eval/offload-eval-metrics.mjs +94 -0
- package/scripts/agent-eval/offload-eval-refs1.sh +50 -0
- package/scripts/agent-eval/offload-eval-setup.sh +24 -0
- package/scripts/agent-eval/offload-eval-styles.sh +72 -0
- package/scripts/agent-eval/offload-eval-summarize.mjs +68 -0
- package/scripts/agent-eval/offload-eval.md +76 -0
- package/scripts/agent-eval/parse-arms.mjs +116 -116
- package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
- package/scripts/agent-eval/parse-run.mjs +45 -45
- package/scripts/agent-eval/parse-session.mjs +93 -93
- package/scripts/agent-eval/probe-context.mjs +21 -21
- package/scripts/agent-eval/probe-explore.mjs +40 -40
- package/scripts/agent-eval/probe-node.mjs +20 -20
- package/scripts/agent-eval/probe-sweep.mjs +119 -119
- package/scripts/agent-eval/probe-trace.mjs +20 -20
- package/scripts/agent-eval/redirect-read-hook.sh +38 -0
- package/scripts/agent-eval/run-agent.sh +34 -34
- package/scripts/agent-eval/run-all.sh +69 -67
- package/scripts/agent-eval/run-arms.sh +56 -56
- package/scripts/agent-eval/seq-matrix.mjs +137 -137
- package/scripts/build-bundle.sh +118 -118
- package/scripts/extract-release-notes.mjs +130 -130
- package/scripts/local-install.sh +41 -41
- package/scripts/npm-sdk.js +75 -75
- package/scripts/npm-shim.js +246 -246
- package/scripts/pack-npm.sh +119 -119
- package/scripts/prepare-release.mjs +270 -270
- package/scripts/qa_eval/README.md +400 -0
- package/scripts/qa_eval/agent_runner.py +526 -0
- package/scripts/qa_eval/data/.gitignore +4 -0
- package/scripts/qa_eval/data/test-set.jsonl +22 -0
- package/scripts/qa_eval/eval_metrics.py +233 -0
- package/scripts/qa_eval/external_agent.py +577 -0
- package/scripts/qa_eval/llm_config.py +92 -0
- package/scripts/qa_eval/memory_monitor.py +132 -0
- package/scripts/qa_eval/my_answer_accuracy.py +187 -0
- package/scripts/qa_eval/requirements.txt +2 -0
- package/scripts/qa_eval/run_pipeline.py +702 -0
- package/scripts/qa_eval/stats_efficiency.py +279 -0
- package/scripts/qa_eval/stats_scores.py +207 -0
- package/dist/bin/codegraph.d.ts +0 -26
- package/dist/bin/codegraph.d.ts.map +0 -1
- package/dist/bin/codegraph.js +0 -1572
- package/dist/bin/codegraph.js.map +0 -1
- package/dist/extraction/arkanalyzer-extractor.d.ts +0 -6
- package/dist/extraction/arkanalyzer-extractor.d.ts.map +0 -1
- package/dist/extraction/arkanalyzer-extractor.js +0 -11
- package/dist/extraction/arkanalyzer-extractor.js.map +0 -1
- package/dist/extraction/arkanalyzer-project.d.ts +0 -20
- package/dist/extraction/arkanalyzer-project.d.ts.map +0 -1
- package/dist/extraction/arkanalyzer-project.js +0 -596
- package/dist/extraction/arkanalyzer-project.js.map +0 -1
package/dist/bin/homegraph.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* HomeGraph CLI
|
|
5
5
|
*
|
|
6
|
-
* Command-line interface for
|
|
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
|
|
12
|
-
* homegraph init [path] Initialize
|
|
13
|
-
* homegraph uninit [path] Remove
|
|
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
|
|
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
|
-
|
|
71
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
186
|
-
// Note:
|
|
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(
|
|
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 =
|
|
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
|
-
`
|
|
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
|
-
*
|
|
441
|
+
* homegraph init [path]
|
|
396
442
|
*/
|
|
397
443
|
program
|
|
398
444
|
.command('init [path]')
|
|
399
|
-
.description('Initialize
|
|
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
|
|
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:
|
|
419
|
-
const cg = await
|
|
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
|
-
*
|
|
513
|
+
* homegraph uninit [path]
|
|
455
514
|
*/
|
|
456
515
|
program
|
|
457
516
|
.command('uninit [path]')
|
|
458
|
-
.description('Remove
|
|
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(`
|
|
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
|
|
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:
|
|
481
|
-
const cg =
|
|
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
|
|
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
|
-
*
|
|
566
|
+
* homegraph index [path]
|
|
501
567
|
*/
|
|
502
568
|
program
|
|
503
569
|
.command('index [path]')
|
|
504
|
-
.description('
|
|
505
|
-
.option('-f, --force', '
|
|
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(`
|
|
585
|
+
error(`HomeGraph not initialized in ${projectPath}`);
|
|
513
586
|
info('Run "homegraph init" first');
|
|
514
587
|
process.exit(1);
|
|
515
588
|
}
|
|
516
|
-
const { default:
|
|
517
|
-
const cg = await
|
|
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
|
-
|
|
521
|
-
|
|
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
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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
|
-
*
|
|
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(`
|
|
649
|
+
error(`HomeGraph not initialized in ${projectPath}`);
|
|
574
650
|
}
|
|
575
651
|
process.exit(1);
|
|
576
652
|
}
|
|
577
|
-
const { default:
|
|
578
|
-
const cg = await
|
|
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
|
|
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
|
-
*
|
|
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.
|
|
714
|
+
indexPath: (0, directory_1.getHomeGraphDir)(projectPath),
|
|
639
715
|
lastIndexed: null,
|
|
640
716
|
}));
|
|
641
717
|
return;
|
|
642
718
|
}
|
|
643
|
-
console.log(chalk.bold('\
|
|
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:
|
|
650
|
-
const cg = await
|
|
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.
|
|
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('\
|
|
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
|
|
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
|
-
*
|
|
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(`
|
|
860
|
+
error(`HomeGraph not initialized in ${projectPath}`);
|
|
785
861
|
process.exit(1);
|
|
786
862
|
}
|
|
787
|
-
const { default:
|
|
788
|
-
const cg = await
|
|
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
|
-
*
|
|
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(`
|
|
1125
|
+
error(`HomeGraph not initialized in ${projectPath}`);
|
|
852
1126
|
process.exit(1);
|
|
853
1127
|
}
|
|
854
|
-
const { default:
|
|
855
|
-
const cg = await
|
|
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
|
-
*
|
|
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
|
-
|
|
1008
|
-
|
|
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('\
|
|
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
|
-
*
|
|
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(`
|
|
1432
|
+
error(`HomeGraph not initialized in ${projectPath}`);
|
|
1070
1433
|
return;
|
|
1071
1434
|
}
|
|
1072
|
-
const lockPath = path.join((0, directory_1.
|
|
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
|
-
*
|
|
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(`
|
|
1465
|
+
error(`HomeGraph not initialized in ${projectPath}`);
|
|
1103
1466
|
process.exit(1);
|
|
1104
1467
|
}
|
|
1105
|
-
const { default:
|
|
1106
|
-
const cg = await
|
|
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
|
-
*
|
|
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(`
|
|
1536
|
+
error(`HomeGraph not initialized in ${projectPath}`);
|
|
1174
1537
|
process.exit(1);
|
|
1175
1538
|
}
|
|
1176
|
-
const { default:
|
|
1177
|
-
const cg = await
|
|
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
|
-
*
|
|
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(`
|
|
1606
|
+
error(`HomeGraph not initialized in ${projectPath}`);
|
|
1244
1607
|
process.exit(1);
|
|
1245
1608
|
}
|
|
1246
|
-
const { default:
|
|
1247
|
-
const cg = await
|
|
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
|
-
*
|
|
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 |
|
|
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(`
|
|
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:
|
|
1359
|
-
const cg = await
|
|
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
|
-
*
|
|
1821
|
+
* homegraph install
|
|
1452
1822
|
*/
|
|
1453
1823
|
program
|
|
1454
1824
|
.command('install')
|
|
1455
|
-
.description('Install
|
|
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
|
-
*
|
|
1875
|
+
* homegraph uninstall
|
|
1506
1876
|
*
|
|
1507
|
-
* Inverse of `install`. Removes the
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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()
|