gitnexus 1.6.13-rc.82 → 1.6.13-rc.83

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.
@@ -12,6 +12,12 @@ import type { NodeLabel } from '../../_shared/index.js';
12
12
  import { KnowledgeGraph } from '../graph/types.js';
13
13
  /** Graphology Graph instance type (AbstractGraph from graphology-types avoids CJS/ESM interop namespace issue) */
14
14
  type GraphInstance = AbstractGraph<Attributes, Attributes, Attributes>;
15
+ /** Result returned by leiden.detailed() */
16
+ interface LeidenDetailedResult {
17
+ communities: Record<string, number>;
18
+ count: number;
19
+ modularity: number;
20
+ }
15
21
  type CommunityEngine = 'graphology' | 'icebug';
16
22
  export type CommunityDetectionEngine = CommunityEngine | 'auto';
17
23
  export interface CommunityDetectionOptions {
@@ -48,6 +54,11 @@ export interface CommunityCsr {
48
54
  indptr: BigUint64Array;
49
55
  indices: BigUint64Array;
50
56
  }
57
+ interface CommunityEngineResult extends LeidenDetailedResult {
58
+ engine: CommunityEngine;
59
+ engineRequested: CommunityDetectionEngine;
60
+ fallbackReason?: string;
61
+ }
51
62
  export declare const resolveCommunityDetectionEngine: (raw?: string) => CommunityDetectionEngine;
52
63
  export interface CommunityNode {
53
64
  id: string;
@@ -92,6 +103,7 @@ export declare const processCommunities: (knowledgeGraph: KnowledgeGraph, onProg
92
103
  export declare const buildCommunityProjection: (knowledgeGraph: KnowledgeGraph) => CommunityProjection;
93
104
  export declare const buildCommunityCsr: (projection: CommunityProjection) => CommunityCsr;
94
105
  export declare const buildGraphologyGraph: (projection: CommunityProjection) => GraphInstance;
106
+ export declare const runGraphologyLeiden: (graph: GraphInstance, isLarge: boolean, engineRequested: CommunityDetectionEngine, timeoutMs?: number) => Promise<CommunityEngineResult>;
95
107
  /**
96
108
  * Runs Leiden in a worker so a native crash cannot take the analyze process
97
109
  * with it. Written against @ladybugmem/icebug's published surface (lib/index.js
@@ -21,7 +21,9 @@ const __dirname = dirname(__filename);
21
21
  // Navigate to package root (works from both src/ and dist/)
22
22
  const leidenPath = resolve(__dirname, '..', '..', '..', 'vendor', 'leiden', 'index.cjs');
23
23
  const _require = createRequire(import.meta.url);
24
- const leiden = _require(leidenPath);
24
+ // The Leiden worker loads its own copy; this load keeps a missing vendor/ asset
25
+ // failing at import time and keeps it visible to dockerfile-runtime-asset-parity.
26
+ _require(leidenPath);
25
27
  /**
26
28
  * Deterministic PRNG (mulberry32) seed for the vendored Leiden algorithm.
27
29
  * Vendored Leiden defaults `rng: Math.random`, which makes community
@@ -30,15 +32,6 @@ const leiden = _require(leidenPath);
30
32
  * incremental-indexing equivalence test (incremental ≡ full rebuild).
31
33
  */
32
34
  const LEIDEN_SEED = 0xc0de;
33
- function createSeededRng(seed) {
34
- let s = seed >>> 0;
35
- return () => {
36
- s = (s + 0x6d2b79f5) >>> 0;
37
- let t = Math.imul(s ^ (s >>> 15), 1 | s);
38
- t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
39
- return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
40
- };
41
- }
42
35
  const COMMUNITY_ENGINE_ENV = 'GITNEXUS_COMMUNITY_ENGINE';
43
36
  /**
44
37
  * Not a declared dependency: the prebuilds need system Arrow 24, libomp and
@@ -289,19 +282,96 @@ const runCommunityEngine = async (graph, projection, engineRequested, options, o
289
282
  const fallbackReason = error instanceof Error ? error.message : String(error);
290
283
  onProgress?.(`Icebug community engine unavailable, falling back to Graphology: ${fallbackReason}`, 35);
291
284
  const fallback = await runGraphologyLeiden(graph, projection.isLarge, engineRequested);
292
- return { ...fallback, fallbackReason };
285
+ return {
286
+ ...fallback,
287
+ fallbackReason: fallback.fallbackReason
288
+ ? `${fallbackReason}; ${fallback.fallbackReason}`
289
+ : fallbackReason,
290
+ };
293
291
  }
294
292
  };
295
- const runGraphologyLeiden = async (graph, isLarge, engineRequested) => {
293
+ /**
294
+ * Runs the vendored Leiden in a worker so LEIDEN_TIMEOUT_MS can actually fire.
295
+ * leiden.detailed is synchronous and, on some graphs, never returns
296
+ * (graphology/graphology#557); a timer on the main thread cannot interrupt it.
297
+ * The worker is pure JS, so terminate() is safe (unlike the icebug N-API worker).
298
+ */
299
+ const GRAPHOLOGY_WORKER_SOURCE = `
300
+ const { parentPort, workerData } = require('node:worker_threads');
301
+ try {
302
+ const Graph = require(workerData.graphologyPath);
303
+ const leiden = require(workerData.leidenPath);
304
+ const graph = Graph.from(workerData.graph);
305
+ const rng = (() => {
306
+ let s = workerData.seed >>> 0;
307
+ return () => {
308
+ s = (s + 0x6d2b79f5) >>> 0;
309
+ let t = Math.imul(s ^ (s >>> 15), 1 | s);
310
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
311
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
312
+ };
313
+ })();
314
+ const d = leiden.detailed(graph, {
315
+ resolution: workerData.resolution,
316
+ maxIterations: workerData.maxIterations,
317
+ rng,
318
+ });
319
+ parentPort.postMessage({
320
+ ok: true,
321
+ communities: d.communities,
322
+ count: d.count,
323
+ modularity: d.modularity,
324
+ });
325
+ } catch (error) {
326
+ parentPort.postMessage({ ok: false, error: error instanceof Error ? error.message : String(error) });
327
+ }
328
+ `;
329
+ export const runGraphologyLeiden = async (graph, isLarge, engineRequested, timeoutMs = LEIDEN_TIMEOUT_MS) => {
296
330
  try {
297
- const details = await Promise.race([
298
- Promise.resolve(leiden.detailed(graph, {
299
- resolution: isLarge ? 2.0 : 1.0,
300
- maxIterations: isLarge ? 3 : 0,
301
- rng: createSeededRng(LEIDEN_SEED),
302
- })),
303
- new Promise((_, reject) => setTimeout(() => reject(new Error('Leiden timeout')), LEIDEN_TIMEOUT_MS)),
304
- ]);
331
+ const details = await new Promise((resolve, reject) => {
332
+ const worker = new Worker(GRAPHOLOGY_WORKER_SOURCE, {
333
+ eval: true,
334
+ workerData: {
335
+ graphologyPath: _require.resolve('graphology'),
336
+ leidenPath,
337
+ graph: graph.export(),
338
+ seed: LEIDEN_SEED,
339
+ resolution: isLarge ? 2.0 : 1.0,
340
+ maxIterations: isLarge ? 3 : 0,
341
+ },
342
+ });
343
+ let settled = false;
344
+ const timeout = setTimeout(() => {
345
+ settled = true;
346
+ void worker.terminate();
347
+ reject(new Error('Leiden timeout'));
348
+ }, timeoutMs);
349
+ worker.once('message', (message) => {
350
+ settled = true;
351
+ clearTimeout(timeout);
352
+ if (message.ok === true) {
353
+ resolve({
354
+ communities: message.communities,
355
+ count: message.count,
356
+ modularity: message.modularity,
357
+ });
358
+ }
359
+ else {
360
+ reject(new Error(message.error));
361
+ }
362
+ });
363
+ worker.once('error', (error) => {
364
+ settled = true;
365
+ clearTimeout(timeout);
366
+ reject(error);
367
+ });
368
+ worker.once('exit', (code) => {
369
+ if (settled)
370
+ return;
371
+ clearTimeout(timeout);
372
+ reject(new Error(`Graphology Leiden worker exited with code ${code}`));
373
+ });
374
+ });
305
375
  return { ...details, engine: 'graphology', engineRequested };
306
376
  }
307
377
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.13-rc.82",
3
+ "version": "1.6.13-rc.83",
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",
@@ -289,6 +289,7 @@ const SPAWN_CLI = [
289
289
  // Worker threads tests — exercise real worker_threads which have
290
290
  // platform-specific behavior (thread spawning, IPC, exit handling)
291
291
  const WORKER_THREADS = [
292
+ 'test/unit/community-processor.test.ts',
292
293
  'test/integration/worker-pool.test.ts',
293
294
  'test/integration/parse-impl-quarantine-cache-skip.test.ts',
294
295
  ];