openkrak-mcp 1.1.3 → 1.1.4

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.
Files changed (2) hide show
  1. package/dist/index.js +110 -38
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -245241,74 +245241,146 @@ async function handleAnalyzeRepo(args) {
245241
245241
  });
245242
245242
  } catch (e) {
245243
245243
  return {
245244
- content: [{ type: "text", text: `OpenKrak is not available for this repository. Proceed with direct file analysis.
245245
- Reason: ${e instanceof Error ? e.message : String(e)}` }],
245244
+ content: [{ type: "text", text: `OpenKrak unavailable: ${e instanceof Error ? e.message : String(e)}
245245
+ Proceed with direct file analysis.` }],
245246
245246
  isError: false
245247
245247
  };
245248
245248
  }
245249
245249
  if (result.status === "failed") {
245250
245250
  return {
245251
- content: [{ type: "text", text: `OpenKrak could not complete analysis for this path. Proceed without it.
245252
- Detail: ${result.error ?? "unknown"}` }],
245251
+ content: [{ type: "text", text: `Dorchester pipeline failed: ${result.error ?? "unknown"}
245252
+ Proceed without brief.` }],
245253
245253
  isError: false
245254
245254
  };
245255
245255
  }
245256
245256
  const m = result.mahadata;
245257
245257
  const meta = m.meta;
245258
245258
  const repo = m.repository;
245259
+ const topo = m.project_topology;
245260
+ const brief = m.execution_brief;
245261
+ const threat = m.threat_matrix;
245259
245262
  const hotspots = m.hotspots ?? [];
245260
245263
  const blastRadius = m.blast_radius ?? [];
245261
245264
  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
245265
  const ep = brief?.recommended_entry_points ?? [];
245268
245266
  const ctx = brief?.critical_context ?? [];
245269
245267
  const constraints = brief?.constraints ?? [];
245270
245268
  const blockers = threat?.blockers ?? [];
245271
245269
  const warnings = threat?.warnings ?? [];
