openkrak-mcp 1.0.18 → 1.1.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.
Files changed (2) hide show
  1. package/dist/index.js +229 -31
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -241629,13 +241629,63 @@ function createLogger(component) {
241629
241629
  process.stderr
241630
241630
  );
241631
241631
  }
241632
- var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"];
241632
+ var SUPPORTED_EXTENSIONS = [
241633
+ // JavaScript / TypeScript
241634
+ ".ts",
241635
+ ".tsx",
241636
+ ".js",
241637
+ ".jsx",
241638
+ // Python
241639
+ ".py",
241640
+ // Go
241641
+ ".go",
241642
+ // Rust
241643
+ ".rs",
241644
+ // Java
241645
+ ".java",
241646
+ // C#
241647
+ ".cs"
241648
+ ];
241649
+ var LANGUAGE_BY_EXT = {
241650
+ ".ts": "typescript",
241651
+ ".tsx": "typescript",
241652
+ ".js": "javascript",
241653
+ ".jsx": "javascript",
241654
+ ".py": "python",
241655
+ ".go": "go",
241656
+ ".rs": "rust",
241657
+ ".java": "java",
241658
+ ".cs": "csharp"
241659
+ };
241660
+ function isTypeScriptOrJS(filePath) {
241661
+ const ext2 = import_path.default.extname(filePath).toLowerCase();
241662
+ return [".ts", ".tsx", ".js", ".jsx"].includes(ext2);
241663
+ }
241633
241664
  async function discoverFiles(repoRoot) {
241634
241665
  const patterns = SUPPORTED_EXTENSIONS.map((ext2) => `**/*${ext2}`);
241635
241666
  const files = await glob(patterns, {
241636
241667
  cwd: repoRoot,
241637
241668
  absolute: false,
241638
- ignore: ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**", "**/*.d.ts"]
241669
+ ignore: [
241670
+ "**/node_modules/**",
241671
+ "**/dist/**",
241672
+ "**/build/**",
241673
+ "**/.git/**",
241674
+ "**/*.d.ts",
241675
+ // Python
241676
+ "**/__pycache__/**",
241677
+ "**/.venv/**",
241678
+ "**/venv/**",
241679
+ "**/*.pyc",
241680
+ // Go
241681
+ "**/vendor/**",
241682
+ // Rust
241683
+ "**/target/**",
241684
+ // Java / C#
241685
+ "**/bin/**",
241686
+ "**/obj/**",
241687
+ "**/.gradle/**"
241688
+ ]
241639
241689
  });
241640
241690
  return files.map((f) => f.replace(/\\/g, "/")).sort();
241641
241691
  }
@@ -242516,7 +242566,7 @@ function detectSecurityPatterns(filePath, content) {
242516
242566
  }
242517
242567
  async function classifyTopology(repoRoot, allFiles) {
242518
242568
  const type = await detectProjectType(repoRoot);
242519
- const framework = await detectFramework(repoRoot);
242569
+ const framework = await detectFramework(repoRoot, allFiles);
242520
242570
  const entryPoints = detectEntryPoints(allFiles);
242521
242571
  const layers = detectLayers(allFiles);
242522
242572
  const modules = detectModules(allFiles);
@@ -242539,9 +242589,8 @@ async function detectProjectType(repoRoot) {
242539
242589
  }
242540
242590
  return "monolith";
242541
242591
  }
