@quolu/lattice 0.69.5 → 0.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +5 -1
- 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/cli-help.mjs +4 -2
- package/src/sensor-adapter.mjs +5 -1
- package/src/todo-cli.mjs +88 -11
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* addon) with a per-platform strategy chosen to keep the open-descriptor /
|
|
10
10
|
* kernel-watch cost BOUNDED rather than growing with the number of files:
|
|
11
11
|
*
|
|
12
|
-
* - macOS / Windows: a
|
|
12
|
+
* - macOS / Windows: a recursive `fs.watch(root, {recursive:true})`, plus
|
|
13
|
+
* bounded supplemental streams for directory symlinks (#770).
|
|
13
14
|
* libuv maps this to one FSEvents stream (macOS) / one
|
|
14
15
|
* ReadDirectoryChangesW handle (Windows), so it costs O(1) descriptors no
|
|
15
16
|
* matter how large the tree. This is the fix for the macOS file-table
|
|
@@ -25,11 +26,12 @@
|
|
|
25
26
|
* per-file watches are never needed.
|
|
26
27
|
*
|
|
27
28
|
* Excluded trees (node_modules/, dist/, .git/, …) are filtered via the
|
|
28
|
-
* indexer's `buildScopeIgnore` (built-in
|
|
29
|
-
*
|
|
30
|
-
*
|
|
29
|
+
* indexer's `buildScopeIgnore` (built-in defaults + root `.gitignore` +
|
|
30
|
+
* `.git/info/exclude` + `core.excludesFile` + git ignored-untracked dirs) —
|
|
31
|
+
* on Linux they're never descended into (so they cost no watch), and on
|
|
32
|
+
* macOS/Windows the single recursive stream still covers them but their
|
|
31
33
|
* events are dropped before any sync is scheduled. Either way the watcher's
|
|
32
|
-
* scope matches
|
|
34
|
+
* scope matches `git ls-files --exclude-standard` (#276 / #407 / #1728).
|
|
33
35
|
*/
|
|
34
36
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
35
37
|
if (k2 === undefined) k2 = k;
|
|
@@ -82,6 +84,8 @@ const watch_policy_1 = require("./watch-policy");
|
|
|
82
84
|
* few cycles) stays under this; a long-lived external writer crosses it.
|
|
83
85
|
*/
|
|
84
86
|
const MAX_LOCK_RETRIES = 5;
|
|
87
|
+
/** A failed re-arm must not turn frequent MCP calls into a lock-polling loop. */
|
|
88
|
+
const LOCK_REARM_COOLDOWN_MS = 30_000;
|
|
85
89
|
/**
|
|
86
90
|
* Number of consecutive GENERIC (non-lock) sync failures the watcher tolerates
|
|
87
91
|
* before it degrades auto-sync. A deterministic failure — a tree-sitter
|
|
@@ -205,8 +209,8 @@ exports.LockUnavailableError = LockUnavailableError;
|
|
|
205
209
|
* debounced sync operations via a provided callback.
|
|
206
210
|
*
|
|
207
211
|
* Design goals:
|
|
208
|
-
* - Bounded resource usage:
|
|
209
|
-
*
|
|
212
|
+
* - Bounded resource usage: one recursive stream plus capped symlink streams
|
|
213
|
+
* on macOS/Windows, O(directories) inotify watches on Linux — never O(files), which
|
|
210
214
|
* was the system-crashing fd leak on macOS (#644/#496/#555/#628).
|
|
211
215
|
* - Debounced to avoid thrashing on rapid saves
|
|
212
216
|
* - Filters to supported source files by extension
|
|
@@ -217,7 +221,7 @@ exports.LockUnavailableError = LockUnavailableError;
|
|
|
217
221
|
class FileWatcher {
|
|
218
222
|
/** macOS/Windows: the single recursive watcher. Null on Linux. */
|
|
219
223
|
recursiveWatcher = null;
|
|
220
|
-
/** Linux
|
|
224
|
+
/** Linux directory watches / macOS and Windows supplemental symlink streams. */
|
|
221
225
|
dirWatchers = new Map();
|
|
222
226
|
/** Set once the per-directory watch cap is hit, so we log only once. */
|
|
223
227
|
dirCapWarned = false;
|
|
@@ -230,18 +234,31 @@ class FileWatcher {
|
|
|
230
234
|
*/
|
|
231
235
|
inotifyLimitWarned = false;
|
|
232
236
|
/**
|
|
233
|
-
*
|
|
237
|
+
* The reason live watching was disabled at runtime
|
|
234
238
|
* (watch-resource exhaustion, lock contention past the retry budget, or a
|
|
235
239
|
* persistent generic sync failure past the retry budget), or null while
|
|
236
|
-
* healthy. Set by {@link degrade};
|
|
240
|
+
* healthy. Set by {@link degrade}; a lock-contention recovery keeps it until
|
|
241
|
+
* a full reconciliation succeeds.
|
|
237
242
|
*/
|
|
238
243
|
degradedReason = null;
|
|
244
|
+
degradedByLock = false;
|
|
245
|
+
recoveringFromLock = false;
|
|
246
|
+
lastLockRearmMs = 0;
|
|
239
247
|
/** Consecutive lock-contention retries for watcher-triggered syncs. */
|
|
240
248
|
lockRetryCount = 0;
|
|
241
249
|
/** Consecutive generic (non-lock) sync failures; reset only by a clean sync. */
|
|
242
250
|
syncFailureRetryCount = 0;
|
|
243
251
|
/** Test-only inert mode: started, but with no OS watcher installed. */
|
|
244
252
|
inert = false;
|
|
253
|
+
/**
|
|
254
|
+
* Resolved realpath of directories already watched (or skipped). Prevents
|
|
255
|
+
* infinite recursion via symlink cycles — mirrors the same guard used in
|
|
256
|
+
* the indexer's `walk()` (extraction/index.ts).
|
|
257
|
+
*/
|
|
258
|
+
visitedRealDirs = new Set();
|
|
259
|
+
knownDirs = new Map();
|
|
260
|
+
watchedRealDirs = new Map();
|
|
261
|
+
treeRefreshTimer = null;
|
|
245
262
|
debounceTimer = null;
|
|
246
263
|
/**
|
|
247
264
|
* True when the pending set does NOT exactly describe the change (a
|
|
@@ -282,11 +299,15 @@ class FileWatcher {
|
|
|
282
299
|
* deterministically gate on watcher readiness.
|
|
283
300
|
*/
|
|
284
301
|
readyWaiters = [];
|
|
285
|
-
// The shared scope matcher (built-in defaults +
|
|
286
|
-
//
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
//
|
|
302
|
+
// The shared scope matcher from `buildScopeIgnore` (built-in defaults +
|
|
303
|
+
// root `.gitignore` + `.git/info/exclude` + `core.excludesFile` + dirs
|
|
304
|
+
// `git ls-files --exclude-standard` reports ignored + `lattice-sensor.json`
|
|
305
|
+
// exclude/include, with embedded child repos matched by their OWN rules —
|
|
306
|
+
// #514), built at start() and REBUILT whenever one of the files it is
|
|
307
|
+
// derived from changes (see `refreshScope`, #1590). Same construction the
|
|
308
|
+
// indexer uses for scoped sync, so watcher scope cannot diverge from index
|
|
309
|
+
// scope (#1728). An embedded repo created after start() joins the scope on
|
|
310
|
+
// the next scope refresh / watcher restart / re-index.
|
|
290
311
|
ignoreMatcher = null;
|
|
291
312
|
projectRoot;
|
|
292
313
|
debounceMs;
|
|
@@ -295,7 +316,14 @@ class FileWatcher {
|
|
|
295
316
|
onSyncError;
|
|
296
317
|
onDegraded;
|
|
297
318
|
inertForTests;
|
|
298
|
-
|
|
319
|
+
/**
|
|
320
|
+
* Optional metadata guard supplied by the LatticeSensor facade. Windows'
|
|
321
|
+
* ReadDirectoryChangesW stream includes last-access updates, so a read can
|
|
322
|
+
* otherwise look exactly like an edit. Returning true means the file's
|
|
323
|
+
* current size/mtime still match the indexed record and the event is noise.
|
|
324
|
+
*/
|
|
325
|
+
isFileStateCurrent;
|
|
326
|
+
constructor(projectRoot, syncFn, options = {}, isFileStateCurrent) {
|
|
299
327
|
this.projectRoot = projectRoot;
|
|
300
328
|
this.syncFn = syncFn;
|
|
301
329
|
this.debounceMs = options.debounceMs ?? 2000;
|
|
@@ -303,6 +331,7 @@ class FileWatcher {
|
|
|
303
331
|
this.onSyncError = options.onSyncError;
|
|
304
332
|
this.onDegraded = options.onDegraded;
|
|
305
333
|
this.inertForTests = options.inertForTests ?? false;
|
|
334
|
+
this.isFileStateCurrent = isFileStateCurrent;
|
|
306
335
|
}
|
|
307
336
|
/**
|
|
308
337
|
* Start watching for file changes.
|
|
@@ -313,8 +342,11 @@ class FileWatcher {
|
|
|
313
342
|
return true; // Already watching
|
|
314
343
|
this.stopped = false;
|
|
315
344
|
this.degradedReason = null;
|
|
345
|
+
this.degradedByLock = false;
|
|
346
|
+
this.recoveringFromLock = false;
|
|
316
347
|
this.lockRetryCount = 0;
|
|
317
348
|
this.syncFailureRetryCount = 0;
|
|
349
|
+
this.needsFullScan = false;
|
|
318
350
|
// Some environments make filesystem watching unusable — most notably
|
|
319
351
|
// WSL2 /mnt/ drives, where the underlying fs.watch calls block long
|
|
320
352
|
// enough to break MCP startup handshakes (issue #199). Skip watching
|
|
@@ -335,10 +367,10 @@ class FileWatcher {
|
|
|
335
367
|
this.startRecursive();
|
|
336
368
|
}
|
|
337
369
|
else {
|
|
338
|
-
this.
|
|
370
|
+
this.refreshWatchTree();
|
|
339
371
|
}
|
|
340
372
|
// The per-directory (Linux) path catches watch-resource exhaustion inside
|
|
341
|
-
//
|
|
373
|
+
// watchDirectory and degrades synchronously rather than throwing, so it never
|
|
342
374
|
// reaches the catch below. Surface that as a failed start here so both
|
|
343
375
|
// strategies report exhaustion identically (start() === false).
|
|
344
376
|
if (this.degradedReason)
|
|
@@ -377,16 +409,12 @@ class FileWatcher {
|
|
|
377
409
|
}
|
|
378
410
|
}
|
|
379
411
|
/**
|
|
380
|
-
* macOS/Windows: one
|
|
412
|
+
* macOS/Windows: one root stream, supplemented for directory symlinks.
|
|
381
413
|
* `filename` arrives relative to the project root (with subdirectories), so
|
|
382
414
|
* it maps straight to a project-relative path.
|
|
383
415
|
*/
|
|
384
416
|
startRecursive() {
|
|
385
|
-
this.recursiveWatcher = watchImpl(this.projectRoot, { recursive: true, persistent: true }, (_event, filename) =>
|
|
386
|
-
if (this.stopped || filename == null)
|
|
387
|
-
return;
|
|
388
|
-
this.handleChange((0, utils_1.normalizePath)(String(filename)));
|
|
389
|
-
});
|
|
417
|
+
this.recursiveWatcher = watchImpl(this.projectRoot, { recursive: true, persistent: true }, (_event, filename) => this.handleDirEvent(this.projectRoot, filename));
|
|
390
418
|
this.recursiveWatcher.on('error', (err) => {
|
|
391
419
|
if (isWatchResourceExhaustion(err)) {
|
|
392
420
|
this.degrade(EXHAUSTION_REASON, { error: String(err) });
|
|
@@ -394,46 +422,88 @@ class FileWatcher {
|
|
|
394
422
|
}
|
|
395
423
|
(0, errors_1.logWarn)('File watcher error', { error: String(err) });
|
|
396
424
|
});
|
|
425
|
+
this.refreshWatchTree();
|
|
397
426
|
}
|
|
398
|
-
/**
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
427
|
+
/** Reconcile logical directory paths with real targets, including retargeted links. */
|
|
428
|
+
refreshWatchTree() {
|
|
429
|
+
if (this.stopped || this.inert)
|
|
430
|
+
return;
|
|
431
|
+
this.visitedRealDirs.clear();
|
|
432
|
+
const directories = new Map();
|
|
433
|
+
const desired = new Map();
|
|
434
|
+
const recursive = supportsRecursiveWatch();
|
|
435
|
+
const walk = (dir, linked) => {
|
|
436
|
+
if (this.shouldIgnoreDir(dir))
|
|
437
|
+
return;
|
|
438
|
+
let real;
|
|
439
|
+
try {
|
|
440
|
+
real = fs.realpathSync(dir);
|
|
441
|
+
if (this.visitedRealDirs.has(real))
|
|
442
|
+
return;
|
|
443
|
+
this.visitedRealDirs.add(real);
|
|
444
|
+
directories.set(dir, real);
|
|
445
|
+
if (!recursive || linked)
|
|
446
|
+
desired.set(dir, real);
|
|
447
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
448
|
+
const child = path.join(dir, entry.name);
|
|
449
|
+
if (entry.isDirectory()) {
|
|
450
|
+
walk(child, false);
|
|
451
|
+
}
|
|
452
|
+
else if (entry.isSymbolicLink()) {
|
|
453
|
+
// Follow directory symlinks just like the indexer's walk. Realpath
|
|
454
|
+
// deduplication includes ordinary directories and the root itself.
|
|
455
|
+
try {
|
|
456
|
+
if (fs.statSync(child).isDirectory())
|
|
457
|
+
walk(child, true);
|
|
458
|
+
}
|
|
459
|
+
catch { /* broken link */ }
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
catch { /* removed or unreadable directory */ }
|
|
464
|
+
};
|
|
465
|
+
walk(this.projectRoot, false);
|
|
466
|
+
this.knownDirs = directories;
|
|
467
|
+
for (const dir of this.dirWatchers.keys()) {
|
|
468
|
+
if (desired.get(dir) !== this.watchedRealDirs.get(dir))
|
|
469
|
+
this.unwatchDir(dir);
|
|
470
|
+
}
|
|
471
|
+
for (const [dir, real] of desired)
|
|
472
|
+
this.watchDirectory(dir, real, recursive);
|
|
405
473
|
}
|
|
406
|
-
/**
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
474
|
+
/** Coalesce directory topology events before walking; file edits never walk the tree. */
|
|
475
|
+
scheduleTreeRefresh() {
|
|
476
|
+
if (this.treeRefreshTimer || this.inert || this.stopped)
|
|
477
|
+
return;
|
|
478
|
+
this.treeRefreshTimer = setTimeout(() => {
|
|
479
|
+
this.treeRefreshTimer = null;
|
|
480
|
+
this.refreshWatchTree();
|
|
481
|
+
if (this.stopped)
|
|
482
|
+
return;
|
|
483
|
+
// A new/retargeted directory can already contain files before its watch
|
|
484
|
+
// is installed; a full reconcile closes that race and removes old paths.
|
|
485
|
+
this.needsFullScan = true;
|
|
486
|
+
this.scheduleSync();
|
|
487
|
+
}, 50);
|
|
488
|
+
}
|
|
489
|
+
watchDirectory(dir, real, recursive) {
|
|
490
|
+
if (this.stopped || (this.degradedReason && !this.recoveringFromLock) || this.inotifyLimitWarned)
|
|
422
491
|
return;
|
|
423
492
|
if (this.dirWatchers.has(dir))
|
|
424
493
|
return;
|
|
425
|
-
|
|
494
|
+
// Recursive streams cost more than inotify entries. Keep a separate hard
|
|
495
|
+
// ceiling while honouring a lower user-configured directory watch budget.
|
|
496
|
+
const cap = recursive ? Math.min(256, maxDirWatches()) : maxDirWatches();
|
|
497
|
+
if (this.dirWatchers.size >= cap) {
|
|
426
498
|
if (!this.dirCapWarned) {
|
|
427
499
|
this.dirCapWarned = true;
|
|
428
|
-
(0, errors_1.logWarn)('File watcher hit directory-watch cap; remaining subtrees rely on manual/periodic sync', {
|
|
429
|
-
cap: maxDirWatches(),
|
|
430
|
-
});
|
|
500
|
+
(0, errors_1.logWarn)('File watcher hit directory-watch cap; remaining subtrees rely on manual/periodic sync', { cap });
|
|
431
501
|
}
|
|
432
502
|
return;
|
|
433
503
|
}
|
|
434
504
|
let w;
|
|
435
505
|
try {
|
|
436
|
-
w = watchImpl(dir, { persistent: true }, (_event, filename) => this.handleDirEvent(dir, filename));
|
|
506
|
+
w = watchImpl(dir, { persistent: true, recursive }, (_event, filename) => this.handleDirEvent(dir, filename));
|
|
437
507
|
}
|
|
438
508
|
catch (err) {
|
|
439
509
|
// EMFILE/ENFILE means the PROCESS is out of descriptors — every further
|
|
@@ -461,49 +531,41 @@ class FileWatcher {
|
|
|
461
531
|
this.unwatchDir(dir);
|
|
462
532
|
});
|
|
463
533
|
this.dirWatchers.set(dir, w);
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
467
|
-
}
|
|
468
|
-
catch {
|
|
469
|
-
return;
|
|
470
|
-
}
|
|
471
|
-
for (const entry of entries) {
|
|
472
|
-
const child = path.join(dir, entry.name);
|
|
473
|
-
if (entry.isDirectory()) {
|
|
474
|
-
if (this.shouldIgnoreDir(child))
|
|
475
|
-
continue;
|
|
476
|
-
this.watchTree(child, markExisting);
|
|
477
|
-
}
|
|
478
|
-
else if (markExisting && entry.isFile()) {
|
|
479
|
-
this.handleChange((0, utils_1.normalizePath)(path.relative(this.projectRoot, child)));
|
|
480
|
-
}
|
|
481
|
-
}
|
|
534
|
+
this.watchedRealDirs.set(dir, real);
|
|
482
535
|
}
|
|
483
|
-
/**
|
|
484
|
-
* Linux per-directory event handler. `filename` is relative to `dir`. A new
|
|
485
|
-
* sub-directory is picked up by extending the watch tree; everything else is
|
|
486
|
-
* routed through the shared change handler.
|
|
487
|
-
*/
|
|
536
|
+
/** Events are relative to a watch's logical path, even for an external target. */
|
|
488
537
|
handleDirEvent(dir, filename) {
|
|
489
|
-
if (this.stopped
|
|
538
|
+
if (this.stopped)
|
|
490
539
|
return;
|
|
540
|
+
if (filename == null) {
|
|
541
|
+
this.scheduleTreeRefresh();
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
491
544
|
const full = path.join(dir, String(filename));
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
545
|
+
const rel = (0, utils_1.normalizePath)(path.relative(this.projectRoot, full));
|
|
546
|
+
if (!rel || rel === '.') {
|
|
547
|
+
this.scheduleTreeRefresh();
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
// Churn under an ignored directory (node_modules, dist, .git) is dropped
|
|
551
|
+
// before any per-event fs call; `.git/info/exclude` still reaches the scope
|
|
552
|
+
// refresh in handleChange (#1728).
|
|
553
|
+
if (rel !== '.git/info/exclude' && this.shouldIgnoreDir(path.dirname(full)))
|
|
554
|
+
return;
|
|
496
555
|
try {
|
|
497
556
|
if (fs.statSync(full).isDirectory()) {
|
|
498
|
-
if (
|
|
499
|
-
|
|
557
|
+
if (this.shouldIgnoreDir(full))
|
|
558
|
+
return;
|
|
559
|
+
// Existing directory notifications can represent a retargeted link.
|
|
560
|
+
if (this.knownDirs.get(full) !== fs.realpathSync(full))
|
|
561
|
+
this.scheduleTreeRefresh();
|
|
500
562
|
return;
|
|
501
563
|
}
|
|
502
564
|
}
|
|
503
|
-
catch {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
this.handleChange(
|
|
565
|
+
catch { /* deleted/inaccessible */ }
|
|
566
|
+
if (this.knownDirs.has(full) && !this.shouldIgnoreDir(full))
|
|
567
|
+
this.scheduleTreeRefresh();
|
|
568
|
+
this.handleChange(rel);
|
|
507
569
|
}
|
|
508
570
|
/**
|
|
509
571
|
* Shared change handler for both watch strategies. `rel` is a
|
|
@@ -518,14 +580,53 @@ class FileWatcher {
|
|
|
518
580
|
handleChange(rel) {
|
|
519
581
|
if (!rel || rel === '.' || rel.startsWith('..'))
|
|
520
582
|
return;
|
|
583
|
+
// `.git/info/exclude` is otherwise always-ignored with the rest of `.git/`,
|
|
584
|
+
// but it feeds `buildScopeIgnore` — allow it through as a scope refresh
|
|
585
|
+
// when the platform delivers the event (recursive watchers may; Linux
|
|
586
|
+
// per-directory watching does not descend into `.git/`) (#1728).
|
|
587
|
+
if (rel === '.git/info/exclude') {
|
|
588
|
+
this.refreshScope(rel);
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
521
591
|
if (this.isAlwaysIgnored(rel))
|
|
522
592
|
return;
|
|
593
|
+
// The two root files the scope matcher is derived from are handled BEFORE
|
|
594
|
+
// the matcher is consulted: a user `exclude` pattern that happens to cover
|
|
595
|
+
// them (`*.json`, `.*`) must not be able to hide their own edits (#1590).
|
|
596
|
+
if (rel === project_config_1.PROJECT_CONFIG_FILENAME || rel === '.gitignore') {
|
|
597
|
+
this.refreshScope(rel);
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
523
600
|
if (this.ignoreMatcher && this.ignoreMatcher.ignores(rel))
|
|
524
601
|
return;
|
|
602
|
+
// A nested `.gitignore` (an embedded child repo's own rules, #514, or a
|
|
603
|
+
// subdirectory rule the git-backed full scan honors) is only a scope
|
|
604
|
+
// change when it sits INSIDE the current scope — checked after the matcher
|
|
605
|
+
// on purpose, so the thousands of package-local `.gitignore`s an
|
|
606
|
+
// `npm install` writes under an ignored `node_modules/` never trigger a
|
|
607
|
+
// rebuild storm.
|
|
608
|
+
if (rel.endsWith('/.gitignore')) {
|
|
609
|
+
this.refreshScope(rel);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
525
612
|
if (!(0, extraction_1.isSourceFile)(rel, (0, project_config_1.loadExtensionOverrides)(this.projectRoot))) {
|
|
526
613
|
this.maybeScheduleForRemovedDir(rel);
|
|
527
614
|
return;
|
|
528
615
|
}
|
|
616
|
+
try {
|
|
617
|
+
if (this.isFileStateCurrent?.(rel)) {
|
|
618
|
+
(0, errors_1.logDebug)('Ignoring file event with unchanged indexed metadata', { file: rel });
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
// The guard is an optimization, never a correctness boundary. If the
|
|
624
|
+
// stat/DB lookup fails, keep the event so a sync can reconcile it.
|
|
625
|
+
(0, errors_1.logDebug)('Could not verify file event metadata; treating it as a change', {
|
|
626
|
+
file: rel,
|
|
627
|
+
error: String(error),
|
|
628
|
+
});
|
|
629
|
+
}
|
|
529
630
|
(0, errors_1.logDebug)('File change detected', { file: rel });
|
|
530
631
|
if (this.ready) {
|
|
531
632
|
const now = Date.now();
|
|
@@ -537,6 +638,34 @@ class FileWatcher {
|
|
|
537
638
|
}
|
|
538
639
|
this.scheduleSync();
|
|
539
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* A scope-defining file changed (`lattice-sensor.json`, a `.gitignore`): rebuild
|
|
643
|
+
* the ignore matcher and make the next sync a FULL reconcile (#1590).
|
|
644
|
+
*
|
|
645
|
+
* The matcher used to be built once in `start()` and kept for the watcher's
|
|
646
|
+
* lifetime — in a long-lived MCP daemon that meant a `lattice-sensor.json`
|
|
647
|
+
* created or edited after startup was invisible to the live watcher, while
|
|
648
|
+
* `lattice sensor sync` (a fresh process) honoured it immediately: the CLI
|
|
649
|
+
* removed a newly excluded file and the watcher re-added it seconds later.
|
|
650
|
+
* `loadExtensionOverrides()` on the same filter line was already read live
|
|
651
|
+
* (mtime-cached), so two fields of the same config file disagreed.
|
|
652
|
+
*
|
|
653
|
+
* Rebuilding costs one `git ls-files` pass (embedded-repo discovery), which
|
|
654
|
+
* is fine per config edit — never per event. Replacing the field is enough
|
|
655
|
+
* for both strategies: the recursive handler and the per-directory
|
|
656
|
+
* `shouldIgnoreDir` walk read `this.ignoreMatcher` on every call. The full
|
|
657
|
+
* scan is required because a scope change has no per-file events: newly
|
|
658
|
+
* excluded files must be REMOVED from the index and newly included ones
|
|
659
|
+
* added, and only the scan-diff (which builds its own fresh matcher) knows
|
|
660
|
+
* which those are.
|
|
661
|
+
*/
|
|
662
|
+
refreshScope(rel) {
|
|
663
|
+
(0, errors_1.logDebug)('Scope config changed; rebuilding watcher scope', { file: rel });
|
|
664
|
+
this.ignoreMatcher = (0, extraction_1.buildScopeIgnore)(this.projectRoot);
|
|
665
|
+
this.scheduleTreeRefresh();
|
|
666
|
+
this.needsFullScan = true;
|
|
667
|
+
this.scheduleSync();
|
|
668
|
+
}
|
|
540
669
|
/**
|
|
541
670
|
* A deleted DIRECTORY arrives as one event on the directory's own path —
|
|
542
671
|
* no source extension, so the source-file filter drops it, and the files
|
|
@@ -578,16 +707,15 @@ class FileWatcher {
|
|
|
578
707
|
/* already closed */
|
|
579
708
|
}
|
|
580
709
|
this.dirWatchers.delete(dir);
|
|
710
|
+
this.watchedRealDirs.delete(dir);
|
|
581
711
|
}
|
|
582
712
|
}
|
|
583
713
|
/** Our own dirs are always ignored, regardless of .gitignore. */
|
|
584
714
|
isAlwaysIgnored(rel) {
|
|
585
|
-
//
|
|
715
|
+
// Ignore any LatticeSensor data dir — the active one AND a
|
|
586
716
|
// sibling like `.lattice/sensor-win` a second environment (Windows/WSL) created
|
|
587
717
|
// in the same tree, so neither side watches the other's index (#636).
|
|
588
|
-
|
|
589
|
-
return ((0, directory_1.isLatticeStateDir)(top) ||
|
|
590
|
-
rel === '.git' || rel.startsWith('.git/'));
|
|
718
|
+
return rel.split('/').some(part => (0, directory_1.isLatticeStateDir)(part) || part === '.git');
|
|
591
719
|
}
|
|
592
720
|
/**
|
|
593
721
|
* True for any directory that should NOT be watched (used while building the
|
|
@@ -605,16 +733,18 @@ class FileWatcher {
|
|
|
605
733
|
return this.ignoreMatcher.ignores(rel + '/');
|
|
606
734
|
}
|
|
607
735
|
/**
|
|
608
|
-
*
|
|
736
|
+
* Disable live watching after a terminal runtime failure
|
|
609
737
|
* (watch-resource exhaustion, lock contention past the retry budget, or a
|
|
610
738
|
* persistent generic sync failure past the retry budget).
|
|
611
739
|
* Idempotent: logs one actionable warning, fires {@link WatchOptions.onDegraded}
|
|
612
740
|
* once, and stops the watcher. A subsequent start() clears the latch.
|
|
613
741
|
*/
|
|
614
|
-
degrade(reason, context = {}) {
|
|
615
|
-
if (this.degradedReason)
|
|
742
|
+
degrade(reason, context = {}, byLock = false) {
|
|
743
|
+
if (this.degradedReason && !this.recoveringFromLock)
|
|
616
744
|
return;
|
|
617
745
|
this.degradedReason = reason;
|
|
746
|
+
this.degradedByLock = byLock;
|
|
747
|
+
this.recoveringFromLock = false;
|
|
618
748
|
(0, errors_1.logWarn)('File watcher disabled', { projectRoot: this.projectRoot, reason, ...context });
|
|
619
749
|
this.onDegraded?.(reason);
|
|
620
750
|
this.stop();
|
|
@@ -634,7 +764,7 @@ class FileWatcher {
|
|
|
634
764
|
(0, errors_1.logWarn)(INOTIFY_LIMIT_REASON, { watchedDirs: this.dirWatchers.size, ...context });
|
|
635
765
|
}
|
|
636
766
|
/**
|
|
637
|
-
* Whether live watching has degraded
|
|
767
|
+
* Whether live watching has degraded or is still catching up after re-arm.
|
|
638
768
|
* Distinct from {@link isActive}: a degraded watcher is inactive, but an
|
|
639
769
|
* inactive watcher is not necessarily degraded (it may simply be stopped or
|
|
640
770
|
* never started). Hosts use this to tell the user auto-sync is off.
|
|
@@ -646,11 +776,52 @@ class FileWatcher {
|
|
|
646
776
|
getDegradedReason() {
|
|
647
777
|
return this.degradedReason;
|
|
648
778
|
}
|
|
779
|
+
/** Watches are live again, but the full catch-up has not committed yet. */
|
|
780
|
+
isRecoveringFromLock() {
|
|
781
|
+
return this.recoveringFromLock;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Re-arm a watcher disabled by lock contention when a caller next uses the
|
|
785
|
+
* graph. Keep the whole-index stale banner until a FULL scan reconciles edits
|
|
786
|
+
* missed while watches were off. Resource exhaustion and deterministic sync
|
|
787
|
+
* failures are not automatically retried. Repeated unsuccessful re-arms are
|
|
788
|
+
* throttled so many MCP sessions cannot hammer a long-lived writer.
|
|
789
|
+
*/
|
|
790
|
+
rearmAfterLockContention() {
|
|
791
|
+
if (!this.degradedByLock || this.isActive())
|
|
792
|
+
return false;
|
|
793
|
+
const now = Date.now();
|
|
794
|
+
if (this.lastLockRearmMs && now - this.lastLockRearmMs < LOCK_REARM_COOLDOWN_MS)
|
|
795
|
+
return false;
|
|
796
|
+
const reason = this.degradedReason;
|
|
797
|
+
this.lastLockRearmMs = now;
|
|
798
|
+
if (!this.start()) {
|
|
799
|
+
// A disabled platform can reject start() without calling degrade().
|
|
800
|
+
// Preserve the old stale-index signal in that case; a new resource
|
|
801
|
+
// failure has its own more precise degraded reason.
|
|
802
|
+
if (!this.degradedReason) {
|
|
803
|
+
this.degradedReason = reason;
|
|
804
|
+
this.degradedByLock = true;
|
|
805
|
+
}
|
|
806
|
+
return false;
|
|
807
|
+
}
|
|
808
|
+
this.degradedReason = reason;
|
|
809
|
+
this.recoveringFromLock = true;
|
|
810
|
+
this.needsFullScan = true;
|
|
811
|
+
this.scheduleSync();
|
|
812
|
+
return true;
|
|
813
|
+
}
|
|
649
814
|
/**
|
|
650
815
|
* Stop watching for file changes.
|
|
651
816
|
*/
|
|
652
817
|
stop() {
|
|
653
818
|
this.stopped = true;
|
|
819
|
+
if (this.treeRefreshTimer)
|
|
820
|
+
clearTimeout(this.treeRefreshTimer);
|
|
821
|
+
this.treeRefreshTimer = null;
|
|
822
|
+
this.knownDirs.clear();
|
|
823
|
+
this.watchedRealDirs.clear();
|
|
824
|
+
this.recoveringFromLock = false;
|
|
654
825
|
if (this.debounceTimer) {
|
|
655
826
|
clearTimeout(this.debounceTimer);
|
|
656
827
|
this.debounceTimer = null;
|
|
@@ -679,6 +850,7 @@ class FileWatcher {
|
|
|
679
850
|
this.syncFailureRetryCount = 0;
|
|
680
851
|
// NB: degradedReason is intentionally NOT reset here — it must survive the
|
|
681
852
|
// stop() that degrade() triggers so isDegraded() stays true. start() clears it.
|
|
853
|
+
this.visitedRealDirs.clear();
|
|
682
854
|
this.inert = false;
|
|
683
855
|
this.pendingFiles.clear();
|
|
684
856
|
this.ready = false;
|
|
@@ -788,10 +960,16 @@ class FileWatcher {
|
|
|
788
960
|
const scoped = !this.needsFullScan && this.pendingFiles.size > 0 && this.pendingFiles.size <= SCOPED_SYNC_MAX_PENDING
|
|
789
961
|
? [...this.pendingFiles.keys()]
|
|
790
962
|
: undefined;
|
|
963
|
+
// Consume this request before yielding so a topology/scope change during
|
|
964
|
+
// the full sync remains pending for the next reconcile.
|
|
965
|
+
if (!scoped)
|
|
966
|
+
this.needsFullScan = false;
|
|
791
967
|
try {
|
|
792
968
|
const result = await this.syncFn(scoped);
|
|
793
|
-
if (!scoped)
|
|
794
|
-
this.
|
|
969
|
+
if (this.recoveringFromLock && !scoped && !this.needsFullScan) {
|
|
970
|
+
this.degradedReason = null;
|
|
971
|
+
this.recoveringFromLock = false;
|
|
972
|
+
}
|
|
795
973
|
this.lockRetryCount = 0; // a clean sync clears any contention backoff
|
|
796
974
|
this.syncFailureRetryCount = 0; // ...and any generic-failure backoff
|
|
797
975
|
// Remove entries whose most recent event predates this sync — those
|
|
@@ -809,6 +987,8 @@ class FileWatcher {
|
|
|
809
987
|
this.onSyncComplete?.(result);
|
|
810
988
|
}
|
|
811
989
|
catch (err) {
|
|
990
|
+
if (!scoped)
|
|
991
|
+
this.needsFullScan = true;
|
|
812
992
|
if (err instanceof LockUnavailableError) {
|
|
813
993
|
this.lockRetryCount += 1;
|
|
814
994
|
// Lock-failure no-op (another writer holds the lock). pendingFiles
|
|
@@ -823,7 +1003,7 @@ class FileWatcher {
|
|
|
823
1003
|
if (this.lockRetryCount > MAX_LOCK_RETRIES) {
|
|
824
1004
|
this.degrade('LatticeSensor file lock held by another process past the retry budget; ' +
|
|
825
1005
|
'auto-sync disabled. Run `lattice sensor sync` once the other writer finishes ' +
|
|
826
|
-
'(or install git sync hooks) to refresh the graph.', { pendingFiles: this.pendingFiles.size, retryCount: this.lockRetryCount });
|
|
1006
|
+
'(or install git sync hooks) to refresh the graph.', { pendingFiles: this.pendingFiles.size, retryCount: this.lockRetryCount }, true);
|
|
827
1007
|
}
|
|
828
1008
|
}
|
|
829
1009
|
else {
|
|
@@ -861,8 +1041,10 @@ class FileWatcher {
|
|
|
861
1041
|
// sync resets both counters so normal edits keep the fast debounce. Use
|
|
862
1042
|
// the larger streak so interleaved failures still back off. A degrade()
|
|
863
1043
|
// above already set `stopped`, so this won't reschedule a watcher that
|
|
864
|
-
// has given up.
|
|
865
|
-
|
|
1044
|
+
// has given up. A directory removal whose full sync failed adds no
|
|
1045
|
+
// pending file, only `needsFullScan` — it still owes the full reconcile
|
|
1046
|
+
// it asked for (#1964).
|
|
1047
|
+
if ((this.pendingFiles.size > 0 || this.needsFullScan) && !this.stopped) {
|
|
866
1048
|
const retryCount = Math.max(this.lockRetryCount, this.syncFailureRetryCount);
|
|
867
1049
|
if (retryCount > 0) {
|
|
868
1050
|
const retryDelayMs = Math.min(this.debounceMs * 2 ** Math.max(0, retryCount - 1), MAX_RETRY_BACKOFF_MS);
|