gitnexus 1.6.10-rc.8 → 1.6.10-rc.9

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
@@ -535,17 +535,26 @@ After scope resolution, analyze prunes inert block-local value symbols (a functi
535
535
 
536
536
  Programmatic callers can pass `keepLocalValueSymbols: true` in `PipelineOptions` instead of setting the env var.
537
537
 
538
- ### Hook augmentation/notifications are silently skipped
538
+ ### Hook augmentation and skip diagnostics
539
539
 
540
- The Claude Code / Antigravity hooks intentionally stay **silent** on normal skip
540
+ The Claude Code / Antigravity hooks keep their **stderr** silent on normal skip
541
541
  paths so strict hook runners (e.g. Codex `PreToolUse`) never see unexpected
542
- output. A search may not be augmented — or a stale-index reminder may not appear
543
- on stderr — when the GitNexus MCP server owns the repo DB, when the DB-lock probe
544
- times out and fails closed, or when the index is already current.
545
-
546
- To see why a hook skipped, set `GITNEXUS_DEBUG=1` and re-run the action the hook
547
- writes the reason (e.g. `[GitNexus] augment skipped: MCP server owns DB`) and the
548
- stale-index hint to its stderr:
542
+ diagnostic output.
543
+
544
+ When a GitNexus process holds the repo DB write lock (the common case the MCP
545
+ server is running, or the DB-lock probe timed out and failed closed), the local
546
+ CLI `augment` can't run (LadybugDB is single-writer). Rather than drop the
547
+ augmentation, the hook hands the agent a short, conditional MCP-query hint on
548
+ stdout (the sanctioned `additionalContext` channel) — _"if the GitNexus MCP tools
549
+ are live in this session, call `query` …"_ — so an agent that has the tools can
550
+ still fetch graph-ranked context. The hint is throttled to at most once per repo
551
+ per window (`GITNEXUS_MCP_HINT_THROTTLE_MS`, default 10 min; `0` disables), so an
552
+ owner-locked session isn't nudged on every search. A stale-index reminder, or an
553
+ already-current index, stays silent.
554
+
555
+ To see why a hook skipped the CLI augment, set `GITNEXUS_DEBUG=1` and re-run the
556
+ action — the hook writes the reason (e.g. `[GitNexus] augment skipped: MCP server
557
+ owns DB`) and the stale-index hint to its stderr:
549
558
 
550
559
  ```bash
551
560
  GITNEXUS_DEBUG=1 <your command> # surfaces hook skip/diagnostic reasons on stderr
@@ -391,6 +391,49 @@ function buildAfterToolContext(input) {
391
391
  return parts.length > 0 ? parts.join('\n\n') : null;
392
392
  }
393
393
 
394
+ /**
395
+ * Fallback augmentation for the #2396 path: when a GitNexus process holds the
396
+ * lbug DB write lock the CLI `augment` can't run, so point the agent at the MCP
397
+ * `query` tool instead. Phrased conditionally ("if the MCP tools are live") so it
398
+ * stays truthful on every owner path — a confirmed MCP owner, a `serve` owner, or
399
+ * a fail-closed probe where no server is actually confirmed. `pattern` is embedded
400
+ * verbatim; the caller (writeAdditionalContext) JSON-escapes it structurally.
401
+ */
402
+ function buildMcpQueryHint(pattern) {
403
+ return (
404
+ `[GitNexus] Local augment is unavailable (the graph DB is held by another ` +
405
+ `GitNexus process). If the GitNexus MCP tools are live in this session, call ` +
406
+ `the GitNexus \`query\` MCP tool (e.g. mcp__gitnexus__query) with ` +
407
+ `search_query "${pattern}".`
408
+ );
409
+ }
410
+
411
+ /**
412
+ * #2396 throttle: emit the MCP-query hint at most once per repo per window, so an
413
+ * owner-locked session isn't nudged on every search. Window (ms) via
414
+ * GITNEXUS_MCP_HINT_THROTTLE_MS (default 10min; 0/invalid disables). Best-effort —
415
+ * any fs error falls back to emitting.
416
+ * ponytail: per-repo mtime marker, shared across concurrent sessions on the same
417
+ * repo; add per-session dedup only if that sharing becomes a problem.
418
+ */
419
+ function shouldEmitMcpHint(gitNexusDir) {
420
+ const raw = process.env.GITNEXUS_MCP_HINT_THROTTLE_MS;
421
+ const windowMs = raw === undefined || raw === '' ? 600000 : Number(raw);
422
+ if (!Number.isFinite(windowMs) || windowMs <= 0) return true;
423
+ const marker = path.join(gitNexusDir, '.mcp-hint-shown');
424
+ try {
425
+ if (Date.now() - fs.statSync(marker).mtimeMs < windowMs) return false;
426
+ } catch {
427
+ /* marker missing/unreadable → emit */
428
+ }
429
+ try {
430
+ fs.writeFileSync(marker, '');
431
+ } catch {
432
+ /* best-effort; still emit */
433
+ }
434
+ return true;
435
+ }
436
+
394
437
  function runAugment(gitNexusDir, cwd, pattern) {
395
438
  // Acquire the per-repo slot BEFORE the DB-owner probe (#2163): the probe
396
439
  // itself spawns lsof/ps, so it must be bounded by the same ≤3-per-repo cap
@@ -410,12 +453,16 @@ function runAugment(gitNexusDir, cwd, pattern) {
410
453
  }
411
454
  try {
412
455
  if (hasGitNexusServerOwner(gitNexusDir)) {
413
- // Normal skip path: the MCP server owns the DB. Stay silent for strict
414
- // hook runners (issue #1913); surface the reason only under GITNEXUS_DEBUG.
456
+ // #2396: the MCP server holds the DB write lock, so a competing CLI
457
+ // `augment` would only contend on it (LadybugDB is single-writer). The
458
+ // session has the GitNexus MCP tools live — route the augmentation to the
459
+ // agent via additionalContext instead of dropping it. Mirror the skip
460
+ // reason to stderr only under GITNEXUS_DEBUG (strict-runner contract,
461
+ // #1913); the hint itself rides the sanctioned additionalContext channel.
415
462
  if (isDebugEnabled()) {
416
463
  process.stderr.write('[GitNexus] augment skipped: MCP server owns DB\n');
417
464
  }
418
- return '';
465
+ return shouldEmitMcpHint(gitNexusDir) ? buildMcpQueryHint(pattern) : '';
419
466
  }
420
467
  const cliPath = resolveCliPath();
421
468
  const child = runGitNexusCli(cliPath, ['augment', '--', pattern], cwd, 7000);
@@ -349,6 +349,49 @@ function runGitNexusCli(cliPath, args, cwd, timeout) {
349
349
  });
350
350
  }
