@quolu/lattice 0.70.0 → 0.71.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/bin/lattice.mjs +21 -0
- package/package.json +1 -1
- package/sensor/dist/bin/lattice-sensor.js +746 -323
- package/sensor/dist/bin/viewer-gate.d.ts +17 -0
- package/sensor/dist/bin/viewer-gate.d.ts.map +1 -0
- package/sensor/dist/bin/viewer-gate.js +31 -0
- package/sensor/dist/bin/viewer-gate.js.map +1 -0
- package/sensor/dist/context/formatter.d.ts +7 -1
- package/sensor/dist/context/formatter.d.ts.map +1 -1
- package/sensor/dist/context/formatter.js +12 -6
- package/sensor/dist/context/formatter.js.map +1 -1
- package/sensor/dist/context/index.d.ts +12 -0
- package/sensor/dist/context/index.d.ts.map +1 -1
- package/sensor/dist/context/index.js +103 -16
- package/sensor/dist/context/index.js.map +1 -1
- package/sensor/dist/db/index.d.ts +23 -2
- package/sensor/dist/db/index.d.ts.map +1 -1
- package/sensor/dist/db/index.js +109 -31
- package/sensor/dist/db/index.js.map +1 -1
- package/sensor/dist/db/migrations.d.ts +1 -1
- package/sensor/dist/db/migrations.d.ts.map +1 -1
- package/sensor/dist/db/migrations.js +68 -1
- package/sensor/dist/db/migrations.js.map +1 -1
- package/sensor/dist/db/queries.d.ts +583 -6
- package/sensor/dist/db/queries.d.ts.map +1 -1
- package/sensor/dist/db/queries.js +1425 -57
- package/sensor/dist/db/queries.js.map +1 -1
- package/sensor/dist/db/schema.sql +27 -4
- package/sensor/dist/db/sqlite-adapter.d.ts +2 -0
- package/sensor/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/sensor/dist/db/sqlite-adapter.js +56 -7
- package/sensor/dist/db/sqlite-adapter.js.map +1 -1
- package/sensor/dist/db/synthesis-stage.d.ts +12 -0
- package/sensor/dist/db/synthesis-stage.d.ts.map +1 -0
- package/sensor/dist/db/synthesis-stage.js +93 -0
- package/sensor/dist/db/synthesis-stage.js.map +1 -0
- package/sensor/dist/db/wal-valve.d.ts +32 -12
- package/sensor/dist/db/wal-valve.d.ts.map +1 -1
- package/sensor/dist/db/wal-valve.js +65 -22
- package/sensor/dist/db/wal-valve.js.map +1 -1
- package/sensor/dist/db/wsl-shared-index.d.ts +53 -0
- package/sensor/dist/db/wsl-shared-index.d.ts.map +1 -0
- package/sensor/dist/db/wsl-shared-index.js +121 -0
- package/sensor/dist/db/wsl-shared-index.js.map +1 -0
- package/sensor/dist/directory.d.ts +126 -2
- package/sensor/dist/directory.d.ts.map +1 -1
- package/sensor/dist/directory.js +285 -16
- package/sensor/dist/directory.js.map +1 -1
- package/sensor/dist/errors.d.ts +14 -0
- package/sensor/dist/errors.d.ts.map +1 -1
- package/sensor/dist/errors.js +16 -1
- package/sensor/dist/errors.js.map +1 -1
- package/sensor/dist/extraction/cfml-extractor.d.ts +1 -0
- package/sensor/dist/extraction/cfml-extractor.d.ts.map +1 -1
- package/sensor/dist/extraction/cfml-extractor.js +15 -3
- package/sensor/dist/extraction/cfml-extractor.js.map +1 -1
- package/sensor/dist/extraction/dfm-extractor.d.ts.map +1 -1
- package/sensor/dist/extraction/dfm-extractor.js +14 -10
- package/sensor/dist/extraction/dfm-extractor.js.map +1 -1
- package/sensor/dist/extraction/extraction-version.d.ts +1 -1
- package/sensor/dist/extraction/extraction-version.d.ts.map +1 -1
- package/sensor/dist/extraction/extraction-version.js +3 -1
- package/sensor/dist/extraction/extraction-version.js.map +1 -1
- package/sensor/dist/extraction/function-ref.d.ts +6 -4
- package/sensor/dist/extraction/function-ref.d.ts.map +1 -1
- package/sensor/dist/extraction/function-ref.js +35 -14
- package/sensor/dist/extraction/function-ref.js.map +1 -1
- package/sensor/dist/extraction/generated-detection.d.ts +48 -12
- package/sensor/dist/extraction/generated-detection.d.ts.map +1 -1
- package/sensor/dist/extraction/generated-detection.js +176 -11
- package/sensor/dist/extraction/generated-detection.js.map +1 -1
- package/sensor/dist/extraction/grammars.d.ts +38 -0
- package/sensor/dist/extraction/grammars.d.ts.map +1 -1
- package/sensor/dist/extraction/grammars.js +115 -3
- package/sensor/dist/extraction/grammars.js.map +1 -1
- package/sensor/dist/extraction/index.d.ts +218 -14
- package/sensor/dist/extraction/index.d.ts.map +1 -1
- package/sensor/dist/extraction/index.js +887 -175
- package/sensor/dist/extraction/index.js.map +1 -1
- package/sensor/dist/extraction/languages/c-cpp.d.ts +58 -0
- package/sensor/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/c-cpp.js +310 -19
- package/sensor/dist/extraction/languages/c-cpp.js.map +1 -1
- package/sensor/dist/extraction/languages/dart.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/dart.js +8 -3
- package/sensor/dist/extraction/languages/dart.js.map +1 -1
- package/sensor/dist/extraction/languages/erlang.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/erlang.js +58 -22
- package/sensor/dist/extraction/languages/erlang.js.map +1 -1
- package/sensor/dist/extraction/languages/javascript.js +1 -1
- package/sensor/dist/extraction/languages/javascript.js.map +1 -1
- package/sensor/dist/extraction/languages/kotlin.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/kotlin.js +169 -36
- package/sensor/dist/extraction/languages/kotlin.js.map +1 -1
- package/sensor/dist/extraction/languages/lua.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/lua.js +4 -1
- package/sensor/dist/extraction/languages/lua.js.map +1 -1
- package/sensor/dist/extraction/languages/objc.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/objc.js +4 -0
- package/sensor/dist/extraction/languages/objc.js.map +1 -1
- package/sensor/dist/extraction/languages/python.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/python.js +71 -0
- package/sensor/dist/extraction/languages/python.js.map +1 -1
- package/sensor/dist/extraction/languages/rust.d.ts +20 -0
- package/sensor/dist/extraction/languages/rust.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/rust.js +50 -20
- package/sensor/dist/extraction/languages/rust.js.map +1 -1
- package/sensor/dist/extraction/languages/scala.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/scala.js +18 -3
- package/sensor/dist/extraction/languages/scala.js.map +1 -1
- package/sensor/dist/extraction/languages/swift.d.ts +15 -0
- package/sensor/dist/extraction/languages/swift.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/swift.js +50 -0
- package/sensor/dist/extraction/languages/swift.js.map +1 -1
- package/sensor/dist/extraction/languages/typescript.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/typescript.js +9 -2
- package/sensor/dist/extraction/languages/typescript.js.map +1 -1
- package/sensor/dist/extraction/liquid-extractor.d.ts +18 -0
- package/sensor/dist/extraction/liquid-extractor.d.ts.map +1 -1
- package/sensor/dist/extraction/liquid-extractor.js +98 -22
- package/sensor/dist/extraction/liquid-extractor.js.map +1 -1
- package/sensor/dist/extraction/mybatis-extractor.d.ts.map +1 -1
- package/sensor/dist/extraction/mybatis-extractor.js +6 -4
- package/sensor/dist/extraction/mybatis-extractor.js.map +1 -1
- package/sensor/dist/extraction/parse-pool.d.ts +7 -0
- package/sensor/dist/extraction/parse-pool.d.ts.map +1 -1
- package/sensor/dist/extraction/parse-pool.js +20 -1
- package/sensor/dist/extraction/parse-pool.js.map +1 -1
- package/sensor/dist/extraction/syntax-tokens.d.ts +103 -0
- package/sensor/dist/extraction/syntax-tokens.d.ts.map +1 -0
- package/sensor/dist/extraction/syntax-tokens.js +381 -0
- package/sensor/dist/extraction/syntax-tokens.js.map +1 -0
- package/sensor/dist/extraction/tree-sitter-helpers.d.ts +5 -0
- package/sensor/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
- package/sensor/dist/extraction/tree-sitter-helpers.js +17 -0
- package/sensor/dist/extraction/tree-sitter-helpers.js.map +1 -1
- package/sensor/dist/extraction/tree-sitter-types.d.ts +31 -3
- package/sensor/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/sensor/dist/extraction/tree-sitter.d.ts +101 -18
- package/sensor/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/sensor/dist/extraction/tree-sitter.js +928 -134
- package/sensor/dist/extraction/tree-sitter.js.map +1 -1
- package/sensor/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
- package/sensor/dist/file-limits.d.ts +40 -0
- package/sensor/dist/file-limits.d.ts.map +1 -0
- package/sensor/dist/file-limits.js +147 -0
- package/sensor/dist/file-limits.js.map +1 -0
- package/sensor/dist/graph/branch-guards.d.ts +265 -0
- package/sensor/dist/graph/branch-guards.d.ts.map +1 -0
- package/sensor/dist/graph/branch-guards.js +2325 -0
- package/sensor/dist/graph/branch-guards.js.map +1 -0
- package/sensor/dist/graph/dead-code.d.ts +251 -0
- package/sensor/dist/graph/dead-code.d.ts.map +1 -0
- package/sensor/dist/graph/dead-code.js +776 -0
- package/sensor/dist/graph/dead-code.js.map +1 -0
- package/sensor/dist/graph/dynamic-boundary-report.d.ts +121 -0
- package/sensor/dist/graph/dynamic-boundary-report.d.ts.map +1 -0
- package/sensor/dist/graph/dynamic-boundary-report.js +283 -0
- package/sensor/dist/graph/dynamic-boundary-report.js.map +1 -0
- package/sensor/dist/graph/index.d.ts +4 -0
- package/sensor/dist/graph/index.d.ts.map +1 -1
- package/sensor/dist/graph/index.js +16 -1
- package/sensor/dist/graph/index.js.map +1 -1
- package/sensor/dist/graph/named-symbol-flow.d.ts +125 -0
- package/sensor/dist/graph/named-symbol-flow.d.ts.map +1 -0
- package/sensor/dist/graph/named-symbol-flow.js +552 -0
- package/sensor/dist/graph/named-symbol-flow.js.map +1 -0
- package/sensor/dist/graph/queries.d.ts.map +1 -1
- package/sensor/dist/graph/queries.js +2 -0
- package/sensor/dist/graph/queries.js.map +1 -1
- package/sensor/dist/graph/symbol-lookup.d.ts +83 -0
- package/sensor/dist/graph/symbol-lookup.d.ts.map +1 -0
- package/sensor/dist/graph/symbol-lookup.js +181 -0
- package/sensor/dist/graph/symbol-lookup.js.map +1 -0
- package/sensor/dist/graph/traversal.d.ts +9 -0
- package/sensor/dist/graph/traversal.d.ts.map +1 -1
- package/sensor/dist/graph/traversal.js +62 -36
- package/sensor/dist/graph/traversal.js.map +1 -1
- package/sensor/dist/graph/type-hierarchy.d.ts +155 -0
- package/sensor/dist/graph/type-hierarchy.d.ts.map +1 -0
- package/sensor/dist/graph/type-hierarchy.js +382 -0
- package/sensor/dist/graph/type-hierarchy.js.map +1 -0
- package/sensor/dist/index.d.ts +272 -10
- package/sensor/dist/index.d.ts.map +1 -1
- package/sensor/dist/index.js +510 -34
- package/sensor/dist/index.js.map +1 -1
- package/sensor/dist/mcp/answer-freshness.d.ts +10 -0
- package/sensor/dist/mcp/answer-freshness.d.ts.map +1 -0
- package/sensor/dist/mcp/answer-freshness.js +68 -0
- package/sensor/dist/mcp/answer-freshness.js.map +1 -0
- package/sensor/dist/mcp/daemon-manager.d.ts +1 -1
- package/sensor/dist/mcp/daemon-manager.d.ts.map +1 -1
- package/sensor/dist/mcp/daemon-manager.js +17 -1
- package/sensor/dist/mcp/daemon-manager.js.map +1 -1
- package/sensor/dist/mcp/daemon-paths.d.ts +8 -0
- package/sensor/dist/mcp/daemon-paths.d.ts.map +1 -1
- package/sensor/dist/mcp/daemon-paths.js +65 -2
- package/sensor/dist/mcp/daemon-paths.js.map +1 -1
- package/sensor/dist/mcp/daemon-registry.d.ts +17 -4
- package/sensor/dist/mcp/daemon-registry.d.ts.map +1 -1
- package/sensor/dist/mcp/daemon-registry.js +133 -23
- package/sensor/dist/mcp/daemon-registry.js.map +1 -1
- package/sensor/dist/mcp/daemon.d.ts +26 -13
- package/sensor/dist/mcp/daemon.d.ts.map +1 -1
- package/sensor/dist/mcp/daemon.js +126 -32
- package/sensor/dist/mcp/daemon.js.map +1 -1
- package/sensor/dist/mcp/dynamic-boundaries.d.ts +1 -10
- package/sensor/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
- package/sensor/dist/mcp/dynamic-boundaries.js +46 -42
- package/sensor/dist/mcp/dynamic-boundaries.js.map +1 -1
- package/sensor/dist/mcp/engine.d.ts +31 -9
- package/sensor/dist/mcp/engine.d.ts.map +1 -1
- package/sensor/dist/mcp/engine.js +190 -79
- package/sensor/dist/mcp/engine.js.map +1 -1
- package/sensor/dist/mcp/explore-dedup.d.ts +140 -0
- package/sensor/dist/mcp/explore-dedup.d.ts.map +1 -0
- package/sensor/dist/mcp/explore-dedup.js +239 -0
- package/sensor/dist/mcp/explore-dedup.js.map +1 -0
- package/sensor/dist/mcp/explore-diagnostics.d.ts +289 -0
- package/sensor/dist/mcp/explore-diagnostics.d.ts.map +1 -0
- package/sensor/dist/mcp/explore-diagnostics.js +558 -0
- package/sensor/dist/mcp/explore-diagnostics.js.map +1 -0
- package/sensor/dist/mcp/explore-session-state.d.ts +217 -0
- package/sensor/dist/mcp/explore-session-state.d.ts.map +1 -0
- package/sensor/dist/mcp/explore-session-state.js +322 -0
- package/sensor/dist/mcp/explore-session-state.js.map +1 -0
- package/sensor/dist/mcp/index-freshness-worker.d.ts +2 -0
- package/sensor/dist/mcp/index-freshness-worker.d.ts.map +1 -0
- package/sensor/dist/mcp/index-freshness-worker.js +30 -0
- package/sensor/dist/mcp/index-freshness-worker.js.map +1 -0
- package/sensor/dist/mcp/index-freshness.d.ts +7 -0
- package/sensor/dist/mcp/index-freshness.d.ts.map +1 -0
- package/sensor/dist/mcp/index-freshness.js +94 -0
- package/sensor/dist/mcp/index-freshness.js.map +1 -0
- package/sensor/dist/mcp/index.d.ts +3 -1
- package/sensor/dist/mcp/index.d.ts.map +1 -1
- package/sensor/dist/mcp/index.js +109 -12
- package/sensor/dist/mcp/index.js.map +1 -1
- package/sensor/dist/mcp/liveness-watchdog.d.ts +4 -1
- package/sensor/dist/mcp/liveness-watchdog.d.ts.map +1 -1
- package/sensor/dist/mcp/liveness-watchdog.js +11 -2
- package/sensor/dist/mcp/liveness-watchdog.js.map +1 -1
- package/sensor/dist/mcp/project-lifecycle.d.ts +9 -0
- package/sensor/dist/mcp/project-lifecycle.d.ts.map +1 -0
- package/sensor/dist/mcp/project-lifecycle.js +182 -0
- package/sensor/dist/mcp/project-lifecycle.js.map +1 -0
- package/sensor/dist/mcp/proxy.d.ts.map +1 -1
- package/sensor/dist/mcp/proxy.js +15 -1
- package/sensor/dist/mcp/proxy.js.map +1 -1
- package/sensor/dist/mcp/query-pool.d.ts +2 -2
- package/sensor/dist/mcp/query-pool.d.ts.map +1 -1
- package/sensor/dist/mcp/query-pool.js +9 -7
- package/sensor/dist/mcp/query-pool.js.map +1 -1
- package/sensor/dist/mcp/query-worker.js +2 -2
- package/sensor/dist/mcp/query-worker.js.map +1 -1
- package/sensor/dist/mcp/server-instructions.d.ts +2 -2
- package/sensor/dist/mcp/server-instructions.d.ts.map +1 -1
- package/sensor/dist/mcp/server-instructions.js +13 -6
- package/sensor/dist/mcp/server-instructions.js.map +1 -1
- package/sensor/dist/mcp/session.d.ts +16 -0
- package/sensor/dist/mcp/session.d.ts.map +1 -1
- package/sensor/dist/mcp/session.js +36 -13
- package/sensor/dist/mcp/session.js.map +1 -1
- package/sensor/dist/mcp/startup-handshake.d.ts +3 -1
- package/sensor/dist/mcp/startup-handshake.d.ts.map +1 -1
- package/sensor/dist/mcp/startup-handshake.js +10 -2
- package/sensor/dist/mcp/startup-handshake.js.map +1 -1
- package/sensor/dist/mcp/tools.d.ts +496 -38
- package/sensor/dist/mcp/tools.d.ts.map +1 -1
- package/sensor/dist/mcp/tools.js +4021 -772
- package/sensor/dist/mcp/tools.js.map +1 -1
- package/sensor/dist/mcp/writer-lock.d.ts +61 -0
- package/sensor/dist/mcp/writer-lock.d.ts.map +1 -0
- package/sensor/dist/mcp/writer-lock.js +260 -0
- package/sensor/dist/mcp/writer-lock.js.map +1 -0
- package/sensor/dist/project-config.d.ts +23 -0
- package/sensor/dist/project-config.d.ts.map +1 -1
- package/sensor/dist/project-config.js +39 -2
- package/sensor/dist/project-config.js.map +1 -1
- package/sensor/dist/resolution/alias-binding.d.ts +56 -0
- package/sensor/dist/resolution/alias-binding.d.ts.map +1 -0
- package/sensor/dist/resolution/alias-binding.js +127 -0
- package/sensor/dist/resolution/alias-binding.js.map +1 -0
- package/sensor/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
- package/sensor/dist/resolution/c-fnptr-synthesizer.js +21 -19
- package/sensor/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
- package/sensor/dist/resolution/callback-synthesizer.d.ts +23 -1
- package/sensor/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/sensor/dist/resolution/callback-synthesizer.js +356 -155
- package/sensor/dist/resolution/callback-synthesizer.js.map +1 -1
- package/sensor/dist/resolution/cpp-constructor.d.ts +4 -0
- package/sensor/dist/resolution/cpp-constructor.d.ts.map +1 -0
- package/sensor/dist/resolution/cpp-constructor.js +123 -0
- package/sensor/dist/resolution/cpp-constructor.js.map +1 -0
- package/sensor/dist/resolution/cpp-macro-visibility.d.ts +12 -0
- package/sensor/dist/resolution/cpp-macro-visibility.d.ts.map +1 -0
- package/sensor/dist/resolution/cpp-macro-visibility.js +342 -0
- package/sensor/dist/resolution/cpp-macro-visibility.js.map +1 -0
- package/sensor/dist/resolution/expo-router-synthesizer.d.ts +32 -0
- package/sensor/dist/resolution/expo-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/expo-router-synthesizer.js +189 -0
- package/sensor/dist/resolution/expo-router-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/frameworks/csharp.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/csharp.js +96 -2
- package/sensor/dist/resolution/frameworks/csharp.js.map +1 -1
- package/sensor/dist/resolution/frameworks/expo-router.d.ts +189 -0
- package/sensor/dist/resolution/frameworks/expo-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/expo-router.js +785 -0
- package/sensor/dist/resolution/frameworks/expo-router.js.map +1 -0
- package/sensor/dist/resolution/frameworks/express.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/express.js +251 -16
- package/sensor/dist/resolution/frameworks/express.js.map +1 -1
- package/sensor/dist/resolution/frameworks/index.d.ts +5 -0
- package/sensor/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/index.js +29 -1
- package/sensor/dist/resolution/frameworks/index.js.map +1 -1
- package/sensor/dist/resolution/frameworks/java.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/java.js +79 -47
- package/sensor/dist/resolution/frameworks/java.js.map +1 -1
- package/sensor/dist/resolution/frameworks/laravel.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/laravel.js +294 -4
- package/sensor/dist/resolution/frameworks/laravel.js.map +1 -1
- package/sensor/dist/resolution/frameworks/nestjs.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/nestjs.js +6 -14
- package/sensor/dist/resolution/frameworks/nestjs.js.map +1 -1
- package/sensor/dist/resolution/frameworks/nextjs.d.ts +76 -0
- package/sensor/dist/resolution/frameworks/nextjs.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/nextjs.js +328 -0
- package/sensor/dist/resolution/frameworks/nextjs.js.map +1 -0
- package/sensor/dist/resolution/frameworks/object-literal.d.ts +32 -0
- package/sensor/dist/resolution/frameworks/object-literal.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/object-literal.js +139 -0
- package/sensor/dist/resolution/frameworks/object-literal.js.map +1 -0
- package/sensor/dist/resolution/frameworks/package-deps.d.ts +14 -0
- package/sensor/dist/resolution/frameworks/package-deps.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/package-deps.js +78 -0
- package/sensor/dist/resolution/frameworks/package-deps.js.map +1 -0
- package/sensor/dist/resolution/frameworks/python.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/python.js +166 -0
- package/sensor/dist/resolution/frameworks/python.js.map +1 -1
- package/sensor/dist/resolution/frameworks/react-native.d.ts +26 -0
- package/sensor/dist/resolution/frameworks/react-native.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/react-native.js +153 -14
- package/sensor/dist/resolution/frameworks/react-native.js.map +1 -1
- package/sensor/dist/resolution/frameworks/react-router.d.ts +46 -0
- package/sensor/dist/resolution/frameworks/react-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/react-router.js +187 -0
- package/sensor/dist/resolution/frameworks/react-router.js.map +1 -0
- package/sensor/dist/resolution/frameworks/react.d.ts +2 -1
- package/sensor/dist/resolution/frameworks/react.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/react.js +188 -139
- package/sensor/dist/resolution/frameworks/react.js.map +1 -1
- package/sensor/dist/resolution/frameworks/svelte.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/svelte.js +6 -1
- package/sensor/dist/resolution/frameworks/svelte.js.map +1 -1
- package/sensor/dist/resolution/frameworks/sveltekit-router.d.ts +36 -0
- package/sensor/dist/resolution/frameworks/sveltekit-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/sveltekit-router.js +156 -0
- package/sensor/dist/resolution/frameworks/sveltekit-router.js.map +1 -0
- package/sensor/dist/resolution/frameworks/swift.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/swift.js +140 -99
- package/sensor/dist/resolution/frameworks/swift.js.map +1 -1
- package/sensor/dist/resolution/frameworks/tanstack-router.d.ts +84 -0
- package/sensor/dist/resolution/frameworks/tanstack-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/tanstack-router.js +437 -0
- package/sensor/dist/resolution/frameworks/tanstack-router.js.map +1 -0
- package/sensor/dist/resolution/frameworks/vue-router.d.ts +82 -0
- package/sensor/dist/resolution/frameworks/vue-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/vue-router.js +377 -0
- package/sensor/dist/resolution/frameworks/vue-router.js.map +1 -0
- package/sensor/dist/resolution/import-resolver.d.ts +38 -0
- package/sensor/dist/resolution/import-resolver.d.ts.map +1 -1
- package/sensor/dist/resolution/import-resolver.js +394 -28
- package/sensor/dist/resolution/import-resolver.js.map +1 -1
- package/sensor/dist/resolution/index.d.ts +89 -25
- package/sensor/dist/resolution/index.d.ts.map +1 -1
- package/sensor/dist/resolution/index.js +573 -148
- package/sensor/dist/resolution/index.js.map +1 -1
- package/sensor/dist/resolution/js-builtins.d.ts +13 -0
- package/sensor/dist/resolution/js-builtins.d.ts.map +1 -0
- package/sensor/dist/resolution/js-builtins.js +46 -0
- package/sensor/dist/resolution/js-builtins.js.map +1 -0
- package/sensor/dist/resolution/name-matcher.d.ts +99 -22
- package/sensor/dist/resolution/name-matcher.d.ts.map +1 -1
- package/sensor/dist/resolution/name-matcher.js +2220 -86
- package/sensor/dist/resolution/name-matcher.js.map +1 -1
- package/sensor/dist/resolution/next-router-synthesizer.d.ts +27 -0
- package/sensor/dist/resolution/next-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/next-router-synthesizer.js +113 -0
- package/sensor/dist/resolution/next-router-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/path-aliases.d.ts +6 -4
- package/sensor/dist/resolution/path-aliases.d.ts.map +1 -1
- package/sensor/dist/resolution/path-aliases.js +125 -17
- package/sensor/dist/resolution/path-aliases.js.map +1 -1
- package/sensor/dist/resolution/react-router-synthesizer.d.ts +33 -0
- package/sensor/dist/resolution/react-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/react-router-synthesizer.js +126 -0
- package/sensor/dist/resolution/react-router-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/resolver-pool.d.ts +2 -0
- package/sensor/dist/resolution/resolver-pool.d.ts.map +1 -1
- package/sensor/dist/resolution/resolver-pool.js +4 -0
- package/sensor/dist/resolution/resolver-pool.js.map +1 -1
- package/sensor/dist/resolution/strip-comments.d.ts +6 -0
- package/sensor/dist/resolution/strip-comments.d.ts.map +1 -1
- package/sensor/dist/resolution/strip-comments.js +58 -0
- package/sensor/dist/resolution/strip-comments.js.map +1 -1
- package/sensor/dist/resolution/sveltekit-synthesizer.d.ts +58 -0
- package/sensor/dist/resolution/sveltekit-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/sveltekit-synthesizer.js +173 -0
- package/sensor/dist/resolution/sveltekit-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/swift-type-visibility.d.ts +52 -0
- package/sensor/dist/resolution/swift-type-visibility.d.ts.map +1 -0
- package/sensor/dist/resolution/swift-type-visibility.js +328 -0
- package/sensor/dist/resolution/swift-type-visibility.js.map +1 -0
- package/sensor/dist/resolution/synth-utils.d.ts +26 -0
- package/sensor/dist/resolution/synth-utils.d.ts.map +1 -0
- package/sensor/dist/resolution/synth-utils.js +75 -0
- package/sensor/dist/resolution/synth-utils.js.map +1 -0
- package/sensor/dist/resolution/tanstack-router-synthesizer.d.ts +31 -0
- package/sensor/dist/resolution/tanstack-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/tanstack-router-synthesizer.js +114 -0
- package/sensor/dist/resolution/tanstack-router-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/tier-synthesizer.d.ts +54 -0
- package/sensor/dist/resolution/tier-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/tier-synthesizer.js +1294 -0
- package/sensor/dist/resolution/tier-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/types.d.ts +78 -2
- package/sensor/dist/resolution/types.d.ts.map +1 -1
- package/sensor/dist/resolution/types.js +64 -0
- package/sensor/dist/resolution/types.js.map +1 -1
- package/sensor/dist/resolution/vue-router-synthesizer.d.ts +30 -0
- package/sensor/dist/resolution/vue-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/vue-router-synthesizer.js +115 -0
- package/sensor/dist/resolution/vue-router-synthesizer.js.map +1 -0
- package/sensor/dist/search/identifier-segments.d.ts +10 -0
- package/sensor/dist/search/identifier-segments.d.ts.map +1 -1
- package/sensor/dist/search/identifier-segments.js +29 -0
- package/sensor/dist/search/identifier-segments.js.map +1 -1
- package/sensor/dist/search/query-paths.d.ts +106 -0
- package/sensor/dist/search/query-paths.d.ts.map +1 -0
- package/sensor/dist/search/query-paths.js +513 -0
- package/sensor/dist/search/query-paths.js.map +1 -0
- package/sensor/dist/search/query-utils.d.ts +22 -2
- package/sensor/dist/search/query-utils.d.ts.map +1 -1
- package/sensor/dist/search/query-utils.js +56 -16
- package/sensor/dist/search/query-utils.js.map +1 -1
- package/sensor/dist/sync/watch-policy.d.ts +14 -0
- package/sensor/dist/sync/watch-policy.d.ts.map +1 -1
- package/sensor/dist/sync/watch-policy.js +19 -0
- package/sensor/dist/sync/watch-policy.js.map +1 -1
- package/sensor/dist/sync/watcher.d.ts +74 -35
- package/sensor/dist/sync/watcher.d.ts.map +1 -1
- package/sensor/dist/sync/watcher.js +281 -99
- package/sensor/dist/sync/watcher.js.map +1 -1
- package/sensor/dist/telemetry/index.d.ts +4 -2
- package/sensor/dist/telemetry/index.d.ts.map +1 -1
- package/sensor/dist/telemetry/index.js +92 -41
- package/sensor/dist/telemetry/index.js.map +1 -1
- package/sensor/dist/types.d.ts +18 -2
- package/sensor/dist/types.d.ts.map +1 -1
- package/sensor/dist/types.js +2 -0
- package/sensor/dist/types.js.map +1 -1
- package/sensor/dist/ui-server/api/deadcode.d.ts +84 -0
- package/sensor/dist/ui-server/api/deadcode.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/deadcode.js +136 -0
- package/sensor/dist/ui-server/api/deadcode.js.map +1 -0
- package/sensor/dist/ui-server/api/effects.d.ts +94 -0
- package/sensor/dist/ui-server/api/effects.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/effects.js +527 -0
- package/sensor/dist/ui-server/api/effects.js.map +1 -0
- package/sensor/dist/ui-server/api/entrypoints.d.ts +92 -0
- package/sensor/dist/ui-server/api/entrypoints.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/entrypoints.js +361 -0
- package/sensor/dist/ui-server/api/entrypoints.js.map +1 -0
- package/sensor/dist/ui-server/api/events.d.ts +183 -0
- package/sensor/dist/ui-server/api/events.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/events.js +430 -0
- package/sensor/dist/ui-server/api/events.js.map +1 -0
- package/sensor/dist/ui-server/api/file.d.ts +66 -0
- package/sensor/dist/ui-server/api/file.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/file.js +235 -0
- package/sensor/dist/ui-server/api/file.js.map +1 -0
- package/sensor/dist/ui-server/api/filecode.d.ts +126 -0
- package/sensor/dist/ui-server/api/filecode.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/filecode.js +205 -0
- package/sensor/dist/ui-server/api/filecode.js.map +1 -0
- package/sensor/dist/ui-server/api/flow.d.ts +226 -0
- package/sensor/dist/ui-server/api/flow.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/flow.js +612 -0
- package/sensor/dist/ui-server/api/flow.js.map +1 -0
- package/sensor/dist/ui-server/api/hierarchy.d.ts +81 -0
- package/sensor/dist/ui-server/api/hierarchy.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/hierarchy.js +92 -0
- package/sensor/dist/ui-server/api/hierarchy.js.map +1 -0
- package/sensor/dist/ui-server/api/index.d.ts +90 -0
- package/sensor/dist/ui-server/api/index.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/index.js +332 -0
- package/sensor/dist/ui-server/api/index.js.map +1 -0
- package/sensor/dist/ui-server/api/map.d.ts +256 -0
- package/sensor/dist/ui-server/api/map.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/map.js +760 -0
- package/sensor/dist/ui-server/api/map.js.map +1 -0
- package/sensor/dist/ui-server/api/node.d.ts +81 -0
- package/sensor/dist/ui-server/api/node.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/node.js +388 -0
- package/sensor/dist/ui-server/api/node.js.map +1 -0
- package/sensor/dist/ui-server/api/nodes.d.ts +25 -0
- package/sensor/dist/ui-server/api/nodes.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/nodes.js +45 -0
- package/sensor/dist/ui-server/api/nodes.js.map +1 -0
- package/sensor/dist/ui-server/api/program.d.ts +139 -0
- package/sensor/dist/ui-server/api/program.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/program.js +315 -0
- package/sensor/dist/ui-server/api/program.js.map +1 -0
- package/sensor/dist/ui-server/api/respond.d.ts +76 -0
- package/sensor/dist/ui-server/api/respond.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/respond.js +186 -0
- package/sensor/dist/ui-server/api/respond.js.map +1 -0
- package/sensor/dist/ui-server/api/route-roots.d.ts +39 -0
- package/sensor/dist/ui-server/api/route-roots.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/route-roots.js +96 -0
- package/sensor/dist/ui-server/api/route-roots.js.map +1 -0
- package/sensor/dist/ui-server/api/routes.d.ts +59 -0
- package/sensor/dist/ui-server/api/routes.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/routes.js +108 -0
- package/sensor/dist/ui-server/api/routes.js.map +1 -0
- package/sensor/dist/ui-server/api/screens.d.ts +117 -0
- package/sensor/dist/ui-server/api/screens.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/screens.js +611 -0
- package/sensor/dist/ui-server/api/screens.js.map +1 -0
- package/sensor/dist/ui-server/api/search.d.ts +29 -0
- package/sensor/dist/ui-server/api/search.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/search.js +232 -0
- package/sensor/dist/ui-server/api/search.js.map +1 -0
- package/sensor/dist/ui-server/api/session.d.ts +52 -0
- package/sensor/dist/ui-server/api/session.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/session.js +196 -0
- package/sensor/dist/ui-server/api/session.js.map +1 -0
- package/sensor/dist/ui-server/api/source.d.ts +200 -0
- package/sensor/dist/ui-server/api/source.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/source.js +422 -0
- package/sensor/dist/ui-server/api/source.js.map +1 -0
- package/sensor/dist/ui-server/api/stats.d.ts +27 -0
- package/sensor/dist/ui-server/api/stats.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/stats.js +164 -0
- package/sensor/dist/ui-server/api/stats.js.map +1 -0
- package/sensor/dist/ui-server/api/steps.d.ts +274 -0
- package/sensor/dist/ui-server/api/steps.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/steps.js +1544 -0
- package/sensor/dist/ui-server/api/steps.js.map +1 -0
- package/sensor/dist/ui-server/api/trail-store.d.ts +142 -0
- package/sensor/dist/ui-server/api/trail-store.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/trail-store.js +325 -0
- package/sensor/dist/ui-server/api/trail-store.js.map +1 -0
- package/sensor/dist/ui-server/api/trails.d.ts +163 -0
- package/sensor/dist/ui-server/api/trails.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/trails.js +369 -0
- package/sensor/dist/ui-server/api/trails.js.map +1 -0
- package/sensor/dist/ui-server/api/when.d.ts +133 -0
- package/sensor/dist/ui-server/api/when.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/when.js +275 -0
- package/sensor/dist/ui-server/api/when.js.map +1 -0
- package/sensor/dist/ui-server/api/wire.d.ts +179 -0
- package/sensor/dist/ui-server/api/wire.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/wire.js +231 -0
- package/sensor/dist/ui-server/api/wire.js.map +1 -0
- package/sensor/dist/ui-server/assets.d.ts +40 -0
- package/sensor/dist/ui-server/assets.d.ts.map +1 -0
- package/sensor/dist/ui-server/assets.js +110 -0
- package/sensor/dist/ui-server/assets.js.map +1 -0
- package/sensor/dist/ui-server/constants.d.ts +32 -0
- package/sensor/dist/ui-server/constants.d.ts.map +1 -0
- package/sensor/dist/ui-server/constants.js +35 -0
- package/sensor/dist/ui-server/constants.js.map +1 -0
- package/sensor/dist/ui-server/highlight/index.d.ts +113 -0
- package/sensor/dist/ui-server/highlight/index.d.ts.map +1 -0
- package/sensor/dist/ui-server/highlight/index.js +307 -0
- package/sensor/dist/ui-server/highlight/index.js.map +1 -0
- package/sensor/dist/ui-server/highlight/languages.d.ts +36 -0
- package/sensor/dist/ui-server/highlight/languages.d.ts.map +1 -0
- package/sensor/dist/ui-server/highlight/languages.js +50 -0
- package/sensor/dist/ui-server/highlight/languages.js.map +1 -0
- package/sensor/dist/ui-server/index.d.ts +92 -0
- package/sensor/dist/ui-server/index.d.ts.map +1 -0
- package/sensor/dist/ui-server/index.js +399 -0
- package/sensor/dist/ui-server/index.js.map +1 -0
- package/sensor/dist/ui-server/open-browser.d.ts +31 -0
- package/sensor/dist/ui-server/open-browser.d.ts.map +1 -0
- package/sensor/dist/ui-server/open-browser.js +79 -0
- package/sensor/dist/ui-server/open-browser.js.map +1 -0
- package/sensor/dist/ui-server/security.d.ts +127 -0
- package/sensor/dist/ui-server/security.d.ts.map +1 -0
- package/sensor/dist/ui-server/security.js +332 -0
- package/sensor/dist/ui-server/security.js.map +1 -0
- package/sensor/dist/ui-server/static.d.ts +45 -0
- package/sensor/dist/ui-server/static.d.ts.map +1 -0
- package/sensor/dist/ui-server/static.js +165 -0
- package/sensor/dist/ui-server/static.js.map +1 -0
- package/sensor/dist/utils.d.ts +14 -2
- package/sensor/dist/utils.d.ts.map +1 -1
- package/sensor/dist/utils.js +25 -10
- package/sensor/dist/utils.js.map +1 -1
- package/src/sensor-adapter.mjs +5 -1
|
@@ -61,6 +61,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
61
61
|
// launcher is (almost certainly) still alive. A launcher killed mid-startup
|
|
62
62
|
// otherwise blinds the PPID watchdog forever (#1185) — see early-ppid.ts.
|
|
63
63
|
require("../mcp/early-ppid");
|
|
64
|
+
// The browser viewer is not part of a release yet (see viewer-gate). Refuse
|
|
65
|
+
// `ui` / `web` — also as `help ui` or `ui --help` — before any startup work,
|
|
66
|
+
// unless LATTICE_SENSOR_UI=1 opts in.
|
|
67
|
+
const viewer_gate_1 = require("./viewer-gate");
|
|
68
|
+
{
|
|
69
|
+
const viewerCommand = (0, viewer_gate_1.requestedViewerCommand)(process.argv.slice(2));
|
|
70
|
+
if (viewerCommand && !(0, viewer_gate_1.viewerEnabled)()) {
|
|
71
|
+
process.stderr.write(`error: 'lattice sensor ${viewerCommand}' is not in this release yet. The browser viewer is coming in an upcoming release.\n`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
64
75
|
// Persist V8 compile artifacts across runs (Node ≥22.8). Every invocation —
|
|
65
76
|
// and every worker thread, which re-requires the whole extraction module
|
|
66
77
|
// graph — skips recompiling unchanged sources. Worth hundreds of ms of
|
|
@@ -87,6 +98,11 @@ const command_supervision_1 = require("./command-supervision");
|
|
|
87
98
|
const exact_traversal_1 = require("./exact-traversal");
|
|
88
99
|
const extraction_version_1 = require("../extraction/extraction-version");
|
|
89
100
|
const telemetry_1 = require("../telemetry");
|
|
101
|
+
// Value import, but dependency-free by design so `--help` text can name the
|
|
102
|
+
// default port without dragging node:http into every other subcommand; the
|
|
103
|
+
// server itself is loaded lazily inside the `ui` action. See ui-server/constants.
|
|
104
|
+
const constants_1 = require("../ui-server/constants");
|
|
105
|
+
const symbol_lookup_1 = require("../graph/symbol-lookup");
|
|
90
106
|
// Decided once, before `--color`/`--no-color` are stripped from argv below
|
|
91
107
|
// (#1281). Piped/redirected stdout, NO_COLOR, or --no-color -> plain output.
|
|
92
108
|
const COLORS_ENABLED = (0, color_1.ansiColorsEnabled)();
|
|
@@ -355,11 +371,31 @@ function main() {
|
|
|
355
371
|
function warn(message) {
|
|
356
372
|
console.log(chalk.yellow((0, glyphs_1.getGlyphs)().warn) + ' ' + message);
|
|
357
373
|
}
|
|
374
|
+
/** "not found" (+ optional did-you-mean) when no exact symbol matches. */
|
|
375
|
+
function formatSymbolNotFound(symbol, fuzzyNames) {
|
|
376
|
+
const suggestions = [...new Set(fuzzyNames.filter((n) => n !== symbol))].slice(0, 3);
|
|
377
|
+
if (suggestions.length === 0)
|
|
378
|
+
return `Symbol "${symbol}" not found`;
|
|
379
|
+
return `Symbol "${symbol}" not found — did you mean: ${suggestions.join(', ')}?`;
|
|
380
|
+
}
|
|
381
|
+
/** Compact node shape retained by the CLI's existing JSON lists. */
|
|
382
|
+
function cliNode(node) {
|
|
383
|
+
return { name: node.name, kind: node.kind, filePath: node.filePath, startLine: node.startLine };
|
|
384
|
+
}
|
|
385
|
+
/** Attribute a group's edges to every overload of this definition. */
|
|
386
|
+
function cliDefinition(group) {
|
|
387
|
+
const head = group[0];
|
|
388
|
+
return {
|
|
389
|
+
definition: { ...cliNode(head), id: head.id, qualifiedName: head.qualifiedName, language: head.language },
|
|
390
|
+
roots: group.map((node) => node.id),
|
|
391
|
+
};
|
|
392
|
+
}
|
|
358
393
|
/**
|
|
359
394
|
* Print indexing results using clack log methods
|
|
360
395
|
*/
|
|
361
396
|
function printIndexResult(clack, result, projectPath) {
|
|
362
397
|
const hasErrors = result.filesErrored > 0;
|
|
398
|
+
const parseWarnings = result.errors.filter((e) => e.code === 'parse_error' && e.severity === 'warning');
|
|
363
399
|
// Surface non-file-level failures (e.g. lock-acquisition failure
|
|
364
400
|
// when another indexer is running) before the file-count branches.
|
|
365
401
|
// Without this the CLI falls through to "No files found to index",
|
|
@@ -384,6 +420,10 @@ function main() {
|
|
|
384
420
|
clack.log.success(`Indexed ${formatNumber(result.filesIndexed)} files`);
|
|
385
421
|
}
|
|
386
422
|
clack.log.info(`${formatNumber(result.nodesCreated)} nodes, ${formatNumber(result.edgesCreated)} edges in ${formatDuration(result.durationMs)}`);
|
|
423
|
+
// Warning-only parse failures keep indexing successful, but must be visible.
|
|
424
|
+
for (const warning of parseWarnings) {
|
|
425
|
+
clack.log.warn(warning.message);
|
|
426
|
+
}
|
|
387
427
|
// A PARTIAL index (files silently dropped mid-pipeline) must not pass
|
|
388
428
|
// as a clean run — it's the difference between "indexed the repo" and
|
|
389
429
|
// "indexed most of the repo, quietly". Only the completeness
|
|
@@ -392,10 +432,33 @@ function main() {
|
|
|
392
432
|
for (const w of result.errors.filter((e) => e.code === 'index_partial')) {
|
|
393
433
|
clack.log.warn(w.message);
|
|
394
434
|
}
|
|
435
|
+
// Files salvaged from comment-stripped source after repeated parser
|
|
436
|
+
// failures are indexed but possibly incomplete — say so here, or the run
|
|
437
|
+
// reads as fully clean and the index quietly disagrees with a later
|
|
438
|
+
// re-parse of the same bytes (#1565).
|
|
439
|
+
const salvaged = result.errors.filter((e) => e.code === 'salvaged_stripped');
|
|
440
|
+
if (salvaged.length > 0) {
|
|
441
|
+
const sample = salvaged.slice(0, 3).map((e) => e.filePath).filter(Boolean).join(', ');
|
|
442
|
+
const more = salvaged.length > 3 ? ', ...' : '';
|
|
443
|
+
clack.log.warn(`${formatNumber(salvaged.length)} file(s) indexed from comment-stripped source after repeated parse failures ${(0, glyphs_1.getGlyphs)().dash} symbols may be incomplete (${sample}${more})`);
|
|
444
|
+
}
|
|
395
445
|
}
|
|
396
446
|
else if (hasErrors) {
|
|
397
447
|
clack.log.error(`Indexing failed ${(0, glyphs_1.getGlyphs)().dash} all ${formatNumber(result.filesErrored)} files had errors`);
|
|
398
448
|
}
|
|
449
|
+
else if (result.filesSkippedUnsupported) {
|
|
450
|
+
// A project LatticeSensor has no grammar for used to be indistinguishable from
|
|
451
|
+
// an empty one: same message, same `complete` state, same exit 0. Say which
|
|
452
|
+
// files were there and that the graph is empty on purpose, so nobody — and
|
|
453
|
+
// no agent trusting the graph — reads silence as "this code doesn't exist"
|
|
454
|
+
// (#1502).
|
|
455
|
+
const top = (result.topUnsupportedExtensions ?? [])
|
|
456
|
+
.map(e => `${e.ext} (${formatNumber(e.count)})`)
|
|
457
|
+
.join(', ');
|
|
458
|
+
clack.log.warn(`No supported source files found ${(0, glyphs_1.getGlyphs)().dash} ${formatNumber(result.filesSkippedUnsupported)} file(s) present, none in a language LatticeSensor indexes`
|
|
459
|
+
+ (top ? `: ${top}` : ''));
|
|
460
|
+
clack.log.info('LatticeSensor is inactive for this workspace — searches will return nothing. Use your own file tools here.');
|
|
461
|
+
}
|
|
399
462
|
else {
|
|
400
463
|
clack.log.warn('No files found to index');
|
|
401
464
|
}
|
|
@@ -428,9 +491,17 @@ function main() {
|
|
|
428
491
|
}
|
|
429
492
|
}
|
|
430
493
|
else if (projectPath) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
494
|
+
// No hard errors. Salvaged-file warnings still belong in the log — it
|
|
495
|
+
// carries the per-file detail behind the one-line summary above.
|
|
496
|
+
if (result.errors.some((e) => e.code === 'salvaged_stripped')) {
|
|
497
|
+
writeErrorLog(projectPath, result.errors);
|
|
498
|
+
clack.log.info('See .lattice/sensor/errors.log for details');
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
const logPath = path.join((0, directory_1.getLatticeSensorDir)(projectPath), 'errors.log');
|
|
502
|
+
if (fs.existsSync(logPath)) {
|
|
503
|
+
fs.unlinkSync(logPath);
|
|
504
|
+
}
|
|
434
505
|
}
|
|
435
506
|
}
|
|
436
507
|
}
|
|
@@ -550,16 +621,14 @@ function main() {
|
|
|
550
621
|
// Commands
|
|
551
622
|
// =============================================================================
|
|
552
623
|
/**
|
|
553
|
-
* lattice sensor init
|
|
624
|
+
* The `init` flow — shared by `lattice sensor init` and `lattice sensor install --init`
|
|
625
|
+
* (#1578): refuse an unsafe root, create `.lattice/sensor/`, build the initial
|
|
626
|
+
* index under supervision, then the post-index offers. `yes` makes every
|
|
627
|
+
* offer non-interactive (defaults only), so a container / CI bootstrap never
|
|
628
|
+
* blocks on a prompt. An unsafe root sets `process.exitCode = 1` and returns
|
|
629
|
+
* (no `--force` is implied by any caller); an index failure exits 1.
|
|
554
630
|
*/
|
|
555
|
-
|
|
556
|
-
.command('init [path]')
|
|
557
|
-
.description('Initialize LatticeSensor in a project directory and build the initial index')
|
|
558
|
-
.option('-i, --index', 'Deprecated: indexing now runs by default; flag accepted for backward compatibility')
|
|
559
|
-
.option('-f, --force', 'Initialize even if the path looks like your home directory or a filesystem root')
|
|
560
|
-
.option('-v, --verbose', 'Show detailed worker lifecycle and memory info')
|
|
561
|
-
.action(async (pathArg, options) => {
|
|
562
|
-
const projectPath = path.resolve(pathArg || process.cwd());
|
|
631
|
+
async function runInit(projectPath, options) {
|
|
563
632
|
const clack = await importESM('@clack/prompts');
|
|
564
633
|
clack.intro('Initializing LatticeSensor');
|
|
565
634
|
try {
|
|
@@ -580,9 +649,27 @@ function main() {
|
|
|
580
649
|
clack.outro('');
|
|
581
650
|
return;
|
|
582
651
|
}
|
|
652
|
+
if ((0, directory_1.hasForeignDbFile)(projectPath)) {
|
|
653
|
+
const dbFile = path.join((0, directory_1.getLatticeSensorDir)(projectPath), 'sensor.db');
|
|
654
|
+
clack.log.error(`${dbFile} is not a SQLite database, so it cannot be rebuilt in place.`);
|
|
655
|
+
clack.log.info('Move or delete that file, then run "lattice sensor init" again.');
|
|
656
|
+
clack.outro('');
|
|
657
|
+
process.exitCode = 1;
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
if ((0, directory_1.hasSchemalessDb)(projectPath)) {
|
|
661
|
+
clack.log.warn(`Found a sensor.db without the lattice sensor schema in ${(0, directory_1.getLatticeSensorDir)(projectPath)} (left by an interrupted init?) — rebuilding it.`);
|
|
662
|
+
}
|
|
583
663
|
const { default: LatticeSensor, getDatabasePath } = await loadLatticeSensor();
|
|
584
664
|
const cg = await LatticeSensor.init(projectPath, { index: false });
|
|
585
665
|
clack.log.success(`Initialized in ${projectPath}`);
|
|
666
|
+
// A fresh index on a Windows drive under WSL gets its own directory (#995).
|
|
667
|
+
// It isn't the documented name, so say where it went and why.
|
|
668
|
+
const dataDir = path.basename((0, directory_1.getLatticeSensorDir)(projectPath));
|
|
669
|
+
if (dataDir !== (0, directory_1.latticeSensorRelativeDir)()) {
|
|
670
|
+
clack.log.info(`The index is in ${dataDir}/: this project is on a Windows drive, so WSL keeps its own index ` +
|
|
671
|
+
`rather than share ${directory_1.DEFAULT_LATTICE_SENSOR_DIR}/ with LatticeSensor on Windows. Set LATTICE_SENSOR_DIR to choose the name yourself.`);
|
|
672
|
+
}
|
|
586
673
|
// Indexing runs by default now. The legacy -i/--index flag is still
|
|
587
674
|
// accepted (so existing muscle memory and scripts don't break) but is a
|
|
588
675
|
// no-op — initializing always builds the initial index.
|
|
@@ -614,8 +701,10 @@ function main() {
|
|
|
614
701
|
// An empty graph at a git super-repo usually means `.gitignore` excludes
|
|
615
702
|
// the child repos that hold the code — surface them and offer to opt in
|
|
616
703
|
// rather than leaving the user with a silent 0-node "Done". (#1156)
|
|
704
|
+
// Under --yes the offer prints its one-line opt-in snippet instead of
|
|
705
|
+
// prompting (same as a non-TTY run).
|
|
617
706
|
if (result.nodesCreated === 0) {
|
|
618
|
-
await offerIndexIgnoredRepos(clack, projectPath, runIndex, { interactive:
|
|
707
|
+
await offerIndexIgnoredRepos(clack, projectPath, runIndex, { interactive: !options.yes });
|
|
619
708
|
}
|
|
620
709
|
clack.outro('Done');
|
|
621
710
|
cg.destroy();
|
|
@@ -624,6 +713,19 @@ function main() {
|
|
|
624
713
|
clack.log.error(`Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
625
714
|
process.exit(1);
|
|
626
715
|
}
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* lattice sensor init [path]
|
|
719
|
+
*/
|
|
720
|
+
program
|
|
721
|
+
.command('init [path]')
|
|
722
|
+
.description('Initialize LatticeSensor in a project directory and build the initial index')
|
|
723
|
+
.option('-i, --index', 'Deprecated: indexing now runs by default; flag accepted for backward compatibility')
|
|
724
|
+
.option('-f, --force', 'Initialize even if the path looks like your home directory or a filesystem root')
|
|
725
|
+
.option('-v, --verbose', 'Show detailed worker lifecycle and memory info')
|
|
726
|
+
.option('-y, --yes', 'Non-interactive: skip every prompt and take the defaults (for scripts / CI / container bootstraps)')
|
|
727
|
+
.action(async (pathArg, options) => {
|
|
728
|
+
await runInit(path.resolve(pathArg || process.cwd()), options);
|
|
627
729
|
});
|
|
628
730
|
/**
|
|
629
731
|
* lattice sensor uninit [path]
|
|
@@ -688,7 +790,13 @@ function main() {
|
|
|
688
790
|
.option('-q, --quiet', 'Suppress progress output')
|
|
689
791
|
.option('-v, --verbose', 'Show detailed worker lifecycle and memory info')
|
|
690
792
|
.action(async (pathArg, options) => {
|
|
691
|
-
|
|
793
|
+
// An EXPLICIT path names the project to rebuild — it is never a hint to go
|
|
794
|
+
// looking for one. resolveProjectPath walks up to the nearest initialized
|
|
795
|
+
// ancestor, which is right for `lattice sensor query` run from a subdirectory,
|
|
796
|
+
// but for a full re-index it silently rebuilt the parent's graph under a
|
|
797
|
+
// normal "Done" when <path> had no index of its own (#1524). Only a bare
|
|
798
|
+
// `lattice sensor index` (cwd) may resolve upward.
|
|
799
|
+
const projectPath = pathArg ? path.resolve(pathArg) : resolveProjectPath();
|
|
692
800
|
try {
|
|
693
801
|
// Don't (re)index your home directory / a filesystem root (#845). --force
|
|
694
802
|
// doubles as the override.
|
|
@@ -699,66 +807,97 @@ function main() {
|
|
|
699
807
|
}
|
|
700
808
|
if (!(0, directory_1.isInitialized)(projectPath)) {
|
|
701
809
|
error(`LatticeSensor not initialized in ${projectPath}`);
|
|
702
|
-
|
|
810
|
+
const ancestor = pathArg ? resolveProjectPath(pathArg) : projectPath;
|
|
811
|
+
if (ancestor !== projectPath) {
|
|
812
|
+
info(`The nearest initialized project is ${ancestor} — pass that path to rebuild it, or run "lattice sensor init" in ${projectPath} to index it on its own.`);
|
|
813
|
+
}
|
|
814
|
+
else {
|
|
815
|
+
info('Run "lattice sensor init" first');
|
|
816
|
+
}
|
|
703
817
|
process.exit(1);
|
|
704
818
|
}
|
|
705
|
-
const {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
// approach reported "0 nodes" without the clear (#874); the recreate keeps
|
|
710
|
-
// that fixed AND avoids the failure mode where, on a large or pre-fix
|
|
711
|
-
// poisoned index, the per-row FTS delete churn wedged the main thread long
|
|
712
|
-
// enough to trip the liveness watchdog before scanning even began (#1067).
|
|
713
|
-
// recreate() hands back a fresh, empty instance — no clear() needed. For
|
|
714
|
-
// fast incremental updates use `sync`.
|
|
715
|
-
const cg = await LatticeSensor.recreate(projectPath);
|
|
716
|
-
// Supervise the indexer: self-terminate if orphaned (parent shim killed)
|
|
717
|
-
// or if the main thread wedges — neither was guarded on this path (#999).
|
|
718
|
-
// The DB + WAL paths let the liveness watchdog tell a slow store on
|
|
719
|
-
// degraded storage from a true wedge (#1231).
|
|
720
|
-
const dbPath = getDatabasePath(projectPath);
|
|
721
|
-
const supervision = (0, command_supervision_1.installCommandSupervision)('index', { progressPaths: [dbPath, `${dbPath}-wal`] });
|
|
819
|
+
const { tryAcquireWriterLock, releaseWriterLock, writerLockHeldMessage } = await Promise.resolve().then(() => __importStar(require('../mcp/writer-lock')));
|
|
820
|
+
const rebuild = tryAcquireWriterLock(projectPath, 'rebuild', 'rebuild.pid');
|
|
821
|
+
if (rebuild.kind === 'taken')
|
|
822
|
+
throw new Error('Another index rebuild is already in progress.');
|
|
722
823
|
try {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
return;
|
|
824
|
+
// A live MCP daemon keeps SQLite handles open. Verify it by its socket
|
|
825
|
+
// before stopping it so a stale pidfile can never signal another process.
|
|
826
|
+
const { stopDaemonAt } = await Promise.resolve().then(() => __importStar(require('../mcp/daemon-registry')));
|
|
827
|
+
const daemonStop = await stopDaemonAt(fs.realpathSync(projectPath), { preserveUnverified: true });
|
|
828
|
+
if (daemonStop.outcome === 'unverified' || daemonStop.outcome === 'still-running') {
|
|
829
|
+
throw new Error('Could not verify that the active LatticeSensor daemon has stopped. Run `lattice sensor daemon stop` to stop it, then retry `lattice sensor index`.');
|
|
730
830
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
831
|
+
// Keep the writer slot through recreation AND indexing. A reconnecting
|
|
832
|
+
// proxy/daemon must not open the replacement database halfway through.
|
|
833
|
+
const writer = tryAcquireWriterLock(projectPath, 'rebuild');
|
|
834
|
+
if (writer.kind === 'taken')
|
|
835
|
+
throw new Error(writerLockHeldMessage(writer.existing, writer.pidPath));
|
|
836
|
+
try {
|
|
837
|
+
const { default: LatticeSensor, getDatabasePath } = await loadLatticeSensor();
|
|
838
|
+
// `index` is a FULL re-index — identical to a fresh `init`. RECREATE the
|
|
839
|
+
// database from scratch (discard .lattice/sensor/sensor.db + its WAL) rather
|
|
840
|
+
// than opening the old graph and DELETE-ing every row. The clear-then-index
|
|
841
|
+
// approach reported "0 nodes" without the clear (#874); the recreate keeps
|
|
842
|
+
// that fixed AND avoids the failure mode where, on a large or pre-fix
|
|
843
|
+
// poisoned index, the per-row FTS delete churn wedged the main thread long
|
|
844
|
+
// enough to trip the liveness watchdog before scanning even began (#1067).
|
|
845
|
+
// recreate() hands back a fresh, empty instance — no clear() needed. For
|
|
846
|
+
// fast incremental updates use `sync`.
|
|
847
|
+
const cg = await LatticeSensor.recreate(projectPath);
|
|
848
|
+
// Supervise the indexer: self-terminate if orphaned (parent shim killed)
|
|
849
|
+
// or if the main thread wedges — neither was guarded on this path (#999).
|
|
850
|
+
// The DB + WAL paths let the liveness watchdog tell a slow store on
|
|
851
|
+
// degraded storage from a true wedge (#1231).
|
|
852
|
+
const dbPath = getDatabasePath(projectPath);
|
|
853
|
+
const supervision = (0, command_supervision_1.installCommandSupervision)('index', { progressPaths: [dbPath, `${dbPath}-wal`] });
|
|
854
|
+
try {
|
|
855
|
+
if (options.quiet) {
|
|
856
|
+
// Quiet mode: no UI, just run against the freshly-recreated graph.
|
|
857
|
+
const result = await cg.indexAll();
|
|
858
|
+
if (!result.success)
|
|
859
|
+
process.exit(1);
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
const clack = await importESM('@clack/prompts');
|
|
863
|
+
clack.intro('Indexing project');
|
|
864
|
+
// A closure so a re-index (after opting gitignored child repos in, #1156)
|
|
865
|
+
// renders identically. Supervision already wraps the whole command.
|
|
866
|
+
const renderIndex = async () => {
|
|
867
|
+
if (options.verbose) {
|
|
868
|
+
return await cg.indexAll({ onProgress: createVerboseProgress(), verbose: true });
|
|
869
|
+
}
|
|
870
|
+
process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
|
|
871
|
+
const progress = (0, shimmer_progress_1.createShimmerProgress)();
|
|
872
|
+
const r = await cg.indexAll({ onProgress: progress.onProgress });
|
|
873
|
+
await progress.stop();
|
|
874
|
+
return r;
|
|
875
|
+
};
|
|
876
|
+
const result = await renderIndex();
|
|
877
|
+
printIndexResult(clack, result, projectPath);
|
|
878
|
+
await recordIndexTelemetry(cg, result);
|
|
879
|
+
// Empty graph at a git super-repo → likely `.gitignore`d child repos;
|
|
880
|
+
// name them and offer to opt in instead of a silent 0-node result (#1156).
|
|
881
|
+
let finalResult = result;
|
|
882
|
+
if (result.nodesCreated === 0) {
|
|
883
|
+
finalResult = (await offerIndexIgnoredRepos(clack, projectPath, renderIndex, { interactive: true })) ?? result;
|
|
884
|
+
}
|
|
885
|
+
if (!finalResult.success) {
|
|
886
|
+
process.exit(1);
|
|
887
|
+
}
|
|
888
|
+
clack.outro('Done');
|
|
889
|
+
}
|
|
890
|
+
finally {
|
|
891
|
+
supervision.stop();
|
|
892
|
+
cg.destroy();
|
|
738
893
|
}
|
|
739
|
-
process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
|
|
740
|
-
const progress = (0, shimmer_progress_1.createShimmerProgress)();
|
|
741
|
-
const r = await cg.indexAll({ onProgress: progress.onProgress });
|
|
742
|
-
await progress.stop();
|
|
743
|
-
return r;
|
|
744
|
-
};
|
|
745
|
-
const result = await renderIndex();
|
|
746
|
-
printIndexResult(clack, result, projectPath);
|
|
747
|
-
await recordIndexTelemetry(cg, result);
|
|
748
|
-
// Empty graph at a git super-repo → likely `.gitignore`d child repos;
|
|
749
|
-
// name them and offer to opt in instead of a silent 0-node result (#1156).
|
|
750
|
-
let finalResult = result;
|
|
751
|
-
if (result.nodesCreated === 0) {
|
|
752
|
-
finalResult = (await offerIndexIgnoredRepos(clack, projectPath, renderIndex, { interactive: true })) ?? result;
|
|
753
894
|
}
|
|
754
|
-
|
|
755
|
-
|
|
895
|
+
finally {
|
|
896
|
+
releaseWriterLock(projectPath);
|
|
756
897
|
}
|
|
757
|
-
clack.outro('Done');
|
|
758
|
-
cg.destroy();
|
|
759
898
|
}
|
|
760
899
|
finally {
|
|
761
|
-
|
|
900
|
+
releaseWriterLock(projectPath, 'rebuild.pid');
|
|
762
901
|
}
|
|
763
902
|
}
|
|
764
903
|
catch (err) {
|
|
@@ -784,36 +923,43 @@ function main() {
|
|
|
784
923
|
}
|
|
785
924
|
const { default: LatticeSensor } = await loadLatticeSensor();
|
|
786
925
|
const cg = await LatticeSensor.open(projectPath);
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
926
|
+
try {
|
|
927
|
+
if (options.quiet) {
|
|
928
|
+
await cg.sync();
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
const clack = await importESM('@clack/prompts');
|
|
932
|
+
clack.intro('Syncing LatticeSensor');
|
|
933
|
+
process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
|
|
934
|
+
const progress = (0, shimmer_progress_1.createShimmerProgress)();
|
|
935
|
+
const result = await cg.sync({
|
|
936
|
+
onProgress: progress.onProgress,
|
|
937
|
+
}).finally(() => progress.stop());
|
|
938
|
+
const totalChanges = result.filesAdded + result.filesModified + result.filesRemoved;
|
|
939
|
+
if (totalChanges === 0 && !result.pendingRefsProcessed) {
|
|
940
|
+
clack.log.info('Already up to date');
|
|
941
|
+
}
|
|
942
|
+
else if (totalChanges > 0) {
|
|
943
|
+
clack.log.success(`Synced ${formatNumber(totalChanges)} changed files`);
|
|
944
|
+
const details = [];
|
|
945
|
+
if (result.filesAdded > 0)
|
|
946
|
+
details.push(`Added: ${result.filesAdded}`);
|
|
947
|
+
if (result.filesModified > 0)
|
|
948
|
+
details.push(`Modified: ${result.filesModified}`);
|
|
949
|
+
if (result.filesRemoved > 0)
|
|
950
|
+
details.push(`Removed: ${result.filesRemoved}`);
|
|
951
|
+
clack.log.info(`${details.join(', ')} ${(0, glyphs_1.getGlyphs)().dash} ${formatNumber(result.nodesUpdated)} nodes in ${formatDuration(result.durationMs)}`);
|
|
952
|
+
}
|
|
953
|
+
if (result.pendingRefsProcessed) {
|
|
954
|
+
const unresolved = result.pendingRefsUnresolved
|
|
955
|
+
? ` (${formatNumber(result.pendingRefsUnresolved)} unresolved)` : '';
|
|
956
|
+
clack.log.info(`Resolved ${formatNumber(result.pendingRefsResolved ?? 0)} pending references${unresolved}`);
|
|
957
|
+
}
|
|
958
|
+
clack.outro('Done');
|
|
803
959
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
const details = [];
|
|
807
|
-
if (result.filesAdded > 0)
|
|
808
|
-
details.push(`Added: ${result.filesAdded}`);
|
|
809
|
-
if (result.filesModified > 0)
|
|
810
|
-
details.push(`Modified: ${result.filesModified}`);
|
|
811
|
-
if (result.filesRemoved > 0)
|
|
812
|
-
details.push(`Removed: ${result.filesRemoved}`);
|
|
813
|
-
clack.log.info(`${details.join(', ')} ${(0, glyphs_1.getGlyphs)().dash} ${formatNumber(result.nodesUpdated)} nodes in ${formatDuration(result.durationMs)}`);
|
|
960
|
+
finally {
|
|
961
|
+
cg.destroy();
|
|
814
962
|
}
|
|
815
|
-
clack.outro('Done');
|
|
816
|
-
cg.destroy();
|
|
817
963
|
}
|
|
818
964
|
catch (err) {
|
|
819
965
|
if (!options.quiet) {
|
|
@@ -1051,20 +1197,27 @@ function main() {
|
|
|
1051
1197
|
const cg = await LatticeSensor.open(projectPath);
|
|
1052
1198
|
const limit = parseInt(options.limit || '10', 10);
|
|
1053
1199
|
const rawResults = cg.searchNodes(search, {
|
|
1054
|
-
|
|
1200
|
+
// Fetch one extra row so the CLI can report a cut without changing the
|
|
1201
|
+
// long-standing bare-array contract of `query --json` (#1639).
|
|
1202
|
+
limit: limit + 1,
|
|
1055
1203
|
kinds: options.kind ? [options.kind] : undefined,
|
|
1056
1204
|
});
|
|
1057
1205
|
// Mirror the MCP search down-rank so the CLI also surfaces the
|
|
1058
1206
|
// hand-written implementation before protobuf/gRPC scaffolding
|
|
1059
1207
|
// when both share a name. See extraction/generated-detection.ts.
|
|
1060
|
-
const
|
|
1061
|
-
const
|
|
1062
|
-
const aGen =
|
|
1063
|
-
const bGen =
|
|
1208
|
+
const isGen = cg.generatedFilePredicate(rawResults.map((r) => r.node.filePath));
|
|
1209
|
+
const rankedResults = [...rawResults].sort((a, b) => {
|
|
1210
|
+
const aGen = isGen(a.node.filePath) ? 1 : 0;
|
|
1211
|
+
const bGen = isGen(b.node.filePath) ? 1 : 0;
|
|
1064
1212
|
return aGen - bGen;
|
|
1065
1213
|
});
|
|
1214
|
+
const truncated = rankedResults.length > limit;
|
|
1215
|
+
const results = rankedResults.slice(0, limit);
|
|
1216
|
+
const truncationMessage = `Results truncated at ${limit}; pass --limit to widen.`;
|
|
1066
1217
|
if (options.json) {
|
|
1067
1218
|
console.log(JSON.stringify(results, null, 2));
|
|
1219
|
+
if (truncated)
|
|
1220
|
+
console.error(truncationMessage);
|
|
1068
1221
|
}
|
|
1069
1222
|
else {
|
|
1070
1223
|
if (results.length === 0) {
|
|
@@ -1088,6 +1241,8 @@ function main() {
|
|
|
1088
1241
|
}
|
|
1089
1242
|
console.log();
|
|
1090
1243
|
}
|
|
1244
|
+
if (truncated)
|
|
1245
|
+
console.log(chalk.dim(truncationMessage));
|
|
1091
1246
|
}
|
|
1092
1247
|
}
|
|
1093
1248
|
cg.destroy();
|
|
@@ -1136,6 +1291,60 @@ function main() {
|
|
|
1136
1291
|
process.exit(1);
|
|
1137
1292
|
}
|
|
1138
1293
|
});
|
|
1294
|
+
/**
|
|
1295
|
+
* lattice sensor context <task...>
|
|
1296
|
+
*
|
|
1297
|
+
* The CLI face of the public `buildContext` API (ContextBuilder): FTS entry
|
|
1298
|
+
* points + graph expansion + code blocks, formatted as markdown or JSON.
|
|
1299
|
+
* Advertised in the usage header since the first release but never actually
|
|
1300
|
+
* registered (#1611); external integrations (e.g. Memorix) invoke it as
|
|
1301
|
+
* `lattice sensor context --path <root> --format json --max-nodes 8 --no-code <task>`.
|
|
1302
|
+
*/
|
|
1303
|
+
program
|
|
1304
|
+
.command('context <task...>')
|
|
1305
|
+
.description('Build context for a task: relevant symbols, relationships, and code blocks')
|
|
1306
|
+
.option('-p, --path <path>', 'Project path')
|
|
1307
|
+
.option('-f, --format <format>', 'Output format: markdown or json', 'markdown')
|
|
1308
|
+
.option('-n, --max-nodes <number>', 'Maximum number of symbols to include')
|
|
1309
|
+
.option('--no-code', 'Omit code blocks (structure only)')
|
|
1310
|
+
.action(async (taskParts, options) => {
|
|
1311
|
+
const projectPath = resolveProjectPath(options.path);
|
|
1312
|
+
const format = options.format ?? 'markdown';
|
|
1313
|
+
if (format !== 'markdown' && format !== 'json') {
|
|
1314
|
+
error(`Unknown format "${options.format}" — use "markdown" or "json".`);
|
|
1315
|
+
process.exit(1);
|
|
1316
|
+
}
|
|
1317
|
+
let maxNodes;
|
|
1318
|
+
if (options.maxNodes !== undefined) {
|
|
1319
|
+
maxNodes = parseInt(options.maxNodes, 10);
|
|
1320
|
+
if (Number.isNaN(maxNodes) || maxNodes < 1) {
|
|
1321
|
+
error(`--max-nodes expects a positive integer, got "${options.maxNodes}".`);
|
|
1322
|
+
process.exit(1);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
try {
|
|
1326
|
+
if (!(0, directory_1.isInitialized)(projectPath)) {
|
|
1327
|
+
error(`LatticeSensor not initialized in ${projectPath}`);
|
|
1328
|
+
process.exit(1);
|
|
1329
|
+
}
|
|
1330
|
+
const { default: LatticeSensor } = await loadLatticeSensor();
|
|
1331
|
+
const cg = await LatticeSensor.open(projectPath);
|
|
1332
|
+
const result = await cg.buildContext(taskParts.join(' '), {
|
|
1333
|
+
format,
|
|
1334
|
+
includeCode: options.code !== false,
|
|
1335
|
+
...(maxNodes !== undefined ? { maxNodes } : {}),
|
|
1336
|
+
});
|
|
1337
|
+
// Both supported formats return a formatted string; print it verbatim so
|
|
1338
|
+
// `--format json` stays machine-parseable on stdout (error()/warnings go
|
|
1339
|
+
// to stderr only).
|
|
1340
|
+
console.log(typeof result === 'string' ? result : JSON.stringify(result, null, 2));
|
|
1341
|
+
cg.destroy();
|
|
1342
|
+
}
|
|
1343
|
+
catch (err) {
|
|
1344
|
+
error(`Context build failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1345
|
+
process.exit(1);
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1139
1348
|
/**
|
|
1140
1349
|
* lattice sensor prompt-hook (hidden)
|
|
1141
1350
|
*
|
|
@@ -1176,6 +1385,10 @@ function main() {
|
|
|
1176
1385
|
return;
|
|
1177
1386
|
}
|
|
1178
1387
|
const prompt = String(input.prompt || '');
|
|
1388
|
+
// System-injected task notifications are not user prompts: exit before
|
|
1389
|
+
// any project lookup or explore work (#1832).
|
|
1390
|
+
if ((0, directory_1.isTaskNotification)(prompt))
|
|
1391
|
+
return;
|
|
1179
1392
|
// Gate telemetry: how often each tier fires vs. no-ops — counter names
|
|
1180
1393
|
// only, NEVER prompt content (see TELEMETRY.md). This is the data that
|
|
1181
1394
|
// turns "is the gate any good" from vibes into a measured recall rate.
|
|
@@ -1240,8 +1453,11 @@ function main() {
|
|
|
1240
1453
|
const text = result.content[0]?.text ?? '';
|
|
1241
1454
|
if (!result.isError && text.trim()) {
|
|
1242
1455
|
// Cap the injection so a large-repo explore can't flood the prompt.
|
|
1243
|
-
|
|
1244
|
-
|
|
1456
|
+
// Claude Code shows hook stdout inline only up to 10,000 characters;
|
|
1457
|
+
// above that it persists the output to a file and the model sees a
|
|
1458
|
+
// 2 KB preview (#1694). PROMPT_HOOK_INJECTION_MAX (9,000) leaves
|
|
1459
|
+
// room for the wrapper and the projectPath nudge lines below.
|
|
1460
|
+
const body = (0, directory_1.capPromptHookInjection)(text);
|
|
1245
1461
|
// For a front-loaded SUB-project, a follow-up explore needs its path.
|
|
1246
1462
|
const more = plan.viaSubScan
|
|
1247
1463
|
? `call lattice_sensor_explore with projectPath: "${plan.exploreRoot}" for more`
|
|
@@ -1651,9 +1867,9 @@ function main() {
|
|
|
1651
1867
|
.aliases(['daemons'])
|
|
1652
1868
|
.description('Manage running LatticeSensor background daemons — pick one and press enter to stop it')
|
|
1653
1869
|
.action(async () => {
|
|
1654
|
-
const {
|
|
1870
|
+
const { listVerifiedDaemons, stopDaemonAt, stopAllDaemons } = await Promise.resolve().then(() => __importStar(require('../mcp/daemon-registry')));
|
|
1655
1871
|
const { runDaemonPicker } = await Promise.resolve().then(() => __importStar(require('../mcp/daemon-manager')));
|
|
1656
|
-
const daemons =
|
|
1872
|
+
const daemons = await listVerifiedDaemons();
|
|
1657
1873
|
if (daemons.length === 0) {
|
|
1658
1874
|
info('No LatticeSensor daemons running.');
|
|
1659
1875
|
return;
|
|
@@ -1680,7 +1896,7 @@ function main() {
|
|
|
1680
1896
|
const clack = await importESM('@clack/prompts');
|
|
1681
1897
|
clack.intro('LatticeSensor daemons');
|
|
1682
1898
|
await runDaemonPicker({
|
|
1683
|
-
list:
|
|
1899
|
+
list: listVerifiedDaemons,
|
|
1684
1900
|
stop: stopDaemonAt,
|
|
1685
1901
|
stopAll: stopAllDaemons,
|
|
1686
1902
|
cwdRoot,
|
|
@@ -1691,6 +1907,172 @@ function main() {
|
|
|
1691
1907
|
done: (m) => clack.outro(m),
|
|
1692
1908
|
});
|
|
1693
1909
|
});
|
|
1910
|
+
/**
|
|
1911
|
+
* Print the "no index here" guidance.
|
|
1912
|
+
*
|
|
1913
|
+
* The viewer READS an index; it never builds one — indexing stays the user's
|
|
1914
|
+
* decision, exactly as it is for the MCP tools. So a missing index is normal
|
|
1915
|
+
* input, not a failure to apologize for: say what is missing, say the one
|
|
1916
|
+
* command that fixes it, and never print a stack trace.
|
|
1917
|
+
*/
|
|
1918
|
+
function printNoIndexGuidance(projectPath) {
|
|
1919
|
+
error(`No LatticeSensor index found for ${projectPath}`);
|
|
1920
|
+
console.error('');
|
|
1921
|
+
// getGlyphs() (not a literal em dash): a legacy Windows console decodes raw
|
|
1922
|
+
// UTF-8 with its OEM codepage and renders one as mojibake (#168).
|
|
1923
|
+
console.error(` The viewer reads an index that already exists ${(0, glyphs_1.getGlyphs)().dash} it never creates one.`);
|
|
1924
|
+
console.error(' To index this project:');
|
|
1925
|
+
console.error('');
|
|
1926
|
+
console.error(` ${chalk.cyan('lattice sensor init')}`);
|
|
1927
|
+
console.error('');
|
|
1928
|
+
console.error(' Already indexed somewhere else? Point the viewer at it:');
|
|
1929
|
+
console.error('');
|
|
1930
|
+
console.error(` ${chalk.cyan('lattice sensor ui /path/to/indexed/project')}`);
|
|
1931
|
+
console.error('');
|
|
1932
|
+
}
|
|
1933
|
+
/**
|
|
1934
|
+
* lattice sensor ui [path] (alias: web)
|
|
1935
|
+
*
|
|
1936
|
+
* The browser reader: serves the built viewer (`dist/viewer/`) over loopback
|
|
1937
|
+
* and opens it. It opens the index for reading and never writes to it, never
|
|
1938
|
+
* indexes, and never changes a line of the project's code. The single thing it
|
|
1939
|
+
* writes is a trail the reader saved, as JSON under `.lattice/sensor/ui/trails/`;
|
|
1940
|
+
* `--read-only` turns even that off.
|
|
1941
|
+
*
|
|
1942
|
+
* Deliberately absent from TELEMETRY_FLUSH_COMMANDS above: the command's own
|
|
1943
|
+
* banner tells the user nothing leaves their machine, so it must not be the
|
|
1944
|
+
* thing that triggers a telemetry send. The usage count still buffers locally
|
|
1945
|
+
* like every other quick command.
|
|
1946
|
+
*/
|
|
1947
|
+
program
|
|
1948
|
+
.command('ui [path]', { hidden: !(0, viewer_gate_1.viewerEnabled)() })
|
|
1949
|
+
.alias('web')
|
|
1950
|
+
.description('Open the LatticeSensor viewer in your browser — read your indexed project as a graph')
|
|
1951
|
+
.option('--port <number>', `Port to listen on (default: ${constants_1.DEFAULT_UI_PORT}, or the next free one)`)
|
|
1952
|
+
.option('--no-open', 'Print the URL instead of opening a browser')
|
|
1953
|
+
.option('--read-only', 'Refuse every write — saved trails can be opened but not saved or deleted')
|
|
1954
|
+
.addHelpText('after', `
|
|
1955
|
+
Examples:
|
|
1956
|
+
$ lattice sensor ui Read the project you're standing in
|
|
1957
|
+
$ lattice sensor ui ~/code/my-app Read a specific indexed project
|
|
1958
|
+
$ lattice sensor ui --port 8080 Use one specific port (fails if it's taken)
|
|
1959
|
+
$ lattice sensor ui --no-open Just print the URL (headless boxes, SSH)
|
|
1960
|
+
$ lattice sensor web Same command under its alias
|
|
1961
|
+
|
|
1962
|
+
Pick a symbol and you see who calls it on the left, its source in the middle,
|
|
1963
|
+
and what it calls on the right at the height of the line that calls it. Search
|
|
1964
|
+
with / (or Cmd-K), click a file path for the file's outline and its imports.
|
|
1965
|
+
|
|
1966
|
+
Ask "how does execute reach getFile" (or "execute -> getFile") in the search
|
|
1967
|
+
box for the flow between two symbols: one card per hop, opened at the line that
|
|
1968
|
+
makes the next call, with dynamic-dispatch hops drawn dashed and named. The Map
|
|
1969
|
+
tab draws the whole project by module, with dependencies pointing down.
|
|
1970
|
+
|
|
1971
|
+
Never opened this codebase before? The Entry points tab lists the routes with
|
|
1972
|
+
the symbols that serve them, the files that run something when they load, the
|
|
1973
|
+
tests, and what the most code depends on — and starts a flow from any of them.
|
|
1974
|
+
|
|
1975
|
+
The page keeps up with the project while it is open: save a file and it says so
|
|
1976
|
+
within about a third of a second, and whatever is on screen re-reads the graph
|
|
1977
|
+
when something re-indexes it. It watches for that; it never polls.
|
|
1978
|
+
|
|
1979
|
+
Save a walk you want to keep: name the trail and it is written to
|
|
1980
|
+
.lattice/sensor/ui/trails/ (already gitignored) as plain JSON, listed on the empty
|
|
1981
|
+
screen, and reopened at the symbol you left. Hops are remembered by name rather
|
|
1982
|
+
than by position, so a saved trail survives re-indexing and says which hop moved
|
|
1983
|
+
when one does. Pass --read-only to refuse every write.
|
|
1984
|
+
|
|
1985
|
+
The viewer listens on 127.0.0.1 only, so nothing on your network can reach it.
|
|
1986
|
+
It opens an index that already exists, never indexes, and never changes a line
|
|
1987
|
+
of your code — the one thing it writes is a trail you asked it to save.
|
|
1988
|
+
Requests from any other host are refused, and nothing is sent anywhere: no code,
|
|
1989
|
+
no paths, no analytics.
|
|
1990
|
+
|
|
1991
|
+
Without --port it takes ${constants_1.DEFAULT_UI_PORT}, or the next free port if that one is busy.
|
|
1992
|
+
|
|
1993
|
+
Set ${constants_1.BROWSER_ENV}=<command> to choose which browser opens, or
|
|
1994
|
+
${constants_1.BROWSER_ENV}=none to never open one.
|
|
1995
|
+
`)
|
|
1996
|
+
.action(async (pathArg, options) => {
|
|
1997
|
+
// An explicit --port stays explicit: a scripted `--port 8080` that quietly
|
|
1998
|
+
// lands on 8081 is worse than one that says the port is busy. The default
|
|
1999
|
+
// port is the only one we're free to walk away from.
|
|
2000
|
+
let requestedPort;
|
|
2001
|
+
if (options.port !== undefined) {
|
|
2002
|
+
requestedPort = Number(options.port);
|
|
2003
|
+
if (!Number.isInteger(requestedPort) || requestedPort < 0 || requestedPort > 65535) {
|
|
2004
|
+
error(`--port must be a whole number between 0 and 65535 (got "${options.port}").`);
|
|
2005
|
+
process.exit(1);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
const projectPath = resolveProjectPath(pathArg);
|
|
2009
|
+
// Sensitive-directory refusal before anything opens: the same guard the MCP
|
|
2010
|
+
// entry points use, so `lattice sensor ui /etc` is turned away here rather than
|
|
2011
|
+
// becoming a browsable view of the system.
|
|
2012
|
+
const { validateProjectPath } = await Promise.resolve().then(() => __importStar(require('../utils')));
|
|
2013
|
+
const rootError = validateProjectPath(projectPath);
|
|
2014
|
+
if (rootError) {
|
|
2015
|
+
error(rootError);
|
|
2016
|
+
process.exit(1);
|
|
2017
|
+
}
|
|
2018
|
+
if (!(0, directory_1.isInitialized)(projectPath)) {
|
|
2019
|
+
printNoIndexGuidance(projectPath);
|
|
2020
|
+
process.exit(1);
|
|
2021
|
+
}
|
|
2022
|
+
const { startUiServer, openBrowser, createGraphApi, ViewerMissingError } = await Promise.resolve().then(() => __importStar(require('../ui-server')));
|
|
2023
|
+
// The JSON API the viewer reads its screens from. It opens the index lazily
|
|
2024
|
+
// on the first request, so a slow first paint is the only cost of mounting
|
|
2025
|
+
// it here rather than after the browser connects.
|
|
2026
|
+
const readOnly = options.readOnly === true;
|
|
2027
|
+
const api = createGraphApi({
|
|
2028
|
+
projectRoot: projectPath,
|
|
2029
|
+
readOnly,
|
|
2030
|
+
readOnlyReason: readOnly
|
|
2031
|
+
? 'This viewer was started with --read-only, so trails cannot be saved.'
|
|
2032
|
+
: undefined,
|
|
2033
|
+
});
|
|
2034
|
+
let handle;
|
|
2035
|
+
try {
|
|
2036
|
+
handle = await startUiServer({
|
|
2037
|
+
projectRoot: projectPath,
|
|
2038
|
+
port: requestedPort,
|
|
2039
|
+
portFallback: requestedPort === undefined,
|
|
2040
|
+
api: api.handler,
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
2043
|
+
catch (err) {
|
|
2044
|
+
api.close();
|
|
2045
|
+
// Both failure modes here (viewer assets missing, no port available) carry
|
|
2046
|
+
// their own remediation — print it plainly, never a stack trace.
|
|
2047
|
+
error(err instanceof ViewerMissingError || err instanceof Error ? err.message : String(err));
|
|
2048
|
+
process.exit(1);
|
|
2049
|
+
}
|
|
2050
|
+
console.log('');
|
|
2051
|
+
console.log(chalk.bold('LatticeSensor viewer'));
|
|
2052
|
+
console.log('');
|
|
2053
|
+
console.log(` ${chalk.dim('Reading')} ${projectPath}`);
|
|
2054
|
+
console.log(` ${chalk.dim('URL')} ${chalk.cyan(handle.url)}`);
|
|
2055
|
+
console.log(` ${chalk.dim('Access')} this machine only ${(0, glyphs_1.getGlyphs)().dash} ` +
|
|
2056
|
+
(readOnly
|
|
2057
|
+
? 'read-only, nothing leaves your computer'
|
|
2058
|
+
: 'nothing leaves your computer; saved trails are the only thing written'));
|
|
2059
|
+
console.log('');
|
|
2060
|
+
const opened = options.open === false ? false : openBrowser(handle.url);
|
|
2061
|
+
console.log(opened
|
|
2062
|
+
? chalk.dim(' Opening your browser... press Ctrl+C to stop.')
|
|
2063
|
+
: chalk.dim(' Open that URL in a browser. Press Ctrl+C to stop.'));
|
|
2064
|
+
console.log('');
|
|
2065
|
+
// The http server keeps the event loop alive on its own; these just make
|
|
2066
|
+
// Ctrl-C hang up live sockets instead of waiting on browser keep-alives.
|
|
2067
|
+
const shutdown = () => {
|
|
2068
|
+
// Release the SQLite handle before the socket: the process should never
|
|
2069
|
+
// exit with a live connection to the user's index.
|
|
2070
|
+
api.close();
|
|
2071
|
+
void handle.close().then(() => process.exit(0));
|
|
2072
|
+
};
|
|
2073
|
+
process.once('SIGINT', shutdown);
|
|
2074
|
+
process.once('SIGTERM', shutdown);
|
|
2075
|
+
});
|
|
1694
2076
|
/**
|
|
1695
2077
|
* lattice sensor serve
|
|
1696
2078
|
*/
|
|
@@ -1782,12 +2164,17 @@ function main() {
|
|
|
1782
2164
|
return;
|
|
1783
2165
|
}
|
|
1784
2166
|
const lockPath = path.join((0, directory_1.getLatticeSensorDir)(projectPath), 'sensor.lock');
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
2167
|
+
let removed = false;
|
|
2168
|
+
if (fs.existsSync(lockPath)) {
|
|
2169
|
+
fs.unlinkSync(lockPath);
|
|
2170
|
+
removed = true;
|
|
2171
|
+
}
|
|
2172
|
+
const { clearStaleDaemonArtifacts } = await Promise.resolve().then(() => __importStar(require('../mcp/daemon-registry')));
|
|
2173
|
+
removed = await clearStaleDaemonArtifacts(projectPath) || removed;
|
|
2174
|
+
if (removed)
|
|
2175
|
+
success('Removed stale lock artifacts. You can now run indexing again.');
|
|
2176
|
+
else
|
|
2177
|
+
info(`No stale lock files found ${(0, glyphs_1.getGlyphs)().dash} nothing to do`);
|
|
1791
2178
|
}
|
|
1792
2179
|
catch (err) {
|
|
1793
2180
|
error(`Failed to remove lock: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -1795,175 +2182,183 @@ function main() {
|
|
|
1795
2182
|
}
|
|
1796
2183
|
});
|
|
1797
2184
|
/**
|
|
1798
|
-
*
|
|
2185
|
+
* CLI parity with MCP callers/callees: resolve once, then collect and limit
|
|
2186
|
+
* within each definition. The legacy JSON list remains an explicitly labeled
|
|
2187
|
+
* union, with its original total/limit/truncated contract (#1674).
|
|
1799
2188
|
*
|
|
1800
|
-
*
|
|
1801
|
-
*
|
|
1802
|
-
*
|
|
2189
|
+
* Lattice contract on top (src/sensor-adapter.mjs, todo-structure-source-adapter,
|
|
2190
|
+
* seam-cost): `--exact-path` traverses exactly the definition of `symbol` in one
|
|
2191
|
+
* repo-relative file and reports `exactResolution`; every listed node carries
|
|
2192
|
+
* `edgeKind`/`valueRef`/`valueWrite` from the edges that connect it.
|
|
1803
2193
|
*/
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
if (matches.length === 0) {
|
|
1823
|
-
info(`Symbol "${symbol}" not found`);
|
|
1824
|
-
cg.destroy();
|
|
1825
|
-
return;
|
|
1826
|
-
}
|
|
1827
|
-
const seen = new Set();
|
|
1828
|
-
const allCallers = [];
|
|
1829
|
-
const strict = options.exactPath === undefined
|
|
1830
|
-
? null : (0, exact_traversal_1.selectExactTraversalCandidate)(matches, symbol, options.exactPath);
|
|
1831
|
-
const traversalMatches = strict === null
|
|
1832
|
-
? matches : strict.outcome === 'ready' ? [strict.candidate] : [];
|
|
1833
|
-
for (const match of traversalMatches) {
|
|
1834
|
-
const exactMatch = match.node.name === symbol || match.node.name.endsWith(`.${symbol}`) || match.node.name.endsWith(`::${symbol}`);
|
|
1835
|
-
if (strict === null && !exactMatch && matches.length > 1)
|
|
1836
|
-
continue;
|
|
1837
|
-
for (const c of cg.getCallers(match.node.id)) {
|
|
1838
|
-
if (!seen.has(c.node.id)) {
|
|
1839
|
-
seen.add(c.node.id);
|
|
1840
|
-
allCallers.push({ name: c.node.name, kind: c.node.kind, filePath: c.node.filePath, startLine: c.node.startLine, edgeKind: c.edge.kind, valueRef: c.edge.metadata?.valueRef === true, valueWrite: c.edge.metadata?.write === true });
|
|
1841
|
-
}
|
|
2194
|
+
for (const direction of ['callers', 'callees']) {
|
|
2195
|
+
const title = direction === 'callers' ? 'Callers' : 'Callees';
|
|
2196
|
+
program
|
|
2197
|
+
.command(`${direction} <symbol>`)
|
|
2198
|
+
.description(direction === 'callers'
|
|
2199
|
+
? 'Find all functions/methods that call a specific symbol'
|
|
2200
|
+
: 'Find all functions/methods called by a specific symbol')
|
|
2201
|
+
.option('-p, --path <path>', 'Project path')
|
|
2202
|
+
.option('-f, --file <path>', 'Narrow definitions by file path or suffix (no match: show all with a note)')
|
|
2203
|
+
.option('-l, --limit <number>', 'Maximum results per definition (also caps the JSON union)', '20')
|
|
2204
|
+
.option('--exact-path <repo-relative-path>', 'Traverse one exact symbol in this repo-relative file')
|
|
2205
|
+
.option('-j, --json', 'Output as JSON')
|
|
2206
|
+
.action(async (symbol, options) => {
|
|
2207
|
+
const projectPath = resolveProjectPath(options.path);
|
|
2208
|
+
try {
|
|
2209
|
+
if (!(0, directory_1.isInitialized)(projectPath)) {
|
|
2210
|
+
error(`LatticeSensor not initialized in ${projectPath}`);
|
|
2211
|
+
process.exit(1);
|
|
1842
2212
|
}
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
2213
|
+
const { default: LatticeSensor } = await loadLatticeSensor();
|
|
2214
|
+
const cg = await LatticeSensor.open(projectPath);
|
|
2215
|
+
try {
|
|
2216
|
+
const limit = parseInt(options.limit || '20', 10);
|
|
2217
|
+
const { nodes: targets } = (0, symbol_lookup_1.lookupSymbolNodes)(cg, symbol);
|
|
2218
|
+
if (targets.length === 0) {
|
|
2219
|
+
info(formatSymbolNotFound(symbol, cg.searchNodes(symbol, { limit: 5 }).map((m) => m.node.name)));
|
|
2220
|
+
return;
|
|
1850
2221
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
else {
|
|
1865
|
-
console.log(chalk.bold(`\nCallers of "${symbol}" (${limited.length}):\n`));
|
|
1866
|
-
for (const node of limited) {
|
|
1867
|
-
const loc = node.startLine ? `:${node.startLine}` : '';
|
|
1868
|
-
console.log(chalk.cyan(node.kind.padEnd(12)) +
|
|
1869
|
-
chalk.white(node.name));
|
|
1870
|
-
console.log(chalk.dim(` ${node.filePath}${loc}`));
|
|
1871
|
-
console.log();
|
|
1872
|
-
}
|
|
1873
|
-
}
|
|
1874
|
-
cg.destroy();
|
|
1875
|
-
}
|
|
1876
|
-
catch (err) {
|
|
1877
|
-
error(`callers failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1878
|
-
process.exit(1);
|
|
1879
|
-
}
|
|
1880
|
-
});
|
|
1881
|
-
/**
|
|
1882
|
-
* lattice sensor callees <symbol>
|
|
1883
|
-
*/
|
|
1884
|
-
program
|
|
1885
|
-
.command('callees <symbol>')
|
|
1886
|
-
.description('Find all functions/methods that a specific symbol calls')
|
|
1887
|
-
.option('-p, --path <path>', 'Project path')
|
|
1888
|
-
.option('-l, --limit <number>', 'Maximum results', '20')
|
|
1889
|
-
.option('--exact-path <repo-relative-path>', 'Traverse one exact symbol in this repo-relative file')
|
|
1890
|
-
.option('-j, --json', 'Output as JSON')
|
|
1891
|
-
.action(async (symbol, options) => {
|
|
1892
|
-
const projectPath = resolveProjectPath(options.path);
|
|
1893
|
-
try {
|
|
1894
|
-
if (!(0, directory_1.isInitialized)(projectPath)) {
|
|
1895
|
-
error(`LatticeSensor not initialized in ${projectPath}`);
|
|
1896
|
-
process.exit(1);
|
|
1897
|
-
}
|
|
1898
|
-
const { default: LatticeSensor } = await loadLatticeSensor();
|
|
1899
|
-
const cg = await LatticeSensor.open(projectPath);
|
|
1900
|
-
const limit = parseInt(options.limit || '20', 10);
|
|
1901
|
-
const matches = cg.searchNodes(symbol, { limit: 50 });
|
|
1902
|
-
if (matches.length === 0) {
|
|
1903
|
-
info(`Symbol "${symbol}" not found`);
|
|
1904
|
-
cg.destroy();
|
|
1905
|
-
return;
|
|
1906
|
-
}
|
|
1907
|
-
const seen = new Set();
|
|
1908
|
-
const allCallees = [];
|
|
1909
|
-
const strict = options.exactPath === undefined
|
|
1910
|
-
? null : (0, exact_traversal_1.selectExactTraversalCandidate)(matches, symbol, options.exactPath);
|
|
1911
|
-
const traversalMatches = strict === null
|
|
1912
|
-
? matches : strict.outcome === 'ready' ? [strict.candidate] : [];
|
|
1913
|
-
for (const match of traversalMatches) {
|
|
1914
|
-
const exactMatch = match.node.name === symbol || match.node.name.endsWith(`.${symbol}`) || match.node.name.endsWith(`::${symbol}`);
|
|
1915
|
-
if (strict === null && !exactMatch && matches.length > 1)
|
|
1916
|
-
continue;
|
|
1917
|
-
for (const c of cg.getCallees(match.node.id)) {
|
|
1918
|
-
if (!seen.has(c.node.id)) {
|
|
1919
|
-
seen.add(c.node.id);
|
|
1920
|
-
allCallees.push({ name: c.node.name, kind: c.node.kind, filePath: c.node.filePath, startLine: c.node.startLine, edgeKind: c.edge.kind, valueRef: c.edge.metadata?.valueRef === true, valueWrite: c.edge.metadata?.write === true });
|
|
2222
|
+
const strict = options.exactPath === undefined
|
|
2223
|
+
? null : (0, exact_traversal_1.selectExactTraversalCandidate)(targets.map((node) => ({ node })), symbol, options.exactPath);
|
|
2224
|
+
if (strict !== null && strict.outcome !== 'ready') {
|
|
2225
|
+
if (options.json) {
|
|
2226
|
+
console.log(JSON.stringify({
|
|
2227
|
+
symbol, exactPath: options.exactPath, exactResolution: strict.outcome,
|
|
2228
|
+
[direction]: [], total: 0, limit, truncated: false,
|
|
2229
|
+
}, null, 2));
|
|
2230
|
+
}
|
|
2231
|
+
else {
|
|
2232
|
+
info(`No single definition of "${symbol}" in ${options.exactPath} (${strict.outcome})`);
|
|
2233
|
+
}
|
|
2234
|
+
return;
|
|
1921
2235
|
}
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
2236
|
+
const exact = strict === null
|
|
2237
|
+
? {} : { exactPath: options.exactPath, exactResolution: strict.outcome };
|
|
2238
|
+
const { groups, filteredOut } = (0, symbol_lookup_1.groupDefinitions)(strict === null ? targets : [strict.candidate.node], options.file);
|
|
2239
|
+
const ambiguous = groups.length > 1;
|
|
2240
|
+
const note = filteredOut
|
|
2241
|
+
? `no definition of "${symbol}" matches file "${options.file}" — showing all definitions instead.`
|
|
2242
|
+
: undefined;
|
|
2243
|
+
const collected = groups.map((group) => {
|
|
2244
|
+
const nodes = new Map();
|
|
2245
|
+
const edges = new Map();
|
|
2246
|
+
for (const target of group) {
|
|
2247
|
+
const connections = direction === 'callers' ? cg.getCallers(target.id) : cg.getCallees(target.id);
|
|
2248
|
+
for (const { node, edge } of connections) {
|
|
2249
|
+
nodes.set(node.id, node);
|
|
2250
|
+
edges.set(`${edge.source}->${edge.target}:${edge.kind}`, edge);
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
return { group, nodes: [...nodes.values()], edges: [...edges.values()] };
|
|
2254
|
+
});
|
|
2255
|
+
const relationships = (node, edges) => [...new Set(edges
|
|
2256
|
+
.filter((edge) => (direction === 'callers' ? edge.source : edge.target) === node.id)
|
|
2257
|
+
.map((edge) => edge.kind))];
|
|
2258
|
+
// Lattice: the edge facts behind each listed node. A value write on ANY
|
|
2259
|
+
// connecting edge counts — dropping one would hide a writer from seam cost.
|
|
2260
|
+
const edgeFacts = (node, edges) => {
|
|
2261
|
+
const own = edges.filter((edge) => (direction === 'callers' ? edge.source : edge.target) === node.id);
|
|
2262
|
+
return {
|
|
2263
|
+
edgeKind: own[0]?.kind ?? 'calls',
|
|
2264
|
+
valueRef: own.some((edge) => edge.metadata?.valueRef === true),
|
|
2265
|
+
valueWrite: own.some((edge) => edge.metadata?.valueWrite === true),
|
|
2266
|
+
};
|
|
2267
|
+
};
|
|
2268
|
+
if (options.json) {
|
|
2269
|
+
const definitions = collected.map(({ group, nodes, edges }) => {
|
|
2270
|
+
const limited = nodes.slice(0, limit);
|
|
2271
|
+
const shown = new Set(limited.map((node) => node.id));
|
|
2272
|
+
return {
|
|
2273
|
+
...cliDefinition(group),
|
|
2274
|
+
[direction]: limited.map((node) => ({ id: node.id, ...cliNode(node),
|
|
2275
|
+
relationships: relationships(node, edges), ...edgeFacts(node, edges) })),
|
|
2276
|
+
edges: edges.filter((edge) => shown.has(direction === 'callers' ? edge.source : edge.target)),
|
|
2277
|
+
total: nodes.length,
|
|
2278
|
+
limit,
|
|
2279
|
+
truncated: nodes.length > limit,
|
|
2280
|
+
};
|
|
2281
|
+
});
|
|
2282
|
+
const union = new Map();
|
|
2283
|
+
for (const { nodes } of collected) {
|
|
2284
|
+
for (const node of nodes)
|
|
2285
|
+
union.set(node.id, node);
|
|
2286
|
+
}
|
|
2287
|
+
const total = union.size;
|
|
2288
|
+
console.log(JSON.stringify({
|
|
2289
|
+
symbol,
|
|
2290
|
+
...exact,
|
|
2291
|
+
targets: groups.flat().map((node) => cliDefinition([node]).definition),
|
|
2292
|
+
ambiguous,
|
|
2293
|
+
aggregation: ambiguous ? 'union' : 'definition',
|
|
2294
|
+
file: options.file,
|
|
2295
|
+
filteredOut,
|
|
2296
|
+
note,
|
|
2297
|
+
definitions,
|
|
2298
|
+
[direction]: [...union.values()].slice(0, limit).map((node) => {
|
|
2299
|
+
const all = collected.flatMap((entry) => entry.edges);
|
|
2300
|
+
return { ...cliNode(node), relationships: relationships(node, all), ...edgeFacts(node, all) };
|
|
2301
|
+
}),
|
|
2302
|
+
total,
|
|
2303
|
+
limit,
|
|
2304
|
+
truncated: total > limit,
|
|
2305
|
+
}, null, 2));
|
|
2306
|
+
}
|
|
2307
|
+
else {
|
|
2308
|
+
if (note)
|
|
2309
|
+
warn(note);
|
|
2310
|
+
if (ambiguous) {
|
|
2311
|
+
console.log(chalk.bold(`\n${title} of "${symbol}" — ${groups.length} distinct definitions (narrow with --file):`));
|
|
2312
|
+
}
|
|
2313
|
+
for (const { group, nodes, edges } of collected) {
|
|
2314
|
+
const limited = nodes.slice(0, limit);
|
|
2315
|
+
const total = nodes.length;
|
|
2316
|
+
const truncated = total > limit;
|
|
2317
|
+
const count = truncated ? `${limited.length} of ${total}` : String(total);
|
|
2318
|
+
if (ambiguous) {
|
|
2319
|
+
console.log(chalk.bold(`\n${(0, symbol_lookup_1.describeSymbolNode)(group[0])} (${count}):\n`));
|
|
2320
|
+
}
|
|
2321
|
+
else {
|
|
2322
|
+
console.log(chalk.bold(`\n${title} of "${symbol}" (${count}):\n`));
|
|
2323
|
+
console.log(chalk.dim((0, symbol_lookup_1.describeSymbolNode)(group[0])));
|
|
2324
|
+
}
|
|
2325
|
+
if (total === 0) {
|
|
2326
|
+
if (ambiguous)
|
|
2327
|
+
console.log(chalk.dim(` (no ${direction})`));
|
|
2328
|
+
else
|
|
2329
|
+
info(`No ${direction} found for "${symbol}"`);
|
|
2330
|
+
}
|
|
2331
|
+
for (const node of limited) {
|
|
2332
|
+
const loc = node.startLine ? `:${node.startLine}` : '';
|
|
2333
|
+
const kinds = relationships(node, edges).filter((kind) => kind !== 'calls');
|
|
2334
|
+
const relation = kinds.length ? ` [${kinds.join(', ')}]` : '';
|
|
2335
|
+
console.log(chalk.cyan(node.kind.padEnd(12)) + chalk.white(node.name) + chalk.dim(relation));
|
|
2336
|
+
console.log(chalk.dim(` ${node.filePath}${loc}`));
|
|
2337
|
+
console.log();
|
|
2338
|
+
}
|
|
2339
|
+
if (truncated)
|
|
2340
|
+
console.log(chalk.dim(`Showing ${limited.length} of ${total}; pass --limit to widen.`));
|
|
2341
|
+
}
|
|
1929
2342
|
}
|
|
1930
2343
|
}
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
if (options.json) {
|
|
1934
|
-
console.log(JSON.stringify({
|
|
1935
|
-
symbol,
|
|
1936
|
-
...(strict === null ? {} : { exactPath: options.exactPath, exactResolution: strict.outcome }),
|
|
1937
|
-
callees: limited,
|
|
1938
|
-
}, null, 2));
|
|
1939
|
-
}
|
|
1940
|
-
else if (limited.length === 0) {
|
|
1941
|
-
info(`No callees found for "${symbol}"`);
|
|
1942
|
-
}
|
|
1943
|
-
else {
|
|
1944
|
-
console.log(chalk.bold(`\nCallees of "${symbol}" (${limited.length}):\n`));
|
|
1945
|
-
for (const node of limited) {
|
|
1946
|
-
const loc = node.startLine ? `:${node.startLine}` : '';
|
|
1947
|
-
console.log(chalk.cyan(node.kind.padEnd(12)) +
|
|
1948
|
-
chalk.white(node.name));
|
|
1949
|
-
console.log(chalk.dim(` ${node.filePath}${loc}`));
|
|
1950
|
-
console.log();
|
|
2344
|
+
finally {
|
|
2345
|
+
cg.destroy();
|
|
1951
2346
|
}
|
|
1952
2347
|
}
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
});
|
|
2348
|
+
catch (err) {
|
|
2349
|
+
error(`${direction} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2350
|
+
process.exit(1);
|
|
2351
|
+
}
|
|
2352
|
+
});
|
|
2353
|
+
}
|
|
1960
2354
|
/**
|
|
1961
|
-
* lattice sensor impact <symbol>
|
|
2355
|
+
* lattice sensor impact <symbol> — one blast radius per distinct definition.
|
|
1962
2356
|
*/
|
|
1963
2357
|
program
|
|
1964
2358
|
.command('impact <symbol>')
|
|
1965
2359
|
.description('Analyze what code is affected by changing a symbol')
|
|
1966
2360
|
.option('-p, --path <path>', 'Project path')
|
|
2361
|
+
.option('-f, --file <path>', 'Narrow definitions by file path or suffix (no match: show all with a note)')
|
|
1967
2362
|
.option('-d, --depth <number>', 'Traversal depth', '2')
|
|
1968
2363
|
.option('-j, --json', 'Output as JSON')
|
|
1969
2364
|
.action(async (symbol, options) => {
|
|
@@ -1975,72 +2370,95 @@ function main() {
|
|
|
1975
2370
|
}
|
|
1976
2371
|
const { default: LatticeSensor } = await loadLatticeSensor();
|
|
1977
2372
|
const cg = await LatticeSensor.open(projectPath);
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
}
|
|
1985
|
-
// Merge impact subgraphs across all exact-matching symbols
|
|
1986
|
-
const mergedNodes = new Map();
|
|
1987
|
-
const seenEdges = new Set();
|
|
1988
|
-
let edgeCount = 0;
|
|
1989
|
-
for (const match of matches) {
|
|
1990
|
-
const exactMatch = match.node.name === symbol || match.node.name.endsWith(`.${symbol}`) || match.node.name.endsWith(`::${symbol}`);
|
|
1991
|
-
if (!exactMatch && matches.length > 1)
|
|
1992
|
-
continue;
|
|
1993
|
-
const impact = cg.getImpactRadius(match.node.id, depth);
|
|
1994
|
-
for (const [id, n] of impact.nodes) {
|
|
1995
|
-
mergedNodes.set(id, { name: n.name, kind: n.kind, filePath: n.filePath, startLine: n.startLine });
|
|
2373
|
+
try {
|
|
2374
|
+
const depth = Math.min(Math.max(parseInt(options.depth || '2', 10), 1), 10);
|
|
2375
|
+
const { nodes: targets } = (0, symbol_lookup_1.lookupSymbolNodes)(cg, symbol);
|
|
2376
|
+
if (targets.length === 0) {
|
|
2377
|
+
info(formatSymbolNotFound(symbol, cg.searchNodes(symbol, { limit: 5 }).map((m) => m.node.name)));
|
|
2378
|
+
return;
|
|
1996
2379
|
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2380
|
+
const { groups, filteredOut } = (0, symbol_lookup_1.groupDefinitions)(targets, options.file);
|
|
2381
|
+
const ambiguous = groups.length > 1;
|
|
2382
|
+
const note = filteredOut
|
|
2383
|
+
? `no definition of "${symbol}" matches file "${options.file}" — showing all definitions instead.`
|
|
2384
|
+
: undefined;
|
|
2385
|
+
const collected = groups.map((group) => {
|
|
2386
|
+
const nodes = new Map();
|
|
2387
|
+
const edges = new Map();
|
|
2388
|
+
for (const target of group) {
|
|
2389
|
+
const impact = cg.getImpactRadius(target.id, depth);
|
|
2390
|
+
for (const [id, node] of impact.nodes)
|
|
2391
|
+
nodes.set(id, node);
|
|
2392
|
+
for (const edge of impact.edges)
|
|
2393
|
+
edges.set(`${edge.source}->${edge.target}:${edge.kind}`, edge);
|
|
2002
2394
|
}
|
|
2395
|
+
return { group, nodes, edges };
|
|
2396
|
+
});
|
|
2397
|
+
if (options.json) {
|
|
2398
|
+
const unionNodes = new Map();
|
|
2399
|
+
const unionEdges = new Map();
|
|
2400
|
+
const definitions = collected.map(({ group, nodes, edges }) => {
|
|
2401
|
+
for (const [id, node] of nodes)
|
|
2402
|
+
unionNodes.set(id, node);
|
|
2403
|
+
for (const [key, edge] of edges)
|
|
2404
|
+
unionEdges.set(key, edge);
|
|
2405
|
+
return {
|
|
2406
|
+
...cliDefinition(group),
|
|
2407
|
+
nodeCount: nodes.size,
|
|
2408
|
+
edgeCount: edges.size,
|
|
2409
|
+
affected: [...nodes.values()].map((node) => ({ id: node.id, ...cliNode(node) })),
|
|
2410
|
+
edges: [...edges.values()],
|
|
2411
|
+
};
|
|
2412
|
+
});
|
|
2413
|
+
console.log(JSON.stringify({
|
|
2414
|
+
symbol,
|
|
2415
|
+
depth,
|
|
2416
|
+
targets: groups.flat().map((node) => cliDefinition([node]).definition),
|
|
2417
|
+
ambiguous,
|
|
2418
|
+
aggregation: ambiguous ? 'union' : 'definition',
|
|
2419
|
+
file: options.file,
|
|
2420
|
+
filteredOut,
|
|
2421
|
+
note,
|
|
2422
|
+
definitions,
|
|
2423
|
+
nodeCount: unionNodes.size,
|
|
2424
|
+
edgeCount: unionEdges.size,
|
|
2425
|
+
affected: [...unionNodes.values()].map(cliNode),
|
|
2426
|
+
}, null, 2));
|
|
2003
2427
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
byFile.set(node.filePath, list);
|
|
2033
|
-
}
|
|
2034
|
-
for (const [file, nodes] of byFile) {
|
|
2035
|
-
console.log(chalk.cyan(file));
|
|
2036
|
-
for (const node of nodes) {
|
|
2037
|
-
const loc = node.startLine ? `:${node.startLine}` : '';
|
|
2038
|
-
console.log(` ${chalk.dim(node.kind.padEnd(12))}${node.name}${chalk.dim(loc)}`);
|
|
2428
|
+
else {
|
|
2429
|
+
if (note)
|
|
2430
|
+
warn(note);
|
|
2431
|
+
if (ambiguous) {
|
|
2432
|
+
console.log(chalk.bold(`\nImpact of changing "${symbol}" — ${groups.length} distinct definitions (each with its own blast radius; narrow with --file):`));
|
|
2433
|
+
}
|
|
2434
|
+
for (const { group, nodes } of collected) {
|
|
2435
|
+
if (ambiguous) {
|
|
2436
|
+
console.log(chalk.bold(`\n${(0, symbol_lookup_1.describeSymbolNode)(group[0])} — ${nodes.size} affected symbols:\n`));
|
|
2437
|
+
}
|
|
2438
|
+
else {
|
|
2439
|
+
console.log(chalk.bold(`\nImpact of changing "${symbol}" — ${nodes.size} affected symbols:\n`));
|
|
2440
|
+
console.log(chalk.dim((0, symbol_lookup_1.describeSymbolNode)(group[0])));
|
|
2441
|
+
}
|
|
2442
|
+
const byFile = new Map();
|
|
2443
|
+
for (const node of nodes.values()) {
|
|
2444
|
+
const list = byFile.get(node.filePath) || [];
|
|
2445
|
+
list.push(node);
|
|
2446
|
+
byFile.set(node.filePath, list);
|
|
2447
|
+
}
|
|
2448
|
+
for (const [file, affected] of byFile) {
|
|
2449
|
+
console.log(chalk.cyan(file));
|
|
2450
|
+
for (const node of affected) {
|
|
2451
|
+
const loc = node.startLine ? `:${node.startLine}` : '';
|
|
2452
|
+
console.log(` ${chalk.dim(node.kind.padEnd(12))}${node.name}${chalk.dim(loc)}`);
|
|
2453
|
+
}
|
|
2454
|
+
console.log();
|
|
2455
|
+
}
|
|
2039
2456
|
}
|
|
2040
|
-
console.log();
|
|
2041
2457
|
}
|
|
2042
2458
|
}
|
|
2043
|
-
|
|
2459
|
+
finally {
|
|
2460
|
+
cg.destroy();
|
|
2461
|
+
}
|
|
2044
2462
|
}
|
|
2045
2463
|
catch (err) {
|
|
2046
2464
|
error(`impact failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -2106,6 +2524,11 @@ function main() {
|
|
|
2106
2524
|
.replace(/\*/g, '[^/]*');
|
|
2107
2525
|
customFilter = new RegExp(regex);
|
|
2108
2526
|
}
|
|
2527
|
+
// One notion of "a test" for the whole tool (#1507): the CLI used to keep
|
|
2528
|
+
// its own six regexes here, which knew `.test.` and `/tests/` but not Go's
|
|
2529
|
+
// `_test.go`, Python's `test_x.py` or the JVM's `FooTest.kt` — so
|
|
2530
|
+
// `affected` reported "no tests" for whole ecosystems while `search` and
|
|
2531
|
+
// the MCP tools counted those very files as tests.
|
|
2109
2532
|
function matchesTestFile(filePath) {
|
|
2110
2533
|
if (customFilter)
|
|
2111
2534
|
return customFilter.test(filePath);
|