gitnexus 1.6.10-rc.2 → 1.6.10-rc.21
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.md +56 -12
- package/dist/cli/analyze.js +166 -5
- package/dist/cli/clean.js +17 -3
- package/dist/cli/cli-message.d.ts +1 -1
- package/dist/cli/doctor.d.ts +18 -0
- package/dist/cli/doctor.js +76 -3
- package/dist/cli/embeddings.d.ts +12 -0
- package/dist/cli/embeddings.js +49 -0
- package/dist/cli/help-i18n.js +4 -0
- package/dist/cli/i18n/en.d.ts +10 -5
- package/dist/cli/i18n/en.js +10 -5
- package/dist/cli/i18n/resources.d.ts +15 -5
- package/dist/cli/i18n/zh-CN.d.ts +5 -0
- package/dist/cli/i18n/zh-CN.js +10 -5
- package/dist/cli/index.js +12 -1
- package/dist/core/augmentation/engine.js +4 -3
- package/dist/core/embeddings/embedder.js +16 -2
- package/dist/core/embeddings/embedding-pipeline.d.ts +20 -0
- package/dist/core/embeddings/embedding-pipeline.js +10 -2
- package/dist/core/embeddings/http-client.d.ts +28 -1
- package/dist/core/embeddings/http-client.js +107 -15
- package/dist/core/embeddings/node-module-compat.d.ts +23 -0
- package/dist/core/embeddings/node-module-compat.js +23 -0
- package/dist/core/embeddings/onnxruntime-common-resolver.js +6 -3
- package/dist/core/embeddings/onnxruntime-node-resolver.js +31 -5
- package/dist/core/embeddings/runtime-install.d.ts +119 -0
- package/dist/core/embeddings/runtime-install.js +372 -0
- package/dist/core/embeddings/runtime-support.d.ts +48 -17
- package/dist/core/embeddings/runtime-support.js +96 -0
- package/dist/core/group/extractors/http-patterns/python.js +246 -108
- package/dist/core/group/extractors/manifest-extractor.js +4 -0
- package/dist/core/incremental/escalation-gate.d.ts +38 -0
- package/dist/core/incremental/escalation-gate.js +48 -0
- package/dist/core/incremental/shadow-candidates.d.ts +3 -3
- package/dist/core/incremental/shadow-candidates.js +3 -3
- package/dist/core/incremental/subgraph-extract.d.ts +2 -2
- package/dist/core/incremental/subgraph-extract.js +2 -2
- package/dist/core/ingestion/cobol/jcl-processor.js +9 -8
- package/dist/core/ingestion/cobol-processor.js +27 -26
- package/dist/core/ingestion/community-processor.d.ts +51 -1
- package/dist/core/ingestion/community-processor.js +316 -63
- package/dist/core/ingestion/emit-references.js +3 -2
- package/dist/core/ingestion/languages/cpp/captures.js +157 -74
- package/dist/core/ingestion/markdown-processor.js +3 -2
- package/dist/core/ingestion/parsing-processor.d.ts +3 -1
- package/dist/core/ingestion/parsing-processor.js +4 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +42 -0
- package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +83 -0
- package/dist/core/ingestion/route-extractors/constant-resolver.js +131 -0
- package/dist/core/ingestion/route-extractors/python-const-resolver.d.ts +75 -0
- package/dist/core/ingestion/route-extractors/python-const-resolver.js +299 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +12 -1
- package/dist/core/ingestion/utils/line-base.d.ts +20 -0
- package/dist/core/ingestion/utils/line-base.js +20 -0
- package/dist/core/ingestion/utils/symbol-labels.d.ts +21 -0
- package/dist/core/ingestion/utils/symbol-labels.js +45 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +34 -0
- package/dist/core/ingestion/workers/parse-worker.js +40 -5
- package/dist/core/ingestion/workers/result-merge.js +4 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +14 -0
- package/dist/core/ingestion/workers/worker-pool.js +85 -5
- package/dist/core/lbug/csv-generator.js +8 -2
- package/dist/core/lbug/cypher-escape.d.ts +20 -0
- package/dist/core/lbug/cypher-escape.js +20 -0
- package/dist/core/lbug/extension-load-error.d.ts +67 -0
- package/dist/core/lbug/extension-load-error.js +320 -0
- package/dist/core/lbug/extension-loader.d.ts +17 -2
- package/dist/core/lbug/extension-loader.js +38 -13
- package/dist/core/lbug/lbug-adapter.d.ts +147 -1
- package/dist/core/lbug/lbug-adapter.js +390 -70
- package/dist/core/lbug/lbug-config.d.ts +28 -0
- package/dist/core/lbug/lbug-config.js +114 -4
- package/dist/core/lbug/native-check.d.ts +22 -0
- package/dist/core/lbug/native-check.js +66 -0
- package/dist/core/lbug/pool-adapter.js +10 -1
- package/dist/core/lbug/sidecar-recovery.d.ts +172 -0
- package/dist/core/lbug/sidecar-recovery.js +418 -16
- package/dist/core/platform/capabilities.js +27 -1
- package/dist/core/run-analyze.js +470 -108
- package/dist/core/search/fts-indexes.d.ts +7 -0
- package/dist/core/search/fts-indexes.js +37 -0
- package/dist/core/tree-sitter/safe-parse.d.ts +8 -3
- package/dist/core/tree-sitter/safe-parse.js +21 -7
- package/dist/core/wiki/graph-queries.js +6 -5
- package/dist/mcp/core/embedder.js +16 -2
- package/dist/mcp/local/line-display.d.ts +22 -0
- package/dist/mcp/local/line-display.js +3 -0
- package/dist/mcp/local/local-backend.d.ts +14 -0
- package/dist/mcp/local/local-backend.js +63 -19
- package/dist/mcp/local/pdg-impact.d.ts +5 -3
- package/dist/mcp/local/pdg-impact.js +5 -2
- package/dist/mcp/resources.js +1 -0
- package/dist/mcp/tools.js +1 -1
- package/dist/server/analyze-launch.d.ts +6 -0
- package/dist/server/analyze-launch.js +82 -6
- package/dist/server/api.d.ts +30 -0
- package/dist/server/api.js +63 -21
- package/dist/storage/parse-cache.js +1 -1
- package/dist/storage/repo-manager.d.ts +65 -1
- package/dist/storage/repo-manager.js +18 -1
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +50 -3
- package/hooks/claude/gitnexus-hook.cjs +59 -9
- package/package.json +5 -3
- package/scripts/cross-platform-tests.ts +43 -0
- package/scripts/ensure-fts.ts +32 -0
- package/scripts/install-duckdb-extension.mjs +85 -24
- package/scripts/run-cross-platform.ts +46 -6
- package/scripts/shard-arg.ts +30 -0
- package/web/assets/ProcessFlowModal-Dna7GkwO.js +22 -0
- package/web/assets/{agent-Dli_x7bU.js → agent-DNYDy-KA.js} +49 -49
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BVWFvYz2.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-BU5ZRITg.js +36 -0
- package/web/assets/{blockDiagram-7IZFK4PR-BkWhpzWB.js → blockDiagram-7IZFK4PR-Dut1BpTV.js} +2 -2
- package/web/assets/{c4Diagram-Y2BXMSZH-DtBvpzWD.js → c4Diagram-Y2BXMSZH-DOXVs7-C.js} +2 -2
- package/web/assets/chunk-2T2R6R2M-pkw2oXHH.js +4 -0
- package/web/assets/chunk-2UTLFMKG-CXlhF3Pt.js +1 -0
- package/web/assets/chunk-3SSMPTDK-rPsRM1x0.js +321 -0
- package/web/assets/chunk-4R4BOZG6-Be_F0JoX.js +159 -0
- package/web/assets/{chunk-6764PJDD-DpIS7hxD.js → chunk-6764PJDD-C7xxk063.js} +1 -1
- package/web/assets/{chunk-67TQ5CYL-4sNPJU1q.js → chunk-67TQ5CYL-zxhDWgyF.js} +3 -3
- package/web/assets/chunk-7FYTHRHK-CsmYIswB.js +32 -0
- package/web/assets/chunk-7J6CGLKN-AmkN8jJN.js +10 -0
- package/web/assets/chunk-7W6UQGC5-pyKGssV3.js +1 -0
- package/web/assets/chunk-C62D2QBJ-3gdL8EKc.js +1 -0
- package/web/assets/chunk-CEXFNPSA-CjwtMDkc.js +1 -0
- package/web/assets/{chunk-INKRHTLW-Nu4ri9P-.js → chunk-INKRHTLW-D9BM9HWZ.js} +1 -1
- package/web/assets/chunk-J5EP6P6S-L19oz55R.js +1 -0
- package/web/assets/{chunk-KGFNY3KK-JGMJvKCK.js → chunk-KGFNY3KK-tD2F6wxK.js} +1 -1
- package/web/assets/chunk-KGYTTC2M-zm6n242I.js +1 -0
- package/web/assets/{chunk-KRXBNO2N-BW5o0KUN.js → chunk-KRXBNO2N-C-UNuKKf.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-CfLLCywY.js → chunk-LCXTWHL2-Ba9JK-6F.js} +2 -2
- package/web/assets/{chunk-LII3EMHJ-D-jm-dLa.js → chunk-LII3EMHJ-EGx-eBIu.js} +1 -1
- package/web/assets/chunk-LRIF4GLE-C3_PqUBq.js +1 -0
- package/web/assets/{chunk-QA3QBVWF-BgRW3SXd.js → chunk-QA3QBVWF-D4cSJBf6.js} +1 -1
- package/web/assets/chunk-RERM46MO-B5dAdWpP.js +1 -0
- package/web/assets/{chunk-RG4AUYOV-CqWzWsV3.js → chunk-RG4AUYOV-OqBBMwuQ.js} +4 -4
- package/web/assets/chunk-RKZBBQEN-MyIQbGgD.js +1 -0
- package/web/assets/chunk-RLI5ZMPA-CkXZ0y0U.js +1 -0
- package/web/assets/{chunk-T2UQINTJ-DSBqkzH7.js → chunk-T2UQINTJ-BJusEiGe.js} +1 -1
- package/web/assets/chunk-UP6H54XL-BG-n7qDp.js +1 -0
- package/web/assets/chunk-UXSXWOXI-CW1_r5cS.js +1 -0
- package/web/assets/{chunk-UY5QBCOK-DyF0vyGd.js → chunk-UY5QBCOK-BCpUlARQ.js} +1 -1
- package/web/assets/chunk-VU6ZFW4Y-BeXVk45_.js +2 -0
- package/web/assets/{chunk-W44A43WB-JqMLIpR0.js → chunk-W44A43WB-BN8EQc_u.js} +1 -1
- package/web/assets/{chunk-ZXARS5L4-CxN8oiwI.js → chunk-ZXARS5L4-BI_qR2Nm.js} +1 -1
- package/web/assets/classDiagram-KGZ6W3CR-D9zSIg0x.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-D9zSIg0x.js +1 -0
- package/web/assets/cose-bilkent-UX7MHV2Q-BmnZ7Mvj.js +1 -0
- package/web/assets/dagre-ND4H6XIP-CpcV5kbl.js +4 -0
- package/web/assets/diagram-3NCE3AQN-6SMxBRpj.js +43 -0
- package/web/assets/diagram-GF46GFSD-BZEdNcRZ.js +24 -0
- package/web/assets/{diagram-HNR7UZ2L-DFCfd5LI.js → diagram-HNR7UZ2L-DxKW2a2Y.js} +2 -2
- package/web/assets/diagram-QXG6HAR7-HfTHcXX_.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-CyijUS8r.js +10 -0
- package/web/assets/{erDiagram-L5TCEMPS-8X1y6R4Y.js → erDiagram-L5TCEMPS-D0fvpWEX.js} +3 -3
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-CgFBM7e-.js +1 -0
- package/web/assets/flowDiagram-H6V6AXG4-Bvr9bbhk.js +162 -0
- package/web/assets/{ganttDiagram-JCBTUEKG-D3iL2Aet.js → ganttDiagram-JCBTUEKG-TzODrLzv.js} +2 -2
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DCJv7SII.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-ONQSwJIY.js +106 -0
- package/web/assets/index-B4eB4dNZ.js +575 -0
- package/web/assets/index-CX_fADmQ.css +2 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-BfNy-9Nd.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-DIPVUIQ6.js +2 -0
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-DfYpxnE5.js → ishikawaDiagram-BNXS4ZKH-BLjivjXL.js} +3 -3
- package/web/assets/{journeyDiagram-M6C3CM3L-CvArszLo.js → journeyDiagram-M6C3CM3L-Cetgs3NH.js} +3 -3
- package/web/assets/{kanban-definition-75IXJCU3-CpfVLLf9.js → kanban-definition-75IXJCU3-DMlCaIpf.js} +5 -5
- package/web/assets/{katex-K3KEBU37-CTc5BslQ.js → katex-K3KEBU37-qRQBy-EZ.js} +2 -2
- package/web/assets/{mindmap-definition-2TDM6QVE-DypvbOMQ.js → mindmap-definition-2TDM6QVE-B4GbXQBc.js} +3 -3
- package/web/assets/packet-YPE3B663-LP52Z2RK-D4qkeG9k.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-B_yMKyQa.js +1 -0
- package/web/assets/{pieDiagram-CU6KROY3-s27EFWgP.js → pieDiagram-CU6KROY3-D3YC_xyg.js} +2 -2
- package/web/assets/{quadrantDiagram-VICAPDV7-yXSZ2lLz.js → quadrantDiagram-VICAPDV7-B1TQnlm0.js} +2 -2
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DeD6yN_0.js +1 -0
- package/web/assets/{requirementDiagram-JXO7QTGE-CWhqInuf.js → requirementDiagram-JXO7QTGE-f8wczLQf.js} +3 -3
- package/web/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/web/assets/{sankeyDiagram-URQDO5SZ-1qEjlFIB.js → sankeyDiagram-URQDO5SZ-BTxzG5j0.js} +2 -2
- package/web/assets/{sequenceDiagram-VS2MUI6T-RyTlZ5cR.js → sequenceDiagram-VS2MUI6T-DuamM-IR.js} +5 -5
- package/web/assets/src-BNCXICdA.js +1 -0
- package/web/assets/stateDiagram-7D4R322I-Ch2pEUcw.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-7ANuoZLL.js +1 -0
- package/web/assets/{timeline-definition-O6YCAMPW-DrrqLYAf.js → timeline-definition-O6YCAMPW-07BR8R8G.js} +3 -3
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CDuSYnd4.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-imazucyJ.js +1 -0
- package/web/assets/{vennDiagram-MWXL3ELB-B0RkWAim.js → vennDiagram-MWXL3ELB-BQX2ossk.js} +4 -4
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-DqrT9tB8.js +1 -0
- package/web/assets/{wardleyDiagram-CUQ6CDDI-boUxiQ5F.js → wardleyDiagram-CUQ6CDDI-CGIJBBiK.js} +3 -3
- package/web/assets/{xychartDiagram-N2JHSOCM-BOLm0eNm.js → xychartDiagram-N2JHSOCM-B3HNMuWp.js} +4 -4
- package/web/index.html +17 -10
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +0 -1
- package/web/assets/architectureDiagram-UL44E2DR-dEkqUZN9.js +0 -36
- package/web/assets/chunk-3SSMPTDK-B4_etUhr.js +0 -321
- package/web/assets/chunk-7W6UQGC5-KyEG0HQg.js +0 -1
- package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +0 -161
- package/web/assets/classDiagram-KGZ6W3CR-CMne4tG9.js +0 -1
- package/web/assets/classDiagram-v2-72OJOZXJ-CMne4tG9.js +0 -1
- package/web/assets/cose-bilkent-UX7MHV2Q-D71wNYRJ.js +0 -1
- package/web/assets/dagre-ND4H6XIP-Co5rRx9X.js +0 -4
- package/web/assets/diagram-3NCE3AQN-DBp4O00j.js +0 -43
- package/web/assets/diagram-GF46GFSD-6N_8yS0i.js +0 -24
- package/web/assets/diagram-QXG6HAR7-Di093rFg.js +0 -24
- package/web/assets/diagram-WEQXMOUZ-DZWi4SUN.js +0 -10
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +0 -1
- package/web/assets/flowDiagram-H6V6AXG4-CMpY8Ufn.js +0 -162
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +0 -1
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +0 -106
- package/web/assets/index-KctnI3Vq.js +0 -635
- package/web/assets/index-_lgn7hs5.css +0 -2
- package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +0 -1
- package/web/assets/infoDiagram-3YFTVSEB-BaLMZkUg.js +0 -2
- package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +0 -1
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +0 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +0 -1
- package/web/assets/stateDiagram-7D4R322I-DTjVfX4A.js +0 -1
- package/web/assets/stateDiagram-v2-36443NZ5-xY9_k9_Q.js +0 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +0 -1
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +0 -1
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +0 -1
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-demand install of the optional local embedding stack (#2370).
|
|
3
|
+
*
|
|
4
|
+
* `@huggingface/transformers` and `onnxruntime-node` are optionalDependencies:
|
|
5
|
+
* npm prunes them (instead of failing the whole install) when
|
|
6
|
+
* `onnxruntime-node`'s postinstall cannot download its CUDA binaries from
|
|
7
|
+
* api.nuget.org — common behind HTTP proxies and regional firewalls, where
|
|
8
|
+
* that download ignores standard proxy env vars and 302 redirects.
|
|
9
|
+
*
|
|
10
|
+
* This module heals such an install without a reinstall: it fetches the stack
|
|
11
|
+
* into a user-level runtime prefix (`~/.gitnexus/embedding-runtime`) straight
|
|
12
|
+
* from the user's configured npm registry — honouring their mirror and proxy
|
|
13
|
+
* settings, the part of their network setup that demonstrably works — with
|
|
14
|
+
* `--ignore-scripts`, so no NuGet download is attempted at all. The CPU ONNX
|
|
15
|
+
* binding ships inside the npm tarball; only CUDA GPU acceleration needs the
|
|
16
|
+
* postinstall, and `installEmbeddingRuntime({ cuda: true })` opts into it.
|
|
17
|
+
*
|
|
18
|
+
* Resolution is package-first: a normally-installed stack always wins, and the
|
|
19
|
+
* runtime prefix is only consulted when the bare specifier does not resolve.
|
|
20
|
+
*/
|
|
21
|
+
import { createRequire } from 'node:module';
|
|
22
|
+
import { spawn, execFileSync } from 'node:child_process';
|
|
23
|
+
import { pathToFileURL } from 'node:url';
|
|
24
|
+
import { homedir } from 'node:os';
|
|
25
|
+
import { join, resolve } from 'node:path';
|
|
26
|
+
import { logger } from '../logger.js';
|
|
27
|
+
import { getRegisterHooks } from './node-module-compat.js';
|
|
28
|
+
const DEFAULT_EMBEDDING_INSTALL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
29
|
+
/** Shorter deadline for analyze's auto-install (interactive; must not stall the index run). */
|
|
30
|
+
export const ANALYZE_EMBEDDING_INSTALL_TIMEOUT_MS = 2 * 60 * 1000;
|
|
31
|
+
/**
|
|
32
|
+
* Deadline for the on-demand npm install. An explicit
|
|
33
|
+
* `GITNEXUS_EMBEDDING_INSTALL_TIMEOUT_MS` always wins (so a user on a slow
|
|
34
|
+
* mirror can raise it); otherwise `defaultMs` applies. The default is generous
|
|
35
|
+
* (the ONNX stack is a large registry fetch), but latency-sensitive callers
|
|
36
|
+
* (analyze's auto-install) pass a shorter `defaultMs` so a blackholed proxy
|
|
37
|
+
* can't stall the whole run for the full ten minutes. Mirrors
|
|
38
|
+
* `getExtensionInstallTimeoutMs`.
|
|
39
|
+
*/
|
|
40
|
+
export const getEmbeddingInstallTimeoutMs = (defaultMs = DEFAULT_EMBEDDING_INSTALL_TIMEOUT_MS) => {
|
|
41
|
+
const raw = process.env.GITNEXUS_EMBEDDING_INSTALL_TIMEOUT_MS;
|
|
42
|
+
const parsed = raw ? Number(raw) : NaN;
|
|
43
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : defaultMs;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* SIGKILL the npm child and its whole tree. npm spawns a node grandchild, and a
|
|
47
|
+
* plain SIGTERM to the direct child lets the grandchild escape (pr-2169), so on
|
|
48
|
+
* Windows use `taskkill /T /F` (mirrors `killChildTree` in local-cli-client.ts).
|
|
49
|
+
*/
|
|
50
|
+
const killNpmChild = (child) => {
|
|
51
|
+
if (process.platform === 'win32' && child.pid !== undefined) {
|
|
52
|
+
try {
|
|
53
|
+
execFileSync('taskkill', ['/T', '/F', '/PID', String(child.pid)], {
|
|
54
|
+
stdio: 'ignore',
|
|
55
|
+
windowsHide: true,
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Already exited — fall through to child.kill().
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
child.kill('SIGKILL');
|
|
64
|
+
};
|
|
65
|
+
const require = createRequire(import.meta.url);
|
|
66
|
+
/** The stack the runtime prefix provides; resolution fallback covers all three. */
|
|
67
|
+
const EMBEDDING_STACK_PACKAGES = [
|
|
68
|
+
'@huggingface/transformers',
|
|
69
|
+
'onnxruntime-node',
|
|
70
|
+
'onnxruntime-common',
|
|
71
|
+
];
|
|
72
|
+
/**
|
|
73
|
+
* User-level prefix the on-demand stack installs into. The env override is
|
|
74
|
+
* `path.resolve`d once here (the single chokepoint) so a relative or empty
|
|
75
|
+
* value can't poison the probes downstream — `createRequire` throws
|
|
76
|
+
* `ERR_INVALID_ARG_VALUE` on a relative anchor, which otherwise made every
|
|
77
|
+
* resolution report "not installed" and reinstall on every run. An empty or
|
|
78
|
+
* whitespace-only value falls through to the default.
|
|
79
|
+
*/
|
|
80
|
+
export const getEmbeddingRuntimeDir = () => {
|
|
81
|
+
const override = process.env.GITNEXUS_EMBEDDING_RUNTIME_DIR?.trim();
|
|
82
|
+
return override ? resolve(override) : join(homedir(), '.gitnexus', 'embedding-runtime');
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* The version specs to install — read from gitnexus' own package.json
|
|
86
|
+
* `optionalDependencies` so the on-demand install can never drift from what a
|
|
87
|
+
* normal install would have provided. (The manifest ships in the tarball even
|
|
88
|
+
* when npm pruned the packages themselves.)
|
|
89
|
+
*/
|
|
90
|
+
export const getEmbeddingStackSpecs = () => {
|
|
91
|
+
const manifest = require('../../../package.json');
|
|
92
|
+
const optional = manifest.optionalDependencies ?? {};
|
|
93
|
+
return Object.fromEntries(['@huggingface/transformers', 'onnxruntime-node']
|
|
94
|
+
.filter((name) => optional[name] !== undefined)
|
|
95
|
+
.map((name) => [name, optional[name]]));
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Whether a runtime-prefix-sourced stack can actually be loaded on this Node
|
|
99
|
+
* (#2372). The prefix mechanism re-anchors bare specifiers via
|
|
100
|
+
* `module.registerHooks`, absent before Node 22.15 / 23.5 — so on 22.0–22.14 and
|
|
101
|
+
* 23.0–23.4 a populated prefix exists but the ESM loader can never reach it. A
|
|
102
|
+
* package-sourced stack never needs the hook and is unaffected. CLI code
|
|
103
|
+
* consumes this predicate (never the compat module directly) to keep messaging
|
|
104
|
+
* truthful instead of promising a prefix runtime the loader can't use.
|
|
105
|
+
*/
|
|
106
|
+
export const isPrefixRuntimeLoadable = () => typeof getRegisterHooks() === 'function';
|
|
107
|
+
/** Resolution anchored inside the runtime prefix (`<dir>/node_modules`). */
|
|
108
|
+
const prefixRequire = () => createRequire(join(getEmbeddingRuntimeDir(), 'noop.js'));
|
|
109
|
+
/**
|
|
110
|
+
* True when BOTH load-bearing stack packages resolve from `req`. Probing
|
|
111
|
+
* `@huggingface/transformers` alone is not enough: an interrupted or partial
|
|
112
|
+
* prefix install (transformers extracted, `onnxruntime-node` not yet) would
|
|
113
|
+
* otherwise read as "installed", suppress the self-heal, and fail later at model
|
|
114
|
+
* load. `onnxruntime-common` stays un-probed — it is a regular dependency the
|
|
115
|
+
* #307 resolver owns, never pruned.
|
|
116
|
+
*/
|
|
117
|
+
const stackResolvesFrom = (req) => {
|
|
118
|
+
try {
|
|
119
|
+
req.resolve('@huggingface/transformers');
|
|
120
|
+
req.resolve('onnxruntime-node');
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Where the embedding stack resolves from, or `null` when it is not (fully)
|
|
129
|
+
* installed. Resolution only — nothing is imported, so this never loads native
|
|
130
|
+
* code and is safe on every platform.
|
|
131
|
+
*/
|
|
132
|
+
export const resolveEmbeddingRuntime = () => {
|
|
133
|
+
if (stackResolvesFrom(require))
|
|
134
|
+
return { source: 'package' };
|
|
135
|
+
if (stackResolvesFrom(prefixRequire()))
|
|
136
|
+
return { source: 'runtime-prefix' };
|
|
137
|
+
return null;
|
|
138
|
+
};
|
|
139
|
+
let hookAttempted = false;
|
|
140
|
+
// While set, the resolve hook passes straight through. It guards the
|
|
141
|
+
// `resolveEmbeddingRuntime()` probe inside the onnxruntime-common gate below:
|
|
142
|
+
// today `require.resolve` bypasses these sync hooks, so the probe can't re-enter
|
|
143
|
+
// the chain — but the latch makes that acyclicity STRUCTURAL rather than relying
|
|
144
|
+
// on that (undocumented, version-specific — verified on Node 22.16) behaviour.
|
|
145
|
+
let hookReentrant = false;
|
|
146
|
+
/** Whether the stack itself resolved from the runtime prefix — re-entrancy-guarded. */
|
|
147
|
+
const stackIsPrefixSourced = () => {
|
|
148
|
+
hookReentrant = true;
|
|
149
|
+
try {
|
|
150
|
+
return resolveEmbeddingRuntime()?.source === 'runtime-prefix';
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
hookReentrant = false;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Idempotently register the resolution fallback that redirects the embedding
|
|
158
|
+
* stack's bare specifiers to the runtime prefix when normal resolution fails.
|
|
159
|
+
* Mirrors the onnxruntime-common fallback hook (#307): try the default
|
|
160
|
+
* resolution first so a real, package-manager-installed copy always wins, and
|
|
161
|
+
* only re-anchor at the prefix on ERR_MODULE_NOT_FOUND.
|
|
162
|
+
*
|
|
163
|
+
* Must be registered BEFORE the CUDA-13 redirect hook
|
|
164
|
+
* (`ensureOnnxRuntimeNodeMatchesSystem`) — `registerHooks` runs the most
|
|
165
|
+
* recently registered hook first, so registering this one earliest makes it
|
|
166
|
+
* the last-resort fallback in the chain.
|
|
167
|
+
*/
|
|
168
|
+
export const ensureEmbeddingStackResolvable = () => {
|
|
169
|
+
if (hookAttempted)
|
|
170
|
+
return;
|
|
171
|
+
hookAttempted = true;
|
|
172
|
+
try {
|
|
173
|
+
// Node < 22.15 / < 23.5 (engines floor is >= 22.0.0): no synchronous hooks
|
|
174
|
+
// API. Degrade gracefully — normally-installed stacks still resolve; only
|
|
175
|
+
// the runtime-prefix fallback is unavailable. Reachable now that the import
|
|
176
|
+
// is a namespace access (see node-module-compat.ts) rather than a static
|
|
177
|
+
// named import that would fail at link time.
|
|
178
|
+
const registerHooks = getRegisterHooks();
|
|
179
|
+
if (typeof registerHooks !== 'function')
|
|
180
|
+
return;
|
|
181
|
+
registerHooks({
|
|
182
|
+
resolve(specifier, context, nextResolve) {
|
|
183
|
+
if (hookReentrant || !EMBEDDING_STACK_PACKAGES.includes(specifier)) {
|
|
184
|
+
return nextResolve(specifier, context);
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
return nextResolve(specifier, context);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
const code = err?.code;
|
|
191
|
+
// ESM-only allowlist: never add the CJS `MODULE_NOT_FOUND` — that is
|
|
192
|
+
// what keeps the source probe below (which uses `require.resolve`)
|
|
193
|
+
// from feeding its own miss back into the chain.
|
|
194
|
+
if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') {
|
|
195
|
+
throw err;
|
|
196
|
+
}
|
|
197
|
+
// onnxruntime-common is version-paired by the #307 resolver, which sits
|
|
198
|
+
// ABOVE this last-resort fallback. Only steal its phantom-import case
|
|
199
|
+
// when the stack itself came from the prefix — otherwise a leftover
|
|
200
|
+
// user-global prefix would hijack #307 for a package-sourced stack and
|
|
201
|
+
// pair a package onnxruntime-node with a version-drifted prefix common.
|
|
202
|
+
if (specifier === 'onnxruntime-common' && !stackIsPrefixSourced()) {
|
|
203
|
+
throw err;
|
|
204
|
+
}
|
|
205
|
+
// Re-anchor at the runtime prefix so Node applies the package's own
|
|
206
|
+
// exports conditions (ESM/CJS) exactly as a normal install would. The
|
|
207
|
+
// anchor is read here (not at registration) so it stays coherent with
|
|
208
|
+
// the current GITNEXUS_EMBEDDING_RUNTIME_DIR.
|
|
209
|
+
const prefixAnchor = pathToFileURL(join(getEmbeddingRuntimeDir(), 'noop.js')).href;
|
|
210
|
+
return nextResolve(specifier, { ...context, parentURL: prefixAnchor });
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
logger.debug({ prefix: getEmbeddingRuntimeDir() }, 'Installed embedding-runtime resolution fallback (#2370)');
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
logger.debug({ err: err instanceof Error ? err.message : String(err) }, 'embedding-runtime resolution fallback not installed');
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
/** Pure command builder, exported for tests. */
|
|
221
|
+
export const buildEmbeddingInstallCommand = (opts = {}) => {
|
|
222
|
+
const specs = getEmbeddingStackSpecs();
|
|
223
|
+
const args = [
|
|
224
|
+
'install',
|
|
225
|
+
'--prefix',
|
|
226
|
+
getEmbeddingRuntimeDir(),
|
|
227
|
+
'--no-fund',
|
|
228
|
+
'--no-audit',
|
|
229
|
+
'--loglevel',
|
|
230
|
+
'error',
|
|
231
|
+
...(opts.cuda ? [] : ['--ignore-scripts']),
|
|
232
|
+
...Object.entries(specs).map(([name, spec]) => `${name}@${spec}`),
|
|
233
|
+
];
|
|
234
|
+
const env = { ...process.env };
|
|
235
|
+
if (opts.cuda) {
|
|
236
|
+
// --cuda opts into the NuGet CUDA download. A user who exported
|
|
237
|
+
// ONNXRUNTIME_NODE_INSTALL=skip per our proxy docs must not have it silently
|
|
238
|
+
// suppress that download and then be told the install succeeded.
|
|
239
|
+
delete env.ONNXRUNTIME_NODE_INSTALL;
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
env.ONNXRUNTIME_NODE_INSTALL = 'skip';
|
|
243
|
+
}
|
|
244
|
+
return { args, env };
|
|
245
|
+
};
|
|
246
|
+
/** cmd.exe metacharacters that force quoting (plus whitespace), per Colascione. */
|
|
247
|
+
const WIN32_NEEDS_QUOTING = /[\s&|<>^()%!]/;
|
|
248
|
+
/**
|
|
249
|
+
* Quote a single argument for the Windows `cmd.exe` shell (#2372). npm is a
|
|
250
|
+
* `.cmd` shim, so the spawn must go through a shell (EINVAL otherwise since
|
|
251
|
+
* CVE-2024-27980), and Node does NOT escape args under `shell: true` — a spaced
|
|
252
|
+
* `--prefix` path splits, and cmd eats the `^` in `@pkg@^1.0.0` semver ranges.
|
|
253
|
+
*
|
|
254
|
+
* Rules (validated against Node source, MS cmd/CRT docs, BatBadBut, Rust std):
|
|
255
|
+
* reject NUL/CR/LF and embedded `"` (both unrepresentable/unsafe at the cmd
|
|
256
|
+
* layer, and `"` is illegal in Windows paths and npm specs); wrap in double
|
|
257
|
+
* quotes when empty or containing whitespace/metacharacters; double the trailing
|
|
258
|
+
* backslash run so the added closing quote is not itself escaped (`C:\` →
|
|
259
|
+
* `"C:\\"`). `^` is literal inside cmd double quotes across all three parse
|
|
260
|
+
* layers (cmd `/c` → npm.cmd's `%*` re-parse → node CRT argv). Two documented
|
|
261
|
+
* ceilings quoting can't close: a defined `%VAR%` expands once at the first cmd
|
|
262
|
+
* parse, and `!` expands only under registry-enabled delayed expansion — both
|
|
263
|
+
* are the env-var owner's trust, out of the malicious-repo threat model.
|
|
264
|
+
*/
|
|
265
|
+
export const quoteWin32Arg = (arg) => {
|
|
266
|
+
if (/[\0\r\n]/.test(arg)) {
|
|
267
|
+
throw new Error(`argument contains NUL/CR/LF, unsafe for the Windows shell: ${JSON.stringify(arg)}`);
|
|
268
|
+
}
|
|
269
|
+
if (arg.includes('"')) {
|
|
270
|
+
throw new Error(`argument contains a double quote, unsafe for the Windows shell: ${JSON.stringify(arg)}`);
|
|
271
|
+
}
|
|
272
|
+
if (arg !== '' && !WIN32_NEEDS_QUOTING.test(arg))
|
|
273
|
+
return arg;
|
|
274
|
+
const trailingBackslashes = /\\*$/.exec(arg)?.[0].length ?? 0;
|
|
275
|
+
return `"${arg}${'\\'.repeat(trailingBackslashes)}"`;
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Compose a full `cmd.exe` command line: the command stays unquoted (so
|
|
279
|
+
* PATH/PATHEXT resolves a bare name or `.cmd` shim), args are individually
|
|
280
|
+
* quoted. Passing this as spawn's first (only) string argument — no args array
|
|
281
|
+
* — yields a byte-identical `cmd.exe /d /s /c "…"` line while avoiding DEP0190
|
|
282
|
+
* (the runtime deprecation warning Node >=24 emits for
|
|
283
|
+
* `spawn(file, args, {shell:true})`). Exported generically so the real-cmd.exe
|
|
284
|
+
* round-trip test drives the exact same composition the npm spawn uses.
|
|
285
|
+
*/
|
|
286
|
+
export const composeWin32Command = (command, args) => [command, ...args.map(quoteWin32Arg)].join(' ');
|
|
287
|
+
/** {@link composeWin32Command} for the on-demand npm install (`npm` stays unquoted). */
|
|
288
|
+
export const composeWin32NpmCommand = (args) => composeWin32Command('npm', args);
|
|
289
|
+
/**
|
|
290
|
+
* Install (or update) the embedding stack into the runtime prefix via the
|
|
291
|
+
* user's npm — registry, mirror, and proxy configuration all apply. Rejects
|
|
292
|
+
* with npm's tail output on failure or timeout.
|
|
293
|
+
*
|
|
294
|
+
* The child is bounded by `timeoutMs` (default {@link getEmbeddingInstallTimeoutMs})
|
|
295
|
+
* and SIGKILLed — with its grandchildren — if it overruns, so a blackholed
|
|
296
|
+
* proxy (the exact #2370 environment) can't hang the caller forever. It is also
|
|
297
|
+
* killed if the parent exits mid-install, so a leftover npm can't keep writing
|
|
298
|
+
* into the shared prefix.
|
|
299
|
+
*/
|
|
300
|
+
export const installEmbeddingRuntime = async (opts = {}, timeoutMs = getEmbeddingInstallTimeoutMs()) => {
|
|
301
|
+
const { args, env } = buildEmbeddingInstallCommand(opts);
|
|
302
|
+
await new Promise((resolve, reject) => {
|
|
303
|
+
// Windows `npm` is a `.cmd` shim, so the spawn must go through a shell.
|
|
304
|
+
// Compose the quoted command line ourselves and pass it as spawn's single
|
|
305
|
+
// string arg (no args array) so cmd.exe receives correctly-quoted paths/
|
|
306
|
+
// specs and Node >=24 doesn't warn (DEP0190). POSIX uses the array form.
|
|
307
|
+
// cwd: homedir() so npm reads its config from the user's home, never the
|
|
308
|
+
// analyzed repo's cwd — a project-local .npmrc there can't redirect the
|
|
309
|
+
// registry into the prefix we then load in-process (legacy npm; refuted on
|
|
310
|
+
// npm 10, but this closes the class regardless of npm version).
|
|
311
|
+
const child = process.platform === 'win32'
|
|
312
|
+
? spawn(composeWin32NpmCommand(args), {
|
|
313
|
+
env,
|
|
314
|
+
cwd: homedir(),
|
|
315
|
+
windowsHide: true,
|
|
316
|
+
shell: true,
|
|
317
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
318
|
+
})
|
|
319
|
+
: spawn('npm', args, {
|
|
320
|
+
env,
|
|
321
|
+
cwd: homedir(),
|
|
322
|
+
windowsHide: true,
|
|
323
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
324
|
+
});
|
|
325
|
+
let tail = '';
|
|
326
|
+
const onChunk = (chunk) => {
|
|
327
|
+
const text = chunk.toString();
|
|
328
|
+
tail = (tail + text).slice(-2000);
|
|
329
|
+
if (opts.onOutput)
|
|
330
|
+
text.split('\n').filter(Boolean).forEach(opts.onOutput);
|
|
331
|
+
};
|
|
332
|
+
child.stdout?.on('data', onChunk);
|
|
333
|
+
child.stderr?.on('data', onChunk);
|
|
334
|
+
let settled = false;
|
|
335
|
+
// Kill a still-running npm if the parent exits (analyze's SIGINT handler, or
|
|
336
|
+
// a crash) so it can't keep writing into the shared prefix. Removed on settle.
|
|
337
|
+
const onParentExit = () => killNpmChild(child);
|
|
338
|
+
process.on('exit', onParentExit);
|
|
339
|
+
const cleanup = () => {
|
|
340
|
+
process.removeListener('exit', onParentExit);
|
|
341
|
+
};
|
|
342
|
+
const timer = setTimeout(() => {
|
|
343
|
+
if (settled)
|
|
344
|
+
return;
|
|
345
|
+
settled = true;
|
|
346
|
+
cleanup();
|
|
347
|
+
killNpmChild(child);
|
|
348
|
+
reject(new Error(`npm install of the embedding runtime timed out after ${timeoutMs}ms ` +
|
|
349
|
+
`(override with GITNEXUS_EMBEDDING_INSTALL_TIMEOUT_MS) — check your proxy/registry:\n${tail}`));
|
|
350
|
+
}, timeoutMs);
|
|
351
|
+
child.on('error', (err) => {
|
|
352
|
+
if (settled)
|
|
353
|
+
return;
|
|
354
|
+
settled = true;
|
|
355
|
+
clearTimeout(timer);
|
|
356
|
+
cleanup();
|
|
357
|
+
reject(err);
|
|
358
|
+
});
|
|
359
|
+
child.on('close', (exitCode, signal) => {
|
|
360
|
+
if (settled)
|
|
361
|
+
return;
|
|
362
|
+
settled = true;
|
|
363
|
+
clearTimeout(timer);
|
|
364
|
+
cleanup();
|
|
365
|
+
if (exitCode === 0)
|
|
366
|
+
resolve();
|
|
367
|
+
else
|
|
368
|
+
reject(new Error(`npm install of the embedding runtime failed ` +
|
|
369
|
+
`(${signal ? `killed with ${signal}` : `exit ${exitCode}`}):\n${tail}`));
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
};
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Local embedding runtime support guard.
|
|
3
|
-
*
|
|
4
|
-
* The bundled local embedding stack (`@huggingface/transformers` →
|
|
5
|
-
* `onnxruntime-node`) only ships native ONNX Runtime bindings for a subset of
|
|
6
|
-
* platform/arch pairs. On macOS Intel (`darwin`/`x64`), `onnxruntime-node`
|
|
7
|
-
* ships no `bin/napi-v6/darwin/x64/onnxruntime_binding.node`, so *importing*
|
|
8
|
-
* transformers.js throws a raw `Cannot find module ...onnxruntime_binding.node`
|
|
9
|
-
* before any device/backend selection can run (#1515). `ONNX_WEB_BACKEND=wasm`
|
|
10
|
-
* cannot rescue this — the failure is at native-module import time, not backend
|
|
11
|
-
* selection (#1516).
|
|
12
|
-
*
|
|
13
|
-
* This module is intentionally free of any native or transformers.js import (at
|
|
14
|
-
* module scope or inside its functions) so it can be consulted *before* the
|
|
15
|
-
* dynamic import that would crash. HTTP embedding mode never touches the native
|
|
16
|
-
* runtime, so callers in HTTP mode must skip this guard.
|
|
17
|
-
*/
|
|
18
1
|
export interface LocalEmbeddingRuntimeOptions {
|
|
19
2
|
platform?: NodeJS.Platform;
|
|
20
3
|
arch?: NodeJS.Architecture;
|
|
@@ -39,3 +22,51 @@ export declare const getLocalEmbeddingRuntimeBlocker: (options?: LocalEmbeddingR
|
|
|
39
22
|
* full wording.
|
|
40
23
|
*/
|
|
41
24
|
export declare const isLocalEmbeddingRuntimeBlockerMessage: (message: string) => boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The full guidance shown when the optional local embedding stack
|
|
27
|
+
* (`@huggingface/transformers` → `onnxruntime-node`) is missing at runtime.
|
|
28
|
+
*
|
|
29
|
+
* Both packages are `optionalDependencies` (#2370): `onnxruntime-node`'s
|
|
30
|
+
* postinstall downloads CUDA support binaries from api.nuget.org, which fails
|
|
31
|
+
* behind HTTP proxies and regional firewalls (its `global-agent` proxy layer
|
|
32
|
+
* ignores the standard HTTP_PROXY/HTTPS_PROXY vars and rejects 302 redirects).
|
|
33
|
+
* npm then skips the optional subtree instead of failing the whole install —
|
|
34
|
+
* every GitNexus feature except local embeddings keeps working.
|
|
35
|
+
*/
|
|
36
|
+
export declare const localEmbeddingStackMissingMessage: () => string;
|
|
37
|
+
/**
|
|
38
|
+
* Guidance when the runtime-prefix stack cannot be used because this Node lacks
|
|
39
|
+
* `module.registerHooks` (added in 22.15 / 23.5) — whether the prefix is already
|
|
40
|
+
* populated or not, this Node's ESM loader can never reach a prefix-installed
|
|
41
|
+
* copy (#2372). A normally-installed (package) stack never needs the hook and
|
|
42
|
+
* never hits this. State-neutral lead (it applies both when the prefix is
|
|
43
|
+
* populated and when nothing is installed) plus capability-first wording — a
|
|
44
|
+
* bare ">= 22.15" is untruthful for a 23.0–23.4 user whose version is
|
|
45
|
+
* numerically greater yet still lacks the API.
|
|
46
|
+
*/
|
|
47
|
+
export declare const localEmbeddingPrefixUnloadableMessage: () => string;
|
|
48
|
+
/**
|
|
49
|
+
* When `err` is a module-not-found failure for the optional local embedding
|
|
50
|
+
* stack, return the actionable {@link localEmbeddingStackMissingMessage};
|
|
51
|
+
* otherwise `null` so genuine load errors surface unchanged.
|
|
52
|
+
*
|
|
53
|
+
* Matches on the error `code` (ERR_MODULE_NOT_FOUND for ESM `import()`,
|
|
54
|
+
* MODULE_NOT_FOUND for CJS require) plus the missing specifier in the message,
|
|
55
|
+
* so an unrelated module-not-found inside transformers.js is not misreported
|
|
56
|
+
* as a pruned install.
|
|
57
|
+
*/
|
|
58
|
+
export declare const getMissingLocalEmbeddingStackMessage: (err: unknown) => string | null;
|
|
59
|
+
/**
|
|
60
|
+
* True when `message` is the missing-optional-stack message produced by
|
|
61
|
+
* {@link localEmbeddingStackMissingMessage}. CLI counterpart of
|
|
62
|
+
* {@link isLocalEmbeddingRuntimeBlockerMessage}.
|
|
63
|
+
*/
|
|
64
|
+
export declare const isMissingLocalEmbeddingStackMessage: (message: string) => boolean;
|
|
65
|
+
/**
|
|
66
|
+
* True when the optional local embedding stack resolves from this install —
|
|
67
|
+
* either the normally-installed packages or the on-demand runtime prefix.
|
|
68
|
+
* Resolution only — nothing is imported, so this is safe on every platform
|
|
69
|
+
* (including macOS Intel, where *loading* onnxruntime-node would crash).
|
|
70
|
+
* Used by `doctor` to surface a pruned optional install (#2370) up front.
|
|
71
|
+
*/
|
|
72
|
+
export declare const isLocalEmbeddingStackInstalled: () => boolean;
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
* module scope or inside its functions) so it can be consulted *before* the
|
|
15
15
|
* dynamic import that would crash. HTTP embedding mode never touches the native
|
|
16
16
|
* runtime, so callers in HTTP mode must skip this guard.
|
|
17
|
+
* (The runtime-install import below only resolves paths — it never loads the
|
|
18
|
+
* embedding stack.)
|
|
17
19
|
*/
|
|
20
|
+
import { resolveEmbeddingRuntime } from './runtime-install.js';
|
|
18
21
|
/**
|
|
19
22
|
* Stable lead line of the macOS-Intel blocker message. Also used to recognise
|
|
20
23
|
* the thrown error in the CLI error handler without coupling to the full
|
|
@@ -63,3 +66,96 @@ export const getLocalEmbeddingRuntimeBlocker = (options = {}) => {
|
|
|
63
66
|
* full wording.
|
|
64
67
|
*/
|
|
65
68
|
export const isLocalEmbeddingRuntimeBlockerMessage = (message) => message.includes(LOCAL_EMBEDDING_BLOCKER_LEAD);
|
|
69
|
+
/**
|
|
70
|
+
* Stable lead line of the missing-optional-stack message. Mirrors
|
|
71
|
+
* {@link LOCAL_EMBEDDING_BLOCKER_LEAD}: the CLI error handler matches on this
|
|
72
|
+
* line (see {@link isMissingLocalEmbeddingStackMessage}).
|
|
73
|
+
*/
|
|
74
|
+
const LOCAL_EMBEDDING_STACK_MISSING_LEAD = 'Local semantic embeddings are unavailable: the optional embedding stack is not installed.';
|
|
75
|
+
/**
|
|
76
|
+
* The full guidance shown when the optional local embedding stack
|
|
77
|
+
* (`@huggingface/transformers` → `onnxruntime-node`) is missing at runtime.
|
|
78
|
+
*
|
|
79
|
+
* Both packages are `optionalDependencies` (#2370): `onnxruntime-node`'s
|
|
80
|
+
* postinstall downloads CUDA support binaries from api.nuget.org, which fails
|
|
81
|
+
* behind HTTP proxies and regional firewalls (its `global-agent` proxy layer
|
|
82
|
+
* ignores the standard HTTP_PROXY/HTTPS_PROXY vars and rejects 302 redirects).
|
|
83
|
+
* npm then skips the optional subtree instead of failing the whole install —
|
|
84
|
+
* every GitNexus feature except local embeddings keeps working.
|
|
85
|
+
*/
|
|
86
|
+
export const localEmbeddingStackMissingMessage = () => [
|
|
87
|
+
LOCAL_EMBEDDING_STACK_MISSING_LEAD,
|
|
88
|
+
'npm skipped the optional packages @huggingface/transformers / onnxruntime-node',
|
|
89
|
+
"during install — usually because onnxruntime-node's postinstall could not",
|
|
90
|
+
'download its CUDA support binaries from api.nuget.org (common behind HTTP',
|
|
91
|
+
'proxies and regional firewalls, #2370). Everything except local embeddings',
|
|
92
|
+
'still works.',
|
|
93
|
+
'',
|
|
94
|
+
'To enable local embeddings:',
|
|
95
|
+
' - Run `gitnexus embeddings install` — fetches the stack on demand through',
|
|
96
|
+
' your npm registry config (mirrors and proxies apply; no NuGet download).',
|
|
97
|
+
' `gitnexus analyze --embeddings` does this automatically.',
|
|
98
|
+
' Add --cuda on CUDA GPU hosts (behind a proxy, also set',
|
|
99
|
+
' GLOBAL_AGENT_HTTPS_PROXY=<proxy-url> for the NuGet download).',
|
|
100
|
+
' - Or reinstall with the CUDA download skipped (CPU embeddings need no CUDA):',
|
|
101
|
+
' ONNXRUNTIME_NODE_INSTALL=skip npm install -g gitnexus',
|
|
102
|
+
' (Windows: set ONNXRUNTIME_NODE_INSTALL=skip && npm install -g gitnexus)',
|
|
103
|
+
' - Or point GITNEXUS_EMBEDDING_URL (with GITNEXUS_EMBEDDING_MODEL) at an',
|
|
104
|
+
' OpenAI-compatible /v1/embeddings endpoint to embed over HTTP.',
|
|
105
|
+
].join('\n');
|
|
106
|
+
/** Stable lead line of the prefix-unloadable message (mirrors the leads above). */
|
|
107
|
+
const LOCAL_EMBEDDING_PREFIX_UNLOADABLE_LEAD = 'The on-demand embedding runtime cannot be loaded on this Node build.';
|
|
108
|
+
/**
|
|
109
|
+
* Guidance when the runtime-prefix stack cannot be used because this Node lacks
|
|
110
|
+
* `module.registerHooks` (added in 22.15 / 23.5) — whether the prefix is already
|
|
111
|
+
* populated or not, this Node's ESM loader can never reach a prefix-installed
|
|
112
|
+
* copy (#2372). A normally-installed (package) stack never needs the hook and
|
|
113
|
+
* never hits this. State-neutral lead (it applies both when the prefix is
|
|
114
|
+
* populated and when nothing is installed) plus capability-first wording — a
|
|
115
|
+
* bare ">= 22.15" is untruthful for a 23.0–23.4 user whose version is
|
|
116
|
+
* numerically greater yet still lacks the API.
|
|
117
|
+
*/
|
|
118
|
+
export const localEmbeddingPrefixUnloadableMessage = () => [
|
|
119
|
+
LOCAL_EMBEDDING_PREFIX_UNLOADABLE_LEAD,
|
|
120
|
+
'The runtime prefix loads via module.registerHooks, which needs Node',
|
|
121
|
+
'>= 22.15 (on the 22.x line) or >= 23.5 (on the 23.x line). Either:',
|
|
122
|
+
' - Upgrade Node to a build that has module.registerHooks, or',
|
|
123
|
+
' - Reinstall the packages normally (works on every supported Node):',
|
|
124
|
+
' ONNXRUNTIME_NODE_INSTALL=skip npm install -g gitnexus',
|
|
125
|
+
' (Windows: set ONNXRUNTIME_NODE_INSTALL=skip && npm install -g gitnexus)',
|
|
126
|
+
].join('\n');
|
|
127
|
+
/** Module specifiers whose absence means the optional embedding stack was pruned. */
|
|
128
|
+
const EMBEDDING_STACK_SPECIFIERS = ['@huggingface/transformers', 'onnxruntime-node'];
|
|
129
|
+
/**
|
|
130
|
+
* When `err` is a module-not-found failure for the optional local embedding
|
|
131
|
+
* stack, return the actionable {@link localEmbeddingStackMissingMessage};
|
|
132
|
+
* otherwise `null` so genuine load errors surface unchanged.
|
|
133
|
+
*
|
|
134
|
+
* Matches on the error `code` (ERR_MODULE_NOT_FOUND for ESM `import()`,
|
|
135
|
+
* MODULE_NOT_FOUND for CJS require) plus the missing specifier in the message,
|
|
136
|
+
* so an unrelated module-not-found inside transformers.js is not misreported
|
|
137
|
+
* as a pruned install.
|
|
138
|
+
*/
|
|
139
|
+
export const getMissingLocalEmbeddingStackMessage = (err) => {
|
|
140
|
+
if (!(err instanceof Error))
|
|
141
|
+
return null;
|
|
142
|
+
const code = err.code;
|
|
143
|
+
if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND')
|
|
144
|
+
return null;
|
|
145
|
+
const namesStack = EMBEDDING_STACK_SPECIFIERS.some((s) => err.message.includes(`'${s}'`));
|
|
146
|
+
return namesStack ? localEmbeddingStackMissingMessage() : null;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* True when `message` is the missing-optional-stack message produced by
|
|
150
|
+
* {@link localEmbeddingStackMissingMessage}. CLI counterpart of
|
|
151
|
+
* {@link isLocalEmbeddingRuntimeBlockerMessage}.
|
|
152
|
+
*/
|
|
153
|
+
export const isMissingLocalEmbeddingStackMessage = (message) => message.includes(LOCAL_EMBEDDING_STACK_MISSING_LEAD);
|
|
154
|
+
/**
|
|
155
|
+
* True when the optional local embedding stack resolves from this install —
|
|
156
|
+
* either the normally-installed packages or the on-demand runtime prefix.
|
|
157
|
+
* Resolution only — nothing is imported, so this is safe on every platform
|
|
158
|
+
* (including macOS Intel, where *loading* onnxruntime-node would crash).
|
|
159
|
+
* Used by `doctor` to surface a pruned optional install (#2370) up front.
|
|
160
|
+
*/
|
|
161
|
+
export const isLocalEmbeddingStackInstalled = () => resolveEmbeddingRuntime() !== null;
|