sigmap 8.34.0 → 8.35.0

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/gen-context.js CHANGED
@@ -5469,8 +5469,13 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
5469
5469
  // Ceilings sit above the default `maxSigsPerFile` so the configured budget
5470
5470
  // governs output rather than a literal buried here, and omissions are disclosed
5471
5471
  // — an undisclosed cap looks like a class that simply has eight methods (#576).
5472
- const MEMBER_LIMIT = 8;
5473
- const PER_FILE_LIMIT = 25;
5472
+ // Class bodies are scanned to this many characters. Real classes routinely
5473
+ // run past the old 4KB scan window — truncating there silently hid every
5474
+ // member after ~4000 chars AND anchored class end-lines short (#576). The
5475
+ // ceiling only guards against pathological input (Java parity, #551).
5476
+ const MAX_CLASS_BODY_CHARS = 200000;
5477
+ const MEMBER_LIMIT = 120;
5478
+ const PER_FILE_LIMIT = 200;
5474
5479
 
5475
5480
  /**
5476
5481
  * Extract signatures from C/C++ source code.
@@ -5507,7 +5512,7 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
5507
5512
 
5508
5513
  function extractBlock(src, startIndex) {
5509
5514
  let depth = 1, i = startIndex;
5510
- const end = Math.min(src.length, startIndex + 4000);
5515
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
5511
5516
  while (i < end && depth > 0) {
5512
5517
  if (src[i] === '{') depth++;
5513
5518
  else if (src[i] === '}') depth--;
@@ -5551,8 +5556,13 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
5551
5556
  // Ceilings sit above the default `maxSigsPerFile` so the configured budget
5552
5557
  // governs output rather than a literal buried here, and omissions are disclosed
5553
5558
  // — an undisclosed cap looks like a class that simply has eight methods (#576).
5554
- const MEMBER_LIMIT = 8;
5555
- const PER_FILE_LIMIT = 25;
5559
+ // Class bodies are scanned to this many characters. Real classes routinely
5560
+ // run past the old 4KB scan window — truncating there silently hid every
5561
+ // member after ~4000 chars AND anchored class end-lines short (#576). The
5562
+ // ceiling only guards against pathological input (Java parity, #551).
5563
+ const MAX_CLASS_BODY_CHARS = 200000;
5564
+ const MEMBER_LIMIT = 120;
5565
+ const PER_FILE_LIMIT = 200;
5556
5566
 
5557
5567
  /**
5558
5568
  * Extract signatures from C# source code.
@@ -5587,7 +5597,7 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
5587
5597
 
5588
5598
  function extractBlock(src, startIndex) {
5589
5599
  let depth = 1, i = startIndex;
5590
- const end = Math.min(src.length, startIndex + 5000);
5600
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
5591
5601
  while (i < end && depth > 0) {
5592
5602
  if (src[i] === '{') depth++;
5593
5603
  else if (src[i] === '}') depth--;
@@ -5632,7 +5642,7 @@ __factories["./src/extractors/css"] = function(module, exports) {
5632
5642
 
5633
5643
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
5634
5644
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
5635
- const PER_FILE_LIMIT = 25;
5645
+ const PER_FILE_LIMIT = 200;
5636
5646
 
5637
5647
  /**
5638
5648
  * Extract signatures from CSS/SCSS/SASS/Less source code.
@@ -5713,8 +5723,13 @@ __factories["./src/extractors/dart"] = function(module, exports) {
5713
5723
  // Ceilings sit above the default `maxSigsPerFile` so the configured budget
5714
5724
  // governs output rather than a literal buried here, and omissions are disclosed
5715
5725
  // — an undisclosed cap looks like a class that simply has eight methods (#576).
5716
- const MEMBER_LIMIT = 8;
5717
- const PER_FILE_LIMIT = 25;
5726
+ // Class bodies are scanned to this many characters. Real classes routinely
5727
+ // run past the old 4KB scan window — truncating there silently hid every
5728
+ // member after ~4000 chars AND anchored class end-lines short (#576). The
5729
+ // ceiling only guards against pathological input (Java parity, #551).
5730
+ const MAX_CLASS_BODY_CHARS = 200000;
5731
+ const MEMBER_LIMIT = 120;
5732
+ const PER_FILE_LIMIT = 200;
5718
5733
 
5719
5734
  /**
5720
5735
  * Extract signatures from Dart source code.
@@ -5768,7 +5783,7 @@ __factories["./src/extractors/dart"] = function(module, exports) {
5768
5783
 
5769
5784
  function extractBlock(src, startIndex) {
5770
5785
  let depth = 1, i = startIndex;
5771
- const end = Math.min(src.length, startIndex + 4000);
5786
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
5772
5787
  while (i < end && depth > 0) {
5773
5788
  if (src[i] === '{') depth++;
5774
5789
  else if (src[i] === '}') depth--;
@@ -6075,7 +6090,7 @@ __factories["./src/extractors/dockerfile"] = function(module, exports) {
6075
6090
 
6076
6091
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
6077
6092
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
6078
- const PER_FILE_LIMIT = 25;
6093
+ const PER_FILE_LIMIT = 200;
6079
6094
 
6080
6095
  /**
6081
6096
  * Extract signatures from Dockerfiles.
@@ -6134,10 +6149,10 @@ __factories["./src/extractors/gdscript"] = function(module, exports) {
6134
6149
 
6135
6150
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
6136
6151
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
6137
- const PER_FILE_LIMIT = 25;
6152
+ const PER_FILE_LIMIT = 200;
6138
6153
 
6139
6154
  // Ceilings disclose what they drop rather than truncating silently (#576).
6140
- const MEMBER_LIMIT = 6;
6155
+ const MEMBER_LIMIT = 120;
6141
6156
  const ENUM_LIMIT = 24;
6142
6157
 
6143
6158
  /**
@@ -6307,11 +6322,19 @@ __factories["./src/extractors/generic"] = function(module, exports) {
6307
6322
  __factories["./src/extractors/go"] = function(module, exports) {
6308
6323
 
6309
6324
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
6310
- const { capWithNotice } = __require('./src/util/truncate');
6325
+ const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
6311
6326
 
6312
6327
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
6313
6328
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
6314
- const PER_FILE_LIMIT = 25;
6329
+ // Class bodies are scanned to this many characters. Real classes routinely
6330
+ // run past the old 4KB scan window — truncating there silently hid every
6331
+ // member after ~4000 chars AND anchored class end-lines short (#576). The
6332
+ // ceiling only guards against pathological input (Java parity, #551).
6333
+ const MAX_CLASS_BODY_CHARS = 200000;
6334
+ const PER_FILE_LIMIT = 200;
6335
+
6336
+ // Per-interface member ceiling, disclosed via capMembersWithNotice (#576).
6337
+ const MEMBER_LIMIT = 120;
6315
6338
 
6316
6339
  /**
6317
6340
  * Extract signatures from Go source code.
@@ -6347,7 +6370,7 @@ __factories["./src/extractors/go"] = function(module, exports) {
6347
6370
  const block = extractBlock(stripped, bodyStart);
6348
6371
  sigs.push(hinted(withAnchor(`type ${m[1]} interface`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)), m[1]));
6349
6372
  for (const meth of extractInterfaceMethods(block)) {
6350
- sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
6373
+ sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
6351
6374
  }
6352
6375
  }
6353
6376
 
@@ -6365,7 +6388,7 @@ __factories["./src/extractors/go"] = function(module, exports) {
6365
6388
 
6366
6389
  function extractBlock(src, startIndex) {
6367
6390
  let depth = 1, i = startIndex;
6368
- const end = Math.min(src.length, startIndex + 2000);
6391
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
6369
6392
  while (i < end && depth > 0) {
6370
6393
  if (src[i] === '{') depth++;
6371
6394
  else if (src[i] === '}') depth--;
@@ -6385,7 +6408,7 @@ __factories["./src/extractors/go"] = function(module, exports) {
6385
6408
  endIdx: m.index + m[0].length,
6386
6409
  });
6387
6410
  }
6388
- return methods.slice(0, 8);
6411
+ return capMembersWithNotice(methods, MEMBER_LIMIT, 'methods');
6389
6412
  }
6390
6413
 
6391
6414
  function normalizeParams(params) {
@@ -6498,7 +6521,7 @@ __factories["./src/extractors/html"] = function(module, exports) {
6498
6521
 
6499
6522
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
6500
6523
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
6501
- const PER_FILE_LIMIT = 25;
6524
+ const PER_FILE_LIMIT = 200;
6502
6525
 
6503
6526
  /**
6504
6527
  * Extract signatures from HTML files.
@@ -6673,6 +6696,10 @@ __factories["./src/extractors/javascript"] = function(module, exports) {
6673
6696
  const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
6674
6697
  const { stripComments, maskCode, readBalanced } = __require('./src/extractors/scan');
6675
6698
 
6699
+ // Class bodies are scanned to this many characters — guard against
6700
+ // pathological input only; the old 4KB window silently hid members (#576).
6701
+ const MAX_CLASS_BODY_CHARS = 200000;
6702
+
6676
6703
  /**
6677
6704
  * Extract signatures from JavaScript source code.
6678
6705
  * Top-level declarations and class members carry a `:start-end` line anchor
@@ -6782,13 +6809,13 @@ __factories["./src/extractors/javascript"] = function(module, exports) {
6782
6809
  const anchored = anchors[i] ? withAnchor(s, anchors[i][0], anchors[i][1]) : s;
6783
6810
  return docHintFor[i] ? `${anchored} # ${docHintFor[i]}` : anchored;
6784
6811
  });
6785
- return capWithNotice(withAnchors, 25, 'signatures');
6812
+ return capWithNotice(withAnchors, 200, 'signatures');
6786
6813
  }
6787
6814
 
6788
6815
  function extractBlock(src, startIndex) {
6789
6816
  let depth = 1;
6790
6817
  let i = startIndex;
6791
- const end = Math.min(src.length, startIndex + 4000);
6818
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
6792
6819
  while (i < end && depth > 0) {
6793
6820
  if (src[i] === '{') depth++;
6794
6821
  else if (src[i] === '}') depth--;
@@ -6823,7 +6850,7 @@ __factories["./src/extractors/javascript"] = function(module, exports) {
6823
6850
  const retStr = formatReturnHint(returnHints.get(m[1]));
6824
6851
  members.push({ text: `${isStatic}${isAsync}${m[1]}(${normalizeParams(params)})${retStr}`, start, end });
6825
6852
  }
6826
- return capMembersWithNotice(members, 8, 'methods');
6853
+ return capMembersWithNotice(members, 120, 'methods');
6827
6854
  }
6828
6855
 
6829
6856
  function buildReturnHints(src) {
@@ -6897,8 +6924,13 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
6897
6924
  // Ceilings sit above the default `maxSigsPerFile` so the configured budget
6898
6925
  // governs output rather than a literal buried here, and omissions are disclosed
6899
6926
  // — an undisclosed cap looks like a class that simply has eight methods (#576).
6900
- const MEMBER_LIMIT = 8;
6901
- const PER_FILE_LIMIT = 25;
6927
+ // Class bodies are scanned to this many characters. Real classes routinely
6928
+ // run past the old 4KB scan window — truncating there silently hid every
6929
+ // member after ~4000 chars AND anchored class end-lines short (#576). The
6930
+ // ceiling only guards against pathological input (Java parity, #551).
6931
+ const MAX_CLASS_BODY_CHARS = 200000;
6932
+ const MEMBER_LIMIT = 120;
6933
+ const PER_FILE_LIMIT = 200;
6902
6934
 
6903
6935
  /**
6904
6936
  * Extract signatures from Kotlin source code.
@@ -6952,7 +6984,7 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
6952
6984
 
6953
6985
  function extractBlock(src, startIndex) {
6954
6986
  let depth = 1, i = startIndex;
6955
- const end = Math.min(src.length, startIndex + 4000);
6987
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
6956
6988
  while (i < end && depth > 0) {
6957
6989
  if (src[i] === '{') depth++;
6958
6990
  else if (src[i] === '}') depth--;
@@ -7054,7 +7086,7 @@ __factories["./src/extractors/lua"] = function(module, exports) {
7054
7086
  // Ceiling discloses what it drops rather than truncating silently (#583).
7055
7087
  // Collection runs to completion so the marker reports the true overflow —
7056
7088
  // stopping early made r.js report "+1 more" where 50 were hidden (#584).
7057
- const PER_FILE_LIMIT = 30;
7089
+ const PER_FILE_LIMIT = 200;
7058
7090
 
7059
7091
  /**
7060
7092
  * Extract signatures from Lua source code.
@@ -7208,7 +7240,7 @@ __factories["./src/extractors/markdown"] = function(module, exports) {
7208
7240
  const { capWithNotice } = __require('./src/util/truncate');
7209
7241
 
7210
7242
  // Ceiling discloses what it drops rather than truncating silently (#583).
7211
- const PER_FILE_LIMIT = 40;
7243
+ const PER_FILE_LIMIT = 200;
7212
7244
 
7213
7245
  /**
7214
7246
  * Lightweight markdown technical indexer.
@@ -7389,8 +7421,13 @@ __factories["./src/extractors/php"] = function(module, exports) {
7389
7421
  // Ceilings sit above the default `maxSigsPerFile` so the configured budget
7390
7422
  // governs output rather than a literal buried here, and omissions are disclosed
7391
7423
  // — an undisclosed cap looks like a class that simply has eight methods (#576).
7392
- const MEMBER_LIMIT = 8;
7393
- const PER_FILE_LIMIT = 25;
7424
+ // Class bodies are scanned to this many characters. Real classes routinely
7425
+ // run past the old 4KB scan window — truncating there silently hid every
7426
+ // member after ~4000 chars AND anchored class end-lines short (#576). The
7427
+ // ceiling only guards against pathological input (Java parity, #551).
7428
+ const MAX_CLASS_BODY_CHARS = 200000;
7429
+ const MEMBER_LIMIT = 120;
7430
+ const PER_FILE_LIMIT = 200;
7394
7431
 
7395
7432
  /**
7396
7433
  * Extract signatures from PHP source code.
@@ -7448,7 +7485,7 @@ __factories["./src/extractors/php"] = function(module, exports) {
7448
7485
 
7449
7486
  function extractBlock(src, startIndex) {
7450
7487
  let depth = 1, i = startIndex;
7451
- const end = Math.min(src.length, startIndex + 4000);
7488
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
7452
7489
  while (i < end && depth > 0) {
7453
7490
  if (src[i] === '{') depth++;
7454
7491
  else if (src[i] === '}') depth--;
@@ -7568,7 +7605,7 @@ __factories["./src/extractors/properties"] = function(module, exports) {
7568
7605
  const { capWithNotice } = __require('./src/util/truncate');
7569
7606
 
7570
7607
  // Ceiling discloses what it drops rather than truncating silently (#583).
7571
- const PER_FILE_LIMIT = 50;
7608
+ const PER_FILE_LIMIT = 200;
7572
7609
 
7573
7610
  /**
7574
7611
  * Extract signatures from .properties configuration files.
@@ -7684,7 +7721,10 @@ __factories["./src/extractors/python"] = function(module, exports) {
7684
7721
 
7685
7722
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
7686
7723
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
7687
- const PER_FILE_LIMIT = 30;
7724
+ const PER_FILE_LIMIT = 200;
7725
+
7726
+ // Per-class member ceiling, disclosed via capWithNotice (#576).
7727
+ const MEMBER_LIMIT = 120;
7688
7728
 
7689
7729
  /**
7690
7730
  * 1-based line of the last source line belonging to a top-level (indent 0)
@@ -7840,7 +7880,7 @@ __factories["./src/extractors/python"] = function(module, exports) {
7840
7880
  methods.push(`${asyncKw}def ${m[1]}(${params})${retStr}`);
7841
7881
  }
7842
7882
  }
7843
- return methods.slice(0, 8);
7883
+ return capWithNotice(methods, MEMBER_LIMIT, 'methods');
7844
7884
  }
7845
7885
 
7846
7886
  function tryExtractDataclassFields(stripped, classIndex) {
@@ -7949,6 +7989,8 @@ __factories["./src/extractors/python"] = function(module, exports) {
7949
7989
  // ── ./src/extractors/python_dataclass ──
7950
7990
  __factories["./src/extractors/python_dataclass"] = function(module, exports) {
7951
7991
 
7992
+ const { capWithNotice } = __require('./src/util/truncate');
7993
+
7952
7994
  /**
7953
7995
  * Extract Python dataclass, Pydantic model, and SQLAlchemy ORM metadata.
7954
7996
  * Focuses on model fields, validation, and relationships.
@@ -8020,7 +8062,7 @@ __factories["./src/extractors/python_dataclass"] = function(module, exports) {
8020
8062
  sigs.push('config-class');
8021
8063
  }
8022
8064
 
8023
- return Array.from(new Set(sigs)).slice(0, 50);
8065
+ return capWithNotice(Array.from(new Set(sigs)), 200, 'signatures');
8024
8066
  }
8025
8067
 
8026
8068
  module.exports = { extract };
@@ -8034,7 +8076,7 @@ __factories["./src/extractors/r"] = function(module, exports) {
8034
8076
 
8035
8077
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
8036
8078
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
8037
- const PER_FILE_LIMIT = 30;
8079
+ const PER_FILE_LIMIT = 200;
8038
8080
 
8039
8081
  /**
8040
8082
  * Extract signatures from R source code.
@@ -8313,7 +8355,7 @@ __factories["./src/extractors/ruby"] = function(module, exports) {
8313
8355
 
8314
8356
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
8315
8357
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
8316
- const PER_FILE_LIMIT = 25;
8358
+ const PER_FILE_LIMIT = 200;
8317
8359
 
8318
8360
  /**
8319
8361
  * Extract signatures from Ruby source code.
@@ -8374,11 +8416,19 @@ __factories["./src/extractors/ruby"] = function(module, exports) {
8374
8416
  __factories["./src/extractors/rust"] = function(module, exports) {
8375
8417
 
8376
8418
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
8377
- const { capWithNotice } = __require('./src/util/truncate');
8419
+ const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
8378
8420
 
8379
8421
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
8380
8422
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
8381
- const PER_FILE_LIMIT = 25;
8423
+ // Class bodies are scanned to this many characters. Real classes routinely
8424
+ // run past the old 4KB scan window — truncating there silently hid every
8425
+ // member after ~4000 chars AND anchored class end-lines short (#576). The
8426
+ // ceiling only guards against pathological input (Java parity, #551).
8427
+ const MAX_CLASS_BODY_CHARS = 200000;
8428
+ const PER_FILE_LIMIT = 200;
8429
+
8430
+ // Per-impl member ceiling, disclosed via capMembersWithNotice (#576).
8431
+ const MEMBER_LIMIT = 120;
8382
8432
 
8383
8433
  /**
8384
8434
  * Extract signatures from Rust source code.
@@ -8436,7 +8486,7 @@ __factories["./src/extractors/rust"] = function(module, exports) {
8436
8486
  const block = extractBlock(stripped, bodyStart);
8437
8487
  sigs.push(withAnchor(`impl ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
8438
8488
  for (const fn of extractMethods(block)) {
8439
- sigs.push(hinted(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + fn.declIdx), lineAt(stripped, bodyStart + fn.endIdx)), fn.name));
8489
+ sigs.push(hinted(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + (fn.declIdx || 0)), lineAt(stripped, bodyStart + (fn.endIdx || 0))), fn.name));
8440
8490
  }
8441
8491
  }
8442
8492
 
@@ -8453,7 +8503,7 @@ __factories["./src/extractors/rust"] = function(module, exports) {
8453
8503
 
8454
8504
  function extractBlock(src, startIndex) {
8455
8505
  let depth = 1, i = startIndex;
8456
- const end = Math.min(src.length, startIndex + 5000);
8506
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
8457
8507
  while (i < end && depth > 0) {
8458
8508
  if (src[i] === '{') depth++;
8459
8509
  else if (src[i] === '}') depth--;
@@ -8474,7 +8524,7 @@ __factories["./src/extractors/rust"] = function(module, exports) {
8474
8524
  endIdx: m.index + m[0].length,
8475
8525
  });
8476
8526
  }
8477
- return methods.slice(0, 8);
8527
+ return capMembersWithNotice(methods, MEMBER_LIMIT, 'methods');
8478
8528
  }
8479
8529
 
8480
8530
  function normalizeParams(params) {
@@ -8526,8 +8576,13 @@ __factories["./src/extractors/scala"] = function(module, exports) {
8526
8576
  // Ceilings sit above the default `maxSigsPerFile` so the configured budget
8527
8577
  // governs output rather than a literal buried here, and omissions are disclosed
8528
8578
  // — an undisclosed cap looks like a class that simply has eight methods (#576).
8529
- const MEMBER_LIMIT = 8;
8530
- const PER_FILE_LIMIT = 25;
8579
+ // Class bodies are scanned to this many characters. Real classes routinely
8580
+ // run past the old 4KB scan window — truncating there silently hid every
8581
+ // member after ~4000 chars AND anchored class end-lines short (#576). The
8582
+ // ceiling only guards against pathological input (Java parity, #551).
8583
+ const MAX_CLASS_BODY_CHARS = 200000;
8584
+ const MEMBER_LIMIT = 120;
8585
+ const PER_FILE_LIMIT = 200;
8531
8586
 
8532
8587
  /**
8533
8588
  * Extract signatures from Scala source code.
@@ -8574,7 +8629,7 @@ __factories["./src/extractors/scala"] = function(module, exports) {
8574
8629
 
8575
8630
  function extractBlock(src, startIndex) {
8576
8631
  let depth = 1, i = startIndex;
8577
- const end = Math.min(src.length, startIndex + 4000);
8632
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
8578
8633
  while (i < end && depth > 0) {
8579
8634
  if (src[i] === '{') depth++;
8580
8635
  else if (src[i] === '}') depth--;
@@ -8719,7 +8774,7 @@ __factories["./src/extractors/shell"] = function(module, exports) {
8719
8774
 
8720
8775
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
8721
8776
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
8722
- const PER_FILE_LIMIT = 25;
8777
+ const PER_FILE_LIMIT = 200;
8723
8778
 
8724
8779
  /**
8725
8780
  * Extract signatures from shell scripts (bash, zsh, fish).
@@ -8869,7 +8924,7 @@ __factories["./src/extractors/svelte"] = function(module, exports) {
8869
8924
 
8870
8925
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
8871
8926
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
8872
- const PER_FILE_LIMIT = 25;
8927
+ const PER_FILE_LIMIT = 200;
8873
8928
 
8874
8929
  /**
8875
8930
  * Extract signatures from Svelte components.
@@ -8939,8 +8994,13 @@ __factories["./src/extractors/swift"] = function(module, exports) {
8939
8994
  // Ceilings sit above the default `maxSigsPerFile` so the configured budget
8940
8995
  // governs output rather than a literal buried here, and omissions are disclosed
8941
8996
  // — an undisclosed cap looks like a class that simply has eight methods (#576).
8942
- const MEMBER_LIMIT = 8;
8943
- const PER_FILE_LIMIT = 25;
8997
+ // Class bodies are scanned to this many characters. Real classes routinely
8998
+ // run past the old 4KB scan window — truncating there silently hid every
8999
+ // member after ~4000 chars AND anchored class end-lines short (#576). The
9000
+ // ceiling only guards against pathological input (Java parity, #551).
9001
+ const MAX_CLASS_BODY_CHARS = 200000;
9002
+ const MEMBER_LIMIT = 120;
9003
+ const PER_FILE_LIMIT = 200;
8944
9004
 
8945
9005
  /**
8946
9006
  * Extract signatures from Swift source code.
@@ -8994,7 +9054,7 @@ __factories["./src/extractors/swift"] = function(module, exports) {
8994
9054
 
8995
9055
  function extractBlock(src, startIndex) {
8996
9056
  let depth = 1, i = startIndex;
8997
- const end = Math.min(src.length, startIndex + 4000);
9057
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
8998
9058
  while (i < end && depth > 0) {
8999
9059
  if (src[i] === '{') depth++;
9000
9060
  else if (src[i] === '}') depth--;
@@ -9153,7 +9213,7 @@ __factories["./src/extractors/toml"] = function(module, exports) {
9153
9213
  const { capWithNotice } = __require('./src/util/truncate');
9154
9214
 
9155
9215
  // Ceiling discloses what it drops rather than truncating silently (#583).
9156
- const PER_FILE_LIMIT = 40;
9216
+ const PER_FILE_LIMIT = 200;
9157
9217
 
9158
9218
  /**
9159
9219
  * Extract signatures from TOML configuration files.
@@ -9205,6 +9265,10 @@ __factories["./src/extractors/typescript"] = function(module, exports) {
9205
9265
  const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
9206
9266
  const { stripComments, maskCode, readBalanced } = __require('./src/extractors/scan');
9207
9267
 
9268
+ // Class bodies are scanned to this many characters — guard against
9269
+ // pathological input only; the old 4KB window silently hid members (#576).
9270
+ const MAX_CLASS_BODY_CHARS = 200000;
9271
+
9208
9272
  /**
9209
9273
  * Extract signatures from TypeScript source code.
9210
9274
  * Top-level declarations carry a `:start-end` line anchor (see line-anchor.js);
@@ -9390,13 +9454,13 @@ __factories["./src/extractors/typescript"] = function(module, exports) {
9390
9454
  const anchored = anchors[i] ? withAnchor(s, anchors[i][0], anchors[i][1]) : s;
9391
9455
  return docHintFor[i] ? `${anchored} # ${docHintFor[i]}` : anchored;
9392
9456
  });
9393
- return capWithNotice(withAnchors, 35, 'signatures');
9457
+ return capWithNotice(withAnchors, 200, 'signatures');
9394
9458
  }
9395
9459
 
9396
9460
  function extractBlock(src, startIndex) {
9397
9461
  let depth = 1;
9398
9462
  let i = startIndex;
9399
- const end = Math.min(src.length, startIndex + 4000);
9463
+ const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
9400
9464
  while (i < end && depth > 0) {
9401
9465
  if (src[i] === '{') depth++;
9402
9466
  else if (src[i] === '}') depth--;
@@ -9424,7 +9488,7 @@ __factories["./src/extractors/typescript"] = function(module, exports) {
9424
9488
  const start = m.index + (m[0].length - m[0].replace(/^\s+/, '').length);
9425
9489
  members.push({ text: `${m[1]}(${normalizeParams(block.slice(openIdx + 1, closeIdx))})`, start, end: closeIdx + 1 });
9426
9490
  }
9427
- return capMembersWithNotice(members, 8, 'members');
9491
+ return capMembersWithNotice(members, 120, 'members');
9428
9492
  }
9429
9493
 
9430
9494
  const _CTRL_KEYWORDS = new Set(['if', 'for', 'while', 'switch', 'do', 'try', 'catch', 'finally', 'else', 'return']);
@@ -9459,7 +9523,7 @@ __factories["./src/extractors/typescript"] = function(module, exports) {
9459
9523
  const retStr = retType ? ` → ${retType}` : '';
9460
9524
  members.push({ text: `${isStatic}${isAsync}${m[1]}(${normalizeParams(params)})${retStr}`, start, end });
9461
9525
  }
9462
- return capMembersWithNotice(members, 8, 'methods');
9526
+ return capMembersWithNotice(members, 120, 'methods');
9463
9527
  }
9464
9528
 
9465
9529
  function normalizeParams(params) {
@@ -9534,7 +9598,7 @@ __factories["./src/extractors/typescript_react"] = function(module, exports) {
9534
9598
  const { capWithNotice } = __require('./src/util/truncate');
9535
9599
 
9536
9600
  // Ceiling discloses what it drops rather than truncating silently (#583).
9537
- const PER_FILE_LIMIT = 50;
9601
+ const PER_FILE_LIMIT = 200;
9538
9602
 
9539
9603
  /**
9540
9604
  * Extract React component signatures from .tsx files.
@@ -9600,6 +9664,8 @@ __factories["./src/extractors/typescript_react"] = function(module, exports) {
9600
9664
  // ── ./src/extractors/vue_sfc ──
9601
9665
  __factories["./src/extractors/vue_sfc"] = function(module, exports) {
9602
9666
 
9667
+ const { capWithNotice } = __require('./src/util/truncate');
9668
+
9603
9669
  /**
9604
9670
  * Extract Vue Single-File Component (SFC) signatures from .vue files.
9605
9671
  * Captures component metadata: name, props, emits, slots, composables, lifecycle.
@@ -9693,7 +9759,7 @@ __factories["./src/extractors/vue_sfc"] = function(module, exports) {
9693
9759
  sigs.push(`slot ${s}`);
9694
9760
  }
9695
9761
 
9696
- return Array.from(new Set(sigs)).slice(0, 50);
9762
+ return capWithNotice(Array.from(new Set(sigs)), 200, 'signatures');
9697
9763
  }
9698
9764
 
9699
9765
  module.exports = { extract };
@@ -9703,6 +9769,8 @@ __factories["./src/extractors/vue_sfc"] = function(module, exports) {
9703
9769
  // ── ./src/extractors/xml ──
9704
9770
  __factories["./src/extractors/xml"] = function(module, exports) {
9705
9771
 
9772
+ const { capWithNotice } = __require('./src/util/truncate');
9773
+
9706
9774
  /**
9707
9775
  * Lightweight XML config extractor.
9708
9776
  * Captures root tags, key config tags, and id/name/class attributes.
@@ -9743,7 +9811,7 @@ __factories["./src/extractors/xml"] = function(module, exports) {
9743
9811
  if (cls) sigs.push(`${tag} -> ${cls[1]}`);
9744
9812
  }
9745
9813
 
9746
- return Array.from(new Set(sigs)).slice(0, 50);
9814
+ return capWithNotice(Array.from(new Set(sigs)), 200, 'signatures');
9747
9815
  }
9748
9816
 
9749
9817
  module.exports = { extract };
@@ -9757,7 +9825,7 @@ __factories["./src/extractors/yaml"] = function(module, exports) {
9757
9825
 
9758
9826
  // Ceiling sits above the default `maxSigsPerFile` so the configured budget
9759
9827
  // governs output rather than a literal buried here, and omissions are disclosed (#576).
9760
- const PER_FILE_LIMIT = 25;
9828
+ const PER_FILE_LIMIT = 200;
9761
9829
 
9762
9830
  /**
9763
9831
  * Extract signatures from YAML configuration files.
@@ -16065,8 +16133,8 @@ __factories["./src/mcp/server"] = function(module, exports) {
16065
16133
  * One JSON object per line on both stdin and stdout.
16066
16134
  *
16067
16135
  * Supported methods:
16068
- * initialize → serverInfo + capabilities
16069
- * tools/list → 19 tool definitions
16136
+ * initialize → serverInfo + capabilities + negotiated protocolVersion
16137
+ * tools/list → 21 tool definitions
16070
16138
  * tools/call → dispatch to handler, return result
16071
16139
  */
