gitnexus 1.6.5-rc.2 → 1.6.5-rc.4

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 CHANGED
@@ -33,7 +33,7 @@ To configure MCP for your editor, run `npx gitnexus setup` once — or set it up
33
33
  | Editor | MCP | Skills | Hooks (auto-augment) | Support |
34
34
  |--------|-----|--------|---------------------|---------|
35
35
  | **Claude Code** | Yes | Yes | Yes (PreToolUse) | **Full** |
36
- | **Cursor** | Yes | Yes | | MCP + Skills |
36
+ | **Cursor** | Yes | Yes | Yes (postToolUse, [manual install](../gitnexus-cursor-integration/README.md#hook-install)) | **Full** |
37
37
  | **Codex** | Yes | Yes | — | MCP + Skills |
38
38
  | **Windsurf** | Yes | — | — | MCP |
39
39
  | **OpenCode** | Yes | Yes | — | MCP + Skills |
@@ -2,7 +2,7 @@
2
2
  * Augment CLI Command
3
3
  *
4
4
  * Fast-path command for platform hooks.
5
- * Shells out from Claude Code PreToolUse / Cursor beforeShellExecution hooks.
5
+ * Shells out from Claude Code PreToolUse / Cursor postToolUse hooks.
6
6
  *
7
7
  * Usage: gitnexus augment <pattern>
8
8
  * Returns enriched text to stdout.
@@ -2,7 +2,7 @@
2
2
  * Augment CLI Command
3
3
  *
4
4
  * Fast-path command for platform hooks.
5
- * Shells out from Claude Code PreToolUse / Cursor beforeShellExecution hooks.
5
+ * Shells out from Claude Code PreToolUse / Cursor postToolUse hooks.
6
6
  *
7
7
  * Usage: gitnexus augment <pattern>
8
8
  * Returns enriched text to stdout.
@@ -2,8 +2,8 @@
2
2
  * Augmentation Engine
3
3
  *
4
4
  * Lightweight, fast-path enrichment of search patterns with knowledge graph context.
5
- * Designed to be called from platform hooks (Claude Code PreToolUse, Cursor beforeShellExecution)
6
- * when an agent runs grep/glob/search.
5
+ * Designed to be called from platform hooks (Claude Code PreToolUse, Cursor postToolUse)
6
+ * when an agent runs grep/glob/read/search.
7
7
  *
8
8
  * Performance target: <500ms cold start, <200ms warm.
9
9
  *
@@ -2,8 +2,8 @@
2
2
  * Augmentation Engine
3
3
  *
4
4
  * Lightweight, fast-path enrichment of search patterns with knowledge graph context.
5
- * Designed to be called from platform hooks (Claude Code PreToolUse, Cursor beforeShellExecution)
6
- * when an agent runs grep/glob/search.
5
+ * Designed to be called from platform hooks (Claude Code PreToolUse, Cursor postToolUse)
6
+ * when an agent runs grep/glob/read/search.
7
7
  *
8
8
  * Performance target: <500ms cold start, <200ms warm.
9
9
  *
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { getLanguageFromFilename } from '../../_shared/index.js';
7
7
  import { createParserForLanguage, isLanguageAvailable, resolveLanguageKey, } from '../tree-sitter/parser-loader.js';
8
+ import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
8
9
  const parserCache = new Map();
9
10
  /**
10
11
  * Ensure parser is initialized and language is loaded, then parse content.
@@ -22,7 +23,7 @@ export const ensureAndParse = async (content, filePath) => {
22
23
  parserInstance = await createParserForLanguage(language, filePath);
23
24
  parserCache.set(parserKey, parserInstance);
24
25
  }
25
- return parserInstance.parse(content);
26
+ return parseSourceSafe(parserInstance, content);
26
27
  };
27
28
  const FUNCTION_LIKE_TYPES = new Set([
28
29
  'function_declaration',
@@ -3,6 +3,7 @@ import { glob } from 'glob';
3
3
  import Parser from 'tree-sitter';
4
4
  import { createIgnoreFilter } from '../../../config/ignore-service.js';
5
5
  import { readSafe } from './fs-utils.js';
6
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
6
7
  import { logger } from '../../logger.js';
7
8
  import { GRPC_SCAN_GLOB, getPluginForFile, hasProtoPlugin, } from './grpc-patterns/index.js';
8
9
  /**
@@ -352,7 +353,7 @@ export class GrpcExtractor {
352
353
  let detections = [];
353
354
  try {
354
355
  parser.setLanguage(plugin.language);
355
- const tree = parser.parse(content);
356
+ const tree = parseSourceSafe(parser, content);
356
357
  detections = plugin.scan(tree);
357
358
  }
358
359
  catch {
@@ -3,6 +3,7 @@ import { glob } from 'glob';
3
3
  import Parser from 'tree-sitter';
4
4
  import { createIgnoreFilter } from '../../../config/ignore-service.js';
5
5
  import { readSafe } from './fs-utils.js';
6
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
6
7
  import { getPluginForFile, HTTP_SCAN_GLOB } from './http-patterns/index.js';
7
8
  /**
8
9
  * Language-agnostic orchestrator for HTTP route (provider + consumer)
@@ -154,7 +155,7 @@ export class HttpRouteExtractor {
154
155
  }
155
156
  try {
156
157
  parser.setLanguage(plugin.language);
157
- const tree = parser.parse(content);
158
+ const tree = parseSourceSafe(parser, content);
158
159
  const detections = plugin.scan(tree);
159
160
  cachedDetections.set(rel, detections);
160
161
  return detections;
@@ -8,6 +8,7 @@ import { readSafe } from './fs-utils.js';
8
8
  import { buildSuffixIndex } from '../../ingestion/import-resolvers/utils.js';
9
9
  import { createIgnoreFilter } from '../../../config/ignore-service.js';
10
10
  import { getMaxFileSizeBytes } from '../../ingestion/utils/max-file-size.js';
11
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
11
12
  import { logger } from '../../logger.js';
12
13
  /**
13
14
  * Cross-repo C/C++ `#include` dependency extractor.
@@ -457,7 +458,7 @@ export class IncludeExtractor {
457
458
  let extractionSource;
458
459
  try {
459
460
  parser.setLanguage(lang);
460
- const tree = parser.parse(content);
461
+ const tree = parseSourceSafe(parser, content);
461
462
  let matches;
462
463
  try {
463
464
  matches = query.matches(tree.rootNode);
@@ -1,6 +1,7 @@
1
1
  import { glob } from 'glob';
2
2
  import Parser from 'tree-sitter';
3
3
  import { readSafe } from './fs-utils.js';
4
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
4
5
  import { getPluginForFile, THRIFT_SCAN_GLOB, } from './thrift-patterns/index.js';
5
6
  function normalizeThriftPath(rel) {
6
7
  return rel.replace(/\\/g, '/');
@@ -228,7 +229,7 @@ export class ThriftExtractor {
228
229
  let detections = [];
229
230
  try {
230
231
  parser.setLanguage(plugin.language);
231
- const tree = parser.parse(content);
232
+ const tree = parseSourceSafe(parser, content);
232
233
  detections = plugin.scan(tree);
233
234
  }
234
235
  catch {
@@ -1,4 +1,5 @@
1
1
  import Parser from 'tree-sitter';
2
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
2
3
  /**
3
4
  * Compile a LanguagePatterns bundle. Call this once per plugin, at
4
5
  * module load time, and export the result. Throws if any pattern
@@ -60,7 +61,7 @@ export function scanFile(parser, plugin, content) {
60
61
  let tree;
61
62
  try {
62
63
  parser.setLanguage(plugin.language);
63
- tree = parser.parse(content);
64
+ tree = parseSourceSafe(parser, content);
64
65
  }
65
66
  catch {
66
67
  return [];
@@ -29,6 +29,7 @@ import { getLanguageFromFilename, SupportedLanguages } from '../../_shared/index
29
29
  import { isRegistryPrimary } from './registry-primary-flag.js';
30
30
  import { isVerboseIngestionEnabled } from './utils/verbose.js';
31
31
  import { yieldToEventLoop } from './utils/event-loop.js';
32
+ import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
32
33
  import { FUNCTION_NODE_TYPES, findEnclosingClassId, findEnclosingClassInfo, genericFuncName, inferFunctionLabel, } from './utils/ast-helpers.js';
33
34
  import { typeTagForId, constTagForId, buildCollisionGroups } from './utils/method-props.js';
34
35
  import { countCallArguments, inferCallForm, extractReceiverName, extractReceiverNode, extractMixedChain, extractCallArgTypes, } from './utils/call-analysis.js';
@@ -614,7 +615,7 @@ importedRawReturnTypesMap, heritageMap, bindingAccumulator) => {
614
615
  if (!tree) {
615
616
  const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
616
617
  try {
617
- tree = parser.parse(parseContent, undefined, {
618
+ tree = parseSourceSafe(parser, parseContent, undefined, {
618
619
  bufferSize: getTreeSitterBufferSize(parseContent),
619
620
  });
620
621
  }
@@ -2586,7 +2587,7 @@ export const extractFetchCallsFromFiles = async (files, astCache) => {
2586
2587
  if (!tree) {
2587
2588
  const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
2588
2589
  try {
2589
- tree = parser.parse(parseContent, undefined, {
2590
+ tree = parseSourceSafe(parser, parseContent, undefined, {
2590
2591
  bufferSize: getTreeSitterBufferSize(parseContent),
2591
2592
  });
2592
2593
  }
@@ -19,6 +19,7 @@ import { generateId } from '../../lib/utils.js';
19
19
  import { getLanguageFromFilename } from '../../_shared/index.js';
20
20
  import { isVerboseIngestionEnabled } from './utils/verbose.js';
21
21
  import { yieldToEventLoop } from './utils/event-loop.js';
22
+ import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
22
23
  import { getProvider } from './languages/index.js';
23
24
  import { getTreeSitterBufferSize } from './constants.js';
24
25
  import { resolveExtendsType } from './model/heritage-map.js';
@@ -152,7 +153,7 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
152
153
  // re-parses see the same input as the cached AST.
153
154
  const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
154
155
  try {
155
- tree = parser.parse(parseContent, undefined, {
156
+ tree = parseSourceSafe(parser, parseContent, undefined, {
156
157
  bufferSize: getTreeSitterBufferSize(parseContent),
157
158
  });
158
159
  }
@@ -300,7 +301,7 @@ export async function extractExtractedHeritageFromFiles(files, astCache) {
300
301
  if (!tree) {
301
302
  const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
302
303
  try {
303
- tree = parser.parse(parseContent, undefined, {
304
+ tree = parseSourceSafe(parser, parseContent, undefined, {
304
305
  bufferSize: getTreeSitterBufferSize(parseContent),
305
306
  });
306
307
  }
@@ -5,6 +5,7 @@ import { generateId } from '../../lib/utils.js';
5
5
  import { getLanguageFromFilename } from '../../_shared/index.js';
6
6
  import { isVerboseIngestionEnabled } from './utils/verbose.js';
7
7
  import { yieldToEventLoop } from './utils/event-loop.js';
8
+ import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
8
9
  import { getTreeSitterBufferSize } from './constants.js';
9
10
  import { loadImportConfigs } from './language-config.js';
10
11
  import { buildSuffixIndex } from './import-resolvers/utils.js';
@@ -243,7 +244,7 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
243
244
  if (!tree) {
244
245
  const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
245
246
  try {
246
- tree = parser.parse(parseContent, undefined, {
247
+ tree = parseSourceSafe(parser, parseContent, undefined, {
247
248
  bufferSize: getTreeSitterBufferSize(parseContent),
248
249
  });
249
250
  }
@@ -22,6 +22,7 @@ import { synthesizeCsharpReceiverBinding } from './receiver-binding.js';
22
22
  import { getCsharpParser, getCsharpScopeQuery } from './query.js';
23
23
  import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
24
24
  import { getTreeSitterBufferSize } from '../../constants.js';
25
+ import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
25
26
  /** Declaration anchors that carry function-like arity metadata. */
26
27
  const FUNCTION_DECL_TAGS = [
27
28
  '@declaration.method',
@@ -75,7 +76,7 @@ export function emitCsharpScopeCaptures(sourceText, _filePath, cachedTree) {
75
76
  // the LanguageProvider contract layer; cast here at the use site.
76
77
  let tree = cachedTree;
77
78
  if (tree === undefined) {
78
- tree = getCsharpParser().parse(sourceText, undefined, {
79
+ tree = parseSourceSafe(getCsharpParser(), sourceText, undefined, {
79
80
  bufferSize: getTreeSitterBufferSize(sourceText),
80
81
  });
81
82
  recordCacheMiss();
@@ -32,6 +32,7 @@
32
32
  */
33
33
  import { getCsharpParser } from './query.js';
34
34
  import { getTreeSitterBufferSize } from '../../constants.js';
35
+ import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
35
36
  /** Build a structural view of a C# file by walking the tree-sitter
36
37
  * AST. Prefers `cachedTree` (handed in via `treeCache`) so we don't
37
38
  * re-parse files the orchestrator already parsed for `extractParsedFile`;
@@ -39,7 +40,7 @@ import { getTreeSitterBufferSize } from '../../constants.js';
39
40
  * shared across calls. */
40
41
  function extractFileStructure(content, cachedTree) {
41
42
  const tree = cachedTree ??
42
- getCsharpParser().parse(content, undefined, {
43
+ parseSourceSafe(getCsharpParser(), content, undefined, {
43
44
  bufferSize: getTreeSitterBufferSize(content),
44
45
  });
45
46
  const namespaces = [];
@@ -332,7 +333,7 @@ export function populateCsharpNamespaceSiblings(parsedFiles, indexes, inputs) {
332
333
  const key = q.includes('.') ? q.slice(q.lastIndexOf('.') + 1) : q;
333
334
  if (key === '')
334
335
  continue;
335
- const arr = defsByName.get(key) ?? [];
336
+ const arr = [...(defsByName.get(key) ?? [])];
336
337
  arr.push(def);
337
338
  defsByName.set(key, arr);
338
339
  }
@@ -6,10 +6,11 @@ import { splitGoImportStatement } from './import-decomposer.js';
6
6
  import { synthesizeGoReceiverBinding } from './receiver-binding.js';
7
7
  import { synthesizeGoTypeBindings } from './type-binding.js';
8
8
  import { getTreeSitterBufferSize } from '../../constants.js';
9
+ import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
9
10
  export function emitGoScopeCaptures(sourceText, _filePath, cachedTree) {
10
11
  let tree = cachedTree;
11
12
  if (tree === undefined) {
12
- tree = getGoParser().parse(sourceText, undefined, {
13
+ tree = parseSourceSafe(getGoParser(), sourceText, undefined, {
13
14
  bufferSize: getTreeSitterBufferSize(sourceText),
14
15
  });
15
16
  recordGoCacheMiss();
@@ -1,5 +1,6 @@
1
1
  import { getGoParser } from './query.js';
2
2
  import { getTreeSitterBufferSize } from '../../constants.js';
3
+ import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
3
4
  export function populateGoRangeBindings(parsedFiles, _indexes, ctx) {
4
5
  const parser = getGoParser();
5
6
  for (const parsed of parsedFiles) {
@@ -8,7 +9,7 @@ export function populateGoRangeBindings(parsedFiles, _indexes, ctx) {
8
9
  continue;
9
10
  const cachedTree = ctx.treeCache?.get(parsed.filePath);
10
11
  const tree = cachedTree ??
11
- parser.parse(sourceText, undefined, {
12
+ parseSourceSafe(parser, sourceText, undefined, {
12
13
  bufferSize: getTreeSitterBufferSize(sourceText),
13
14
  });
14
15
  const moduleScope = parsed.scopes.find((s) => s.kind === 'Module');
@@ -22,6 +22,7 @@ import { synthesizeReceiverTypeBinding } from './receiver-binding.js';
22
22
  import { computePythonArityMetadata } from './arity-metadata.js';
23
23
  import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
24
24
  import { getTreeSitterBufferSize } from '../../constants.js';
25
+ import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
25
26
  import { pythonFunctionDefinitionLabel } from './simple-hooks.js';
26
27
  export function emitPythonScopeCaptures(sourceText, _filePath, cachedTree) {
27
28
  // Skip the parse when the caller (parse phase's ASTCache) already
@@ -32,7 +33,7 @@ export function emitPythonScopeCaptures(sourceText, _filePath, cachedTree) {
32
33
  let tree = cachedTree;
33
34
  if (tree === undefined) {
34
35
  try {
35
- tree = getPythonParser().parse(sourceText, undefined, {
36
+ tree = parseSourceSafe(getPythonParser(), sourceText, undefined, {
36
37
  bufferSize: getTreeSitterBufferSize(sourceText),
37
38
  });
38
39
  }
@@ -31,6 +31,7 @@ import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
31
31
  import { synthesizeTsReceiverBinding } from './receiver-binding.js';
32
32
  import { computeTsArityMetadata } from './arity-metadata.js';
33
33
  import { getTreeSitterBufferSize } from '../../constants.js';
34
+ import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
34
35
  /** tree-sitter-typescript node types for function-like scopes that may
35
36
  * carry a synthesized `this` binding. Kept in sync with the
36
37
  * `@scope.function` patterns in `query.ts`. */
@@ -119,7 +120,7 @@ export function emitTsScopeCaptures(sourceText, filePath, cachedTree) {
119
120
  tree = undefined;
120
121
  }
121
122
  if (tree === undefined) {
122
- tree = getTsParser(filePath).parse(sourceText, undefined, {
123
+ tree = parseSourceSafe(getTsParser(filePath), sourceText, undefined, {
123
124
  bufferSize: getTreeSitterBufferSize(sourceText),
124
125
  });
125
126
  recordCacheMiss();
@@ -5,6 +5,7 @@ import { generateId } from '../../lib/utils.js';
5
5
  import { getLanguageFromFilename, SupportedLanguages } from '../../_shared/index.js';
6
6
  import { extractVueScript, isVueSetupTopLevel } from './vue-sfc-extractor.js';
7
7
  import { yieldToEventLoop } from './utils/event-loop.js';
8
+ import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
8
9
  import { isVerboseIngestionEnabled } from './utils/verbose.js';
9
10
  import { getDefinitionNodeFromCaptures, findEnclosingClassInfo, getLabelFromCaptures, CLASS_CONTAINER_TYPES, } from './utils/ast-helpers.js';
10
11
  import { detectFrameworkFromAST } from './framework-detection.js';
@@ -274,7 +275,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
274
275
  }
275
276
  let tree;
276
277
  try {
277
- tree = parser.parse(parseContent, undefined, {
278
+ tree = parseSourceSafe(parser, parseContent, undefined, {
278
279
  bufferSize: getTreeSitterBufferSize(parseContent),
279
280
  });
280
281
  }
@@ -16,6 +16,7 @@ import { createRequire } from 'node:module';
16
16
  import { SupportedLanguages } from '../../../_shared/index.js';
17
17
  import { getProvider } from '../languages/index.js';
18
18
  import { getTreeSitterBufferSize, getTreeSitterContentByteLength, TREE_SITTER_MAX_BUFFER, } from '../constants.js';
19
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
19
20
  // tree-sitter-swift is an optionalDependency — may not be installed
20
21
  const _require = createRequire(import.meta.url);
21
22
  let Swift = null;
@@ -1026,7 +1027,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1026
1027
  clearCaches(); // Reset memoization before each new file
1027
1028
  let tree;
1028
1029
  try {
1029
- tree = parser.parse(parseContent, undefined, {
1030
+ tree = parseSourceSafe(parser, parseContent, undefined, {
1030
1031
  bufferSize: getTreeSitterBufferSize(parseContent),
1031
1032
  });
1032
1033
  }
@@ -1102,6 +1102,14 @@ export const loadVectorExtension = async (targetConn, opts = {}) => {
1102
1102
  const useModuleState = targetConn === undefined;
1103
1103
  if (useModuleState && vectorExtensionLoaded)
1104
1104
  return true;
1105
+ // INSTALL VECTOR crashes with SIGSEGV on Windows: the KuzuDB native extension
1106
+ // installer has an unhandled error path on Windows that raises a fatal signal
1107
+ // that JS try/catch cannot intercept. Skip loading — vector/embedding search
1108
+ // is unavailable but all graph index queries still work. Do NOT set
1109
+ // vectorExtensionLoaded here: the flag means "successfully loaded", and a
1110
+ // subsequent call would otherwise short-circuit to `return true` at the top.
1111
+ if (process.platform === 'win32')
1112
+ return false;
1105
1113
  if (!isVectorExtensionSupportedByPlatform())
1106
1114
  return false;
1107
1115
  const c = targetConn ?? conn;
@@ -348,7 +348,18 @@ async function doInitLbug(repoId, dbPath) {
348
348
  // install; analyze owns extension installation. If LOAD fails, search
349
349
  // features degrade gracefully and the user-facing query path proceeds.
350
350
  if (!shared.ftsLoaded) {
351
- shared.ftsLoaded = await loadFTSExtension(available[0], { policy: 'load-only' });
351
+ // Windows guard: LOAD EXTENSION fts crashes with SIGSEGV on Windows when
352
+ // the FTS extension binary is not installed locally (@ladybugdb/core native
353
+ // bug — the extension loader hits an unhandled error path that signals SIGSEGV
354
+ // rather than throwing a JS exception, so try/catch cannot protect here).
355
+ // Skip the load on Windows; bm25-index.js catches the resulting Kuzu catalog
356
+ // errors and returns empty BM25 results gracefully. Graph queries are unaffected.
357
+ if (process.platform === 'win32') {
358
+ shared.ftsLoaded = true;
359
+ }
360
+ else {
361
+ shared.ftsLoaded = await loadFTSExtension(available[0], { policy: 'load-only' });
362
+ }
352
363
  }
353
364
  // Register pool entry only after all connections are pre-warmed and FTS is
354
365
  // loaded. Concurrent executeQuery calls see either "not initialized"
@@ -404,8 +415,14 @@ export async function initLbugWithDb(repoId, existingDb, dbPath) {
404
415
  // Load FTS extension if not already loaded on this Database.
405
416
  // policy: 'load-only' — same contract as initLbug above; the read pool
406
417
  // must not block on a network install during query execution.
418
+ // Windows guard: same SIGSEGV risk as doInitLbug above — skip on Windows.
407
419
  if (!shared.ftsLoaded) {
408
- shared.ftsLoaded = await loadFTSExtension(available[0], { policy: 'load-only' });
420
+ if (process.platform === 'win32') {
421
+ shared.ftsLoaded = true;
422
+ }
423
+ else {
424
+ shared.ftsLoaded = await loadFTSExtension(available[0], { policy: 'load-only' });
425
+ }
409
426
  }
410
427
  pool.set(repoId, {
411
428
  db: existingDb,
@@ -0,0 +1,6 @@
1
+ import type Parser from 'tree-sitter';
2
+ /**
3
+ * Parse `sourceText` safely on every platform. See {@link SAFE_PARSE_CHUNK_CHARS}
4
+ * for the underlying tree-sitter binding bug this works around.
5
+ */
6
+ export declare function parseSourceSafe(parser: Parser, sourceText: string, oldTree?: Parser.Tree, options?: Parser.Options): Parser.Tree;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * tree-sitter 0.21.x's Node native binding crashes (SIGSEGV) on Windows when
3
+ * `parser.parse(string, …)` is handed a JS string longer than 32 767 chars.
4
+ * The crash happens inside the binding's V8 string-to-buffer conversion and
5
+ * cannot be intercepted from JavaScript. The callback (`Parser.Input`) overload
6
+ * pulls source in fixed-size chunks via repeated callback invocations and
7
+ * bypasses that conversion path entirely.
8
+ *
9
+ * Chunk size is comfortably below the boundary; any value < 32 767 works.
10
+ */
11
+ const SAFE_PARSE_CHUNK_CHARS = 16 * 1024;
12
+ /**
13
+ * Files at or below this length skip the callback machinery and use the
14
+ * direct string overload — the bug only manifests above the int16 boundary,
15
+ * so small inputs save the cost of N callback invocations per parse.
16
+ */
17
+ const DIRECT_PARSE_LIMIT_CHARS = 16 * 1024;
18
+ /**
19
+ * Parse `sourceText` safely on every platform. See {@link SAFE_PARSE_CHUNK_CHARS}
20
+ * for the underlying tree-sitter binding bug this works around.
21
+ */
22
+ export function parseSourceSafe(parser, sourceText, oldTree, options) {
23
+ if (sourceText.length <= DIRECT_PARSE_LIMIT_CHARS) {
24
+ return parser.parse(sourceText, oldTree, options);
25
+ }
26
+ const input = (index) => {
27
+ if (index >= sourceText.length)
28
+ return null;
29
+ return sourceText.slice(index, index + SAFE_PARSE_CHUNK_CHARS);
30
+ };
31
+ return parser.parse(input, oldTree, options);
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.5-rc.2",
3
+ "version": "1.6.5-rc.4",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",