@getmikk/mcp-server 1.9.1 → 1.9.2

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.cjs CHANGED
@@ -15394,7 +15394,7 @@ ${lanes.join("\n")}
15394
15394
  writeOutputIsTTY() {
15395
15395
  return process.stdout.isTTY;
15396
15396
  },
15397
- readFile: readFile7,
15397
+ readFile: readFile6,
15398
15398
  writeFile: writeFile22,
15399
15399
  watchFile: watchFile2,
15400
15400
  watchDirectory,
@@ -15600,7 +15600,7 @@ ${lanes.join("\n")}
15600
15600
  callback
15601
15601
  );
15602
15602
  }
15603
- function readFile7(fileName, _encoding) {
15603
+ function readFile6(fileName, _encoding) {
15604
15604
  let buffer;
15605
15605
  try {
15606
15606
  buffer = _fs.readFileSync(fileName);
@@ -52040,7 +52040,7 @@ ${lanes.join("\n")}
52040
52040
  const possibleOption = getSpellingSuggestion(unknownOption, diagnostics.optionDeclarations, getOptionName);
52041
52041
  return possibleOption ? createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) : createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption);
52042
52042
  }
52043
- function parseCommandLineWorker(diagnostics, commandLine, readFile7) {
52043
+ function parseCommandLineWorker(diagnostics, commandLine, readFile6) {
52044
52044
  const options = {};
52045
52045
  let watchOptions;
52046
52046
  const fileNames = [];
@@ -52088,7 +52088,7 @@ ${lanes.join("\n")}
52088
52088
  }
52089
52089
  }
52090
52090
  function parseResponseFile(fileName) {
52091
- const text = tryReadFile(fileName, readFile7 || ((fileName2) => sys.readFile(fileName2)));
52091
+ const text = tryReadFile(fileName, readFile6 || ((fileName2) => sys.readFile(fileName2)));
52092
52092
  if (!isString(text)) {
52093
52093
  errors.push(text);
52094
52094
  return;
@@ -52190,8 +52190,8 @@ ${lanes.join("\n")}
52190
52190
  unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1,
52191
52191
  optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument
52192
52192
  };
52193
- function parseCommandLine(commandLine, readFile7) {
52194
- return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile7);
52193
+ function parseCommandLine(commandLine, readFile6) {
52194
+ return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile6);
52195
52195
  }
52196
52196
  function getOptionFromName(optionName, allowShort) {
52197
52197
  return getOptionDeclarationFromName(getOptionsNameMap, optionName, allowShort);
@@ -52273,8 +52273,8 @@ ${lanes.join("\n")}
52273
52273
  watchOptionsToExtend
52274
52274
  );
52275
52275
  }
52276
- function readConfigFile(fileName, readFile7) {
52277
- const textOrDiagnostic = tryReadFile(fileName, readFile7);
52276
+ function readConfigFile(fileName, readFile6) {
52277
+ const textOrDiagnostic = tryReadFile(fileName, readFile6);
52278
52278
  return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic };
52279
52279
  }
52280
52280
  function parseConfigFileTextToJson(fileName, jsonText) {
@@ -52289,14 +52289,14 @@ ${lanes.join("\n")}
52289
52289
  error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : void 0
52290
52290
  };
52291
52291
  }