16072
16140
 
@@ -16076,10 +16144,22 @@ __factories["./src/mcp/server"] = function(module, exports) {
16076
16144
 
16077
16145
  const SERVER_INFO = {
16078
16146
  name: 'sigmap',
16079
- version: '8.34.0',
16147
+ version: '8.35.0',
16080
16148
  description: 'SigMap MCP server — code signatures on demand',
16081
16149
  };
16082
16150
 
16151
+ // Protocol revisions this server actually speaks. The tools-only surface —
16152
+ // initialize / tools/list / tools/call plus the initialized/cancelled
16153
+ // notifications — is identical across these revisions, and the
16154
+ // @hasmcp/mcp-spec-test suite passes every applicable 2025-11-25 case against
16155
+ // it. 2026-07-28 is deliberately absent: that revision requires
16156
+ // server/discover, which is not implemented. Newest first: a client offering
16157
+ // a version outside this list is downgraded to [0], never echoed back —
16158
+ // echoing an unspeakable version is itself a spec violation (#544), and it
16159
+ // made the conformance suite believe 2026-07-28 was supported, producing six
16160
+ // phantom server/discover failures on a revision never really offered (#545).
16161
+ const SUPPORTED_PROTOCOL_VERSIONS = ['2025-11-25', '2025-06-18', '2025-03-26', '2024-11-05'];
16162
+
16083
16163
  // ---------------------------------------------------------------------------
16084
16164
  // JSON-RPC helpers
16085
16165
  // ---------------------------------------------------------------------------
@@ -16104,9 +16184,32 @@ __factories["./src/mcp/server"] = function(module, exports) {
16104
16184
  return;
16105
16185
  }
16106
16186
 
16187
+ // server/discover (spec 2026-07-28) — session-less discovery, answerable
16188
+ // before any handshake, so a client can learn the honest version list
16189
+ // instead of offering versions and hoping. The response is a
16190
+ // CacheableResult: deterministic, so the TTL promise of stability holds.
16191
+ // Note supportedVersions does NOT include 2026-07-28 — answering discover
16192
+ // is forward-compatible plumbing, not a claim to serve that revision's
16193
+ // whole surface (per-result envelopes, inline _meta negotiation).
16194
+ if (method === 'server/discover') {
16195
+ respond(id, {
16196
+ resultType: 'complete',
16197
+ cacheScope: 'public',
16198
+ ttlMs: 3600000,
16199
+ supportedVersions: SUPPORTED_PROTOCOL_VERSIONS,
16200
+ capabilities: { tools: {} },
16201
+ serverInfo: SERVER_INFO,
16202
+ instructions: 'SigMap serves code signatures for the working directory. Call query_context or search_signatures to rank and fetch signature blocks instead of reading whole files.',
16203
+ });
16204
+ return;
16205
+ }
16206
+
16107
16207
  if (method === 'initialize') {
16208
+ const offered = params && params.protocolVersion;
16108
16209
  respond(id, {
16109
- protocolVersion: (params && params.protocolVersion) || '2024-11-05',
16210
+ protocolVersion: SUPPORTED_PROTOCOL_VERSIONS.includes(offered)
16211
+ ? offered
16212
+ : SUPPORTED_PROTOCOL_VERSIONS[0],
16110
16213
  serverInfo: SERVER_INFO,
16111
16214
  capabilities: { tools: {} },
16112
16215
  });
@@ -16114,6 +16217,13 @@ __factories["./src/mcp/server"] = function(module, exports) {
16114
16217
  }
16115
16218
 
16116
16219
  if (method === 'tools/list') {
16220
+ // No pagination: the full list fits one page, so any cursor a client
16221
+ // presents is one this server never issued — reject it (-32602, per the
16222
+ // spec's SHOULD) rather than silently restarting from page one.
16223
+ if (params && params.cursor !== undefined) {
16224
+ respondError(id, -32602, `Invalid cursor: ${String(params.cursor)}`);
16225
+ return;
16226
+ }
16117
16227
  respond(id, { tools: TOOLS });
16118
16228
  return;
16119
16229
  }
@@ -17743,9 +17853,15 @@ __factories["./src/retrieval/ranker"] = function(module, exports) {
17743
17853
  const hop1Files = new Set(); // normalised keys that received a hop1 boost
17744
17854
  const hop1Seeds = []; // original (un-normalised) paths, for hop-2 lookup
17745
17855
 
17746
- // Hop 1: direct neighbors of scored files
17747
- for (const entry of scored) {
17748
- if (entry.score <= 0) continue;
17856
+ // Hop 1: direct neighbors of scored files. Seeds snapshotted BEFORE the
17857
+ // loop (as the call-graph block below already does) so boosts never
17858
+ // cascade: a file whose only score is a hop-1 boost must not become a seed
17859
+ // itself mid-loop, or the effective seed set — and every boost total —
17860
+ // depends on index insertion order, which git history changes via the
17861
+ // recent-commits hoist. That made gate scores differ between a shallow CI
17862
+ // checkout and a developer clone of the same commit (#596).
17863
+ const hop1SeedEntries = scored.filter((e) => e.score > 0);
17864
+ for (const entry of hop1SeedEntries) {
17749
17865
  const neighbors = _graphGet(graph.forward, path.resolve(cwd, entry.file)) || [];
17750
17866
  for (const neighborAbs of neighbors) {
17751
17867
  const nk = path.normalize(neighborAbs);
@@ -17760,7 +17876,10 @@ __factories["./src/retrieval/ranker"] = function(module, exports) {
17760
17876
  }
17761
17877
  }
17762
17878
 
17763
- // Hop 2: neighbors of hop1 files (only if they didn't get a direct score)
17879
+ // Hop 2: neighbors of hop1 files (only if they didn't get a direct score).
17880
+ // Eligibility frozen after hop-1 for the same reason: a file whose first
17881
+ // score is a hop-2 boost must not become hop-2-eligible mid-loop (#596).
17882
+ const hop2Eligible = scored.map((e) => e.score > 0);
17764
17883
  for (const hop1Key of hop1Seeds) {
17765
17884
  if (_graphGet(keyToIdx, hop1Key) === undefined) continue; // skip files not in index
17766
17885
  const neighbors = _graphGet(graph.forward, hop1Key) || [];
@@ -17769,7 +17888,7 @@ __factories["./src/retrieval/ranker"] = function(module, exports) {
17769
17888
  if (_isHub(nk) || hubs.has(nk) || hubs.has(nk.toLowerCase())) continue;
17770
17889
  if (hop1Files.has(nk)) continue; // skip already hop1-boosted
17771
17890
  const idx = _graphGet(keyToIdx, nk);
17772
- if (idx !== undefined && scored[idx].score > 0) {
17891
+ if (idx !== undefined && hop2Eligible[idx]) {
17773
17892
  // Only boost files that have some baseline score (not noise)
17774
17893
  scored[idx].score += GRAPH_BOOST_AMOUNTS.hop2;
17775
17894
  scored[idx].signals.graphBoost = (scored[idx].signals.graphBoost || 0) + GRAPH_BOOST_AMOUNTS.hop2;
@@ -22370,7 +22489,7 @@ function __tryGit(args, opts = {}) {
22370
22489
  catch (_) { return ''; }
22371
22490
  }
22372
22491
 
22373
- const VERSION = '8.34.0';
22492
+ const VERSION = '8.35.0';
22374
22493
  const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
22375
22494
 
22376
22495
  function requireSourceOrBundled(key) {
@@ -22665,7 +22784,20 @@ function estimateTokens(str) {
22665
22784
  }
22666
22785
 
22667
22786
  function isTestFile(filePath) {
22668
- return /\.(test|spec)\.[a-z]+$/.test(filePath) || /_test\.[a-z]+$/.test(filePath);
22787
+ const p = filePath.replace(/\\/g, '/');
22788
+ // Filename conventions: foo.test.ts / foo.spec.js / foo_test.go / test_foo.py,
22789
+ // plus the PascalCase JVM/C#/Swift family (FooTest.java, FooTests.kt,
22790
+ // FooSpec.scala). The [a-z0-9] guard keeps `contest.java` and `Latest.java`
22791
+ // out; the suffix must be a real case boundary.
22792
+ if (/\.(test|spec)\.[a-z]+$/.test(p) || /_test\.[a-z]+$/.test(p)) return true;
22793
+ if (/(^|\/)test_[^/]+\.[a-z]+$/.test(p)) return true;
22794
+ if (/[a-z0-9](Test|Spec)s?\.(java|kt|kts|scala|groovy|cs|swift)$/.test(p)) return true;
22795
+ // Path-segment conventions (src/test/java/**, tests/, spec/, __tests__/, e2e/)
22796
+ // — the form the entire JVM world uses. Without this, "drop test files first"
22797
+ // ran INVERTED on JVM repos: spring-petclinic's budget kept all 17 src/test/
22798
+ // files while dropping the application entry point, the owner entities and
22799
+ // every owner template (#592).
22800
+ return /(^|\/)(test|tests|spec|specs|__tests__|e2e)(\/|$)/i.test(p);
22669
22801
  }
22670
22802
 
22671
22803
  function isConfigFile(filePath) {
@@ -22684,6 +22816,21 @@ function isMockFile(filePath) {
22684
22816
  /mock\.(ts|js|tsx|jsx)$/.test(p);
22685
22817
  }
22686
22818
 
22819
+ // The application entry point is the single most orientation-valuable file in
22820
+ // a repo, yet it is often tiny (a main class with 2-3 signatures), so the
22821
+ // fewest-sigs tie-break dropped it while keeping bulkier files: petclinic's
22822
+ // budget dropped PetClinicApplication.java and an agent asking for the startup
22823
+ // entry point could not reach it at all (#592). Deliberately narrow — bare
22824
+ // main/app/application names plus the Spring `*Application.java` and C#
22825
+ // `Program.cs` conventions. `index.*` is excluded: JS barrel files are hubs,
22826
+ // not entry points, and protecting every one would crowd out real code.
22827
+ function isEntryPointFile(filePath) {
22828
+ const base = path.basename(filePath.replace(/\\/g, '/'));
22829
+ return /^(main|app|application|__main__)\.[a-z]+$/i.test(base)
22830
+ || /Application\.(java|kt|kts)$/.test(base)
22831
+ || /^Program\.cs$/.test(base);
22832
+ }
22833
+
22687
22834
  /**
22688
22835
  * Compute the effective token budget based on repo size and config.
22689
22836
  *
@@ -22803,6 +22950,7 @@ function applyTokenBudget(fileEntries, maxTokens) {
22803
22950
  else if (isMockFile(e.filePath)) { priority = 9; dropReason = 'budget: mock file'; }
22804
22951
  else if (isTestFile(e.filePath)) { priority = 8; dropReason = 'budget: test file'; }
22805
22952
  else if (isConfigFile(e.filePath)) { priority = 6; dropReason = 'budget: config file'; }
22953
+ else if (isEntryPointFile(e.filePath)) { priority = 3; dropReason = 'budget: entry point'; }
22806
22954
  else priority = 4;
22807
22955
  const loc = e.content ? e.content.split('\n').length : 1;
22808
22956
  const signalQuality = loc > 0 ? (e.sigs ? e.sigs.length : 0) / loc : 0;