242542
- async function detectFramework(repoRoot) {
242592
+ async function readFrameworkFromPkg(pkgPath) {
242543
242593
  try {
242544
- const pkgPath = import_path4.default.join(repoRoot, "package.json");
242545
242594
  const pkg = JSON.parse(await import_promises3.default.readFile(pkgPath, "utf-8"));
242546
242595
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
242547
242596
  if (deps["next"]) return `next@${deps["next"].replace(/[\^~]/g, "")}`;
@@ -242558,30 +242607,68 @@ async function detectFramework(repoRoot) {
242558
242607
  if (deps["@angular/core"]) return "angular";
242559
242608
  } catch {
242560
242609
  }
242561
- try {
242562
- await import_promises3.default.access(import_path4.default.join(repoRoot, "next.config.js"));
242563
- return "next";
242564
- } catch {
242565
- }
242566
- try {
242567
- await import_promises3.default.access(import_path4.default.join(repoRoot, "next.config.mjs"));
242568
- return "next";
242569
- } catch {
242610
+ return null;
242611
+ }
242612
+ async function findSubPackageRoots(repoRoot, allFiles) {
242613
+ const candidates = /* @__PURE__ */ new Set();
242614
+ for (const f of allFiles) {
242615
+ const parts = f.split("/");
242616
+ if (parts.length >= 1) candidates.add(parts[0]);
242617
+ if (parts.length >= 2) candidates.add(`${parts[0]}/${parts[1]}`);
242570
242618
  }
242571
- try {
242572
- await import_promises3.default.access(import_path4.default.join(repoRoot, "next.config.ts"));
242573
- return "next";
242574
- } catch {
242619
+ const roots = [];
242620
+ for (const candidate of candidates) {
242621
+ const pkgPath = import_path4.default.join(repoRoot, candidate, "package.json");
242622
+ try {
242623
+ await import_promises3.default.access(pkgPath);
242624
+ roots.push(candidate);
242625
+ } catch {
242626
+ }
242575
242627
  }
242576
- try {
242577
- await import_promises3.default.access(import_path4.default.join(repoRoot, "vite.config.ts"));
242578
- return "vite";
242579
- } catch {
242628
+ return roots;
242629
+ }
242630
+ async function detectFramework(repoRoot, allFiles) {
242631
+ const rootFramework = await readFrameworkFromPkg(import_path4.default.join(repoRoot, "package.json"));
242632
+ if (rootFramework) return rootFramework;
242633
+ const configChecks = [
242634
+ ["next.config.js", "next"],
242635
+ ["next.config.mjs", "next"],
242636
+ ["next.config.ts", "next"],
242637
+ ["vite.config.ts", "vite"],
242638
+ ["astro.config.mjs", "astro"]
242639
+ ];
242640
+ for (const [cfg, name] of configChecks) {
242641
+ try {
242642
+ await import_promises3.default.access(import_path4.default.join(repoRoot, cfg));
242643
+ return name;
242644
+ } catch {
242645
+ }
242580
242646
  }
242581
- try {
242582
- await import_promises3.default.access(import_path4.default.join(repoRoot, "astro.config.mjs"));
242583
- return "astro";
242584
- } catch {
242647
+ if (allFiles && allFiles.length > 0) {
242648
+ const subRoots = await findSubPackageRoots(repoRoot, allFiles);
242649
+ const detected = [];
242650
+ for (const subRoot of subRoots) {
242651
+ const fw = await readFrameworkFromPkg(import_path4.default.join(repoRoot, subRoot, "package.json"));
242652
+ if (fw && !detected.includes(fw)) detected.push(fw);
242653
+ }
242654
+ for (const subRoot of subRoots) {
242655
+ for (const [cfg, name] of configChecks) {
242656
+ try {
242657
+ await import_promises3.default.access(import_path4.default.join(repoRoot, subRoot, cfg));
242658
+ if (!detected.includes(name)) detected.push(name);
242659
+ } catch {
242660
+ }
242661
+ }
242662
+ }
242663
+ if (detected.length === 1) return detected[0];
242664
+ if (detected.length > 1) {
242665
+ const prefixCount = /* @__PURE__ */ new Map();
242666
+ for (const d of detected) {
242667
+ const prefix = d.split("@")[0];
242668
+ prefixCount.set(prefix, (prefixCount.get(prefix) ?? 0) + 1);
242669
+ }
242670
+ return [...prefixCount.entries()].map(([fw, count]) => count > 1 ? `${fw} (\xD7${count})` : fw).join(", ");
242671
+ }
242585
242672
  }
242586
242673
  return null;
242587
242674
  }
@@ -242593,11 +242680,15 @@ function detectEntryPoints(files) {
242593
242680
  entries.push({ path: f, type });
242594
242681
  continue;
242595
242682
  }
242596
- if (/^app\/.*page\.(ts|js)x?$/.test(f) || /^app\/layout\.(ts|js)x?$/.test(f)) {
242683
+ if (/(?:^|\/)app\/.*page\.(ts|js)x?$/.test(f) || /(?:^|\/)app\/layout\.(ts|js)x?$/.test(f)) {
242684
+ entries.push({ path: f, type: "api" });
242685
+ continue;
242686
+ }
242687
+ if (/(?:^|\/)app\/.*(?:loading|error|not-found)\.(ts|js)x?$/.test(f)) {
242597
242688
  entries.push({ path: f, type: "api" });
242598
242689
  continue;
242599
242690
  }
242600
- if (/^app\/.*route\.(ts|js)x?$/.test(f) || /^pages\/api\//.test(f)) {
242691
+ if (/(?:^|\/)app\/.*route\.(ts|js)x?$/.test(f) || /(?:^|\/)pages\/api\//.test(f)) {
242601
242692
  entries.push({ path: f, type: "api" });
242602
242693
  continue;
242603
242694
  }
@@ -242763,6 +242854,35 @@ function extractCyclomaticComplexity(ast, filePath) {
242763
242854
  return fileMetrics;
242764
242855
  }
242765
242856
  var logger = createLogger("deepstrike");
242857
+ function detectPrimaryLanguage(filePaths) {
242858
+ const counts = computeLanguageCounts(filePaths);
242859
+ let maxLang = "typescript";
242860
+ let maxCount = 0;
242861
+ for (const [lang, count] of Object.entries(counts)) {
242862
+ if (count > maxCount) {
242863
+ maxCount = count;
242864
+ maxLang = lang;
242865
+ }
242866
+ }
242867
+ return maxLang;
242868
+ }
242869
+ function computeLanguageBreakdown(filePaths) {
242870
+ const counts = computeLanguageCounts(filePaths);
242871
+ const total = filePaths.length || 1;
242872
+ return Object.entries(counts).map(([name, count]) => ({
242873
+ name,
242874
+ percentage: Math.round(count / total * 100)
242875
+ }));
242876
+ }
242877
+ function computeLanguageCounts(filePaths) {
242878
+ const counts = {};
242879
+ for (const fp of filePaths) {
242880
+ const ext2 = fp.slice(fp.lastIndexOf(".")).toLowerCase();
242881
+ const lang = LANGUAGE_BY_EXT[ext2] ?? "unknown";
242882
+ counts[lang] = (counts[lang] ?? 0) + 1;
242883
+ }
242884
+ return counts;
242885
+ }
242766
242886
  async function runDeepStrike(store, opts) {
242767
242887
  const start = Date.now();
242768
242888
  const scanId = store.getMeta().scan_id;
@@ -242808,7 +242928,7 @@ async function runDeepStrike(store, opts) {
242808
242928
  allFindings.push(...secFindings);
242809
242929
  try {
242810
242930
  const partialEntry = await buildFileIndexEntry(opts.repoRoot, relPath, content, symbols.length);
242811
- const cyclomaticByFunc = extractCyclomaticComplexity(ast, relPath);
242931
+ const cyclomaticByFunc = isTypeScriptOrJS(relPath) ? extractCyclomaticComplexity(parseFile(absPath, content, opts.repoRoot).ast, relPath) : /* @__PURE__ */ new Map();
242812
242932
  const entry = {
242813
242933
  ...partialEntry,
242814
242934
  complexity: {
@@ -242840,8 +242960,8 @@ async function runDeepStrike(store, opts) {
242840
242960
  name: repoName,
242841
242961
  path: opts.repoRoot,
242842
242962
  remote_url: null,
242843
- primary_language: "typescript",
242844
- languages: [{ name: "typescript", percentage: 100 }],
242963
+ primary_language: detectPrimaryLanguage(fileIndexEntries.map((e) => e.path)),
242964
+ languages: computeLanguageBreakdown(fileIndexEntries.map((e) => e.path)),
242845
242965
  framework: null,
242846
242966
  total_files: relFiles.length,
242847
242967
  total_loc: fileIndexEntries.reduce((s, e) => s + e.loc, 0),
@@ -243034,6 +243154,73 @@ function buildImpactChains(candidates) {
243034
243154
  function describeMechanism(root, related, depth) {
243035
243155
  return `${root.type} in ${root.file} propagates via ${depth} dependency hop(s) to ${related.type} in ${related.file}`;
243036
243156
  }
243157
+ var CROSS_BUNDLE_SAFE_EXPORTS = /* @__PURE__ */ new Set([
243158
+ // action_contracts
243159
+ "ActionType",
243160
+ "PlannedAction",
243161
+ "ShellCommandSpec",
243162
+ "TEST_COMMAND_WHITELIST",
243163
+ "SENSITIVE_KEY_RE",
243164
+ "DESTRUCTIVE_RE",
243165
+ // orchestrator / plan
243166
+ "OrchestratorPlan",
243167
+ "OrchestratorStep",
243168
+ // contracts / store
243169
+ "MahadataStore",
243170
+ "InMemoryMahadataStore",
243171
+ "Mahadata",
243172
+ "TokenCounter",
243173
+ "LLMClientConfig",
243174
+ // handlers exposed via MCP tool layer
243175
+ "handleAnalyzeRepo",
243176
+ "handleBlastRadius",
243177
+ "handleGetHotspots",
243178
+ "handleGetMahadata",
243179
+ // shared utilities
243180
+ "calculateRiskScore",
243181
+ "assembleGraph",
243182
+ "classifyTopology",
243183
+ "resolveTaskDependencies",
243184
+ // constants / prompts
243185
+ "SYSTEM_PROMPT",
243186
+ "JSON_TAG_RE",
243187
+ // Next.js / framework reserved exports — always safe
243188
+ "metadata",
243189
+ "nextConfig",
243190
+ "geistSans",
243191
+ "geistMono",
243192
+ "default"
243193
+ // default exports are always externally consumable
243194
+ ]);
243195
+ var SAFE_EXPORT_PREFIXES = [
243196
+ "handle",
243197
+ // MCP handlers
243198
+ "create",
243199
+ // factory functions
243200
+ "build",
243201
+ // builder functions
243202
+ "run"
243203
+ // runner functions exposed to orchestrator
243204
+ ];
243205
+ var CROSS_BUNDLE_BARREL_PATTERNS = [
243206
+ /\/contracts\/index\.ts$/,
243207
+ /\/action_contracts\/index\.ts$/,
243208
+ /\/action_layer\/index\.ts$/,
243209
+ /\/shared\/index\.ts$/,
243210
+ /\/shared\/logger\/index\.ts$/,
243211
+ /\/orchestrator\/index\.ts$/
243212
+ ];
243213
+ function isCrossBundleSafeSymbol(symbolName, filePath) {
243214
+ if (CROSS_BUNDLE_SAFE_EXPORTS.has(symbolName)) return true;
243215
+ for (const prefix of SAFE_EXPORT_PREFIXES) {
243216
+ if (symbolName.startsWith(prefix)) return true;
243217
+ }
243218
+ if (symbolName === "logger" || symbolName.startsWith("logger")) return true;
243219
+ for (const pattern of CROSS_BUNDLE_BARREL_PATTERNS) {
243220
+ if (pattern.test(filePath)) return true;
243221
+ }
243222
+ return false;
243223
+ }
243037
243224
  function tagNoise(findings, chains) {
243038
243225
  const suppressionReasons = /* @__PURE__ */ new Map();
243039
243226
  const severityOrder = {
@@ -243043,6 +243230,17 @@ function tagNoise(findings, chains) {
243043
243230
  low: 1,
243044
243231
  info: 0
243045
243232
  };
243233
+ for (const f of findings) {
243234
+ if (f.type !== "dead_code") continue;
243235
+ if (suppressionReasons.has(f.id)) continue;
243236
+ const symbolName = f.symbol ? f.symbol.split("::")[1] ?? f.symbol : "";
243237
+ if (isCrossBundleSafeSymbol(symbolName, f.file)) {
243238
+ suppressionReasons.set(
243239
+ f.id,
243240
+ `Cross-bundle false positive: '${symbolName}' is a known exported interface consumed outside this scan boundary.`
243241
+ );
243242
+ }
243243
+ }
243046
243244
  const groupedByFileType = /* @__PURE__ */ new Map();
243047
243245
  for (const f of findings) {
243048
243246
  const key = `${f.file}::${f.type}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openkrak-mcp",
3
- "version": "1.0.18",
3
+ "version": "1.1.0",
4
4
  "description": "OpenKrak MCP Server - AI coding intelligence via Dorchester engine",
5
5
  "mcpName": "io.github.FrnzJulianBergmann/openkrak",
6
6
  "type": "commonjs",