52292
- function readJsonConfigFile(fileName, readFile7) {
52293
- const textOrDiagnostic = tryReadFile(fileName, readFile7);
52292
+ function readJsonConfigFile(fileName, readFile6) {
52293
+ const textOrDiagnostic = tryReadFile(fileName, readFile6);
52294
52294
  return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : { fileName, parseDiagnostics: [textOrDiagnostic] };
52295
52295
  }
52296
- function tryReadFile(fileName, readFile7) {
52296
+ function tryReadFile(fileName, readFile6) {
52297
52297
  let text;
52298
52298
  try {
52299
- text = readFile7(fileName);
52299
+ text = readFile6(fileName);
52300
52300
  } catch (e) {
52301
52301
  return createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message);
52302
52302
  }
@@ -141824,12 +141824,12 @@ ${lanes.join("\n")}
141824
141824
  function createCompilerHost(options, setParentNodes) {
141825
141825
  return createCompilerHostWorker(options, setParentNodes);
141826
141826
  }
141827
- function createGetSourceFile(readFile7, setParentNodes) {
141827
+ function createGetSourceFile(readFile6, setParentNodes) {
141828
141828
  return (fileName, languageVersionOrOptions, onError) => {
141829
141829
  let text;
141830
141830
  try {
141831
141831
  mark("beforeIORead");
141832
- text = readFile7(fileName);
141832
+ text = readFile6(fileName);
141833
141833
  mark("afterIORead");
141834
141834
  measure("I/O Read", "beforeIORead", "afterIORead");
141835
141835
  } catch (e) {
@@ -142733,7 +142733,7 @@ ${lanes.join("\n")}
142733
142733
  getRedirectFromOutput,
142734
142734
  forEachResolvedProjectReference: forEachResolvedProjectReference2
142735
142735
  });
142736
- const readFile7 = host.readFile.bind(host);
142736
+ const readFile6 = host.readFile.bind(host);
142737
142737
  (_e = tracing) == null ? void 0 : _e.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram });
142738
142738
  const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
142739
142739
  (_f = tracing) == null ? void 0 : _f.pop();
@@ -142959,7 +142959,7 @@ ${lanes.join("\n")}
142959
142959
  shouldTransformImportCall,
142960
142960
  emitBuildInfo,
142961
142961
  fileExists: fileExists2,
142962
- readFile: readFile7,
142962
+ readFile: readFile6,
142963
142963
  directoryExists,
142964
142964
  getSymlinkCache,
142965
142965
  realpath: (_o = host.realpath) == null ? void 0 : _o.bind(host),
@@ -236933,7 +236933,8 @@ var ImpactAnalyzer = class {
236933
236933
  analyze(changedNodeIds) {
236934
236934
  const visited = /* @__PURE__ */ new Set();
236935
236935
  const depthMap = /* @__PURE__ */ new Map();
236936
- const queue = changedNodeIds.map((id) => ({ id, depth: 0 }));
236936
+ const pathConfidence = /* @__PURE__ */ new Map();
236937
+ const queue = changedNodeIds.map((id) => ({ id, depth: 0, confidence: 1 }));
236937
236938
  let maxDepth = 0;
236938
236939
  const changedSet = new Set(changedNodeIds);
236939
236940
  const changedModules = /* @__PURE__ */ new Set();
@@ -236943,16 +236944,19 @@ var ImpactAnalyzer = class {
236943
236944
  changedModules.add(node.moduleId);
236944
236945
  }
236945
236946
  while (queue.length > 0) {
236946
- const { id: current, depth } = queue.shift();
236947
+ const { id: current, depth, confidence: pathConf } = queue.shift();
236947
236948
  if (visited.has(current))
236948
236949
  continue;
236949
236950
  visited.add(current);
236950
236951
  depthMap.set(current, depth);
236952
+ pathConfidence.set(current, pathConf);
236951
236953
  maxDepth = Math.max(maxDepth, depth);
236952
236954
  const dependents = this.graph.inEdges.get(current) || [];
236953
236955
  for (const edge of dependents) {
236954
236956
  if (!visited.has(edge.source) && edge.type !== "contains") {
236955
- queue.push({ id: edge.source, depth: depth + 1 });
236957
+ const edgeConf = edge.confidence ?? 1;
236958
+ const newPathConf = Math.min(pathConf, edgeConf);
236959
+ queue.push({ id: edge.source, depth: depth + 1, confidence: newPathConf });
236956
236960
  }
236957
236961
  }
236958
236962
  }
@@ -236984,19 +236988,33 @@ var ImpactAnalyzer = class {
236984
236988
  changed: changedNodeIds,
236985
236989
  impacted,
236986
236990
  depth: maxDepth,
236987
- confidence: this.computeConfidence(impacted.length, maxDepth),
236991
+ confidence: this.computeConfidence(impacted, pathConfidence),
236988
236992
  classified
236989
236993
  };
236990
236994
  }
236991
236995
  /**
236992
- * How confident are we in this impact analysis?
236993
- * High = few nodes affected, shallow depth
236994
- * Low = many nodes affected, deep chains
236996
+ * Derive confidence from the actual quality of edges traversed, not from
236997
+ * result size. A small result built from fuzzy/unresolved edges is LOW
236998
+ * confidence; a large result built from high-confidence AST edges is HIGH.
236999
+ *
237000
+ * Algorithm:
237001
+ * - Compute the average minimum-path-confidence across all impacted nodes.
237002
+ * - Penalise for deep chains (they amplify uncertainty).
237003
+ * - Map the combined score to HIGH / MEDIUM / LOW.
236995
237004
  */
236996
- computeConfidence(impactedCount, depth) {
236997
- if (impactedCount < 5 && depth < 3)
237005
+ computeConfidence(impacted, pathConfidence) {
237006
+ if (impacted.length === 0)
237007
+ return "high";
237008
+ let total = 0;
237009
+ for (const id of impacted) {
237010
+ total += pathConfidence.get(id) ?? 1;
237011
+ }
237012
+ const avgConf = total / impacted.length;
237013
+ const sizePenalty = impacted.length > 20 ? 0.15 : impacted.length > 10 ? 0.08 : 0;
237014
+ const score = avgConf - sizePenalty;
237015
+ if (score >= 0.75)
236998
237016
  return "high";
236999
- if (impactedCount < 20 && depth < 6)
237017
+ if (score >= 0.5)
237000
237018
  return "medium";
237001
237019
  return "low";
237002
237020
  }
@@ -237007,7 +237025,6 @@ var ENTRY_POINT_PATTERNS = [
237007
237025
  /^(main|bootstrap|start|init|setup|configure|register|mount)$/i,
237008
237026
  /^(app|server|index|mod|program)$/i,
237009
237027
  /Handler$/i,
237010
- // Express/Koa/Hono handlers
237011
237028
  /Middleware$/i,
237012
237029
  /Controller$/i,
237013
237030
  /^use[A-Z]/,
@@ -237023,14 +237040,26 @@ var TEST_PATTERNS = [
237023
237040
  /\.spec\./,
237024
237041
  /__test__/
237025
237042
  ];
237043
+ var DYNAMIC_USAGE_PATTERNS = [
237044
+ /^addEventListener$/i,
237045
+ /^removeEventListener$/i,
237046
+ /^on[A-Z]/,
237047
+ /(invoke|dispatch|emit|call|apply)/i,
237048
+ /^ngOnInit$/i,
237049
+ /^componentDidMount$/i,
237050
+ /^componentWillUnmount$/i
237051
+ ];
237026
237052
  var DeadCodeDetector = class {
237027
237053
  graph;
237028
237054
  lock;
237029
237055
  routeHandlers;
237056
+ /** Files that have at least one unresolved import (empty resolvedPath) */
237057
+ filesWithUnresolvedImports;
237030
237058
  constructor(graph, lock) {
237031
237059
  this.graph = graph;
237032
237060
  this.lock = lock;
237033
237061
  this.routeHandlers = new Set((lock.routes ?? []).map((r) => r.handler).filter(Boolean));
237062
+ this.filesWithUnresolvedImports = this.buildUnresolvedImportFileSet();
237034
237063
  }
237035
237064
  detect() {
237036
237065
  const dead = [];
@@ -237049,13 +237078,15 @@ var DeadCodeDetector = class {
237049
237078
  continue;
237050
237079
  if (this.isExempt(fn, id))
237051
237080
  continue;
237081
+ const confidence = this.inferConfidence(fn);
237052
237082
  const entry = {
237053
237083
  id,
237054
237084
  name: fn.name,
237055
237085
  file: fn.file,
237056
237086
  moduleId,
237057
237087
  type: "function",
237058
- reason: this.inferReason(fn, id)
237088
+ reason: this.inferReason(fn),
237089
+ confidence
237059
237090
  };
237060
237091
  dead.push(entry);
237061
237092
  byModule[moduleId].dead++;
@@ -237069,9 +237100,7 @@ var DeadCodeDetector = class {
237069
237100
  }
237070
237101
  const inEdges = this.graph.inEdges.get(id) || [];
237071
237102
  const hasCallers = inEdges.some((e) => e.type === "calls" || e.type === "imports");
237072
- if (hasCallers)
237073
- continue;
237074
- if (cls.isExported)
237103
+ if (hasCallers || cls.isExported)
237075
237104
  continue;
237076
237105
  const entry = {
237077
237106
  id,
@@ -237079,7 +237108,8 @@ var DeadCodeDetector = class {
237079
237108
  file: cls.file,
237080
237109
  moduleId,
237081
237110
  type: "class",
237082
- reason: "Class has no callers or importers and is not exported"
237111
+ reason: "Class has no callers or importers and is not exported",
237112
+ confidence: this.filesWithUnresolvedImports.has(cls.file) ? "medium" : "high"
237083
237113
  };
237084
237114
  dead.push(entry);
237085
237115
  byModule[moduleId].dead++;
@@ -237094,7 +237124,7 @@ var DeadCodeDetector = class {
237094
237124
  byModule
237095
237125
  };
237096
237126
  }
237097
- // ─── Exemption checks ──────────────────────────────────────────
237127
+ // ─── Private helpers ───────────────────────────────────────────
237098
237128
  isExempt(fn, id) {
237099
237129
  if (fn.isExported)
237100
237130
  return true;
@@ -237106,24 +237136,66 @@ var DeadCodeDetector = class {
237106
237136
  return true;
237107
237137
  if (fn.name === "constructor" || fn.name === "__init__")
237108
237138
  return true;
237109
- if (this.isCalledByExportedInSameFile(fn, id))
237139
+ if (this.isCalledByExportedInSameFile(fn))
237110
237140
  return true;
237111
237141
  return false;
237112
237142
  }
237113
- isCalledByExportedInSameFile(fn, fnId) {
237143
+ isCalledByExportedInSameFile(fn) {
237114
237144
  for (const callerId of fn.calledBy) {
237115
237145
  const caller = this.lock.functions[callerId];
237116
- if (caller && caller.isExported && caller.file === fn.file) {
237146
+ if (caller && caller.isExported && caller.file === fn.file)
237117
237147
  return true;
237118
- }
237119
237148
  }
237120
237149
  return false;
237121
237150
  }
237122
- inferReason(fn, id) {
237151
+ /**
237152
+ * Assign a confidence level to a dead code finding.
237153
+ *
237154
+ * Priority (first match wins):
237155
+ * medium — lock.calledBy has entries that didn't become graph edges:
237156
+ * something references this function but resolution failed.
237157
+ * medium — file has unresolved imports: the graph may be incomplete.
237158
+ * low — function name matches common dynamic-dispatch patterns.
237159
+ * high — none of the above: safe to remove.
237160
+ */
237161
+ inferConfidence(fn) {
237162
+ if (fn.calledBy.length > 0)
237163
+ return "medium";
237164
+ if (this.filesWithUnresolvedImports.has(fn.file))
237165
+ return "medium";
237166
+ if (DYNAMIC_USAGE_PATTERNS.some((p) => p.test(fn.name)))
237167
+ return "low";
237168
+ return "high";
237169
+ }
237170
+ inferReason(fn) {
237123
237171
  if (fn.calledBy.length === 0) {
237124
237172
  return "No callers found anywhere in the codebase";
237125
237173
  }
237126
- return `${fn.calledBy.length} references exist but none resolved to active call edges`;
237174
+ return `${fn.calledBy.length} reference(s) in lock but none resolved to active call edges`;
237175
+ }
237176
+ /**
237177
+ * Build the set of file paths that have at least one import whose
237178
+ * resolvedPath is empty. Used to downgrade confidence for all dead
237179
+ * findings in those files, since the graph may be incomplete.
237180
+ *
237181
+ * We derive this from the lock's file entries. Each file entry stores
237182
+ * its imports; any import with an empty resolvedPath (or no match in
237183
+ * the graph nodes) indicates an unresolved dependency.
237184
+ */
237185
+ buildUnresolvedImportFileSet() {
237186
+ const result = /* @__PURE__ */ new Set();
237187
+ if (!this.lock.files)
237188
+ return result;
237189
+ for (const [filePath, fileInfo] of Object.entries(this.lock.files)) {
237190
+ const imports = fileInfo.imports ?? [];
237191
+ for (const imp of imports) {
237192
+ if (!imp.resolvedPath || imp.resolvedPath === "") {
237193
+ result.add(filePath);
237194
+ break;
237195
+ }
237196
+ }
237197
+ }
237198
+ return result;
237127
237199
  }
237128
237200
  };
237129
237201
 
@@ -237272,22 +237344,43 @@ var MikkLockSchema = external_exports.object({
237272
237344
  })
237273
237345
  });
237274
237346
 
237275
- // ../core/dist/contract/contract-reader.js
237347
+ // ../core/dist/utils/json.js
237276
237348
  var fs = __toESM(require("node:fs/promises"), 1);
237349
+ async function readJsonSafe(filePath, fileLabel = "JSON file") {
237350
+ let content;
237351
+ try {
237352
+ content = await fs.readFile(filePath, "utf-8");
237353
+ } catch (e) {
237354
+ if (e.code === "ENOENT") {
237355
+ throw e;
237356
+ }
237357
+ throw new Error(`Failed to read ${fileLabel}: ${e.message}`);
237358
+ }
237359
+ const sanitized = content.replace(/^\uFEFF/, "");
237360
+ try {
237361
+ return JSON.parse(sanitized);
237362
+ } catch (e) {
237363
+ throw new Error(`Malformed ${fileLabel}: Syntax error - ${e.message}`);
237364
+ }
237365
+ }
237366
+
237367
+ // ../core/dist/contract/contract-reader.js
237277
237368
  var ContractReader = class {
237278
237369
  /** Read and validate mikk.json */
237279
237370
  async read(contractPath) {
237280
- let content;
237371
+ let json;
237281
237372
  try {
237282
- content = await fs.readFile(contractPath, "utf-8");
237283
- } catch {
237284
- throw new ContractNotFoundError(contractPath);
237373
+ json = await readJsonSafe(contractPath, "mikk.json");
237374
+ } catch (e) {
237375
+ if (e.code === "ENOENT") {
237376
+ throw new ContractNotFoundError(contractPath);
237377
+ }
237378
+ throw e;
237285
237379
  }
237286
- const json = JSON.parse(content.replace(/^\uFEFF/, ""));
237287
237380
  const result = MikkContractSchema.safeParse(json);
237288
237381
  if (!result.success) {
237289
237382
  const errors = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
237290
- throw new Error(`Invalid mikk.json:
237383
+ throw new Error(`Invalid mikk.json structure:
237291
237384
  ${errors}`);
237292
237385
  }
237293
237386
  return result.data;
@@ -237299,18 +237392,20 @@ var fs2 = __toESM(require("node:fs/promises"), 1);
237299
237392
  var LockReader = class {
237300
237393
  /** Read and validate mikk.lock.json */
237301
237394
  async read(lockPath) {
237302
- let content;
237395
+ let json;
237303
237396
  try {
237304
- content = await fs2.readFile(lockPath, "utf-8");
237305
- } catch {
237306
- throw new LockNotFoundError();
237397
+ json = await readJsonSafe(lockPath, "mikk.lock.json");
237398
+ } catch (e) {
237399
+ if (e.code === "ENOENT") {
237400
+ throw new LockNotFoundError();
237401
+ }
237402
+ throw e;
237307
237403
  }
237308
- const json = JSON.parse(content.replace(/^\uFEFF/, ""));
237309
237404
  const hydrated = hydrateLock(json);
237310
237405
  const result = MikkLockSchema.safeParse(hydrated);
237311
237406
  if (!result.success) {
237312
237407
  const errors = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
237313
- throw new Error(`Invalid mikk.lock.json:
237408
+ throw new Error(`Invalid mikk.lock.json structure:
237314
237409
  ${errors}`);
237315
237410
  }
237316
237411
  return result.data;
@@ -238745,7 +238840,7 @@ function registerTools(server2, projectRoot) {
238745
238840
  );
238746
238841
  server2.tool(
238747
238842
  "mikk_query_context",
238748
- "Ask an architecture question \xC3\xA2\xE2\u201A\xAC\xC2\x9D returns graph-traced context with relevant functions, files, and call chains. Use this to understand how code flows through the project.",
238843
+ "Ask an architecture question \u2014 returns graph-traced context with relevant functions, files, and call chains. Use this to understand how code flows through the project.",
238749
238844
  {
238750
238845
  question: external_exports.string().describe("The architecture question or task description"),
238751
238846
  maxHops: external_exports.number().optional().default(4).describe("Graph traversal depth (default: 4)"),
@@ -238953,7 +239048,7 @@ ${staleness}` : "";
238953
239048
  constraintStatus: totalViolations === 0 ? "pass" : "fail",
238954
239049
  files: fileReports,
238955
239050
  warning: staleness,
238956
- hint: totalViolations > 0 ? "\xC3\u201A\xC2\x8F Constraint violations detected! Review the violations before proceeding. Use mikk_get_constraints for full rule context." : "All constraints satisfied. If safe, proceed with your edits."
239051
+ hint: totalViolations > 0 ? "\u26A0 Constraint violations detected! Review the violations before proceeding. Use mikk_get_constraints for full rule context." : "All constraints satisfied. If safe, proceed with your edits."
238957
239052
  };
238958
239053
  const _rawBE = _filesTok(lock, filesToEdit) * 4;
238959
239054
  response.tokens = _track(projectRoot, _rawBE, response);
@@ -239087,7 +239182,7 @@ ${staleness}` : "";
239087
239182
  content: [{
239088
239183
  type: "text",
239089
239184
  text: [
239090
- "\xC3\u201A\xC2\x9D\xC3\u2026\xE2\u20AC\u2122 Semantic search requires @xenova/transformers.",
239185
+ "\u26A0 Semantic search requires @xenova/transformers.",
239091
239186
  "",
239092
239187
  "Install it in your project root:",
239093
239188
  " npm install @xenova/transformers",
@@ -239216,7 +239311,7 @@ ${content}`
239216
239311
  );
239217
239312
  server2.tool(
239218
239313
  "mikk_dead_code",
239219
- "Detect dead code \xC3\xA2\xE2\u201A\xAC\xC2\x9D functions with zero callers after exempting exports, entry points, route handlers, tests, and constructors. Use this before refactoring or cleanup.",
239314
+ "Detect dead code \u2014 functions with zero callers after exempting exports, entry points, route handlers, tests, and constructors. Use this before refactoring or cleanup.",
239220
239315
  {
239221
239316
  moduleId: external_exports.string().optional().describe("Filter results to a specific module ID")
239222
239317
  },
@@ -239241,7 +239336,7 @@ ${content}`
239241
239336
  );
239242
239337
  server2.tool(
239243
239338
  "mikk_manage_adr",
239244
- "CRUD for Architectural Decision Records (ADRs) in mikk.json. Actions: list, get, add, update, remove. WHEN TO USE: When making architectural changes \xC3\xA2\xE2\u201A\xAC\xE2\u20AC\x9D document WHY so future AI agents understand. AFTER THIS: ADRs automatically surface in mikk_query_context responses. Required for add: id, title, reason.",
239339
+ "CRUD for Architectural Decision Records (ADRs) in mikk.json. Actions: list, get, add, update, remove. WHEN TO USE: When making architectural changes \u2014 document WHY so future AI agents understand. AFTER THIS: ADRs automatically surface in mikk_query_context responses. Required for add: id, title, reason.",
239245
239340
  {
239246
239341
  action: external_exports.enum(["list", "get", "add", "update", "remove"]).describe("The CRUD action to perform"),
239247
239342
  id: external_exports.string().optional().describe("ADR id (required for get, update, remove)"),
@@ -239351,7 +239446,7 @@ ${content}`
239351
239446
  );
239352
239447
  server2.tool(
239353
239448
  "mikk_read_file",
239354
- "Read file scoped to specific functions. Returns bodies with metadata headers (params, calls, calledBy). WHEN TO USE: When you know which functions you need \xC3\xA2\xE2\u201A\xAC\xE2\u20AC\x9D saves tokens vs mikk_get_file. AFTER THIS: Use mikk_before_edit before making changes. TIP: This is the preferred way to read code \xC3\xA2\xE2\u201A\xAC\xE2\u20AC\x9D always specify function names when possible.",
239449
+ "Read file scoped to specific functions. Returns bodies with metadata headers (params, calls, calledBy). WHEN TO USE: When you know which functions you need \u2014 saves tokens vs mikk_get_file. AFTER THIS: Use mikk_before_edit before making changes. TIP: This is the preferred way to read code \u2014 always specify function names when possible.",
239355
239450
  {
239356
239451
  file: external_exports.string().describe("File path relative to project root"),
239357
239452
  functions: external_exports.array(external_exports.string()).optional().describe("Function names to extract. If omitted, returns the whole file.")
@@ -239391,7 +239486,7 @@ ${content}` }]
239391
239486
  (f) => (f.name === fnName || f.name.endsWith(`.${fnName}`)) && (f.file === normalizedFile || f.file.endsWith("/" + normalizedFile))
239392
239487
  );
239393
239488
  if (!fn) {
239394
- sections.push(`// \xC3\u201A\xC2\x9D\xC3\u2026\xE2\u20AC\u2122 Function "${fnName}" not found in ${file}`);
239489
+ sections.push(`// \u26A0 Function "${fnName}" not found in ${file}`);
239395
239490
  continue;
239396
239491
  }
239397
239492
  const header = [
@@ -239531,7 +239626,7 @@ ${staleness}` : "";
239531
239626
  );
239532
239627
  server2.tool(
239533
239628
  "mikk_rename",
239534
- "Plan a coordinated multi-file rename. Finds all call sites and import locations for a function and provides a step-by-step edit plan. WHEN TO USE: Before renaming any function \xC3\xA2\xE2\u201A\xAC\xE2\u20AC\x9D ensures you update ALL call sites. AFTER THIS: Execute the edit plan, then run mikk analyze.",
239629
+ "Plan a coordinated multi-file rename. Finds all call sites and import locations for a function and provides a step-by-step edit plan. WHEN TO USE: Before renaming any function \u2014 ensures you update ALL call sites. AFTER THIS: Execute the edit plan, then run mikk analyze.",
239535
239630
  {
239536
239631
  functionName: external_exports.string().describe("The current function name to rename"),
239537
239632
  newName: external_exports.string().describe("The desired new name")
@@ -239631,7 +239726,7 @@ async function loadContractAndLock(projectRoot) {
239631
239726
  const syncStatus = lock.syncState?.status ?? "unknown";
239632
239727
  let staleness = null;
239633
239728
  if (syncStatus === "drifted" || syncStatus === "conflict") {
239634
- staleness = `\xC3\u201A\xC2\x8F Lock file is ${syncStatus}. Run \`mikk analyze\` for accurate results.`;
239729
+ staleness = `\u26A0 Lock file is ${syncStatus}. Run \`mikk analyze\` for accurate results.`;
239635
239730
  }
239636
239731
  if (!staleness) {
239637
239732
  const fileEntries = Object.entries(lock.files);
@@ -239654,7 +239749,7 @@ async function loadContractAndLock(projectRoot) {
239654
239749
  }
239655
239750
  }
239656
239751
  if (mismatched > 0) {
239657
- staleness = `\xC3\u201A\xC2\x8F STALE: ${mismatched} file(s) changed since last analysis (${mismatchedFiles.slice(0, 3).join(", ")}${mismatched > 3 ? "..." : ""}). Run \`mikk analyze\`.`;
239752
+ staleness = `\u26A0 STALE: ${mismatched} file(s) changed since last analysis (${mismatchedFiles.slice(0, 3).join(", ")}${mismatched > 3 ? "..." : ""}). Run \`mikk analyze\`.`;
239658
239753
  }
239659
239754
  }
239660
239755
  const graph = buildGraphFromLock(lock);
@@ -239726,7 +239821,7 @@ function detectCircularDeps(fns, lock) {
239726
239821
  const cycleStart = cyclePath.indexOf(id);
239727
239822
  const cycle = cyclePath.slice(cycleStart).map((cid) => lock.functions[cid]?.name ?? cid);
239728
239823
  cycle.push(lock.functions[id]?.name ?? id);
239729
- warnings.push(`\xC3\u201A\xC2\x8F Circular: ${cycle.join(" \xC3\xA2\xE2\u201A\xAC\xC2\xA0\xC3\xA2\xE2\u201A\xAC\xE2\u201E\xA2 ")}`);
239824
+ warnings.push(`\u26A0 Circular: ${cycle.join(" -> ")}`);
239730
239825
  return true;
239731
239826
  }
239732
239827
  if (visited.has(id)) return false;
@@ -239861,7 +239956,7 @@ async function safeRead(filePath) {
239861
239956
  }
239862
239957
 
239863
239958
  // src/server.ts
239864
- var VERSION = true ? "1.9.1" : "0.0.0-dev";
239959
+ var VERSION = true ? "1.9.2" : "0.0.0-dev";
239865
239960
  function createMikkMcpServer(projectRoot) {
239866
239961
  const server2 = new McpServer({
239867
239962
  name: "mikk",