gitnexus 1.6.5-rc.8 → 1.6.5
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/dist/_shared/scope-resolution/finalize-algorithm.js +10 -2
- package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +26 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.js +22 -3
- package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/lookup-core.js +18 -1
- package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -1
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +2 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +1 -0
- package/dist/cli/ai-context.js +70 -16
- package/dist/cli/analyze.d.ts +30 -2
- package/dist/cli/analyze.js +45 -5
- package/dist/cli/index.js +8 -1
- package/dist/cli/setup.js +18 -0
- package/dist/cli/wiki.d.ts +2 -0
- package/dist/cli/wiki.js +11 -0
- package/dist/core/augmentation/engine.js +24 -4
- package/dist/core/embeddings/http-client.js +22 -6
- package/dist/core/incremental/shadow-candidates.d.ts +44 -0
- package/dist/core/incremental/shadow-candidates.js +74 -0
- package/dist/core/incremental/subgraph-extract.d.ts +64 -0
- package/dist/core/incremental/subgraph-extract.js +111 -0
- package/dist/core/ingestion/call-processor.d.ts +12 -1
- package/dist/core/ingestion/call-processor.js +183 -47
- package/dist/core/ingestion/class-extractors/configs/c-cpp.js +38 -0
- package/dist/core/ingestion/class-extractors/generic.js +8 -0
- package/dist/core/ingestion/class-types.d.ts +15 -0
- package/dist/core/ingestion/community-processor.js +18 -0
- package/dist/core/ingestion/import-resolvers/standard.d.ts +5 -0
- package/dist/core/ingestion/import-resolvers/standard.js +31 -1
- package/dist/core/ingestion/import-resolvers/utils.js +4 -0
- package/dist/core/ingestion/languages/c-cpp.js +20 -2
- package/dist/core/ingestion/languages/cpp/adl.d.ts +141 -0
- package/dist/core/ingestion/languages/cpp/adl.js +478 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.d.ts +18 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +170 -0
- package/dist/core/ingestion/languages/cpp/arity.d.ts +17 -0
- package/dist/core/ingestion/languages/cpp/arity.js +31 -0
- package/dist/core/ingestion/languages/cpp/captures.d.ts +2 -0
- package/dist/core/ingestion/languages/cpp/captures.js +1131 -0
- package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +31 -0
- package/dist/core/ingestion/languages/cpp/conversion-rank.js +47 -0
- package/dist/core/ingestion/languages/cpp/file-local-linkage.d.ts +118 -0
- package/dist/core/ingestion/languages/cpp/file-local-linkage.js +266 -0
- package/dist/core/ingestion/languages/cpp/header-scan.d.ts +8 -0
- package/dist/core/ingestion/languages/cpp/header-scan.js +50 -0
- package/dist/core/ingestion/languages/cpp/import-decomposer.d.ts +19 -0
- package/dist/core/ingestion/languages/cpp/import-decomposer.js +111 -0
- package/dist/core/ingestion/languages/cpp/import-target.d.ts +10 -0
- package/dist/core/ingestion/languages/cpp/import-target.js +13 -0
- package/dist/core/ingestion/languages/cpp/index.d.ts +11 -0
- package/dist/core/ingestion/languages/cpp/index.js +11 -0
- package/dist/core/ingestion/languages/cpp/inline-namespaces.d.ts +67 -0
- package/dist/core/ingestion/languages/cpp/inline-namespaces.js +176 -0
- package/dist/core/ingestion/languages/cpp/interpret.d.ts +35 -0
- package/dist/core/ingestion/languages/cpp/interpret.js +113 -0
- package/dist/core/ingestion/languages/cpp/merge-bindings.d.ts +13 -0
- package/dist/core/ingestion/languages/cpp/merge-bindings.js +29 -0
- package/dist/core/ingestion/languages/cpp/query.d.ts +3 -0
- package/dist/core/ingestion/languages/cpp/query.js +508 -0
- package/dist/core/ingestion/languages/cpp/range-bindings.d.ts +20 -0
- package/dist/core/ingestion/languages/cpp/range-bindings.js +212 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.d.ts +17 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +246 -0
- package/dist/core/ingestion/languages/cpp/simple-hooks.d.ts +24 -0
- package/dist/core/ingestion/languages/cpp/simple-hooks.js +62 -0
- package/dist/core/ingestion/languages/cpp/two-phase-lookup.d.ts +76 -0
- package/dist/core/ingestion/languages/cpp/two-phase-lookup.js +195 -0
- package/dist/core/ingestion/languages/java/arity-metadata.d.ts +18 -0
- package/dist/core/ingestion/languages/java/arity-metadata.js +40 -0
- package/dist/core/ingestion/languages/java/arity.d.ts +10 -0
- package/dist/core/ingestion/languages/java/arity.js +24 -0
- package/dist/core/ingestion/languages/java/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/java/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/java/captures.d.ts +17 -0
- package/dist/core/ingestion/languages/java/captures.js +187 -0
- package/dist/core/ingestion/languages/java/import-decomposer.d.ts +18 -0
- package/dist/core/ingestion/languages/java/import-decomposer.js +85 -0
- package/dist/core/ingestion/languages/java/import-target.d.ts +17 -0
- package/dist/core/ingestion/languages/java/import-target.js +100 -0
- package/dist/core/ingestion/languages/java/index.d.ts +29 -0
- package/dist/core/ingestion/languages/java/index.js +29 -0
- package/dist/core/ingestion/languages/java/interpret.d.ts +13 -0
- package/dist/core/ingestion/languages/java/interpret.js +131 -0
- package/dist/core/ingestion/languages/java/merge-bindings.d.ts +12 -0
- package/dist/core/ingestion/languages/java/merge-bindings.js +40 -0
- package/dist/core/ingestion/languages/java/query.d.ts +30 -0
- package/dist/core/ingestion/languages/java/query.js +192 -0
- package/dist/core/ingestion/languages/java/receiver-binding.d.ts +11 -0
- package/dist/core/ingestion/languages/java/receiver-binding.js +95 -0
- package/dist/core/ingestion/languages/java/scope-resolver.d.ts +50 -0
- package/dist/core/ingestion/languages/java/scope-resolver.js +74 -0
- package/dist/core/ingestion/languages/java/simple-hooks.d.ts +13 -0
- package/dist/core/ingestion/languages/java/simple-hooks.js +34 -0
- package/dist/core/ingestion/languages/java.js +11 -0
- package/dist/core/ingestion/languages/php/arity-metadata.d.ts +28 -0
- package/dist/core/ingestion/languages/php/arity-metadata.js +63 -0
- package/dist/core/ingestion/languages/php/arity.d.ts +25 -0
- package/dist/core/ingestion/languages/php/arity.js +40 -0
- package/dist/core/ingestion/languages/php/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/php/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/php/captures.d.ts +34 -0
- package/dist/core/ingestion/languages/php/captures.js +739 -0
- package/dist/core/ingestion/languages/php/import-decomposer.d.ts +28 -0
- package/dist/core/ingestion/languages/php/import-decomposer.js +265 -0
- package/dist/core/ingestion/languages/php/import-target.d.ts +47 -0
- package/dist/core/ingestion/languages/php/import-target.js +100 -0
- package/dist/core/ingestion/languages/php/index.d.ts +68 -0
- package/dist/core/ingestion/languages/php/index.js +72 -0
- package/dist/core/ingestion/languages/php/interpret.d.ts +36 -0
- package/dist/core/ingestion/languages/php/interpret.js +241 -0
- package/dist/core/ingestion/languages/php/merge-bindings.d.ts +19 -0
- package/dist/core/ingestion/languages/php/merge-bindings.js +47 -0
- package/dist/core/ingestion/languages/php/namespace-siblings.d.ts +51 -0
- package/dist/core/ingestion/languages/php/namespace-siblings.js +288 -0
- package/dist/core/ingestion/languages/php/query.d.ts +32 -0
- package/dist/core/ingestion/languages/php/query.js +326 -0
- package/dist/core/ingestion/languages/php/receiver-binding.d.ts +36 -0
- package/dist/core/ingestion/languages/php/receiver-binding.js +128 -0
- package/dist/core/ingestion/languages/php/scope-resolver.d.ts +23 -0
- package/dist/core/ingestion/languages/php/scope-resolver.js +358 -0
- package/dist/core/ingestion/languages/php/simple-hooks.d.ts +42 -0
- package/dist/core/ingestion/languages/php/simple-hooks.js +111 -0
- package/dist/core/ingestion/languages/php.d.ts +0 -7
- package/dist/core/ingestion/languages/php.js +15 -0
- package/dist/core/ingestion/markdown-processor.js +6 -1
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
- package/dist/core/ingestion/model/symbol-table.js +3 -0
- package/dist/core/ingestion/parsing-processor.d.ts +22 -2
- package/dist/core/ingestion/parsing-processor.js +123 -50
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.js +54 -2
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +5 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +119 -11
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +14 -0
- package/dist/core/ingestion/pipeline.d.ts +13 -0
- package/dist/core/ingestion/registry-primary-flag.js +2 -0
- package/dist/core/ingestion/scope-extractor.js +4 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +167 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +3 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +1 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +12 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.d.ts +1 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +12 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +16 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +36 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +204 -13
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +1 -1
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +55 -4
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +186 -5
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +10 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +207 -9
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +13 -1
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +6 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +17 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +86 -8
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +30 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +90 -8
- package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -2
- package/dist/core/ingestion/tree-sitter-queries.js +23 -0
- package/dist/core/ingestion/utils/ast-helpers.js +6 -1
- package/dist/core/ingestion/utils/template-arguments.d.ts +11 -0
- package/dist/core/ingestion/utils/template-arguments.js +65 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +3 -0
- package/dist/core/ingestion/workers/parse-worker.js +42 -1
- package/dist/core/lbug/lbug-adapter.d.ts +39 -0
- package/dist/core/lbug/lbug-adapter.js +348 -48
- package/dist/core/run-analyze.d.ts +2 -0
- package/dist/core/run-analyze.js +323 -29
- package/dist/core/search/hybrid-search.d.ts +3 -0
- package/dist/core/search/hybrid-search.js +23 -6
- package/dist/core/wiki/generator.js +4 -3
- package/dist/core/wiki/html-viewer.js +2 -1
- package/dist/core/wiki/llm-client.d.ts +4 -0
- package/dist/core/wiki/llm-client.js +3 -3
- package/dist/core/wiki/mermaid-sanitizer.d.ts +2 -0
- package/dist/core/wiki/mermaid-sanitizer.js +100 -0
- package/dist/mcp/local/local-backend.js +20 -7
- package/dist/storage/file-hash.d.ts +47 -0
- package/dist/storage/file-hash.js +86 -0
- package/dist/storage/parse-cache.d.ts +73 -0
- package/dist/storage/parse-cache.js +253 -0
- package/dist/storage/repo-manager.d.ts +41 -1
- package/dist/storage/repo-manager.js +61 -6
- package/hooks/claude/gitnexus-hook.cjs +42 -4
- package/hooks/claude/hook-db-lock-probe.cjs +238 -0
- package/hooks/claude/hook-lock.cjs +119 -0
- package/hooks/claude/win-rm-list-json.ps1 +76 -0
- package/package.json +1 -1
- package/scripts/build.js +6 -2
- package/vendor/node_modules/node-addon-api/node_addon_api.target.mk +16 -16
- package/vendor/node_modules/node-addon-api/node_addon_api_except.target.mk +16 -16
- package/vendor/node_modules/node-addon-api/node_addon_api_except_all.target.mk +16 -16
- package/vendor/node_modules/node-addon-api/node_addon_api_maybe.target.mk +16 -16
- package/web/assets/{agent-BpHQleHE.js → agent-D2kLt6Dl.js} +91 -91
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-DvIkEGkp.js +36 -0
- package/web/assets/blockDiagram-7IZFK4PR-B4niSLvR.js +132 -0
- package/web/assets/{c4Diagram-DFAF54RM-DeJV1rCn.js → c4Diagram-Y2BXMSZH-DIzEXalR.js} +6 -6
- package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +4 -0
- package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +1 -0
- package/web/assets/{chunk-7RZVMHOQ-BdIU-RGO.js → chunk-3SSMPTDK-BzGeeheI.js} +1 -1
- package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +159 -0
- package/web/assets/chunk-5IMINLNL-CnTLsXIV.js +1 -0
- package/web/assets/chunk-5VCL7Z4A-w1BCx98Z.js +1 -0
- package/web/assets/chunk-6764PJDD-ChwMM2z4.js +1 -0
- package/web/assets/chunk-67TQ5CYL-CChC2cAv.js +124 -0
- package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +10 -0
- package/web/assets/chunk-7W6UQGC5-CgFyfZ6k.js +1 -0
- package/web/assets/chunk-AQ6EADP3-CCFje6lL.js +1 -0
- package/web/assets/{chunk-KSICW3F5-C2tZmXwv.js → chunk-AZZRMDJM-5E9ARdDQ.js} +1 -1
- package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +1 -0
- package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +1 -0
- package/web/assets/chunk-INKRHTLW-ELpfuk9h.js +70 -0
- package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +1 -0
- package/web/assets/{chunk-AEOMTBSW-D7qjBMHW.js → chunk-JQRUD6KW-Dcq_Qnyy.js} +1 -1
- package/web/assets/chunk-KGFNY3KK-W-VR57xb.js +62 -0
- package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +1 -0
- package/web/assets/chunk-KNLZD3CH-BuZBOcso.js +1 -0
- package/web/assets/chunk-KRXBNO2N-DH2NPM7I.js +1 -0
- package/web/assets/chunk-LCXTWHL2-CqJ0oo1x.js +231 -0
- package/web/assets/chunk-LII3EMHJ-3X33tCpU.js +1 -0
- package/web/assets/chunk-QA3QBVWF-D5Ha3GgB.js +2 -0
- package/web/assets/chunk-RERM46MO-DQNbXtfw.js +1 -0
- package/web/assets/chunk-RG4AUYOV-D0M6vdq9.js +206 -0
- package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +1 -0
- package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +1 -0
- package/web/assets/chunk-T2UQINTJ-kGYG7ppP.js +1 -0
- package/web/assets/chunk-T5OCTHI4--9wWpVws.js +1 -0
- package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +1 -0
- package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +1 -0
- package/web/assets/chunk-UY5QBCOK-Du-c56gs.js +1 -0
- package/web/assets/chunk-W44A43WB-lrCpuupA.js +1 -0
- package/web/assets/chunk-ZXARS5L4-CSZRiyOf.js +1 -0
- package/web/assets/classDiagram-KGZ6W3CR-BB-saqC1.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-Bp2bAlS5.js +1 -0
- package/web/assets/cose-bilkent-UX7MHV2Q-BHv2bbtl.js +1 -0
- package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +4 -0
- package/web/assets/diagram-3NCE3AQN-BUxnDPOY.js +43 -0
- package/web/assets/diagram-GF46GFSD-BJTyqqvI.js +24 -0
- package/web/assets/diagram-HNR7UZ2L-fUWreZzx.js +3 -0
- package/web/assets/diagram-QXG6HAR7-DilMHamP.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-8KUrarg1.js +10 -0
- package/web/assets/erDiagram-L5TCEMPS-Doj9mSiW.js +85 -0
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +1 -0
- package/web/assets/{flowDiagram-OTCZ4VVT-aAZw4c_M.js → flowDiagram-H6V6AXG4-BOSR-i3p.js} +12 -12
- package/web/assets/ganttDiagram-JCBTUEKG-BHQssTz6.js +292 -0
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +106 -0
- package/web/assets/index-j4-NuleT.js +623 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-Ce_TvtaV.js +2 -0
- package/web/assets/{ishikawaDiagram-YMYX4NHK-BF8AtDaj.js → ishikawaDiagram-BNXS4ZKH-4MXIDCSF.js} +6 -6
- package/web/assets/journeyDiagram-M6C3CM3L-DNPYCpvq.js +139 -0
- package/web/assets/kanban-definition-75IXJCU3-yYdfm8Kk.js +89 -0
- package/web/assets/{katex-GD7MH7QM-CJiOjBBJ.js → katex-K3KEBU37-CrVLz8l7.js} +1 -1
- package/web/assets/mindmap-definition-2TDM6QVE-DFNEKM77.js +96 -0
- package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +1 -0
- package/web/assets/pieDiagram-CU6KROY3-iZAqpvhd.js +30 -0
- package/web/assets/quadrantDiagram-VICAPDV7-bAm6Hi_5.js +7 -0
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +1 -0
- package/web/assets/requirementDiagram-JXO7QTGE-CtDijhnf.js +84 -0
- package/web/assets/sankeyDiagram-URQDO5SZ-LFJz53u5.js +40 -0
- package/web/assets/sequenceDiagram-VS2MUI6T-BdjvyCHM.js +162 -0
- package/web/assets/stateDiagram-7D4R322I-e5odN9fG.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-vPsvjR2D.js +1 -0
- package/web/assets/timeline-definition-O6YCAMPW-DPAksNQp.js +120 -0
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +1 -0
- package/web/assets/vennDiagram-MWXL3ELB-Dtlfdt7J.js +34 -0
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +1 -0
- package/web/assets/wardleyDiagram-CUQ6CDDI-B23uRMUC.js +78 -0
- package/web/assets/{xychartDiagram-ZHJ5623Y-DZ7fP1_3.js → xychartDiagram-N2JHSOCM-DxwHeksW.js} +6 -6
- package/web/index.html +13 -2
- package/web/assets/architecture-YZFGNWBL-S5CXDPWN-BUzkWgDl.js +0 -1
- package/web/assets/architectureDiagram-EMZXCZ2Q-CXbzok1G.js +0 -36
- package/web/assets/blockDiagram-IGV67L2C-DA1QJ4ZB.js +0 -132
- package/web/assets/chunk-3GS5O3IE-B8hpnia8.js +0 -231
- package/web/assets/chunk-3YCYZ6SJ-B-BVu21C.js +0 -1
- package/web/assets/chunk-6NTNNK5N-DW-jYSDr.js +0 -1
- package/web/assets/chunk-A34GCYZU-BbZl-IKy.js +0 -1
- package/web/assets/chunk-DJ7UZH7F-B5tMfF87.js +0 -1
- package/web/assets/chunk-DKKBVRCY-Djm-6K_e.js +0 -4
- package/web/assets/chunk-DU5LTGQ6-QPoynYcp.js +0 -1
- package/web/assets/chunk-FXACKDTF-jieSmbe2.js +0 -159
- package/web/assets/chunk-H3VCZNTA-8EMHZ3SV.js +0 -1
- package/web/assets/chunk-HN6EAY2L-CgE_agsD.js +0 -1
- package/web/assets/chunk-O5ABG6QK-DEZV1O19.js +0 -1
- package/web/assets/chunk-PK6DOVAG-BXv0JnsJ.js +0 -206
- package/web/assets/chunk-RNJOYNJ4-BiBkF9dN.js +0 -1
- package/web/assets/chunk-RWUO3TPN-DTWzAhQ1.js +0 -1
- package/web/assets/chunk-TBF5ZNIQ-BSl6s9lT.js +0 -1
- package/web/assets/chunk-TU3PZOEN-DE5Qhc0N.js +0 -1
- package/web/assets/chunk-TYMNRAUI-D1NDLIMG.js +0 -1
- package/web/assets/chunk-VELTKBKT-C9dVN39o.js +0 -1
- package/web/assets/chunk-W7ZLLLMY-Bu-cdLzs.js +0 -1
- package/web/assets/chunk-WSB5WSVC-Dor71SOz.js +0 -1
- package/web/assets/chunk-XGPFEOL4-CUonLRle.js +0 -1
- package/web/assets/classDiagram-PPOCWD7C-Cdd6UdVv.js +0 -1
- package/web/assets/classDiagram-v2-23LJLIIU-DNhxY2Ib.js +0 -1
- package/web/assets/cose-bilkent-PNC4W37J-DdZq7Qz_.js +0 -1
- package/web/assets/dagre-E77IOHMT-Cfj_6e17.js +0 -4
- package/web/assets/diagram-H7BISOXX-BNvpsrBv.js +0 -43
- package/web/assets/diagram-JC5VWROH-Cn0rtDbJ.js +0 -24
- package/web/assets/diagram-LXUTUG65-CHfoVKNm.js +0 -10
- package/web/assets/diagram-WEHSV5V5-BLxHksnu.js +0 -24
- package/web/assets/erDiagram-GCSMX5X6-DfdN6iqF.js +0 -85
- package/web/assets/ganttDiagram-MUNLMDZQ-BEfC_7Or.js +0 -292
- package/web/assets/gitGraph-7Q5UKJZL-54BCDZD5-B6ZeRLP0.js +0 -1
- package/web/assets/gitGraphDiagram-3HKGZ4G3-CG0kC8Q5.js +0 -106
- package/web/assets/index-3NUCUW2s.js +0 -886
- package/web/assets/info-OMHHGYJF-BF2H5H6G-BIOsZy0W.js +0 -1
- package/web/assets/infoDiagram-MN7RKWGX-DUoMH-pq.js +0 -2
- package/web/assets/journeyDiagram-SO5T7YLQ-BW8oKa3N.js +0 -139
- package/web/assets/kanban-definition-LJHFXRCJ-DzbOsR-2.js +0 -89
- package/web/assets/mindmap-definition-2EUWGEK5-BIXGQALq.js +0 -96
- package/web/assets/packet-4T2RLAQJ-EV4IVRXR-Bs7ysNMU.js +0 -1
- package/web/assets/pie-ZZUOXDRM-N23DN5KN-Csi8nnbH.js +0 -1
- package/web/assets/pieDiagram-3IATQBI2-QY-u7P6a.js +0 -30
- package/web/assets/quadrantDiagram-E256RVCF-Di4aNiU8.js +0 -7
- package/web/assets/radar-PYXPWWZC-P6TP7ZYP-DJlyXh2-.js +0 -1
- package/web/assets/requirementDiagram-M5DCFWZL-CzUUrhQD.js +0 -84
- package/web/assets/sankeyDiagram-L3NBLAOT-D2fbMiIU.js +0 -10
- package/web/assets/sequenceDiagram-ZOUHS735-BNdkqguh.js +0 -157
- package/web/assets/stateDiagram-MLPALWAM-51_Q2w2L.js +0 -1
- package/web/assets/stateDiagram-v2-B5LQ5ZB2-8nHs2aNE.js +0 -1
- package/web/assets/timeline-definition-5SPVSISX-DkMiGj4Z.js +0 -120
- package/web/assets/treeView-SZITEDCU-5DXDK3XO-Cy6P0_CZ.js +0 -1
- package/web/assets/treemap-W4RFUUIX-WYLRDWKO-C_pp1R7A.js +0 -1
- package/web/assets/vennDiagram-IE5QUKF5-BCxMmf9q.js +0 -34
- package/web/assets/wardley-RL74JXVD-BCRCBASE-CMStJhpn.js +0 -1
- package/web/assets/wardleyDiagram-XU3VSMPF-ijlLF77s.js +0 -20
- /package/web/assets/{context-builder-CqQNhRj1.js → context-builder-_HS0v2ma.js} +0 -0
package/dist/core/run-analyze.js
CHANGED
|
@@ -10,10 +10,15 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import path from 'path';
|
|
12
12
|
import fs from 'fs/promises';
|
|
13
|
+
import { execFileSync } from 'child_process';
|
|
13
14
|
import { runPipelineFromRepo } from './ingestion/pipeline.js';
|
|
14
|
-
import { initLbug, loadGraphToLbug, getLbugStats, executeQuery, executeWithReusedStatement, closeLbug, loadCachedEmbeddings, } from './lbug/lbug-adapter.js';
|
|
15
|
+
import { initLbug, loadGraphToLbug, getLbugStats, executeQuery, executeWithReusedStatement, closeLbug, loadCachedEmbeddings, deleteNodesForFile, deleteAllCommunitiesAndProcesses, queryImporters, } from './lbug/lbug-adapter.js';
|
|
15
16
|
import { createSearchFTSIndexes } from './search/fts-indexes.js';
|
|
16
|
-
import { getStoragePaths, saveMeta, loadMeta, ensureGitNexusIgnored, registerRepo, cleanupOldKuzuFiles, } from '../storage/repo-manager.js';
|
|
17
|
+
import { getStoragePaths, saveMeta, loadMeta, ensureGitNexusIgnored, registerRepo, cleanupOldKuzuFiles, INCREMENTAL_SCHEMA_VERSION, } from '../storage/repo-manager.js';
|
|
18
|
+
import { computeFileHashes, diffFileHashes } from '../storage/file-hash.js';
|
|
19
|
+
import { extractChangedSubgraph, computeEffectiveWriteSet, } from './incremental/subgraph-extract.js';
|
|
20
|
+
import { shadowCandidatesFor } from './incremental/shadow-candidates.js';
|
|
21
|
+
import { loadParseCache, saveParseCache, pruneCache } from '../storage/parse-cache.js';
|
|
17
22
|
import { getCurrentCommit, getRemoteUrl, hasGitDir, getInferredRepoName, resolveRepoIdentityRoot, } from '../storage/git.js';
|
|
18
23
|
import { generateAIContextFiles } from '../cli/ai-context.js';
|
|
19
24
|
import { EMBEDDING_TABLE_NAME } from './lbug/schema.js';
|
|
@@ -63,22 +68,74 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
|
|
|
63
68
|
const repoHasGit = hasGitDir(repoPath);
|
|
64
69
|
const currentCommit = repoHasGit ? getCurrentCommit(repoPath) : '';
|
|
65
70
|
const existingMeta = await loadMeta(storagePath);
|
|
71
|
+
// ── Crash recovery: dirty flag forces full rebuild ────────────────
|
|
72
|
+
// If the previous incremental run set incrementalInProgress and didn't
|
|
73
|
+
// clear it, the on-disk index may be in a half-state. Cheapest path
|
|
74
|
+
// back to a known-good index is to wipe + rebuild from scratch.
|
|
75
|
+
if (existingMeta?.incrementalInProgress) {
|
|
76
|
+
log('Previous incremental run did not complete cleanly (incrementalInProgress flag set); ' +
|
|
77
|
+
'forcing full rebuild to restore a known-good index.');
|
|
78
|
+
options = { ...options, force: true };
|
|
79
|
+
// Reload meta after clearing the flag in-memory; we still want fileHashes
|
|
80
|
+
// for the post-rebuild meta carry-over, but force=true ensures the
|
|
81
|
+
// rebuild path executes.
|
|
82
|
+
}
|
|
66
83
|
// ── Early-return: already up to date ──────────────────────────────
|
|
67
84
|
if (existingMeta && !options.force && existingMeta.lastCommit === currentCommit) {
|
|
68
85
|
// Non-git folders have currentCommit = '' — always rebuild since we can't detect changes
|
|
69
86
|
if (currentCommit !== '') {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
// For git repos, even if HEAD matches lastCommit, the working tree
|
|
88
|
+
// may have uncommitted changes. Only short-circuit when the working
|
|
89
|
+
// tree is also clean — otherwise fall through to the incremental
|
|
90
|
+
// path which will hash-diff and update only changed files.
|
|
91
|
+
//
|
|
92
|
+
// We exclude paths that GitNexus itself writes during analyze:
|
|
93
|
+
// .gitnexus/ — db / parse cache / meta.json
|
|
94
|
+
// .claude/, .cursor/ — auto-generated agent skill files
|
|
95
|
+
// AGENTS.md, CLAUDE.md — auto-updated stats blocks
|
|
96
|
+
// Counting them as dirty would perpetually defeat the up-to-date
|
|
97
|
+
// fast path because the previous analyze just wrote them
|
|
98
|
+
// (regression vs PR #1233 behavior).
|
|
99
|
+
const dirty = (() => {
|
|
100
|
+
try {
|
|
101
|
+
const out = execFileSync('git', [
|
|
102
|
+
'status',
|
|
103
|
+
'--porcelain',
|
|
104
|
+
'--',
|
|
105
|
+
'.',
|
|
106
|
+
':(exclude).gitnexus',
|
|
107
|
+
':(exclude).gitnexus/**',
|
|
108
|
+
':(exclude).claude',
|
|
109
|
+
':(exclude).claude/**',
|
|
110
|
+
':(exclude).cursor',
|
|
111
|
+
':(exclude).cursor/**',
|
|
112
|
+
':(exclude)AGENTS.md',
|
|
113
|
+
':(exclude)CLAUDE.md',
|
|
114
|
+
], {
|
|
115
|
+
cwd: repoPath,
|
|
116
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
117
|
+
encoding: 'utf8',
|
|
118
|
+
});
|
|
119
|
+
return out.trim().length > 0;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return true; // conservative on git failure
|
|
123
|
+
}
|
|
124
|
+
})();
|
|
125
|
+
if (!dirty) {
|
|
126
|
+
await ensureGitNexusIgnored(repoPath);
|
|
127
|
+
return {
|
|
128
|
+
// `resolveRepoIdentityRoot` collapses worktree roots to the
|
|
129
|
+
// canonical repo basename (#1259) but leaves arbitrary subdirs
|
|
130
|
+
// and `--skip-git` paths unchanged (#1232/#1233 intent preserved).
|
|
131
|
+
repoName: options.registryName ??
|
|
132
|
+
getInferredRepoName(repoPath) ??
|
|
133
|
+
path.basename(resolveRepoIdentityRoot(repoPath)),
|
|
134
|
+
repoPath,
|
|
135
|
+
stats: existingMeta.stats ?? {},
|
|
136
|
+
alreadyUpToDate: true,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
82
139
|
}
|
|
83
140
|
}
|
|
84
141
|
// ── Cache embeddings from existing index before rebuild ────────────
|
|
@@ -114,6 +171,14 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
|
|
|
114
171
|
`Pass --embeddings to also generate embeddings for new/changed nodes, ` +
|
|
115
172
|
`or --drop-embeddings to wipe them.`);
|
|
116
173
|
}
|
|
174
|
+
// We *always* load the embedding cache when one is requested (regardless
|
|
175
|
+
// of the predicted `willTryIncremental`). The post-pipeline branch may
|
|
176
|
+
// disagree with the prediction (e.g. when the pipeline produces zero
|
|
177
|
+
// File nodes, `isIncremental` flips false and the full-rebuild path
|
|
178
|
+
// wipes the DB) — loading unconditionally is cheap insurance against
|
|
179
|
+
// silently dropping embeddings on a mispredicted run. The re-insert
|
|
180
|
+
// step gates itself on the actual `isIncremental` value to avoid
|
|
181
|
+
// PK-conflicts when the incremental writeback path keeps the rows.
|
|
117
182
|
if (shouldLoadCache && existingMeta) {
|
|
118
183
|
try {
|
|
119
184
|
progress('embeddings', 0, 'Caching embeddings...');
|
|
@@ -140,23 +205,77 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
|
|
|
140
205
|
}
|
|
141
206
|
}
|
|
142
207
|
}
|
|
208
|
+
// ── Load incremental parse cache ──────────────────────────────────
|
|
209
|
+
// Content-addressed: safe to reuse across `--force` runs (chunks whose
|
|
210
|
+
// file contents haven't changed produce identical worker output).
|
|
211
|
+
// Loaded into a single ParseCache object that the pipeline mutates
|
|
212
|
+
// in-place (cache hits leave entries unchanged; misses add new ones).
|
|
213
|
+
const parseCache = await loadParseCache(storagePath);
|
|
143
214
|
// ── Phase 1: Full Pipeline (0–60%) ────────────────────────────────
|
|
144
215
|
const pipelineResult = await runPipelineFromRepo(repoPath, (p) => {
|
|
145
216
|
const phaseLabel = PHASE_LABELS[p.phase] || p.phase;
|
|
146
217
|
const scaled = Math.round(p.percent * 0.6);
|
|
147
|
-
const message = p.detail
|
|
218
|
+
const message = p.detail
|
|
219
|
+
? `${p.message || phaseLabel} (${p.detail})`
|
|
220
|
+
: p.message || phaseLabel;
|
|
148
221
|
progress(p.phase, scaled, message);
|
|
149
|
-
});
|
|
222
|
+
}, { parseCache });
|
|
150
223
|
// ── Phase 2: LadybugDB (60–85%) ──────────────────────────────────
|
|
151
224
|
progress('lbug', 60, 'Loading into LadybugDB...');
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
225
|
+
// Compute current per-file content hashes from the pipeline's File nodes.
|
|
226
|
+
// Used both to drive the incremental DB writeback (when eligible) and to
|
|
227
|
+
// populate meta.json.fileHashes for the next run.
|
|
228
|
+
const allFilePaths = [];
|
|
229
|
+
pipelineResult.graph.forEachNode((n) => {
|
|
230
|
+
if (n.label === 'File') {
|
|
231
|
+
const fp = n.properties?.filePath;
|
|
232
|
+
if (fp)
|
|
233
|
+
allFilePaths.push(fp);
|
|
157
234
|
}
|
|
158
|
-
|
|
159
|
-
|
|
235
|
+
});
|
|
236
|
+
const newFileHashes = await computeFileHashes(repoPath, allFilePaths);
|
|
237
|
+
// Decide incremental vs full at THIS point (post-pipeline, pre-DB).
|
|
238
|
+
// All eligibility conditions are checked here against the actual
|
|
239
|
+
// pipeline output — no separate pre-pipeline prediction to desync from
|
|
240
|
+
// (Bugbot review on PR #1479: a prediction that flipped post-pipeline
|
|
241
|
+
// could skip the embedding cache load and then take the full-rebuild
|
|
242
|
+
// path, silently losing embeddings).
|
|
243
|
+
const isIncremental = !options.force &&
|
|
244
|
+
!!existingMeta &&
|
|
245
|
+
existingMeta.schemaVersion === INCREMENTAL_SCHEMA_VERSION &&
|
|
246
|
+
!!existingMeta.fileHashes &&
|
|
247
|
+
Object.keys(existingMeta.fileHashes).length > 0 &&
|
|
248
|
+
repoHasGit &&
|
|
249
|
+
allFilePaths.length > 0;
|
|
250
|
+
const hashDiff = isIncremental
|
|
251
|
+
? diffFileHashes(newFileHashes, existingMeta.fileHashes)
|
|
252
|
+
: undefined;
|
|
253
|
+
if (isIncremental && hashDiff) {
|
|
254
|
+
log(`Incremental: changed=${hashDiff.changed.length}, ` +
|
|
255
|
+
`added=${hashDiff.added.length}, ` +
|
|
256
|
+
`deleted=${hashDiff.deleted.length} ` +
|
|
257
|
+
`(skipping wipe + ${allFilePaths.length - hashDiff.toWrite.length} unchanged file rows preserved)`);
|
|
258
|
+
// Set the dirty flag BEFORE any destructive DB mutation. Cleared on
|
|
259
|
+
// success at the meta-save step.
|
|
260
|
+
await saveMeta(storagePath, {
|
|
261
|
+
...existingMeta,
|
|
262
|
+
incrementalInProgress: {
|
|
263
|
+
startedAt: Date.now(),
|
|
264
|
+
toWriteCount: hashDiff.toWrite.length,
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// Full rebuild path: wipe DB files first.
|
|
270
|
+
await closeLbug();
|
|
271
|
+
const lbugFiles = [lbugPath, `${lbugPath}.wal`, `${lbugPath}.lock`];
|
|
272
|
+
for (const f of lbugFiles) {
|
|
273
|
+
try {
|
|
274
|
+
await fs.rm(f, { recursive: true, force: true });
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
/* swallow */
|
|
278
|
+
}
|
|
160
279
|
}
|
|
161
280
|
}
|
|
162
281
|
await initLbug(lbugPath);
|
|
@@ -165,16 +284,158 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
|
|
|
165
284
|
// is called even if an error occurs — the module-level singleton DB handle
|
|
166
285
|
// must be released to avoid blocking subsequent invocations.
|
|
167
286
|
let lbugMsgCount = 0;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
287
|
+
if (isIncremental && hashDiff) {
|
|
288
|
+
// ── Incremental DB writeback ───────────────────────────────────
|
|
289
|
+
// 0. Expand the writable set with transitive importers of
|
|
290
|
+
// changed/deleted files (bounded BFS).
|
|
291
|
+
//
|
|
292
|
+
// Reason (Bugbot/Claude review on PR #1479): when a barrel /
|
|
293
|
+
// re-export file C changes, cross-file resolution may update
|
|
294
|
+
// CALLS edges between two unchanged files A and B (A imports
|
|
295
|
+
// from C, C re-exports something from B). Those refined edges
|
|
296
|
+
// live in `ctx.graph` but would be excluded from the subgraph
|
|
297
|
+
// if neither endpoint is in the changed set. To catch this,
|
|
298
|
+
// files that imported (directly OR transitively, through
|
|
299
|
+
// other unchanged intermediaries) any changed file get pulled
|
|
300
|
+
// into the writable set so their rows are deleted + rewritten
|
|
301
|
+
// against the refined edges.
|
|
302
|
+
//
|
|
303
|
+
// BFS bound: MAX_IMPORTER_BFS_DEPTH. Practically sized to
|
|
304
|
+
// catch nested barrel chains (e.g. `index.ts → submodule/index.ts
|
|
305
|
+
// → submodule/impl.ts`) without ballooning into a near-full-
|
|
306
|
+
// rebuild on monorepos with deep re-export pyramids. Beyond
|
|
307
|
+
// this depth, the "incremental ≡ full-rebuild" invariant is
|
|
308
|
+
// self-acknowledged as best-effort; `--force` remains the
|
|
309
|
+
// escape hatch documented in GUARDRAILS.md.
|
|
310
|
+
//
|
|
311
|
+
// `queryImporters` reads `IMPORTS` from the pre-pipeline DB
|
|
312
|
+
// state, so the result is "files that USED TO import the
|
|
313
|
+
// target" — exactly the set whose previously-stored edges may
|
|
314
|
+
// no longer match what cross-file resolution produces this run.
|
|
315
|
+
const MAX_IMPORTER_BFS_DEPTH = 4;
|
|
316
|
+
const writableFiles = new Set(hashDiff.toWrite);
|
|
317
|
+
const directlyChangedCount = writableFiles.size;
|
|
318
|
+
// Shadow-seed: for ADDED files, queryImporters returns 0 (the new
|
|
319
|
+
// file has no IMPORTS rows in the pre-pipeline DB yet). But pre-
|
|
320
|
+
// existing unchanged files may have IMPORTS edges whose module-
|
|
321
|
+
// resolution claim the newcomer can steal under standard JS/TS
|
|
322
|
+
// resolution (Bugbot review on PR #1479). For each added file we
|
|
323
|
+
// derive the shadow candidates and, if the candidate was a known
|
|
324
|
+
// file in the prior meta, seed it into the BFS frontier so its
|
|
325
|
+
// importers — surfaced via queryImporters — get their CALLS edges
|
|
326
|
+
// re-resolved against the new file. See shadow-candidates.ts for
|
|
327
|
+
// the full pattern catalogue.
|
|
328
|
+
const priorFileSet = new Set(existingMeta?.fileHashes ? Object.keys(existingMeta.fileHashes) : []);
|
|
329
|
+
const shadowSeed = [];
|
|
330
|
+
for (const added of hashDiff.added) {
|
|
331
|
+
for (const cand of shadowCandidatesFor(added)) {
|
|
332
|
+
if (priorFileSet.has(cand) && !writableFiles.has(cand)) {
|
|
333
|
+
shadowSeed.push(cand);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
{
|
|
338
|
+
let frontier = [...hashDiff.toWrite, ...hashDiff.deleted, ...shadowSeed];
|
|
339
|
+
for (let depth = 0; depth < MAX_IMPORTER_BFS_DEPTH && frontier.length > 0; depth++) {
|
|
340
|
+
const nextFrontier = [];
|
|
341
|
+
for (const f of frontier) {
|
|
342
|
+
try {
|
|
343
|
+
const importers = await queryImporters(f);
|
|
344
|
+
for (const i of importers) {
|
|
345
|
+
if (!writableFiles.has(i)) {
|
|
346
|
+
writableFiles.add(i);
|
|
347
|
+
nextFrontier.push(i);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
/* per-file importer query failure → skip; correctness degrades on
|
|
353
|
+
that branch, but DB stays writable. */
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
frontier = nextFrontier;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const importerExpansion = writableFiles.size - directlyChangedCount;
|
|
360
|
+
if (importerExpansion > 0) {
|
|
361
|
+
log(`Incremental: +${importerExpansion} importer(s) added to writable set ` +
|
|
362
|
+
`(BFS depth ≤ ${MAX_IMPORTER_BFS_DEPTH}` +
|
|
363
|
+
(shadowSeed.length > 0 ? `, ${shadowSeed.length} shadow-seed(s)` : '') +
|
|
364
|
+
`)`);
|
|
365
|
+
}
|
|
366
|
+
// 1. Compute the EFFECTIVE write-set (Finding 1). Two layers,
|
|
367
|
+
// composed:
|
|
368
|
+
// (a) `writableFiles` — toWrite ∪ transitive importers of
|
|
369
|
+
// changed/deleted files (the bounded BFS above, reading
|
|
370
|
+
// IMPORTS from the pre-pipeline DB).
|
|
371
|
+
// (b) `computeEffectiveWriteSet` — walks the NEW graph's
|
|
372
|
+
// edges and pulls in any unchanged-side file that sits
|
|
373
|
+
// on a writable-boundary-crossing edge (catches refined
|
|
374
|
+
// cross-file CALLS edges that the pre-run DB couldn't
|
|
375
|
+
// predict, e.g. a barrel re-export shifting `foo` from
|
|
376
|
+
// B to D).
|
|
377
|
+
// The composed set is the input to BOTH deleteNodesForFile
|
|
378
|
+
// and extractChangedSubgraph — asymmetry between the two would
|
|
379
|
+
// leave stale rows or PK-conflict at COPY time.
|
|
380
|
+
const effectiveWriteSet = computeEffectiveWriteSet(pipelineResult.graph, writableFiles);
|
|
381
|
+
// Deduped: deleted entries may already appear via importer-BFS
|
|
382
|
+
// expansion (queryImporters can return a now-deleted path), which
|
|
383
|
+
// would otherwise call deleteNodesForFile twice for the same file
|
|
384
|
+
// (Bugbot LOW finding on PR #1479).
|
|
385
|
+
const filesToDelete = [...new Set([...effectiveWriteSet, ...hashDiff.deleted])];
|
|
386
|
+
for (let i = 0; i < filesToDelete.length; i++) {
|
|
387
|
+
const f = filesToDelete[i];
|
|
388
|
+
try {
|
|
389
|
+
await deleteNodesForFile(f);
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
/* file may not have rows (e.g. an unparseable file) — fine */
|
|
393
|
+
}
|
|
394
|
+
if (i % 20 === 0) {
|
|
395
|
+
progress('lbug', 62, `Removing rows for changed files (${i}/${filesToDelete.length})...`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
// 2. Drop graph-wide nodes (Community, Process). They'll be re-inserted
|
|
399
|
+
// from the fresh pipeline output below. Required for the
|
|
400
|
+
// "Leiden runs on the FULL graph" correctness invariant.
|
|
401
|
+
await deleteAllCommunitiesAndProcesses();
|
|
402
|
+
// 3. Extract the changed subgraph from the FULL ctx.graph and write
|
|
403
|
+
// only that. Unchanged-file rows in the DB stay untouched. Pass
|
|
404
|
+
// the SAME effectiveWriteSet so the subgraph and the deletes
|
|
405
|
+
// cover identical files (asymmetry would silently corrupt).
|
|
406
|
+
const subgraph = extractChangedSubgraph(pipelineResult.graph, effectiveWriteSet);
|
|
407
|
+
await loadGraphToLbug(subgraph, pipelineResult.repoPath, storagePath, (msg) => {
|
|
408
|
+
lbugMsgCount++;
|
|
409
|
+
const pct = Math.min(84, 65 + Math.round((lbugMsgCount / (lbugMsgCount + 10)) * 19));
|
|
410
|
+
progress('lbug', pct, msg);
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
// ── Full rebuild ───────────────────────────────────────────────
|
|
415
|
+
await loadGraphToLbug(pipelineResult.graph, pipelineResult.repoPath, storagePath, (msg) => {
|
|
416
|
+
lbugMsgCount++;
|
|
417
|
+
const pct = Math.min(84, 60 + Math.round((lbugMsgCount / (lbugMsgCount + 10)) * 24));
|
|
418
|
+
progress('lbug', pct, msg);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
173
421
|
// ── Phase 3: FTS (85–90%) ─────────────────────────────────────────
|
|
174
422
|
progress('fts', 85, 'Creating search indexes...');
|
|
175
423
|
await createSearchFTSIndexes();
|
|
176
424
|
progress('fts', 90, 'Search indexes ready');
|
|
177
425
|
// ── Phase 3.5: Re-insert cached embeddings ────────────────────────
|
|
426
|
+
// Runs on BOTH the full-rebuild path and the incremental path:
|
|
427
|
+
// - Full rebuild: DB was wiped, every cached row needs to come back.
|
|
428
|
+
// - Incremental: changed-file rows were just deleted by
|
|
429
|
+
// deleteNodesForFile (which cascades to their
|
|
430
|
+
// embedding rows) — so their cached vectors need
|
|
431
|
+
// to come back too. Unchanged-file rows still
|
|
432
|
+
// exist; re-inserting their cached vectors would
|
|
433
|
+
// PK-conflict, but the per-batch try/catch below
|
|
434
|
+
// silently ignores those (matches the existing
|
|
435
|
+
// "some may fail if node was removed, that's
|
|
436
|
+
// fine" semantics). Bugbot review on PR #1479
|
|
437
|
+
// flagged that gating this on `!isIncremental`
|
|
438
|
+
// silently lost changed-file embeddings.
|
|
178
439
|
if (cachedEmbeddings.length > 0) {
|
|
179
440
|
const cachedDims = cachedEmbeddings[0].embedding.length;
|
|
180
441
|
const { EMBEDDING_DIMS } = await import('./lbug/schema.js');
|
|
@@ -286,6 +547,11 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
|
|
|
286
547
|
const runtimeCapabilities = getRuntimeCapabilities();
|
|
287
548
|
const effectiveSemanticMode = semanticMode ??
|
|
288
549
|
(runtimeCapabilities.semanticMode === 'vector-index' ? 'vector-index' : 'exact-scan');
|
|
550
|
+
// Convert the post-run file-hash map to the on-disk Record<string,string>
|
|
551
|
+
// shape consumed by RepoMeta.fileHashes.
|
|
552
|
+
const newFileHashesRecord = {};
|
|
553
|
+
for (const [k, v] of newFileHashes)
|
|
554
|
+
newFileHashesRecord[k] = v;
|
|
289
555
|
const meta = {
|
|
290
556
|
repoPath,
|
|
291
557
|
lastCommit: currentCommit,
|
|
@@ -315,8 +581,32 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
|
|
|
315
581
|
reason: runtimeCapabilities.reason,
|
|
316
582
|
},
|
|
317
583
|
},
|
|
584
|
+
// Incremental-indexing fields. Populated for git repos so the next
|
|
585
|
+
// analyze run can take the incremental DB-writeback path. Setting
|
|
586
|
+
// incrementalInProgress to undefined explicitly clears any prior
|
|
587
|
+
// dirty flag (full and incremental success paths converge here).
|
|
588
|
+
schemaVersion: hasGitDir(repoPath) ? INCREMENTAL_SCHEMA_VERSION : undefined,
|
|
589
|
+
fileHashes: hasGitDir(repoPath) ? newFileHashesRecord : undefined,
|
|
590
|
+
incrementalInProgress: undefined,
|
|
318
591
|
};
|
|
319
592
|
await saveMeta(storagePath, meta);
|
|
593
|
+
// Persist the incremental parse cache for the next run. Wraps in
|
|
594
|
+
// try/catch so a cache-write failure never breaks an otherwise
|
|
595
|
+
// successful indexing run. Prune stale chunk-hash entries first so
|
|
596
|
+
// the cache file size stays bounded across runs (chunks whose
|
|
597
|
+
// composition no longer matches anything in the current scan are
|
|
598
|
+
// dead weight; the parse phase populates `usedKeys` as it processes
|
|
599
|
+
// chunks).
|
|
600
|
+
try {
|
|
601
|
+
const pruned = pruneCache(parseCache, parseCache.usedKeys);
|
|
602
|
+
if (pruned > 0) {
|
|
603
|
+
log(`Parse cache: pruned ${pruned} stale chunk entries`);
|
|
604
|
+
}
|
|
605
|
+
await saveParseCache(storagePath, parseCache);
|
|
606
|
+
}
|
|
607
|
+
catch (e) {
|
|
608
|
+
log(`Warning: could not save parse cache (${e.message}); continuing.`);
|
|
609
|
+
}
|
|
320
610
|
// Forward the --name alias and the registry-collision bypass bit.
|
|
321
611
|
// `allowDuplicateName` is its own concern — independent from the
|
|
322
612
|
// pipeline `force` above. The CLI maps it from
|
|
@@ -350,7 +640,11 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
|
|
|
350
640
|
communities: pipelineResult.communityResult?.stats.totalCommunities,
|
|
351
641
|
clusters: aggregatedClusterCount,
|
|
352
642
|
processes: pipelineResult.processResult?.stats.totalProcesses,
|
|
353
|
-
}, undefined, {
|
|
643
|
+
}, undefined, {
|
|
644
|
+
skipAgentsMd: options.skipAgentsMd,
|
|
645
|
+
skipSkills: options.skipSkills,
|
|
646
|
+
noStats: options.noStats,
|
|
647
|
+
});
|
|
354
648
|
}
|
|
355
649
|
catch {
|
|
356
650
|
// Best-effort — don't fail the entire analysis for context file issues
|
|
@@ -46,5 +46,8 @@ export declare const formatHybridResults: (results: HybridSearchResult[]) => str
|
|
|
46
46
|
* Execute BM25 + semantic search and merge with RRF.
|
|
47
47
|
* Uses LadybugDB FTS for always-fresh BM25 results (no cached data).
|
|
48
48
|
* The semanticSearch function is injected to keep this module environment-agnostic.
|
|
49
|
+
*
|
|
50
|
+
* When FTS is unavailable (e.g. read-only MCP connection, missing indexes),
|
|
51
|
+
* falls back to semantic-only results instead of crashing (#1489).
|
|
49
52
|
*/
|
|
50
53
|
export declare const hybridSearch: (query: string, limit: number, executeQuery: (cypher: string) => Promise<any[]>, semanticSearch: (executeQuery: (cypher: string) => Promise<any[]>, query: string, k?: number) => Promise<SemanticSearchResult[]>) => Promise<HybridSearchResult[]>;
|
|
@@ -23,9 +23,14 @@ const RRF_K = 60;
|
|
|
23
23
|
*/
|
|
24
24
|
export const mergeWithRRF = (bm25Results, semanticResults, limit = 10) => {
|
|
25
25
|
const merged = new Map();
|
|
26
|
+
// Guard against undefined/null inputs (#1489) — when FTS is unavailable
|
|
27
|
+
// in the MCP process, bm25Results can arrive as undefined and the
|
|
28
|
+
// for-loop would throw "bm25Results is not iterable".
|
|
29
|
+
const safeBm25 = bm25Results ?? [];
|
|
30
|
+
const safeSemantic = semanticResults ?? [];
|
|
26
31
|
// Process BM25 results
|
|
27
|
-
for (let i = 0; i <
|
|
28
|
-
const r =
|
|
32
|
+
for (let i = 0; i < safeBm25.length; i++) {
|
|
33
|
+
const r = safeBm25[i];
|
|
29
34
|
const rrfScore = 1 / (RRF_K + i + 1); // i+1 because rank starts at 1
|
|
30
35
|
merged.set(r.filePath, {
|
|
31
36
|
filePath: r.filePath,
|
|
@@ -36,8 +41,8 @@ export const mergeWithRRF = (bm25Results, semanticResults, limit = 10) => {
|
|
|
36
41
|
});
|
|
37
42
|
}
|
|
38
43
|
// Process semantic results and merge
|
|
39
|
-
for (let i = 0; i <
|
|
40
|
-
const r =
|
|
44
|
+
for (let i = 0; i < safeSemantic.length; i++) {
|
|
45
|
+
const r = safeSemantic[i];
|
|
41
46
|
const rrfScore = 1 / (RRF_K + i + 1);
|
|
42
47
|
const existing = merged.get(r.filePath);
|
|
43
48
|
if (existing) {
|
|
@@ -110,10 +115,22 @@ export const formatHybridResults = (results) => {
|
|
|
110
115
|
* Execute BM25 + semantic search and merge with RRF.
|
|
111
116
|
* Uses LadybugDB FTS for always-fresh BM25 results (no cached data).
|
|
112
117
|
* The semanticSearch function is injected to keep this module environment-agnostic.
|
|
118
|
+
*
|
|
119
|
+
* When FTS is unavailable (e.g. read-only MCP connection, missing indexes),
|
|
120
|
+
* falls back to semantic-only results instead of crashing (#1489).
|
|
113
121
|
*/
|
|
114
122
|
export const hybridSearch = async (query, limit, executeQuery, semanticSearch) => {
|
|
115
|
-
// Use LadybugDB FTS for always-fresh BM25 results
|
|
116
|
-
|
|
123
|
+
// Use LadybugDB FTS for always-fresh BM25 results.
|
|
124
|
+
// If FTS fails (e.g. extension not loaded in MCP process), fall back to
|
|
125
|
+
// semantic-only search instead of crashing with "bm25Results is not iterable".
|
|
126
|
+
let bm25Results = [];
|
|
127
|
+
try {
|
|
128
|
+
const ftsResponse = await searchFTSFromLbug(query, limit);
|
|
129
|
+
bm25Results = ftsResponse?.results ?? [];
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// FTS unavailable — continue with semantic-only search
|
|
133
|
+
}
|
|
117
134
|
const semanticResults = await semanticSearch(executeQuery, query, limit);
|
|
118
135
|
return mergeWithRRF(bm25Results, semanticResults, limit);
|
|
119
136
|
};
|
|
@@ -14,6 +14,7 @@ import path from 'path';
|
|
|
14
14
|
import { execSync, execFileSync } from 'child_process';
|
|
15
15
|
import { initWikiDb, closeWikiDb, touchWikiDb, getFilesWithExports, getAllFiles, getIntraModuleCallEdges, getInterModuleCallEdges, getProcessesForFiles, getAllProcesses, getInterModuleEdgesForOverview, } from './graph-queries.js';
|
|
16
16
|
import { generateHTMLViewer } from './html-viewer.js';
|
|
17
|
+
import { sanitizeMermaidMarkdown } from './mermaid-sanitizer.js';
|
|
17
18
|
import { callLLM, estimateTokens, } from './llm-client.js';
|
|
18
19
|
import { callCursorLLM, resolveCursorConfig } from './cursor-client.js';
|
|
19
20
|
import { GROUPING_SYSTEM_PROMPT, GROUPING_USER_PROMPT, MODULE_SYSTEM_PROMPT, MODULE_USER_PROMPT, PARENT_SYSTEM_PROMPT, PARENT_USER_PROMPT, OVERVIEW_SYSTEM_PROMPT, OVERVIEW_USER_PROMPT, fillTemplate, formatFileListForGrouping, formatDirectoryTree, formatCallEdges, formatProcesses, } from './prompts.js';
|
|
@@ -445,7 +446,7 @@ export class WikiGenerator {
|
|
|
445
446
|
});
|
|
446
447
|
const response = await this.invokeLLM(prompt, MODULE_SYSTEM_PROMPT, this.streamOpts(node.name));
|
|
447
448
|
// Write page with front matter
|
|
448
|
-
const pageContent = `# ${node.name}\n\n${response.content}
|
|
449
|
+
const pageContent = sanitizeMermaidMarkdown(`# ${node.name}\n\n${response.content}`);
|
|
449
450
|
await fs.writeFile(path.join(this.wikiDir, `${node.slug}.md`), pageContent, 'utf-8');
|
|
450
451
|
}
|
|
451
452
|
/**
|
|
@@ -480,7 +481,7 @@ export class WikiGenerator {
|
|
|
480
481
|
CROSS_PROCESSES: formatProcesses(processes),
|
|
481
482
|
});
|
|
482
483
|
const response = await this.invokeLLM(prompt, PARENT_SYSTEM_PROMPT, this.streamOpts(node.name));
|
|
483
|
-
const pageContent = `# ${node.name}\n\n${response.content}
|
|
484
|
+
const pageContent = sanitizeMermaidMarkdown(`# ${node.name}\n\n${response.content}`);
|
|
484
485
|
await fs.writeFile(path.join(this.wikiDir, `${node.slug}.md`), pageContent, 'utf-8');
|
|
485
486
|
}
|
|
486
487
|
// ─── Phase 3: Generate Overview ─────────────────────────────────────
|
|
@@ -516,7 +517,7 @@ export class WikiGenerator {
|
|
|
516
517
|
TOP_PROCESSES: formatProcesses(topProcesses),
|
|
517
518
|
});
|
|
518
519
|
const response = await this.invokeLLM(prompt, OVERVIEW_SYSTEM_PROMPT, this.streamOpts('Generating overview', 88));
|
|
519
|
-
const pageContent = `# ${path.basename(this.repoPath)} — Wiki\n\n${response.content}
|
|
520
|
+
const pageContent = sanitizeMermaidMarkdown(`# ${path.basename(this.repoPath)} — Wiki\n\n${response.content}`);
|
|
520
521
|
await fs.writeFile(path.join(this.wikiDir, 'overview.md'), pageContent, 'utf-8');
|
|
521
522
|
}
|
|
522
523
|
// ─── Incremental Updates ────────────────────────────────────────────
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import fs from 'fs/promises';
|
|
8
8
|
import path from 'path';
|
|
9
|
+
import { sanitizeMermaidMarkdown } from './mermaid-sanitizer.js';
|
|
9
10
|
/**
|
|
10
11
|
* Generate the wiki HTML viewer (index.html) from existing markdown pages.
|
|
11
12
|
*/
|
|
@@ -33,7 +34,7 @@ export async function generateHTMLViewer(wikiDir, projectName) {
|
|
|
33
34
|
const dirEntries = await fs.readdir(wikiDir);
|
|
34
35
|
for (const f of dirEntries.filter((f) => f.endsWith('.md'))) {
|
|
35
36
|
const content = await fs.readFile(path.join(wikiDir, f), 'utf-8');
|
|
36
|
-
pages[f.replace(/\.md$/, '')] = content;
|
|
37
|
+
pages[f.replace(/\.md$/, '')] = sanitizeMermaidMarkdown(content);
|
|
37
38
|
}
|
|
38
39
|
const html = buildHTML(projectName, moduleTree, pages, meta);
|
|
39
40
|
const outputPath = path.join(wikiDir, 'index.html');
|
|
@@ -19,6 +19,10 @@ export interface LLMConfig {
|
|
|
19
19
|
apiVersion?: string;
|
|
20
20
|
/** When true, strips sampling params and uses max_completion_tokens instead of max_tokens */
|
|
21
21
|
isReasoningModel?: boolean;
|
|
22
|
+
/** Per-attempt fetch timeout in ms (default: 60_000). */
|
|
23
|
+
requestTimeoutMs?: number;
|
|
24
|
+
/** Max fetch attempts before giving up (default: 3). */
|
|
25
|
+
maxAttempts?: number;
|
|
22
26
|
}
|
|
23
27
|
export interface LLMResponse {
|
|
24
28
|
content: string;
|
|
@@ -170,11 +170,11 @@ export async function callLLM(prompt, config, systemPrompt, options) {
|
|
|
170
170
|
// indefinitely on a frozen TCP connection — the per-call
|
|
171
171
|
// signal is the only timeout `resilientFetch` honors;
|
|
172
172
|
// `capDelayMs` only bounds the *backoff* between attempts.
|
|
173
|
-
// 60s
|
|
174
|
-
signal: AbortSignal.timeout(60_000),
|
|
173
|
+
// Default 60s; raise via --timeout for slow models or large pages.
|
|
174
|
+
signal: AbortSignal.timeout(config.requestTimeoutMs ?? 60_000),
|
|
175
175
|
}, {
|
|
176
176
|
breakerKey: `wiki-llm-${new URL(url).host}`,
|
|
177
|
-
retry: { maxAttempts: 3, baseDelayMs: 2_000, capDelayMs: 30_000 },
|
|
177
|
+
retry: { maxAttempts: config.maxAttempts ?? 3, baseDelayMs: 2_000, capDelayMs: 30_000 },
|
|
178
178
|
});
|
|
179
179
|
}
|
|
180
180
|
catch (err) {
|