351
351
 
352
+ /**
353
+ * Fallback augmentation for the #2396 path: when a GitNexus process holds the
354
+ * lbug DB write lock the CLI `augment` can't run, so point the agent at the MCP
355
+ * `query` tool instead. Phrased conditionally ("if the MCP tools are live") so it
356
+ * stays truthful on every owner path — a confirmed MCP owner, a `serve` owner, or
357
+ * a fail-closed probe where no server is actually confirmed. `pattern` is embedded
358
+ * verbatim; the caller (sendHookResponse) JSON-escapes it structurally.
359
+ */
360
+ function buildMcpQueryHint(pattern) {
361
+ return (
362
+ `[GitNexus] Local augment is unavailable (the graph DB is held by another ` +
363
+ `GitNexus process). If the GitNexus MCP tools are live in this session, call ` +
364
+ `the GitNexus \`query\` MCP tool (e.g. mcp__gitnexus__query) with ` +
365
+ `search_query "${pattern}".`
366
+ );
367
+ }
368
+
369
+ /**
370
+ * #2396 throttle: emit the MCP-query hint at most once per repo per window, so an
371
+ * owner-locked session isn't nudged on every search. Window (ms) via
372
+ * GITNEXUS_MCP_HINT_THROTTLE_MS (default 10min; 0/invalid disables). Best-effort —
373
+ * any fs error falls back to emitting.
374
+ * ponytail: per-repo mtime marker, shared across concurrent sessions on the same
375
+ * repo; add per-session dedup only if that sharing becomes a problem.
376
+ */
377
+ function shouldEmitMcpHint(gitNexusDir) {
378
+ const raw = process.env.GITNEXUS_MCP_HINT_THROTTLE_MS;
379
+ const windowMs = raw === undefined || raw === '' ? 600000 : Number(raw);
380
+ if (!Number.isFinite(windowMs) || windowMs <= 0) return true;
381
+ const marker = path.join(gitNexusDir, '.mcp-hint-shown');
382
+ try {
383
+ if (Date.now() - fs.statSync(marker).mtimeMs < windowMs) return false;
384
+ } catch {
385
+ /* marker missing/unreadable → emit */
386
+ }
387
+ try {
388
+ fs.writeFileSync(marker, '');
389
+ } catch {
390
+ /* best-effort; still emit */
391
+ }
392
+ return true;
393
+ }
394
+
352
395
  /**
353
396
  * PreToolUse handler — augment searches with graph context.
354
397
  */
@@ -385,18 +428,25 @@ function handlePreToolUse(input) {
385
428
  let result = '';
386
429
  try {
387
430
  if (hasGitNexusServerOwner(gitNexusDir)) {
388
- // Normal skip path: the MCP server owns the DB, so the CLI augment would
389
- // contend on the lock. Stay silent for strict hook runners (issue #1913);
390
- // surface the reason only when diagnostics are explicitly requested.
431
+ // #2396: the MCP server holds the DB write lock, so a competing CLI
432
+ // `augment` would only contend on it (LadybugDB is single-writer). But the
433
+ // session that triggered this hook has the GitNexus MCP tools live route
434
+ // the augmentation to the agent via additionalContext instead of silently
435
+ // doing nothing. Mirror the skip reason to stderr only under GITNEXUS_DEBUG
436
+ // (strict-runner contract, #1913); the hint itself rides the sanctioned
437
+ // additionalContext stdout channel the successful augment already uses.
391
438
  if (isDebugEnabled()) {
392
439
  process.stderr.write('[GitNexus] augment skipped: MCP server owns DB\n');
393
440
  }
394
- return;
395
- }
396
- const cliPath = resolveCliPath();
397
- const child = runGitNexusCli(cliPath, ['augment', '--', pattern], cwd, 7000);
398
- if (!child.error && child.status === 0) {
399
- result = extractAugmentContext(child.stderr || '');
441
+ if (shouldEmitMcpHint(gitNexusDir)) {
442
+ result = buildMcpQueryHint(pattern);
443
+ }
444
+ } else {
445
+ const cliPath = resolveCliPath();
446
+ const child = runGitNexusCli(cliPath, ['augment', '--', pattern], cwd, 7000);
447
+ if (!child.error && child.status === 0) {
448
+ result = extractAugmentContext(child.stderr || '');
449
+ }
400
450
  }
401
451
  } catch {
402
452
  /* graceful failure */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.10-rc.8",
3
+ "version": "1.6.10-rc.9",
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",