gitnexus 1.6.13-rc.63 → 1.6.13-rc.64

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.
@@ -190,6 +190,22 @@ function resolveAliasString(canonical, legacy) {
190
190
  function nonBlankUid(value) {
191
191
  return typeof value === 'string' ? value.trim() || undefined : undefined;
192
192
  }
193
+ const SYMBOL_IDENTITY_RECOVERY_SUGGESTION = 'Run gitnexus analyze --force from the affected repository root to rebuild the index.';
194
+ class SymbolIdentityError extends Error {
195
+ constructor() {
196
+ super('The index returned an invalid symbol identity. ' + SYMBOL_IDENTITY_RECOVERY_SUGGESTION);
197
+ this.name = 'SymbolIdentityError';
198
+ }
199
+ }
200
+ /** Validate database identities before using them as graph traversal anchors. */
201
+ function assertSymbolIdentity(id, expectedUid) {
202
+ if (typeof id !== 'string' ||
203
+ !id.trim() ||
204
+ id.includes('\0') ||
205
+ (expectedUid !== undefined && id !== expectedUid)) {
206
+ throw new SymbolIdentityError();
207
+ }
208
+ }
193
209
  const TOOL_STRING_ALIASES = {
194
210
  impact: [{ canonical: 'target', aliases: ['name', 'symbol'] }],
195
211
  context: [{ canonical: 'file_path', aliases: ['file'] }],
@@ -3562,6 +3578,7 @@ export class LocalBackend {
3562
3578
  endLine: (r.endLine ?? r[5]),
3563
3579
  ...(include_content ? { content: (r.content ?? r[6]) } : {}),
3564
3580
  };
3581
+ assertSymbolIdentity(symbol.id, uid);
3565
3582
  // Same LadybugDB label-enrichment as the name-based path: a UID
3566
3583
  // pointing at a Class must still surface `type: 'Class'` so impact's
3567
3584
  // Class/Interface BFS seed fires. No-op when type is already set.
@@ -3683,6 +3700,10 @@ export class LocalBackend {
3683
3700
  endLine: (r.endLine ?? r[5]),
3684
3701
  ...(include_content ? { content: (r.content ?? r[6]) } : {}),
3685
3702
  }));
3703
+ // Reject the whole result before narrowing or scoring: dropping a corrupt
3704
+ // candidate could make an unrelated surviving symbol look unambiguous.
3705
+ for (const candidate of normalized)
3706
+ assertSymbolIdentity(candidate.id);
3686
3707
  // An exact File path wins over anchored suffix candidates. Without this,
3687
3708
  // `lib/a.ts` and `src/lib/a.ts` both score as File candidates and turn an
3688
3709
  // otherwise unambiguous exact target into `ambiguous` (#3084 review P2).
@@ -3812,6 +3833,9 @@ export class LocalBackend {
3812
3833
  }
3813
3834
  catch (err) {
3814
3835
  const msg = (err instanceof Error ? err.message : String(err)) || 'Context query failed';
3836
+ if (err instanceof SymbolIdentityError) {
3837
+ return { error: msg, recoverySuggestion: SYMBOL_IDENTITY_RECOVERY_SUGGESTION };
3838
+ }
3815
3839
  if (isWalCorruptionError(err)) {
3816
3840
  return {
3817
3841
  error: msg,
@@ -5749,8 +5773,14 @@ export class LocalBackend {
5749
5773
  catch (err) {
5750
5774
  // Return structured error instead of crashing (#321)
5751
5775
  const message = (err instanceof Error ? err.message : String(err)) || 'Impact analysis failed';
5752
- const suggestion = 'The graph query failed — try gitnexus context <symbol> as a fallback';
5753
- const recoverySuggestion = isWalCorruptionError(err) ? WAL_RECOVERY_SUGGESTION : undefined;
5776
+ const recoverySuggestion = err instanceof SymbolIdentityError
5777
+ ? SYMBOL_IDENTITY_RECOVERY_SUGGESTION
5778
+ : isWalCorruptionError(err)
5779
+ ? WAL_RECOVERY_SUGGESTION
5780
+ : undefined;
5781
+ const suggestion = err instanceof SymbolIdentityError
5782
+ ? SYMBOL_IDENTITY_RECOVERY_SUGGESTION
5783
+ : 'The graph query failed — try gitnexus context <symbol> as a fallback';
5754
5784
  if (params.mode === 'pdg') {
5755
5785
  // Symbol resolution never reached the catch with a resolved symbol (the
5756
5786
  // throw can originate before/within resolution), so the envelope carries
@@ -7496,6 +7526,7 @@ export class LocalBackend {
7496
7526
  'METHOD_IMPLEMENTS',
7497
7527
  ];
7498
7528
  try {
7529
+ assertSymbolIdentity(sym.id ?? sym[0], uid);
7499
7530
  // skipPerSymbolEnrichment suppresses ONLY the per-symbol STEP_IN_PROCESS
7500
7531
  // enrichment pass while preserving byDepth. Group-mode cross-repo fan-out
7501
7532
  // may fan across many repos; the per-symbol pass adds up to MAX_CHUNKS
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.13-rc.63",
3
+ "version": "1.6.13-rc.64",
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",