Compare commits

...
Author SHA1 Message Date
copilot-swe-agent[bot]andmagyargergo 740d3b9b83 chore(parse): clarify test description and warning message phrasing
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/5591f1ba-9032-4706-b007-effb0df46eb8

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
2026-05-18 06:47:41 +00:00
copilot-swe-agent[bot]andmagyargergo 350b1ece63 chore(parse): use template literal for warning, add .hh test case
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/5591f1ba-9032-4706-b007-effb0df46eb8

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
2026-05-18 06:46:45 +00:00
copilot-swe-agent[bot]andmagyargergo af81512f61 chore(parse): rename chunkHasCppFiles → chunkHasWorkerUnsafeFiles, add hpp/hxx test
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/5591f1ba-9032-4706-b007-effb0df46eb8

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
2026-05-18 06:45:36 +00:00
copilot-swe-agent[bot]andmagyargergo 950f41bfdf fix(analyze): per-chunk C/C++ guard — workers for all other languages unchanged
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/5591f1ba-9032-4706-b007-effb0df46eb8

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
2026-05-18 06:44:14 +00:00
copilot-swe-agent[bot] f1593016da chore(parse): refine C/C++ worker guard naming and warning guidance
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/1417a00f-d72b-4659-8c8e-e0c8a1cbfa4c
2026-05-18 06:28:15 +00:00
copilot-swe-agent[bot] f2cbf27219 refactor(parse): move worker language guard helper and clarify warning
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/1417a00f-d72b-4659-8c8e-e0c8a1cbfa4c
2026-05-18 06:27:01 +00:00
copilot-swe-agent[bot] 676f91ebf5 fix(analyze): disable worker pool by default for C/C++ parse workloads
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/1417a00f-d72b-4659-8c8e-e0c8a1cbfa4c
2026-05-18 06:25:26 +00:00
copilot-swe-agent[bot] 8c5648563f Initial plan 2026-05-18 06:04:20 +00:00
4 changed files with 81 additions and 1 deletions
+1
View File
@@ -81,6 +81,7 @@ program
' GITNEXUS_MAX_FILE_SIZE=N Override large-file skip threshold (KB). Default 512, max 32768.\n' +
' GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS=N Worker idle timeout in milliseconds. Default 30000.\n' +
' GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES=N Worker job byte budget. Default 8388608.\n' +
' GITNEXUS_ALLOW_CPP_WORKERS=1 Force worker threads even when C/C++ files are detected.\n' +
' GITNEXUS_EMBEDDING_THREADS=N Limit local ONNX CPU threads for --embeddings.\n' +
' GITNEXUS_SEMANTIC_EXACT_SCAN_LIMIT=N Max embedding chunks for exact-scan fallback. Default 10000.\n' +
'\nTip: `.gitnexusignore` supports `.gitignore`-style negation. Add e.g.\n' +
@@ -71,6 +71,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
import { isDev } from '../utils/env.js';
import { synthesizeWildcardImportBindings, needsSynthesis } from './wildcard-synthesis.js';
import { extractORMQueriesInline } from './orm-extraction.js';
import { hasWorkerUnsafeLanguages } from '../workers/worker-language-guard.js';
import { logger } from '../../logger.js';
// ── Constants ──────────────────────────────────────────────────────────────
@@ -315,6 +316,8 @@ export async function runChunkedParseAndResolve(
const parseCache = options?.parseCache;
let chunkCacheHits = 0;
let chunkCacheMisses = 0;
// Suppress duplicate warnings when multiple consecutive chunks contain C/C++ files.
let hasWarnedAboutCppChunks = false;
try {
for (let chunkIdx = 0; chunkIdx < numChunks; chunkIdx++) {
@@ -370,6 +373,25 @@ export async function runChunkedParseAndResolve(
// them under the chunk hash for the next run.
chunkCacheMisses++;
const rawResults: ParseWorkerResult[] = [];
// C/C++ grammar native bindings can crash worker threads with an
// unrecoverable Napi::Error / std::terminate(). Detect C/C++ files
// within this specific chunk and route them through the main-thread
// sequential path to avoid the crash. Other chunks (no C/C++) keep
// using the worker pool. GITNEXUS_ALLOW_CPP_WORKERS=1 opts out of
// this guard when a stable custom build is in use.
const chunkHasWorkerUnsafeFiles =
workerPool &&
process.env.GITNEXUS_ALLOW_CPP_WORKERS !== '1' &&
hasWorkerUnsafeLanguages(chunkFiles);
if (chunkHasWorkerUnsafeFiles && !hasWarnedAboutCppChunks) {
hasWarnedAboutCppChunks = true;
logger.warn(
`C/C++ files detected — parsing chunks containing C/C++ files in sequential mode to avoid known ` +
`worker-thread native binding errors (e.g. \`Napi::Error\`). C/C++ source files ` +
`are still fully indexed; chunks with no C/C++ continue using workers. ` +
`Set GITNEXUS_ALLOW_CPP_WORKERS=1 if you use a custom tree-sitter build without this issue.`,
);
}
chunkWorkerData = await processParsing(
graph,
chunkFiles,
@@ -391,7 +413,11 @@ export async function runChunkedParseAndResolve(
},
});
},
workerPool,
// For chunks containing C/C++ files, bypass the worker pool to avoid
// unrecoverable Napi::Error crashes from native grammar bindings in
// worker threads. processParsing falls through to processParsingSequential
// (main-thread safe). All other chunks keep using the worker pool.
chunkHasWorkerUnsafeFiles ? undefined : workerPool,
// Capture raw results only when we have a cache to write to —
// otherwise we'd retain extra arrays for nothing.
parseCache && chunkHash ? rawResults : undefined,
@@ -0,0 +1,12 @@
import { getLanguageFromFilename, SupportedLanguages } from 'gitnexus-shared';
const WORKER_UNSAFE_LANGUAGES = new Set<SupportedLanguages>([
SupportedLanguages.C,
SupportedLanguages.CPlusPlus,
]);
export const hasWorkerUnsafeLanguages = (files: ReadonlyArray<{ path: string }>): boolean =>
files.some((f) => {
const language = getLanguageFromFilename(f.path);
return language !== null && WORKER_UNSAFE_LANGUAGES.has(language);
});
@@ -0,0 +1,41 @@
import { describe, expect, it } from 'vitest';
import { hasWorkerUnsafeLanguages } from '../../src/core/ingestion/workers/worker-language-guard.js';
describe('hasWorkerUnsafeLanguages', () => {
it('returns false for non-C/C++ inputs', () => {
expect(
hasWorkerUnsafeLanguages([
{ path: 'src/app.ts', size: 123 },
{ path: 'src/main.py', size: 456 },
]),
).toBe(false);
});
it('returns true when C++ (.cpp) files are present', () => {
expect(
hasWorkerUnsafeLanguages([
{ path: 'src/main.ts', size: 123 },
{ path: 'native/runtime.cpp', size: 456 },
]),
).toBe(true);
});
it('returns true when C files (.c extension) are present', () => {
expect(hasWorkerUnsafeLanguages([{ path: 'lib/util.c', size: 100 }])).toBe(true);
});
it('returns true when C header files are present', () => {
expect(hasWorkerUnsafeLanguages([{ path: 'include/api.h', size: 100 }])).toBe(true);
});
it('returns true when C++ header files (.hpp, .hxx, .hh) are present', () => {
expect(hasWorkerUnsafeLanguages([{ path: 'include/api.hpp', size: 100 }])).toBe(true);
expect(hasWorkerUnsafeLanguages([{ path: 'include/core.hxx', size: 100 }])).toBe(true);
expect(hasWorkerUnsafeLanguages([{ path: 'include/util.hh', size: 100 }])).toBe(true);
});
it('returns false for an empty list', () => {
expect(hasWorkerUnsafeLanguages([])).toBe(false);
});
});