sigmap 8.30.0 → 8.32.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/CHANGELOG.md +29 -0
- package/README.md +2 -2
- package/gen-context.js +480 -55
- package/llms-full.txt +4 -2
- package/llms.txt +2 -2
- package/package.json +3 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/extractors/cpp.js +10 -2
- package/src/extractors/csharp.js +11 -3
- package/src/extractors/css.js +7 -1
- package/src/extractors/dart.js +11 -3
- package/src/extractors/dockerfile.js +7 -1
- package/src/extractors/gdscript.js +13 -3
- package/src/extractors/go.js +6 -1
- package/src/extractors/html.js +7 -1
- package/src/extractors/kotlin.js +11 -3
- package/src/extractors/php.js +11 -3
- package/src/extractors/python.js +6 -1
- package/src/extractors/r.js +7 -1
- package/src/extractors/ruby.js +7 -1
- package/src/extractors/rust.js +6 -1
- package/src/extractors/scala.js +11 -3
- package/src/extractors/shell.js +7 -1
- package/src/extractors/svelte.js +7 -1
- package/src/extractors/swift.js +11 -3
- package/src/extractors/vue.js +7 -1
- package/src/extractors/yaml.js +7 -1
- package/src/graph/builder.js +39 -3
- package/src/graph/call-graph.js +216 -13
- package/src/mcp/server.js +1 -1
- package/src/skills/skills.js +2 -2
package/gen-context.js
CHANGED
|
@@ -5439,6 +5439,14 @@ __factories["./src/extractors/coverage"] = function(module, exports) {
|
|
|
5439
5439
|
// ── ./src/extractors/cpp ──
|
|
5440
5440
|
__factories["./src/extractors/cpp"] = function(module, exports) {
|
|
5441
5441
|
|
|
5442
|
+
const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
|
|
5443
|
+
|
|
5444
|
+
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
5445
|
+
// governs output rather than a literal buried here, and omissions are disclosed
|
|
5446
|
+
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
5447
|
+
const MEMBER_LIMIT = 8;
|
|
5448
|
+
const PER_FILE_LIMIT = 25;
|
|
5449
|
+
|
|
5442
5450
|
/**
|
|
5443
5451
|
* Extract signatures from C/C++ source code.
|
|
5444
5452
|
* @param {string} src - Raw file content
|
|
@@ -5469,7 +5477,7 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
|
|
|
5469
5477
|
sigs.push(`${m[2]}(${normalizeParams(m[3])})${retStr}`);
|
|
5470
5478
|
}
|
|
5471
5479
|
|
|
5472
|
-
return sigs
|
|
5480
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
5473
5481
|
}
|
|
5474
5482
|
|
|
5475
5483
|
function extractBlock(src, startIndex) {
|
|
@@ -5492,7 +5500,7 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
|
|
|
5492
5500
|
const retStr = ret ? ` → ${ret}` : '';
|
|
5493
5501
|
members.push(`${m[2]}(${normalizeParams(m[3])})${retStr}`);
|
|
5494
5502
|
}
|
|
5495
|
-
return members
|
|
5503
|
+
return capWithNotice(members, MEMBER_LIMIT, 'members');
|
|
5496
5504
|
}
|
|
5497
5505
|
|
|
5498
5506
|
function normalizeParams(params) {
|
|
@@ -5513,6 +5521,13 @@ __factories["./src/extractors/cpp"] = function(module, exports) {
|
|
|
5513
5521
|
__factories["./src/extractors/csharp"] = function(module, exports) {
|
|
5514
5522
|
|
|
5515
5523
|
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
5524
|
+
const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
|
|
5525
|
+
|
|
5526
|
+
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
5527
|
+
// governs output rather than a literal buried here, and omissions are disclosed
|
|
5528
|
+
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
5529
|
+
const MEMBER_LIMIT = 8;
|
|
5530
|
+
const PER_FILE_LIMIT = 25;
|
|
5516
5531
|
|
|
5517
5532
|
/**
|
|
5518
5533
|
* Extract signatures from C# source code.
|
|
@@ -5537,11 +5552,12 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
|
|
|
5537
5552
|
const block = extractBlock(stripped, bodyStart);
|
|
5538
5553
|
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, declIdx), lineAt(stripped, bodyStart + block.length)));
|
|
5539
5554
|
for (const meth of extractMembers(block)) {
|
|
5540
|
-
|
|
5555
|
+
// The disclosure marker carries no offsets; anchor it at the class body.
|
|
5556
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
|
|
5541
5557
|
}
|
|
5542
5558
|
}
|
|
5543
5559
|
|
|
5544
|
-
return sigs
|
|
5560
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
5545
5561
|
}
|
|
5546
5562
|
|
|
5547
5563
|
function extractBlock(src, startIndex) {
|
|
@@ -5567,7 +5583,7 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
|
|
|
5567
5583
|
endIdx: m.index + m[0].length,
|
|
5568
5584
|
});
|
|
5569
5585
|
}
|
|
5570
|
-
return members
|
|
5586
|
+
return capMembersWithNotice(members, MEMBER_LIMIT);
|
|
5571
5587
|
}
|
|
5572
5588
|
|
|
5573
5589
|
function normalizeParams(params) {
|
|
@@ -5587,6 +5603,12 @@ __factories["./src/extractors/csharp"] = function(module, exports) {
|
|
|
5587
5603
|
// ── ./src/extractors/css ──
|
|
5588
5604
|
__factories["./src/extractors/css"] = function(module, exports) {
|
|
5589
5605
|
|
|
5606
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
5607
|
+
|
|
5608
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
5609
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
5610
|
+
const PER_FILE_LIMIT = 25;
|
|
5611
|
+
|
|
5590
5612
|
/**
|
|
5591
5613
|
* Extract signatures from CSS/SCSS/SASS/Less source code.
|
|
5592
5614
|
* @param {string} src - Raw file content
|
|
@@ -5650,7 +5672,7 @@ __factories["./src/extractors/css"] = function(module, exports) {
|
|
|
5650
5672
|
for (const name of selected) sigs.push(`.${name}`);
|
|
5651
5673
|
}
|
|
5652
5674
|
|
|
5653
|
-
return sigs
|
|
5675
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
5654
5676
|
}
|
|
5655
5677
|
|
|
5656
5678
|
module.exports = { extract };
|
|
@@ -5661,6 +5683,13 @@ __factories["./src/extractors/css"] = function(module, exports) {
|
|
|
5661
5683
|
__factories["./src/extractors/dart"] = function(module, exports) {
|
|
5662
5684
|
|
|
5663
5685
|
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
5686
|
+
const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
|
|
5687
|
+
|
|
5688
|
+
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
5689
|
+
// governs output rather than a literal buried here, and omissions are disclosed
|
|
5690
|
+
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
5691
|
+
const MEMBER_LIMIT = 8;
|
|
5692
|
+
const PER_FILE_LIMIT = 25;
|
|
5664
5693
|
|
|
5665
5694
|
/**
|
|
5666
5695
|
* Extract signatures from Dart source code.
|
|
@@ -5696,7 +5725,8 @@ __factories["./src/extractors/dart"] = function(module, exports) {
|
|
|
5696
5725
|
const block = extractBlock(stripped, bodyStart);
|
|
5697
5726
|
sigs.push(withAnchor(`${abs}class ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
5698
5727
|
for (const meth of extractMembers(block)) {
|
|
5699
|
-
|
|
5728
|
+
// The disclosure marker carries no offsets; anchor it at the class body.
|
|
5729
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
|
|
5700
5730
|
}
|
|
5701
5731
|
}
|
|
5702
5732
|
|
|
@@ -5708,7 +5738,7 @@ __factories["./src/extractors/dart"] = function(module, exports) {
|
|
|
5708
5738
|
sigs.push(withAnchor(`${m[2]}(${normalizeParams(m[3])})${retStr}`, s, e));
|
|
5709
5739
|
}
|
|
5710
5740
|
|
|
5711
|
-
return sigs
|
|
5741
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
5712
5742
|
}
|
|
5713
5743
|
|
|
5714
5744
|
function extractBlock(src, startIndex) {
|
|
@@ -5733,7 +5763,7 @@ __factories["./src/extractors/dart"] = function(module, exports) {
|
|
|
5733
5763
|
endIdx: m.index + m[0].length,
|
|
5734
5764
|
});
|
|
5735
5765
|
}
|
|
5736
|
-
return members
|
|
5766
|
+
return capMembersWithNotice(members, MEMBER_LIMIT);
|
|
5737
5767
|
}
|
|
5738
5768
|
|
|
5739
5769
|
function normalizeParams(params) {
|
|
@@ -5978,6 +6008,12 @@ __factories["./src/extractors/dispatch"] = function(module, exports) {
|
|
|
5978
6008
|
// ── ./src/extractors/dockerfile ──
|
|
5979
6009
|
__factories["./src/extractors/dockerfile"] = function(module, exports) {
|
|
5980
6010
|
|
|
6011
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
6012
|
+
|
|
6013
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
6014
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
6015
|
+
const PER_FILE_LIMIT = 25;
|
|
6016
|
+
|
|
5981
6017
|
/**
|
|
5982
6018
|
* Extract signatures from Dockerfiles.
|
|
5983
6019
|
* @param {string} src - Raw file content
|
|
@@ -6021,7 +6057,7 @@ __factories["./src/extractors/dockerfile"] = function(module, exports) {
|
|
|
6021
6057
|
if (m) sigs.push(`ARG ${m[1]}`);
|
|
6022
6058
|
}
|
|
6023
6059
|
|
|
6024
|
-
return sigs
|
|
6060
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
6025
6061
|
}
|
|
6026
6062
|
|
|
6027
6063
|
module.exports = { extract };
|
|
@@ -6031,6 +6067,16 @@ __factories["./src/extractors/dockerfile"] = function(module, exports) {
|
|
|
6031
6067
|
// ── ./src/extractors/gdscript ──
|
|
6032
6068
|
__factories["./src/extractors/gdscript"] = function(module, exports) {
|
|
6033
6069
|
|
|
6070
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
6071
|
+
|
|
6072
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
6073
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
6074
|
+
const PER_FILE_LIMIT = 25;
|
|
6075
|
+
|
|
6076
|
+
// Ceilings disclose what they drop rather than truncating silently (#576).
|
|
6077
|
+
const MEMBER_LIMIT = 6;
|
|
6078
|
+
const ENUM_LIMIT = 24;
|
|
6079
|
+
|
|
6034
6080
|
/**
|
|
6035
6081
|
* Extract signatures from Godot GDScript source code.
|
|
6036
6082
|
* @param {string} src - Raw file content
|
|
@@ -6075,7 +6121,7 @@ __factories["./src/extractors/gdscript"] = function(module, exports) {
|
|
|
6075
6121
|
.split(',')
|
|
6076
6122
|
.map((s) => s.trim().split(/\s*=/)[0].trim())
|
|
6077
6123
|
.filter(Boolean);
|
|
6078
|
-
sigs.push(`${indent}enum ${m[1]} { ${members
|
|
6124
|
+
sigs.push(`${indent}enum ${m[1]} { ${capWithNotice(members, ENUM_LIMIT, 'values').join(', ')} }`);
|
|
6079
6125
|
}
|
|
6080
6126
|
|
|
6081
6127
|
let constCount = 0;
|
|
@@ -6123,7 +6169,7 @@ __factories["./src/extractors/gdscript"] = function(module, exports) {
|
|
|
6123
6169
|
}
|
|
6124
6170
|
}
|
|
6125
6171
|
|
|
6126
|
-
return sigs
|
|
6172
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
6127
6173
|
}
|
|
6128
6174
|
|
|
6129
6175
|
function extractInnerMembers(stripped, startIndex) {
|
|
@@ -6141,7 +6187,7 @@ __factories["./src/extractors/gdscript"] = function(module, exports) {
|
|
|
6141
6187
|
members.push(`${staticKw}func ${fm[2]}(${params})${retStr}`);
|
|
6142
6188
|
}
|
|
6143
6189
|
}
|
|
6144
|
-
return members
|
|
6190
|
+
return capWithNotice(members, MEMBER_LIMIT, 'members');
|
|
6145
6191
|
}
|
|
6146
6192
|
|
|
6147
6193
|
function normalizeParams(params) {
|
|
@@ -6198,6 +6244,11 @@ __factories["./src/extractors/generic"] = function(module, exports) {
|
|
|
6198
6244
|
__factories["./src/extractors/go"] = function(module, exports) {
|
|
6199
6245
|
|
|
6200
6246
|
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
6247
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
6248
|
+
|
|
6249
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
6250
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
6251
|
+
const PER_FILE_LIMIT = 25;
|
|
6201
6252
|
|
|
6202
6253
|
/**
|
|
6203
6254
|
* Extract signatures from Go source code.
|
|
@@ -6246,7 +6297,7 @@ __factories["./src/extractors/go"] = function(module, exports) {
|
|
|
6246
6297
|
sigs.push(hinted(withAnchor(`func ${receiver}${m[2]}(${normalizeParams(m[3])})${retStr}`, lineAt(stripped, m.index), lineAt(stripped, end)), m[2]));
|
|
6247
6298
|
}
|
|
6248
6299
|
|
|
6249
|
-
return sigs
|
|
6300
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
6250
6301
|
}
|
|
6251
6302
|
|
|
6252
6303
|
function extractBlock(src, startIndex) {
|
|
@@ -6380,6 +6431,12 @@ __factories["./src/extractors/graphql"] = function(module, exports) {
|
|
|
6380
6431
|
// ── ./src/extractors/html ──
|
|
6381
6432
|
__factories["./src/extractors/html"] = function(module, exports) {
|
|
6382
6433
|
|
|
6434
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
6435
|
+
|
|
6436
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
6437
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
6438
|
+
const PER_FILE_LIMIT = 25;
|
|
6439
|
+
|
|
6383
6440
|
/**
|
|
6384
6441
|
* Extract signatures from HTML files.
|
|
6385
6442
|
* Focuses on id/class attributes, forms, and script tags.
|
|
@@ -6413,7 +6470,7 @@ __factories["./src/extractors/html"] = function(module, exports) {
|
|
|
6413
6470
|
sigs.push(`data-${m[0].match(/data-(\w[\w-]*)/i)[1]}: ${m[1]}`);
|
|
6414
6471
|
}
|
|
6415
6472
|
|
|
6416
|
-
return sigs
|
|
6473
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
6417
6474
|
}
|
|
6418
6475
|
|
|
6419
6476
|
module.exports = { extract };
|
|
@@ -6772,6 +6829,13 @@ __factories["./src/extractors/javascript"] = function(module, exports) {
|
|
|
6772
6829
|
__factories["./src/extractors/kotlin"] = function(module, exports) {
|
|
6773
6830
|
|
|
6774
6831
|
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
6832
|
+
const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
|
|
6833
|
+
|
|
6834
|
+
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
6835
|
+
// governs output rather than a literal buried here, and omissions are disclosed
|
|
6836
|
+
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
6837
|
+
const MEMBER_LIMIT = 8;
|
|
6838
|
+
const PER_FILE_LIMIT = 25;
|
|
6775
6839
|
|
|
6776
6840
|
/**
|
|
6777
6841
|
* Extract signatures from Kotlin source code.
|
|
@@ -6806,7 +6870,8 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
|
|
|
6806
6870
|
const block = extractBlock(stripped, bodyStart);
|
|
6807
6871
|
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
6808
6872
|
for (const meth of extractMembers(block)) {
|
|
6809
|
-
|
|
6873
|
+
// The disclosure marker carries no offsets; anchor it at the class body.
|
|
6874
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
|
|
6810
6875
|
}
|
|
6811
6876
|
}
|
|
6812
6877
|
|
|
@@ -6819,7 +6884,7 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
|
|
|
6819
6884
|
sigs.push(withAnchor(`${suspend}fun ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
|
|
6820
6885
|
}
|
|
6821
6886
|
|
|
6822
|
-
return sigs
|
|
6887
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
6823
6888
|
}
|
|
6824
6889
|
|
|
6825
6890
|
function extractBlock(src, startIndex) {
|
|
@@ -6846,7 +6911,7 @@ __factories["./src/extractors/kotlin"] = function(module, exports) {
|
|
|
6846
6911
|
endIdx: m.index + m[0].length,
|
|
6847
6912
|
});
|
|
6848
6913
|
}
|
|
6849
|
-
return members
|
|
6914
|
+
return capMembersWithNotice(members, MEMBER_LIMIT);
|
|
6850
6915
|
}
|
|
6851
6916
|
|
|
6852
6917
|
function normalizeParams(params) {
|
|
@@ -7095,6 +7160,13 @@ __factories["./src/extractors/patterns"] = function(module, exports) {
|
|
|
7095
7160
|
__factories["./src/extractors/php"] = function(module, exports) {
|
|
7096
7161
|
|
|
7097
7162
|
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
7163
|
+
const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
|
|
7164
|
+
|
|
7165
|
+
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
7166
|
+
// governs output rather than a literal buried here, and omissions are disclosed
|
|
7167
|
+
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
7168
|
+
const MEMBER_LIMIT = 8;
|
|
7169
|
+
const PER_FILE_LIMIT = 25;
|
|
7098
7170
|
|
|
7099
7171
|
/**
|
|
7100
7172
|
* Extract signatures from PHP source code.
|
|
@@ -7134,7 +7206,8 @@ __factories["./src/extractors/php"] = function(module, exports) {
|
|
|
7134
7206
|
const block = extractBlock(stripped, bodyStart);
|
|
7135
7207
|
sigs.push(withAnchor(`${kind} ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
7136
7208
|
for (const meth of extractMembers(block)) {
|
|
7137
|
-
|
|
7209
|
+
// The disclosure marker carries no offsets; anchor it at the class body.
|
|
7210
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
|
|
7138
7211
|
}
|
|
7139
7212
|
}
|
|
7140
7213
|
|
|
@@ -7146,7 +7219,7 @@ __factories["./src/extractors/php"] = function(module, exports) {
|
|
|
7146
7219
|
sigs.push(withAnchor(`function ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
|
|
7147
7220
|
}
|
|
7148
7221
|
|
|
7149
|
-
return sigs
|
|
7222
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
7150
7223
|
}
|
|
7151
7224
|
|
|
7152
7225
|
function extractBlock(src, startIndex) {
|
|
@@ -7174,7 +7247,7 @@ __factories["./src/extractors/php"] = function(module, exports) {
|
|
|
7174
7247
|
endIdx: m.index + m[0].length,
|
|
7175
7248
|
});
|
|
7176
7249
|
}
|
|
7177
|
-
return members
|
|
7250
|
+
return capMembersWithNotice(members, MEMBER_LIMIT);
|
|
7178
7251
|
}
|
|
7179
7252
|
|
|
7180
7253
|
function normalizeParams(params) {
|
|
@@ -7378,6 +7451,11 @@ __factories["./src/extractors/python"] = function(module, exports) {
|
|
|
7378
7451
|
|
|
7379
7452
|
const path = require('path');
|
|
7380
7453
|
const { lineAt } = __require('./src/extractors/line-anchor');
|
|
7454
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
7455
|
+
|
|
7456
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
7457
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
7458
|
+
const PER_FILE_LIMIT = 30;
|
|
7381
7459
|
|
|
7382
7460
|
/**
|
|
7383
7461
|
* 1-based line of the last source line belonging to a top-level (indent 0)
|
|
@@ -7512,7 +7590,7 @@ __factories["./src/extractors/python"] = function(module, exports) {
|
|
|
7512
7590
|
}
|
|
7513
7591
|
}
|
|
7514
7592
|
|
|
7515
|
-
return sigs
|
|
7593
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
7516
7594
|
}
|
|
7517
7595
|
|
|
7518
7596
|
function extractClassMethods(stripped, startIndex) {
|
|
@@ -7723,6 +7801,12 @@ __factories["./src/extractors/python_dataclass"] = function(module, exports) {
|
|
|
7723
7801
|
// ── ./src/extractors/r ──
|
|
7724
7802
|
__factories["./src/extractors/r"] = function(module, exports) {
|
|
7725
7803
|
|
|
7804
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
7805
|
+
|
|
7806
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
7807
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
7808
|
+
const PER_FILE_LIMIT = 30;
|
|
7809
|
+
|
|
7726
7810
|
/**
|
|
7727
7811
|
* Extract signatures from R source code.
|
|
7728
7812
|
*
|
|
@@ -7836,7 +7920,7 @@ __factories["./src/extractors/r"] = function(module, exports) {
|
|
|
7836
7920
|
sigs.push(`setClass("${sm[1]}")`);
|
|
7837
7921
|
}
|
|
7838
7922
|
|
|
7839
|
-
return sigs
|
|
7923
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
7840
7924
|
}
|
|
7841
7925
|
|
|
7842
7926
|
/**
|
|
@@ -8000,6 +8084,12 @@ __factories["./src/extractors/r"] = function(module, exports) {
|
|
|
8000
8084
|
// ── ./src/extractors/ruby ──
|
|
8001
8085
|
__factories["./src/extractors/ruby"] = function(module, exports) {
|
|
8002
8086
|
|
|
8087
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
8088
|
+
|
|
8089
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
8090
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
8091
|
+
const PER_FILE_LIMIT = 25;
|
|
8092
|
+
|
|
8003
8093
|
/**
|
|
8004
8094
|
* Extract signatures from Ruby source code.
|
|
8005
8095
|
* @param {string} src - Raw file content
|
|
@@ -8034,7 +8124,7 @@ __factories["./src/extractors/ruby"] = function(module, exports) {
|
|
|
8034
8124
|
sigs.push(`def ${m[1]}${params}${retStr}`);
|
|
8035
8125
|
}
|
|
8036
8126
|
|
|
8037
|
-
return sigs
|
|
8127
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
8038
8128
|
}
|
|
8039
8129
|
|
|
8040
8130
|
function normalizeParams(params) {
|
|
@@ -8059,6 +8149,11 @@ __factories["./src/extractors/ruby"] = function(module, exports) {
|
|
|
8059
8149
|
__factories["./src/extractors/rust"] = function(module, exports) {
|
|
8060
8150
|
|
|
8061
8151
|
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
8152
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
8153
|
+
|
|
8154
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
8155
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
8156
|
+
const PER_FILE_LIMIT = 25;
|
|
8062
8157
|
|
|
8063
8158
|
/**
|
|
8064
8159
|
* Extract signatures from Rust source code.
|
|
@@ -8128,7 +8223,7 @@ __factories["./src/extractors/rust"] = function(module, exports) {
|
|
|
8128
8223
|
sigs.push(hinted(withAnchor(`pub ${asyncKw}fn ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e), m[1]));
|
|
8129
8224
|
}
|
|
8130
8225
|
|
|
8131
|
-
return sigs
|
|
8226
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
8132
8227
|
}
|
|
8133
8228
|
|
|
8134
8229
|
function extractBlock(src, startIndex) {
|
|
@@ -8201,6 +8296,13 @@ __factories["./src/extractors/rust"] = function(module, exports) {
|
|
|
8201
8296
|
__factories["./src/extractors/scala"] = function(module, exports) {
|
|
8202
8297
|
|
|
8203
8298
|
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
8299
|
+
const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
|
|
8300
|
+
|
|
8301
|
+
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
8302
|
+
// governs output rather than a literal buried here, and omissions are disclosed
|
|
8303
|
+
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
8304
|
+
const MEMBER_LIMIT = 8;
|
|
8305
|
+
const PER_FILE_LIMIT = 25;
|
|
8204
8306
|
|
|
8205
8307
|
/**
|
|
8206
8308
|
* Extract signatures from Scala source code.
|
|
@@ -8227,7 +8329,8 @@ __factories["./src/extractors/scala"] = function(module, exports) {
|
|
|
8227
8329
|
const block = extractBlock(stripped, bodyStart);
|
|
8228
8330
|
sigs.push(withAnchor(`${kind} ${m[1]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
8229
8331
|
for (const fn of extractMembers(block)) {
|
|
8230
|
-
|
|
8332
|
+
// The disclosure marker carries no offsets; anchor it at the class body.
|
|
8333
|
+
sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + (fn.declIdx || 0)), lineAt(stripped, bodyStart + (fn.endIdx || 0))));
|
|
8231
8334
|
}
|
|
8232
8335
|
}
|
|
8233
8336
|
|
|
@@ -8241,7 +8344,7 @@ __factories["./src/extractors/scala"] = function(module, exports) {
|
|
|
8241
8344
|
sigs.push(withAnchor(`def ${m[1]}${params}${retStr}`, line, line));
|
|
8242
8345
|
}
|
|
8243
8346
|
|
|
8244
|
-
return sigs
|
|
8347
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
8245
8348
|
}
|
|
8246
8349
|
|
|
8247
8350
|
function extractBlock(src, startIndex) {
|
|
@@ -8268,7 +8371,7 @@ __factories["./src/extractors/scala"] = function(module, exports) {
|
|
|
8268
8371
|
endIdx: m.index + m[0].length,
|
|
8269
8372
|
});
|
|
8270
8373
|
}
|
|
8271
|
-
return members
|
|
8374
|
+
return capMembersWithNotice(members, MEMBER_LIMIT);
|
|
8272
8375
|
}
|
|
8273
8376
|
|
|
8274
8377
|
function normalizeParams(params) {
|
|
@@ -8387,6 +8490,12 @@ __factories["./src/extractors/scan"] = function(module, exports) {
|
|
|
8387
8490
|
// ── ./src/extractors/shell ──
|
|
8388
8491
|
__factories["./src/extractors/shell"] = function(module, exports) {
|
|
8389
8492
|
|
|
8493
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
8494
|
+
|
|
8495
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
8496
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
8497
|
+
const PER_FILE_LIMIT = 25;
|
|
8498
|
+
|
|
8390
8499
|
/**
|
|
8391
8500
|
* Extract signatures from shell scripts (bash, zsh, fish).
|
|
8392
8501
|
* @param {string} src - Raw file content
|
|
@@ -8424,7 +8533,7 @@ __factories["./src/extractors/shell"] = function(module, exports) {
|
|
|
8424
8533
|
}
|
|
8425
8534
|
}
|
|
8426
8535
|
|
|
8427
|
-
return sigs
|
|
8536
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
8428
8537
|
}
|
|
8429
8538
|
|
|
8430
8539
|
module.exports = { extract };
|
|
@@ -8531,6 +8640,12 @@ __factories["./src/extractors/sql"] = function(module, exports) {
|
|
|
8531
8640
|
// ── ./src/extractors/svelte ──
|
|
8532
8641
|
__factories["./src/extractors/svelte"] = function(module, exports) {
|
|
8533
8642
|
|
|
8643
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
8644
|
+
|
|
8645
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
8646
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
8647
|
+
const PER_FILE_LIMIT = 25;
|
|
8648
|
+
|
|
8534
8649
|
/**
|
|
8535
8650
|
* Extract signatures from Svelte components.
|
|
8536
8651
|
* @param {string} src - Raw file content
|
|
@@ -8573,7 +8688,7 @@ __factories["./src/extractors/svelte"] = function(module, exports) {
|
|
|
8573
8688
|
sigs.push(`$: ${m[1]}`);
|
|
8574
8689
|
}
|
|
8575
8690
|
|
|
8576
|
-
return sigs
|
|
8691
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
8577
8692
|
}
|
|
8578
8693
|
|
|
8579
8694
|
function normalizeParams(params) {
|
|
@@ -8594,6 +8709,13 @@ __factories["./src/extractors/svelte"] = function(module, exports) {
|
|
|
8594
8709
|
__factories["./src/extractors/swift"] = function(module, exports) {
|
|
8595
8710
|
|
|
8596
8711
|
const { lineAt, withAnchor } = __require('./src/extractors/line-anchor');
|
|
8712
|
+
const { capWithNotice, capMembersWithNotice } = __require('./src/util/truncate');
|
|
8713
|
+
|
|
8714
|
+
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
8715
|
+
// governs output rather than a literal buried here, and omissions are disclosed
|
|
8716
|
+
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
8717
|
+
const MEMBER_LIMIT = 8;
|
|
8718
|
+
const PER_FILE_LIMIT = 25;
|
|
8597
8719
|
|
|
8598
8720
|
/**
|
|
8599
8721
|
* Extract signatures from Swift source code.
|
|
@@ -8629,7 +8751,8 @@ __factories["./src/extractors/swift"] = function(module, exports) {
|
|
|
8629
8751
|
const block = extractBlock(stripped, bodyStart);
|
|
8630
8752
|
sigs.push(withAnchor(`${m[1]} ${m[2]}`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)));
|
|
8631
8753
|
for (const fn of extractMembers(block)) {
|
|
8632
|
-
|
|
8754
|
+
// The disclosure marker carries no offsets; anchor it at the class body.
|
|
8755
|
+
sigs.push(withAnchor(` ${fn.text}`, lineAt(stripped, bodyStart + (fn.declIdx || 0)), lineAt(stripped, bodyStart + (fn.endIdx || 0))));
|
|
8633
8756
|
}
|
|
8634
8757
|
}
|
|
8635
8758
|
|
|
@@ -8641,7 +8764,7 @@ __factories["./src/extractors/swift"] = function(module, exports) {
|
|
|
8641
8764
|
sigs.push(withAnchor(`${asyncKw}func ${m[1]}(${normalizeParams(m[2])})${retStr}`, s, e));
|
|
8642
8765
|
}
|
|
8643
8766
|
|
|
8644
|
-
return sigs
|
|
8767
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
8645
8768
|
}
|
|
8646
8769
|
|
|
8647
8770
|
function extractBlock(src, startIndex) {
|
|
@@ -8667,7 +8790,7 @@ __factories["./src/extractors/swift"] = function(module, exports) {
|
|
|
8667
8790
|
endIdx: m.index + m[0].length,
|
|
8668
8791
|
});
|
|
8669
8792
|
}
|
|
8670
|
-
return members
|
|
8793
|
+
return capMembersWithNotice(members, MEMBER_LIMIT);
|
|
8671
8794
|
}
|
|
8672
8795
|
|
|
8673
8796
|
function normalizeParams(params) {
|
|
@@ -9242,6 +9365,12 @@ __factories["./src/extractors/typescript_react"] = function(module, exports) {
|
|
|
9242
9365
|
// ── ./src/extractors/vue ──
|
|
9243
9366
|
__factories["./src/extractors/vue"] = function(module, exports) {
|
|
9244
9367
|
|
|
9368
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
9369
|
+
|
|
9370
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
9371
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
9372
|
+
const PER_FILE_LIMIT = 25;
|
|
9373
|
+
|
|
9245
9374
|
/**
|
|
9246
9375
|
* Extract signatures from Vue single-file components.
|
|
9247
9376
|
* @param {string} src - Raw file content
|
|
@@ -9306,7 +9435,7 @@ __factories["./src/extractors/vue"] = function(module, exports) {
|
|
|
9306
9435
|
const emitsMatch = script.match(/(?:defineEmits|emits)\s*(?::\s*|\(\s*)(\[[\s\S]*?\])/);
|
|
9307
9436
|
if (emitsMatch) sigs.push(`emits: ${emitsMatch[1].replace(/\s+/g, ' ')}`);
|
|
9308
9437
|
|
|
9309
|
-
return sigs
|
|
9438
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
9310
9439
|
}
|
|
9311
9440
|
|
|
9312
9441
|
function normalizeParams(params) {
|
|
@@ -9479,6 +9608,12 @@ __factories["./src/extractors/xml"] = function(module, exports) {
|
|
|
9479
9608
|
// ── ./src/extractors/yaml ──
|
|
9480
9609
|
__factories["./src/extractors/yaml"] = function(module, exports) {
|
|
9481
9610
|
|
|
9611
|
+
const { capWithNotice } = __require('./src/util/truncate');
|
|
9612
|
+
|
|
9613
|
+
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
9614
|
+
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
9615
|
+
const PER_FILE_LIMIT = 25;
|
|
9616
|
+
|
|
9482
9617
|
/**
|
|
9483
9618
|
* Extract signatures from YAML configuration files.
|
|
9484
9619
|
* @param {string} src - Raw file content
|
|
@@ -9532,7 +9667,7 @@ __factories["./src/extractors/yaml"] = function(module, exports) {
|
|
|
9532
9667
|
}
|
|
9533
9668
|
}
|
|
9534
9669
|
|
|
9535
|
-
return sigs
|
|
9670
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
9536
9671
|
}
|
|
9537
9672
|
|
|
9538
9673
|
module.exports = { extract };
|
|
@@ -11752,24 +11887,60 @@ __factories["./src/graph/builder"] = function(module, exports) {
|
|
|
11752
11887
|
return { forward, reverse };
|
|
11753
11888
|
}
|
|
11754
11889
|
|
|
11890
|
+
// Directory names assumed when neither the caller nor the project config says
|
|
11891
|
+
// otherwise. A Maven/Gradle module (`mall-portal/`, `service-api/`) matches none
|
|
11892
|
+
// of them, which is why the config is consulted first.
|
|
11893
|
+
const DEFAULT_SRC_DIRS = ['src', 'app', 'lib', 'R', 'inst'];
|
|
11894
|
+
|
|
11895
|
+
// Walk depth measured from EACH srcDir root, not from cwd — so this is not the
|
|
11896
|
+
// same quantity as the extractor's cwd-relative `maxDepth` and must not be read
|
|
11897
|
+
// from it. A standard Maven tree reaches `src/main/java/<group>/<artifact>/…`
|
|
11898
|
+
// nine directories below its module root, so the previous ceiling of 8 silently
|
|
11899
|
+
// dropped the deepest packages (on macrozheng/mall: every `service/impl/` class).
|
|
11900
|
+
const DEFAULT_WALK_DEPTH = 12;
|
|
11901
|
+
|
|
11902
|
+
/**
|
|
11903
|
+
* Source directories declared in the project's own config, or null when there
|
|
11904
|
+
* is no readable config. Read directly rather than through `loadConfig`, which
|
|
11905
|
+
* can fetch `extends` over the network and spawn a child process — neither is
|
|
11906
|
+
* acceptable inside a graph build.
|
|
11907
|
+
*/
|
|
11908
|
+
function _configuredSrcDirs(cwd) {
|
|
11909
|
+
try {
|
|
11910
|
+
const raw = fs.readFileSync(path.join(cwd, 'gen-context.config.json'), 'utf8');
|
|
11911
|
+
const cfg = JSON.parse(raw);
|
|
11912
|
+
if (Array.isArray(cfg.srcDirs) && cfg.srcDirs.length > 0) return cfg.srcDirs;
|
|
11913
|
+
} catch (_) { /* absent or unparsable — fall back to the defaults */ }
|
|
11914
|
+
return null;
|
|
11915
|
+
}
|
|
11916
|
+
|
|
11755
11917
|
/**
|
|
11756
11918
|
* Build a dependency graph scoped to a single cwd by walking all JS/TS/Py/Go
|
|
11757
11919
|
* files under srcDirs. Useful for the MCP tool handler.
|
|
11758
11920
|
*
|
|
11921
|
+
* srcDirs resolution order: explicit `opts.srcDirs` → `gen-context.config.json`
|
|
11922
|
+
* → DEFAULT_SRC_DIRS. Without the config step the graph is empty on any repo
|
|
11923
|
+
* whose sources do not sit under a conventionally-named directory.
|
|
11924
|
+
*
|
|
11759
11925
|
* @param {string} cwd
|
|
11760
11926
|
* @param {object} [opts]
|
|
11761
11927
|
* @param {string[]} [opts.srcDirs]
|
|
11762
11928
|
* @param {string[]} [opts.exclude]
|
|
11929
|
+
* @param {number} [opts.maxDepth] - walk depth from each srcDir root
|
|
11763
11930
|
* @returns {{ forward: Map<string,string[]>, reverse: Map<string,string[]> }}
|
|
11764
11931
|
*/
|
|
11765
11932
|
function buildFromCwd(cwd, opts) {
|
|
11766
11933
|
// R-package layouts use `R/` and `inst/`; Shiny apps put helpers in `R/`.
|
|
11767
11934
|
// The existence check below makes these no-ops in non-R projects.
|
|
11768
|
-
const {
|
|
11935
|
+
const {
|
|
11936
|
+
srcDirs = _configuredSrcDirs(cwd) || DEFAULT_SRC_DIRS,
|
|
11937
|
+
exclude = ['node_modules', '.git', 'dist', 'build'],
|
|
11938
|
+
maxDepth = DEFAULT_WALK_DEPTH,
|
|
11939
|
+
} = opts || {};
|
|
11769
11940
|
const excludeSet = new Set(exclude);
|
|
11770
11941
|
|
|
11771
11942
|
function walkDir(dir, depth) {
|
|
11772
|
-
if (depth >
|
|
11943
|
+
if (depth > maxDepth) return [];
|
|
11773
11944
|
let entries;
|
|
11774
11945
|
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch (_) { return []; }
|
|
11775
11946
|
const out = [];
|
|
@@ -11818,7 +11989,7 @@ __factories["./src/graph/builder"] = function(module, exports) {
|
|
|
11818
11989
|
return build(files, cwd, ctx);
|
|
11819
11990
|
}
|
|
11820
11991
|
|
|
11821
|
-
module.exports = { build, buildFromCwd, extractFileDeps, normalizePath, loadAliasMap, resolveAlias };
|
|
11992
|
+
module.exports = { build, buildFromCwd, extractFileDeps, normalizePath, loadAliasMap, resolveAlias, _configuredSrcDirs, DEFAULT_SRC_DIRS, DEFAULT_WALK_DEPTH };
|
|
11822
11993
|
|
|
11823
11994
|
};
|
|
11824
11995
|
|
|
@@ -12073,6 +12244,44 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12073
12244
|
// Java: methods + constructors with braced bodies. Statement-shaped matches
|
|
12074
12245
|
// (calls, control flow) are rejected because their `)` is followed by `;`,
|
|
12075
12246
|
// and keyword headers (`if`, `while`, …) fall to the NON_CALL guard.
|
|
12247
|
+
// Words that can precede `name(` in a STATEMENT, so their presence means the
|
|
12248
|
+
// line is not a method declaration.
|
|
12249
|
+
const STMT_KEYWORDS = new Set([
|
|
12250
|
+
'return', 'throw', 'else', 'do', 'try', 'case', 'yield', 'assert', 'new',
|
|
12251
|
+
'if', 'while', 'for', 'switch', 'catch', 'synchronized', 'instanceof', 'await',
|
|
12252
|
+
]);
|
|
12253
|
+
|
|
12254
|
+
// Types a Java class declares it implements or extends, with generic arguments
|
|
12255
|
+
// stripped and any package qualifier dropped: `implements Foo<Bar, Baz>` yields
|
|
12256
|
+
// ['Foo'], never 'Baz>'. Also records whether the class is a Spring bean and
|
|
12257
|
+
// whether it is @Primary, which is what disambiguates several implementations.
|
|
12258
|
+
function javaTypeDecl(masked) {
|
|
12259
|
+
const m = /(?:^|\n)[^\n]*?\bclass\s+([A-Za-z_$][\w$]*)([^{]*)\{/.exec(masked);
|
|
12260
|
+
if (!m) return null;
|
|
12261
|
+
const [, className, tail] = m;
|
|
12262
|
+
const supers = [];
|
|
12263
|
+
for (const kw of ['implements', 'extends']) {
|
|
12264
|
+
const k = new RegExp('\\b' + kw + '\\s+([^{]*?)(?=\\b(?:implements|extends)\\b|$)').exec(tail);
|
|
12265
|
+
if (!k) continue;
|
|
12266
|
+
let depth = 0;
|
|
12267
|
+
let cur = '';
|
|
12268
|
+
for (const ch of k[1]) {
|
|
12269
|
+
if (ch === '<') { depth++; continue; }
|
|
12270
|
+
if (ch === '>') { depth--; continue; }
|
|
12271
|
+
if (ch === ',' && depth === 0) { if (cur.trim()) supers.push(cur.trim()); cur = ''; continue; }
|
|
12272
|
+
if (depth === 0) cur += ch;
|
|
12273
|
+
}
|
|
12274
|
+
if (cur.trim()) supers.push(cur.trim());
|
|
12275
|
+
}
|
|
12276
|
+
const head = masked.slice(0, m.index + m[0].length);
|
|
12277
|
+
return {
|
|
12278
|
+
className,
|
|
12279
|
+
supers: supers.map((t) => t.split('.').pop().trim()).filter(Boolean),
|
|
12280
|
+
isBean: /@(Service|Component|Repository|Controller|RestController)\b/.test(head),
|
|
12281
|
+
isPrimary: /@Primary\b/.test(head),
|
|
12282
|
+
};
|
|
12283
|
+
}
|
|
12284
|
+
|
|
12076
12285
|
function javaDefs(masked) {
|
|
12077
12286
|
const defs = [];
|
|
12078
12287
|
const seen = new Set();
|
|
@@ -12089,11 +12298,24 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12089
12298
|
// skip `throws A, B` up to the body `{` (same line — multi-line headers are skipped)
|
|
12090
12299
|
let k = close + 1;
|
|
12091
12300
|
while (k < masked.length && masked[k] !== '{' && masked[k] !== ';' && masked[k] !== '\n' && masked[k] !== '=') k++;
|
|
12092
|
-
|
|
12301
|
+
// A `;` here is an interface or abstract method DECLARATION. It owns no body,
|
|
12302
|
+
// so it emits no calls — but in Spring the declared interface is what callers
|
|
12303
|
+
// name, so without it as a node every controller→service edge has no target.
|
|
12304
|
+
// Recorded with an empty body range: can receive edges, never produces them.
|
|
12305
|
+
// `before` is everything between line start and the method name. A real
|
|
12306
|
+
// declaration has modifiers or a return type there (`void chargeCard(`);
|
|
12307
|
+
// a call statement has only whitespace (`identity(1);`) or a statement
|
|
12308
|
+
// keyword (`return helper(a);`) — neither may be read as a declaration,
|
|
12309
|
+
// or the call resolves to a phantom local def instead of the real target.
|
|
12310
|
+
const headWord = (before.match(/([A-Za-z_$][\w$]*)\s*$/) || [])[1];
|
|
12311
|
+
const isDecl = masked[k] === ';' && /\S/.test(before) && !STMT_KEYWORDS.has(headWord);
|
|
12312
|
+
if (masked[k] !== '{' && !isDecl) continue;
|
|
12093
12313
|
const key = name + ':' + k;
|
|
12094
12314
|
if (seen.has(key)) continue;
|
|
12095
12315
|
seen.add(key);
|
|
12096
|
-
defs.push(
|
|
12316
|
+
defs.push(isDecl
|
|
12317
|
+
? { name, line: lineAt(masked, m.index + 1), bodyStart: k, bodyEnd: k }
|
|
12318
|
+
: { name, line: lineAt(masked, m.index + 1), bodyStart: k, bodyEnd: matchDelim(masked, k, '{', '}') });
|
|
12097
12319
|
}
|
|
12098
12320
|
return defs;
|
|
12099
12321
|
}
|
|
@@ -12147,7 +12369,7 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12147
12369
|
const re = /([A-Za-z_$][\w$]*)\s*\(/g;
|
|
12148
12370
|
let m;
|
|
12149
12371
|
while ((m = re.exec(slice)) !== null) {
|
|
12150
|
-
// skip a `.name(` method access
|
|
12372
|
+
// skip a `.name(` method access — resolved separately via receiverCallsInRange
|
|
12151
12373
|
const before = slice[m.index - 1];
|
|
12152
12374
|
if (before === '.') continue;
|
|
12153
12375
|
if (!NON_CALL.has(m[1])) names.add(m[1]);
|
|
@@ -12155,16 +12377,75 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12155
12377
|
return names;
|
|
12156
12378
|
}
|
|
12157
12379
|
|
|
12380
|
+
// Collect `receiver.method(` pairs within [start,end). A chained or computed
|
|
12381
|
+
// receiver (`a.b().c(`, `arr[0].c(`) is skipped: only a plain identifier can be
|
|
12382
|
+
// looked up in the declaration map, and guessing is worse than no edge.
|
|
12383
|
+
function receiverCallsInRange(masked, start, end) {
|
|
12384
|
+
const slice = masked.slice(start, end);
|
|
12385
|
+
const out = [];
|
|
12386
|
+
const re = /([A-Za-z_$][\w$]*)\s*\.\s*([A-Za-z_$][\w$]*)\s*\(/g;
|
|
12387
|
+
let m;
|
|
12388
|
+
while ((m = re.exec(slice)) !== null) {
|
|
12389
|
+
const before = slice[m.index - 1];
|
|
12390
|
+
if (before === '.' || before === ')' || before === ']') continue;
|
|
12391
|
+
if (NON_CALL.has(m[2])) continue;
|
|
12392
|
+
out.push({ receiver: m[1], method: m[2] });
|
|
12393
|
+
}
|
|
12394
|
+
return out;
|
|
12395
|
+
}
|
|
12396
|
+
|
|
12397
|
+
// `private UserService userService;` / `UserService svc = new UserService();`
|
|
12398
|
+
// / `for (OmsOrderItem item : list)` → { userService: 'UserService', … }.
|
|
12399
|
+
// Declarations only: a bare assignment carries no type and is not inferred.
|
|
12400
|
+
const DECL_RE = /(?:^|[;{}(,\n])\s*(?:(?:public|private|protected|static|final|volatile|transient)\s+)*([A-Z][\w$]*)(?:\s*<[^>;=(){}]*>)?(?:\s*\[\s*\])?\s+([a-z_$][\w$]*)\s*(?=[;=:)])/g;
|
|
12401
|
+
|
|
12402
|
+
function buildTypeMap(masked) {
|
|
12403
|
+
const map = new Map();
|
|
12404
|
+
let m;
|
|
12405
|
+
DECL_RE.lastIndex = 0;
|
|
12406
|
+
while ((m = DECL_RE.exec(masked)) !== null) {
|
|
12407
|
+
const [, type, name] = m;
|
|
12408
|
+
if (JVM_KEYWORDS.has(type) || JVM_KEYWORDS.has(name)) continue;
|
|
12409
|
+
if (!map.has(name)) map.set(name, type); // first declaration wins — deterministic
|
|
12410
|
+
}
|
|
12411
|
+
return map;
|
|
12412
|
+
}
|
|
12413
|
+
|
|
12414
|
+
// Type names that are never a user class, so never a resolvable receiver type.
|
|
12415
|
+
const JVM_KEYWORDS = new Set([
|
|
12416
|
+
'return', 'new', 'if', 'else', 'for', 'while', 'switch', 'case', 'throw', 'catch',
|
|
12417
|
+
'String', 'Integer', 'Long', 'Boolean', 'Double', 'Float', 'Object', 'List', 'Map',
|
|
12418
|
+
'Set', 'Collection', 'Optional', 'Override', 'Autowired', 'Resource', 'Deprecated',
|
|
12419
|
+
]);
|
|
12420
|
+
|
|
12158
12421
|
// ── Public API ───────────────────────────────────────────────────────────────
|
|
12159
12422
|
|
|
12160
|
-
|
|
12161
|
-
|
|
12423
|
+
// Walk depth from each srcDir root (not from cwd). A Maven module reaches
|
|
12424
|
+
// `src/main/java/<group>/<artifact>/service/impl` nine directories down, so the
|
|
12425
|
+
// previous ceiling of 8 never saw the classes that own the method bodies.
|
|
12426
|
+
const DEFAULT_WALK_DEPTH = 12;
|
|
12427
|
+
|
|
12428
|
+
/**
|
|
12429
|
+
* Source directories declared in the project's own config, or null. Read
|
|
12430
|
+
* directly rather than through `loadConfig`, which can fetch `extends` over the
|
|
12431
|
+
* network and spawn a child process — neither belongs inside a graph build.
|
|
12432
|
+
*/
|
|
12433
|
+
function _configuredSrcDirs(cwd) {
|
|
12434
|
+
try {
|
|
12435
|
+
const cfg = JSON.parse(fs.readFileSync(path.join(cwd, 'gen-context.config.json'), 'utf8'));
|
|
12436
|
+
if (Array.isArray(cfg.srcDirs) && cfg.srcDirs.length > 0) return cfg.srcDirs;
|
|
12437
|
+
} catch (_) { /* absent or unparsable — fall back to the defaults */ }
|
|
12438
|
+
return null;
|
|
12439
|
+
}
|
|
12440
|
+
|
|
12441
|
+
function _walk(dir, excludeSet, out, depth, maxDepth) {
|
|
12442
|
+
if (depth > (maxDepth === undefined ? DEFAULT_WALK_DEPTH : maxDepth)) return;
|
|
12162
12443
|
let entries;
|
|
12163
12444
|
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch (_) { return; }
|
|
12164
12445
|
for (const e of entries) {
|
|
12165
12446
|
if (excludeSet.has(e.name) || e.name.startsWith('.')) continue;
|
|
12166
12447
|
const full = path.join(dir, e.name);
|
|
12167
|
-
if (e.isDirectory()) _walk(full, excludeSet, out, depth + 1);
|
|
12448
|
+
if (e.isDirectory()) _walk(full, excludeSet, out, depth + 1, maxDepth);
|
|
12168
12449
|
else if (e.isFile()) {
|
|
12169
12450
|
const ext = path.extname(e.name).toLowerCase();
|
|
12170
12451
|
if (JS_EXTS.has(ext) || PY_EXTS.has(ext) || JAVA_EXTS.has(ext) || GO_EXTS.has(ext) || RS_EXTS.has(ext)) out.push(full);
|
|
@@ -12190,9 +12471,13 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12190
12471
|
const excludeSet = new Set(opts.exclude || ['node_modules', '.git', 'dist', 'build', 'coverage', 'vendor']);
|
|
12191
12472
|
let files = opts.files ? opts.files.map((f) => path.resolve(f)) : [];
|
|
12192
12473
|
if (!opts.files) {
|
|
12193
|
-
|
|
12474
|
+
// Same resolution order as the dependency graph (#560): explicit opts →
|
|
12475
|
+
// the project's own config → the historical defaults. Without the config
|
|
12476
|
+
// step this is empty on any repo whose sources are not under src/app/lib.
|
|
12477
|
+
const srcDirs = opts.srcDirs || _configuredSrcDirs(cwd) || ['src', 'app', 'lib'];
|
|
12478
|
+
for (const sd of srcDirs) {
|
|
12194
12479
|
const abs = path.resolve(cwd, sd);
|
|
12195
|
-
if (fs.existsSync(abs)) _walk(abs, excludeSet, files, 0);
|
|
12480
|
+
if (fs.existsSync(abs)) _walk(abs, excludeSet, files, 0, opts.maxDepth);
|
|
12196
12481
|
}
|
|
12197
12482
|
}
|
|
12198
12483
|
|
|
@@ -12206,6 +12491,44 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12206
12491
|
const normToAbs = new Map(); // normalized abs → abs
|
|
12207
12492
|
const defs = new Map(); // symbolId → {file,name,line}
|
|
12208
12493
|
|
|
12494
|
+
// JVM convention: a public type lives in a file of the same name. This is the
|
|
12495
|
+
// deterministic type→file mapping receiver resolution needs, with no AST.
|
|
12496
|
+
const fileByTypeName = new Map(); // 'UserService' → [absFile]
|
|
12497
|
+
for (const f of files) {
|
|
12498
|
+
const ext = path.extname(f).toLowerCase();
|
|
12499
|
+
if (JAVA_EXTS.has(ext)) {
|
|
12500
|
+
const base = path.basename(f, path.extname(f));
|
|
12501
|
+
if (!fileByTypeName.has(base)) fileByTypeName.set(base, []);
|
|
12502
|
+
fileByTypeName.get(base).push(f);
|
|
12503
|
+
}
|
|
12504
|
+
}
|
|
12505
|
+
|
|
12506
|
+
// interface/superclass name → implementing files, for the Spring hop below.
|
|
12507
|
+
const implsByType = new Map(); // 'PaymentService' → [{ file, isBean, isPrimary }]
|
|
12508
|
+
for (const f of files) {
|
|
12509
|
+
if (!JAVA_EXTS.has(path.extname(f).toLowerCase())) continue;
|
|
12510
|
+
let decl;
|
|
12511
|
+
try { decl = javaTypeDecl(maskJs(fs.readFileSync(f, 'utf8'))); } catch (_) { continue; }
|
|
12512
|
+
if (!decl) continue;
|
|
12513
|
+
for (const sup of decl.supers) {
|
|
12514
|
+
if (!implsByType.has(sup)) implsByType.set(sup, []);
|
|
12515
|
+
implsByType.get(sup).push({ file: f, isBean: decl.isBean, isPrimary: decl.isPrimary });
|
|
12516
|
+
}
|
|
12517
|
+
}
|
|
12518
|
+
|
|
12519
|
+
/**
|
|
12520
|
+
* The single implementing file for a type, or null when it is ambiguous.
|
|
12521
|
+
* One implementation resolves outright; several resolve only via @Primary.
|
|
12522
|
+
* Anything still ambiguous yields no edge — polymorphism is not guessed.
|
|
12523
|
+
*/
|
|
12524
|
+
const soleImpl = (typeName) => {
|
|
12525
|
+
const cands = implsByType.get(typeName) || [];
|
|
12526
|
+
if (cands.length === 1) return cands[0].file;
|
|
12527
|
+
const primary = cands.filter((c) => c.isPrimary);
|
|
12528
|
+
if (primary.length === 1) return primary[0].file;
|
|
12529
|
+
return null;
|
|
12530
|
+
};
|
|
12531
|
+
|
|
12209
12532
|
for (const f of files) {
|
|
12210
12533
|
normToAbs.set(normalizePath(path.resolve(f)), path.resolve(f));
|
|
12211
12534
|
let src;
|
|
@@ -12225,12 +12548,20 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12225
12548
|
|
|
12226
12549
|
const forward = new Map();
|
|
12227
12550
|
const reverse = new Map();
|
|
12228
|
-
|
|
12551
|
+
// Additive: `forward`/`reverse` keep their existing shape, so every current
|
|
12552
|
+
// consumer is unaffected. Confidence is looked up by "from\u0000to".
|
|
12553
|
+
const edgeConfidence = new Map();
|
|
12554
|
+
const addEdge = (from, to, confidence) => {
|
|
12229
12555
|
if (from === to) return;
|
|
12230
12556
|
if (!forward.has(from)) forward.set(from, new Set());
|
|
12231
12557
|
forward.get(from).add(to);
|
|
12232
12558
|
if (!reverse.has(to)) reverse.set(to, new Set());
|
|
12233
12559
|
reverse.get(to).add(from);
|
|
12560
|
+
if (confidence) {
|
|
12561
|
+
const k = from + '\u0000' + to;
|
|
12562
|
+
// A 'high' resolution never loses to a later 'medium' one.
|
|
12563
|
+
if (edgeConfidence.get(k) !== 'high') edgeConfidence.set(k, confidence);
|
|
12564
|
+
}
|
|
12234
12565
|
};
|
|
12235
12566
|
|
|
12236
12567
|
for (const [f, fileDefs] of perFileDefs.entries()) {
|
|
@@ -12248,16 +12579,59 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12248
12579
|
.sort();
|
|
12249
12580
|
importedAbs.push(...siblings);
|
|
12250
12581
|
}
|
|
12582
|
+
// Receiver types come from declarations anywhere in the file: fields are
|
|
12583
|
+
// declared outside any method body, locals inside one.
|
|
12584
|
+
const typeMap = JAVA_EXTS.has(ext) ? buildTypeMap(masked) : null;
|
|
12585
|
+
// Types reachable from this file, by name — imports first, then same-package
|
|
12586
|
+
// siblings, so an import always wins over a coincidental sibling name.
|
|
12587
|
+
const scopeByTypeName = new Map();
|
|
12588
|
+
if (typeMap) {
|
|
12589
|
+
for (const imp of importedAbs) {
|
|
12590
|
+
const base = path.basename(imp, path.extname(imp));
|
|
12591
|
+
if (!scopeByTypeName.has(base)) scopeByTypeName.set(base, imp);
|
|
12592
|
+
}
|
|
12593
|
+
}
|
|
12594
|
+
|
|
12251
12595
|
for (const d of fileDefs) {
|
|
12252
12596
|
const callerId = symId(cwd, f, d.name);
|
|
12253
12597
|
if (!forward.has(callerId)) forward.set(callerId, new Set()); // ensure node exists
|
|
12254
12598
|
const callees = callsInRange(masked, d.bodyStart, d.bodyEnd);
|
|
12255
12599
|
for (const nm of callees) {
|
|
12256
12600
|
const local = (defsByName.get(f) || new Map()).get(nm);
|
|
12257
|
-
if (local && local.length) { for (const id of local) addEdge(callerId, id); continue; }
|
|
12601
|
+
if (local && local.length) { for (const id of local) addEdge(callerId, id, 'high'); continue; }
|
|
12258
12602
|
for (const imp of importedAbs) {
|
|
12259
12603
|
const ids = (defsByName.get(imp) || new Map()).get(nm);
|
|
12260
|
-
if (ids && ids.length) { for (const id of ids) addEdge(callerId, id); break; }
|
|
12604
|
+
if (ids && ids.length) { for (const id of ids) addEdge(callerId, id, 'high'); break; }
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
12607
|
+
|
|
12608
|
+
// `receiver.method(` — resolve the receiver's declared type to a file.
|
|
12609
|
+
if (!typeMap) continue;
|
|
12610
|
+
for (const { receiver, method } of receiverCallsInRange(masked, d.bodyStart, d.bodyEnd)) {
|
|
12611
|
+
// A receiver that is itself a type name is a static call: `Foo.bar()`.
|
|
12612
|
+
const typeName = typeMap.get(receiver)
|
|
12613
|
+
|| (fileByTypeName.has(receiver) ? receiver : null);
|
|
12614
|
+
if (!typeName) continue; // unknown receiver → no edge, never a guess
|
|
12615
|
+
|
|
12616
|
+
let target = scopeByTypeName.get(typeName);
|
|
12617
|
+
let confidence = 'high'; // typed receiver, resolved in scope
|
|
12618
|
+
if (!target) {
|
|
12619
|
+
const candidates = fileByTypeName.get(typeName) || [];
|
|
12620
|
+
if (candidates.length !== 1) continue; // ambiguous or absent → no edge
|
|
12621
|
+
target = candidates[0];
|
|
12622
|
+
confidence = 'medium'; // type known, but not in this file's scope
|
|
12623
|
+
}
|
|
12624
|
+
const ids = (defsByName.get(target) || new Map()).get(method);
|
|
12625
|
+
if (ids && ids.length) for (const id of ids) addEdge(callerId, id, confidence);
|
|
12626
|
+
|
|
12627
|
+
// Spring: the call names the interface, but the code that runs — and
|
|
12628
|
+
// that a reviewer changes — lives in the implementation. Both edges are
|
|
12629
|
+
// true, so both are recorded; without the second, blast radius on an
|
|
12630
|
+
// implementation is empty.
|
|
12631
|
+
const implFile = soleImpl(typeName);
|
|
12632
|
+
if (implFile && implFile !== target) {
|
|
12633
|
+
const implIds = (defsByName.get(implFile) || new Map()).get(method);
|
|
12634
|
+
if (implIds && implIds.length) for (const id of implIds) addEdge(callerId, id, confidence);
|
|
12261
12635
|
}
|
|
12262
12636
|
}
|
|
12263
12637
|
}
|
|
@@ -12268,7 +12642,7 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12268
12642
|
for (const [k, set] of mapOfSets.entries()) out.set(k, [...set]);
|
|
12269
12643
|
return out;
|
|
12270
12644
|
};
|
|
12271
|
-
return { forward: toArr(forward), reverse: toArr(reverse), defs };
|
|
12645
|
+
return { forward: toArr(forward), reverse: toArr(reverse), defs, edgeConfidence };
|
|
12272
12646
|
}
|
|
12273
12647
|
|
|
12274
12648
|
/**
|
|
@@ -12390,7 +12764,7 @@ __factories["./src/graph/call-graph"] = function(module, exports) {
|
|
|
12390
12764
|
}
|
|
12391
12765
|
|
|
12392
12766
|
module.exports = {
|
|
12393
|
-
buildCallGraph, buildCallFileGraph, methodImpact, methodCallees,
|
|
12767
|
+
buildCallGraph, buildTypeMap, receiverCallsInRange, javaTypeDecl, DEFAULT_WALK_DEPTH, buildCallFileGraph, methodImpact, methodCallees,
|
|
12394
12768
|
formatCallGraph, formatCallGraphJSON,
|
|
12395
12769
|
extractDefs, maskJs, maskPy, maskRust,
|
|
12396
12770
|
};
|
|
@@ -15440,7 +15814,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
15440
15814
|
|
|
15441
15815
|
const SERVER_INFO = {
|
|
15442
15816
|
name: 'sigmap',
|
|
15443
|
-
version: '8.
|
|
15817
|
+
version: '8.32.0',
|
|
15444
15818
|
description: 'SigMap MCP server — code signatures on demand',
|
|
15445
15819
|
};
|
|
15446
15820
|
|
|
@@ -18805,7 +19179,7 @@ __factories["./src/skills/skills"] = function(module, exports) {
|
|
|
18805
19179
|
'Follow this loop before any file exploration in a repo with SigMap installed.',
|
|
18806
19180
|
'',
|
|
18807
19181
|
'1. **Ask before reading.** `sigmap ask "<task>"` (or the `query_context` MCP tool) ranks the relevant files as ~hundreds of tokens of signatures instead of thousands of raw-file tokens. Never open files to "look around".',
|
|
18808
|
-
'2. **Read ranges, not files.** Use the `get_lines` MCP tool with the `:start-end` line anchors carried on every signature to pull only the lines you need.',
|
|
19182
|
+
'2. **Read ranges, not files.** Use the `get_lines` MCP tool — or `sigmap lines <file> :<line> --context <n>` where MCP is unavailable — with the `:start-end` line anchors carried on every signature to pull only the lines you need.',
|
|
18809
19183
|
'3. **Ground before trusting.** Run the `verify_suggestion` MCP tool (or `sigmap verify-ai-output`) on generated code before applying it — it flags fabricated files, imports, symbols, and npm scripts against the live index.',
|
|
18810
19184
|
'4. **Squeeze big pastes.** Any stack trace, CI/build log, or JSON blob goes through `sigmap squeeze` (or the `squeeze_output` MCP tool) before it enters context — the signal survives, the noise does not.',
|
|
18811
19185
|
'5. **Checkpoint progress.** Use the `create_checkpoint` MCP tool or `sigmap note "<decision>"` so a follow-up session resumes without re-deriving state.',
|
|
@@ -18823,7 +19197,7 @@ __factories["./src/skills/skills"] = function(module, exports) {
|
|
|
18823
19197
|
'',
|
|
18824
19198
|
'1. **Look up, do not search.** `npx sigmap ask "<the task>"` — this writes `.context/query-context.md`.',
|
|
18825
19199
|
'2. **Read the map.** `cat .context/query-context.md`. It ranks the relevant files and lists their signatures with `:start-end` line anchors — a few hundred tokens where the same files read whole are tens of thousands. Say which files it surfaced before continuing. If nothing relevant appears, re-run step 1 with different wording; fall back to search only after two attempts, and say so.',
|
|
18826
|
-
'3. **
|
|
19200
|
+
'3. **Read the anchored range, by command.** A signature ending `:425-425` means line 425, not the 547-line file. Run `npx sigmap lines <file> :425 --context 10` — paste the anchor straight off the signature. Never `cat` a whole file when you hold an anchor for it: on a real repo a 220-line span costs ~2,700 tokens where the anchored window costs ~220.',
|
|
18827
19201
|
'4. **Make the change.** Follow the conventions visible in the signatures — same layering, same response wrapper, same annotation style. Add no dependencies.',
|
|
18828
19202
|
'5. **Verify before reporting.** Write what you changed to `.sigmap-notes.md`, naming every file by its **full repository-relative path** (a bare filename is reported as fake), then run `npx sigmap verify-ai-output .sigmap-notes.md`. It checks every name against the real index, offline, with no model call. Fix anything it flags and re-run before you reply.',
|
|
18829
19203
|
'6. **Refresh the map.** `npx sigmap` — your edits made it stale.',
|
|
@@ -21734,7 +22108,7 @@ function __tryGit(args, opts = {}) {
|
|
|
21734
22108
|
catch (_) { return ''; }
|
|
21735
22109
|
}
|
|
21736
22110
|
|
|
21737
|
-
const VERSION = '8.
|
|
22111
|
+
const VERSION = '8.32.0';
|
|
21738
22112
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
21739
22113
|
|
|
21740
22114
|
function requireSourceOrBundled(key) {
|
|
@@ -23740,6 +24114,8 @@ Usage:
|
|
|
23740
24114
|
${cmd} tune --apply Write the recommendations into gen-context.config.json (merges; your keys preserved)
|
|
23741
24115
|
${cmd} skills list List skill clients (Claude/Cursor/Windsurf/Copilot/AGENTS.md) and install state (--json)
|
|
23742
24116
|
${cmd} skills install Install the SigMap agent playbooks for detected clients (--client <name> | --all)
|
|
24117
|
+
${cmd} lines <file> <start>-<end> Print an exact line range — CLI twin of get_lines (secrets redacted)
|
|
24118
|
+
${cmd} lines <file> :<line> --context <n> Window around one signature anchor (default ±10)
|
|
23743
24119
|
${cmd} note "<text>" Append a note to the cross-session decision log
|
|
23744
24120
|
${cmd} note List recent notes (also: note --list <N>)
|
|
23745
24121
|
${cmd} status Show repo state — branch, dirty files, index freshness, notes
|
|
@@ -25343,6 +25719,55 @@ function main() {
|
|
|
25343
25719
|
process.exit(0);
|
|
25344
25720
|
}
|
|
25345
25721
|
|
|
25722
|
+
// `sigmap lines <file> <start>-<end>` — the CLI twin of the get_lines MCP
|
|
25723
|
+
// tool. Without it, an agent in an MCP-less environment receives precise
|
|
25724
|
+
// `:start-end` anchors from `ask` and has no sanctioned way to spend them,
|
|
25725
|
+
// so it falls back to reading whole files and throws the saving away.
|
|
25726
|
+
// Delegates to the same handler as MCP so both paths share the sandbox,
|
|
25727
|
+
// the bounds clamping and the secret redaction.
|
|
25728
|
+
if (args[0] === 'lines') {
|
|
25729
|
+
const valOf = (f) => { const i = args.indexOf(f); return i >= 0 && args[i + 1] ? args[i + 1] : null; };
|
|
25730
|
+
const positional = [];
|
|
25731
|
+
const VALUE_FLAGS = new Set(['--cwd', '--context']);
|
|
25732
|
+
for (let i = 1; i < args.length; i++) {
|
|
25733
|
+
const a = args[i];
|
|
25734
|
+
if (a.startsWith('--')) { if (VALUE_FLAGS.has(a)) i++; continue; }
|
|
25735
|
+
positional.push(a);
|
|
25736
|
+
}
|
|
25737
|
+
const file = positional[0];
|
|
25738
|
+
const range = positional[1];
|
|
25739
|
+
if (!file || !range) {
|
|
25740
|
+
console.error('[sigmap] usage: sigmap lines <file> <start>-<end> (or :<line> --context <n>)');
|
|
25741
|
+
process.exit(2);
|
|
25742
|
+
}
|
|
25743
|
+
|
|
25744
|
+
// Accept `84-104`, a bare `94`, or the `:94` form copied straight off a
|
|
25745
|
+
// signature anchor — the whole point is to paste what `ask` printed.
|
|
25746
|
+
const ctx = Math.max(0, parseInt(valOf('--context') || '10', 10));
|
|
25747
|
+
let start;
|
|
25748
|
+
let end;
|
|
25749
|
+
const span = /^:?(\d+)\s*-\s*(\d+)$/.exec(range);
|
|
25750
|
+
const single = /^:?(\d+)$/.exec(range);
|
|
25751
|
+
if (span) { start = parseInt(span[1], 10); end = parseInt(span[2], 10); }
|
|
25752
|
+
else if (single) { const n = parseInt(single[1], 10); start = Math.max(1, n - ctx); end = n + ctx; }
|
|
25753
|
+
else {
|
|
25754
|
+
console.error(`[sigmap] lines: could not read range "${range}" — expected <start>-<end> or :<line>`);
|
|
25755
|
+
process.exit(2);
|
|
25756
|
+
}
|
|
25757
|
+
|
|
25758
|
+
const { getLines } = requireSourceOrBundled('./src/mcp/handlers');
|
|
25759
|
+
const out = getLines({ file, start, end }, cwd);
|
|
25760
|
+
// The handler reports its own failures as prose; surface them on stderr
|
|
25761
|
+
// with a non-zero exit so a script can tell a hit from a miss.
|
|
25762
|
+
if (/^(Missing required argument|Refused:|File not found:|Could not read |Arguments )/.test(out)
|
|
25763
|
+
|| /has only \d+ lines; requested/.test(out)) {
|
|
25764
|
+
console.error('[sigmap] ' + out);
|
|
25765
|
+
process.exit(1);
|
|
25766
|
+
}
|
|
25767
|
+
process.stdout.write(out + '\n');
|
|
25768
|
+
process.exit(0);
|
|
25769
|
+
}
|
|
25770
|
+
|
|
25346
25771
|
if (args[0] === 'note') {
|
|
25347
25772
|
const jsonOut = args.includes('--json');
|
|
25348
25773
|
const { addNote, readNotes, formatNotes } = requireSourceOrBundled('./src/session/notes');
|