@getmikk/mcp-server 1.9.2 → 1.10.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.
- package/dist/index.cjs +681 -141
- package/dist/index.cjs.map +4 -4
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
9
12
|
var __commonJS = (cb, mod) => function __require() {
|
|
10
13
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
14
|
};
|
|
@@ -6800,6 +6803,20 @@ var require_dist = __commonJS({
|
|
|
6800
6803
|
}
|
|
6801
6804
|
});
|
|
6802
6805
|
|
|
6806
|
+
// ../core/dist/parser/base-parser.js
|
|
6807
|
+
var init_base_parser = __esm({
|
|
6808
|
+
"../core/dist/parser/base-parser.js"() {
|
|
6809
|
+
"use strict";
|
|
6810
|
+
}
|
|
6811
|
+
});
|
|
6812
|
+
|
|
6813
|
+
// ../core/dist/hash/file-hasher.js
|
|
6814
|
+
var init_file_hasher = __esm({
|
|
6815
|
+
"../core/dist/hash/file-hasher.js"() {
|
|
6816
|
+
"use strict";
|
|
6817
|
+
}
|
|
6818
|
+
});
|
|
6819
|
+
|
|
6803
6820
|
// ../../node_modules/.bun/typescript@5.9.3/node_modules/typescript/lib/typescript.js
|
|
6804
6821
|
var require_typescript = __commonJS({
|
|
6805
6822
|
"../../node_modules/.bun/typescript@5.9.3/node_modules/typescript/lib/typescript.js"(exports2, module2) {
|
|
@@ -217133,6 +217150,34 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
|
|
|
217133
217150
|
}
|
|
217134
217151
|
});
|
|
217135
217152
|
|
|
217153
|
+
// ../core/dist/parser/tree-sitter/queries.js
|
|
217154
|
+
var init_queries = __esm({
|
|
217155
|
+
"../core/dist/parser/tree-sitter/queries.js"() {
|
|
217156
|
+
"use strict";
|
|
217157
|
+
}
|
|
217158
|
+
});
|
|
217159
|
+
|
|
217160
|
+
// ../core/dist/parser/tree-sitter/parser.js
|
|
217161
|
+
var import_node_module, import_meta, getRequire, _require, ParserModule, Parser;
|
|
217162
|
+
var init_parser = __esm({
|
|
217163
|
+
"../core/dist/parser/tree-sitter/parser.js"() {
|
|
217164
|
+
"use strict";
|
|
217165
|
+
import_node_module = require("node:module");
|
|
217166
|
+
init_file_hasher();
|
|
217167
|
+
init_base_parser();
|
|
217168
|
+
init_queries();
|
|
217169
|
+
import_meta = {};
|
|
217170
|
+
getRequire = () => {
|
|
217171
|
+
if (typeof require !== "undefined")
|
|
217172
|
+
return require;
|
|
217173
|
+
return (0, import_node_module.createRequire)(import_meta.url);
|
|
217174
|
+
};
|
|
217175
|
+
_require = getRequire();
|
|
217176
|
+
ParserModule = _require("web-tree-sitter");
|
|
217177
|
+
Parser = ParserModule.Parser || ParserModule;
|
|
217178
|
+
}
|
|
217179
|
+
});
|
|
217180
|
+
|
|
217136
217181
|
// ../../node_modules/.bun/fast-glob@3.3.3/node_modules/fast-glob/out/utils/array.js
|
|
217137
217182
|
var require_array = __commonJS({
|
|
217138
217183
|
"../../node_modules/.bun/fast-glob@3.3.3/node_modules/fast-glob/out/utils/array.js"(exports2) {
|
|
@@ -236753,11 +236798,24 @@ var fs6 = __toESM(require("node:fs/promises"), 1);
|
|
|
236753
236798
|
var import_node_child_process = require("node:child_process");
|
|
236754
236799
|
var import_node_crypto = require("node:crypto");
|
|
236755
236800
|
|
|
236756
|
-
// ../core/dist/parser/
|
|
236757
|
-
var
|
|
236801
|
+
// ../core/dist/parser/oxc-parser.js
|
|
236802
|
+
var import_oxc_parser = require("oxc-parser");
|
|
236803
|
+
init_base_parser();
|
|
236758
236804
|
|
|
236759
|
-
// ../core/dist/parser/
|
|
236760
|
-
var
|
|
236805
|
+
// ../core/dist/parser/oxc-resolver.js
|
|
236806
|
+
var import_oxc_resolver = require("oxc-resolver");
|
|
236807
|
+
|
|
236808
|
+
// ../core/dist/parser/oxc-parser.js
|
|
236809
|
+
init_file_hasher();
|
|
236810
|
+
|
|
236811
|
+
// ../core/dist/parser/go/go-parser.js
|
|
236812
|
+
init_base_parser();
|
|
236813
|
+
|
|
236814
|
+
// ../core/dist/parser/go/go-extractor.js
|
|
236815
|
+
init_file_hasher();
|
|
236816
|
+
|
|
236817
|
+
// ../core/dist/parser/go/go-parser.js
|
|
236818
|
+
init_file_hasher();
|
|
236761
236819
|
|
|
236762
236820
|
// ../core/dist/utils/errors.js
|
|
236763
236821
|
var MikkError = class extends Error {
|
|
@@ -236779,6 +236837,29 @@ var LockNotFoundError = class extends MikkError {
|
|
|
236779
236837
|
}
|
|
236780
236838
|
};
|
|
236781
236839
|
|
|
236840
|
+
// ../core/dist/parser/index.js
|
|
236841
|
+
init_base_parser();
|
|
236842
|
+
|
|
236843
|
+
// ../core/dist/parser/typescript/ts-parser.js
|
|
236844
|
+
init_base_parser();
|
|
236845
|
+
|
|
236846
|
+
// ../core/dist/parser/typescript/ts-extractor.js
|
|
236847
|
+
var import_typescript = __toESM(require_typescript(), 1);
|
|
236848
|
+
init_file_hasher();
|
|
236849
|
+
|
|
236850
|
+
// ../core/dist/parser/typescript/ts-parser.js
|
|
236851
|
+
init_file_hasher();
|
|
236852
|
+
|
|
236853
|
+
// ../core/dist/parser/javascript/js-parser.js
|
|
236854
|
+
init_base_parser();
|
|
236855
|
+
|
|
236856
|
+
// ../core/dist/parser/javascript/js-extractor.js
|
|
236857
|
+
var import_typescript2 = __toESM(require_typescript(), 1);
|
|
236858
|
+
init_file_hasher();
|
|
236859
|
+
|
|
236860
|
+
// ../core/dist/parser/javascript/js-parser.js
|
|
236861
|
+
init_file_hasher();
|
|
236862
|
+
|
|
236782
236863
|
// ../core/dist/parser/boundary-checker.js
|
|
236783
236864
|
var path = __toESM(require("node:path"), 1);
|
|
236784
236865
|
function stripPrefix(s) {
|
|
@@ -236839,7 +236920,10 @@ var BoundaryChecker = class {
|
|
|
236839
236920
|
for (const file of Object.values(this.lock.files)) {
|
|
236840
236921
|
if (file.moduleId === "unknown" || !file.imports?.length)
|
|
236841
236922
|
continue;
|
|
236842
|
-
for (const
|
|
236923
|
+
for (const imp of file.imports) {
|
|
236924
|
+
const importedPath = imp.resolvedPath;
|
|
236925
|
+
if (!importedPath)
|
|
236926
|
+
continue;
|
|
236843
236927
|
const importedFile = this.lock.files[importedPath];
|
|
236844
236928
|
if (!importedFile || importedFile.moduleId === "unknown" || file.moduleId === importedFile.moduleId)
|
|
236845
236929
|
continue;
|
|
@@ -236911,113 +236995,236 @@ var BoundaryChecker = class {
|
|
|
236911
236995
|
}
|
|
236912
236996
|
};
|
|
236913
236997
|
|
|
236914
|
-
// ../core/dist/parser/
|
|
236915
|
-
|
|
236916
|
-
|
|
236917
|
-
|
|
236918
|
-
|
|
236919
|
-
|
|
236920
|
-
|
|
236998
|
+
// ../core/dist/parser/index.js
|
|
236999
|
+
init_parser();
|
|
237000
|
+
|
|
237001
|
+
// ../core/dist/graph/risk-engine.js
|
|
237002
|
+
var RiskEngine = class {
|
|
237003
|
+
graph;
|
|
237004
|
+
constructor(graph) {
|
|
237005
|
+
this.graph = graph;
|
|
237006
|
+
}
|
|
237007
|
+
/**
|
|
237008
|
+
* Compute the absolute risk score (0-100) for modifying a specific node.
|
|
237009
|
+
* Formula: Base Risk = (Connected Nodes * 1.5) + (Depth * 2) + Modifiers
|
|
237010
|
+
*/
|
|
237011
|
+
scoreNode(nodeId) {
|
|
237012
|
+
const node = this.graph.nodes.get(nodeId);
|
|
237013
|
+
if (!node)
|
|
237014
|
+
return 0;
|
|
237015
|
+
const context = this.analyzeContext(nodeId);
|
|
237016
|
+
const modifiers = this.analyzeModifiers(node);
|
|
237017
|
+
let score = context.connectedNodesCount * 1.5 + context.dependencyDepth * 2;
|
|
237018
|
+
if (modifiers.isAuthOrSecurity)
|
|
237019
|
+
score += 30;
|
|
237020
|
+
if (modifiers.isDatabaseOrState)
|
|
237021
|
+
score += 20;
|
|
237022
|
+
if (modifiers.isPublicAPI)
|
|
237023
|
+
score += 15;
|
|
237024
|
+
return Math.min(Math.max(score, 0), 100);
|
|
237025
|
+
}
|
|
237026
|
+
analyzeContext(nodeId) {
|
|
237027
|
+
const visited = /* @__PURE__ */ new Set();
|
|
237028
|
+
let maxDepth = 0;
|
|
237029
|
+
const queue = [{ id: nodeId, depth: 0 }];
|
|
237030
|
+
let queueHead = 0;
|
|
237031
|
+
visited.add(nodeId);
|
|
237032
|
+
let connectedNodesCount = 0;
|
|
237033
|
+
while (queueHead < queue.length) {
|
|
237034
|
+
const current = queue[queueHead++];
|
|
237035
|
+
maxDepth = Math.max(maxDepth, current.depth);
|
|
237036
|
+
const inEdges = this.graph.inEdges.get(current.id) || [];
|
|
237037
|
+
connectedNodesCount += inEdges.length;
|
|
237038
|
+
for (const edge of inEdges) {
|
|
237039
|
+
if (!visited.has(edge.from)) {
|
|
237040
|
+
visited.add(edge.from);
|
|
237041
|
+
queue.push({ id: edge.from, depth: current.depth + 1 });
|
|
237042
|
+
}
|
|
237043
|
+
}
|
|
237044
|
+
}
|
|
237045
|
+
return {
|
|
237046
|
+
connectedNodesCount,
|
|
237047
|
+
dependencyDepth: maxDepth
|
|
237048
|
+
};
|
|
237049
|
+
}
|
|
237050
|
+
analyzeModifiers(node) {
|
|
237051
|
+
const nameAndFile = `${node.name} ${node.file}`.toLowerCase();
|
|
237052
|
+
const authKeywords = ["auth", "login", "jwt", "verify", "token", "crypt", "hash", "password"];
|
|
237053
|
+
const dbKeywords = ["db", "query", "sql", "insert", "update", "delete", "redis", "cache", "transaction"];
|
|
237054
|
+
return {
|
|
237055
|
+
isAuthOrSecurity: authKeywords.some((kw) => nameAndFile.includes(kw)),
|
|
237056
|
+
isDatabaseOrState: dbKeywords.some((kw) => nameAndFile.includes(kw)),
|
|
237057
|
+
isPublicAPI: !!node.metadata?.isExported
|
|
237058
|
+
};
|
|
237059
|
+
}
|
|
237060
|
+
};
|
|
237061
|
+
|
|
237062
|
+
// ../core/dist/graph/confidence-engine.js
|
|
237063
|
+
var ConfidenceEngine = class {
|
|
237064
|
+
graph;
|
|
237065
|
+
constructor(graph) {
|
|
237066
|
+
this.graph = graph;
|
|
237067
|
+
}
|
|
237068
|
+
/**
|
|
237069
|
+
* Compute confidence decay along a specific path of node IDs.
|
|
237070
|
+
* @param pathIds Array of node IDs forming a path (e.g. ['A', 'B', 'C'])
|
|
237071
|
+
* @returns Cumulative confidence score from 0.0 to 1.0
|
|
237072
|
+
*/
|
|
237073
|
+
calculatePathConfidence(pathIds) {
|
|
237074
|
+
if (pathIds.length < 2)
|
|
237075
|
+
return 1;
|
|
237076
|
+
let totalConfidence = 1;
|
|
237077
|
+
for (let i = 0; i < pathIds.length - 1; i++) {
|
|
237078
|
+
const current = pathIds[i];
|
|
237079
|
+
const next = pathIds[i + 1];
|
|
237080
|
+
const outEdges = this.graph.outEdges.get(current) || [];
|
|
237081
|
+
let maxEdgeConfidence = 0;
|
|
237082
|
+
for (const edge of outEdges) {
|
|
237083
|
+
if (edge.to === next) {
|
|
237084
|
+
if (edge.confidence > maxEdgeConfidence) {
|
|
237085
|
+
maxEdgeConfidence = edge.confidence;
|
|
237086
|
+
}
|
|
237087
|
+
}
|
|
237088
|
+
}
|
|
237089
|
+
if (maxEdgeConfidence === 0) {
|
|
237090
|
+
return 0;
|
|
237091
|
+
}
|
|
237092
|
+
totalConfidence *= maxEdgeConfidence;
|
|
237093
|
+
}
|
|
237094
|
+
return totalConfidence;
|
|
237095
|
+
}
|
|
237096
|
+
/**
|
|
237097
|
+
* Calculates the overall aggregated confidence for a target node
|
|
237098
|
+
* by averaging the confidence of all paths leading to it.
|
|
237099
|
+
*/
|
|
237100
|
+
calculateNodeAggregatedConfidence(paths) {
|
|
237101
|
+
if (paths.length === 0)
|
|
237102
|
+
return 1;
|
|
237103
|
+
const pathConfidences = paths.map((path6) => this.calculatePathConfidence(path6));
|
|
237104
|
+
const sum = pathConfidences.reduce((a, b) => a + b, 0);
|
|
237105
|
+
return Number((sum / paths.length).toFixed(3));
|
|
237106
|
+
}
|
|
236921
237107
|
};
|
|
236922
|
-
var _require = getRequire();
|
|
236923
|
-
var ParserModule = _require("web-tree-sitter");
|
|
236924
|
-
var Parser = ParserModule.Parser || ParserModule;
|
|
236925
237108
|
|
|
236926
237109
|
// ../core/dist/graph/impact-analyzer.js
|
|
236927
237110
|
var ImpactAnalyzer = class {
|
|
236928
237111
|
graph;
|
|
237112
|
+
riskEngine;
|
|
237113
|
+
confidenceEngine;
|
|
236929
237114
|
constructor(graph) {
|
|
236930
237115
|
this.graph = graph;
|
|
237116
|
+
this.riskEngine = new RiskEngine(graph);
|
|
237117
|
+
this.confidenceEngine = new ConfidenceEngine(graph);
|
|
236931
237118
|
}
|
|
236932
237119
|
/** Given a list of changed node IDs, find everything impacted */
|
|
236933
237120
|
analyze(changedNodeIds) {
|
|
236934
|
-
const visited = /* @__PURE__ */ new
|
|
236935
|
-
const
|
|
236936
|
-
|
|
236937
|
-
const queue = changedNodeIds.map((id) => ({ id, depth: 0, confidence: 1 }));
|
|
237121
|
+
const visited = /* @__PURE__ */ new Map();
|
|
237122
|
+
const queue = changedNodeIds.map((id) => ({ id, depth: 0, path: [id], pathSet: /* @__PURE__ */ new Set([id]) }));
|
|
237123
|
+
let queueHead = 0;
|
|
236938
237124
|
let maxDepth = 0;
|
|
236939
|
-
const
|
|
236940
|
-
const
|
|
236941
|
-
|
|
236942
|
-
const
|
|
236943
|
-
if (
|
|
236944
|
-
|
|
236945
|
-
|
|
236946
|
-
|
|
236947
|
-
|
|
236948
|
-
|
|
236949
|
-
|
|
236950
|
-
|
|
236951
|
-
depthMap.set(current, depth);
|
|
236952
|
-
pathConfidence.set(current, pathConf);
|
|
237125
|
+
const entryPoints = /* @__PURE__ */ new Set();
|
|
237126
|
+
const criticalModules = /* @__PURE__ */ new Set();
|
|
237127
|
+
while (queueHead < queue.length) {
|
|
237128
|
+
const { id: current, depth, path: path6, pathSet } = queue[queueHead++];
|
|
237129
|
+
if (!visited.has(current)) {
|
|
237130
|
+
visited.set(current, { depth, paths: [path6] });
|
|
237131
|
+
} else {
|
|
237132
|
+
visited.get(current).paths.push(path6);
|
|
237133
|
+
if (depth < visited.get(current).depth) {
|
|
237134
|
+
visited.get(current).depth = depth;
|
|
237135
|
+
}
|
|
237136
|
+
}
|
|
236953
237137
|
maxDepth = Math.max(maxDepth, depth);
|
|
237138
|
+
const node = this.graph.nodes.get(current);
|
|
237139
|
+
if (node?.metadata?.isExported) {
|
|
237140
|
+
entryPoints.add(current);
|
|
237141
|
+
}
|
|
236954
237142
|
const dependents = this.graph.inEdges.get(current) || [];
|
|
236955
237143
|
for (const edge of dependents) {
|
|
236956
|
-
if (
|
|
236957
|
-
|
|
236958
|
-
|
|
236959
|
-
|
|
237144
|
+
if (edge.type === "contains")
|
|
237145
|
+
continue;
|
|
237146
|
+
if (!pathSet.has(edge.from)) {
|
|
237147
|
+
const newPathSet = new Set(pathSet);
|
|
237148
|
+
newPathSet.add(edge.from);
|
|
237149
|
+
queue.push({
|
|
237150
|
+
id: edge.from,
|
|
237151
|
+
depth: depth + 1,
|
|
237152
|
+
path: [...path6, edge.from],
|
|
237153
|
+
pathSet: newPathSet
|
|
237154
|
+
});
|
|
236960
237155
|
}
|
|
236961
237156
|
}
|
|
236962
237157
|
}
|
|
236963
|
-
const
|
|
237158
|
+
const impactedIds = Array.from(visited.keys()).filter((id) => !changedNodeIds.includes(id));
|
|
237159
|
+
let totalRisk = 0;
|
|
237160
|
+
let totalConfidence = 0;
|
|
236964
237161
|
const classified = {
|
|
236965
237162
|
critical: [],
|
|
236966
237163
|
high: [],
|
|
236967
237164
|
medium: [],
|
|
236968
237165
|
low: []
|
|
236969
237166
|
};
|
|
236970
|
-
for (const id of
|
|
237167
|
+
for (const id of impactedIds) {
|
|
237168
|
+
const context = visited.get(id);
|
|
236971
237169
|
const node = this.graph.nodes.get(id);
|
|
236972
|
-
|
|
236973
|
-
|
|
236974
|
-
const
|
|
236975
|
-
|
|
236976
|
-
|
|
236977
|
-
|
|
237170
|
+
let risk = this.riskEngine.scoreNode(id);
|
|
237171
|
+
const reversedPaths = context.paths.map((p) => [...p].reverse());
|
|
237172
|
+
const confidence = this.confidenceEngine.calculateNodeAggregatedConfidence(reversedPaths);
|
|
237173
|
+
if (context.depth === 1 && node?.moduleId) {
|
|
237174
|
+
const crossesBoundary = changedNodeIds.some((id2) => {
|
|
237175
|
+
const changedNode = this.graph.nodes.get(id2);
|
|
237176
|
+
if (!changedNode?.moduleId || !node.moduleId) {
|
|
237177
|
+
return false;
|
|
237178
|
+
}
|
|
237179
|
+
return changedNode.moduleId !== node.moduleId;
|
|
237180
|
+
});
|
|
237181
|
+
if (crossesBoundary) {
|
|
237182
|
+
risk = Math.max(risk, 80);
|
|
237183
|
+
}
|
|
237184
|
+
}
|
|
237185
|
+
totalRisk += risk;
|
|
237186
|
+
totalConfidence += confidence;
|
|
237187
|
+
const impactEntry = {
|
|
236978
237188
|
nodeId: id,
|
|
236979
|
-
label: node
|
|
236980
|
-
file: node
|
|
236981
|
-
|
|
236982
|
-
risk,
|
|
236983
|
-
depth
|
|
237189
|
+
label: node?.name || "unknown",
|
|
237190
|
+
file: node?.file || "unknown",
|
|
237191
|
+
risk: risk >= 80 ? "CRITICAL" : risk >= 60 ? "HIGH" : risk >= 40 ? "MEDIUM" : "LOW",
|
|
237192
|
+
riskScore: risk,
|
|
237193
|
+
depth: context.depth
|
|
236984
237194
|
};
|
|
236985
|
-
|
|
236986
|
-
|
|
237195
|
+
if (risk >= 80)
|
|
237196
|
+
classified.critical.push(impactEntry);
|
|
237197
|
+
else if (risk >= 60)
|
|
237198
|
+
classified.high.push(impactEntry);
|
|
237199
|
+
else if (risk >= 40)
|
|
237200
|
+
classified.medium.push(impactEntry);
|
|
237201
|
+
else
|
|
237202
|
+
classified.low.push(impactEntry);
|
|
237203
|
+
if (risk > 70 && node?.moduleId) {
|
|
237204
|
+
criticalModules.add(node.moduleId);
|
|
237205
|
+
}
|
|
237206
|
+
}
|
|
237207
|
+
const avgConfidence = impactedIds.length > 0 ? totalConfidence / impactedIds.length : 1;
|
|
237208
|
+
const riskScore = impactedIds.length > 0 ? Math.min(Math.max(totalRisk / impactedIds.length, 0), 100) : 0;
|
|
237209
|
+
const allImpacted = [
|
|
237210
|
+
...classified.critical,
|
|
237211
|
+
...classified.high,
|
|
237212
|
+
...classified.medium,
|
|
237213
|
+
...classified.low
|
|
237214
|
+
];
|
|
236987
237215
|
return {
|
|
236988
237216
|
changed: changedNodeIds,
|
|
236989
|
-
impacted,
|
|
237217
|
+
impacted: impactedIds,
|
|
237218
|
+
allImpacted,
|
|
236990
237219
|
depth: maxDepth,
|
|
236991
|
-
|
|
237220
|
+
entryPoints: Array.from(entryPoints),
|
|
237221
|
+
criticalModules: Array.from(criticalModules),
|
|
237222
|
+
paths: Array.from(visited.values()).flatMap((v) => v.paths),
|
|
237223
|
+
confidence: Number(avgConfidence.toFixed(3)),
|
|
237224
|
+
riskScore: Math.round(riskScore),
|
|
236992
237225
|
classified
|
|
236993
237226
|
};
|
|
236994
237227
|
}
|
|
236995
|
-
/**
|
|
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.
|
|
237004
|
-
*/
|
|
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)
|
|
237016
|
-
return "high";
|
|
237017
|
-
if (score >= 0.5)
|
|
237018
|
-
return "medium";
|
|
237019
|
-
return "low";
|
|
237020
|
-
}
|
|
237021
237228
|
};
|
|
237022
237229
|
|
|
237023
237230
|
// ../core/dist/graph/dead-code-detector.js
|
|
@@ -237141,10 +237348,29 @@ var DeadCodeDetector = class {
|
|
|
237141
237348
|
return false;
|
|
237142
237349
|
}
|
|
237143
237350
|
isCalledByExportedInSameFile(fn) {
|
|
237144
|
-
|
|
237145
|
-
|
|
237146
|
-
|
|
237147
|
-
|
|
237351
|
+
const file = fn.file;
|
|
237352
|
+
const visited = /* @__PURE__ */ new Set();
|
|
237353
|
+
const queue = [fn.id];
|
|
237354
|
+
while (queue.length > 0) {
|
|
237355
|
+
const currentId = queue.pop();
|
|
237356
|
+
if (visited.has(currentId))
|
|
237357
|
+
continue;
|
|
237358
|
+
visited.add(currentId);
|
|
237359
|
+
const current = this.lock.functions[currentId];
|
|
237360
|
+
if (!current)
|
|
237361
|
+
continue;
|
|
237362
|
+
for (const callerId of current.calledBy) {
|
|
237363
|
+
if (visited.has(callerId))
|
|
237364
|
+
continue;
|
|
237365
|
+
const caller = this.lock.functions[callerId];
|
|
237366
|
+
if (!caller)
|
|
237367
|
+
continue;
|
|
237368
|
+
if (caller.file !== file)
|
|
237369
|
+
continue;
|
|
237370
|
+
if (caller.isExported)
|
|
237371
|
+
return true;
|
|
237372
|
+
queue.push(callerId);
|
|
237373
|
+
}
|
|
237148
237374
|
}
|
|
237149
237375
|
return false;
|
|
237150
237376
|
}
|
|
@@ -237159,12 +237385,12 @@ var DeadCodeDetector = class {
|
|
|
237159
237385
|
* high — none of the above: safe to remove.
|
|
237160
237386
|
*/
|
|
237161
237387
|
inferConfidence(fn) {
|
|
237388
|
+
if (DYNAMIC_USAGE_PATTERNS.some((p) => p.test(fn.name)))
|
|
237389
|
+
return "low";
|
|
237162
237390
|
if (fn.calledBy.length > 0)
|
|
237163
237391
|
return "medium";
|
|
237164
237392
|
if (this.filesWithUnresolvedImports.has(fn.file))
|
|
237165
237393
|
return "medium";
|
|
237166
|
-
if (DYNAMIC_USAGE_PATTERNS.some((p) => p.test(fn.name)))
|
|
237167
|
-
return "low";
|
|
237168
237394
|
return "high";
|
|
237169
237395
|
}
|
|
237170
237396
|
inferReason(fn) {
|
|
@@ -237221,6 +237447,19 @@ var MikkOverwriteSchema = external_exports.object({
|
|
|
237221
237447
|
lastOverwrittenBy: external_exports.string().optional(),
|
|
237222
237448
|
lastOverwrittenAt: external_exports.string().optional()
|
|
237223
237449
|
}).default({ mode: "never", requireConfirmation: true });
|
|
237450
|
+
var MikkPolicySchema = external_exports.object({
|
|
237451
|
+
maxRiskScore: external_exports.number().default(70),
|
|
237452
|
+
maxImpactNodes: external_exports.number().default(10),
|
|
237453
|
+
protectedModules: external_exports.array(external_exports.string()).default(["auth", "security", "billing"]),
|
|
237454
|
+
enforceStrictBoundaries: external_exports.boolean().default(true),
|
|
237455
|
+
requireReasoningForCritical: external_exports.boolean().default(true)
|
|
237456
|
+
}).default({
|
|
237457
|
+
maxRiskScore: 70,
|
|
237458
|
+
maxImpactNodes: 10,
|
|
237459
|
+
protectedModules: ["auth", "security", "billing"],
|
|
237460
|
+
enforceStrictBoundaries: true,
|
|
237461
|
+
requireReasoningForCritical: true
|
|
237462
|
+
});
|
|
237224
237463
|
var MikkContractSchema = external_exports.object({
|
|
237225
237464
|
version: external_exports.string(),
|
|
237226
237465
|
project: external_exports.object({
|
|
@@ -237235,7 +237474,8 @@ var MikkContractSchema = external_exports.object({
|
|
|
237235
237474
|
constraints: external_exports.array(external_exports.string()).default([]),
|
|
237236
237475
|
decisions: external_exports.array(MikkDecisionSchema).default([])
|
|
237237
237476
|
}),
|
|
237238
|
-
overwrite: MikkOverwriteSchema
|
|
237477
|
+
overwrite: MikkOverwriteSchema,
|
|
237478
|
+
policies: MikkPolicySchema
|
|
237239
237479
|
});
|
|
237240
237480
|
var MikkLockFunctionSchema = external_exports.object({
|
|
237241
237481
|
id: external_exports.string(),
|
|
@@ -237261,7 +237501,9 @@ var MikkLockFunctionSchema = external_exports.object({
|
|
|
237261
237501
|
line: external_exports.number(),
|
|
237262
237502
|
type: external_exports.enum(["try-catch", "throw"]),
|
|
237263
237503
|
detail: external_exports.string()
|
|
237264
|
-
})).optional()
|
|
237504
|
+
})).optional(),
|
|
237505
|
+
confidence: external_exports.number().optional(),
|
|
237506
|
+
riskScore: external_exports.number().optional()
|
|
237265
237507
|
});
|
|
237266
237508
|
var MikkLockModuleSchema = external_exports.object({
|
|
237267
237509
|
id: external_exports.string(),
|
|
@@ -237269,12 +237511,17 @@ var MikkLockModuleSchema = external_exports.object({
|
|
|
237269
237511
|
hash: external_exports.string(),
|
|
237270
237512
|
fragmentPath: external_exports.string()
|
|
237271
237513
|
});
|
|
237514
|
+
var MikkLockImportSchema = external_exports.object({
|
|
237515
|
+
source: external_exports.string(),
|
|
237516
|
+
resolvedPath: external_exports.string().optional(),
|
|
237517
|
+
names: external_exports.array(external_exports.string()).optional()
|
|
237518
|
+
});
|
|
237272
237519
|
var MikkLockFileSchema = external_exports.object({
|
|
237273
237520
|
path: external_exports.string(),
|
|
237274
237521
|
hash: external_exports.string(),
|
|
237275
237522
|
moduleId: external_exports.string(),
|
|
237276
237523
|
lastModified: external_exports.string(),
|
|
237277
|
-
imports: external_exports.array(
|
|
237524
|
+
imports: external_exports.array(MikkLockImportSchema).optional()
|
|
237278
237525
|
});
|
|
237279
237526
|
var MikkLockClassSchema = external_exports.object({
|
|
237280
237527
|
id: external_exports.string(),
|
|
@@ -237290,7 +237537,9 @@ var MikkLockClassSchema = external_exports.object({
|
|
|
237290
237537
|
line: external_exports.number(),
|
|
237291
237538
|
type: external_exports.enum(["try-catch", "throw"]),
|
|
237292
237539
|
detail: external_exports.string()
|
|
237293
|
-
})).optional()
|
|
237540
|
+
})).optional(),
|
|
237541
|
+
confidence: external_exports.number().optional(),
|
|
237542
|
+
riskScore: external_exports.number().optional()
|
|
237294
237543
|
});
|
|
237295
237544
|
var MikkLockGenericSchema = external_exports.object({
|
|
237296
237545
|
id: external_exports.string(),
|
|
@@ -237344,6 +237593,12 @@ var MikkLockSchema = external_exports.object({
|
|
|
237344
237593
|
})
|
|
237345
237594
|
});
|
|
237346
237595
|
|
|
237596
|
+
// ../core/dist/contract/lock-compiler.js
|
|
237597
|
+
init_file_hasher();
|
|
237598
|
+
|
|
237599
|
+
// ../core/dist/hash/tree-hasher.js
|
|
237600
|
+
init_file_hasher();
|
|
237601
|
+
|
|
237347
237602
|
// ../core/dist/utils/json.js
|
|
237348
237603
|
var fs = __toESM(require("node:fs/promises"), 1);
|
|
237349
237604
|
async function readJsonSafe(filePath, fileLabel = "JSON file") {
|
|
@@ -237505,8 +237760,9 @@ function compactifyLock(lock) {
|
|
|
237505
237760
|
};
|
|
237506
237761
|
if (file.moduleId && file.moduleId !== "unknown")
|
|
237507
237762
|
c.moduleId = file.moduleId;
|
|
237508
|
-
if (file.imports && file.imports.length > 0)
|
|
237509
|
-
c.imports = file.imports;
|
|
237763
|
+
if (file.imports && file.imports.length > 0) {
|
|
237764
|
+
c.imports = file.imports.map(normalizeImportEntry);
|
|
237765
|
+
}
|
|
237510
237766
|
out.files[key] = c;
|
|
237511
237767
|
}
|
|
237512
237768
|
if (lock.contextFiles && lock.contextFiles.length > 0) {
|
|
@@ -237536,7 +237792,10 @@ function hydrateLock(raw) {
|
|
|
237536
237792
|
const hasFnIndex = fnIndex.length > 0;
|
|
237537
237793
|
const fileModuleMap = {};
|
|
237538
237794
|
for (const [key, c] of Object.entries(raw.files || {})) {
|
|
237539
|
-
|
|
237795
|
+
const moduleId = c.moduleId || "unknown";
|
|
237796
|
+
const normalizedKey = normalizeFilePath(key);
|
|
237797
|
+
fileModuleMap[key] = moduleId;
|
|
237798
|
+
fileModuleMap[normalizedKey] = moduleId;
|
|
237540
237799
|
}
|
|
237541
237800
|
out.functions = {};
|
|
237542
237801
|
for (const [key, c] of Object.entries(raw.functions || {})) {
|
|
@@ -237545,6 +237804,7 @@ function hydrateLock(raw) {
|
|
|
237545
237804
|
const lines = c.lines || [c.startLine || 0, c.endLine || 0];
|
|
237546
237805
|
const calls = (c.calls || []).map((v) => typeof v === "number" ? fnIndex[v] ?? null : v).filter(Boolean);
|
|
237547
237806
|
const calledBy = (c.calledBy || []).map((v) => typeof v === "number" ? fnIndex[v] ?? null : v).filter(Boolean);
|
|
237807
|
+
const normalizedFile = normalizeFilePath(file);
|
|
237548
237808
|
out.functions[fullId] = {
|
|
237549
237809
|
id: fullId,
|
|
237550
237810
|
name,
|
|
@@ -237555,7 +237815,7 @@ function hydrateLock(raw) {
|
|
|
237555
237815
|
// P4: empty string when not stored
|
|
237556
237816
|
calls,
|
|
237557
237817
|
calledBy,
|
|
237558
|
-
moduleId: fileModuleMap[file] || c.moduleId || "unknown",
|
|
237818
|
+
moduleId: fileModuleMap[normalizedFile] || fileModuleMap[file] || c.moduleId || "unknown",
|
|
237559
237819
|
// P6: derive from file
|
|
237560
237820
|
...c.params ? { params: c.params } : {},
|
|
237561
237821
|
...c.returnType ? { returnType: c.returnType } : {},
|
|
@@ -237625,7 +237885,7 @@ function hydrateLock(raw) {
|
|
|
237625
237885
|
hash: c.hash || "",
|
|
237626
237886
|
moduleId: c.moduleId || "unknown",
|
|
237627
237887
|
lastModified: c.lastModified || "",
|
|
237628
|
-
...c.imports && c.imports.length > 0 ? { imports: c.imports } : {}
|
|
237888
|
+
...c.imports && c.imports.length > 0 ? { imports: c.imports.map(normalizeImportEntry) } : {}
|
|
237629
237889
|
};
|
|
237630
237890
|
}
|
|
237631
237891
|
out.modules = raw.modules;
|
|
@@ -237660,6 +237920,20 @@ function parseEntityKeyFull(key) {
|
|
|
237660
237920
|
name: rest.slice(lastColon + 1)
|
|
237661
237921
|
};
|
|
237662
237922
|
}
|
|
237923
|
+
function normalizeImportEntry(entry) {
|
|
237924
|
+
if (!entry)
|
|
237925
|
+
return { source: "" };
|
|
237926
|
+
if (typeof entry === "string")
|
|
237927
|
+
return { source: entry };
|
|
237928
|
+
return {
|
|
237929
|
+
source: entry.source,
|
|
237930
|
+
resolvedPath: entry.resolvedPath || void 0,
|
|
237931
|
+
names: entry.names?.length ? entry.names : void 0
|
|
237932
|
+
};
|
|
237933
|
+
}
|
|
237934
|
+
function normalizeFilePath(p) {
|
|
237935
|
+
return (p || "").replace(/\\/g, "/").toLowerCase();
|
|
237936
|
+
}
|
|
237663
237937
|
|
|
237664
237938
|
// ../core/dist/contract/adr-manager.js
|
|
237665
237939
|
var fs3 = __toESM(require("node:fs/promises"), 1);
|
|
@@ -237721,6 +237995,9 @@ var AdrManager = class {
|
|
|
237721
237995
|
}
|
|
237722
237996
|
};
|
|
237723
237997
|
|
|
237998
|
+
// ../core/dist/hash/index.js
|
|
237999
|
+
init_file_hasher();
|
|
238000
|
+
|
|
237724
238001
|
// ../core/dist/hash/hash-store.js
|
|
237725
238002
|
var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
|
|
237726
238003
|
|
|
@@ -237732,11 +238009,14 @@ var BM25Index = class {
|
|
|
237732
238009
|
documentFrequency = /* @__PURE__ */ new Map();
|
|
237733
238010
|
// term → how many docs contain it
|
|
237734
238011
|
avgDocLength = 0;
|
|
238012
|
+
totalDocLength = 0;
|
|
238013
|
+
// running total — avoids O(n²) recompute on every addDocument
|
|
237735
238014
|
/** Clear the index */
|
|
237736
238015
|
clear() {
|
|
237737
238016
|
this.documents = [];
|
|
237738
238017
|
this.documentFrequency.clear();
|
|
237739
238018
|
this.avgDocLength = 0;
|
|
238019
|
+
this.totalDocLength = 0;
|
|
237740
238020
|
}
|
|
237741
238021
|
/** Add a document with pre-tokenized terms */
|
|
237742
238022
|
addDocument(id, tokens) {
|
|
@@ -237746,7 +238026,8 @@ var BM25Index = class {
|
|
|
237746
238026
|
for (const term of uniqueTerms) {
|
|
237747
238027
|
this.documentFrequency.set(term, (this.documentFrequency.get(term) ?? 0) + 1);
|
|
237748
238028
|
}
|
|
237749
|
-
this.
|
|
238029
|
+
this.totalDocLength += normalizedTokens.length;
|
|
238030
|
+
this.avgDocLength = this.totalDocLength / this.documents.length;
|
|
237750
238031
|
}
|
|
237751
238032
|
/** Search the index and return ranked results */
|
|
237752
238033
|
search(query, limit = 20) {
|
|
@@ -237947,25 +238228,90 @@ var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
|
237947
238228
|
"my",
|
|
237948
238229
|
"your"
|
|
237949
238230
|
]);
|
|
237950
|
-
|
|
237951
|
-
|
|
238231
|
+
var SHORT_TECH_WORDS = /* @__PURE__ */ new Set([
|
|
238232
|
+
"ai",
|
|
238233
|
+
"ml",
|
|
238234
|
+
"ui",
|
|
238235
|
+
"ux",
|
|
238236
|
+
"ts",
|
|
238237
|
+
"js",
|
|
238238
|
+
"db",
|
|
238239
|
+
"io",
|
|
238240
|
+
"id",
|
|
238241
|
+
"ip",
|
|
238242
|
+
"ci",
|
|
238243
|
+
"cd",
|
|
238244
|
+
"qa",
|
|
238245
|
+
"api",
|
|
238246
|
+
"mcp",
|
|
238247
|
+
"jwt",
|
|
238248
|
+
"sql"
|
|
238249
|
+
]);
|
|
238250
|
+
function normalizeKeyword(value) {
|
|
238251
|
+
return value.toLowerCase().trim().replace(/[^a-z0-9_-]/g, "");
|
|
238252
|
+
}
|
|
238253
|
+
function extractKeywords2(task, requiredKeywords = []) {
|
|
238254
|
+
const out = [];
|
|
238255
|
+
const seen = /* @__PURE__ */ new Set();
|
|
238256
|
+
for (const match of task.matchAll(/"([^"]+)"|'([^']+)'/g)) {
|
|
238257
|
+
const phrase = (match[1] ?? match[2] ?? "").toLowerCase().trim();
|
|
238258
|
+
if (!phrase || seen.has(phrase))
|
|
238259
|
+
continue;
|
|
238260
|
+
seen.add(phrase);
|
|
238261
|
+
out.push(phrase);
|
|
238262
|
+
}
|
|
238263
|
+
const words = task.toLowerCase().replace(/[^a-z0-9\s_-]/g, " ").split(/\s+/).map(normalizeKeyword).filter((w) => {
|
|
238264
|
+
if (!w || STOP_WORDS.has(w))
|
|
238265
|
+
return false;
|
|
238266
|
+
if (w.length > 2)
|
|
238267
|
+
return true;
|
|
238268
|
+
return SHORT_TECH_WORDS.has(w);
|
|
238269
|
+
});
|
|
238270
|
+
for (const w of words) {
|
|
238271
|
+
if (seen.has(w))
|
|
238272
|
+
continue;
|
|
238273
|
+
seen.add(w);
|
|
238274
|
+
out.push(w);
|
|
238275
|
+
}
|
|
238276
|
+
const expandedRequired = requiredKeywords.flatMap((item) => item.split(/[,\s]+/)).map(normalizeKeyword).filter(Boolean);
|
|
238277
|
+
for (const kw of expandedRequired) {
|
|
238278
|
+
if (seen.has(kw))
|
|
238279
|
+
continue;
|
|
238280
|
+
seen.add(kw);
|
|
238281
|
+
out.push(kw);
|
|
238282
|
+
}
|
|
238283
|
+
return out;
|
|
237952
238284
|
}
|
|
237953
238285
|
function keywordScore(fn, keywords) {
|
|
237954
238286
|
if (keywords.length === 0)
|
|
237955
|
-
return 0;
|
|
238287
|
+
return { score: 0, matchedKeywords: [] };
|
|
237956
238288
|
const nameLower = fn.name.toLowerCase();
|
|
237957
238289
|
const fileLower = fn.file.toLowerCase();
|
|
238290
|
+
const fileNoExt = fileLower.replace(/\.(d\.ts|ts|tsx|js|jsx|mjs|cjs|mts|cts)\b/g, " ");
|
|
238291
|
+
const purposeLower = (fn.purpose ?? "").toLowerCase();
|
|
238292
|
+
const tokenSet = /* @__PURE__ */ new Set([
|
|
238293
|
+
...nameLower.match(/[a-z0-9]+/g) ?? [],
|
|
238294
|
+
...fileNoExt.match(/[a-z0-9]+/g) ?? [],
|
|
238295
|
+
...purposeLower.match(/[a-z0-9]+/g) ?? []
|
|
238296
|
+
]);
|
|
237958
238297
|
let score = 0;
|
|
238298
|
+
const matched = [];
|
|
237959
238299
|
for (const kw of keywords) {
|
|
237960
|
-
|
|
238300
|
+
const shortKw = kw.length <= 2;
|
|
238301
|
+
const exactName = nameLower === kw;
|
|
238302
|
+
const partial2 = shortKw ? tokenSet.has(kw) : nameLower.includes(kw) || fileLower.includes(kw) || purposeLower.includes(kw);
|
|
238303
|
+
if (exactName) {
|
|
237961
238304
|
score = Math.max(score, WEIGHT.KEYWORD_EXACT);
|
|
237962
|
-
|
|
238305
|
+
matched.push(kw);
|
|
238306
|
+
} else if (partial2) {
|
|
237963
238307
|
score = Math.max(score, WEIGHT.KEYWORD_PARTIAL);
|
|
238308
|
+
matched.push(kw);
|
|
237964
238309
|
}
|
|
237965
238310
|
}
|
|
237966
|
-
return score;
|
|
238311
|
+
return { score, matchedKeywords: matched };
|
|
237967
238312
|
}
|
|
237968
|
-
function resolveSeeds(query, contract, lock) {
|
|
238313
|
+
function resolveSeeds(query, contract, lock, keywords) {
|
|
238314
|
+
const strictMode = query.relevanceMode === "strict";
|
|
237969
238315
|
const seeds = /* @__PURE__ */ new Set();
|
|
237970
238316
|
if (query.focusFiles && query.focusFiles.length > 0) {
|
|
237971
238317
|
for (const filePath of query.focusFiles) {
|
|
@@ -237985,14 +238331,13 @@ function resolveSeeds(query, contract, lock) {
|
|
|
237985
238331
|
}
|
|
237986
238332
|
}
|
|
237987
238333
|
if (seeds.size === 0) {
|
|
237988
|
-
const keywords = extractKeywords2(query.task);
|
|
237989
238334
|
for (const fn of Object.values(lock.functions)) {
|
|
237990
|
-
if (keywordScore(fn, keywords) >= WEIGHT.KEYWORD_PARTIAL) {
|
|
238335
|
+
if (keywordScore(fn, keywords).score >= WEIGHT.KEYWORD_PARTIAL) {
|
|
237991
238336
|
seeds.add(fn.id);
|
|
237992
238337
|
}
|
|
237993
238338
|
}
|
|
237994
238339
|
}
|
|
237995
|
-
if (seeds.size === 0) {
|
|
238340
|
+
if (!strictMode && seeds.size === 0) {
|
|
237996
238341
|
const taskLower = query.task.toLowerCase();
|
|
237997
238342
|
for (const mod of contract.declared.modules) {
|
|
237998
238343
|
if (taskLower.includes(mod.id.toLowerCase()) || taskLower.includes(mod.name.toLowerCase())) {
|
|
@@ -238024,25 +238369,72 @@ var ContextBuilder = class {
|
|
|
238024
238369
|
* 6. Group survivors by module, emit structured context
|
|
238025
238370
|
*/
|
|
238026
238371
|
build(query) {
|
|
238372
|
+
const relevanceMode = query.relevanceMode ?? "balanced";
|
|
238373
|
+
const strictMode = relevanceMode === "strict";
|
|
238027
238374
|
const tokenBudget = query.tokenBudget ?? DEFAULT_TOKEN_BUDGET;
|
|
238028
238375
|
const maxHops = query.maxHops ?? 4;
|
|
238029
|
-
const
|
|
238376
|
+
const requiredKeywords = query.requiredKeywords ?? [];
|
|
238377
|
+
const keywords = extractKeywords2(query.task, requiredKeywords);
|
|
238378
|
+
const requiredKeywordSet = new Set(requiredKeywords.flatMap((item) => item.split(/[,\s]+/)).map(normalizeKeyword).filter(Boolean));
|
|
238379
|
+
const seeds = resolveSeeds(query, this.contract, this.lock, keywords);
|
|
238380
|
+
const seedSet = new Set(seeds);
|
|
238030
238381
|
const proximityMap = seeds.length > 0 ? bfsNeighbors(seeds, this.lock.functions, maxHops) : /* @__PURE__ */ new Map();
|
|
238031
|
-
const keywords = extractKeywords2(query.task);
|
|
238032
238382
|
const allFunctions = Object.values(this.lock.functions);
|
|
238383
|
+
const focusFiles = query.focusFiles ?? [];
|
|
238384
|
+
const focusModules = new Set(query.focusModules ?? []);
|
|
238385
|
+
const requireAllKeywords = query.requireAllKeywords ?? false;
|
|
238386
|
+
const minKeywordMatches = query.minKeywordMatches ?? 1;
|
|
238387
|
+
const strictPassIds = /* @__PURE__ */ new Set();
|
|
238388
|
+
const reasons = [];
|
|
238389
|
+
const suggestions = [];
|
|
238390
|
+
const nearMissSuggestions = [];
|
|
238033
238391
|
const scored = allFunctions.map((fn) => {
|
|
238034
238392
|
let score = 0;
|
|
238035
238393
|
const depth = proximityMap.get(fn.id);
|
|
238036
238394
|
if (depth !== void 0) {
|
|
238037
238395
|
score += depthToScore(depth);
|
|
238038
238396
|
}
|
|
238039
|
-
|
|
238040
|
-
|
|
238397
|
+
const kwInfo = keywordScore(fn, keywords);
|
|
238398
|
+
score += kwInfo.score;
|
|
238399
|
+
const matchedSet = new Set(kwInfo.matchedKeywords);
|
|
238400
|
+
const inFocusFile = focusFiles.some((filePath) => fn.file.includes(filePath) || filePath.includes(fn.file));
|
|
238401
|
+
const inFocusModule = focusModules.has(fn.moduleId);
|
|
238402
|
+
const inFocus = inFocusFile || inFocusModule;
|
|
238403
|
+
const requiredPass = requiredKeywordSet.size === 0 ? true : [...requiredKeywordSet].every((kw) => matchedSet.has(kw));
|
|
238404
|
+
const generalPass = requireAllKeywords ? keywords.length > 0 && matchedSet.size >= keywords.length : keywords.length === 0 ? false : matchedSet.size >= minKeywordMatches;
|
|
238405
|
+
const keywordPass = requiredPass && generalPass;
|
|
238406
|
+
if (keywordPass)
|
|
238407
|
+
strictPassIds.add(fn.id);
|
|
238408
|
+
if (strictMode) {
|
|
238409
|
+
const isSeed = seedSet.has(fn.id);
|
|
238410
|
+
const seedFromFocus = isSeed && (inFocus || focusFiles.length > 0 || focusModules.size > 0);
|
|
238411
|
+
if (!(inFocus || keywordPass || seedFromFocus)) {
|
|
238412
|
+
if (kwInfo.score > 0) {
|
|
238413
|
+
nearMissSuggestions.push(`${fn.name} (${fn.file}:${fn.startLine})`);
|
|
238414
|
+
}
|
|
238415
|
+
return { fn, score: -1 };
|
|
238416
|
+
}
|
|
238417
|
+
}
|
|
238418
|
+
if (!strictMode && fn.calledBy.length === 0)
|
|
238041
238419
|
score += WEIGHT.ENTRY_POINT;
|
|
238042
238420
|
return { fn, score };
|
|
238043
238421
|
});
|
|
238044
238422
|
scored.sort((a, b) => b.score - a.score);
|
|
238045
|
-
const
|
|
238423
|
+
for (const { fn, score } of scored) {
|
|
238424
|
+
if (score <= 0)
|
|
238425
|
+
continue;
|
|
238426
|
+
suggestions.push(`${fn.name} (${fn.file}:${fn.startLine})`);
|
|
238427
|
+
if (suggestions.length >= 5)
|
|
238428
|
+
break;
|
|
238429
|
+
}
|
|
238430
|
+
for (const s of nearMissSuggestions) {
|
|
238431
|
+
if (suggestions.includes(s))
|
|
238432
|
+
continue;
|
|
238433
|
+
suggestions.push(s);
|
|
238434
|
+
if (suggestions.length >= 5)
|
|
238435
|
+
break;
|
|
238436
|
+
}
|
|
238437
|
+
let selected = [];
|
|
238046
238438
|
let usedTokens = 0;
|
|
238047
238439
|
for (const { fn, score } of scored) {
|
|
238048
238440
|
if (score <= 0 && seeds.length > 0)
|
|
@@ -238056,6 +238448,51 @@ var ContextBuilder = class {
|
|
|
238056
238448
|
selected.push(fn);
|
|
238057
238449
|
usedTokens += tokens;
|
|
238058
238450
|
}
|
|
238451
|
+
if (strictMode) {
|
|
238452
|
+
if (requiredKeywordSet.size > 0) {
|
|
238453
|
+
reasons.push(`required terms: ${[...requiredKeywordSet].join(", ")}`);
|
|
238454
|
+
}
|
|
238455
|
+
if (strictPassIds.size === 0) {
|
|
238456
|
+
reasons.push("no functions matched strict keyword filters");
|
|
238457
|
+
}
|
|
238458
|
+
}
|
|
238459
|
+
if (strictMode && query.exactOnly) {
|
|
238460
|
+
selected = selected.filter((fn) => strictPassIds.has(fn.id));
|
|
238461
|
+
usedTokens = selected.reduce((sum, fn) => sum + estimateTokens(this.buildFunctionSnippet(fn, query)), 0);
|
|
238462
|
+
if (selected.length === 0 && strictPassIds.size > 0) {
|
|
238463
|
+
reasons.push("exact matches exist but did not fit token budget or max function limit");
|
|
238464
|
+
}
|
|
238465
|
+
}
|
|
238466
|
+
if (strictMode && query.failFast && selected.length === 0) {
|
|
238467
|
+
reasons.push("fail-fast enabled: returning no context when exact match set is empty");
|
|
238468
|
+
return {
|
|
238469
|
+
project: {
|
|
238470
|
+
name: this.contract.project.name,
|
|
238471
|
+
language: this.contract.project.language,
|
|
238472
|
+
description: this.contract.project.description,
|
|
238473
|
+
moduleCount: this.contract.declared.modules.length,
|
|
238474
|
+
functionCount: Object.keys(this.lock.functions).length
|
|
238475
|
+
},
|
|
238476
|
+
modules: [],
|
|
238477
|
+
constraints: this.contract.declared.constraints,
|
|
238478
|
+
decisions: this.contract.declared.decisions.map((d) => ({
|
|
238479
|
+
title: d.title,
|
|
238480
|
+
reason: d.reason
|
|
238481
|
+
})),
|
|
238482
|
+
contextFiles: [],
|
|
238483
|
+
routes: [],
|
|
238484
|
+
prompt: "",
|
|
238485
|
+
meta: {
|
|
238486
|
+
seedCount: seeds.length,
|
|
238487
|
+
totalFunctionsConsidered: allFunctions.length,
|
|
238488
|
+
selectedFunctions: 0,
|
|
238489
|
+
estimatedTokens: 0,
|
|
238490
|
+
keywords,
|
|
238491
|
+
reasons,
|
|
238492
|
+
suggestions: suggestions.length > 0 ? suggestions : void 0
|
|
238493
|
+
}
|
|
238494
|
+
};
|
|
238495
|
+
}
|
|
238059
238496
|
const byModule = /* @__PURE__ */ new Map();
|
|
238060
238497
|
for (const fn of selected) {
|
|
238061
238498
|
if (!byModule.has(fn.moduleId))
|
|
@@ -238076,6 +238513,8 @@ var ContextBuilder = class {
|
|
|
238076
238513
|
});
|
|
238077
238514
|
}
|
|
238078
238515
|
contextModules.sort((a, b) => b.functions.length - a.functions.length);
|
|
238516
|
+
const contextFiles = strictMode ? [] : this.lock.contextFiles;
|
|
238517
|
+
const routes = strictMode ? [] : this.lock.routes;
|
|
238079
238518
|
return {
|
|
238080
238519
|
project: {
|
|
238081
238520
|
name: this.contract.project.name,
|
|
@@ -238090,12 +238529,12 @@ var ContextBuilder = class {
|
|
|
238090
238529
|
title: d.title,
|
|
238091
238530
|
reason: d.reason
|
|
238092
238531
|
})),
|
|
238093
|
-
contextFiles:
|
|
238532
|
+
contextFiles: contextFiles?.map((cf) => ({
|
|
238094
238533
|
path: cf.path,
|
|
238095
238534
|
content: readContextFile(cf.path, query.projectRoot),
|
|
238096
238535
|
type: cf.type
|
|
238097
238536
|
})),
|
|
238098
|
-
routes:
|
|
238537
|
+
routes: routes?.map((r) => ({
|
|
238099
238538
|
method: r.method,
|
|
238100
238539
|
path: r.path,
|
|
238101
238540
|
handler: r.handler,
|
|
@@ -238109,7 +238548,9 @@ var ContextBuilder = class {
|
|
|
238109
238548
|
totalFunctionsConsidered: allFunctions.length,
|
|
238110
238549
|
selectedFunctions: selected.length,
|
|
238111
238550
|
estimatedTokens: usedTokens,
|
|
238112
|
-
keywords
|
|
238551
|
+
keywords,
|
|
238552
|
+
reasons: reasons.length > 0 ? reasons : void 0,
|
|
238553
|
+
suggestions: selected.length === 0 && suggestions.length > 0 ? suggestions : void 0
|
|
238113
238554
|
}
|
|
238114
238555
|
};
|
|
238115
238556
|
}
|
|
@@ -238181,6 +238622,7 @@ var ContextBuilder = class {
|
|
|
238181
238622
|
/** Generate the natural-language prompt section */
|
|
238182
238623
|
generatePrompt(query, modules) {
|
|
238183
238624
|
const lines = [];
|
|
238625
|
+
const strictMode = query.relevanceMode === "strict";
|
|
238184
238626
|
lines.push("=== ARCHITECTURAL CONTEXT ===");
|
|
238185
238627
|
lines.push(`Project: ${this.contract.project.name} (${this.contract.project.language})`);
|
|
238186
238628
|
if (this.contract.project.description) {
|
|
@@ -238189,7 +238631,7 @@ var ContextBuilder = class {
|
|
|
238189
238631
|
lines.push(`Task: ${query.task}`);
|
|
238190
238632
|
lines.push("");
|
|
238191
238633
|
const routes = this.lock.routes;
|
|
238192
|
-
if (routes && routes.length > 0) {
|
|
238634
|
+
if (!strictMode && routes && routes.length > 0) {
|
|
238193
238635
|
lines.push("=== HTTP ROUTES ===");
|
|
238194
238636
|
for (const r of routes) {
|
|
238195
238637
|
const mw = r.middlewares.length > 0 ? ` [${r.middlewares.join(", ")}]` : "";
|
|
@@ -238198,7 +238640,7 @@ var ContextBuilder = class {
|
|
|
238198
238640
|
lines.push("");
|
|
238199
238641
|
}
|
|
238200
238642
|
const ctxFiles = this.lock.contextFiles;
|
|
238201
|
-
if (ctxFiles && ctxFiles.length > 0) {
|
|
238643
|
+
if (!strictMode && ctxFiles && ctxFiles.length > 0) {
|
|
238202
238644
|
lines.push("=== DATA MODELS & SCHEMAS ===");
|
|
238203
238645
|
for (const cf of ctxFiles) {
|
|
238204
238646
|
lines.push(`--- ${cf.path} (${cf.type}) ---`);
|
|
@@ -238465,6 +238907,16 @@ var ClaudeProvider = class {
|
|
|
238465
238907
|
lines.push(` <seeds_found>${context.meta?.seedCount ?? 0}</seeds_found>`);
|
|
238466
238908
|
lines.push(` <functions_selected>${context.meta?.selectedFunctions ?? 0} of ${context.meta?.totalFunctionsConsidered ?? 0}</functions_selected>`);
|
|
238467
238909
|
lines.push(` <estimated_tokens>${context.meta?.estimatedTokens ?? 0}</estimated_tokens>`);
|
|
238910
|
+
if (context.meta?.reasons && context.meta.reasons.length > 0) {
|
|
238911
|
+
for (const reason of context.meta.reasons) {
|
|
238912
|
+
lines.push(` <reason>${esc2(reason)}</reason>`);
|
|
238913
|
+
}
|
|
238914
|
+
}
|
|
238915
|
+
if (context.meta?.suggestions && context.meta.suggestions.length > 0) {
|
|
238916
|
+
for (const s of context.meta.suggestions) {
|
|
238917
|
+
lines.push(` <suggestion>${esc2(s)}</suggestion>`);
|
|
238918
|
+
}
|
|
238919
|
+
}
|
|
238468
238920
|
lines.push("</context_meta>");
|
|
238469
238921
|
lines.push("");
|
|
238470
238922
|
for (const mod of context.modules) {
|
|
@@ -238507,6 +238959,22 @@ var ClaudeProvider = class {
|
|
|
238507
238959
|
lines.push("</module>");
|
|
238508
238960
|
lines.push("");
|
|
238509
238961
|
}
|
|
238962
|
+
if (context.modules.length === 0 && context.meta?.reasons?.length) {
|
|
238963
|
+
lines.push("<no_match_reason>");
|
|
238964
|
+
for (const reason of context.meta.reasons) {
|
|
238965
|
+
lines.push(` <item>${esc2(reason)}</item>`);
|
|
238966
|
+
}
|
|
238967
|
+
lines.push("</no_match_reason>");
|
|
238968
|
+
lines.push("");
|
|
238969
|
+
if (context.meta.suggestions && context.meta.suggestions.length > 0) {
|
|
238970
|
+
lines.push("<did_you_mean>");
|
|
238971
|
+
for (const suggestion of context.meta.suggestions) {
|
|
238972
|
+
lines.push(` <item>${esc2(suggestion)}</item>`);
|
|
238973
|
+
}
|
|
238974
|
+
lines.push("</did_you_mean>");
|
|
238975
|
+
lines.push("");
|
|
238976
|
+
}
|
|
238977
|
+
}
|
|
238510
238978
|
if (context.contextFiles && context.contextFiles.length > 0) {
|
|
238511
238979
|
lines.push("<context_files>");
|
|
238512
238980
|
for (const cf of context.contextFiles) {
|
|
@@ -238567,6 +239035,20 @@ var CompactProvider = class {
|
|
|
238567
239035
|
`Task keywords: ${context.meta?.keywords?.join(", ") ?? ""}`,
|
|
238568
239036
|
""
|
|
238569
239037
|
];
|
|
239038
|
+
if (context.modules.length === 0 && context.meta?.reasons?.length) {
|
|
239039
|
+
lines.push("No exact context selected:");
|
|
239040
|
+
for (const reason of context.meta.reasons) {
|
|
239041
|
+
lines.push(`- ${reason}`);
|
|
239042
|
+
}
|
|
239043
|
+
if (context.meta.suggestions && context.meta.suggestions.length > 0) {
|
|
239044
|
+
lines.push("");
|
|
239045
|
+
lines.push("Did you mean:");
|
|
239046
|
+
for (const suggestion of context.meta.suggestions) {
|
|
239047
|
+
lines.push(`- ${suggestion}`);
|
|
239048
|
+
}
|
|
239049
|
+
}
|
|
239050
|
+
lines.push("");
|
|
239051
|
+
}
|
|
238570
239052
|
for (const mod of context.modules) {
|
|
238571
239053
|
lines.push(`## ${mod.name}`);
|
|
238572
239054
|
for (const fn of mod.functions) {
|
|
@@ -238754,6 +239236,22 @@ var IntentSchema = external_exports.object({
|
|
|
238754
239236
|
// src/tools.ts
|
|
238755
239237
|
var projectCache = /* @__PURE__ */ new Map();
|
|
238756
239238
|
var CACHE_TTL_MS = 3e4;
|
|
239239
|
+
function invalidateCache(projectRoot) {
|
|
239240
|
+
projectCache.delete(projectRoot);
|
|
239241
|
+
}
|
|
239242
|
+
var MAX_SEARCHER_ROOTS = 5;
|
|
239243
|
+
function getSemanticSearcher(projectRoot) {
|
|
239244
|
+
let s = semanticSearchers.get(projectRoot);
|
|
239245
|
+
if (!s) {
|
|
239246
|
+
if (semanticSearchers.size >= MAX_SEARCHER_ROOTS) {
|
|
239247
|
+
const oldestKey = semanticSearchers.keys().next().value;
|
|
239248
|
+
if (oldestKey !== void 0) semanticSearchers.delete(oldestKey);
|
|
239249
|
+
}
|
|
239250
|
+
s = new SemanticSearcher(projectRoot);
|
|
239251
|
+
semanticSearchers.set(projectRoot, s);
|
|
239252
|
+
}
|
|
239253
|
+
return s;
|
|
239254
|
+
}
|
|
238757
239255
|
var _CPT = 4;
|
|
238758
239256
|
var _ALC = 42;
|
|
238759
239257
|
var _tallies = /* @__PURE__ */ new Map();
|
|
@@ -238787,14 +239285,6 @@ function _track(root, raw, resp) {
|
|
|
238787
239285
|
return { used, raw, saved, sessionSaved: t.saved, sessionCalls: t.calls };
|
|
238788
239286
|
}
|
|
238789
239287
|
var semanticSearchers = /* @__PURE__ */ new Map();
|
|
238790
|
-
function getSemanticSearcher(projectRoot) {
|
|
238791
|
-
let s = semanticSearchers.get(projectRoot);
|
|
238792
|
-
if (!s) {
|
|
238793
|
-
s = new SemanticSearcher(projectRoot);
|
|
238794
|
-
semanticSearchers.set(projectRoot, s);
|
|
238795
|
-
}
|
|
238796
|
-
return s;
|
|
238797
|
-
}
|
|
238798
239288
|
function registerTools(server2, projectRoot) {
|
|
238799
239289
|
server2.tool(
|
|
238800
239290
|
"mikk_test_tool",
|
|
@@ -238847,9 +239337,16 @@ function registerTools(server2, projectRoot) {
|
|
|
238847
239337
|
tokenBudget: external_exports.number().optional().default(6e3).describe("Max tokens for function bodies (default: 6000)"),
|
|
238848
239338
|
focusFile: external_exports.string().optional().describe("Anchor traversal from a specific file path"),
|
|
238849
239339
|
focusModule: external_exports.string().optional().describe("Anchor traversal from a specific module ID"),
|
|
239340
|
+
strict: external_exports.boolean().optional().default(false).describe("High-precision mode: include only tightly relevant context"),
|
|
239341
|
+
requiredTerms: external_exports.array(external_exports.string()).optional().describe("Required terms that must match returned context"),
|
|
239342
|
+
requireAllKeywords: external_exports.boolean().optional().default(false).describe("In strict mode, require all extracted keywords"),
|
|
239343
|
+
minKeywordMatches: external_exports.number().optional().default(1).describe("In strict mode, minimum keyword hits per function"),
|
|
239344
|
+
exactOnly: external_exports.boolean().optional().default(false).describe("Hard gate: keep only strict keyword matches"),
|
|
239345
|
+
failFast: external_exports.boolean().optional().default(false).describe("Return no context if strict filters find no exact match"),
|
|
239346
|
+
autoFallback: external_exports.boolean().optional().default(true).describe("When strict mode returns empty, retry with balanced retrieval"),
|
|
238850
239347
|
provider: external_exports.enum(["claude", "generic", "compact"]).optional().default("generic").describe("AI provider format: claude (XML tags), generic (plain), compact (minimal tokens)")
|
|
238851
239348
|
},
|
|
238852
|
-
async ({ question, maxHops, tokenBudget, focusFile, focusModule, provider }) => {
|
|
239349
|
+
async ({ question, maxHops, tokenBudget, focusFile, focusModule, strict, requiredTerms, requireAllKeywords, minKeywordMatches, exactOnly, failFast, autoFallback, provider }) => {
|
|
238853
239350
|
const { contract, lock, staleness } = await loadContractAndLock(projectRoot);
|
|
238854
239351
|
const query = {
|
|
238855
239352
|
task: question,
|
|
@@ -238859,10 +239356,37 @@ function registerTools(server2, projectRoot) {
|
|
|
238859
239356
|
focusModules: focusModule ? [focusModule] : void 0,
|
|
238860
239357
|
includeCallGraph: true,
|
|
238861
239358
|
includeBodies: true,
|
|
239359
|
+
relevanceMode: strict ? "strict" : "balanced",
|
|
239360
|
+
requiredKeywords: requiredTerms,
|
|
239361
|
+
requireAllKeywords,
|
|
239362
|
+
minKeywordMatches,
|
|
239363
|
+
exactOnly,
|
|
239364
|
+
failFast,
|
|
238862
239365
|
projectRoot
|
|
238863
239366
|
};
|
|
238864
239367
|
const builder = new ContextBuilder(contract, lock);
|
|
238865
|
-
|
|
239368
|
+
let ctx = builder.build(query);
|
|
239369
|
+
let fallbackUsed = false;
|
|
239370
|
+
if (autoFallback !== false && strict && ctx.modules.length === 0) {
|
|
239371
|
+
const relaxed = {
|
|
239372
|
+
...query,
|
|
239373
|
+
relevanceMode: "balanced",
|
|
239374
|
+
requiredKeywords: void 0,
|
|
239375
|
+
requireAllKeywords: false,
|
|
239376
|
+
minKeywordMatches: 1,
|
|
239377
|
+
exactOnly: false,
|
|
239378
|
+
failFast: false
|
|
239379
|
+
};
|
|
239380
|
+
const fallback = builder.build(relaxed);
|
|
239381
|
+
if (fallback.modules.length > 0) {
|
|
239382
|
+
ctx = fallback;
|
|
239383
|
+
fallbackUsed = true;
|
|
239384
|
+
ctx.meta.reasons = [
|
|
239385
|
+
...ctx.meta.reasons ?? [],
|
|
239386
|
+
"strict query had no exact matches; returned balanced fallback context"
|
|
239387
|
+
];
|
|
239388
|
+
}
|
|
239389
|
+
}
|
|
238866
239390
|
if (ctx.modules.length === 0) {
|
|
238867
239391
|
return {
|
|
238868
239392
|
content: [{
|
|
@@ -238877,6 +239401,7 @@ function registerTools(server2, projectRoot) {
|
|
|
238877
239401
|
const warning = staleness ? `
|
|
238878
239402
|
|
|
238879
239403
|
${staleness}` : "";
|
|
239404
|
+
const fallbackNote = fallbackUsed ? "Note: strict mode had no exact matches; showing balanced fallback context.\n\n" : "";
|
|
238880
239405
|
const _rawQC = (tokenBudget ?? 6e3) * 3;
|
|
238881
239406
|
const _tokQC = _track(projectRoot, _rawQC, output);
|
|
238882
239407
|
const tokLine = `
|
|
@@ -238884,7 +239409,7 @@ ${staleness}` : "";
|
|
|
238884
239409
|
---
|
|
238885
239410
|
// tokens: ${JSON.stringify(_tokQC)}`;
|
|
238886
239411
|
return {
|
|
238887
|
-
content: [{ type: "text", text: output + warning + "\n\n---\nHint: Use mikk_before_edit on any files you plan to modify, then mikk_impact_analysis to see the full blast radius." + tokLine }]
|
|
239412
|
+
content: [{ type: "text", text: fallbackNote + output + warning + "\n\n---\nHint: Use mikk_before_edit on any files you plan to modify, then mikk_impact_analysis to see the full blast radius." + tokLine }]
|
|
238888
239413
|
};
|
|
238889
239414
|
}
|
|
238890
239415
|
);
|
|
@@ -238916,7 +239441,7 @@ ${staleness}` : "";
|
|
|
238916
239441
|
const result = analyzer.analyze(fileNodes.map((n) => n.id));
|
|
238917
239442
|
const impactedDetails = result.impacted.slice(0, 30).map((id) => {
|
|
238918
239443
|
const node = graph.nodes.get(id);
|
|
238919
|
-
return { function: node?.
|
|
239444
|
+
return { function: node?.name ?? id, file: node?.file ?? "", module: node?.moduleId ?? "" };
|
|
238920
239445
|
});
|
|
238921
239446
|
const response = {
|
|
238922
239447
|
file,
|
|
@@ -239010,7 +239535,7 @@ ${staleness}` : "";
|
|
|
239010
239535
|
const result = analyzer.analyze(fileFns.map((fn) => fn.id));
|
|
239011
239536
|
const impactedDetails = result.impacted.slice(0, 20).map((id) => {
|
|
239012
239537
|
const node = graph.nodes.get(id);
|
|
239013
|
-
return { function: node?.
|
|
239538
|
+
return { function: node?.name ?? id, file: node?.file ?? "", module: node?.moduleId ?? "" };
|
|
239014
239539
|
});
|
|
239015
239540
|
const exportedAtRisk = fileFns.filter((fn) => fn.isExported).map((fn) => ({
|
|
239016
239541
|
name: fn.name,
|
|
@@ -239614,11 +240139,16 @@ ${staleness}` : "";
|
|
|
239614
240139
|
}
|
|
239615
240140
|
}
|
|
239616
240141
|
const totalFns = affectedSymbols.reduce((s, f) => s + f.functions.length, 0);
|
|
239617
|
-
return {
|
|
239618
|
-
|
|
239619
|
-
|
|
239620
|
-
|
|
239621
|
-
|
|
240142
|
+
return {
|
|
240143
|
+
content: [{
|
|
240144
|
+
type: "text",
|
|
240145
|
+
text: JSON.stringify({
|
|
240146
|
+
summary: `${affectedSymbols.length} file(s), ${totalFns} function(s) affected`,
|
|
240147
|
+
affectedSymbols,
|
|
240148
|
+
warning: staleness
|
|
240149
|
+
}, null, 2)
|
|
240150
|
+
}]
|
|
240151
|
+
};
|
|
239622
240152
|
} catch (err) {
|
|
239623
240153
|
return { content: [{ type: "text", text: `Git diff failed: ${err.message}` }], isError: true };
|
|
239624
240154
|
}
|
|
@@ -239652,7 +240182,7 @@ ${staleness}` : "";
|
|
|
239652
240182
|
lineRange: `${fn.startLine}-${fn.endLine}`
|
|
239653
240183
|
}));
|
|
239654
240184
|
const filesImporting = Object.values(lock.files).filter(
|
|
239655
|
-
(file) => file.imports?.some((imp) => imp.includes(functionName) || imp.
|
|
240185
|
+
(file) => file.imports?.some((imp) => imp.names.includes(functionName) || imp.source === targetFn.file)
|
|
239656
240186
|
);
|
|
239657
240187
|
const instructions = [
|
|
239658
240188
|
`1. Rename definition in ${targetFn.file}:${targetFn.startLine}`,
|
|
@@ -239715,9 +240245,19 @@ ${staleness}` : "";
|
|
|
239715
240245
|
);
|
|
239716
240246
|
}
|
|
239717
240247
|
async function loadContractAndLock(projectRoot) {
|
|
240248
|
+
const lockFilePath = path4.join(projectRoot, "mikk.lock.json");
|
|
239718
240249
|
const cached2 = projectCache.get(projectRoot);
|
|
239719
|
-
if (cached2
|
|
239720
|
-
|
|
240250
|
+
if (cached2) {
|
|
240251
|
+
try {
|
|
240252
|
+
const stat2 = await fs6.stat(lockFilePath);
|
|
240253
|
+
if (stat2.mtimeMs > cached2.cachedAt) {
|
|
240254
|
+
invalidateCache(projectRoot);
|
|
240255
|
+
} else if (Date.now() - cached2.cachedAt < CACHE_TTL_MS) {
|
|
240256
|
+
return { contract: cached2.contract, lock: cached2.lock, staleness: cached2.staleness };
|
|
240257
|
+
}
|
|
240258
|
+
} catch {
|
|
240259
|
+
invalidateCache(projectRoot);
|
|
240260
|
+
}
|
|
239721
240261
|
}
|
|
239722
240262
|
const contractReader = new ContractReader();
|
|
239723
240263
|
const lockReader = new LockReader();
|
|
@@ -239771,7 +240311,7 @@ function buildGraphFromLock(lock) {
|
|
|
239771
240311
|
nodes.set(fn.id, {
|
|
239772
240312
|
id: fn.id,
|
|
239773
240313
|
type: "function",
|
|
239774
|
-
|
|
240314
|
+
name: fn.name,
|
|
239775
240315
|
file: fn.file,
|
|
239776
240316
|
moduleId: fn.moduleId,
|
|
239777
240317
|
metadata: {
|
|
@@ -239792,7 +240332,7 @@ function buildGraphFromLock(lock) {
|
|
|
239792
240332
|
nodes.set(file.path, {
|
|
239793
240333
|
id: file.path,
|
|
239794
240334
|
type: "file",
|
|
239795
|
-
|
|
240335
|
+
name: path4.basename(file.path),
|
|
239796
240336
|
file: file.path,
|
|
239797
240337
|
moduleId: file.moduleId,
|
|
239798
240338
|
metadata: {}
|
|
@@ -239801,7 +240341,7 @@ function buildGraphFromLock(lock) {
|
|
|
239801
240341
|
for (const fn of Object.values(lock.functions)) {
|
|
239802
240342
|
for (const calleeId of fn.calls) {
|
|
239803
240343
|
if (!nodes.has(calleeId)) continue;
|
|
239804
|
-
const edge = {
|
|
240344
|
+
const edge = { from: fn.id, to: calleeId, type: "calls", confidence: 1 };
|
|
239805
240345
|
edges.push(edge);
|
|
239806
240346
|
const out = outEdges.get(fn.id) ?? [];
|
|
239807
240347
|
out.push(edge);
|
|
@@ -239956,7 +240496,7 @@ async function safeRead(filePath) {
|
|
|
239956
240496
|
}
|
|
239957
240497
|
|
|
239958
240498
|
// src/server.ts
|
|
239959
|
-
var VERSION = true ? "1.
|
|
240499
|
+
var VERSION = true ? "1.10.0" : "0.0.0-dev";
|
|
239960
240500
|
function createMikkMcpServer(projectRoot) {
|
|
239961
240501
|
const server2 = new McpServer({
|
|
239962
240502
|
name: "mikk",
|