gitnexus 1.6.10-rc.4 → 1.6.10-rc.6

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.
@@ -5,6 +5,7 @@ import { getLocalEmbeddingRuntimeBlocker, localEmbeddingPrefixUnloadableMessage,
5
5
  import { isPrefixRuntimeLoadable, resolveEmbeddingRuntime, } from '../core/embeddings/runtime-install.js';
6
6
  import { cudaRedirectDoctorStatus } from '../core/embeddings/onnxruntime-node-resolver.js';
7
7
  import { checkLbugNative, probeFtsExtensionLoad } from '../core/lbug/native-check.js';
8
+ import { diagnoseExtensionLoad } from '../core/lbug/extension-load-error.js';
8
9
  import { getExtensionInstallPolicy } from '../core/lbug/extension-loader.js';
9
10
  import { t } from './i18n/index.js';
10
11
  function isCombiningMark(codePoint) {
@@ -116,6 +117,15 @@ export const doctorCommand = async () => {
116
117
  console.log(` ${label('doctor.labels.fullTextSearch', 18)}${ftsProbe.loaded ? 'available' : 'unavailable'}`);
117
118
  if (!ftsProbe.loaded && ftsProbe.reason) {
118
119
  console.log(` ${padDisplayEnd('', 18)}${ftsProbe.reason}`);
120
+ // Add an actionable remedy for recognized failure classes (#2374). The
121
+ // Windows missing-dependency case is the point of this: the raw error 126
122
+ // ("specified module could not be found") is opaque, so name the fix (VC++
123
+ // redist, then OpenSSL) instead of leaving the user to reinstall in vain.
124
+ // `unknown`'s remedy is "run doctor", which would be circular here.
125
+ const { kind, remedy } = diagnoseExtensionLoad(ftsProbe.reason);
126
+ if (kind !== 'unknown') {
127
+ console.log(` ${padDisplayEnd('', 18)}${remedy}`);
128
+ }
119
129
  }
120
130
  console.log(` ${label('doctor.labels.vectorIndex', 18)}${capabilities.vector}`);
121
131
  console.log(` ${label('doctor.labels.semanticMode', 18)}${capabilities.semanticMode}`);
@@ -7,6 +7,10 @@ import { logger } from '../../logger.js';
7
7
  // reserved-keyword labels `Macro` and `Union`, and LadybugDB's parser rejects
8
8
  // a disjunction that names a reserved keyword (#2325) — which the resolver's
9
9
  // try/catch then swallowed. `labels(n) IN` has no such collision.
10
+ // This list overlaps `ingestion/utils/symbol-labels.ts` (SYMBOL_NODE_LABELS) but
11
+ // is a deliberate SUBSET — it omits `Namespace`/`Variable`/`Module`. Unifying the
12
+ // two would widen which nodes resolve as contract symbols and must update the
13
+ // #2325 test, so they are intentionally kept separate for now.
10
14
  export const CUSTOM_CONTRACT_RESOLVE_QUERY = `MATCH (n)
11
15
  WHERE labels(n) IN ['Function','Method','Class','Interface','Struct','Enum','Trait','Constructor','TypeAlias','Impl','Macro','Union','Typedef','Property','Record','Delegate','Annotation','Template','Const','Static','CodeElement']
12
16
  AND n.name = $symbolName
@@ -17,6 +17,7 @@
17
17
  */
18
18
  import { parseJcl } from './jcl-parser.js';
19
19
  import { generateId } from '../../../lib/utils.js';
20
+ import { toZeroBasedLine } from '../utils/line-base.js';
20
21
  /**
21
22
  * Process JCL files and integrate into the knowledge graph.
22
23
  *
@@ -71,8 +72,8 @@ function integrateJclResults(graph, parsed, filePath, moduleNames) {
71
72
  properties: {
72
73
  name: job.name,
73
74
  filePath,
74
- startLine: job.line,
75
- endLine: job.line,
75
+ startLine: toZeroBasedLine(job.line),
76
+ endLine: toZeroBasedLine(job.line),
76
77
  description: `jcl-job${classPart}${msgPart}`,
77
78
  },
78
79
  });
@@ -105,8 +106,8 @@ function integrateJclResults(graph, parsed, filePath, moduleNames) {
105
106
  properties: {
106
107
  name: step.name,
107
108
  filePath,
108
- startLine: step.line,
109
- endLine: step.line,
109
+ startLine: toZeroBasedLine(step.line),
110
+ endLine: toZeroBasedLine(step.line),
110
111
  description: `jcl-step${pgmPart}${procPart}`,
111
112
  },
112
113
  });
@@ -170,8 +171,8 @@ function integrateJclResults(graph, parsed, filePath, moduleNames) {
170
171
  properties: {
171
172
  name: dd.dataset,
172
173
  filePath,
173
- startLine: dd.line,
174
- endLine: dd.line,
174
+ startLine: toZeroBasedLine(dd.line),
175
+ endLine: toZeroBasedLine(dd.line),
175
176
  description: `jcl-dataset${dispPart}`,
176
177
  },
177
178
  });
@@ -202,8 +203,8 @@ function integrateJclResults(graph, parsed, filePath, moduleNames) {
202
203
  properties: {
203
204
  name: proc.name,
204
205
  filePath,
205
- startLine: proc.line,
206
- endLine: proc.line,
206
+ startLine: toZeroBasedLine(proc.line),
207
+ endLine: toZeroBasedLine(proc.line),
207
208
  description: 'jcl-proc-instream',
208
209
  },
209
210
  });
@@ -14,6 +14,7 @@
14
14
  */
15
15
  import path from 'node:path';
16
16
  import { generateId } from '../../lib/utils.js';
17
+ import { toZeroBasedLine } from './utils/line-base.js';
17
18
  import { SupportedLanguages } from '../../_shared/index.js';
18
19
  import { preprocessCobolSource, extractCobolSymbolsWithRegex, } from './cobol/cobol-preprocessor.js';
19
20
  import { expandCopies } from './cobol/cobol-copy-expander.js';
@@ -275,8 +276,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
275
276
  properties: {
276
277
  name: extracted.programName,
277
278
  filePath,
278
- startLine: 1,
279
- endLine: lines.length,
279
+ startLine: toZeroBasedLine(1),
280
+ endLine: toZeroBasedLine(lines.length),
280
281
  language: SupportedLanguages.Cobol,
281
282
  isExported: true,
282
283
  description: metaDesc || undefined,
@@ -310,8 +311,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
310
311
  properties: {
311
312
  name: prog.name,
312
313
  filePath,
313
- startLine: prog.startLine,
314
- endLine: prog.endLine,
314
+ startLine: toZeroBasedLine(prog.startLine),
315
+ endLine: toZeroBasedLine(prog.endLine),
315
316
  language: SupportedLanguages.Cobol,
316
317
  isExported: true,
317
318
  description: `nested-program${prog.isCommon ? ' common' : ''}`,
@@ -349,8 +350,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
349
350
  properties: {
350
351
  name: sec.name,
351
352
  filePath,
352
- startLine: sec.line,
353
- endLine: nextLine,
353
+ startLine: toZeroBasedLine(sec.line),
354
+ endLine: toZeroBasedLine(nextLine),
354
355
  language: SupportedLanguages.Cobol,
355
356
  isExported: true,
356
357
  },
@@ -379,8 +380,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
379
380
  properties: {
380
381
  name: para.name,
381
382
  filePath,
382
- startLine: para.line,
383
- endLine: nextLine,
383
+ startLine: toZeroBasedLine(para.line),
384
+ endLine: toZeroBasedLine(nextLine),
384
385
  language: SupportedLanguages.Cobol,
385
386
  isExported: true,
386
387
  },
@@ -412,8 +413,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
412
413
  properties: {
413
414
  name: item.name,
414
415
  filePath,
415
- startLine: item.line,
416
- endLine: item.line,
416
+ startLine: toZeroBasedLine(item.line),
417
+ endLine: toZeroBasedLine(item.line),
417
418
  language: SupportedLanguages.Cobol,
418
419
  description: `level:${item.level} section:${item.section}${item.pic ? ` pic:${item.pic}` : ''}`,
419
420
  },
@@ -506,8 +507,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
506
507
  properties: {
507
508
  name: `CALL ${call.target}`,
508
509
  filePath,
509
- startLine: call.line,
510
- endLine: call.line,
510
+ startLine: toZeroBasedLine(call.line),
511
+ endLine: toZeroBasedLine(call.line),
511
512
  language: SupportedLanguages.Cobol,
512
513
  description: 'dynamic-call (target is a data item, not resolvable statically)',
513
514
  },
@@ -619,8 +620,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
619
620
  properties: {
620
621
  name: `EXEC SQL ${sql.operation}`,
621
622
  filePath,
622
- startLine: sql.line,
623
- endLine: sql.line,
623
+ startLine: toZeroBasedLine(sql.line),
624
+ endLine: toZeroBasedLine(sql.line),
624
625
  language: SupportedLanguages.Cobol,
625
626
  description: `tables:[${sql.tables.join(',')}] cursors:[${sql.cursors.join(',')}]`,
626
627
  },
@@ -691,8 +692,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
691
692
  properties: {
692
693
  name: `EXEC CICS ${cics.command}`,
693
694
  filePath,
694
- startLine: cics.line,
695
- endLine: cics.line,
695
+ startLine: toZeroBasedLine(cics.line),
696
+ endLine: toZeroBasedLine(cics.line),
696
697
  language: SupportedLanguages.Cobol,
697
698
  description: [
698
699
  cics.mapName && `map:${cics.mapName}`,
@@ -726,8 +727,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
726
727
  properties: {
727
728
  name: `CICS ${cics.command} ${cics.programName}`,
728
729
  filePath,
729
- startLine: cics.line,
730
- endLine: cics.line,
730
+ startLine: toZeroBasedLine(cics.line),
731
+ endLine: toZeroBasedLine(cics.line),
731
732
  language: SupportedLanguages.Cobol,
732
733
  description: `cics-dynamic-program (target is data item ${cics.programName})`,
733
734
  },
@@ -879,8 +880,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
879
880
  properties: {
880
881
  name: entry.name,
881
882
  filePath,
882
- startLine: entry.line,
883
- endLine: entry.line,
883
+ startLine: toZeroBasedLine(entry.line),
884
+ endLine: toZeroBasedLine(entry.line),
884
885
  language: SupportedLanguages.Cobol,
885
886
  isExported: true,
886
887
  description: entry.parameters.length > 0 ? `using:${entry.parameters.join(',')}` : undefined,
@@ -1014,8 +1015,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
1014
1015
  properties: {
1015
1016
  name: `EXEC DLI ${dli.verb}`,
1016
1017
  filePath,
1017
- startLine: dli.line,
1018
- endLine: dli.line,
1018
+ startLine: toZeroBasedLine(dli.line),
1019
+ endLine: toZeroBasedLine(dli.line),
1019
1020
  language: SupportedLanguages.Cobol,
1020
1021
  description: [
1021
1022
  dli.segmentName && `segment:${dli.segmentName}`,
@@ -1148,8 +1149,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
1148
1149
  properties: {
1149
1150
  name: fd.selectName,
1150
1151
  filePath,
1151
- startLine: fd.line,
1152
- endLine: fd.line,
1152
+ startLine: toZeroBasedLine(fd.line),
1153
+ endLine: toZeroBasedLine(fd.line),
1153
1154
  language: SupportedLanguages.Cobol,
1154
1155
  description: `assign:${fd.assignTo}${fd.isOptional ? ' optional' : ''}${fd.organization ? ` org:${fd.organization}` : ''}${fd.access ? ` access:${fd.access}` : ''}`,
1155
1156
  },
@@ -1231,8 +1232,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
1231
1232
  properties: {
1232
1233
  name: `CANCEL ${cancel.target}`,
1233
1234
  filePath,
1234
- startLine: cancel.line,
1235
- endLine: cancel.line,
1235
+ startLine: toZeroBasedLine(cancel.line),
1236
+ endLine: toZeroBasedLine(cancel.line),
1236
1237
  language: SupportedLanguages.Cobol,
1237
1238
  description: 'dynamic-cancel (target is a data item, not resolvable statically)',
1238
1239
  },
@@ -44,6 +44,7 @@
44
44
  * ancestor scope, and if THAT produces nothing either the edge is
45
45
  * skipped (with a count returned in `EmitStats.skippedNoCaller`).
46
46
  */
47
+ import { toZeroBasedLine } from './utils/line-base.js';
47
48
  /**
48
49
  * Drain `referenceIndex.bySourceScope` into graph edges.
49
50
  *
@@ -95,8 +96,8 @@ export function emitScopeGraph(input) {
95
96
  properties: {
96
97
  name: scope.kind,
97
98
  filePath: scope.filePath,
98
- startLine: scope.range.startLine,
99
- endLine: scope.range.endLine,
99
+ startLine: toZeroBasedLine(scope.range.startLine),
100
+ endLine: toZeroBasedLine(scope.range.endLine),
100
101
  description: `Scope: ${scope.kind}`,
101
102
  },
102
103
  });
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import path from 'node:path';
9
9
  import { generateId } from '../../lib/utils.js';
10
+ import { toZeroBasedLine } from './utils/line-base.js';
10
11
  const HEADING_RE = /^(#{1,6})\s+(.+)$/;
11
12
  const LINK_RE = /\[([^\]]*)\]\(([^)]+)\)/g;
12
13
  const MD_EXTENSIONS = new Set(['.md', '.mdx']);
@@ -59,8 +60,8 @@ export const processMarkdown = (graph, files, allPathSet) => {
59
60
  properties: {
60
61
  name: heading,
61
62
  filePath: file.path,
62
- startLine: lineNum,
63
- endLine,
63
+ startLine: toZeroBasedLine(lineNum),
64
+ endLine: toZeroBasedLine(endLine),
64
65
  level,
65
66
  description: `h${level}`,
66
67
  },
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Convert a 1-based source line number to the 0-based convention used by
3
+ * GraphNode `startLine`/`endLine`.
4
+ *
5
+ * The graph layer stores line numbers 0-based (tree-sitter `startPosition.row`),
6
+ * and this is load-bearing: the taint/PDG/CFG join and the MCP consumers all add
7
+ * `+ 1` to recover 1-based (see `summary-harvest-driver.ts` — "Function/Method
8
+ * node startLine is 0-based"). Most emitters get 0-based for free from
9
+ * tree-sitter. The exceptions are the regex-based COBOL/JCL processors (their
10
+ * parsers use `lineNum = i + 1`) and the scope-capture path (`Capture` ranges
11
+ * are 1-based per RFC §2.1). Those must convert to 0-based when they build a
12
+ * graph node, or the exact-content slice in `csv-generator.ts` drops the
13
+ * symbol's declaration line (#2379) and reported line numbers are off (#2377).
14
+ *
15
+ * Apply this ONLY at the graph-node `startLine:`/`endLine:` assignment. The
16
+ * parser-internal 1-based values (`.line`, `prog.startLine`) stay 1-based —
17
+ * they feed `L${line}` node/edge IDs and line-range containment checks that
18
+ * must not shift. The clamp guards degenerate inputs (line 0 / empty files).
19
+ */
20
+ export declare const toZeroBasedLine: (oneBasedLine: number) => number;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Convert a 1-based source line number to the 0-based convention used by
3
+ * GraphNode `startLine`/`endLine`.
4
+ *
5
+ * The graph layer stores line numbers 0-based (tree-sitter `startPosition.row`),
6
+ * and this is load-bearing: the taint/PDG/CFG join and the MCP consumers all add
7
+ * `+ 1` to recover 1-based (see `summary-harvest-driver.ts` — "Function/Method
8
+ * node startLine is 0-based"). Most emitters get 0-based for free from
9
+ * tree-sitter. The exceptions are the regex-based COBOL/JCL processors (their
10
+ * parsers use `lineNum = i + 1`) and the scope-capture path (`Capture` ranges
11
+ * are 1-based per RFC §2.1). Those must convert to 0-based when they build a
12
+ * graph node, or the exact-content slice in `csv-generator.ts` drops the
13
+ * symbol's declaration line (#2379) and reported line numbers are off (#2377).
14
+ *
15
+ * Apply this ONLY at the graph-node `startLine:`/`endLine:` assignment. The
16
+ * parser-internal 1-based values (`.line`, `prog.startLine`) stay 1-based —
17
+ * they feed `L${line}` node/edge IDs and line-range containment checks that
18
+ * must not shift. The clamp guards degenerate inputs (line 0 / empty files).
19
+ */
20
+ export const toZeroBasedLine = (oneBasedLine) => Math.max(0, oneBasedLine - 1);
@@ -0,0 +1,21 @@
1
+ import type { NodeLabel } from '../../../_shared/index.js';
2
+ /**
3
+ * Graph-node labels that represent a resolvable code symbol — a definition with
4
+ * its own source span (function, type, member, module-like container).
5
+ *
6
+ * These get EXACT source-span content in the FTS index: `csv-generator.ts`
7
+ * slices exactly `[startLine, endLine]` for them (no ±2 padding), while every
8
+ * other label keeps the context window. That exactness depends on the 0-based
9
+ * `startLine`/`endLine` invariant enforced by `line-base.ts` — the slice is only
10
+ * correct because all emitters store 0-based lines. Keep the two together.
11
+ *
12
+ * Single source of truth so the set can't silently drift the way the inline copy
13
+ * did in #2379.
14
+ *
15
+ * NOTE: `group/extractors/manifest-extractor.ts`'s `CUSTOM_CONTRACT_RESOLVE_QUERY`
16
+ * carries a near-identical hand-list that is intentionally a SUBSET — it excludes
17
+ * `Namespace`, `Variable`, `Module`. Unifying the two needs a contract-resolution
18
+ * behavior check (would widen which nodes resolve as contract symbols), so it is
19
+ * deliberately left separate for now.
20
+ */
21
+ export declare const SYMBOL_NODE_LABELS: ReadonlySet<NodeLabel>;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Graph-node labels that represent a resolvable code symbol — a definition with
3
+ * its own source span (function, type, member, module-like container).
4
+ *
5
+ * These get EXACT source-span content in the FTS index: `csv-generator.ts`
6
+ * slices exactly `[startLine, endLine]` for them (no ±2 padding), while every
7
+ * other label keeps the context window. That exactness depends on the 0-based
8
+ * `startLine`/`endLine` invariant enforced by `line-base.ts` — the slice is only
9
+ * correct because all emitters store 0-based lines. Keep the two together.
10
+ *
11
+ * Single source of truth so the set can't silently drift the way the inline copy
12
+ * did in #2379.
13
+ *
14
+ * NOTE: `group/extractors/manifest-extractor.ts`'s `CUSTOM_CONTRACT_RESOLVE_QUERY`
15
+ * carries a near-identical hand-list that is intentionally a SUBSET — it excludes
16
+ * `Namespace`, `Variable`, `Module`. Unifying the two needs a contract-resolution
17
+ * behavior check (would widen which nodes resolve as contract symbols), so it is
18
+ * deliberately left separate for now.
19
+ */
20
+ export const SYMBOL_NODE_LABELS = new Set([
21
+ 'Function',
22
+ 'Method',
23
+ 'Class',
24
+ 'Interface',
25
+ 'CodeElement',
26
+ 'Struct',
27
+ 'Enum',
28
+ 'Macro',
29
+ 'Typedef',
30
+ 'Union',
31
+ 'Namespace',
32
+ 'Trait',
33
+ 'Impl',
34
+ 'TypeAlias',
35
+ 'Const',
36
+ 'Static',
37
+ 'Variable',
38
+ 'Property',
39
+ 'Record',
40
+ 'Delegate',
41
+ 'Annotation',
42
+ 'Constructor',
43
+ 'Template',
44
+ 'Module',
45
+ ]);
@@ -17,6 +17,7 @@ import path from 'path';
17
17
  import { NODE_TABLES } from './schema.js';
18
18
  import { RelPairRouter } from './rel-pair-routing.js';
19
19
  import { parseTruthyEnv } from '../ingestion/utils/env.js';
20
+ import { SYMBOL_NODE_LABELS } from '../ingestion/utils/symbol-labels.js';
20
21
  import { applyCjkSegmentationIfEnabled } from '../search/cjk-segmentation.js';
21
22
  /**
22
23
  * Deterministic output ordering — optional (out-of-core / windowed-resolve
@@ -187,6 +188,10 @@ class FileContentCache {
187
188
  export const normalizeFtsText = (text) => text.replace(/[\r\n\t]+/g, ' ');
188
189
  /** Composes both FTS-text transforms for the `description` column — one place for the six emission sites below to call, instead of repeating the composition. */
189
190
  const formatFtsDescription = (description) => normalizeFtsText(applyCjkSegmentationIfEnabled(description));
191
+ // Labels that get exact source-span content (no ±2 window). Single source of
192
+ // truth in `symbol-labels.ts` — see there for why the exactness depends on the
193
+ // 0-based line invariant. Kept as a named alias to read intent at the use site.
194
+ const EXACT_SYMBOL_CONTENT_LABELS = SYMBOL_NODE_LABELS;
190
195
  const extractContent = async (node, contentCache) => {
191
196
  const filePath = node.properties.filePath;
192
197
  const content = await contentCache.get(filePath);
@@ -209,8 +214,9 @@ const extractContent = async (node, contentCache) => {
209
214
  if (startLine === undefined || endLine === undefined)
210
215
  return '';
211
216
  const lines = content.split('\n');
212
- const start = Math.max(0, startLine - 2);
213
- const end = Math.min(lines.length - 1, endLine + 2);
217
+ const exactSymbolContent = EXACT_SYMBOL_CONTENT_LABELS.has(node.label);
218
+ const start = Math.max(0, exactSymbolContent ? startLine : startLine - 2);
219
+ const end = Math.min(lines.length - 1, exactSymbolContent ? endLine : endLine + 2);
214
220
  const snippet = lines.slice(start, end + 1).join('\n');
215
221
  const MAX_SNIPPET = 5000;
216
222
  const capped = snippet.length > MAX_SNIPPET ? snippet.slice(0, MAX_SNIPPET) + '\n... [truncated]' : snippet;
@@ -0,0 +1,67 @@
1
+ export type ExtensionLoadErrorKind = 'missing_file' | 'corrupt_file' | 'missing_dependency' | 'unknown';
2
+ export interface ExtensionLoadDiagnosis {
3
+ readonly kind: ExtensionLoadErrorKind;
4
+ /** Actionable, literal-English remedy suited to the class. */
5
+ readonly remedy: string;
6
+ }
7
+ /**
8
+ * On-disk file corruption / wrong-platform. FORCE INSTALL re-downloads.
9
+ * Kept byte-identical to `FILE_CORRUPTION_SIGNATURES` in
10
+ * scripts/install-duckdb-extension.mjs (that `.mjs` cannot import this `.ts`;
11
+ * the duplication is deliberate — the two serve different call sites). Note
12
+ * `/not a valid/i` already covers Windows error 193 ("is not a valid Win32
13
+ * application"), so a truncated Windows download is caught here, before the
14
+ * missing-dependency branch.
15
+ */
16
+ export declare const FILE_CORRUPTION_SIGNATURES: readonly RegExp[];
17
+ /**
18
+ * Classify a collapsed LadybugDB LOAD error. Order is most-specific-first and is
19
+ * load-bearing: corrupt-file is tested before missing-dependency so a truncated
20
+ * Windows download (error 193, matched by `/not a valid/i`) routes to
21
+ * FORCE-reinstall rather than to the runtime-install remedy.
22
+ */
23
+ export declare function classifyExtensionLoadError(reason: string | undefined | null): ExtensionLoadDiagnosis;
24
+ /** Well-formedness of the extension binary for the host platform + arch. */
25
+ export type ExtensionBinaryState = 'absent' | 'corrupt' | 'valid' | 'indeterminate';
26
+ /**
27
+ * Pull the extension file path out of lbug's load error. lbug's wrapper is
28
+ * English regardless of OS language — `Failed to load library: {path} which is
29
+ * needed by extension: {name}` (real lbug), or the quoted `Failed to load
30
+ * library '{path}': {reason}` variant — so the path is recoverable in any locale.
31
+ * Only paths ending in `.lbug_extension` are accepted, so a regex misfire can
32
+ * never point the inspector at an arbitrary file.
33
+ */
34
+ export declare function extractExtensionPath(reason: string | undefined | null): string | null;
35
+ /**
36
+ * A structural verdict on a binary header. `indeterminate` means the probe could
37
+ * not prove validity OR corruption from what it read (e.g. the PE header sits past
38
+ * the BINARY_HEADER_BYTES window) — the caller defers to the string classifier
39
+ * rather than assert a false verdict.
40
+ */
41
+ type HeaderVerdict = 'valid' | 'corrupt' | 'indeterminate';
42
+ /**
43
+ * Decide whether a binary header is a well-formed shared library for the given
44
+ * platform + architecture — using only the file's structure, no localized text.
45
+ * Pure and injectable (platform/arch as params) so every format+arch combination
46
+ * is unit-testable regardless of the host it runs on.
47
+ */
48
+ export declare function classifyBinaryHeader(buf: Buffer, bytesRead: number, platform: NodeJS.Platform, arch: string): HeaderVerdict;
49
+ /**
50
+ * Best-effort language-independent inspection of the extension file. Reads the
51
+ * header and classifies it; never throws — a missing file is `absent`, an
52
+ * unreadable one is `indeterminate`.
53
+ */
54
+ export declare function inspectExtensionBinary(extensionPath: string | null | undefined): ExtensionBinaryState;
55
+ /**
56
+ * Diagnose a LadybugDB load failure, preferring a LANGUAGE-INDEPENDENT structural
57
+ * check of the extension binary over the localized error text:
58
+ * - file absent → missing_file
59
+ * - present but malformed → corrupt_file (bad magic / wrong architecture)
60
+ * - present and well-formed → missing_dependency (a valid binary the loader rejected)
61
+ * The path comes from lbug's own English wrapper, so this holds in any OS display
62
+ * language. When the file cannot be located or read, it falls back to the string
63
+ * classifier (which still carries the language-independent hedged fallback). This
64
+ * is the entry point every surface should call.
65
+ */
66
+ export declare function diagnoseExtensionLoad(reason: string | undefined | null): ExtensionLoadDiagnosis;
67
+ export {};