autodocs-engine 0.10.2 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -4
- package/dist/bin/autodocs-engine.js +10 -1
- package/dist/bin/autodocs-engine.js.map +1 -1
- package/dist/bin/serve.d.ts +1 -0
- package/dist/bin/serve.js +11 -5
- package/dist/bin/serve.js.map +1 -1
- package/dist/bin/visualize.d.ts +5 -0
- package/dist/bin/visualize.js +29 -0
- package/dist/bin/visualize.js.map +1 -0
- package/dist/mcp/cache.js +15 -1
- package/dist/mcp/cache.js.map +1 -1
- package/dist/mcp/queries.d.ts +60 -0
- package/dist/mcp/queries.js +254 -10
- package/dist/mcp/queries.js.map +1 -1
- package/dist/mcp/server.d.ts +5 -2
- package/dist/mcp/server.js +293 -24
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +10 -0
- package/dist/mcp/tools.js +173 -4
- package/dist/mcp/tools.js.map +1 -1
- package/dist/pipeline.js +9 -1
- package/dist/pipeline.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.js.map +1 -1
- package/dist/visualizer.d.ts +2 -0
- package/dist/visualizer.js +291 -0
- package/dist/visualizer.js.map +1 -0
- package/hooks/autodocs-hook.cjs +68 -38
- package/package.json +1 -1
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// src/visualizer.ts — Full-viewport codebase topology visualization.
|
|
2
|
+
// The graph IS the page. Structural imports + behavioral co-change edges
|
|
3
|
+
// rendered simultaneously on a dark canvas. Click to explore blast radius.
|
|
4
|
+
export function generateReport(analysis) {
|
|
5
|
+
const pkg = analysis.packages[0];
|
|
6
|
+
if (!pkg)
|
|
7
|
+
return "<html><body><p>No packages found.</p></body></html>";
|
|
8
|
+
const graph = buildGraphData(pkg);
|
|
9
|
+
const importData = (pkg.importChain ?? []).map((e) => [e.source, e.importer, e.symbolCount]);
|
|
10
|
+
const cochangeData = (pkg.gitHistory?.coChangeEdges ?? []).map((e) => [
|
|
11
|
+
e.file1,
|
|
12
|
+
e.file2,
|
|
13
|
+
Math.round(e.jaccard * 100),
|
|
14
|
+
]);
|
|
15
|
+
const clusterData = pkg.coChangeClusters ?? [];
|
|
16
|
+
const statsHtml = [
|
|
17
|
+
["Files", pkg.files.total],
|
|
18
|
+
["Imports", pkg.importChain?.length ?? 0],
|
|
19
|
+
["Co-changes", pkg.gitHistory?.coChangeEdges?.length ?? 0],
|
|
20
|
+
["Clusters", pkg.coChangeClusters?.length ?? 0],
|
|
21
|
+
["Flows", pkg.executionFlows?.length ?? 0],
|
|
22
|
+
]
|
|
23
|
+
.map(([l, v]) => `<div class="s"><span class="sv">${v}</span><span class="sl">${l}</span></div>`)
|
|
24
|
+
.join("");
|
|
25
|
+
const flowsHtml = (pkg.executionFlows ?? [])
|
|
26
|
+
.slice(0, 6)
|
|
27
|
+
.map((f) => {
|
|
28
|
+
const conf = f.confidence >= 0.3
|
|
29
|
+
? '<i class="dot dot-g"></i>'
|
|
30
|
+
: f.confidence > 0
|
|
31
|
+
? '<i class="dot dot-a"></i>'
|
|
32
|
+
: '<i class="dot dot-m"></i>';
|
|
33
|
+
return `<div class="fl">${conf}<span>${esc(f.steps.join(" \u2192 "))}</span></div>`;
|
|
34
|
+
})
|
|
35
|
+
.join("");
|
|
36
|
+
const convHtml = [
|
|
37
|
+
...(pkg.conventions ?? []).map((c) => `<div class="cv cv-do">${esc(c.name)} <span class="cd">${c.confidence.percentage}%</span></div>`),
|
|
38
|
+
...(pkg.antiPatterns ?? []).map((a) => `<div class="cv cv-no">${esc(a.rule)}</div>`),
|
|
39
|
+
].join("");
|
|
40
|
+
return `<!DOCTYPE html>
|
|
41
|
+
<html lang="en">
|
|
42
|
+
<head>
|
|
43
|
+
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
44
|
+
<title>${esc(pkg.name)} \u2014 Codebase Topology</title>
|
|
45
|
+
<style>
|
|
46
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
47
|
+
html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0a0a0f;color:#e0e0e0}
|
|
48
|
+
svg{display:block;width:100%;height:100%}
|
|
49
|
+
.hdr{position:fixed;top:0;left:0;right:0;padding:16px 24px;display:flex;align-items:center;gap:16px;z-index:10;pointer-events:none}
|
|
50
|
+
.hdr>*{pointer-events:auto}
|
|
51
|
+
.hdr h1{font-size:18px;font-weight:700;letter-spacing:-0.02em;white-space:nowrap}
|
|
52
|
+
.hdr .tag{font-size:11px;padding:2px 8px;border-radius:99px;background:rgba(255,255,255,0.08);color:#888}
|
|
53
|
+
.stats{display:flex;gap:2px;margin-left:auto}
|
|
54
|
+
.s{text-align:center;padding:4px 12px}
|
|
55
|
+
.sv{display:block;font-size:16px;font-weight:700;color:#7aa2f7}
|
|
56
|
+
.sl{display:block;font-size:9px;text-transform:uppercase;letter-spacing:0.08em;color:#555}
|
|
57
|
+
.legend{position:fixed;bottom:16px;left:24px;display:flex;gap:16px;font-size:11px;color:#555;z-index:10}
|
|
58
|
+
.legend i{display:inline-block;width:20px;height:2px;vertical-align:middle;margin-right:4px;border-radius:1px}
|
|
59
|
+
.leg-imp{background:#333}
|
|
60
|
+
.leg-coc{background:#c59a28;opacity:0.7}
|
|
61
|
+
.leg-impl{background:#b44e8a;opacity:0.7}
|
|
62
|
+
.panel{position:fixed;top:0;right:0;width:300px;height:100%;background:#0d0d14;border-left:1px solid #1a1a24;z-index:20;transform:translateX(100%);transition:transform 0.25s ease;overflow-y:auto;padding:20px}
|
|
63
|
+
.panel.open{transform:translateX(0)}
|
|
64
|
+
.panel h2{font-size:15px;font-weight:700;margin-bottom:2px}
|
|
65
|
+
.panel .sub{font-size:12px;color:#555;margin-bottom:16px}
|
|
66
|
+
.panel h3{font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:#444;margin:14px 0 6px}
|
|
67
|
+
.panel ul{list-style:none}
|
|
68
|
+
.panel li{font-size:12px;padding:4px 0;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid #111}
|
|
69
|
+
.panel li:last-child{border:none}
|
|
70
|
+
.panel code{font-size:11px;color:#8a8a9a}
|
|
71
|
+
.badge{font-size:9px;padding:1px 6px;border-radius:99px;font-weight:600}
|
|
72
|
+
.badge-b{background:rgba(122,162,247,0.15);color:#7aa2f7}
|
|
73
|
+
.badge-a{background:rgba(197,154,40,0.15);color:#c59a28}
|
|
74
|
+
.badge-p{background:rgba(180,78,138,0.15);color:#b44e8a}
|
|
75
|
+
.close-btn{position:absolute;top:12px;right:12px;background:none;border:none;color:#444;font-size:18px;cursor:pointer;padding:4px 8px}
|
|
76
|
+
.close-btn:hover{color:#888}
|
|
77
|
+
.drawer{position:fixed;bottom:0;left:0;right:0;z-index:10;pointer-events:none}
|
|
78
|
+
.drawer>*{pointer-events:auto}
|
|
79
|
+
.dtoggle{display:flex;justify-content:center;padding:8px}
|
|
80
|
+
.dtoggle button{font-size:11px;padding:4px 16px;border-radius:99px 99px 0 0;border:1px solid #1a1a24;border-bottom:none;background:#0d0d14;color:#666;cursor:pointer}
|
|
81
|
+
.dtoggle button:hover{color:#999}
|
|
82
|
+
.dcontent{background:#0d0d14;border-top:1px solid #1a1a24;max-height:0;overflow:hidden;transition:max-height 0.3s ease}
|
|
83
|
+
.dcontent.open{max-height:300px;overflow-y:auto}
|
|
84
|
+
.dcontent-inner{padding:16px 24px;display:flex;gap:32px}
|
|
85
|
+
.dcol{flex:1;min-width:200px}
|
|
86
|
+
.dcol h3{font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:#444;margin-bottom:8px}
|
|
87
|
+
.fl{font-size:11px;color:#666;padding:3px 0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
88
|
+
.fl span{margin-left:4px}
|
|
89
|
+
.dot{display:inline-block;width:6px;height:6px;border-radius:50%}
|
|
90
|
+
.dot-g{background:#4ade80}.dot-a{background:#c59a28}.dot-m{background:#333}
|
|
91
|
+
.cv{font-size:11px;padding:4px 8px;margin:2px 0;border-radius:4px;border-left:3px solid}
|
|
92
|
+
.cv-do{border-color:#4ade80;background:rgba(74,222,128,0.05);color:#777}
|
|
93
|
+
.cv-no{border-color:#f87171;background:rgba(248,113,113,0.05);color:#777}
|
|
94
|
+
.cd{font-size:9px;color:#555}
|
|
95
|
+
.hint{position:fixed;bottom:50px;left:50%;transform:translateX(-50%);font-size:12px;color:#333;z-index:5;transition:opacity 0.5s}
|
|
96
|
+
</style>
|
|
97
|
+
</head>
|
|
98
|
+
<body>
|
|
99
|
+
<div class="hdr">
|
|
100
|
+
<h1>${esc(pkg.name)}</h1>
|
|
101
|
+
<span class="tag">${pkg.architecture.packageType}</span>
|
|
102
|
+
<div class="stats">${statsHtml}</div>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="legend">
|
|
105
|
+
<span><i class="leg-imp"></i>import</span>
|
|
106
|
+
<span><i class="leg-coc" style="border:1px dashed #c59a28;height:0;width:20px"></i>co-change</span>
|
|
107
|
+
<span><i class="leg-impl" style="border:1px dotted #b44e8a;height:0;width:20px"></i>implicit coupling</span>
|
|
108
|
+
</div>
|
|
109
|
+
<div class="hint" id="hint">click a module to explore its blast radius</div>
|
|
110
|
+
<svg id="graph"></svg>
|
|
111
|
+
<div class="panel" id="panel">
|
|
112
|
+
<button class="close-btn" onclick="closePanel()">×</button>
|
|
113
|
+
<div id="panel-content"></div>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="drawer">
|
|
116
|
+
<div class="dtoggle"><button onclick="toggleDrawer()">Flows & Conventions</button></div>
|
|
117
|
+
<div class="dcontent" id="drawer">
|
|
118
|
+
<div class="dcontent-inner">
|
|
119
|
+
<div class="dcol"><h3>Execution Flows</h3>${flowsHtml || '<div class="fl">No flows detected</div>'}</div>
|
|
120
|
+
<div class="dcol"><h3>Conventions</h3>${convHtml || '<div class="cv">No conventions detected</div>'}</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
|
|
125
|
+
<script>
|
|
126
|
+
const G=${JSON.stringify(graph)};
|
|
127
|
+
const IM=${JSON.stringify(importData)};
|
|
128
|
+
const CC=${JSON.stringify(cochangeData)};
|
|
129
|
+
const CL=${JSON.stringify(clusterData)};
|
|
130
|
+
const PAL=['#7aa2f7','#4ade80','#c59a28','#f87171','#a78bfa','#e879a0','#38bdf8','#fb923c'];
|
|
131
|
+
const W=innerWidth,H=innerHeight;
|
|
132
|
+
const svg=d3.select('#graph').attr('viewBox',[0,0,W,H]);
|
|
133
|
+
const maxW=Math.max(1,...G.edges.map(e=>e.weight));
|
|
134
|
+
const maxF=Math.max(1,...G.nodes.map(n=>n.files));
|
|
135
|
+
const NC=G.nodes.length;
|
|
136
|
+
const spread=Math.min(W,H)*0.35;
|
|
137
|
+
const sim=d3.forceSimulation(G.nodes)
|
|
138
|
+
.force('link',d3.forceLink(G.edges).id(d=>d.id).distance(220))
|
|
139
|
+
.force('charge',d3.forceManyBody().strength(NC>12?-1200:NC>6?-1800:-2400))
|
|
140
|
+
.force('center',d3.forceCenter(W/2,H/2))
|
|
141
|
+
.force('collision',d3.forceCollide().radius(d=>30+Math.sqrt(d.files/maxF)*35))
|
|
142
|
+
.force('x',d3.forceX(W/2).strength(0.02))
|
|
143
|
+
.force('y',d3.forceY(H/2).strength(0.02));
|
|
144
|
+
const link=svg.append('g').selectAll('line').data(G.edges).join('line')
|
|
145
|
+
.attr('stroke',d=>d.type==='cochange'?'#c59a28':d.type==='implicit'?'#b44e8a':'#222')
|
|
146
|
+
.attr('stroke-width',d=>d.type==='cochange'||d.type==='implicit'?1.5:Math.max(0.8,Math.sqrt(d.weight/maxW)*4))
|
|
147
|
+
.attr('stroke-dasharray',d=>d.type==='cochange'?'6,4':d.type==='implicit'?'2,3':'none')
|
|
148
|
+
.attr('opacity',d=>d.type==='import'?0.35:0.5);
|
|
149
|
+
const defs=svg.append('defs');
|
|
150
|
+
const glow=defs.append('filter').attr('id','glow');
|
|
151
|
+
glow.append('feGaussianBlur').attr('stdDeviation','3').attr('result','blur');
|
|
152
|
+
const m=glow.append('feMerge');m.append('feMergeNode').attr('in','blur');m.append('feMergeNode').attr('in','SourceGraphic');
|
|
153
|
+
const node=svg.append('g').selectAll('g').data(G.nodes).join('g')
|
|
154
|
+
.call(d3.drag().on('start',(e,d)=>{if(!e.active)sim.alphaTarget(.3).restart();d.fx=d.x;d.fy=d.y})
|
|
155
|
+
.on('drag',(e,d)=>{d.fx=e.x;d.fy=e.y}).on('end',(e,d)=>{if(!e.active)sim.alphaTarget(0);d.fx=null;d.fy=null}))
|
|
156
|
+
.on('click',(e,d)=>{e.stopPropagation();selectNode(d)})
|
|
157
|
+
.style('cursor','pointer');
|
|
158
|
+
node.append('circle')
|
|
159
|
+
.attr('r',d=>16+Math.sqrt(d.files/maxF)*32)
|
|
160
|
+
.attr('fill',d=>d.group>=0?PAL[d.group%PAL.length]+'22':'#151520')
|
|
161
|
+
.attr('stroke',d=>d.group>=0?PAL[d.group%PAL.length]:'#282830')
|
|
162
|
+
.attr('stroke-width',1.5);
|
|
163
|
+
function lbl(d){const p=d.id.split('/');if(p.length<=1)return d.id||'root';const l=p.at(-1);return G.nodes.filter(n=>n.id.split('/').at(-1)===l).length>1?p.slice(-2).join('/'):l}
|
|
164
|
+
node.append('text').text(d=>lbl(d))
|
|
165
|
+
.attr('text-anchor','middle').attr('dy',d=>-(22+Math.sqrt(d.files/maxF)*34))
|
|
166
|
+
.attr('font-size','13px').attr('fill','#888').attr('font-weight','600')
|
|
167
|
+
.attr('paint-order','stroke').attr('stroke','#0a0a0f').attr('stroke-width',4);
|
|
168
|
+
node.append('text').text(d=>d.files)
|
|
169
|
+
.attr('text-anchor','middle').attr('dy',6)
|
|
170
|
+
.attr('font-size','13px').attr('fill','#555').attr('font-weight','700');
|
|
171
|
+
sim.on('tick',()=>{
|
|
172
|
+
link.attr('x1',d=>d.source.x).attr('y1',d=>d.source.y).attr('x2',d=>d.target.x).attr('y2',d=>d.target.y);
|
|
173
|
+
node.attr('transform',d=>\`translate(\${d.x},\${d.y})\`);
|
|
174
|
+
});
|
|
175
|
+
function selectNode(d){
|
|
176
|
+
document.getElementById('hint').style.opacity='0';
|
|
177
|
+
node.select('circle').attr('opacity',.15).attr('filter',null);
|
|
178
|
+
link.attr('opacity',.04);
|
|
179
|
+
node.filter(n=>n.id===d.id).select('circle').attr('opacity',1).attr('filter','url(#glow)').attr('stroke-width',2.5);
|
|
180
|
+
const conn=new Set();
|
|
181
|
+
G.edges.forEach(e=>{const s=typeof e.source==='object'?e.source.id:e.source,t=typeof e.target==='object'?e.target.id:e.target;if(s===d.id)conn.add(t);if(t===d.id)conn.add(s)});
|
|
182
|
+
node.filter(n=>conn.has(n.id)).select('circle').attr('opacity',.85);
|
|
183
|
+
link.filter(e=>{const s=typeof e.source==='object'?e.source.id:e.source,t=typeof e.target==='object'?e.target.id:e.target;return s===d.id||t===d.id}).attr('opacity',.9);
|
|
184
|
+
const dir=d.id;
|
|
185
|
+
const imp=IM.filter(e=>(e[0].startsWith(dir+'/')||e[0]===dir)&&!e[1].startsWith(dir+'/'));
|
|
186
|
+
const coc=CC.filter(e=>((e[0].startsWith(dir+'/')||e[0]===dir)&&!e[1].startsWith(dir+'/'))||((e[1].startsWith(dir+'/')||e[1]===dir)&&!e[0].startsWith(dir+'/')));
|
|
187
|
+
const seen=new Set();const ucoc=coc.filter(e=>{const k=e[0]+e[1];if(seen.has(k))return false;seen.add(k);return true});
|
|
188
|
+
const cl=CL.filter(c=>c.some(f=>f.startsWith(dir+'/')||f===dir));
|
|
189
|
+
let h='<h2>'+dir+'/</h2>';
|
|
190
|
+
h+='<div class="sub">'+d.files+' files · '+d.imports+' imported · '+d.exports+' exported</div>';
|
|
191
|
+
if(imp.length){h+='<h3>Imported by ('+imp.length+')</h3><ul>';imp.slice(0,10).forEach(e=>{h+='<li><code>'+e[1].split('/').slice(-2).join('/')+'</code><span class="badge badge-b">'+e[2]+'</span></li>'});h+='</ul>'}
|
|
192
|
+
if(ucoc.length){h+='<h3>Co-change partners</h3><ul>';ucoc.slice(0,6).forEach(e=>{const p=(e[0].startsWith(dir+'/')||e[0]===dir)?e[1]:e[0];h+='<li><code>'+p.split('/').slice(-2).join('/')+'</code><span class="badge badge-a">'+e[2]+'%</span></li>'});h+='</ul>'}
|
|
193
|
+
if(cl.length){h+='<h3>Cluster membership</h3><ul>';cl.forEach(c=>{h+='<li><span>'+c.length+'-file cluster</span><span class="badge badge-p">clique</span></li>'});h+='</ul>'}
|
|
194
|
+
if(!imp.length&&!ucoc.length&&!cl.length){h+='<div style="color:#333;padding:16px 0">No external dependencies detected</div>'}
|
|
195
|
+
document.getElementById('panel-content').innerHTML=h;
|
|
196
|
+
document.getElementById('panel').classList.add('open');
|
|
197
|
+
}
|
|
198
|
+
function closePanel(){
|
|
199
|
+
document.getElementById('panel').classList.remove('open');
|
|
200
|
+
node.select('circle').attr('opacity',1).attr('filter',null).attr('stroke-width',1.5);
|
|
201
|
+
link.attr('opacity',d=>d.type==='import'?.35:.5);
|
|
202
|
+
}
|
|
203
|
+
svg.on('click',()=>closePanel());
|
|
204
|
+
function toggleDrawer(){document.getElementById('drawer').classList.toggle('open')}
|
|
205
|
+
</script>
|
|
206
|
+
</body>
|
|
207
|
+
</html>`;
|
|
208
|
+
}
|
|
209
|
+
function buildGraphData(pkg) {
|
|
210
|
+
const importEdges = pkg.importChain ?? [];
|
|
211
|
+
const coChangeEdges = pkg.gitHistory?.coChangeEdges ?? [];
|
|
212
|
+
const implicitEdges = pkg.implicitCoupling ?? [];
|
|
213
|
+
const clusters = pkg.coChangeClusters ?? [];
|
|
214
|
+
const ds = new Map();
|
|
215
|
+
const de = new Map();
|
|
216
|
+
for (const e of importEdges) {
|
|
217
|
+
const f = fdir(e.importer);
|
|
218
|
+
const t = fdir(e.source);
|
|
219
|
+
for (const d of [f, t])
|
|
220
|
+
if (!ds.has(d))
|
|
221
|
+
ds.set(d, { files: new Set(), imports: 0, exports: 0 });
|
|
222
|
+
ds.get(f).files.add(e.importer);
|
|
223
|
+
ds.get(t).files.add(e.source);
|
|
224
|
+
ds.get(f).imports += e.symbolCount;
|
|
225
|
+
ds.get(t).exports += e.symbolCount;
|
|
226
|
+
if (f !== t) {
|
|
227
|
+
const k = `${f}|${t}`;
|
|
228
|
+
de.set(k, (de.get(k) ?? 0) + e.symbolCount);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const ce = new Map();
|
|
232
|
+
for (const e of coChangeEdges) {
|
|
233
|
+
const a = fdir(e.file1);
|
|
234
|
+
const b = fdir(e.file2);
|
|
235
|
+
if (a === b)
|
|
236
|
+
continue;
|
|
237
|
+
const k = [a, b].sort().join("|");
|
|
238
|
+
ce.set(k, (ce.get(k) ?? 0) + e.jaccard);
|
|
239
|
+
}
|
|
240
|
+
const ie = new Map();
|
|
241
|
+
for (const e of implicitEdges) {
|
|
242
|
+
const a = fdir(e.file1);
|
|
243
|
+
const b = fdir(e.file2);
|
|
244
|
+
if (a === b)
|
|
245
|
+
continue;
|
|
246
|
+
const k = [a, b].sort().join("|");
|
|
247
|
+
ie.set(k, (ie.get(k) ?? 0) + e.jaccard);
|
|
248
|
+
}
|
|
249
|
+
const dc = new Map();
|
|
250
|
+
for (let i = 0; i < clusters.length; i++) {
|
|
251
|
+
for (const f of clusters[i]) {
|
|
252
|
+
const d = fdir(f);
|
|
253
|
+
if (!dc.has(d))
|
|
254
|
+
dc.set(d, i);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const nodes = [...ds.entries()].map(([id, s]) => ({
|
|
258
|
+
id,
|
|
259
|
+
files: s.files.size,
|
|
260
|
+
imports: s.imports,
|
|
261
|
+
exports: s.exports,
|
|
262
|
+
group: dc.get(id) ?? -1,
|
|
263
|
+
}));
|
|
264
|
+
const edges = [];
|
|
265
|
+
for (const [k, w] of de) {
|
|
266
|
+
const [s, t] = k.split("|");
|
|
267
|
+
edges.push({ source: s, target: t, weight: w, type: "import" });
|
|
268
|
+
}
|
|
269
|
+
for (const [k, w] of ce) {
|
|
270
|
+
const [s, t] = k.split("|");
|
|
271
|
+
if (!de.has(`${s}|${t}`) && !de.has(`${t}|${s}`)) {
|
|
272
|
+
edges.push({ source: s, target: t, weight: Math.round(w * 20), type: "cochange" });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
for (const [k, w] of ie) {
|
|
276
|
+
const [s, t] = k.split("|");
|
|
277
|
+
const ck = [s, t].sort().join("|");
|
|
278
|
+
if (!ce.has(ck) && !de.has(`${s}|${t}`) && !de.has(`${t}|${s}`)) {
|
|
279
|
+
edges.push({ source: s, target: t, weight: Math.round(w * 15), type: "implicit" });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return { nodes, edges };
|
|
283
|
+
}
|
|
284
|
+
function esc(s) {
|
|
285
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
286
|
+
}
|
|
287
|
+
function fdir(p) {
|
|
288
|
+
const i = p.lastIndexOf("/");
|
|
289
|
+
return i >= 0 ? p.slice(0, i) : ".";
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=visualizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visualizer.js","sourceRoot":"","sources":["../src/visualizer.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,yEAAyE;AACzE,2EAA2E;AAM3E,MAAM,UAAU,cAAc,CAAC,QAA4B;IACzD,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,CAAC,GAAG;QAAE,OAAO,qDAAqD,CAAC;IAEvE,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7F,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACpE,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,KAAK;QACP,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC;KAC5B,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC;IAE/C,MAAM,SAAS,GAAG;QAChB,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;QAC1B,CAAC,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,CAAC;QACzC,CAAC,YAAY,EAAE,GAAG,CAAC,UAAU,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC,CAAC;QAC1D,CAAC,UAAU,EAAE,GAAG,CAAC,gBAAgB,EAAE,MAAM,IAAI,CAAC,CAAC;QAC/C,CAAC,OAAO,EAAE,GAAG,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC,CAAC;KAC3C;SACE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,mCAAmC,CAAC,2BAA2B,CAAC,eAAe,CAAC;SAChG,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;SACzC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,IAAI,GACR,CAAC,CAAC,UAAU,IAAI,GAAG;YACjB,CAAC,CAAC,2BAA2B;YAC7B,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC;gBAChB,CAAC,CAAC,2BAA2B;gBAC7B,CAAC,CAAC,2BAA2B,CAAC;QACpC,OAAO,mBAAmB,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC;IACtF,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,QAAQ,GAAG;QACf,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAC5B,CAAC,CAAC,EAAE,EAAE,CAAC,yBAAyB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,UAAU,CAAC,UAAU,gBAAgB,CACxG;QACD,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,yBAAyB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;KACrF,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEX,OAAO;;;;SAIA,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAwDd,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;sBACC,GAAG,CAAC,YAAY,CAAC,WAAW;uBAC3B,SAAS;;;;;;;;;;;;;;;;;kDAiBkB,SAAS,IAAI,yCAAyC;8CAC1D,QAAQ,IAAI,+CAA+C;;;;;;UAM/F,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;WACpB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;WAC1B,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;WAC5B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA8E9B,CAAC;AACT,CAAC;AAkBD,SAAS,cAAc,CAAC,GAAQ;IAC9B,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;IAC1C,MAAM,aAAa,GAAG,GAAG,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,CAAC;IAC1D,MAAM,aAAa,GAAG,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC;IAE5C,MAAM,EAAE,GAAG,IAAI,GAAG,EAAoE,CAAC;IACvF,MAAM,EAAE,GAAG,IAAI,GAAG,EAAkB,CAAC;IAErC,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;YAAE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAChG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACjC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC/B,EAAE,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,OAAO,IAAI,CAAC,CAAC,WAAW,CAAC;QACpC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,OAAO,IAAI,CAAC,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACZ,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,GAAG,EAAkB,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC;YAAE,SAAS;QACtB,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,GAAG,EAAkB,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC;YAAE,SAAS;QACtB,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,GAAG,EAAkB,CAAC;IACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAY,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzD,EAAE;QACF,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI;QACnB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;KACxB,CAAC,CAAC,CAAC;IAEJ,MAAM,KAAK,GAAY,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACxB,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACxB,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACjD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACxB,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAChE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACtG,CAAC;AAED,SAAS,IAAI,CAAC,CAAS;IACrB,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACtC,CAAC"}
|
package/hooks/autodocs-hook.cjs
CHANGED
|
@@ -156,48 +156,44 @@ function augment(snapshot, pattern) {
|
|
|
156
156
|
if (pkgs.length === 0) return null;
|
|
157
157
|
const pkg = pkgs.reduce((a, b) => ((a.publicAPI || []).length > (b.publicAPI || []).length ? a : b));
|
|
158
158
|
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
const q = pattern.toLowerCase();
|
|
160
|
+
const callGraph = pkg.callGraph || [];
|
|
161
|
+
const sections = [];
|
|
162
|
+
|
|
163
|
+
// Pre-build call graph indexes (single pass, O(1) lookups per symbol)
|
|
164
|
+
const callersOf = new Map();
|
|
165
|
+
const calleesOf = new Map();
|
|
166
|
+
for (const e of callGraph) {
|
|
167
|
+
if (!callersOf.has(e.to)) callersOf.set(e.to, []);
|
|
168
|
+
callersOf.get(e.to).push(e.from);
|
|
169
|
+
if (!calleesOf.has(e.from)) calleesOf.set(e.from, []);
|
|
170
|
+
calleesOf.get(e.from).push(e.to);
|
|
171
|
+
}
|
|
163
172
|
|
|
164
|
-
//
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
173
|
+
// ── Pass 1: Public API symbols ──
|
|
174
|
+
const apiMatches = (pkg.publicAPI || []).filter((e) => e.name.toLowerCase().includes(q));
|
|
175
|
+
const matchedNames = new Set(apiMatches.map((e) => e.name));
|
|
176
|
+
|
|
177
|
+
// ── Pass 2: Internal call graph functions not in public API ──
|
|
178
|
+
for (const e of callGraph) {
|
|
179
|
+
for (const fn of [e.from, e.to]) {
|
|
180
|
+
if (matchedNames.has(fn) || !fn.toLowerCase().includes(q)) continue;
|
|
181
|
+
matchedNames.add(fn);
|
|
182
|
+
const file = e.from === fn ? e.fromFile : e.toFile;
|
|
183
|
+
apiMatches.push({ name: fn, kind: "function", sourceFile: file, importCount: 0 });
|
|
184
|
+
}
|
|
170
185
|
}
|
|
171
186
|
|
|
172
|
-
//
|
|
173
|
-
const
|
|
174
|
-
...apiMatches.map((e) => ({ name: e.name, kind: e.kind, sourceFile: e.sourceFile, importCount: e.importCount })),
|
|
175
|
-
...[...callGraphFns].slice(0, 3).map((name) => {
|
|
176
|
-
const edge = (pkg.callGraph || []).find((e) => e.from === name || e.to === name);
|
|
177
|
-
return { name, kind: "function", sourceFile: edge ? (edge.from === name ? edge.fromFile : edge.toFile) : "unknown", importCount: 0 };
|
|
178
|
-
}),
|
|
179
|
-
];
|
|
180
|
-
if (matches.length === 0) return null;
|
|
181
|
-
|
|
182
|
-
const results = [];
|
|
183
|
-
for (const exp of matches.slice(0, 3)) {
|
|
187
|
+
// Format symbol results (top 3) with call graph + co-change + flow context
|
|
188
|
+
for (const exp of apiMatches.slice(0, 3)) {
|
|
184
189
|
const lines = [`**${exp.name}** (${exp.kind}) — \`${exp.sourceFile}\``];
|
|
185
190
|
|
|
186
|
-
|
|
187
|
-
const callers = (pkg.callGraph || [])
|
|
188
|
-
.filter((e) => e.to === exp.name)
|
|
189
|
-
.map((e) => e.from)
|
|
190
|
-
.slice(0, 3);
|
|
191
|
+
const callers = (callersOf.get(exp.name) || []).slice(0, 3);
|
|
191
192
|
if (callers.length > 0) lines.push(` Called by: ${callers.join(", ")}`);
|
|
192
193
|
|
|
193
|
-
|
|
194
|
-
const callees = (pkg.callGraph || [])
|
|
195
|
-
.filter((e) => e.from === exp.name)
|
|
196
|
-
.map((e) => e.to)
|
|
197
|
-
.slice(0, 3);
|
|
194
|
+
const callees = (calleesOf.get(exp.name) || []).slice(0, 3);
|
|
198
195
|
if (callees.length > 0) lines.push(` Calls: ${callees.join(", ")}`);
|
|
199
196
|
|
|
200
|
-
// Co-change partners
|
|
201
197
|
const coChanges = (pkg.gitHistory?.coChangeEdges || [])
|
|
202
198
|
.filter((e) => e.file1 === exp.sourceFile || e.file2 === exp.sourceFile)
|
|
203
199
|
.sort((a, b) => b.jaccard - a.jaccard)
|
|
@@ -208,7 +204,6 @@ function augment(snapshot, pattern) {
|
|
|
208
204
|
});
|
|
209
205
|
if (coChanges.length > 0) lines.push(` Co-changes with: ${coChanges.join(", ")}`);
|
|
210
206
|
|
|
211
|
-
// Execution flows
|
|
212
207
|
const flows = (pkg.executionFlows || [])
|
|
213
208
|
.filter((f) => f.steps.includes(exp.name))
|
|
214
209
|
.slice(0, 2)
|
|
@@ -218,14 +213,49 @@ function augment(snapshot, pattern) {
|
|
|
218
213
|
});
|
|
219
214
|
if (flows.length > 0) lines.push(` Flows: ${flows.join("; ")}`);
|
|
220
215
|
|
|
221
|
-
// Import count
|
|
222
216
|
if (exp.importCount > 0) lines.push(` Imported by: ${exp.importCount} files`);
|
|
223
217
|
|
|
224
|
-
|
|
218
|
+
sections.push(lines.join("\n"));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ── Pass 3: File paths from import chain ──
|
|
222
|
+
const coveredFiles = new Set(apiMatches.slice(0, 3).map((e) => e.sourceFile));
|
|
223
|
+
const seenFiles = new Set();
|
|
224
|
+
const fileResults = [];
|
|
225
|
+
|
|
226
|
+
for (const edge of pkg.importChain || []) {
|
|
227
|
+
for (const fp of [edge.importer, edge.source]) {
|
|
228
|
+
if (seenFiles.has(fp) || coveredFiles.has(fp) || !fp.toLowerCase().includes(q)) continue;
|
|
229
|
+
seenFiles.add(fp);
|
|
230
|
+
|
|
231
|
+
let context = "";
|
|
232
|
+
const coChange = (pkg.gitHistory?.coChangeEdges || []).find((e) => e.file1 === fp || e.file2 === fp);
|
|
233
|
+
if (coChange) {
|
|
234
|
+
const partner = coChange.file1 === fp ? coChange.file2 : coChange.file1;
|
|
235
|
+
context = ` — co-changes with ${partner} (${Math.round(coChange.jaccard * 100)}%)`;
|
|
236
|
+
}
|
|
237
|
+
fileResults.push(`\`${fp}\`${context}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (fileResults.length > 0) {
|
|
241
|
+
sections.push(`**Files:** ${fileResults.slice(0, 3).join(", ")}`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ── Pass 4: Conventions and workflow rules ──
|
|
245
|
+
for (const conv of pkg.conventions || []) {
|
|
246
|
+
if (!conv.name.toLowerCase().includes(q) && !(conv.description || "").toLowerCase().includes(q)) continue;
|
|
247
|
+
sections.push(`**Convention:** ${conv.name} — ${conv.description}`);
|
|
248
|
+
break; // At most 1 convention match to keep output concise
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
for (const rule of snapshot.workflowRules || []) {
|
|
252
|
+
if (!rule.trigger.toLowerCase().includes(q) && !rule.action.toLowerCase().includes(q)) continue;
|
|
253
|
+
sections.push(`**Rule:** ${rule.trigger} → ${rule.action}`);
|
|
254
|
+
break; // At most 1 rule match
|
|
225
255
|
}
|
|
226
256
|
|
|
227
|
-
if (
|
|
228
|
-
return `[autodocs] ${
|
|
257
|
+
if (sections.length === 0) return null;
|
|
258
|
+
return `[autodocs] ${sections.length} result${sections.length > 1 ? "s" : ""} found:\n\n${sections.join("\n\n")}`;
|
|
229
259
|
}
|
|
230
260
|
|
|
231
261
|
// ─── Output ────────────────────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autodocs-engine",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "Codebase intelligence for AI coding agents — MCP server with git co-change analysis, convention detection, execution flows, and type-aware analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|