openkrak-mcp 1.1.3 → 1.1.5
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/dist/index.js +132 -52
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -242135,8 +242135,19 @@ function assembleGraph(allNodes, rawEdges, barrelReExports = []) {
|
|
|
242135
242135
|
edges.push(edge);
|
|
242136
242136
|
}
|
|
242137
242137
|
}
|
|
242138
|
+
const fileClassIndex = /* @__PURE__ */ new Map();
|
|
242139
|
+
const fileBarrelIndex = /* @__PURE__ */ new Map();
|
|
242140
|
+
for (const node of allNodes) {
|
|
242141
|
+
if (node.kind === "class") {
|
|
242142
|
+
const arr = fileClassIndex.get(node.file) ?? [];
|
|
242143
|
+
arr.push(node);
|
|
242144
|
+
fileClassIndex.set(node.file, arr);
|
|
242145
|
+
} else if (node.kind === "variable" && node.name === "default") {
|
|
242146
|
+
fileBarrelIndex.set(node.file, node);
|
|
242147
|
+
}
|
|
242148
|
+
}
|
|
242138
242149
|
for (const raw of rawEdges) {
|
|
242139
|
-
const resolvedTo = resolveToNodeId(raw.to, fileNodeMap, nodeById);
|
|
242150
|
+
const resolvedTo = resolveToNodeId(raw.to, fileNodeMap, nodeById, fileClassIndex, fileBarrelIndex);
|
|
242140
242151
|
const edgeId = `${raw.from}->${resolvedTo}:${raw.kind}`;
|
|
242141
242152
|
const edge = {
|
|
242142
242153
|
id: edgeId,
|
|
@@ -242254,21 +242265,18 @@ function assembleGraph(allNodes, rawEdges, barrelReExports = []) {
|
|
|
242254
242265
|
const stats = computeStats(allNodes, finalEdges);
|
|
242255
242266
|
return { nodes: allNodes, edges: finalEdges, stats };
|
|
242256
242267
|
}
|
|
242257
|
-
function resolveToNodeId(to, fileNodeMap,
|
|
242268
|
+
function resolveToNodeId(to, fileNodeMap, _nodeById, fileClassIndex, fileBarrelIndex) {
|
|
242258
242269
|
const fileNodeId = fileNodeMap.get(to) ?? fileNodeMap.get(to + ".ts") ?? fileNodeMap.get(to + ".tsx") ?? fileNodeMap.get(to.replace(/\.ts$/, ".tsx")) ?? fileNodeMap.get(to.replace(/\.tsx$/, ".ts")) ?? fileNodeMap.get(to + "/index.ts") ?? fileNodeMap.get(to + "/index.tsx");
|
|
242259
|
-
if (fileNodeId
|
|
242260
|
-
|
|
242261
|
-
|
|
242262
|
-
|
|
242263
|
-
|
|
242264
|
-
|
|
242265
|
-
|
|
242266
|
-
|
|
242267
|
-
);
|
|
242268
|
-
if (classNodes.length === 1) return classNodes[0].id;
|
|
242270
|
+
if (fileNodeId) {
|
|
242271
|
+
if (fileClassIndex && fileBarrelIndex) {
|
|
242272
|
+
const filePath = fileNodeId.split("::")[0];
|
|
242273
|
+
const barrelNode = fileBarrelIndex.get(filePath);
|
|
242274
|
+
if (barrelNode) return barrelNode.id;
|
|
242275
|
+
const classNodes = fileClassIndex.get(filePath) ?? [];
|
|
242276
|
+
if (classNodes.length === 1) return classNodes[0].id;
|
|
242277
|
+
}
|
|
242269
242278
|
return fileNodeId;
|
|
242270
242279
|
}
|
|
242271
|
-
if (fileNodeId) return fileNodeId;
|
|
242272
242280
|
return to;
|
|
242273
242281
|
}
|
|
242274
242282
|
function computeStats(nodes, edges) {
|
|
@@ -242928,7 +242936,7 @@ async function runDeepStrike(store, opts) {
|
|
|
242928
242936
|
allFindings.push(...secFindings);
|
|
242929
242937
|
try {
|
|
242930
242938
|
const partialEntry = await buildFileIndexEntry(opts.repoRoot, relPath, content, symbols.length);
|
|
242931
|
-
const cyclomaticByFunc = isTypeScriptOrJS(relPath) ? extractCyclomaticComplexity(
|
|
242939
|
+
const cyclomaticByFunc = isTypeScriptOrJS(relPath) ? extractCyclomaticComplexity(ast, relPath) : /* @__PURE__ */ new Map();
|
|
242932
242940
|
const entry = {
|
|
242933
242941
|
...partialEntry,
|
|
242934
242942
|
complexity: {
|
|
@@ -245241,74 +245249,146 @@ async function handleAnalyzeRepo(args) {
|
|
|
245241
245249
|
});
|
|
245242
245250
|
} catch (e) {
|
|
245243
245251
|
return {
|
|
245244
|
-
content: [{ type: "text", text: `OpenKrak
|
|
245245
|
-
|
|
245252
|
+
content: [{ type: "text", text: `OpenKrak unavailable: ${e instanceof Error ? e.message : String(e)}
|
|
245253
|
+
Proceed with direct file analysis.` }],
|
|
245246
245254
|
isError: false
|
|
245247
245255
|
};
|
|
245248
245256
|
}
|
|
245249
245257
|
if (result.status === "failed") {
|
|
245250
245258
|
return {
|
|
245251
|
-
content: [{ type: "text", text: `
|
|
245252
|
-
|
|
245259
|
+
content: [{ type: "text", text: `Dorchester pipeline failed: ${result.error ?? "unknown"}
|
|
245260
|
+
Proceed without brief.` }],
|
|
245253
245261
|
isError: false
|
|
245254
245262
|
};
|
|
245255
245263
|
}
|
|
245256
245264
|
const m = result.mahadata;
|
|
245257
245265
|
const meta = m.meta;
|
|
245258
245266
|
const repo = m.repository;
|
|
245267
|
+
const topo = m.project_topology;
|
|
245268
|
+
const brief = m.execution_brief;
|
|
245269
|
+
const threat = m.threat_matrix;
|
|
245259
245270
|
const hotspots = m.hotspots ?? [];
|
|
245260
245271
|
const blastRadius = m.blast_radius ?? [];
|
|
245261
245272
|
const findings = m.findings ?? [];
|
|
245262
|
-
const brief = m.execution_brief;
|
|
245263
|
-
const threat = m.threat_matrix;
|
|
245264
|
-
const topology = m.project_topology;
|
|
245265
|
-
const totalFiles = Number(repo?.total_files ?? 0);
|
|
245266
|
-
const hotspotLimit = totalFiles < 50 ? 5 : totalFiles < 200 ? 8 : 12;
|
|
245267
245273
|
const ep = brief?.recommended_entry_points ?? [];
|
|
245268
245274
|
const ctx = brief?.critical_context ?? [];
|
|
245269
245275
|
const constraints = brief?.constraints ?? [];
|
|
245270
245276
|
const blockers = threat?.blockers ?? [];
|
|
245271
245277
|
const warnings = threat?.warnings ?? [];
|
|
245278
|
+
const modules = topo?.modules ?? [];
|
|
245279
|
+
const layers = topo?.layers ?? [];
|
|
245280
|
+
const langs = repo?.languages ?? [];
|
|
245281
|
+
const totalFiles = Number(repo?.total_files ?? 0);
|
|
245282
|
+
const totalLoc = Number(repo?.total_loc ?? 0);
|
|
245283
|
+
const critical = findings.filter((f) => f.severity === "critical");
|
|
245284
|
+
const high = findings.filter((f) => f.severity === "high");
|
|
245285
|
+
const medium = findings.filter((f) => f.severity === "medium");
|
|
245286
|
+
const deadCode = findings.filter((f) => f.type === "dead_code" && !f.noise_suppressed);
|
|
245287
|
+
const unresolved = findings.filter((f) => f.type === "missing_symbol" && !f.noise_suppressed);
|
|
245288
|
+
const cycles = findings.filter((f) => f.type === "circular_dependency");
|
|
245289
|
+
const riskScore = Number(threat?.overall_risk_score ?? 0);
|
|
245290
|
+
const riskBar = "\u2588".repeat(Math.round(riskScore * 20)) + "\u2591".repeat(20 - Math.round(riskScore * 20));
|
|
245272
245291
|
const lines = [
|
|
245273
|
-
`\u2554\u2550\u2550
|
|
245274
|
-
`\u2551
|
|
245275
|
-
`\
|
|
245276
|
-
`\u2551
|
|
245277
|
-
`\u2551
|
|
245278
|
-
`\
|
|
245292
|
+
`\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`,
|
|
245293
|
+
`\u2551 D O R C H E S T E R E N G I N E \u2014 S C A N \u2551`,
|
|
245294
|
+
`\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245295
|
+
`\u2551 Repo ${(repo?.name ?? args.path).toString().padEnd(59)}\u2551`,
|
|
245296
|
+
`\u2551 Scan ID ${(meta?.scan_id ?? "?").slice(0, 8).padEnd(59)}\u2551`,
|
|
245297
|
+
`\u2551 Duration ${String(result.durationMs + "ms").padEnd(59)}\u2551`,
|
|
245298
|
+
`\u2560\u2550\u2550 REPOSITORY \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245299
|
+
`\u2551 Files : ${totalFiles}`,
|
|
245300
|
+
`\u2551 LOC : ${totalLoc.toLocaleString()}`,
|
|
245301
|
+
`\u2551 Language : ${repo?.primary_language ?? "?"}${langs.length > 1 ? " [" + langs.map((l) => `${l.name} ${l.percentage}%`).join(", ") + "]" : ""}`,
|
|
245302
|
+
`\u2551 Framework : ${repo?.framework ?? "none detected"}`,
|
|
245303
|
+
`\u2551 Topology : ${topo?.type ?? "?"} \u2014 ${modules.length} modules`,
|
|
245304
|
+
...modules.length > 0 ? modules.map((mod) => `\u2551 \u2022 ${mod.name.padEnd(22)} ${mod.responsibility}`) : [],
|
|
245305
|
+
...layers.length > 0 ? [
|
|
245306
|
+
`\u2551 Layers :`,
|
|
245307
|
+
...layers.map((l) => `\u2551 \u2022 ${l.name.padEnd(18)} ${l.paths.length} files`)
|
|
245308
|
+
] : [],
|
|
245309
|
+
`\u2560\u2550\u2550 OBJECTIVE \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245279
245310
|
`\u2551 ${brief?.objective ?? args.objective ?? "\u2014"}`,
|
|
245280
245311
|
`\u2551 ${brief?.repository_summary ?? ""}`,
|
|
245281
|
-
`\u2560\u2550\u2550 ENTRY POINTS \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\
|
|
245282
|
-
...ep.length > 0 ? ep.map((e) => `\u2551
|
|
245283
|
-
`\u2560\u2550\u2550 CRITICAL CONTEXT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
|
|
245284
|
-
...ctx.length > 0 ? ctx.map((c) => `\u2551
|
|
245285
|
-
|
|
245286
|
-
|
|
245312
|
+
`\u2560\u2550\u2550 ENTRY POINTS (${ep.length}) \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245313
|
+
...ep.length > 0 ? ep.map((e) => `\u2551 \u2192 ${e.path}${e.symbol ? `::${e.symbol}` : ""}${e.reason ? ` [${e.reason}]` : ""}`) : [`\u2551 none detected`],
|
|
245314
|
+
`\u2560\u2550\u2550 CRITICAL CONTEXT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245315
|
+
...ctx.length > 0 ? ctx.map((c) => `\u2551 ${c.key}: ${c.value}`) : [`\u2551 \u2014`],
|
|
245316
|
+
...constraints.length > 0 ? [`\u2551 Constraints: ${constraints.join(" | ")}`] : [],
|
|
245317
|
+
`\u2560\u2550\u2550 HOTSPOT REGISTRY (${hotspots.length} files ranked) \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245318
|
+
...hotspots.map((h, i) => {
|
|
245287
245319
|
const hs = h;
|
|
245288
245320
|
const reasons = hs.reasons ?? [];
|
|
245289
|
-
const
|
|
245290
|
-
|
|
245291
|
-
|
|
245321
|
+
const score = Number(hs.score);
|
|
245322
|
+
const bar = "\u2588".repeat(Math.round(score * 10)) + "\u2591".repeat(10 - Math.round(score * 10));
|
|
245323
|
+
const level = String(hs.risk_level).toUpperCase();
|
|
245324
|
+
const freq = hs.change_frequency !== void 0 ? ` git-chg:${hs.change_frequency}` : "";
|
|
245325
|
+
return [
|
|
245326
|
+
`\u2551 ${String(i + 1).padStart(2)}. [${level.padEnd(8)}] ${hs.path}`,
|
|
245327
|
+
`\u2551 ${bar} ${score.toFixed(3)}${freq}`,
|
|
245328
|
+
`\u2551 flags: ${reasons.map((r) => r.type).join(", ")}`
|
|
245329
|
+
].join("\n");
|
|
245292
245330
|
}),
|
|
245293
|
-
`\u2560\u2550\u2550 BLAST RADIUS (top ${Math.min(
|
|
245294
|
-
...blastRadius.slice(0,
|
|
245331
|
+
`\u2560\u2550\u2550 BLAST RADIUS (top ${Math.min(blastRadius.length, 8)}) \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245332
|
+
...blastRadius.slice(0, 8).map((b) => {
|
|
245295
245333
|
const br = b;
|
|
245296
|
-
|
|
245297
|
-
|
|
245334
|
+
const affected = br.affected_files ?? [];
|
|
245335
|
+
const preview = affected.slice(0, 3).join(", ") + (affected.length > 3 ? ` +${affected.length - 3} more` : "");
|
|
245336
|
+
return [
|
|
245337
|
+
`\u2551 \u26A1 ${br.trigger_file}`,
|
|
245338
|
+
`\u2551 \u2192 ${br.total_affected_files} files ${br.total_affected_modules} modules risk:${Number(br.risk_score).toFixed(3)}`,
|
|
245339
|
+
...preview ? [`\u2551 cascades: ${preview}`] : []
|
|
245340
|
+
].join("\n");
|
|
245298
245341
|
}),
|
|
245299
|
-
`\u2560\u2550\u2550 THREAT MATRIX \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
|
|
245300
|
-
`\u2551
|
|
245301
|
-
`\u2551
|
|
245302
|
-
`\u2551
|
|
245303
|
-
`\u2551
|
|
245304
|
-
`\
|
|
245305
|
-
|
|
245306
|
-
|
|
245342
|
+
`\u2560\u2550\u2550 THREAT MATRIX \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245343
|
+
`\u2551 Overall Risk : ${riskScore.toFixed(3)} [${riskBar}]`,
|
|
245344
|
+
`\u2551 Architecture : ${threat?.architecture_risk ?? "\u2014"}`,
|
|
245345
|
+
`\u2551 Reliability : ${threat?.reliability_risk ?? "\u2014"}`,
|
|
245346
|
+
`\u2551 Maintainability: ${threat?.maintainability_risk ?? "\u2014"}`,
|
|
245347
|
+
`\u2551 Summary : ${threat?.risk_summary ?? "\u2014"}`,
|
|
245348
|
+
...blockers.length > 0 ? [
|
|
245349
|
+
`\u2551 \u2500\u2500 Blockers (${blockers.length}) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
245350
|
+
...blockers.map((b) => `\u2551 \u2716 ${b.description ?? b.type ?? JSON.stringify(b)}`)
|
|
245351
|
+
] : [`\u2551 Blockers: none`],
|
|
245352
|
+
...warnings.length > 0 ? [
|
|
245353
|
+
`\u2551 \u2500\u2500 Warnings (${warnings.length}) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
245354
|
+
...warnings.map((w) => `\u2551 \u25B2 ${w.description ?? w.type ?? JSON.stringify(w)}`)
|
|
245355
|
+
] : [`\u2551 Warnings: none`],
|
|
245356
|
+
`\u2560\u2550\u2550 FINDINGS BREAKDOWN (${findings.length} total) \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245357
|
+
`\u2551 Critical : ${critical.length}`,
|
|
245358
|
+
`\u2551 High : ${high.length}`,
|
|
245359
|
+
`\u2551 Medium : ${medium.length}`,
|
|
245360
|
+
`\u2551 Cycles : ${cycles.length}${cycles.length > 0 ? " \u2190 fix before refactor" : ""}`,
|
|
245361
|
+
`\u2551 Unresolved imports : ${unresolved.length}${unresolved.length > 0 ? " \u2014 " + unresolved.slice(0, 5).map((f) => f.file ?? "?").join(", ") : ""}`,
|
|
245362
|
+
`\u2551 Dead code (genuine): ${deadCode.length}${deadCode.length > 0 ? " \u2014 " + deadCode.slice(0, 5).map((f) => f.symbol ?? f.file ?? "?").join(", ") : ""}`,
|
|
245363
|
+
...critical.length > 0 ? [
|
|
245364
|
+
`\u2551 \u2500\u2500 Critical findings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
245365
|
+
...critical.slice(0, 10).map((f) => {
|
|
245366
|
+
const fi = f;
|
|
245367
|
+
return `\u2551 \u2716 [${String(fi.type ?? "").padEnd(20)}] ${fi.file ?? "?"}:${fi.line_start ?? "?"} ${fi.message ?? ""}`;
|
|
245368
|
+
})
|
|
245369
|
+
] : [],
|
|
245370
|
+
...high.length > 0 ? [
|
|
245371
|
+
`\u2551 \u2500\u2500 High findings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
245372
|
+
...high.slice(0, 8).map((f) => {
|
|
245373
|
+
const fi = f;
|
|
245374
|
+
return `\u2551 \u25B2 [${String(fi.type ?? "").padEnd(20)}] ${fi.file ?? "?"}:${fi.line_start ?? "?"} ${fi.message ?? ""}`;
|
|
245375
|
+
})
|
|
245376
|
+
] : [],
|
|
245377
|
+
`\u2560\u2550\u2550 WHAT TO DO \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`,
|
|
245378
|
+
...blockers.length > 0 ? [`\u2551 1. Resolve blockers before anything else.`] : [],
|
|
245379
|
+
...cycles.length > 0 ? [`\u2551 ${blockers.length > 0 ? "2" : "1"}. Break ${cycles.length} circular import cycle(s) \u2014 replace barrel imports with direct file paths.`] : [],
|
|
245380
|
+
...hotspots.filter((h) => h.risk_level === "critical").length > 0 ? [
|
|
245381
|
+
`\u2551 ${(blockers.length > 0 ? 1 : 0) + (cycles.length > 0 ? 1 : 0) + 1}. Refactor critical hotspots:`,
|
|
245382
|
+
...hotspots.filter((h) => h.risk_level === "critical").slice(0, 3).map(
|
|
245383
|
+
(h) => `\u2551 \u2192 ${h.path}`
|
|
245384
|
+
)
|
|
245385
|
+
] : [],
|
|
245386
|
+
`\u2551 Audit lib/utils or shared utilities with 5+ dependents before touching.`,
|
|
245387
|
+
`\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`,
|
|
245307
245388
|
``,
|
|
245308
|
-
`Dorchester
|
|
245389
|
+
`Dorchester pre-mapped this repository in ${result.durationMs}ms. Proceed from this brief. Do not read source files unless specific line-level detail is required by the user.`
|
|
245309
245390
|
];
|
|
245310
245391
|
const output = lines.join("\n");
|
|
245311
|
-
const totalLoc = Number(repo?.total_loc ?? 0);
|
|
245312
245392
|
const saved = estimateTokensSaved(totalLoc, totalFiles, output);
|
|
245313
245393
|
trackTokens(saved, "analyze_repo");
|
|
245314
245394
|
return { content: [{ type: "text", text: output }] };
|