sigmap 8.31.0 → 8.32.1

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
@@ -1790,6 +1790,55 @@ __factories["./src/config/loader"] = function(module, exports) {
1790
1790
  });
1791
1791
  }
1792
1792
 
1793
+ /**
1794
+ * Directory depth needed to reach source under a JVM package layout.
1795
+ *
1796
+ * `maxDepth: 6` is right for the JS/Python-shaped trees it was tuned on, but a
1797
+ * JVM project puts one directory per package segment — real code in
1798
+ * `src/main/java/com/company/project/module/Class.java` sits 8-10 levels down.
1799
+ * At depth 6 only the top-level package was indexed: on spring-petclinic, 6 of
1800
+ * 47 Java files (#590).
1801
+ *
1802
+ * #561 already raised the dependency-graph walk to 12 for exactly this reason,
1803
+ * so extraction was the shallower half of an inconsistent pair.
1804
+ *
1805
+ * Deepening globally is not free — it adds candidates to every repo and cost
1806
+ * 2.2pp on the (filename-leaky) 105-task matrix corpus while the unbiased
1807
+ * `mined` corpus stayed flat. So the depth is raised only where the layout
1808
+ * demands it, leaving non-JVM repos byte-identical.
1809
+ *
1810
+ * @param {string} cwd
1811
+ * @returns {boolean} true when the repo looks like a Maven/Gradle/sbt project
1812
+ */
1813
+ function _isJvmLayout(cwd) {
1814
+ const MARKERS = ['pom.xml', 'build.gradle', 'build.gradle.kts', 'build.sbt', 'settings.gradle', 'settings.gradle.kts'];
1815
+ for (const m of MARKERS) {
1816
+ try { if (fs.existsSync(path.join(cwd, m))) return true; } catch { /* unreadable cwd */ }
1817
+ }
1818
+ for (const d of ['src/main/java', 'src/main/kotlin', 'src/main/scala']) {
1819
+ try { if (fs.existsSync(path.join(cwd, d))) return true; } catch { /* ignore */ }
1820
+ }
1821
+ return false;
1822
+ }
1823
+
1824
+ /** Walk depth for a JVM package layout — matches the graph walk from #561. */
1825
+ const JVM_MAX_DEPTH = 12;
1826
+
1827
+ /**
1828
+ * Raise `maxDepth` to the JVM depth when the layout needs it (#590).
1829
+ * An explicit user value always wins, including a deliberately shallow one.
1830
+ * @param {object} cfg resolved config (mutated and returned)
1831
+ * @param {string} cwd
1832
+ * @param {boolean} userSetDepth
1833
+ * @returns {object} cfg
1834
+ */
1835
+ function _applyJvmDepth(cfg, cwd, userSetDepth) {
1836
+ if (!userSetDepth && cfg.maxDepth < JVM_MAX_DEPTH && _isJvmLayout(cwd)) {
1837
+ cfg.maxDepth = JVM_MAX_DEPTH;
1838
+ }
1839
+ return cfg;
1840
+ }
1841
+
1793
1842
  /**
1794
1843
  * Load and merge configuration for a given working directory.
1795
1844
  *
@@ -1802,7 +1851,7 @@ __factories["./src/config/loader"] = function(module, exports) {
1802
1851
  const cfg = deepClone(DEFAULTS);
1803
1852
  const detected = detectAutoSrcDirs(cwd, cfg.exclude);
1804
1853
  if (detected.length > 0) cfg.srcDirs = detected;
1805
- return cfg;
1854
+ return _applyJvmDepth(cfg, cwd, false);
1806
1855
  }
1807
1856
 
1808
1857
  let userConfig;
@@ -1814,7 +1863,7 @@ __factories["./src/config/loader"] = function(module, exports) {
1814
1863
  const cfg = deepClone(DEFAULTS);
1815
1864
  const detected = detectAutoSrcDirs(cwd, cfg.exclude);
1816
1865
  if (detected.length > 0) cfg.srcDirs = detected;
1817
- return cfg;
1866
+ return _applyJvmDepth(cfg, cwd, false);
1818
1867
  }
1819
1868
 
1820
1869
  // Warn on unknown keys (helps catch typos)
@@ -1866,7 +1915,8 @@ __factories["./src/config/loader"] = function(module, exports) {
1866
1915
  } else if (Array.isArray(merged.adapters) && !userConfig.outputs) {
1867
1916
  merged.outputs = merged.adapters.filter((a) => ['copilot','claude','cursor','windsurf'].includes(a));
1868
1917
  }
1869
- return merged;
1918
+
1919
+ return _applyJvmDepth(merged, cwd, userConfig.maxDepth !== undefined);
1870
1920
  }
1871
1921
 
1872
1922
  function deepClone(obj) {
@@ -4118,7 +4168,6 @@ __factories["./src/eval/analyzer"] = function(module, exports) {
4118
4168
  '.scala': 'scala', '.sc': 'scala',
4119
4169
  '.gd': 'gdscript',
4120
4170
  '.r': 'r', '.R': 'r',
4121
- '.vue': 'vue',
4122
4171
  '.svelte': 'svelte',
4123
4172
  '.html': 'html', '.htm': 'html',
4124
4173
  '.css': 'css', '.scss': 'css', '.sass': 'css', '.less': 'css',
@@ -5439,6 +5488,14 @@ __factories["./src/extractors/coverage"] = function(module, exports) {
5439
5488
  // ── ./src/extractors/cpp ──
5440
5489
  __factories["./src/extractors/cpp"] = function(module, exports) {
5441
5490
 
5491
+ const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
5492
+
5493
+ // Ceilings sit above the default `maxSigsPerFile` so the configured budget
5494
+ // governs output rather than a literal buried here, and omissions are disclosed
5495
+ // — an undisclosed cap looks like a class that simply has eight methods (#576).
5496
+ const MEMBER_LIMIT = 8;
5497
+ const PER_FILE_LIMIT = 25;
5498
+
5442
5499
  /**
5443
5500
  * Extract signatures from C/C++ source code.
5444
5501
  * @param {string} src - Raw file content
@@ -5469,7 +5526,7 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
5469
5526
  sigs.push(`${m[2]}(${normalizeParams(m[3])})${retStr}`);
5470
5527
  }
5471
5528
 
5472
- return sigs.slice(0, 25);
5529
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
5473
5530
  }
5474
5531
 
5475
5532
  function extractBlock(src, startIndex) {
@@ -5492,7 +5549,7 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
5492
5549
  const retStr = ret ? ` → ${ret}` : '';
5493
5550
  members.push(`${m[2]}(${normalizeParams(m[3])})${retStr}`);
5494
5551
  }
5495
- return members.slice(0, 8);
5552
+ return capWithNotice(members, MEMBER_LIMIT, 'members');
5496
5553
  }
5497
5554
 
5498
5555
  function normalizeParams(params) {
@@ -5513,6 +5570,13 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
5513
5570
  __factories["./src/extractors/csharp"] = function(module, exports) {
5514
5571
 
5515
5572
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
5573
+ const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
5574
+
5575
+ // Ceilings sit above the default `maxSigsPerFile` so the configured budget
5576
+ // governs output rather than a literal buried here, and omissions are disclosed
5577
+ // — an undisclosed cap looks like a class that simply has eight methods (#576).
5578
+ const MEMBER_LIMIT = 8;
5579
+ const PER_FILE_LIMIT = 25;
5516
5580
 
5517
5581
  /**
5518
5582
  * Extract signatures from C# source code.
@@ -5537,11 +5601,12 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
5537
5601
  const block = extractBlock(stripped, bodyStart);
5538
5602
  sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, declIdx), lineAt(stripped, bodyStart + block.length)));
5539
5603
  for (const meth of extractMembers(block)) {
5540
- sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
5604
+ // The disclosure marker carries no offsets; anchor it at the class body.
5605
+ sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
5541
5606
  }
5542
5607
  }
5543
5608
 
5544
- return sigs.slice(0, 25);
5609
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
5545
5610
  }
5546
5611
 
5547
5612
  function extractBlock(src, startIndex) {
@@ -5567,7 +5632,7 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
5567
5632
  endIdx: m.index + m[0].length,
5568
5633
  });
5569
5634
  }
5570
- return members.slice(0, 8);
5635
+ return capMembersWithNotice(members, MEMBER_LIMIT);
5571
5636
  }
5572
5637
 
5573
5638
  function normalizeParams(params) {
@@ -5587,6 +5652,12 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
5587
5652
  // ── ./src/extractors/css ──
5588
5653
  __factories["./src/extractors/css"] = function(module, exports) {
5589
5654
 
5655
+ const { capWithNotice } = __require('./src/util/truncate');
5656
+
5657
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
5658
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
5659
+ const PER_FILE_LIMIT = 25;
5660
+
5590
5661
  /**
5591
5662
  * Extract signatures from CSS/SCSS/SASS/Less source code.
5592
5663
  * @param {string} src - Raw file content
@@ -5650,7 +5721,7 @@ __factories["./src/extractors/css"] = function(module, exports) {
5650
5721
  for (const name of selected) sigs.push(`.${name}`);
5651
5722
  }
5652
5723
 
5653
- return sigs.slice(0, 25);
5724
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
5654
5725
  }
5655
5726
 
5656
5727
  module.exports = { extract };
@@ -5661,6 +5732,13 @@ __factories["./src/extractors/css"] = function(module, exports) {
5661
5732
  __factories["./src/extractors/dart"] = function(module, exports) {
5662
5733
 
5663
5734
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
5735
+ const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
5736
+
5737
+ // Ceilings sit above the default `maxSigsPerFile` so the configured budget
5738
+ // governs output rather than a literal buried here, and omissions are disclosed
5739
+ // — an undisclosed cap looks like a class that simply has eight methods (#576).
5740
+ const MEMBER_LIMIT = 8;
5741
+ const PER_FILE_LIMIT = 25;
5664
5742
 
5665
5743
  /**
5666
5744
  * Extract signatures from Dart source code.
@@ -5696,7 +5774,8 @@ __factories["./src/extractors/dart"] = function(module, exports) {
5696
5774
  const block = extractBlock(stripped, bodyStart);
5697
5775
  sigs.push(withAnchor(`${abs}class ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
5698
5776
  for (const meth of extractMembers(block)) {
5699
- sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
5777
+ // The disclosure marker carries no offsets; anchor it at the class body.
5778
+ sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
5700
5779
  }
5701
5780
  }
5702
5781
 
@@ -5708,7 +5787,7 @@ __factories["./src/extractors/dart"] = function(module, exports) {
5708
5787
  sigs.push(withAnchor(`${m[2]}(${normalizeParams(m[3])})${retStr}`, s, e));
5709
5788
  }
5710
5789
 
5711
- return sigs.slice(0, 25);
5790
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
5712
5791
  }
5713
5792
 
5714
5793
  function extractBlock(src, startIndex) {
@@ -5733,7 +5812,7 @@ __factories["./src/extractors/dart"] = function(module, exports) {
5733
5812
  endIdx: m.index + m[0].length,
5734
5813
  });
5735
5814
  }
5736
- return members.slice(0, 8);
5815
+ return capMembersWithNotice(members, MEMBER_LIMIT);
5737
5816
  }
5738
5817
 
5739
5818
  function normalizeParams(params) {
@@ -5892,7 +5971,6 @@ __factories["./src/extractors/dispatch"] = function(module, exports) {
5892
5971
  scala: __require('./src/extractors/scala'),
5893
5972
  gdscript: __require('./src/extractors/gdscript'),
5894
5973
  r: __require('./src/extractors/r'),
5895
- vue: __require('./src/extractors/vue'),
5896
5974
  vue_sfc: __require('./src/extractors/vue_sfc'),
5897
5975
  svelte: __require('./src/extractors/svelte'),
5898
5976
  html: __require('./src/extractors/html'),
@@ -5978,6 +6056,12 @@ __factories["./src/extractors/dispatch"] = function(module, exports) {
5978
6056
  // ── ./src/extractors/dockerfile ──
5979
6057
  __factories["./src/extractors/dockerfile"] = function(module, exports) {
5980
6058
 
6059
+ const { capWithNotice } = __require('./src/util/truncate');
6060
+
6061
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
6062
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
6063
+ const PER_FILE_LIMIT = 25;
6064
+
5981
6065
  /**
5982
6066
  * Extract signatures from Dockerfiles.
5983
6067
  * @param {string} src - Raw file content
@@ -6021,7 +6105,7 @@ __factories["./src/extractors/dockerfile"] = function(module, exports) {
6021
6105
  if (m) sigs.push(`ARG ${m[1]}`);
6022
6106
  }
6023
6107
 
6024
- return sigs.slice(0, 25);
6108
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
6025
6109
  }
6026
6110
 
6027
6111
  module.exports = { extract };
@@ -6031,6 +6115,16 @@ __factories["./src/extractors/dockerfile"] = function(module, exports) {
6031
6115
  // ── ./src/extractors/gdscript ──
6032
6116
  __factories["./src/extractors/gdscript"] = function(module, exports) {
6033
6117
 
6118
+ const { capWithNotice } = __require('./src/util/truncate');
6119
+
6120
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
6121
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
6122
+ const PER_FILE_LIMIT = 25;
6123
+
6124
+ // Ceilings disclose what they drop rather than truncating silently (#576).
6125
+ const MEMBER_LIMIT = 6;
6126
+ const ENUM_LIMIT = 24;
6127
+
6034
6128
  /**
6035
6129
  * Extract signatures from Godot GDScript source code.
6036
6130
  * @param {string} src - Raw file content
@@ -6075,7 +6169,7 @@ __factories["./src/extractors/gdscript"] = function(module, exports) {
6075
6169
  .split(',')
6076
6170
  .map((s) => s.trim().split(/\s*=/)[0].trim())
6077
6171
  .filter(Boolean);
6078
- sigs.push(`${indent}enum ${m[1]} { ${members.slice(0, 6).join(', ')} }`);
6172
+ sigs.push(`${indent}enum ${m[1]} { ${capWithNotice(members, ENUM_LIMIT, 'values').join(', ')} }`);
6079
6173
  }
6080
6174
 
6081
6175
  let constCount = 0;
@@ -6123,7 +6217,7 @@ __factories["./src/extractors/gdscript"] = function(module, exports) {
6123
6217
  }
6124
6218
  }
6125
6219
 
6126
- return sigs.slice(0, 25);
6220
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
6127
6221
  }
6128
6222
 
6129
6223
  function extractInnerMembers(stripped, startIndex) {
@@ -6141,7 +6235,7 @@ __factories["./src/extractors/gdscript"] = function(module, exports) {
6141
6235
  members.push(`${staticKw}func ${fm[2]}(${params})${retStr}`);
6142
6236
  }
6143
6237
  }
6144
- return members.slice(0, 6);
6238
+ return capWithNotice(members, MEMBER_LIMIT, 'members');
6145
6239
  }
6146
6240
 
6147
6241
  function normalizeParams(params) {
@@ -6198,6 +6292,11 @@ __factories["./src/extractors/generic"] = function(module, exports) {
6198
6292
  __factories["./src/extractors/go"] = function(module, exports) {
6199
6293
 
6200
6294
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
6295
+ const { capWithNotice } = __require('./src/util/truncate');
6296
+
6297
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
6298
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
6299
+ const PER_FILE_LIMIT = 25;
6201
6300
 
6202
6301
  /**
6203
6302
  * Extract signatures from Go source code.
@@ -6246,7 +6345,7 @@ __factories["./src/extractors/go"] = function(module, exports) {
6246
6345
  sigs.push(hinted(withAnchor(`func ${receiver}${m[2]}(${normalizeParams(m[3])})${retStr}`, lineAt(stripped, m.index), lineAt(stripped, end)), m[2]));
6247
6346
  }
6248
6347
 
6249
- return sigs.slice(0, 25);
6348
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
6250
6349
  }
6251
6350
 
6252
6351
  function extractBlock(src, startIndex) {
@@ -6380,6 +6479,12 @@ __factories["./src/extractors/graphql"] = function(module, exports) {
6380
6479
  // ── ./src/extractors/html ──
6381
6480
  __factories["./src/extractors/html"] = function(module, exports) {
6382
6481
 
6482
+ const { capWithNotice } = __require('./src/util/truncate');
6483
+
6484
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
6485
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
6486
+ const PER_FILE_LIMIT = 25;
6487
+
6383
6488
  /**
6384
6489
  * Extract signatures from HTML files.
6385
6490
  * Focuses on id/class attributes, forms, and script tags.
@@ -6413,7 +6518,7 @@ __factories["./src/extractors/html"] = function(module, exports) {
6413
6518
  sigs.push(`data-${m[0].match(/data-(\w[\w-]*)/i)[1]}: ${m[1]}`);
6414
6519
  }
6415
6520
 
6416
- return sigs.slice(0, 25);
6521
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
6417
6522
  }
6418
6523
 
6419
6524
  module.exports = { extract };
@@ -6772,6 +6877,13 @@ __factories["./src/extractors/javascript"] = function(module, exports) {
6772
6877
  __factories["./src/extractors/kotlin"] = function(module, exports) {
6773
6878
 
6774
6879
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
6880
+ const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
6881
+
6882
+ // Ceilings sit above the default `maxSigsPerFile` so the configured budget
6883
+ // governs output rather than a literal buried here, and omissions are disclosed
6884
+ // — an undisclosed cap looks like a class that simply has eight methods (#576).
6885
+ const MEMBER_LIMIT = 8;
6886
+ const PER_FILE_LIMIT = 25;
6775
6887
 
6776
6888
  /**
6777
6889
  * Extract signatures from Kotlin source code.
@@ -6806,7 +6918,8 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
6806
6918
  const block = extractBlock(stripped, bodyStart);
6807
6919
  sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
6808
6920
  for (const meth of extractMembers(block)) {
6809
- sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
6921
+ // The disclosure marker carries no offsets; anchor it at the class body.
6922
+ sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
6810
6923
  }
6811
6924
  }
6812
6925
 
@@ -6819,7 +6932,7 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
6819
6932
  sigs.push(withAnchor(`${suspend}fun ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
6820
6933
  }
6821
6934
 
6822
- return sigs.slice(0, 25);
6935
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
6823
6936
  }
6824
6937
 
6825
6938
  function extractBlock(src, startIndex) {
@@ -6846,7 +6959,7 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
6846
6959
  endIdx: m.index + m[0].length,
6847
6960
  });
6848
6961
  }
6849
- return members.slice(0, 8);
6962
+ return capMembersWithNotice(members, MEMBER_LIMIT);
6850
6963
  }
6851
6964
 
6852
6965
  function normalizeParams(params) {
@@ -6921,6 +7034,11 @@ __factories["./src/extractors/line-anchor"] = function(module, exports) {
6921
7034
  // ── ./src/extractors/markdown ──
6922
7035
  __factories["./src/extractors/markdown"] = function(module, exports) {
6923
7036
 
7037
+ const { capWithNotice } = __require('./src/util/truncate');
7038
+
7039
+ // Ceiling discloses what it drops rather than truncating silently (#583).
7040
+ const PER_FILE_LIMIT = 40;
7041
+
6924
7042
  /**
6925
7043
  * Lightweight markdown technical indexer.
6926
7044
  * Captures headings and fenced code block language hints only.
@@ -6945,7 +7063,7 @@ __factories["./src/extractors/markdown"] = function(module, exports) {
6945
7063
  sigs.push(`code-fence ${lang}`);
6946
7064
  }
6947
7065
 
6948
- return Array.from(new Set(sigs)).slice(0, 40);
7066
+ return capWithNotice(Array.from(new Set(sigs)), PER_FILE_LIMIT, 'headings');
6949
7067
  }
6950
7068
 
6951
7069
  module.exports = { extract };
@@ -7095,6 +7213,13 @@ __factories["./src/extractors/patterns"] = function(module, exports) {
7095
7213
  __factories["./src/extractors/php"] = function(module, exports) {
7096
7214
 
7097
7215
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
7216
+ const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
7217
+
7218
+ // Ceilings sit above the default `maxSigsPerFile` so the configured budget
7219
+ // governs output rather than a literal buried here, and omissions are disclosed
7220
+ // — an undisclosed cap looks like a class that simply has eight methods (#576).
7221
+ const MEMBER_LIMIT = 8;
7222
+ const PER_FILE_LIMIT = 25;
7098
7223
 
7099
7224
  /**
7100
7225
  * Extract signatures from PHP source code.
@@ -7134,7 +7259,8 @@ __factories["./src/extractors/php"] = function(module, exports) {
7134
7259
  const block = extractBlock(stripped, bodyStart);
7135
7260
  sigs.push(withAnchor(`${kind} ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
7136
7261
  for (const meth of extractMembers(block)) {
7137
- sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
7262
+ // The disclosure marker carries no offsets; anchor it at the class body.
7263
+ sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
7138
7264
  }
7139
7265
  }
7140
7266
 
@@ -7146,7 +7272,7 @@ __factories["./src/extractors/php"] = function(module, exports) {
7146
7272
  sigs.push(withAnchor(`function ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
7147
7273
  }
7148
7274
 
7149
- return sigs.slice(0, 25);
7275
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
7150
7276
  }
7151
7277
 
7152
7278
  function extractBlock(src, startIndex) {
@@ -7174,7 +7300,7 @@ __factories["./src/extractors/php"] = function(module, exports) {
7174
7300
  endIdx: m.index + m[0].length,
7175
7301
  });
7176
7302
  }
7177
- return members.slice(0, 8);
7303
+ return capMembersWithNotice(members, MEMBER_LIMIT);
7178
7304
  }
7179
7305
 
7180
7306
  function normalizeParams(params) {
@@ -7268,6 +7394,11 @@ __factories["./src/extractors/prdiff"] = function(module, exports) {
7268
7394
  // ── ./src/extractors/properties ──
7269
7395
  __factories["./src/extractors/properties"] = function(module, exports) {
7270
7396
 
7397
+ const { capWithNotice } = __require('./src/util/truncate');
7398
+
7399
+ // Ceiling discloses what it drops rather than truncating silently (#583).
7400
+ const PER_FILE_LIMIT = 50;
7401
+
7271
7402
  /**
7272
7403
  * Extract signatures from .properties configuration files.
7273
7404
  * Captures key names, grouped by prefixes where possible.
@@ -7299,7 +7430,7 @@ __factories["./src/extractors/properties"] = function(module, exports) {
7299
7430
  sigs.push(`key ${key}`);
7300
7431
  }
7301
7432
 
7302
- return Array.from(new Set(sigs)).slice(0, 50);
7433
+ return capWithNotice(Array.from(new Set(sigs)), PER_FILE_LIMIT, 'keys');
7303
7434
  }
7304
7435
 
7305
7436
  module.exports = { extract };
@@ -7378,6 +7509,11 @@ __factories["./src/extractors/python"] = function(module, exports) {
7378
7509
 
7379
7510
  const path = require('path');
7380
7511
  const { lineAt } = __require('./src/extractors/line-anchor');
7512
+ const { capWithNotice } = __require('./src/util/truncate');
7513
+
7514
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
7515
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
7516
+ const PER_FILE_LIMIT = 30;
7381
7517
 
7382
7518
  /**
7383
7519
  * 1-based line of the last source line belonging to a top-level (indent 0)
@@ -7512,7 +7648,7 @@ __factories["./src/extractors/python"] = function(module, exports) {
7512
7648
  }
7513
7649
  }
7514
7650
 
7515
- return sigs.slice(0, 30);
7651
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
7516
7652
  }
7517
7653
 
7518
7654
  function extractClassMethods(stripped, startIndex) {
@@ -7723,6 +7859,12 @@ __factories["./src/extractors/python_dataclass"] = function(module, exports) {
7723
7859
  // ── ./src/extractors/r ──
7724
7860
  __factories["./src/extractors/r"] = function(module, exports) {
7725
7861
 
7862
+ const { capWithNotice } = __require('./src/util/truncate');
7863
+
7864
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
7865
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
7866
+ const PER_FILE_LIMIT = 30;
7867
+
7726
7868
  /**
7727
7869
  * Extract signatures from R source code.
7728
7870
  *
@@ -7761,7 +7903,7 @@ __factories["./src/extractors/r"] = function(module, exports) {
7761
7903
  // ClassName <- R6::R6Class(...)
7762
7904
  const r6Re = /([\w.]+)\s*(?:<<-|<-|=)\s*(?:R6::)?R6Class\s*\(/g;
7763
7905
  let m;
7764
- while ((m = r6Re.exec(stripped)) !== null && sigs.length < 30) {
7906
+ while ((m = r6Re.exec(stripped)) !== null) {
7765
7907
  const name = m[1];
7766
7908
  if (name.startsWith('.')) continue;
7767
7909
  const openIdx = r6Re.lastIndex - 1;
@@ -7772,7 +7914,6 @@ __factories["./src/extractors/r"] = function(module, exports) {
7772
7914
  sigs.push(`${name} <- R6Class("${classNameLit}")` + applyHint(docHints, name));
7773
7915
  for (const memberSig of extractListMethods(body, 8)) {
7774
7916
  sigs.push(' ' + memberSig);
7775
- if (sigs.length >= 30) break;
7776
7917
  }
7777
7918
  consumedRanges.push([m.index, closeIdx]);
7778
7919
  r6Re.lastIndex = closeIdx;
@@ -7782,7 +7923,7 @@ __factories["./src/extractors/r"] = function(module, exports) {
7782
7923
  // ClassName <- new_class("ClassName", properties = list(...))
7783
7924
  const s7Classes = new Set();
7784
7925
  const s7Re = /([\w.]+)\s*(?:<<-|<-|=)\s*(?:S7::)?new_class\s*\(/g;
7785
- while ((m = s7Re.exec(stripped)) !== null && sigs.length < 30) {
7926
+ while ((m = s7Re.exec(stripped)) !== null) {
7786
7927
  const name = m[1];
7787
7928
  if (name.startsWith('.')) continue;
7788
7929
  const openIdx = s7Re.lastIndex - 1;
@@ -7799,7 +7940,7 @@ __factories["./src/extractors/r"] = function(module, exports) {
7799
7940
 
7800
7941
  // S7 method dispatch: `method(generic, ClassName) <- function(args)`
7801
7942
  const s7MethodRe = /^[ \t]*method\s*\(\s*([\w.]+)\s*,\s*([\w.]+)\s*\)\s*(?:<<-|<-|=)\s*function\s*\(/gm;
7802
- while ((m = s7MethodRe.exec(stripped)) !== null && sigs.length < 30) {
7943
+ while ((m = s7MethodRe.exec(stripped)) !== null) {
7803
7944
  if (!s7Classes.has(m[2])) continue;
7804
7945
  const argsStart = s7MethodRe.lastIndex - 1;
7805
7946
  const args = readBalancedParens(stripped, argsStart);
@@ -7812,7 +7953,7 @@ __factories["./src/extractors/r"] = function(module, exports) {
7812
7953
  // Skip matches whose position falls inside an R6/S7 class body — those have
7813
7954
  // already been emitted as indented members.
7814
7955
  const funcRe = /^(?:[ \t]*)([\w.]+)\s*(?:<<-|<-|=)\s*function\s*\(/gm;
7815
- while ((m = funcRe.exec(stripped)) !== null && sigs.length < 30) {
7956
+ while ((m = funcRe.exec(stripped)) !== null) {
7816
7957
  const name = m[1];
7817
7958
  if (name.startsWith('.')) continue;
7818
7959
  if (inAnyRange(m.index, consumedRanges)) continue;
@@ -7824,19 +7965,16 @@ __factories["./src/extractors/r"] = function(module, exports) {
7824
7965
 
7825
7966
  // ── S4 ────────────────────────────────────────────────────────────────────
7826
7967
  for (const sm of stripped.matchAll(/^[ \t]*setGeneric\s*\(\s*["']([\w.]+)["']/gm)) {
7827
- if (sigs.length >= 30) break;
7828
7968
  sigs.push(`setGeneric("${sm[1]}")`);
7829
7969
  }
7830
7970
  for (const sm of stripped.matchAll(/^[ \t]*setMethod\s*\(\s*["']([\w.]+)["']\s*,\s*["']([\w.]+)["']/gm)) {
7831
- if (sigs.length >= 30) break;
7832
7971
  sigs.push(`setMethod("${sm[1]}", "${sm[2]}")`);
7833
7972
  }
7834
7973
  for (const sm of stripped.matchAll(/^[ \t]*setClass\s*\(\s*["']([\w.]+)["']/gm)) {
7835
- if (sigs.length >= 30) break;
7836
7974
  sigs.push(`setClass("${sm[1]}")`);
7837
7975
  }
7838
7976
 
7839
- return sigs.slice(0, 30);
7977
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
7840
7978
  }
7841
7979
 
7842
7980
  /**
@@ -8000,6 +8138,12 @@ __factories["./src/extractors/r"] = function(module, exports) {
8000
8138
  // ── ./src/extractors/ruby ──
8001
8139
  __factories["./src/extractors/ruby"] = function(module, exports) {
8002
8140
 
8141
+ const { capWithNotice } = __require('./src/util/truncate');
8142
+
8143
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
8144
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
8145
+ const PER_FILE_LIMIT = 25;
8146
+
8003
8147
  /**
8004
8148
  * Extract signatures from Ruby source code.
8005
8149
  * @param {string} src - Raw file content
@@ -8034,7 +8178,7 @@ __factories["./src/extractors/ruby"] = function(module, exports) {
8034
8178
  sigs.push(`def ${m[1]}${params}${retStr}`);
8035
8179
  }
8036
8180
 
8037
- return sigs.slice(0, 25);
8181
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
8038
8182
  }
8039
8183
 
8040
8184
  function normalizeParams(params) {
@@ -8059,6 +8203,11 @@ __factories["./src/extractors/ruby"] = function(module, exports) {
8059
8203
  __factories["./src/extractors/rust"] = function(module, exports) {
8060
8204
 
8061
8205
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
8206
+ const { capWithNotice } = __require('./src/util/truncate');
8207
+
8208
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
8209
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
8210
+ const PER_FILE_LIMIT = 25;
8062
8211
 
8063
8212
  /**
8064
8213
  * Extract signatures from Rust source code.
@@ -8128,7 +8277,7 @@ __factories["./src/extractors/rust"] = function(module, exports) {
8128
8277
  sigs.push(hinted(withAnchor(`pub ${asyncKw}fn ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e), m[1]));
8129
8278
  }
8130
8279
 
8131
- return sigs.slice(0, 25);
8280
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
8132
8281
  }
8133
8282
 
8134
8283
  function extractBlock(src, startIndex) {
@@ -8201,6 +8350,13 @@ __factories["./src/extractors/rust"] = function(module, exports) {
8201
8350
  __factories["./src/extractors/scala"] = function(module, exports) {
8202
8351
 
8203
8352
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
8353
+ const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
8354
+
8355
+ // Ceilings sit above the default `maxSigsPerFile` so the configured budget
8356
+ // governs output rather than a literal buried here, and omissions are disclosed
8357
+ // — an undisclosed cap looks like a class that simply has eight methods (#576).
8358
+ const MEMBER_LIMIT = 8;
8359
+ const PER_FILE_LIMIT = 25;
8204
8360
 
8205
8361
  /**
8206
8362
  * Extract signatures from Scala source code.
@@ -8227,7 +8383,8 @@ __factories["./src/extractors/scala"] = function(module, exports) {
8227
8383
  const block = extractBlock(stripped, bodyStart);
8228
8384
  sigs.push(withAnchor(`${kind} ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
8229
8385
  for (const fn of extractMembers(block)) {
8230
- sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + fn.declIdx), lineAt(stripped, bodyStart + fn.endIdx)));
8386
+ // The disclosure marker carries no offsets; anchor it at the class body.
8387
+ sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + (fn.declIdx || 0)), lineAt(stripped, bodyStart + (fn.endIdx || 0))));
8231
8388
  }
8232
8389
  }
8233
8390
 
@@ -8241,7 +8398,7 @@ __factories["./src/extractors/scala"] = function(module, exports) {
8241
8398
  sigs.push(withAnchor(`def ${m[1]}${params}${retStr}`, line, line));
8242
8399
  }
8243
8400
 
8244
- return sigs.slice(0, 25);
8401
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
8245
8402
  }
8246
8403
 
8247
8404
  function extractBlock(src, startIndex) {
@@ -8268,7 +8425,7 @@ __factories["./src/extractors/scala"] = function(module, exports) {
8268
8425
  endIdx: m.index + m[0].length,
8269
8426
  });
8270
8427
  }
8271
- return members.slice(0, 8);
8428
+ return capMembersWithNotice(members, MEMBER_LIMIT);
8272
8429
  }
8273
8430
 
8274
8431
  function normalizeParams(params) {
@@ -8387,6 +8544,12 @@ __factories["./src/extractors/scan"] = function(module, exports) {
8387
8544
  // ── ./src/extractors/shell ──
8388
8545
  __factories["./src/extractors/shell"] = function(module, exports) {
8389
8546
 
8547
+ const { capWithNotice } = __require('./src/util/truncate');
8548
+
8549
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
8550
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
8551
+ const PER_FILE_LIMIT = 25;
8552
+
8390
8553
  /**
8391
8554
  * Extract signatures from shell scripts (bash, zsh, fish).
8392
8555
  * @param {string} src - Raw file content
@@ -8424,7 +8587,7 @@ __factories["./src/extractors/shell"] = function(module, exports) {
8424
8587
  }
8425
8588
  }
8426
8589
 
8427
- return sigs.slice(0, 25);
8590
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
8428
8591
  }
8429
8592
 
8430
8593
  module.exports = { extract };
@@ -8531,6 +8694,12 @@ __factories["./src/extractors/sql"] = function(module, exports) {
8531
8694
  // ── ./src/extractors/svelte ──
8532
8695
  __factories["./src/extractors/svelte"] = function(module, exports) {
8533
8696
 
8697
+ const { capWithNotice } = __require('./src/util/truncate');
8698
+
8699
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
8700
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
8701
+ const PER_FILE_LIMIT = 25;
8702
+
8534
8703
  /**
8535
8704
  * Extract signatures from Svelte components.
8536
8705
  * @param {string} src - Raw file content
@@ -8573,7 +8742,7 @@ __factories["./src/extractors/svelte"] = function(module, exports) {
8573
8742
  sigs.push(`$: ${m[1]}`);
8574
8743
  }
8575
8744
 
8576
- return sigs.slice(0, 25);
8745
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
8577
8746
  }
8578
8747
 
8579
8748
  function normalizeParams(params) {
@@ -8594,6 +8763,13 @@ __factories["./src/extractors/svelte"] = function(module, exports) {
8594
8763
  __factories["./src/extractors/swift"] = function(module, exports) {
8595
8764
 
8596
8765
  const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
8766
+ const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
8767
+
8768
+ // Ceilings sit above the default `maxSigsPerFile` so the configured budget
8769
+ // governs output rather than a literal buried here, and omissions are disclosed
8770
+ // — an undisclosed cap looks like a class that simply has eight methods (#576).
8771
+ const MEMBER_LIMIT = 8;
8772
+ const PER_FILE_LIMIT = 25;
8597
8773
 
8598
8774
  /**
8599
8775
  * Extract signatures from Swift source code.
@@ -8629,7 +8805,8 @@ __factories["./src/extractors/swift"] = function(module, exports) {
8629
8805
  const block = extractBlock(stripped, bodyStart);
8630
8806
  sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
8631
8807
  for (const fn of extractMembers(block)) {
8632
- sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + fn.declIdx), lineAt(stripped, bodyStart + fn.endIdx)));
8808
+ // The disclosure marker carries no offsets; anchor it at the class body.
8809
+ sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + (fn.declIdx || 0)), lineAt(stripped, bodyStart + (fn.endIdx || 0))));
8633
8810
  }
8634
8811
  }
8635
8812
 
@@ -8641,7 +8818,7 @@ __factories["./src/extractors/swift"] = function(module, exports) {
8641
8818
  sigs.push(withAnchor(`${asyncKw}func ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
8642
8819
  }
8643
8820
 
8644
- return sigs.slice(0, 25);
8821
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
8645
8822
  }
8646
8823
 
8647
8824
  function extractBlock(src, startIndex) {
@@ -8667,7 +8844,7 @@ __factories["./src/extractors/swift"] = function(module, exports) {
8667
8844
  endIdx: m.index + m[0].length,
8668
8845
  });
8669
8846
  }
8670
- return members.slice(0, 8);
8847
+ return capMembersWithNotice(members, MEMBER_LIMIT);
8671
8848
  }
8672
8849
 
8673
8850
  function normalizeParams(params) {
@@ -8802,6 +8979,11 @@ __factories["./src/extractors/todos"] = function(module, exports) {
8802
8979
  // ── ./src/extractors/toml ──
8803
8980
  __factories["./src/extractors/toml"] = function(module, exports) {
8804
8981
 
8982
+ const { capWithNotice } = __require('./src/util/truncate');
8983
+
8984
+ // Ceiling discloses what it drops rather than truncating silently (#583).
8985
+ const PER_FILE_LIMIT = 40;
8986
+
8805
8987
  /**
8806
8988
  * Extract signatures from TOML configuration files.
8807
8989
  * Focuses on section/table names and high-value keys.
@@ -8838,7 +9020,7 @@ __factories["./src/extractors/toml"] = function(module, exports) {
8838
9020
  }
8839
9021
  }
8840
9022
 
8841
- return Array.from(new Set(sigs)).slice(0, 40);
9023
+ return capWithNotice(Array.from(new Set(sigs)), PER_FILE_LIMIT, 'entries');
8842
9024
  }
8843
9025
 
8844
9026
  module.exports = { extract };
@@ -9178,6 +9360,11 @@ __factories["./src/extractors/typescript"] = function(module, exports) {
9178
9360
  // ── ./src/extractors/typescript_react ──
9179
9361
  __factories["./src/extractors/typescript_react"] = function(module, exports) {
9180
9362
 
9363
+ const { capWithNotice } = __require('./src/util/truncate');
9364
+
9365
+ // Ceiling discloses what it drops rather than truncating silently (#583).
9366
+ const PER_FILE_LIMIT = 50;
9367
+
9181
9368
  /**
9182
9369
  * Extract React component signatures from .tsx files.
9183
9370
  * Captures component props interfaces, hooks usage, and exports.
@@ -9232,91 +9419,7 @@ __factories["./src/extractors/typescript_react"] = function(module, exports) {
9232
9419
  sigs.push(`handler on${h}`);
9233
9420
  }
9234
9421
 
9235
- return Array.from(new Set(sigs)).slice(0, 50);
9236
- }
9237
-
9238
- module.exports = { extract };
9239
-
9240
- };
9241
-
9242
- // ── ./src/extractors/vue ──
9243
- __factories["./src/extractors/vue"] = function(module, exports) {
9244
-
9245
- /**
9246
- * Extract signatures from Vue single-file components.
9247
- * @param {string} src - Raw file content
9248
- * @returns {string[]} Array of signature strings
9249
- */
9250
- function extract(src) {
9251
- if (!src || typeof src !== 'string') return [];
9252
- const sigs = [];
9253
-
9254
- // Extract component name from filename hint if present or defineComponent
9255
- const nameMatch = src.match(/name\s*:\s*['"](\w+)['"]/);
9256
- if (nameMatch) sigs.push(`component ${nameMatch[1]}`);
9257
-
9258
- // Extract <script> block
9259
- const scriptMatch = src.match(/<script(?:\s[^>]*)?>(?:\s*)([\s\S]*?)<\/script>/i);
9260
- if (!scriptMatch) return sigs;
9261
-
9262
- const script = scriptMatch[1]
9263
- .replace(/\/\/.*$/gm, '')
9264
- .replace(/\/\*[\s\S]*?\*\//g, '');
9265
-
9266
- // Props
9267
- const propsMatch = script.match(/props\s*:\s*(\{[\s\S]*?\})/);
9268
- if (propsMatch) {
9269
- const propNames = [];
9270
- for (const m of propsMatch[1].matchAll(/^\s+(\w+)\s*:/gm)) {
9271
- propNames.push(m[1]);
9272
- }
9273
- if (propNames.length > 0) sigs.push(`props: [${propNames.join(', ')}]`);
9274
- }
9275
-
9276
- // Methods in options API
9277
- const methodsMatch = script.match(/methods\s*:\s*\{([\s\S]*?)\},?\s*(?:computed|watch|mounted|created|data|\})/);
9278
- if (methodsMatch) {
9279
- for (const m of methodsMatch[1].matchAll(/^\s+(?:async\s+)?(\w+)\s*\(([^)]*)\)(?:\s*:\s*([^{=\n]+))?/gm)) {
9280
- if (m[1].startsWith('_')) continue;
9281
- const asyncKw = m[0].includes('async') ? 'async ' : '';
9282
- const retStr = m[3] ? ` → ${normalizeType(m[3])}` : '';
9283
- sigs.push(` ${asyncKw}${m[1]}(${normalizeParams(m[2])})${retStr}`);
9284
- }
9285
- }
9286
-
9287
- // Top-level functions in <script> (e.g., composition API helpers)
9288
- for (const m of script.matchAll(/^(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)(?:\s*:\s*([^{=\n]+))?/gm)) {
9289
- if (m[1].startsWith('_')) continue;
9290
- const asyncKw = m[0].includes('async') ? 'async ' : '';
9291
- const retStr = m[3] ? ` → ${normalizeType(m[3])}` : '';
9292
- sigs.push(`${asyncKw}function ${m[1]}(${normalizeParams(m[2])})${retStr}`);
9293
- }
9294
-
9295
- // defineProps (Composition API)
9296
- const definePropsMatch = script.match(/defineProps(?:<[^>]*>)?\s*\(\s*(\{[\s\S]*?\})\s*\)/);
9297
- if (definePropsMatch) {
9298
- const propNames = [];
9299
- for (const m of definePropsMatch[1].matchAll(/^\s+(\w+)\s*:/gm)) {
9300
- propNames.push(m[1]);
9301
- }
9302
- if (propNames.length > 0) sigs.push(`defineProps: [${propNames.join(', ')}]`);
9303
- }
9304
-
9305
- // Emits
9306
- const emitsMatch = script.match(/(?:defineEmits|emits)\s*(?::\s*|\(\s*)(\[[\s\S]*?\])/);
9307
- if (emitsMatch) sigs.push(`emits: ${emitsMatch[1].replace(/\s+/g, ' ')}`);
9308
-
9309
- return sigs.slice(0, 25);
9310
- }
9311
-
9312
- function normalizeParams(params) {
9313
- if (!params) return '';
9314
- return params.trim().replace(/\s+/g, ' ');
9315
- }
9316
-
9317
- function normalizeType(type) {
9318
- if (!type) return '';
9319
- return type.trim().replace(/[;\s]+$/g, '').replace(/\s+/g, ' ').slice(0, 25);
9422
+ return capWithNotice(Array.from(new Set(sigs)), PER_FILE_LIMIT, 'signatures');
9320
9423
  }
9321
9424
 
9322
9425
  module.exports = { extract };
@@ -9479,6 +9582,12 @@ __factories["./src/extractors/xml"] = function(module, exports) {
9479
9582
  // ── ./src/extractors/yaml ──
9480
9583
  __factories["./src/extractors/yaml"] = function(module, exports) {
9481
9584
 
9585
+ const { capWithNotice } = __require('./src/util/truncate');
9586
+
9587
+ // Ceiling sits above the default `maxSigsPerFile` so the configured budget
9588
+ // governs output rather than a literal buried here, and omissions are disclosed (#576).
9589
+ const PER_FILE_LIMIT = 25;
9590
+
9482
9591
  /**
9483
9592
  * Extract signatures from YAML configuration files.
9484
9593
  * @param {string} src - Raw file content
@@ -9532,7 +9641,7 @@ __factories["./src/extractors/yaml"] = function(module, exports) {
9532
9641
  }
9533
9642
  }
9534
9643
 
9535
- return sigs.slice(0, 25);
9644
+ return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
9536
9645
  }
9537
9646
 
9538
9647
  module.exports = { extract };
@@ -15679,7 +15788,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
15679
15788
 
15680
15789
  const SERVER_INFO = {
15681
15790
  name: 'sigmap',
15682
- version: '8.31.0',
15791
+ version: '8.32.1',
15683
15792
  description: 'SigMap MCP server — code signatures on demand',
15684
15793
  };
15685
15794
 
@@ -21973,7 +22082,7 @@ function __tryGit(args, opts = {}) {
21973
22082
  catch (_) { return ''; }
21974
22083
  }
21975
22084
 
21976
- const VERSION = '8.31.0';
22085
+ const VERSION = '8.32.1';
21977
22086
  const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
21978
22087
 
21979
22088
  function requireSourceOrBundled(key) {
@@ -26746,7 +26855,7 @@ function main() {
26746
26855
  '.cs': 'csharp', '.cpp': 'cpp', '.rb': 'ruby', '.php': 'php',
26747
26856
  '.swift': 'swift', '.dart': 'dart', '.scala': 'scala',
26748
26857
  '.r': 'r', '.R': 'r',
26749
- '.vue': 'vue', '.svelte': 'svelte', '.html': 'html',
26858
+ '.vue': 'vue_sfc', '.svelte': 'svelte', '.html': 'html',
26750
26859
  '.css': 'css', '.yml': 'yaml', '.sh': 'shell',
26751
26860
  };
26752
26861
  const SPECIAL = { 'Dockerfile': 'dockerfile' };