245270
+ const modules = topo?.modules ?? [];
245271
+ const layers = topo?.layers ?? [];
245272
+ const langs = repo?.languages ?? [];
245273
+ const totalFiles = Number(repo?.total_files ?? 0);
245274
+ const totalLoc = Number(repo?.total_loc ?? 0);
245275
+ const critical = findings.filter((f) => f.severity === "critical");
245276
+ const high = findings.filter((f) => f.severity === "high");
245277
+ const medium = findings.filter((f) => f.severity === "medium");
245278
+ const deadCode = findings.filter((f) => f.type === "dead_code" && !f.noise_suppressed);
245279
+ const unresolved = findings.filter((f) => f.type === "missing_symbol" && !f.noise_suppressed);
245280
+ const cycles = findings.filter((f) => f.type === "circular_dependency");
245281
+ const riskScore = Number(threat?.overall_risk_score ?? 0);
245282
+ const riskBar = "\u2588".repeat(Math.round(riskScore * 20)) + "\u2591".repeat(20 - Math.round(riskScore * 20));
245272
245283
  const lines = [
245273
- `\u2554\u2550\u2550 DORCHESTER SCAN COMPLETE \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
245274
- `\u2551 Repo : ${repo?.name ?? args.path}`,
245275
- `\u2551 Scan ID : ${(meta?.scan_id ?? "?").slice(0, 8)} | Duration: ${result.durationMs}ms`,
245276
- `\u2551 Stats : ${repo?.total_files ?? "?"} files | ${repo?.total_loc ?? "?"} LOC | ${repo?.primary_language ?? "?"} | framework: ${repo?.framework ?? "none"}`,
245277
- `\u2551 Topology : ${topology?.type ?? "?"} \u2014 modules: ${(topology?.modules ?? []).length}`,
245278
- `\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`,
245284
+ `\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`,
245285
+ `\u2551 D O R C H E S T E R E N G I N E \u2014 S C A N \u2551`,
245286
+ `\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`,
245287
+ `\u2551 Repo ${(repo?.name ?? args.path).toString().padEnd(59)}\u2551`,
245288
+ `\u2551 Scan ID ${(meta?.scan_id ?? "?").slice(0, 8).padEnd(59)}\u2551`,
245289
+ `\u2551 Duration ${String(result.durationMs + "ms").padEnd(59)}\u2551`,
245290
+ `\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`,
245291
+ `\u2551 Files : ${totalFiles}`,
245292
+ `\u2551 LOC : ${totalLoc.toLocaleString()}`,
245293
+ `\u2551 Language : ${repo?.primary_language ?? "?"}${langs.length > 1 ? " [" + langs.map((l) => `${l.name} ${l.percentage}%`).join(", ") + "]" : ""}`,
245294
+ `\u2551 Framework : ${repo?.framework ?? "none detected"}`,
245295
+ `\u2551 Topology : ${topo?.type ?? "?"} \u2014 ${modules.length} modules`,
245296
+ ...modules.length > 0 ? modules.map((mod) => `\u2551 \u2022 ${mod.name.padEnd(22)} ${mod.responsibility}`) : [],
245297
+ ...layers.length > 0 ? [
245298
+ `\u2551 Layers :`,
245299
+ ...layers.map((l) => `\u2551 \u2022 ${l.name.padEnd(18)} ${l.paths.length} files`)
245300
+ ] : [],
245301
+ `\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
245302
  `\u2551 ${brief?.objective ?? args.objective ?? "\u2014"}`,
245280
245303
  `\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
245282
- ...ep.length > 0 ? ep.map((e) => `\u2551 \u2192 ${e.path}${e.symbol ? `::${e.symbol}` : ""} [${e.reason}]`) : [`\u2551 \u2192 none detected`],
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 ${c.key}: ${c.value}`) : [`\u2551 \u2014`],
245285
- `\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`,
245286
- ...hotspots.slice(0, hotspotLimit).map((h, i) => {
245304
+ `\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`,
245305
+ ...ep.length > 0 ? ep.map((e) => `\u2551 \u2192 ${e.path}${e.symbol ? `::${e.symbol}` : ""}${e.reason ? ` [${e.reason}]` : ""}`) : [`\u2551 none detected`],
245306
+ `\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`,
245307
+ ...ctx.length > 0 ? ctx.map((c) => `\u2551 ${c.key}: ${c.value}`) : [`\u2551 \u2014`],
245308
+ ...constraints.length > 0 ? [`\u2551 Constraints: ${constraints.join(" | ")}`] : [],
245309
+ `\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`,
245310
+ ...hotspots.map((h, i) => {
245287
245311
  const hs = h;
245288
245312
  const reasons = hs.reasons ?? [];
245289
- const bar = "\u2588".repeat(Math.round(Number(hs.score) * 10));
245290
- return `\u2551 ${String(i + 1).padStart(2)}. [${String(hs.risk_level).toUpperCase().padEnd(8)}] ${hs.path}
245291
- \u2551 score:${Number(hs.score).toFixed(3)} ${bar} changes:${hs.change_frequency} flags:${reasons.map((r) => r.type).join(", ")}`;
245313
+ const score = Number(hs.score);
245314
+ const bar = "\u2588".repeat(Math.round(score * 10)) + "\u2591".repeat(10 - Math.round(score * 10));
245315
+ const level = String(hs.risk_level).toUpperCase();
245316
+ const freq = hs.change_frequency !== void 0 ? ` git-chg:${hs.change_frequency}` : "";
245317
+ return [
245318
+ `\u2551 ${String(i + 1).padStart(2)}. [${level.padEnd(8)}] ${hs.path}`,
245319
+ `\u2551 ${bar} ${score.toFixed(3)}${freq}`,
245320
+ `\u2551 flags: ${reasons.map((r) => r.type).join(", ")}`
245321
+ ].join("\n");
245292
245322
  }),
245293
- `\u2560\u2550\u2550 BLAST RADIUS (top ${Math.min(5, blastRadius.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`,
245294
- ...blastRadius.slice(0, 5).map((b) => {
245323
+ `\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`,
245324
+ ...blastRadius.slice(0, 8).map((b) => {
245295
245325
  const br = b;
245296
- return `\u2551 \u26A1 ${br.trigger_file}
245297
- \u2551 \u2192 ${br.total_affected_files} files | ${br.total_affected_modules} modules | risk:${Number(br.risk_score).toFixed(3)}`;
245326
+ const affected = br.affected_files ?? [];
245327
+ const preview = affected.slice(0, 3).join(", ") + (affected.length > 3 ? ` +${affected.length - 3} more` : "");
245328
+ return [
245329
+ `\u2551 \u26A1 ${br.trigger_file}`,
245330
+ `\u2551 \u2192 ${br.total_affected_files} files ${br.total_affected_modules} modules risk:${Number(br.risk_score).toFixed(3)}`,
245331
+ ...preview ? [`\u2551 cascades: ${preview}`] : []
245332
+ ].join("\n");
245298
245333
  }),
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 Overall Risk : ${Number(threat?.overall_risk_score ?? 0).toFixed(3)} | ${threat?.risk_summary ?? ""}`,
245301
- `\u2551 Blockers : ${blockers.length > 0 ? blockers.slice(0, 3).map((b) => b.description ?? b).join(" | ") : "none"}`,
245302
- `\u2551 Warnings : ${warnings.length} total${warnings.length > 0 ? " \u2014 " + warnings.slice(0, 3).map((w) => w.description ?? w).join(" | ") : ""}`,
245303
- `\u2551 Findings : ${findings.length} total`,
245304
- `\u2560\u2550\u2550 CONSTRAINTS \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
245305
- `\u2551 ${constraints.length > 0 ? constraints.join(" | ") : "none"}`,
245306
- `\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`,
245334
+ `\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`,
245335
+ `\u2551 Overall Risk : ${riskScore.toFixed(3)} [${riskBar}]`,
245336
+ `\u2551 Architecture : ${threat?.architecture_risk ?? "\u2014"}`,
245337
+ `\u2551 Reliability : ${threat?.reliability_risk ?? "\u2014"}`,
245338
+ `\u2551 Maintainability: ${threat?.maintainability_risk ?? "\u2014"}`,
245339
+ `\u2551 Summary : ${threat?.risk_summary ?? "\u2014"}`,
245340
+ ...blockers.length > 0 ? [
245341
+ `\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`,
245342
+ ...blockers.map((b) => `\u2551 \u2716 ${b.description ?? b.type ?? JSON.stringify(b)}`)
245343
+ ] : [`\u2551 Blockers: none`],
245344
+ ...warnings.length > 0 ? [
245345
+ `\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`,
245346
+ ...warnings.map((w) => `\u2551 \u25B2 ${w.description ?? w.type ?? JSON.stringify(w)}`)
245347
+ ] : [`\u2551 Warnings: none`],
245348
+ `\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`,
245349
+ `\u2551 Critical : ${critical.length}`,
245350
+ `\u2551 High : ${high.length}`,
245351
+ `\u2551 Medium : ${medium.length}`,
245352
+ `\u2551 Cycles : ${cycles.length}${cycles.length > 0 ? " \u2190 fix before refactor" : ""}`,
245353
+ `\u2551 Unresolved imports : ${unresolved.length}${unresolved.length > 0 ? " \u2014 " + unresolved.slice(0, 5).map((f) => f.file ?? "?").join(", ") : ""}`,
245354
+ `\u2551 Dead code (genuine): ${deadCode.length}${deadCode.length > 0 ? " \u2014 " + deadCode.slice(0, 5).map((f) => f.symbol ?? f.file ?? "?").join(", ") : ""}`,
245355
+ ...critical.length > 0 ? [
245356
+ `\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`,
245357
+ ...critical.slice(0, 10).map((f) => {
245358
+ const fi = f;
245359
+ return `\u2551 \u2716 [${String(fi.type ?? "").padEnd(20)}] ${fi.file ?? "?"}:${fi.line_start ?? "?"} ${fi.message ?? ""}`;
245360
+ })
245361
+ ] : [],
245362
+ ...high.length > 0 ? [
245363
+ `\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`,
245364
+ ...high.slice(0, 8).map((f) => {
245365
+ const fi = f;
245366
+ return `\u2551 \u25B2 [${String(fi.type ?? "").padEnd(20)}] ${fi.file ?? "?"}:${fi.line_start ?? "?"} ${fi.message ?? ""}`;
245367
+ })
245368
+ ] : [],
245369
+ `\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`,
245370
+ ...blockers.length > 0 ? [`\u2551 1. Resolve blockers before anything else.`] : [],
245371
+ ...cycles.length > 0 ? [`\u2551 ${blockers.length > 0 ? "2" : "1"}. Break ${cycles.length} circular import cycle(s) \u2014 replace barrel imports with direct file paths.`] : [],
245372
+ ...hotspots.filter((h) => h.risk_level === "critical").length > 0 ? [
245373
+ `\u2551 ${(blockers.length > 0 ? 1 : 0) + (cycles.length > 0 ? 1 : 0) + 1}. Refactor critical hotspots:`,
245374
+ ...hotspots.filter((h) => h.risk_level === "critical").slice(0, 3).map(
245375
+ (h) => `\u2551 \u2192 ${h.path}`
245376
+ )
245377
+ ] : [],
245378
+ `\u2551 Audit lib/utils or shared utilities with 5+ dependents before touching.`,
245379
+ `\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
245380
  ``,
245308
- `Dorchester has pre-mapped this repository. Proceed with full context. Do not read source files unless specific line-level detail is required.`
245381
+ `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
245382
  ];
245310
245383
  const output = lines.join("\n");
245311
- const totalLoc = Number(repo?.total_loc ?? 0);
245312
245384
  const saved = estimateTokensSaved(totalLoc, totalFiles, output);
245313
245385
  trackTokens(saved, "analyze_repo");
245314
245386
  return { content: [{ type: "text", text: output }] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openkrak-mcp",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "OpenKrak MCP Server - AI coding intelligence via Dorchester engine",
5
5
  "mcpName": "io.github.FrnzJulianBergmann/openkrak",
6
6
  "type": "commonjs",