@yawlabs/ctxlint 0.9.17 → 0.9.19
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/.pre-commit-hooks.yaml +1 -1
- package/README.md +2 -2
- package/dist/index.js +580 -438
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -448,8 +448,8 @@ var init_parseUtil = __esm({
|
|
|
448
448
|
init_errors();
|
|
449
449
|
init_en();
|
|
450
450
|
makeIssue = (params) => {
|
|
451
|
-
const { data, path:
|
|
452
|
-
const fullPath = [...
|
|
451
|
+
const { data, path: path13, errorMaps, issueData } = params;
|
|
452
|
+
const fullPath = [...path13, ...issueData.path || []];
|
|
453
453
|
const fullIssue = {
|
|
454
454
|
...issueData,
|
|
455
455
|
path: fullPath
|
|
@@ -729,11 +729,11 @@ var init_types = __esm({
|
|
|
729
729
|
init_parseUtil();
|
|
730
730
|
init_util();
|
|
731
731
|
ParseInputLazyPath = class {
|
|
732
|
-
constructor(parent, value,
|
|
732
|
+
constructor(parent, value, path13, key) {
|
|
733
733
|
this._cachedPath = [];
|
|
734
734
|
this.parent = parent;
|
|
735
735
|
this.data = value;
|
|
736
|
-
this._path =
|
|
736
|
+
this._path = path13;
|
|
737
737
|
this._key = key;
|
|
738
738
|
}
|
|
739
739
|
get path() {
|
|
@@ -4238,10 +4238,10 @@ function mergeDefs(...defs) {
|
|
|
4238
4238
|
function cloneDef(schema) {
|
|
4239
4239
|
return mergeDefs(schema._zod.def);
|
|
4240
4240
|
}
|
|
4241
|
-
function getElementAtPath(obj,
|
|
4242
|
-
if (!
|
|
4241
|
+
function getElementAtPath(obj, path13) {
|
|
4242
|
+
if (!path13)
|
|
4243
4243
|
return obj;
|
|
4244
|
-
return
|
|
4244
|
+
return path13.reduce((acc, key) => acc?.[key], obj);
|
|
4245
4245
|
}
|
|
4246
4246
|
function promiseAllObject(promisesObj) {
|
|
4247
4247
|
const keys = Object.keys(promisesObj);
|
|
@@ -4553,11 +4553,11 @@ function aborted(x3, startIndex = 0) {
|
|
|
4553
4553
|
}
|
|
4554
4554
|
return false;
|
|
4555
4555
|
}
|
|
4556
|
-
function prefixIssues(
|
|
4556
|
+
function prefixIssues(path13, issues) {
|
|
4557
4557
|
return issues.map((iss) => {
|
|
4558
4558
|
var _a3;
|
|
4559
4559
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
4560
|
-
iss.path.unshift(
|
|
4560
|
+
iss.path.unshift(path13);
|
|
4561
4561
|
return iss;
|
|
4562
4562
|
});
|
|
4563
4563
|
}
|
|
@@ -4799,7 +4799,7 @@ function formatError(error49, mapper = (issue2) => issue2.message) {
|
|
|
4799
4799
|
}
|
|
4800
4800
|
function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
4801
4801
|
const result = { errors: [] };
|
|
4802
|
-
const processError = (error50,
|
|
4802
|
+
const processError = (error50, path13 = []) => {
|
|
4803
4803
|
var _a3, _b;
|
|
4804
4804
|
for (const issue2 of error50.issues) {
|
|
4805
4805
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -4809,7 +4809,7 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
4809
4809
|
} else if (issue2.code === "invalid_element") {
|
|
4810
4810
|
processError({ issues: issue2.issues }, issue2.path);
|
|
4811
4811
|
} else {
|
|
4812
|
-
const fullpath = [...
|
|
4812
|
+
const fullpath = [...path13, ...issue2.path];
|
|
4813
4813
|
if (fullpath.length === 0) {
|
|
4814
4814
|
result.errors.push(mapper(issue2));
|
|
4815
4815
|
continue;
|
|
@@ -4841,8 +4841,8 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
|
|
|
4841
4841
|
}
|
|
4842
4842
|
function toDotPath(_path) {
|
|
4843
4843
|
const segs = [];
|
|
4844
|
-
const
|
|
4845
|
-
for (const seg of
|
|
4844
|
+
const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
4845
|
+
for (const seg of path13) {
|
|
4846
4846
|
if (typeof seg === "number")
|
|
4847
4847
|
segs.push(`[${seg}]`);
|
|
4848
4848
|
else if (typeof seg === "symbol")
|
|
@@ -17792,13 +17792,13 @@ function resolveRef(ref, ctx) {
|
|
|
17792
17792
|
if (!ref.startsWith("#")) {
|
|
17793
17793
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
17794
17794
|
}
|
|
17795
|
-
const
|
|
17796
|
-
if (
|
|
17795
|
+
const path13 = ref.slice(1).split("/").filter(Boolean);
|
|
17796
|
+
if (path13.length === 0) {
|
|
17797
17797
|
return ctx.rootSchema;
|
|
17798
17798
|
}
|
|
17799
17799
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
17800
|
-
if (
|
|
17801
|
-
const key =
|
|
17800
|
+
if (path13[0] === defsKey) {
|
|
17801
|
+
const key = path13[1];
|
|
17802
17802
|
if (!key || !ctx.defs[key]) {
|
|
17803
17803
|
throw new Error(`Reference not found: ${ref}`);
|
|
17804
17804
|
}
|
|
@@ -25888,8 +25888,8 @@ var require_utils = __commonJS({
|
|
|
25888
25888
|
}
|
|
25889
25889
|
return ind;
|
|
25890
25890
|
}
|
|
25891
|
-
function removeDotSegments(
|
|
25892
|
-
let input =
|
|
25891
|
+
function removeDotSegments(path13) {
|
|
25892
|
+
let input = path13;
|
|
25893
25893
|
const output = [];
|
|
25894
25894
|
let nextSlash = -1;
|
|
25895
25895
|
let len = 0;
|
|
@@ -26088,8 +26088,8 @@ var require_schemes = __commonJS({
|
|
|
26088
26088
|
wsComponent.secure = void 0;
|
|
26089
26089
|
}
|
|
26090
26090
|
if (wsComponent.resourceName) {
|
|
26091
|
-
const [
|
|
26092
|
-
wsComponent.path =
|
|
26091
|
+
const [path13, query] = wsComponent.resourceName.split("?");
|
|
26092
|
+
wsComponent.path = path13 && path13 !== "/" ? path13 : void 0;
|
|
26093
26093
|
wsComponent.query = query;
|
|
26094
26094
|
wsComponent.resourceName = void 0;
|
|
26095
26095
|
}
|
|
@@ -29451,12 +29451,12 @@ var require_dist = __commonJS({
|
|
|
29451
29451
|
throw new Error(`Unknown format "${name}"`);
|
|
29452
29452
|
return f;
|
|
29453
29453
|
};
|
|
29454
|
-
function addFormats(ajv, list,
|
|
29454
|
+
function addFormats(ajv, list, fs10, exportName) {
|
|
29455
29455
|
var _a3;
|
|
29456
29456
|
var _b;
|
|
29457
29457
|
(_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
29458
29458
|
for (const f of list)
|
|
29459
|
-
ajv.addFormat(f,
|
|
29459
|
+
ajv.addFormat(f, fs10[f]);
|
|
29460
29460
|
}
|
|
29461
29461
|
module.exports = exports = formatsPlugin;
|
|
29462
29462
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -35561,10 +35561,10 @@ var require_src2 = __commonJS({
|
|
|
35561
35561
|
var fs_1 = __require("fs");
|
|
35562
35562
|
var debug_1 = __importDefault(require_src());
|
|
35563
35563
|
var log = debug_1.default("@kwsites/file-exists");
|
|
35564
|
-
function check2(
|
|
35565
|
-
log(`checking %s`,
|
|
35564
|
+
function check2(path13, isFile, isDirectory2) {
|
|
35565
|
+
log(`checking %s`, path13);
|
|
35566
35566
|
try {
|
|
35567
|
-
const stat3 = fs_1.statSync(
|
|
35567
|
+
const stat3 = fs_1.statSync(path13);
|
|
35568
35568
|
if (stat3.isFile() && isFile) {
|
|
35569
35569
|
log(`[OK] path represents a file`);
|
|
35570
35570
|
return true;
|
|
@@ -35584,8 +35584,8 @@ var require_src2 = __commonJS({
|
|
|
35584
35584
|
throw e;
|
|
35585
35585
|
}
|
|
35586
35586
|
}
|
|
35587
|
-
function exists2(
|
|
35588
|
-
return check2(
|
|
35587
|
+
function exists2(path13, type = exports.READABLE) {
|
|
35588
|
+
return check2(path13, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
35589
35589
|
}
|
|
35590
35590
|
exports.exists = exists2;
|
|
35591
35591
|
exports.FILE = 1;
|
|
@@ -36174,8 +36174,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
36174
36174
|
function forEachLineWithContent(input, callback) {
|
|
36175
36175
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
36176
36176
|
}
|
|
36177
|
-
function folderExists(
|
|
36178
|
-
return (0, import_file_exists.exists)(
|
|
36177
|
+
function folderExists(path13) {
|
|
36178
|
+
return (0, import_file_exists.exists)(path13, import_file_exists.FOLDER);
|
|
36179
36179
|
}
|
|
36180
36180
|
function append(target, item) {
|
|
36181
36181
|
if (Array.isArray(target)) {
|
|
@@ -36366,8 +36366,8 @@ function checkIsRepoRootTask() {
|
|
|
36366
36366
|
commands,
|
|
36367
36367
|
format: "utf-8",
|
|
36368
36368
|
onError,
|
|
36369
|
-
parser(
|
|
36370
|
-
return /^\.(git)?$/.test(
|
|
36369
|
+
parser(path13) {
|
|
36370
|
+
return /^\.(git)?$/.test(path13.trim());
|
|
36371
36371
|
}
|
|
36372
36372
|
};
|
|
36373
36373
|
}
|
|
@@ -36623,11 +36623,11 @@ function parseGrep(grep) {
|
|
|
36623
36623
|
const paths = /* @__PURE__ */ new Set();
|
|
36624
36624
|
const results = {};
|
|
36625
36625
|
forEachLineWithContent(grep, (input) => {
|
|
36626
|
-
const [
|
|
36627
|
-
paths.add(
|
|
36628
|
-
(results[
|
|
36626
|
+
const [path13, line, preview] = input.split(NULL);
|
|
36627
|
+
paths.add(path13);
|
|
36628
|
+
(results[path13] = results[path13] || []).push({
|
|
36629
36629
|
line: asNumber(line),
|
|
36630
|
-
path:
|
|
36630
|
+
path: path13,
|
|
36631
36631
|
preview
|
|
36632
36632
|
});
|
|
36633
36633
|
});
|
|
@@ -36924,14 +36924,14 @@ function hashObjectTask(filePath, write) {
|
|
|
36924
36924
|
}
|
|
36925
36925
|
return straightThroughStringTask(commands, true);
|
|
36926
36926
|
}
|
|
36927
|
-
function parseInit(bare,
|
|
36927
|
+
function parseInit(bare, path13, text) {
|
|
36928
36928
|
const response = String(text).trim();
|
|
36929
36929
|
let result;
|
|
36930
36930
|
if (result = initResponseRegex.exec(response)) {
|
|
36931
|
-
return new InitSummary(bare,
|
|
36931
|
+
return new InitSummary(bare, path13, false, result[1]);
|
|
36932
36932
|
}
|
|
36933
36933
|
if (result = reInitResponseRegex.exec(response)) {
|
|
36934
|
-
return new InitSummary(bare,
|
|
36934
|
+
return new InitSummary(bare, path13, true, result[1]);
|
|
36935
36935
|
}
|
|
36936
36936
|
let gitDir = "";
|
|
36937
36937
|
const tokens = response.split(" ");
|
|
@@ -36942,12 +36942,12 @@ function parseInit(bare, path14, text) {
|
|
|
36942
36942
|
break;
|
|
36943
36943
|
}
|
|
36944
36944
|
}
|
|
36945
|
-
return new InitSummary(bare,
|
|
36945
|
+
return new InitSummary(bare, path13, /^re/i.test(response), gitDir);
|
|
36946
36946
|
}
|
|
36947
36947
|
function hasBareCommand(command) {
|
|
36948
36948
|
return command.includes(bareCommand);
|
|
36949
36949
|
}
|
|
36950
|
-
function initTask(bare = false,
|
|
36950
|
+
function initTask(bare = false, path13, customArgs) {
|
|
36951
36951
|
const commands = ["init", ...customArgs];
|
|
36952
36952
|
if (bare && !hasBareCommand(commands)) {
|
|
36953
36953
|
commands.splice(1, 0, bareCommand);
|
|
@@ -36956,7 +36956,7 @@ function initTask(bare = false, path14, customArgs) {
|
|
|
36956
36956
|
commands,
|
|
36957
36957
|
format: "utf-8",
|
|
36958
36958
|
parser(text) {
|
|
36959
|
-
return parseInit(commands.includes("--bare"),
|
|
36959
|
+
return parseInit(commands.includes("--bare"), path13, text);
|
|
36960
36960
|
}
|
|
36961
36961
|
};
|
|
36962
36962
|
}
|
|
@@ -37235,14 +37235,14 @@ function splitLine(result, lineStr) {
|
|
|
37235
37235
|
default:
|
|
37236
37236
|
return;
|
|
37237
37237
|
}
|
|
37238
|
-
function data(index, workingDir,
|
|
37238
|
+
function data(index, workingDir, path13) {
|
|
37239
37239
|
const raw = `${index}${workingDir}`;
|
|
37240
37240
|
const handler = parsers6.get(raw);
|
|
37241
37241
|
if (handler) {
|
|
37242
|
-
handler(result,
|
|
37242
|
+
handler(result, path13);
|
|
37243
37243
|
}
|
|
37244
37244
|
if (raw !== "##" && raw !== "!!") {
|
|
37245
|
-
result.files.push(new FileStatusSummary(
|
|
37245
|
+
result.files.push(new FileStatusSummary(path13, index, workingDir));
|
|
37246
37246
|
}
|
|
37247
37247
|
}
|
|
37248
37248
|
}
|
|
@@ -37429,8 +37429,8 @@ function deleteBranchTask(branch, forceDelete = false) {
|
|
|
37429
37429
|
return task;
|
|
37430
37430
|
}
|
|
37431
37431
|
function toPath(input) {
|
|
37432
|
-
const
|
|
37433
|
-
return
|
|
37432
|
+
const path13 = input.trim().replace(/^["']|["']$/g, "");
|
|
37433
|
+
return path13 && normalize2(path13);
|
|
37434
37434
|
}
|
|
37435
37435
|
function checkIgnoreTask(paths) {
|
|
37436
37436
|
return {
|
|
@@ -37569,8 +37569,8 @@ function stashListTask(opt = {}, customArgs) {
|
|
|
37569
37569
|
parser: parser4
|
|
37570
37570
|
};
|
|
37571
37571
|
}
|
|
37572
|
-
function addSubModuleTask(repo,
|
|
37573
|
-
return subModuleTask(["add", repo,
|
|
37572
|
+
function addSubModuleTask(repo, path13) {
|
|
37573
|
+
return subModuleTask(["add", repo, path13]);
|
|
37574
37574
|
}
|
|
37575
37575
|
function initSubModuleTask(customArgs) {
|
|
37576
37576
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -38832,9 +38832,9 @@ var init_esm2 = __esm({
|
|
|
38832
38832
|
"src/lib/responses/InitSummary.ts"() {
|
|
38833
38833
|
"use strict";
|
|
38834
38834
|
InitSummary = class {
|
|
38835
|
-
constructor(bare,
|
|
38835
|
+
constructor(bare, path13, existing, gitDir) {
|
|
38836
38836
|
this.bare = bare;
|
|
38837
|
-
this.path =
|
|
38837
|
+
this.path = path13;
|
|
38838
38838
|
this.existing = existing;
|
|
38839
38839
|
this.gitDir = gitDir;
|
|
38840
38840
|
}
|
|
@@ -39367,12 +39367,12 @@ var init_esm2 = __esm({
|
|
|
39367
39367
|
"use strict";
|
|
39368
39368
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
39369
39369
|
FileStatusSummary = class {
|
|
39370
|
-
constructor(
|
|
39371
|
-
this.path =
|
|
39370
|
+
constructor(path13, index, working_dir) {
|
|
39371
|
+
this.path = path13;
|
|
39372
39372
|
this.index = index;
|
|
39373
39373
|
this.working_dir = working_dir;
|
|
39374
39374
|
if (index === "R" || working_dir === "R") {
|
|
39375
|
-
const detail = fromPathRegex.exec(
|
|
39375
|
+
const detail = fromPathRegex.exec(path13) || [null, path13, path13];
|
|
39376
39376
|
this.from = detail[2] || "";
|
|
39377
39377
|
this.path = detail[1] || "";
|
|
39378
39378
|
}
|
|
@@ -39634,9 +39634,9 @@ var init_esm2 = __esm({
|
|
|
39634
39634
|
next
|
|
39635
39635
|
);
|
|
39636
39636
|
}
|
|
39637
|
-
hashObject(
|
|
39637
|
+
hashObject(path13, write) {
|
|
39638
39638
|
return this._runTask(
|
|
39639
|
-
hashObjectTask(
|
|
39639
|
+
hashObjectTask(path13, write === true),
|
|
39640
39640
|
trailingFunctionArgument(arguments)
|
|
39641
39641
|
);
|
|
39642
39642
|
}
|
|
@@ -40273,8 +40273,8 @@ var init_esm2 = __esm({
|
|
|
40273
40273
|
}
|
|
40274
40274
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
40275
40275
|
};
|
|
40276
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
40277
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
40276
|
+
Git2.prototype.submoduleAdd = function(repo, path13, then) {
|
|
40277
|
+
return this._runTask(addSubModuleTask2(repo, path13), trailingFunctionArgument2(arguments));
|
|
40278
40278
|
};
|
|
40279
40279
|
Git2.prototype.submoduleUpdate = function(args2, then) {
|
|
40280
40280
|
return this._runTask(
|
|
@@ -40617,21 +40617,24 @@ async function findRenames(projectRoot, filePath) {
|
|
|
40617
40617
|
filePath
|
|
40618
40618
|
]);
|
|
40619
40619
|
if (!result.trim()) return null;
|
|
40620
|
+
let currentHash = "unknown";
|
|
40621
|
+
let currentDateStr;
|
|
40620
40622
|
const lines = result.trim().split("\n");
|
|
40621
|
-
for (
|
|
40622
|
-
const
|
|
40623
|
+
for (const line of lines) {
|
|
40624
|
+
const headerMatch = line.match(/^([a-f0-9]{7,40})\s+(.+)$/);
|
|
40625
|
+
if (headerMatch) {
|
|
40626
|
+
currentHash = headerMatch[1].substring(0, 7);
|
|
40627
|
+
currentDateStr = headerMatch[2];
|
|
40628
|
+
continue;
|
|
40629
|
+
}
|
|
40623
40630
|
if (line.startsWith("R")) {
|
|
40624
40631
|
const parts = line.split(" ");
|
|
40625
40632
|
if (parts.length >= 3) {
|
|
40626
|
-
const
|
|
40627
|
-
const hashMatch = hashLine.match(/^([a-f0-9]+)\s+(.+)/);
|
|
40628
|
-
const commitHash = hashMatch?.[1]?.substring(0, 7) || "unknown";
|
|
40629
|
-
const dateStr = hashMatch?.[2];
|
|
40630
|
-
const daysAgo = dateStr ? Math.floor((Date.now() - new Date(dateStr).getTime()) / (1e3 * 60 * 60 * 24)) : 0;
|
|
40633
|
+
const daysAgo = currentDateStr ? Math.floor((Date.now() - new Date(currentDateStr).getTime()) / (1e3 * 60 * 60 * 24)) : 0;
|
|
40631
40634
|
return {
|
|
40632
40635
|
oldPath: parts[1],
|
|
40633
40636
|
newPath: parts[2],
|
|
40634
|
-
commitHash,
|
|
40637
|
+
commitHash: currentHash,
|
|
40635
40638
|
daysAgo
|
|
40636
40639
|
};
|
|
40637
40640
|
}
|
|
@@ -41313,6 +41316,28 @@ function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
|
|
|
41313
41316
|
}
|
|
41314
41317
|
return result;
|
|
41315
41318
|
}
|
|
41319
|
+
function getNodeValue(node) {
|
|
41320
|
+
switch (node.type) {
|
|
41321
|
+
case "array":
|
|
41322
|
+
return node.children.map(getNodeValue);
|
|
41323
|
+
case "object":
|
|
41324
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
41325
|
+
for (let prop of node.children) {
|
|
41326
|
+
const valueNode = prop.children[1];
|
|
41327
|
+
if (valueNode) {
|
|
41328
|
+
obj[prop.children[0].value] = getNodeValue(valueNode);
|
|
41329
|
+
}
|
|
41330
|
+
}
|
|
41331
|
+
return obj;
|
|
41332
|
+
case "null":
|
|
41333
|
+
case "string":
|
|
41334
|
+
case "number":
|
|
41335
|
+
case "boolean":
|
|
41336
|
+
return node.value;
|
|
41337
|
+
default:
|
|
41338
|
+
return void 0;
|
|
41339
|
+
}
|
|
41340
|
+
}
|
|
41316
41341
|
function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
41317
41342
|
const _scanner = createScanner(text, false);
|
|
41318
41343
|
const _jsonPath = [];
|
|
@@ -41661,7 +41686,7 @@ var init_edit = __esm({
|
|
|
41661
41686
|
});
|
|
41662
41687
|
|
|
41663
41688
|
// node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js
|
|
41664
|
-
var ScanError, SyntaxKind, parseTree2, ParseErrorCode;
|
|
41689
|
+
var ScanError, SyntaxKind, parseTree2, getNodeValue2, ParseErrorCode;
|
|
41665
41690
|
var init_main = __esm({
|
|
41666
41691
|
"node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js"() {
|
|
41667
41692
|
"use strict";
|
|
@@ -41698,6 +41723,7 @@ var init_main = __esm({
|
|
|
41698
41723
|
SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
|
|
41699
41724
|
})(SyntaxKind || (SyntaxKind = {}));
|
|
41700
41725
|
parseTree2 = parseTree;
|
|
41726
|
+
getNodeValue2 = getNodeValue;
|
|
41701
41727
|
(function(ParseErrorCode2) {
|
|
41702
41728
|
ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
|
|
41703
41729
|
ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
|
|
@@ -41720,13 +41746,11 @@ var init_main = __esm({
|
|
|
41720
41746
|
});
|
|
41721
41747
|
|
|
41722
41748
|
// src/core/mcph-parser.ts
|
|
41723
|
-
import * as fs4 from "node:fs";
|
|
41724
|
-
import * as path3 from "node:path";
|
|
41725
41749
|
async function parseMchpConfig(file2, projectRoot, scopeOverride) {
|
|
41726
41750
|
const content = readFileContent(file2.absolutePath);
|
|
41727
41751
|
const scope = scopeOverride ?? detectScope2(file2.relativePath);
|
|
41728
41752
|
const isGitTracked = await checkGitTracked2(file2.absolutePath, projectRoot);
|
|
41729
|
-
const isGitignored = checkGitignored(file2.absolutePath, projectRoot);
|
|
41753
|
+
const isGitignored = await checkGitignored(file2.absolutePath, projectRoot);
|
|
41730
41754
|
const result = {
|
|
41731
41755
|
filePath: file2.absolutePath,
|
|
41732
41756
|
relativePath: file2.relativePath,
|
|
@@ -41753,11 +41777,7 @@ async function parseMchpConfig(file2, projectRoot, scopeOverride) {
|
|
|
41753
41777
|
result.parseErrors.push(".mcph.json must be a JSON object at the root");
|
|
41754
41778
|
return result;
|
|
41755
41779
|
}
|
|
41756
|
-
|
|
41757
|
-
result.raw = JSON.parse(stripComments2(content));
|
|
41758
|
-
} catch {
|
|
41759
|
-
return result;
|
|
41760
|
-
}
|
|
41780
|
+
result.raw = getNodeValue2(tree);
|
|
41761
41781
|
const rootProps = tree.children ?? [];
|
|
41762
41782
|
for (const prop of rootProps) {
|
|
41763
41783
|
if (prop.type !== "property" || !prop.children || prop.children.length < 2) continue;
|
|
@@ -41815,46 +41835,6 @@ function offsetToPosition(content, offset) {
|
|
|
41815
41835
|
}
|
|
41816
41836
|
return { line, column };
|
|
41817
41837
|
}
|
|
41818
|
-
function stripComments2(src) {
|
|
41819
|
-
let out = "";
|
|
41820
|
-
let i2 = 0;
|
|
41821
|
-
let inString = false;
|
|
41822
|
-
let escape2 = false;
|
|
41823
|
-
while (i2 < src.length) {
|
|
41824
|
-
const ch = src[i2];
|
|
41825
|
-
if (inString) {
|
|
41826
|
-
out += ch;
|
|
41827
|
-
if (escape2) {
|
|
41828
|
-
escape2 = false;
|
|
41829
|
-
} else if (ch === "\\") {
|
|
41830
|
-
escape2 = true;
|
|
41831
|
-
} else if (ch === '"') {
|
|
41832
|
-
inString = false;
|
|
41833
|
-
}
|
|
41834
|
-
i2++;
|
|
41835
|
-
continue;
|
|
41836
|
-
}
|
|
41837
|
-
if (ch === '"') {
|
|
41838
|
-
inString = true;
|
|
41839
|
-
out += ch;
|
|
41840
|
-
i2++;
|
|
41841
|
-
continue;
|
|
41842
|
-
}
|
|
41843
|
-
if (ch === "/" && src[i2 + 1] === "/") {
|
|
41844
|
-
while (i2 < src.length && src[i2] !== "\n") i2++;
|
|
41845
|
-
continue;
|
|
41846
|
-
}
|
|
41847
|
-
if (ch === "/" && src[i2 + 1] === "*") {
|
|
41848
|
-
i2 += 2;
|
|
41849
|
-
while (i2 < src.length && !(src[i2] === "*" && src[i2 + 1] === "/")) i2++;
|
|
41850
|
-
i2 += 2;
|
|
41851
|
-
continue;
|
|
41852
|
-
}
|
|
41853
|
-
out += ch;
|
|
41854
|
-
i2++;
|
|
41855
|
-
}
|
|
41856
|
-
return out;
|
|
41857
|
-
}
|
|
41858
41838
|
async function checkGitTracked2(filePath, projectRoot) {
|
|
41859
41839
|
try {
|
|
41860
41840
|
const git = getGit(projectRoot);
|
|
@@ -41864,17 +41844,14 @@ async function checkGitTracked2(filePath, projectRoot) {
|
|
|
41864
41844
|
return false;
|
|
41865
41845
|
}
|
|
41866
41846
|
}
|
|
41867
|
-
function checkGitignored(filePath, projectRoot) {
|
|
41868
|
-
const gitignorePath = path3.join(projectRoot, ".gitignore");
|
|
41869
|
-
let content;
|
|
41847
|
+
async function checkGitignored(filePath, projectRoot) {
|
|
41870
41848
|
try {
|
|
41871
|
-
|
|
41849
|
+
const git = getGit(projectRoot);
|
|
41850
|
+
const result = await git.raw(["check-ignore", "--", filePath]);
|
|
41851
|
+
return result.trim().length > 0;
|
|
41872
41852
|
} catch {
|
|
41873
41853
|
return false;
|
|
41874
41854
|
}
|
|
41875
|
-
const basename5 = path3.basename(filePath);
|
|
41876
|
-
const patterns = content.split(/\r?\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
41877
|
-
return patterns.some((p2) => p2 === basename5 || p2 === `/${basename5}` || p2 === `./${basename5}`);
|
|
41878
41855
|
}
|
|
41879
41856
|
var KNOWN_FIELDS;
|
|
41880
41857
|
var init_mcph_parser = __esm({
|
|
@@ -42111,7 +42088,7 @@ var require_levenshtein = __commonJS({
|
|
|
42111
42088
|
});
|
|
42112
42089
|
|
|
42113
42090
|
// src/core/checks/paths.ts
|
|
42114
|
-
import * as
|
|
42091
|
+
import * as path3 from "node:path";
|
|
42115
42092
|
function getProjectFiles(projectRoot) {
|
|
42116
42093
|
if (cachedProjectFiles?.root === projectRoot) return cachedProjectFiles.files;
|
|
42117
42094
|
const files = getAllProjectFiles(projectRoot);
|
|
@@ -42124,10 +42101,10 @@ function resetPathsCache() {
|
|
|
42124
42101
|
async function checkPaths(file2, projectRoot) {
|
|
42125
42102
|
const issues = [];
|
|
42126
42103
|
const projectFiles = getProjectFiles(projectRoot);
|
|
42127
|
-
const contextDir =
|
|
42104
|
+
const contextDir = path3.dirname(file2.filePath);
|
|
42128
42105
|
for (const ref of file2.references.paths) {
|
|
42129
42106
|
const baseDir = ref.value.startsWith("./") || ref.value.startsWith("../") ? contextDir : projectRoot;
|
|
42130
|
-
const resolvedPath =
|
|
42107
|
+
const resolvedPath = path3.resolve(baseDir, ref.value);
|
|
42131
42108
|
const normalizedRef = ref.value.replace(/\\/g, "/");
|
|
42132
42109
|
if (normalizedRef.includes("*")) {
|
|
42133
42110
|
const matches = await Ze(normalizedRef, { cwd: baseDir, nodir: false });
|
|
@@ -42145,7 +42122,7 @@ async function checkPaths(file2, projectRoot) {
|
|
|
42145
42122
|
}
|
|
42146
42123
|
const isDir = normalizedRef.endsWith("/");
|
|
42147
42124
|
if (isDir) {
|
|
42148
|
-
const dirPath =
|
|
42125
|
+
const dirPath = path3.resolve(baseDir, normalizedRef);
|
|
42149
42126
|
if (!isDirectory(dirPath)) {
|
|
42150
42127
|
issues.push({
|
|
42151
42128
|
severity: "error",
|
|
@@ -42190,12 +42167,12 @@ async function checkPaths(file2, projectRoot) {
|
|
|
42190
42167
|
}
|
|
42191
42168
|
function findClosestMatch(target, files) {
|
|
42192
42169
|
const targetNorm = target.replace(/\\/g, "/");
|
|
42193
|
-
const targetBase =
|
|
42170
|
+
const targetBase = path3.basename(targetNorm);
|
|
42194
42171
|
let bestMatch = null;
|
|
42195
42172
|
let bestDistance = Infinity;
|
|
42196
42173
|
for (const file2 of files) {
|
|
42197
42174
|
const fileNorm = file2.replace(/\\/g, "/");
|
|
42198
|
-
if (
|
|
42175
|
+
if (path3.basename(fileNorm) === targetBase && fileNorm !== targetNorm) {
|
|
42199
42176
|
const dist = levenshtein(targetNorm, fileNorm);
|
|
42200
42177
|
if (dist < bestDistance) {
|
|
42201
42178
|
bestDistance = dist;
|
|
@@ -42229,8 +42206,8 @@ var init_paths = __esm({
|
|
|
42229
42206
|
});
|
|
42230
42207
|
|
|
42231
42208
|
// src/core/checks/commands.ts
|
|
42232
|
-
import * as
|
|
42233
|
-
import * as
|
|
42209
|
+
import * as fs4 from "node:fs";
|
|
42210
|
+
import * as path4 from "node:path";
|
|
42234
42211
|
async function checkCommands(file2, projectRoot) {
|
|
42235
42212
|
const issues = [];
|
|
42236
42213
|
const pkgJson = loadPackageJson(projectRoot);
|
|
@@ -42280,9 +42257,9 @@ async function checkCommands(file2, projectRoot) {
|
|
|
42280
42257
|
...pkgJson.optionalDependencies
|
|
42281
42258
|
};
|
|
42282
42259
|
if (!(pkgName in allDeps)) {
|
|
42283
|
-
const binPath =
|
|
42260
|
+
const binPath = path4.join(projectRoot, "node_modules", ".bin", pkgName);
|
|
42284
42261
|
try {
|
|
42285
|
-
|
|
42262
|
+
fs4.accessSync(binPath);
|
|
42286
42263
|
} catch {
|
|
42287
42264
|
issues.push({
|
|
42288
42265
|
severity: "warning",
|
|
@@ -42328,9 +42305,9 @@ async function checkCommands(file2, projectRoot) {
|
|
|
42328
42305
|
...pkgJson.optionalDependencies
|
|
42329
42306
|
};
|
|
42330
42307
|
if (!(tool in allDeps)) {
|
|
42331
|
-
const binPath =
|
|
42308
|
+
const binPath = path4.join(projectRoot, "node_modules", ".bin", tool);
|
|
42332
42309
|
try {
|
|
42333
|
-
|
|
42310
|
+
fs4.accessSync(binPath);
|
|
42334
42311
|
} catch {
|
|
42335
42312
|
issues.push({
|
|
42336
42313
|
severity: "warning",
|
|
@@ -42347,7 +42324,7 @@ async function checkCommands(file2, projectRoot) {
|
|
|
42347
42324
|
}
|
|
42348
42325
|
function loadMakefile(projectRoot) {
|
|
42349
42326
|
try {
|
|
42350
|
-
return
|
|
42327
|
+
return fs4.readFileSync(path4.join(projectRoot, "Makefile"), "utf-8");
|
|
42351
42328
|
} catch {
|
|
42352
42329
|
return null;
|
|
42353
42330
|
}
|
|
@@ -42368,13 +42345,13 @@ var init_commands = __esm({
|
|
|
42368
42345
|
});
|
|
42369
42346
|
|
|
42370
42347
|
// src/core/checks/staleness.ts
|
|
42371
|
-
import * as
|
|
42348
|
+
import * as path5 from "node:path";
|
|
42372
42349
|
async function checkStaleness(file2, projectRoot) {
|
|
42373
42350
|
const issues = [];
|
|
42374
42351
|
if (!await isGitRepo(projectRoot)) {
|
|
42375
42352
|
return issues;
|
|
42376
42353
|
}
|
|
42377
|
-
const relativePath =
|
|
42354
|
+
const relativePath = path5.relative(projectRoot, file2.filePath).replace(/\\/g, "/");
|
|
42378
42355
|
const lastModified = await getFileLastModified(projectRoot, relativePath);
|
|
42379
42356
|
if (!lastModified || isNaN(lastModified.getTime())) {
|
|
42380
42357
|
return issues;
|
|
@@ -42507,8 +42484,8 @@ var init_tokens2 = __esm({
|
|
|
42507
42484
|
});
|
|
42508
42485
|
|
|
42509
42486
|
// src/core/checks/tier-tokens.ts
|
|
42510
|
-
import * as
|
|
42511
|
-
import * as
|
|
42487
|
+
import * as fs5 from "node:fs";
|
|
42488
|
+
import * as path6 from "node:path";
|
|
42512
42489
|
function hasPathsFrontmatter(content) {
|
|
42513
42490
|
const lines = content.split("\n");
|
|
42514
42491
|
if (lines[0]?.trim() !== "---") return false;
|
|
@@ -42537,8 +42514,8 @@ function isAlwaysLoaded(file2) {
|
|
|
42537
42514
|
if (rel.includes("/rules/")) {
|
|
42538
42515
|
return !hasPathsFrontmatter(file2.content);
|
|
42539
42516
|
}
|
|
42540
|
-
const
|
|
42541
|
-
return ALWAYS_LOADED_BASENAMES.has(
|
|
42517
|
+
const basename4 = rel.split("/").pop() ?? "";
|
|
42518
|
+
return ALWAYS_LOADED_BASENAMES.has(basename4);
|
|
42542
42519
|
}
|
|
42543
42520
|
function computeSectionCosts(file2) {
|
|
42544
42521
|
if (file2.sections.length === 0) return [];
|
|
@@ -42553,14 +42530,14 @@ function computeSectionCosts(file2) {
|
|
|
42553
42530
|
function loadSettingsSources(projectRoot) {
|
|
42554
42531
|
const sources = [];
|
|
42555
42532
|
const candidates = [
|
|
42556
|
-
|
|
42557
|
-
|
|
42558
|
-
|
|
42533
|
+
path6.join(projectRoot, ".claude", "settings.json"),
|
|
42534
|
+
path6.join(projectRoot, ".claude", "settings.local.json"),
|
|
42535
|
+
path6.join(process.env.HOME || process.env.USERPROFILE || "", ".claude", "settings.json")
|
|
42559
42536
|
];
|
|
42560
42537
|
for (const p2 of candidates) {
|
|
42561
42538
|
let content;
|
|
42562
42539
|
try {
|
|
42563
|
-
content =
|
|
42540
|
+
content = fs5.readFileSync(p2, "utf-8");
|
|
42564
42541
|
} catch {
|
|
42565
42542
|
continue;
|
|
42566
42543
|
}
|
|
@@ -42687,7 +42664,7 @@ var init_tier_tokens = __esm({
|
|
|
42687
42664
|
});
|
|
42688
42665
|
|
|
42689
42666
|
// src/core/checks/redundancy.ts
|
|
42690
|
-
import * as
|
|
42667
|
+
import * as path7 from "node:path";
|
|
42691
42668
|
function compilePatterns(allDeps) {
|
|
42692
42669
|
const compiled = [];
|
|
42693
42670
|
for (const [pkg, mentions] of Object.entries(PACKAGE_TECH_MAP)) {
|
|
@@ -42752,7 +42729,7 @@ async function checkRedundancy(file2, projectRoot) {
|
|
|
42752
42729
|
);
|
|
42753
42730
|
if (dirMatch) {
|
|
42754
42731
|
const dir = dirMatch[1].replace(/[`"]/g, "");
|
|
42755
|
-
const fullPath =
|
|
42732
|
+
const fullPath = path7.resolve(projectRoot, dir);
|
|
42756
42733
|
if (isDirectory(fullPath)) {
|
|
42757
42734
|
issues.push({
|
|
42758
42735
|
severity: "info",
|
|
@@ -43621,8 +43598,8 @@ var init_security = __esm({
|
|
|
43621
43598
|
});
|
|
43622
43599
|
|
|
43623
43600
|
// src/core/checks/mcp/commands.ts
|
|
43624
|
-
import * as
|
|
43625
|
-
import * as
|
|
43601
|
+
import * as fs6 from "node:fs";
|
|
43602
|
+
import * as path8 from "node:path";
|
|
43626
43603
|
async function checkMcpCommands(config2, projectRoot) {
|
|
43627
43604
|
const issues = [];
|
|
43628
43605
|
if (config2.parseErrors.length > 0) return issues;
|
|
@@ -43639,7 +43616,7 @@ async function checkMcpCommands(config2, projectRoot) {
|
|
|
43639
43616
|
});
|
|
43640
43617
|
}
|
|
43641
43618
|
if (LOCAL_PATH_PATTERN.test(server2.command)) {
|
|
43642
|
-
const resolved =
|
|
43619
|
+
const resolved = path8.resolve(projectRoot, server2.command);
|
|
43643
43620
|
if (!fileExistsSafe(resolved)) {
|
|
43644
43621
|
issues.push({
|
|
43645
43622
|
severity: "warning",
|
|
@@ -43654,7 +43631,7 @@ async function checkMcpCommands(config2, projectRoot) {
|
|
|
43654
43631
|
for (const arg of server2.args) {
|
|
43655
43632
|
if (URL_PREFIX.test(arg)) continue;
|
|
43656
43633
|
if (LOCAL_PATH_PATTERN.test(arg) || FILE_PATH_PATTERN.test(arg)) {
|
|
43657
|
-
const resolved =
|
|
43634
|
+
const resolved = path8.resolve(projectRoot, arg);
|
|
43658
43635
|
if (!fileExistsSafe(resolved)) {
|
|
43659
43636
|
issues.push({
|
|
43660
43637
|
severity: "warning",
|
|
@@ -43672,7 +43649,7 @@ async function checkMcpCommands(config2, projectRoot) {
|
|
|
43672
43649
|
}
|
|
43673
43650
|
function fileExistsSafe(filePath) {
|
|
43674
43651
|
try {
|
|
43675
|
-
|
|
43652
|
+
fs6.accessSync(filePath);
|
|
43676
43653
|
return true;
|
|
43677
43654
|
} catch {
|
|
43678
43655
|
return false;
|
|
@@ -43826,17 +43803,19 @@ async function checkMcpEnv(config2, _projectRoot) {
|
|
|
43826
43803
|
}
|
|
43827
43804
|
}
|
|
43828
43805
|
}
|
|
43829
|
-
|
|
43830
|
-
const
|
|
43831
|
-
|
|
43832
|
-
|
|
43833
|
-
|
|
43834
|
-
|
|
43835
|
-
|
|
43836
|
-
|
|
43837
|
-
|
|
43838
|
-
|
|
43839
|
-
|
|
43806
|
+
if (config2.client !== "continue") {
|
|
43807
|
+
for (const value of allValues) {
|
|
43808
|
+
const refs = extractEnvVarRefs(value);
|
|
43809
|
+
for (const ref of refs) {
|
|
43810
|
+
if (!(ref.varName in process.env)) {
|
|
43811
|
+
issues.push({
|
|
43812
|
+
severity: "info",
|
|
43813
|
+
check: "mcp-env",
|
|
43814
|
+
ruleId: "unset-variable",
|
|
43815
|
+
line: server2.line,
|
|
43816
|
+
message: `Server "${server2.name}": environment variable "${ref.varName}" is not set`
|
|
43817
|
+
});
|
|
43818
|
+
}
|
|
43840
43819
|
}
|
|
43841
43820
|
}
|
|
43842
43821
|
}
|
|
@@ -44342,27 +44321,18 @@ var init_lists = __esm({
|
|
|
44342
44321
|
});
|
|
44343
44322
|
|
|
44344
44323
|
// src/core/checks/mcph/gitignore.ts
|
|
44345
|
-
import * as
|
|
44324
|
+
import * as path9 from "node:path";
|
|
44346
44325
|
async function checkMcphGitignore(config2, _projectRoot) {
|
|
44347
44326
|
const issues = [];
|
|
44348
44327
|
if (config2.scope === "project-local" && !config2.isGitignored) {
|
|
44349
|
-
const
|
|
44328
|
+
const basename4 = path9.basename(config2.filePath);
|
|
44350
44329
|
issues.push({
|
|
44351
44330
|
severity: "error",
|
|
44352
44331
|
check: "mcph-gitignore",
|
|
44353
44332
|
ruleId: "mcph-config/local-file-not-gitignored",
|
|
44354
44333
|
line: 1,
|
|
44355
|
-
message: `${
|
|
44356
|
-
suggestion: `Add "${
|
|
44357
|
-
fix: {
|
|
44358
|
-
file: path10.join(path10.dirname(config2.filePath), ".gitignore"),
|
|
44359
|
-
line: 0,
|
|
44360
|
-
oldText: "",
|
|
44361
|
-
newText: `
|
|
44362
|
-
# mcph CLI local overrides (machine-specific, never commit)
|
|
44363
|
-
${basename5}
|
|
44364
|
-
`
|
|
44365
|
-
}
|
|
44334
|
+
message: `${basename4} is not covered by .gitignore \u2014 machine-local overrides can leak via git`,
|
|
44335
|
+
suggestion: `Add "${basename4}" to .gitignore in your project root.`
|
|
44366
44336
|
});
|
|
44367
44337
|
}
|
|
44368
44338
|
return issues;
|
|
@@ -44444,7 +44414,7 @@ var init_session_parser = __esm({
|
|
|
44444
44414
|
import { readdir, stat } from "node:fs/promises";
|
|
44445
44415
|
import { createReadStream } from "node:fs";
|
|
44446
44416
|
import { createInterface } from "node:readline";
|
|
44447
|
-
import { dirname as
|
|
44417
|
+
import { dirname as dirname2, join as join5, resolve as resolve4 } from "node:path";
|
|
44448
44418
|
import { existsSync } from "node:fs";
|
|
44449
44419
|
function detectProviders() {
|
|
44450
44420
|
if (!home) return [];
|
|
@@ -44469,7 +44439,7 @@ async function parseJsonlFiltered(filePath, filter) {
|
|
|
44469
44439
|
return results;
|
|
44470
44440
|
}
|
|
44471
44441
|
async function readClaudeHistory() {
|
|
44472
|
-
const historyPath =
|
|
44442
|
+
const historyPath = join5(home, ".claude", "history.jsonl");
|
|
44473
44443
|
return parseJsonlFiltered(historyPath, (entry) => {
|
|
44474
44444
|
if (!entry.display || !entry.project) return null;
|
|
44475
44445
|
return {
|
|
@@ -44482,7 +44452,7 @@ async function readClaudeHistory() {
|
|
|
44482
44452
|
});
|
|
44483
44453
|
}
|
|
44484
44454
|
async function readCodexHistory() {
|
|
44485
|
-
const historyPath =
|
|
44455
|
+
const historyPath = join5(home, ".codex", "history.jsonl");
|
|
44486
44456
|
return parseJsonlFiltered(historyPath, (entry) => {
|
|
44487
44457
|
if (!entry.display && !entry.command) return null;
|
|
44488
44458
|
return {
|
|
@@ -44495,18 +44465,18 @@ async function readCodexHistory() {
|
|
|
44495
44465
|
});
|
|
44496
44466
|
}
|
|
44497
44467
|
async function readClaudeMemories() {
|
|
44498
|
-
const projectsDir =
|
|
44468
|
+
const projectsDir = join5(home, ".claude", "projects");
|
|
44499
44469
|
if (!existsSync(projectsDir)) return [];
|
|
44500
44470
|
const memories = [];
|
|
44501
44471
|
const projectDirs = await readdir(projectsDir).catch(() => []);
|
|
44502
44472
|
for (const projDir of projectDirs) {
|
|
44503
|
-
const memoryDir =
|
|
44473
|
+
const memoryDir = join5(projectsDir, projDir, "memory");
|
|
44504
44474
|
if (!existsSync(memoryDir)) continue;
|
|
44505
44475
|
const files = await readdir(memoryDir).catch(() => []);
|
|
44506
44476
|
for (const file2 of files) {
|
|
44507
44477
|
if (!file2.endsWith(".md") || file2 === "MEMORY.md") continue;
|
|
44508
44478
|
try {
|
|
44509
|
-
const entry = await parseMemoryFile(
|
|
44479
|
+
const entry = await parseMemoryFile(join5(memoryDir, file2), projDir);
|
|
44510
44480
|
memories.push(entry);
|
|
44511
44481
|
} catch {
|
|
44512
44482
|
}
|
|
@@ -44516,14 +44486,14 @@ async function readClaudeMemories() {
|
|
|
44516
44486
|
}
|
|
44517
44487
|
function detectAiderInSiblings(siblings) {
|
|
44518
44488
|
for (const sib of siblings) {
|
|
44519
|
-
if (existsSync(
|
|
44489
|
+
if (existsSync(join5(sib.path, ".aider.chat.history.md"))) {
|
|
44520
44490
|
return "aider";
|
|
44521
44491
|
}
|
|
44522
44492
|
}
|
|
44523
44493
|
return null;
|
|
44524
44494
|
}
|
|
44525
44495
|
async function detectSiblings(projectRoot) {
|
|
44526
|
-
const parentDir =
|
|
44496
|
+
const parentDir = dirname2(resolve4(projectRoot));
|
|
44527
44497
|
let entries;
|
|
44528
44498
|
try {
|
|
44529
44499
|
entries = await readdir(parentDir);
|
|
@@ -44533,7 +44503,7 @@ async function detectSiblings(projectRoot) {
|
|
|
44533
44503
|
const candidates = [];
|
|
44534
44504
|
for (const entry of entries) {
|
|
44535
44505
|
if (entry.startsWith(".") || entry === "node_modules") continue;
|
|
44536
|
-
const fullPath =
|
|
44506
|
+
const fullPath = join5(parentDir, entry);
|
|
44537
44507
|
const entryPath = resolve4(fullPath);
|
|
44538
44508
|
if (entryPath === resolve4(projectRoot)) continue;
|
|
44539
44509
|
try {
|
|
@@ -44542,7 +44512,7 @@ async function detectSiblings(projectRoot) {
|
|
|
44542
44512
|
} catch {
|
|
44543
44513
|
continue;
|
|
44544
44514
|
}
|
|
44545
|
-
const isProject = existsSync(
|
|
44515
|
+
const isProject = existsSync(join5(fullPath, ".git")) || existsSync(join5(fullPath, "package.json")) || existsSync(join5(fullPath, "Cargo.toml")) || existsSync(join5(fullPath, "go.mod")) || existsSync(join5(fullPath, "pyproject.toml"));
|
|
44546
44516
|
if (!isProject) continue;
|
|
44547
44517
|
candidates.push({ fullPath, entryPath, name: entry });
|
|
44548
44518
|
}
|
|
@@ -44556,7 +44526,7 @@ async function detectSiblings(projectRoot) {
|
|
|
44556
44526
|
if (orgMatch) currentOrg = orgMatch[1];
|
|
44557
44527
|
} catch {
|
|
44558
44528
|
}
|
|
44559
|
-
const gitCandidates = candidates.filter((c3) => existsSync(
|
|
44529
|
+
const gitCandidates = candidates.filter((c3) => existsSync(join5(c3.fullPath, ".git")));
|
|
44560
44530
|
const results = await Promise.all(
|
|
44561
44531
|
gitCandidates.map(async (c3) => {
|
|
44562
44532
|
const sibling = { path: c3.entryPath.replace(/\\/g, "/"), name: c3.name };
|
|
@@ -44628,28 +44598,28 @@ var init_session_scanner = __esm({
|
|
|
44628
44598
|
init_session_parser();
|
|
44629
44599
|
home = process.env.HOME || process.env.USERPROFILE || "";
|
|
44630
44600
|
AGENT_DIRS = [
|
|
44631
|
-
{ provider: "claude-code", dir:
|
|
44632
|
-
{ provider: "codex-cli", dir:
|
|
44633
|
-
{ provider: "vibe-cli", dir:
|
|
44601
|
+
{ provider: "claude-code", dir: join5(home, ".claude"), historyFile: "history.jsonl" },
|
|
44602
|
+
{ provider: "codex-cli", dir: join5(home, ".codex"), historyFile: "history.jsonl" },
|
|
44603
|
+
{ provider: "vibe-cli", dir: join5(home, ".vibe") },
|
|
44634
44604
|
{
|
|
44635
44605
|
provider: "amazon-q",
|
|
44636
|
-
dir:
|
|
44606
|
+
dir: join5(home, ".aws", "amazonq")
|
|
44637
44607
|
},
|
|
44638
44608
|
{
|
|
44639
44609
|
provider: "goose",
|
|
44640
|
-
dir: process.platform === "win32" ?
|
|
44610
|
+
dir: process.platform === "win32" ? join5(process.env.APPDATA || "", "Block", "goose") : join5(home, ".config", "goose")
|
|
44641
44611
|
},
|
|
44642
|
-
{ provider: "continue", dir:
|
|
44612
|
+
{ provider: "continue", dir: join5(home, ".continue") },
|
|
44643
44613
|
{
|
|
44644
44614
|
provider: "windsurf",
|
|
44645
|
-
dir:
|
|
44615
|
+
dir: join5(home, ".windsurf")
|
|
44646
44616
|
}
|
|
44647
44617
|
];
|
|
44648
44618
|
}
|
|
44649
44619
|
});
|
|
44650
44620
|
|
|
44651
44621
|
// src/core/checks/session/missing-secret.ts
|
|
44652
|
-
import { resolve as resolve5, basename as
|
|
44622
|
+
import { resolve as resolve5, basename as basename3 } from "node:path";
|
|
44653
44623
|
function normalizePath(p2) {
|
|
44654
44624
|
return resolve5(p2).replace(/\\/g, "/").toLowerCase();
|
|
44655
44625
|
}
|
|
@@ -44673,7 +44643,7 @@ async function checkMissingSecret(ctx) {
|
|
|
44673
44643
|
if (s.repo) byName.get(s.name).add(s.repo);
|
|
44674
44644
|
}
|
|
44675
44645
|
const currentNorm = normalizePath(ctx.currentProject);
|
|
44676
|
-
const currentBase =
|
|
44646
|
+
const currentBase = basename3(currentNorm);
|
|
44677
44647
|
for (const [secretName, projects] of byName) {
|
|
44678
44648
|
const normalizedProjects = [...projects].map(normalizePath);
|
|
44679
44649
|
const currentHas = normalizedProjects.some((p2) => {
|
|
@@ -44684,7 +44654,7 @@ async function checkMissingSecret(ctx) {
|
|
|
44684
44654
|
if (currentHas) continue;
|
|
44685
44655
|
const siblingMatches = ctx.siblings.filter((sib) => {
|
|
44686
44656
|
const sibNorm = normalizePath(sib.path);
|
|
44687
|
-
const sibBase =
|
|
44657
|
+
const sibBase = basename3(sibNorm);
|
|
44688
44658
|
return normalizedProjects.some((p2) => {
|
|
44689
44659
|
if (p2 === sibNorm) return true;
|
|
44690
44660
|
const lastSegment = p2.split("/").pop() || "";
|
|
@@ -44717,25 +44687,28 @@ var init_missing_secret = __esm({
|
|
|
44717
44687
|
|
|
44718
44688
|
// src/core/checks/session/diverged-file.ts
|
|
44719
44689
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
44720
|
-
import { join as
|
|
44690
|
+
import { join as join6 } from "node:path";
|
|
44721
44691
|
import { existsSync as existsSync2 } from "node:fs";
|
|
44722
44692
|
function calculateOverlap(a, b2) {
|
|
44723
|
-
const linesA =
|
|
44693
|
+
const linesA = new Set(
|
|
44694
|
+
a.split("\n").map((l) => l.trim()).filter((l) => l.length > 3)
|
|
44695
|
+
);
|
|
44724
44696
|
const linesB = new Set(
|
|
44725
44697
|
b2.split("\n").map((l) => l.trim()).filter((l) => l.length > 3)
|
|
44726
44698
|
);
|
|
44727
|
-
if (linesA.
|
|
44728
|
-
if (linesA.
|
|
44729
|
-
let
|
|
44699
|
+
if (linesA.size === 0 && linesB.size === 0) return 1;
|
|
44700
|
+
if (linesA.size === 0 || linesB.size === 0) return 0;
|
|
44701
|
+
let intersection2 = 0;
|
|
44730
44702
|
for (const line of linesA) {
|
|
44731
|
-
if (linesB.has(line))
|
|
44703
|
+
if (linesB.has(line)) intersection2++;
|
|
44732
44704
|
}
|
|
44733
|
-
|
|
44705
|
+
const unionSize = linesA.size + linesB.size - intersection2;
|
|
44706
|
+
return intersection2 / unionSize;
|
|
44734
44707
|
}
|
|
44735
44708
|
async function checkDivergedFile(ctx) {
|
|
44736
44709
|
const issues = [];
|
|
44737
44710
|
for (const fileName of CANONICAL_FILES) {
|
|
44738
|
-
const currentPath =
|
|
44711
|
+
const currentPath = join6(ctx.currentProject, fileName);
|
|
44739
44712
|
if (!existsSync2(currentPath)) continue;
|
|
44740
44713
|
let currentContent;
|
|
44741
44714
|
try {
|
|
@@ -44745,7 +44718,7 @@ async function checkDivergedFile(ctx) {
|
|
|
44745
44718
|
}
|
|
44746
44719
|
const diverged = [];
|
|
44747
44720
|
for (const sib of ctx.siblings) {
|
|
44748
|
-
const sibPath =
|
|
44721
|
+
const sibPath = join6(sib.path, fileName);
|
|
44749
44722
|
if (!existsSync2(sibPath)) continue;
|
|
44750
44723
|
try {
|
|
44751
44724
|
const sibContent = await readFile2(sibPath, "utf-8");
|
|
@@ -44791,12 +44764,12 @@ var init_diverged_file = __esm({
|
|
|
44791
44764
|
|
|
44792
44765
|
// src/core/checks/session/missing-workflow.ts
|
|
44793
44766
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
44794
|
-
import { join as
|
|
44767
|
+
import { join as join7 } from "node:path";
|
|
44795
44768
|
import { existsSync as existsSync3 } from "node:fs";
|
|
44796
44769
|
async function checkMissingWorkflow(ctx) {
|
|
44797
44770
|
const issues = [];
|
|
44798
|
-
const currentWorkflowDir =
|
|
44799
|
-
if (!existsSync3(
|
|
44771
|
+
const currentWorkflowDir = join7(ctx.currentProject, ".github", "workflows");
|
|
44772
|
+
if (!existsSync3(join7(ctx.currentProject, ".github"))) return issues;
|
|
44800
44773
|
const currentWorkflows = /* @__PURE__ */ new Set();
|
|
44801
44774
|
if (existsSync3(currentWorkflowDir)) {
|
|
44802
44775
|
try {
|
|
@@ -44809,7 +44782,7 @@ async function checkMissingWorkflow(ctx) {
|
|
|
44809
44782
|
}
|
|
44810
44783
|
const workflowMap = /* @__PURE__ */ new Map();
|
|
44811
44784
|
for (const sib of ctx.siblings) {
|
|
44812
|
-
const sibWorkflowDir =
|
|
44785
|
+
const sibWorkflowDir = join7(sib.path, ".github", "workflows");
|
|
44813
44786
|
if (!existsSync3(sibWorkflowDir)) continue;
|
|
44814
44787
|
try {
|
|
44815
44788
|
const files = await readdir2(sibWorkflowDir);
|
|
@@ -44894,16 +44867,19 @@ var init_stale_memory = __esm({
|
|
|
44894
44867
|
|
|
44895
44868
|
// src/core/checks/session/duplicate-memory.ts
|
|
44896
44869
|
function calculateLineOverlap2(a, b2) {
|
|
44897
|
-
const linesA =
|
|
44870
|
+
const linesA = new Set(
|
|
44871
|
+
a.split("\n").map((l) => l.trim()).filter((l) => l.length > 5)
|
|
44872
|
+
);
|
|
44898
44873
|
const linesB = new Set(
|
|
44899
44874
|
b2.split("\n").map((l) => l.trim()).filter((l) => l.length > 5)
|
|
44900
44875
|
);
|
|
44901
|
-
if (linesA.
|
|
44902
|
-
let
|
|
44876
|
+
if (linesA.size === 0 || linesB.size === 0) return 0;
|
|
44877
|
+
let intersection2 = 0;
|
|
44903
44878
|
for (const line of linesA) {
|
|
44904
|
-
if (linesB.has(line))
|
|
44879
|
+
if (linesB.has(line)) intersection2++;
|
|
44905
44880
|
}
|
|
44906
|
-
|
|
44881
|
+
const unionSize = linesA.size + linesB.size - intersection2;
|
|
44882
|
+
return intersection2 / unionSize;
|
|
44907
44883
|
}
|
|
44908
44884
|
async function checkDuplicateMemory(ctx) {
|
|
44909
44885
|
const issues = [];
|
|
@@ -44913,6 +44889,9 @@ async function checkDuplicateMemory(ctx) {
|
|
|
44913
44889
|
const a = ctx.memories[i2];
|
|
44914
44890
|
const b2 = ctx.memories[j3];
|
|
44915
44891
|
if (a.projectDir === b2.projectDir) continue;
|
|
44892
|
+
const aIsCurrent = projectDirMatchesPath(a.projectDir, ctx.currentProject);
|
|
44893
|
+
const bIsCurrent = projectDirMatchesPath(b2.projectDir, ctx.currentProject);
|
|
44894
|
+
if (!aIsCurrent && !bIsCurrent) continue;
|
|
44916
44895
|
if (a.content.length < 50 || b2.content.length < 50) continue;
|
|
44917
44896
|
const overlap = calculateLineOverlap2(a.content, b2.content);
|
|
44918
44897
|
if (overlap < 0.6) continue;
|
|
@@ -44939,6 +44918,7 @@ async function checkDuplicateMemory(ctx) {
|
|
|
44939
44918
|
var init_duplicate_memory = __esm({
|
|
44940
44919
|
"src/core/checks/session/duplicate-memory.ts"() {
|
|
44941
44920
|
"use strict";
|
|
44921
|
+
init_session_parser();
|
|
44942
44922
|
}
|
|
44943
44923
|
});
|
|
44944
44924
|
|
|
@@ -45010,7 +44990,7 @@ async function checkLoopDetection(ctx) {
|
|
|
45010
44990
|
}
|
|
45011
44991
|
const cycles = findCyclicPatterns(displays);
|
|
45012
44992
|
for (const { cycle, repeats: reps } of cycles) {
|
|
45013
|
-
const cycleStr = cycle.map((c3) => c3.length > 40 ? c3.slice(0, 37) + "..." : c3).join("
|
|
44993
|
+
const cycleStr = cycle.map((c3) => c3.length > 40 ? c3.slice(0, 37) + "..." : c3).join(" -> ");
|
|
45014
44994
|
issues.push({
|
|
45015
44995
|
severity: "warning",
|
|
45016
44996
|
check: "session-loop-detection",
|
|
@@ -45034,12 +45014,12 @@ var init_loop_detection = __esm({
|
|
|
45034
45014
|
|
|
45035
45015
|
// src/core/checks/session/memory-index-overflow.ts
|
|
45036
45016
|
import { readFile as readFile3, stat as stat2 } from "node:fs/promises";
|
|
45037
|
-
import { join as
|
|
45017
|
+
import { join as join8 } from "node:path";
|
|
45038
45018
|
async function checkMemoryIndexOverflow(ctx) {
|
|
45039
45019
|
const home2 = process.env.HOME || process.env.USERPROFILE || "";
|
|
45040
45020
|
if (!home2) return [];
|
|
45041
45021
|
const encoded = encodeProjectDir(ctx.currentProject);
|
|
45042
|
-
const memoryFile =
|
|
45022
|
+
const memoryFile = join8(home2, ".claude", "projects", encoded, "memory", "MEMORY.md");
|
|
45043
45023
|
let stats;
|
|
45044
45024
|
try {
|
|
45045
45025
|
stats = await stat2(memoryFile);
|
|
@@ -45090,10 +45070,10 @@ var init_memory_index_overflow = __esm({
|
|
|
45090
45070
|
|
|
45091
45071
|
// src/core/checks/ci-coverage.ts
|
|
45092
45072
|
import { readdir as readdir3, readFile as readFile4 } from "node:fs/promises";
|
|
45093
|
-
import { join as
|
|
45073
|
+
import { join as join9 } from "node:path";
|
|
45094
45074
|
import { existsSync as existsSync5 } from "node:fs";
|
|
45095
45075
|
async function findReleaseWorkflows(projectRoot) {
|
|
45096
|
-
const workflowDir =
|
|
45076
|
+
const workflowDir = join9(projectRoot, ".github", "workflows");
|
|
45097
45077
|
if (!existsSync5(workflowDir)) return [];
|
|
45098
45078
|
let files;
|
|
45099
45079
|
try {
|
|
@@ -45109,7 +45089,7 @@ async function findReleaseWorkflows(projectRoot) {
|
|
|
45109
45089
|
continue;
|
|
45110
45090
|
}
|
|
45111
45091
|
try {
|
|
45112
|
-
const content = await readFile4(
|
|
45092
|
+
const content = await readFile4(join9(workflowDir, f), "utf-8");
|
|
45113
45093
|
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
45114
45094
|
if (nameMatch && RELEASE_FILENAME_PATTERNS.some((p2) => p2.test(nameMatch[1]))) {
|
|
45115
45095
|
releaseWorkflows.push(f);
|
|
@@ -45164,10 +45144,10 @@ var init_ci_coverage = __esm({
|
|
|
45164
45144
|
|
|
45165
45145
|
// src/core/checks/ci-secrets.ts
|
|
45166
45146
|
import { readdir as readdir4, readFile as readFile5 } from "node:fs/promises";
|
|
45167
|
-
import { join as
|
|
45147
|
+
import { join as join10 } from "node:path";
|
|
45168
45148
|
import { existsSync as existsSync6 } from "node:fs";
|
|
45169
45149
|
async function findSecretUsages(projectRoot) {
|
|
45170
|
-
const workflowDir =
|
|
45150
|
+
const workflowDir = join10(projectRoot, ".github", "workflows");
|
|
45171
45151
|
if (!existsSync6(workflowDir)) return [];
|
|
45172
45152
|
let files;
|
|
45173
45153
|
try {
|
|
@@ -45180,7 +45160,7 @@ async function findSecretUsages(projectRoot) {
|
|
|
45180
45160
|
if (!(f.endsWith(".yml") || f.endsWith(".yaml"))) continue;
|
|
45181
45161
|
let content;
|
|
45182
45162
|
try {
|
|
45183
|
-
content = await readFile5(
|
|
45163
|
+
content = await readFile5(join10(workflowDir, f), "utf-8");
|
|
45184
45164
|
} catch {
|
|
45185
45165
|
continue;
|
|
45186
45166
|
}
|
|
@@ -45197,7 +45177,7 @@ async function findSecretUsages(projectRoot) {
|
|
|
45197
45177
|
}
|
|
45198
45178
|
function contextMentionsSecret(files, secretName) {
|
|
45199
45179
|
const escaped = secretName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
45200
|
-
const pattern = new RegExp(escaped.replace(/_/g, "[_\\s-]
|
|
45180
|
+
const pattern = new RegExp(`\\b${escaped.replace(/_/g, "[_\\s-]")}\\b`, "i");
|
|
45201
45181
|
return files.some((f) => pattern.test(f.content));
|
|
45202
45182
|
}
|
|
45203
45183
|
async function checkCiSecrets(files, projectRoot) {
|
|
@@ -45237,14 +45217,14 @@ var init_ci_secrets = __esm({
|
|
|
45237
45217
|
});
|
|
45238
45218
|
|
|
45239
45219
|
// src/version.ts
|
|
45240
|
-
import { readFileSync as
|
|
45241
|
-
import { resolve as resolve8, dirname as
|
|
45220
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
45221
|
+
import { resolve as resolve8, dirname as dirname3 } from "node:path";
|
|
45242
45222
|
import { fileURLToPath } from "node:url";
|
|
45243
45223
|
function loadVersion() {
|
|
45244
|
-
if (true) return "0.9.
|
|
45245
|
-
const __dir =
|
|
45224
|
+
if (true) return "0.9.19";
|
|
45225
|
+
const __dir = dirname3(fileURLToPath(import.meta.url));
|
|
45246
45226
|
const pkgPath = resolve8(__dir, "../package.json");
|
|
45247
|
-
const pkg = JSON.parse(
|
|
45227
|
+
const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
|
|
45248
45228
|
return pkg.version;
|
|
45249
45229
|
}
|
|
45250
45230
|
var VERSION;
|
|
@@ -46138,7 +46118,7 @@ var init_source = __esm({
|
|
|
46138
46118
|
});
|
|
46139
46119
|
|
|
46140
46120
|
// src/core/fixer.ts
|
|
46141
|
-
import * as
|
|
46121
|
+
import * as fs7 from "node:fs";
|
|
46142
46122
|
function applyFixes(result, options = {}) {
|
|
46143
46123
|
const log = options.quiet ? () => {
|
|
46144
46124
|
} : console.log.bind(console);
|
|
@@ -46180,16 +46160,17 @@ function applyFixes(result, options = {}) {
|
|
|
46180
46160
|
let totalFixes = 0;
|
|
46181
46161
|
const filesModified = [];
|
|
46182
46162
|
for (const [filePath, fixes] of fixesByFile) {
|
|
46183
|
-
const content =
|
|
46163
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
46184
46164
|
const lines = content.split("\n");
|
|
46185
46165
|
let modified = false;
|
|
46186
|
-
const sortedFixes = [...fixes].sort((a, b2) => b2.line - a.line);
|
|
46187
46166
|
const fixesByLine = /* @__PURE__ */ new Map();
|
|
46188
|
-
for (const fix of
|
|
46167
|
+
for (const fix of fixes) {
|
|
46189
46168
|
const existing = fixesByLine.get(fix.line) || [];
|
|
46190
46169
|
existing.push(fix);
|
|
46191
46170
|
fixesByLine.set(fix.line, existing);
|
|
46192
46171
|
}
|
|
46172
|
+
let perFileFixCount = 0;
|
|
46173
|
+
const perFileLogs = [];
|
|
46193
46174
|
for (const [lineNum, lineFixes] of fixesByLine) {
|
|
46194
46175
|
const lineIdx = lineNum - 1;
|
|
46195
46176
|
if (lineIdx < 0 || lineIdx >= lines.length) continue;
|
|
@@ -46197,10 +46178,10 @@ function applyFixes(result, options = {}) {
|
|
|
46197
46178
|
for (const fix of lineFixes) {
|
|
46198
46179
|
if (line.includes(fix.oldText)) {
|
|
46199
46180
|
line = line.replaceAll(fix.oldText, fix.newText);
|
|
46200
|
-
|
|
46181
|
+
perFileFixCount++;
|
|
46201
46182
|
const prefix = dryRun ? source_default.cyan(" Would fix") : source_default.green(" Fixed");
|
|
46202
|
-
|
|
46203
|
-
prefix + ` Line ${fix.line}: ${source_default.dim(fix.oldText)} ${source_default.dim("
|
|
46183
|
+
perFileLogs.push(
|
|
46184
|
+
prefix + ` Line ${fix.line}: ${source_default.dim(fix.oldText)} ${source_default.dim("->")} ${fix.newText}`
|
|
46204
46185
|
);
|
|
46205
46186
|
}
|
|
46206
46187
|
}
|
|
@@ -46220,9 +46201,11 @@ function applyFixes(result, options = {}) {
|
|
|
46220
46201
|
}
|
|
46221
46202
|
}
|
|
46222
46203
|
if (!dryRun) {
|
|
46223
|
-
|
|
46204
|
+
fs7.writeFileSync(filePath, newContent, "utf-8");
|
|
46224
46205
|
}
|
|
46225
46206
|
filesModified.push(filePath);
|
|
46207
|
+
totalFixes += perFileFixCount;
|
|
46208
|
+
for (const m of perFileLogs) log(m);
|
|
46226
46209
|
}
|
|
46227
46210
|
}
|
|
46228
46211
|
return { totalFixes, filesModified };
|
|
@@ -46236,13 +46219,13 @@ var init_fixer = __esm({
|
|
|
46236
46219
|
|
|
46237
46220
|
// src/mcp/server.ts
|
|
46238
46221
|
var server_exports = {};
|
|
46239
|
-
import * as
|
|
46222
|
+
import * as path10 from "node:path";
|
|
46240
46223
|
function validateProjectPath(rawPath) {
|
|
46241
46224
|
if (!rawPath) return process.cwd();
|
|
46242
46225
|
if (PATH_DISALLOWED.test(rawPath)) {
|
|
46243
46226
|
throw new Error("projectPath contains disallowed characters");
|
|
46244
46227
|
}
|
|
46245
|
-
const resolved =
|
|
46228
|
+
const resolved = path10.resolve(rawPath);
|
|
46246
46229
|
if (!isDirectory(resolved)) {
|
|
46247
46230
|
throw new Error("projectPath is not an existing directory");
|
|
46248
46231
|
}
|
|
@@ -46253,7 +46236,7 @@ function validateFilePathInput(rawPath) {
|
|
|
46253
46236
|
throw new Error("path contains disallowed characters");
|
|
46254
46237
|
}
|
|
46255
46238
|
}
|
|
46256
|
-
var contextCheckEnum, mcpCheckEnum, sessionCheckEnum, PATH_DISALLOWED, server, transport;
|
|
46239
|
+
var contextCheckEnum, mcpCheckEnum, mcphCheckEnum, sessionCheckEnum, PATH_DISALLOWED, server, transport;
|
|
46257
46240
|
var init_server3 = __esm({
|
|
46258
46241
|
async "src/mcp/server.ts"() {
|
|
46259
46242
|
"use strict";
|
|
@@ -46272,6 +46255,7 @@ var init_server3 = __esm({
|
|
|
46272
46255
|
init_version2();
|
|
46273
46256
|
contextCheckEnum = external_exports3.enum(ALL_CHECKS);
|
|
46274
46257
|
mcpCheckEnum = external_exports3.enum(ALL_MCP_CHECKS);
|
|
46258
|
+
mcphCheckEnum = external_exports3.enum(ALL_MCPH_CHECKS);
|
|
46275
46259
|
sessionCheckEnum = external_exports3.enum(ALL_SESSION_CHECKS);
|
|
46276
46260
|
PATH_DISALLOWED = /[\n\r\t;`|]|\$\(|\$\{/;
|
|
46277
46261
|
server = new McpServer({
|
|
@@ -46328,7 +46312,7 @@ var init_server3 = __esm({
|
|
|
46328
46312
|
try {
|
|
46329
46313
|
validateFilePathInput(filePath);
|
|
46330
46314
|
const root = validateProjectPath(projectPath);
|
|
46331
|
-
const resolved =
|
|
46315
|
+
const resolved = path10.resolve(root, filePath);
|
|
46332
46316
|
const result = {
|
|
46333
46317
|
path: filePath,
|
|
46334
46318
|
exists: fileExists(resolved) || isDirectory(resolved)
|
|
@@ -46493,6 +46477,48 @@ var init_server3 = __esm({
|
|
|
46493
46477
|
}
|
|
46494
46478
|
}
|
|
46495
46479
|
);
|
|
46480
|
+
server.tool(
|
|
46481
|
+
"ctxlint_mcph_audit",
|
|
46482
|
+
"Lint .mcph.json (the @yawlabs/mcph CLI config) files. Checks for PAT (mcp_pat_*) leakage in git-tracked project-scope files, environment-variable posture, plaintext HTTP apiBase to public hosts, schema drift, allow/deny list conflicts and duplicates, and machine-local override files not covered by .gitignore. Distinct from ctxlint_mcp_audit, which lints client-side .mcp.json server lists.",
|
|
46483
|
+
{
|
|
46484
|
+
projectPath: external_exports3.string().optional().describe("Path to the project root. Defaults to current working directory."),
|
|
46485
|
+
checks: external_exports3.array(mcphCheckEnum).optional().describe("Specific mcph checks to run (default: all mcph-* checks)."),
|
|
46486
|
+
includeGlobal: external_exports3.boolean().optional().describe("Also scan ~/.mcph.json (user-global config)."),
|
|
46487
|
+
strictEnvToken: external_exports3.boolean().optional().describe(
|
|
46488
|
+
"Upgrade mcph-config/prefer-env-token from warning to error (env-var-only posture)."
|
|
46489
|
+
)
|
|
46490
|
+
},
|
|
46491
|
+
{
|
|
46492
|
+
readOnlyHint: true,
|
|
46493
|
+
destructiveHint: false,
|
|
46494
|
+
idempotentHint: true,
|
|
46495
|
+
openWorldHint: false
|
|
46496
|
+
},
|
|
46497
|
+
async ({ projectPath, checks, includeGlobal, strictEnvToken }) => {
|
|
46498
|
+
try {
|
|
46499
|
+
const root = validateProjectPath(projectPath);
|
|
46500
|
+
const activeChecks = checks?.length ? checks : ALL_MCPH_CHECKS;
|
|
46501
|
+
const result = await runAudit(root, activeChecks, {
|
|
46502
|
+
mcph: true,
|
|
46503
|
+
mcphOnly: true,
|
|
46504
|
+
mcphGlobal: includeGlobal || false,
|
|
46505
|
+
mcphStrictEnvToken: strictEnvToken || false
|
|
46506
|
+
});
|
|
46507
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
46508
|
+
} catch (err) {
|
|
46509
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
46510
|
+
return {
|
|
46511
|
+
content: [{ type: "text", text: JSON.stringify({ error: msg }) }],
|
|
46512
|
+
isError: true
|
|
46513
|
+
};
|
|
46514
|
+
} finally {
|
|
46515
|
+
freeEncoder();
|
|
46516
|
+
resetGit();
|
|
46517
|
+
resetPathsCache();
|
|
46518
|
+
resetPackageJsonCache();
|
|
46519
|
+
}
|
|
46520
|
+
}
|
|
46521
|
+
);
|
|
46496
46522
|
server.tool(
|
|
46497
46523
|
"ctxlint_session_audit",
|
|
46498
46524
|
"Audit AI agent session data for cross-project consistency. Checks for missing GitHub secrets, diverged config files, missing workflows, stale memory entries, and duplicate memories across sibling repositories.",
|
|
@@ -47698,8 +47724,8 @@ var require_command = __commonJS({
|
|
|
47698
47724
|
"node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/command.js"(exports) {
|
|
47699
47725
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
47700
47726
|
var childProcess = __require("node:child_process");
|
|
47701
|
-
var
|
|
47702
|
-
var
|
|
47727
|
+
var path13 = __require("node:path");
|
|
47728
|
+
var fs10 = __require("node:fs");
|
|
47703
47729
|
var process11 = __require("node:process");
|
|
47704
47730
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
47705
47731
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -48693,7 +48719,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
48693
48719
|
* @param {string} subcommandName
|
|
48694
48720
|
*/
|
|
48695
48721
|
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
|
|
48696
|
-
if (
|
|
48722
|
+
if (fs10.existsSync(executableFile)) return;
|
|
48697
48723
|
const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
|
|
48698
48724
|
const executableMissing = `'${executableFile}' does not exist
|
|
48699
48725
|
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
@@ -48711,11 +48737,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
48711
48737
|
let launchWithNode = false;
|
|
48712
48738
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
48713
48739
|
function findFile(baseDir, baseName) {
|
|
48714
|
-
const localBin =
|
|
48715
|
-
if (
|
|
48716
|
-
if (sourceExt.includes(
|
|
48740
|
+
const localBin = path13.resolve(baseDir, baseName);
|
|
48741
|
+
if (fs10.existsSync(localBin)) return localBin;
|
|
48742
|
+
if (sourceExt.includes(path13.extname(baseName))) return void 0;
|
|
48717
48743
|
const foundExt = sourceExt.find(
|
|
48718
|
-
(ext) =>
|
|
48744
|
+
(ext) => fs10.existsSync(`${localBin}${ext}`)
|
|
48719
48745
|
);
|
|
48720
48746
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
48721
48747
|
return void 0;
|
|
@@ -48727,21 +48753,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
48727
48753
|
if (this._scriptPath) {
|
|
48728
48754
|
let resolvedScriptPath;
|
|
48729
48755
|
try {
|
|
48730
|
-
resolvedScriptPath =
|
|
48756
|
+
resolvedScriptPath = fs10.realpathSync(this._scriptPath);
|
|
48731
48757
|
} catch {
|
|
48732
48758
|
resolvedScriptPath = this._scriptPath;
|
|
48733
48759
|
}
|
|
48734
|
-
executableDir =
|
|
48735
|
-
|
|
48760
|
+
executableDir = path13.resolve(
|
|
48761
|
+
path13.dirname(resolvedScriptPath),
|
|
48736
48762
|
executableDir
|
|
48737
48763
|
);
|
|
48738
48764
|
}
|
|
48739
48765
|
if (executableDir) {
|
|
48740
48766
|
let localFile = findFile(executableDir, executableFile);
|
|
48741
48767
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
48742
|
-
const legacyName =
|
|
48768
|
+
const legacyName = path13.basename(
|
|
48743
48769
|
this._scriptPath,
|
|
48744
|
-
|
|
48770
|
+
path13.extname(this._scriptPath)
|
|
48745
48771
|
);
|
|
48746
48772
|
if (legacyName !== this._name) {
|
|
48747
48773
|
localFile = findFile(
|
|
@@ -48752,7 +48778,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
48752
48778
|
}
|
|
48753
48779
|
executableFile = localFile || executableFile;
|
|
48754
48780
|
}
|
|
48755
|
-
launchWithNode = sourceExt.includes(
|
|
48781
|
+
launchWithNode = sourceExt.includes(path13.extname(executableFile));
|
|
48756
48782
|
let proc;
|
|
48757
48783
|
if (process11.platform !== "win32") {
|
|
48758
48784
|
if (launchWithNode) {
|
|
@@ -49667,7 +49693,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
49667
49693
|
* @return {Command}
|
|
49668
49694
|
*/
|
|
49669
49695
|
nameFromFilename(filename) {
|
|
49670
|
-
this._name =
|
|
49696
|
+
this._name = path13.basename(filename, path13.extname(filename));
|
|
49671
49697
|
return this;
|
|
49672
49698
|
}
|
|
49673
49699
|
/**
|
|
@@ -49681,9 +49707,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
49681
49707
|
* @param {string} [path]
|
|
49682
49708
|
* @return {(string|null|Command)}
|
|
49683
49709
|
*/
|
|
49684
|
-
executableDir(
|
|
49685
|
-
if (
|
|
49686
|
-
this._executableDir =
|
|
49710
|
+
executableDir(path14) {
|
|
49711
|
+
if (path14 === void 0) return this._executableDir;
|
|
49712
|
+
this._executableDir = path14;
|
|
49687
49713
|
return this;
|
|
49688
49714
|
}
|
|
49689
49715
|
/**
|
|
@@ -53008,6 +53034,24 @@ var init_ora = __esm({
|
|
|
53008
53034
|
});
|
|
53009
53035
|
|
|
53010
53036
|
// src/core/reporter.ts
|
|
53037
|
+
function classifyFile(f) {
|
|
53038
|
+
if (f.path === "(mcp)") return "mcp";
|
|
53039
|
+
if (f.path.includes("session audit")) return "session";
|
|
53040
|
+
for (const issue2 of f.issues) {
|
|
53041
|
+
if (issue2.check.startsWith("session-")) return "session";
|
|
53042
|
+
if (issue2.check.startsWith("mcph-")) return "mcph";
|
|
53043
|
+
if (issue2.check.startsWith("mcp-")) return "mcp";
|
|
53044
|
+
}
|
|
53045
|
+
const norm = f.path.replace(/\\/g, "/");
|
|
53046
|
+
if (norm.endsWith(".mcph.json") || norm.endsWith(".mcph.local.json")) return "mcph";
|
|
53047
|
+
if (norm === ".mcp.json" || norm.endsWith("/.mcp.json") || norm.endsWith("/mcp.json") || norm.includes("/mcpServers/") || norm.endsWith("/.claude.json") || norm.endsWith(".claude/settings.json") || norm.endsWith("claude_desktop_config.json")) {
|
|
53048
|
+
return "mcp";
|
|
53049
|
+
}
|
|
53050
|
+
return "context";
|
|
53051
|
+
}
|
|
53052
|
+
function isSyntheticBucket(p2) {
|
|
53053
|
+
return p2.startsWith("(") || p2.includes("session audit");
|
|
53054
|
+
}
|
|
53011
53055
|
function formatText(result, verbose = false) {
|
|
53012
53056
|
const lines = [];
|
|
53013
53057
|
lines.push("");
|
|
@@ -53015,30 +53059,45 @@ function formatText(result, verbose = false) {
|
|
|
53015
53059
|
lines.push("");
|
|
53016
53060
|
lines.push(`Scanning ${result.projectRoot}...`);
|
|
53017
53061
|
lines.push("");
|
|
53018
|
-
const
|
|
53019
|
-
|
|
53020
|
-
|
|
53062
|
+
const groups = {
|
|
53063
|
+
context: [],
|
|
53064
|
+
mcp: [],
|
|
53065
|
+
mcph: [],
|
|
53066
|
+
session: []
|
|
53067
|
+
};
|
|
53068
|
+
for (const f of result.files) {
|
|
53069
|
+
groups[classifyFile(f)].push(f);
|
|
53070
|
+
}
|
|
53021
53071
|
const totalTokens = result.summary.totalTokens;
|
|
53022
|
-
|
|
53072
|
+
let renderedAnySummary = false;
|
|
53073
|
+
const contextReal = groups.context.filter((f) => !isSyntheticBucket(f.path));
|
|
53074
|
+
if (contextReal.length > 0) {
|
|
53023
53075
|
lines.push(
|
|
53024
|
-
`Found ${
|
|
53076
|
+
`Found ${contextReal.length} context file${contextReal.length !== 1 ? "s" : ""} (${totalTokens.toLocaleString()} tokens total)`
|
|
53025
53077
|
);
|
|
53026
|
-
for (const file2 of
|
|
53078
|
+
for (const file2 of contextReal) {
|
|
53027
53079
|
let desc = ` ${file2.path} (${file2.tokens.toLocaleString()} tokens, ${file2.lines} lines)`;
|
|
53028
53080
|
if (file2.isSymlink && file2.symlinkTarget) {
|
|
53029
|
-
desc = ` ${file2.path} ${source_default.dim(
|
|
53081
|
+
desc = ` ${file2.path} ${source_default.dim(`-> ${file2.symlinkTarget} (symlink)`)}`;
|
|
53030
53082
|
}
|
|
53031
53083
|
lines.push(desc);
|
|
53032
53084
|
}
|
|
53085
|
+
renderedAnySummary = true;
|
|
53033
53086
|
}
|
|
53034
|
-
|
|
53035
|
-
|
|
53036
|
-
|
|
53037
|
-
|
|
53038
|
-
|
|
53039
|
-
}
|
|
53087
|
+
for (const g of ["mcp", "mcph"]) {
|
|
53088
|
+
const real = groups[g].filter((f) => !isSyntheticBucket(f.path));
|
|
53089
|
+
if (real.length === 0) continue;
|
|
53090
|
+
if (renderedAnySummary) lines.push("");
|
|
53091
|
+
lines.push(`Found ${real.length} ${GROUP_SUMMARY_NOUNS[g]}${real.length !== 1 ? "s" : ""}`);
|
|
53092
|
+
for (const file2 of real) lines.push(` ${file2.path}`);
|
|
53093
|
+
renderedAnySummary = true;
|
|
53040
53094
|
}
|
|
53041
|
-
if (
|
|
53095
|
+
if (groups.session.length > 0) {
|
|
53096
|
+
if (renderedAnySummary) lines.push("");
|
|
53097
|
+
lines.push("Session audit scanned");
|
|
53098
|
+
renderedAnySummary = true;
|
|
53099
|
+
}
|
|
53100
|
+
if (!renderedAnySummary) {
|
|
53042
53101
|
lines.push(`Found ${result.files.length} file${result.files.length !== 1 ? "s" : ""}`);
|
|
53043
53102
|
}
|
|
53044
53103
|
lines.push("");
|
|
@@ -53048,7 +53107,7 @@ function formatText(result, verbose = false) {
|
|
|
53048
53107
|
if (fileIssues.length === 0 && !verbose) continue;
|
|
53049
53108
|
lines.push(source_default.underline(file2.path));
|
|
53050
53109
|
if (fileIssues.length === 0) {
|
|
53051
|
-
lines.push(source_default.green("
|
|
53110
|
+
lines.push(source_default.green(" [ok] All checks passed"));
|
|
53052
53111
|
} else {
|
|
53053
53112
|
for (const issue2 of fileIssues) {
|
|
53054
53113
|
lines.push(formatIssue(issue2));
|
|
@@ -53057,16 +53116,13 @@ function formatText(result, verbose = false) {
|
|
|
53057
53116
|
lines.push("");
|
|
53058
53117
|
}
|
|
53059
53118
|
};
|
|
53060
|
-
|
|
53061
|
-
|
|
53062
|
-
|
|
53063
|
-
|
|
53064
|
-
|
|
53065
|
-
|
|
53066
|
-
|
|
53067
|
-
if (mcpWithIssues.length > 0) {
|
|
53068
|
-
lines.push(source_default.bold("MCP Configs"));
|
|
53069
|
-
renderFileGroup(mcpFiles);
|
|
53119
|
+
const groupsToRender = GROUP_ORDER.filter(
|
|
53120
|
+
(g) => groups[g].some((f) => f.issues.length > 0 || verbose)
|
|
53121
|
+
);
|
|
53122
|
+
if (groupsToRender.length > 1) {
|
|
53123
|
+
for (const g of groupsToRender) {
|
|
53124
|
+
lines.push(source_default.bold(GROUP_LABELS[g]));
|
|
53125
|
+
renderFileGroup(groups[g]);
|
|
53070
53126
|
}
|
|
53071
53127
|
} else {
|
|
53072
53128
|
renderFileGroup(result.files);
|
|
@@ -53103,13 +53159,13 @@ function formatTokenReport(result) {
|
|
|
53103
53159
|
lines.push(
|
|
53104
53160
|
` ${source_default.dim("File".padEnd(maxPathLen))} ${source_default.dim("Tokens".padStart(8))} ${source_default.dim("Lines".padStart(6))}`
|
|
53105
53161
|
);
|
|
53106
|
-
lines.push(` ${"
|
|
53162
|
+
lines.push(` ${"-".repeat(maxPathLen)} ${"-".repeat(8)} ${"-".repeat(6)}`);
|
|
53107
53163
|
for (const file2 of result.files) {
|
|
53108
53164
|
const tokenStr = file2.tokens.toLocaleString().padStart(8);
|
|
53109
53165
|
const lineStr = file2.lines.toString().padStart(6);
|
|
53110
53166
|
lines.push(` ${file2.path.padEnd(maxPathLen)} ${tokenStr} ${lineStr}`);
|
|
53111
53167
|
}
|
|
53112
|
-
lines.push(` ${"
|
|
53168
|
+
lines.push(` ${"-".repeat(maxPathLen)} ${"-".repeat(8)} ${"-".repeat(6)}`);
|
|
53113
53169
|
lines.push(
|
|
53114
53170
|
` ${"Total".padEnd(maxPathLen)} ${result.summary.totalTokens.toLocaleString().padStart(8)}`
|
|
53115
53171
|
);
|
|
@@ -53282,6 +53338,31 @@ function buildRuleDescriptors() {
|
|
|
53282
53338
|
shortDescription: { text: "Redundant MCP config entry" },
|
|
53283
53339
|
helpUri: "https://github.com/yawlabs/ctxlint#mcp-config-linting"
|
|
53284
53340
|
},
|
|
53341
|
+
{
|
|
53342
|
+
id: "ctxlint/mcph-token-security",
|
|
53343
|
+
shortDescription: { text: "mcp.hosting PAT leakage or env-var posture" },
|
|
53344
|
+
helpUri: "https://github.com/yawlabs/ctxlint#mcph-config-linting"
|
|
53345
|
+
},
|
|
53346
|
+
{
|
|
53347
|
+
id: "ctxlint/mcph-apibase",
|
|
53348
|
+
shortDescription: { text: "mcph apiBase URL validation" },
|
|
53349
|
+
helpUri: "https://github.com/yawlabs/ctxlint#mcph-config-linting"
|
|
53350
|
+
},
|
|
53351
|
+
{
|
|
53352
|
+
id: "ctxlint/mcph-schema-conformance",
|
|
53353
|
+
shortDescription: { text: "mcph config unknown field or stale schema version" },
|
|
53354
|
+
helpUri: "https://github.com/yawlabs/ctxlint#mcph-config-linting"
|
|
53355
|
+
},
|
|
53356
|
+
{
|
|
53357
|
+
id: "ctxlint/mcph-lists",
|
|
53358
|
+
shortDescription: { text: "mcph allow/deny list conflict or duplicate entry" },
|
|
53359
|
+
helpUri: "https://github.com/yawlabs/ctxlint#mcph-config-linting"
|
|
53360
|
+
},
|
|
53361
|
+
{
|
|
53362
|
+
id: "ctxlint/mcph-gitignore",
|
|
53363
|
+
shortDescription: { text: "mcph machine-local file not covered by .gitignore" },
|
|
53364
|
+
helpUri: "https://github.com/yawlabs/ctxlint#mcph-config-linting"
|
|
53365
|
+
},
|
|
53285
53366
|
{
|
|
53286
53367
|
id: "ctxlint/session-missing-secret",
|
|
53287
53368
|
shortDescription: { text: "GitHub secret set on sibling repos but missing here" },
|
|
@@ -53322,12 +53403,12 @@ function buildRuleDescriptors() {
|
|
|
53322
53403
|
];
|
|
53323
53404
|
}
|
|
53324
53405
|
function formatIssue(issue2) {
|
|
53325
|
-
const icon = issue2.severity === "error" ? source_default.red("
|
|
53406
|
+
const icon = issue2.severity === "error" ? source_default.red("x") : issue2.severity === "warning" ? source_default.yellow("!") : source_default.blue("i");
|
|
53326
53407
|
const lineRef = issue2.line > 0 ? `Line ${issue2.line}: ` : "";
|
|
53327
53408
|
let line = ` ${icon} ${lineRef}${issue2.message}`;
|
|
53328
53409
|
if (issue2.suggestion) {
|
|
53329
53410
|
line += `
|
|
53330
|
-
${source_default.dim("
|
|
53411
|
+
${source_default.dim("->")} ${source_default.dim(issue2.suggestion)}`;
|
|
53331
53412
|
}
|
|
53332
53413
|
if (issue2.detail) {
|
|
53333
53414
|
line += `
|
|
@@ -53335,16 +53416,30 @@ function formatIssue(issue2) {
|
|
|
53335
53416
|
}
|
|
53336
53417
|
return line;
|
|
53337
53418
|
}
|
|
53419
|
+
var GROUP_ORDER, GROUP_LABELS, GROUP_SUMMARY_NOUNS;
|
|
53338
53420
|
var init_reporter = __esm({
|
|
53339
53421
|
"src/core/reporter.ts"() {
|
|
53340
53422
|
"use strict";
|
|
53341
53423
|
init_source();
|
|
53424
|
+
GROUP_ORDER = ["context", "mcp", "mcph", "session"];
|
|
53425
|
+
GROUP_LABELS = {
|
|
53426
|
+
context: "Context Files",
|
|
53427
|
+
mcp: "MCP Configs",
|
|
53428
|
+
mcph: "mcph Configs",
|
|
53429
|
+
session: "Session Audit"
|
|
53430
|
+
};
|
|
53431
|
+
GROUP_SUMMARY_NOUNS = {
|
|
53432
|
+
context: "context file",
|
|
53433
|
+
mcp: "MCP config",
|
|
53434
|
+
mcph: "mcph config",
|
|
53435
|
+
session: "session audit"
|
|
53436
|
+
};
|
|
53342
53437
|
}
|
|
53343
53438
|
});
|
|
53344
53439
|
|
|
53345
53440
|
// src/core/config.ts
|
|
53346
|
-
import * as
|
|
53347
|
-
import * as
|
|
53441
|
+
import * as fs8 from "node:fs";
|
|
53442
|
+
import * as path11 from "node:path";
|
|
53348
53443
|
function formatJsonError(content, err) {
|
|
53349
53444
|
const msg = err instanceof Error ? err.message : String(err);
|
|
53350
53445
|
const posMatch = msg.match(/position (\d+)/);
|
|
@@ -53415,33 +53510,46 @@ function warnUnknownKeys(config2, source) {
|
|
|
53415
53510
|
console.error(`Warning: unknown config key "${k3}" in ${source}${suggestion}`);
|
|
53416
53511
|
}
|
|
53417
53512
|
}
|
|
53513
|
+
function parseConfigContent(content, source) {
|
|
53514
|
+
let parsed;
|
|
53515
|
+
try {
|
|
53516
|
+
parsed = JSON.parse(content);
|
|
53517
|
+
} catch (err) {
|
|
53518
|
+
throw new Error(`Invalid JSON in ${source}: ${formatJsonError(content, err)}`, {
|
|
53519
|
+
cause: err
|
|
53520
|
+
});
|
|
53521
|
+
}
|
|
53522
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
53523
|
+
throw new Error(
|
|
53524
|
+
`Invalid config in ${source}: expected a JSON object at the root, got ${Array.isArray(parsed) ? "an array" : typeof parsed}`
|
|
53525
|
+
);
|
|
53526
|
+
}
|
|
53527
|
+
warnUnknownKeys(parsed, source);
|
|
53528
|
+
return parsed;
|
|
53529
|
+
}
|
|
53418
53530
|
function loadConfig(projectRoot) {
|
|
53419
53531
|
for (const filename of CONFIG_FILENAMES) {
|
|
53420
|
-
const filePath =
|
|
53532
|
+
const filePath = path11.join(projectRoot, filename);
|
|
53421
53533
|
let content;
|
|
53422
53534
|
try {
|
|
53423
|
-
content =
|
|
53535
|
+
content = fs8.readFileSync(filePath, "utf-8");
|
|
53424
53536
|
} catch {
|
|
53425
53537
|
continue;
|
|
53426
53538
|
}
|
|
53427
|
-
|
|
53428
|
-
try {
|
|
53429
|
-
parsed = JSON.parse(content);
|
|
53430
|
-
} catch (err) {
|
|
53431
|
-
throw new Error(`Invalid JSON in ${filePath}: ${formatJsonError(content, err)}`, {
|
|
53432
|
-
cause: err
|
|
53433
|
-
});
|
|
53434
|
-
}
|
|
53435
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
53436
|
-
throw new Error(
|
|
53437
|
-
`Invalid config in ${filePath}: expected a JSON object at the root, got ${Array.isArray(parsed) ? "an array" : typeof parsed}`
|
|
53438
|
-
);
|
|
53439
|
-
}
|
|
53440
|
-
warnUnknownKeys(parsed, filePath);
|
|
53441
|
-
return parsed;
|
|
53539
|
+
return parseConfigContent(content, filePath);
|
|
53442
53540
|
}
|
|
53443
53541
|
return null;
|
|
53444
53542
|
}
|
|
53543
|
+
function loadConfigFromExplicitPath(configPath) {
|
|
53544
|
+
let content;
|
|
53545
|
+
try {
|
|
53546
|
+
content = fs8.readFileSync(configPath, "utf-8");
|
|
53547
|
+
} catch (err) {
|
|
53548
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
53549
|
+
throw new Error(`could not load config from ${configPath}: ${detail}`, { cause: err });
|
|
53550
|
+
}
|
|
53551
|
+
return parseConfigContent(content, configPath);
|
|
53552
|
+
}
|
|
53445
53553
|
var import_fast_levenshtein2, levenshtein2, KNOWN_CONFIG_KEYS, CONFIG_FILENAMES;
|
|
53446
53554
|
var init_config2 = __esm({
|
|
53447
53555
|
"src/core/config.ts"() {
|
|
@@ -53455,7 +53563,14 @@ var init_config2 = __esm({
|
|
|
53455
53563
|
"tokenThresholds",
|
|
53456
53564
|
"contextFiles",
|
|
53457
53565
|
"mcp",
|
|
53458
|
-
"
|
|
53566
|
+
"mcpOnly",
|
|
53567
|
+
"mcpGlobal",
|
|
53568
|
+
"mcph",
|
|
53569
|
+
"mcphOnly",
|
|
53570
|
+
"mcphGlobal",
|
|
53571
|
+
"mcphStrictEnvToken",
|
|
53572
|
+
"session",
|
|
53573
|
+
"sessionOnly"
|
|
53459
53574
|
];
|
|
53460
53575
|
CONFIG_FILENAMES = [".ctxlintrc", ".ctxlintrc.json"];
|
|
53461
53576
|
}
|
|
@@ -53466,8 +53581,8 @@ var cli_exports = {};
|
|
|
53466
53581
|
__export(cli_exports, {
|
|
53467
53582
|
runCli: () => runCli
|
|
53468
53583
|
});
|
|
53469
|
-
import * as
|
|
53470
|
-
import * as
|
|
53584
|
+
import * as fs9 from "node:fs";
|
|
53585
|
+
import * as path12 from "node:path";
|
|
53471
53586
|
function validateCheckNames(names, source) {
|
|
53472
53587
|
const invalid = names.filter((n7) => n7 && !VALID_CHECKS.has(n7));
|
|
53473
53588
|
if (invalid.length > 0) {
|
|
@@ -53490,75 +53605,8 @@ async function runCli() {
|
|
|
53490
53605
|
"Upgrade mcph-config/prefer-env-token from warning to error (strict env-var-only posture)",
|
|
53491
53606
|
false
|
|
53492
53607
|
).option("--session", "Run session audit checks (cross-project consistency)", false).option("--session-only", "Run only session checks, skip context and MCP checks", false).option("--watch", "Re-lint on context file changes", false).action(async (projectPath, opts) => {
|
|
53493
|
-
const resolvedPath =
|
|
53494
|
-
const
|
|
53495
|
-
const config2 = configPath ? loadConfigFromPath(configPath) : loadConfig(resolvedPath);
|
|
53496
|
-
const mcpGlobal = opts.mcpGlobal || false;
|
|
53497
|
-
const mcpOnly = opts.mcpOnly || false;
|
|
53498
|
-
const mcpFlag = opts.mcp || mcpGlobal || mcpOnly || config2?.mcp || false;
|
|
53499
|
-
const mcphGlobal = opts.mcphGlobal || false;
|
|
53500
|
-
const mcphOnly = opts.mcphOnly || false;
|
|
53501
|
-
const mcphFlag = opts.mcph || mcphGlobal || mcphOnly || false;
|
|
53502
|
-
const mcphStrictEnvToken = opts.mcphStrictEnvToken || false;
|
|
53503
|
-
const sessionFlag = opts.session || false;
|
|
53504
|
-
const sessionOnly = opts.sessionOnly || false;
|
|
53505
|
-
let explicitChecks = opts.checks ? validateCheckNames(
|
|
53506
|
-
opts.checks.split(",").map((c3) => c3.trim()),
|
|
53507
|
-
"--checks"
|
|
53508
|
-
) : null;
|
|
53509
|
-
if (explicitChecks?.length === 0) explicitChecks = null;
|
|
53510
|
-
const hasMcpInChecks = explicitChecks?.some((c3) => c3.startsWith("mcp-")) || false;
|
|
53511
|
-
const hasMcphInChecks = explicitChecks?.some((c3) => c3.startsWith("mcph-")) || false;
|
|
53512
|
-
const hasSessionInChecks = explicitChecks?.some((c3) => c3.startsWith("session-")) || false;
|
|
53513
|
-
const effectiveMcp = mcpFlag || hasMcpInChecks;
|
|
53514
|
-
const effectiveMcph = mcphFlag || hasMcphInChecks;
|
|
53515
|
-
const effectiveSession = sessionFlag || sessionOnly || hasSessionInChecks;
|
|
53516
|
-
let checks;
|
|
53517
|
-
if (explicitChecks) {
|
|
53518
|
-
checks = explicitChecks;
|
|
53519
|
-
} else if (sessionOnly) {
|
|
53520
|
-
checks = ALL_SESSION_CHECKS;
|
|
53521
|
-
} else if (mcpOnly) {
|
|
53522
|
-
checks = ALL_MCP_CHECKS;
|
|
53523
|
-
} else if (mcphOnly) {
|
|
53524
|
-
checks = ALL_MCPH_CHECKS;
|
|
53525
|
-
} else {
|
|
53526
|
-
const base = config2?.checks || ALL_CHECKS;
|
|
53527
|
-
checks = [
|
|
53528
|
-
...base,
|
|
53529
|
-
...effectiveMcp ? ALL_MCP_CHECKS : [],
|
|
53530
|
-
...effectiveMcph ? ALL_MCPH_CHECKS : [],
|
|
53531
|
-
...effectiveSession ? ALL_SESSION_CHECKS : []
|
|
53532
|
-
];
|
|
53533
|
-
}
|
|
53534
|
-
const options = {
|
|
53535
|
-
projectPath: resolvedPath,
|
|
53536
|
-
checks,
|
|
53537
|
-
strict: opts.strict || config2?.strict || false,
|
|
53538
|
-
format: opts.format,
|
|
53539
|
-
verbose: opts.verbose,
|
|
53540
|
-
fix: opts.fix,
|
|
53541
|
-
ignore: opts.ignore ? validateCheckNames(
|
|
53542
|
-
opts.ignore.split(",").map((c3) => c3.trim()),
|
|
53543
|
-
"--ignore"
|
|
53544
|
-
) : config2?.ignore || [],
|
|
53545
|
-
tokensOnly: opts.tokens,
|
|
53546
|
-
quiet: opts.quiet,
|
|
53547
|
-
depth: Math.max(0, Math.min(parseInt(opts.depth, 10) || 2, 10)),
|
|
53548
|
-
mcp: effectiveMcp,
|
|
53549
|
-
mcpOnly,
|
|
53550
|
-
mcpGlobal: mcpGlobal || config2?.mcpGlobal || false,
|
|
53551
|
-
mcph: effectiveMcph,
|
|
53552
|
-
mcphOnly,
|
|
53553
|
-
mcphGlobal,
|
|
53554
|
-
mcphStrictEnvToken,
|
|
53555
|
-
session: effectiveSession,
|
|
53556
|
-
sessionOnly
|
|
53557
|
-
};
|
|
53558
|
-
if (config2?.tokenThresholds) {
|
|
53559
|
-
setTokenThresholds(config2.tokenThresholds);
|
|
53560
|
-
}
|
|
53561
|
-
const activeChecks = options.checks.filter((c3) => !options.ignore.includes(c3));
|
|
53608
|
+
const resolvedPath = path12.resolve(projectPath);
|
|
53609
|
+
const { config: config2, options, activeChecks } = resolveSession(resolvedPath, opts);
|
|
53562
53610
|
const spinner = options.format === "text" && !options.quiet ? ora("Scanning for context files...").start() : void 0;
|
|
53563
53611
|
try {
|
|
53564
53612
|
if (spinner) spinner.text = "Running checks...";
|
|
@@ -53672,34 +53720,43 @@ Fixed ${applied.totalFixes} issue${applied.totalFixes !== 1 ? "s" : ""} in ${app
|
|
|
53672
53720
|
const chalk2 = (await Promise.resolve().then(() => (init_source(), source_exports))).default;
|
|
53673
53721
|
console.log(chalk2.dim("\nWatching for changes... (Ctrl+C to stop)\n"));
|
|
53674
53722
|
const watchPaths = [
|
|
53675
|
-
|
|
53676
|
-
|
|
53677
|
-
|
|
53678
|
-
|
|
53679
|
-
|
|
53680
|
-
|
|
53681
|
-
|
|
53682
|
-
|
|
53683
|
-
|
|
53684
|
-
|
|
53685
|
-
|
|
53686
|
-
|
|
53687
|
-
|
|
53688
|
-
|
|
53689
|
-
|
|
53723
|
+
path12.join(resolvedPath, "CLAUDE.md"),
|
|
53724
|
+
path12.join(resolvedPath, "CLAUDE.local.md"),
|
|
53725
|
+
path12.join(resolvedPath, "AGENTS.md"),
|
|
53726
|
+
path12.join(resolvedPath, "AGENT.md"),
|
|
53727
|
+
path12.join(resolvedPath, ".cursorrules"),
|
|
53728
|
+
path12.join(resolvedPath, ".windsurfrules"),
|
|
53729
|
+
path12.join(resolvedPath, ".clinerules"),
|
|
53730
|
+
path12.join(resolvedPath, ".aiderules"),
|
|
53731
|
+
path12.join(resolvedPath, ".continuerules"),
|
|
53732
|
+
path12.join(resolvedPath, ".rules"),
|
|
53733
|
+
path12.join(resolvedPath, ".goosehints"),
|
|
53734
|
+
path12.join(resolvedPath, "GEMINI.md"),
|
|
53735
|
+
path12.join(resolvedPath, "replit.md"),
|
|
53736
|
+
path12.join(resolvedPath, "package.json"),
|
|
53737
|
+
path12.join(resolvedPath, ".mcp.json"),
|
|
53738
|
+
// mcph configs — without these, edits to the .mcph.json the user is
|
|
53739
|
+
// actively iterating on don't trigger a re-lint.
|
|
53740
|
+
path12.join(resolvedPath, ".mcph.json"),
|
|
53741
|
+
path12.join(resolvedPath, ".mcph.local.json"),
|
|
53742
|
+
// ctxlint config — re-resolve on edit so threshold changes,
|
|
53743
|
+
// ignore-list edits, and check-list overrides take effect without
|
|
53744
|
+
// restarting the watcher.
|
|
53745
|
+
path12.join(resolvedPath, ".ctxlintrc"),
|
|
53746
|
+
path12.join(resolvedPath, ".ctxlintrc.json")
|
|
53690
53747
|
];
|
|
53691
53748
|
const watchDirs = [
|
|
53692
|
-
|
|
53693
|
-
|
|
53694
|
-
|
|
53695
|
-
|
|
53696
|
-
|
|
53697
|
-
|
|
53698
|
-
|
|
53699
|
-
|
|
53700
|
-
|
|
53701
|
-
|
|
53702
|
-
|
|
53749
|
+
path12.join(resolvedPath, ".claude"),
|
|
53750
|
+
path12.join(resolvedPath, ".cursor"),
|
|
53751
|
+
path12.join(resolvedPath, ".github"),
|
|
53752
|
+
path12.join(resolvedPath, ".windsurf"),
|
|
53753
|
+
path12.join(resolvedPath, ".aide"),
|
|
53754
|
+
path12.join(resolvedPath, ".amazonq"),
|
|
53755
|
+
path12.join(resolvedPath, ".goose"),
|
|
53756
|
+
path12.join(resolvedPath, ".junie"),
|
|
53757
|
+
path12.join(resolvedPath, ".aiassistant"),
|
|
53758
|
+
path12.join(resolvedPath, ".continue"),
|
|
53759
|
+
path12.join(resolvedPath, ".vscode")
|
|
53703
53760
|
];
|
|
53704
53761
|
const watchers = [];
|
|
53705
53762
|
let debounceTimer = null;
|
|
@@ -53707,30 +53764,46 @@ Fixed ${applied.totalFixes} issue${applied.totalFixes !== 1 ? "s" : ""} in ${app
|
|
|
53707
53764
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
53708
53765
|
debounceTimer = setTimeout(async () => {
|
|
53709
53766
|
if (process.stdout.isTTY) console.clear();
|
|
53767
|
+
let liveConfig = config2;
|
|
53768
|
+
let liveOptions = options;
|
|
53769
|
+
let liveActiveChecks = activeChecks;
|
|
53770
|
+
try {
|
|
53771
|
+
const resolved = resolveSession(resolvedPath, opts);
|
|
53772
|
+
liveConfig = resolved.config;
|
|
53773
|
+
liveOptions = resolved.options;
|
|
53774
|
+
liveActiveChecks = resolved.activeChecks;
|
|
53775
|
+
} catch (err) {
|
|
53776
|
+
console.error("Error reloading config:", err instanceof Error ? err.message : err);
|
|
53777
|
+
}
|
|
53710
53778
|
try {
|
|
53711
|
-
|
|
53712
|
-
|
|
53713
|
-
|
|
53714
|
-
|
|
53715
|
-
|
|
53716
|
-
|
|
53717
|
-
|
|
53718
|
-
|
|
53719
|
-
|
|
53720
|
-
|
|
53721
|
-
|
|
53722
|
-
|
|
53779
|
+
if (liveConfig?.tokenThresholds) {
|
|
53780
|
+
setTokenThresholds(liveConfig.tokenThresholds);
|
|
53781
|
+
} else {
|
|
53782
|
+
resetTokenThresholds();
|
|
53783
|
+
}
|
|
53784
|
+
const result = await runAudit(resolvedPath, liveActiveChecks, {
|
|
53785
|
+
depth: liveOptions.depth,
|
|
53786
|
+
extraPatterns: liveConfig?.contextFiles,
|
|
53787
|
+
mcp: liveOptions.mcp,
|
|
53788
|
+
mcpGlobal: liveOptions.mcpGlobal,
|
|
53789
|
+
mcpOnly: liveOptions.mcpOnly,
|
|
53790
|
+
mcph: liveOptions.mcph,
|
|
53791
|
+
mcphGlobal: liveOptions.mcphGlobal,
|
|
53792
|
+
mcphOnly: liveOptions.mcphOnly,
|
|
53793
|
+
mcphStrictEnvToken: liveOptions.mcphStrictEnvToken,
|
|
53794
|
+
session: liveOptions.session,
|
|
53795
|
+
sessionOnly: liveOptions.sessionOnly
|
|
53723
53796
|
});
|
|
53724
53797
|
if (result.files.length === 0) {
|
|
53725
53798
|
console.log("\nNo context files found.\n");
|
|
53726
|
-
} else if (
|
|
53799
|
+
} else if (liveOptions.tokensOnly) {
|
|
53727
53800
|
console.log(formatTokenReport(result));
|
|
53728
|
-
} else if (
|
|
53801
|
+
} else if (liveOptions.format === "json") {
|
|
53729
53802
|
console.log(formatJson(result));
|
|
53730
|
-
} else if (
|
|
53803
|
+
} else if (liveOptions.format === "sarif") {
|
|
53731
53804
|
console.log(formatSarif(result));
|
|
53732
53805
|
} else {
|
|
53733
|
-
console.log(formatText(result,
|
|
53806
|
+
console.log(formatText(result, liveOptions.verbose));
|
|
53734
53807
|
}
|
|
53735
53808
|
} catch (err) {
|
|
53736
53809
|
console.error("Error:", err instanceof Error ? err.message : err);
|
|
@@ -53740,20 +53813,19 @@ Fixed ${applied.totalFixes} issue${applied.totalFixes !== 1 ? "s" : ""} in ${app
|
|
|
53740
53813
|
resetPathsCache();
|
|
53741
53814
|
resetPackageJsonCache();
|
|
53742
53815
|
resetTokenThresholds();
|
|
53743
|
-
if (config2?.tokenThresholds) setTokenThresholds(config2.tokenThresholds);
|
|
53744
53816
|
}
|
|
53745
53817
|
console.log(chalk2.dim("\nWatching for changes... (Ctrl+C to stop)\n"));
|
|
53746
53818
|
}, 300);
|
|
53747
53819
|
};
|
|
53748
53820
|
for (const filePath of watchPaths) {
|
|
53749
53821
|
try {
|
|
53750
|
-
watchers.push(
|
|
53822
|
+
watchers.push(fs9.watch(filePath, rerun));
|
|
53751
53823
|
} catch {
|
|
53752
53824
|
}
|
|
53753
53825
|
}
|
|
53754
53826
|
for (const dir of watchDirs) {
|
|
53755
53827
|
try {
|
|
53756
|
-
watchers.push(
|
|
53828
|
+
watchers.push(fs9.watch(dir, { recursive: true }, rerun));
|
|
53757
53829
|
} catch {
|
|
53758
53830
|
}
|
|
53759
53831
|
}
|
|
@@ -53774,17 +53846,17 @@ Fixed ${applied.totalFixes} issue${applied.totalFixes !== 1 ? "s" : ""} in ${app
|
|
|
53774
53846
|
}
|
|
53775
53847
|
});
|
|
53776
53848
|
program2.command("init").description("Set up a git pre-commit hook that runs ctxlint --strict").argument("[path]", "Project directory", ".").action(async (projectPath) => {
|
|
53777
|
-
const resolvedRoot =
|
|
53778
|
-
const gitDir =
|
|
53779
|
-
const hooksDir =
|
|
53780
|
-
if (!
|
|
53849
|
+
const resolvedRoot = path12.resolve(projectPath);
|
|
53850
|
+
const gitDir = path12.join(resolvedRoot, ".git");
|
|
53851
|
+
const hooksDir = path12.join(gitDir, "hooks");
|
|
53852
|
+
if (!fs9.existsSync(gitDir)) {
|
|
53781
53853
|
console.error('Error: not a git repository. Run "git init" first.');
|
|
53782
53854
|
process.exit(1);
|
|
53783
53855
|
}
|
|
53784
|
-
if (!
|
|
53785
|
-
|
|
53856
|
+
if (!fs9.existsSync(hooksDir)) {
|
|
53857
|
+
fs9.mkdirSync(hooksDir, { recursive: true });
|
|
53786
53858
|
}
|
|
53787
|
-
const hookPath =
|
|
53859
|
+
const hookPath = path12.join(hooksDir, "pre-commit");
|
|
53788
53860
|
const fullHookContent = `#!/bin/sh
|
|
53789
53861
|
# ctxlint pre-commit hook
|
|
53790
53862
|
npx @yawlabs/ctxlint@${VERSION} --strict
|
|
@@ -53793,16 +53865,16 @@ npx @yawlabs/ctxlint@${VERSION} --strict
|
|
|
53793
53865
|
# ctxlint pre-commit hook
|
|
53794
53866
|
npx @yawlabs/ctxlint@${VERSION} --strict
|
|
53795
53867
|
`;
|
|
53796
|
-
if (
|
|
53797
|
-
const existing =
|
|
53868
|
+
if (fs9.existsSync(hookPath)) {
|
|
53869
|
+
const existing = fs9.readFileSync(hookPath, "utf-8");
|
|
53798
53870
|
if (existing.includes("ctxlint")) {
|
|
53799
53871
|
console.log("Pre-commit hook already includes ctxlint.");
|
|
53800
53872
|
return;
|
|
53801
53873
|
}
|
|
53802
|
-
|
|
53874
|
+
fs9.appendFileSync(hookPath, appendHookContent);
|
|
53803
53875
|
console.log("Added ctxlint to existing pre-commit hook.");
|
|
53804
53876
|
} else {
|
|
53805
|
-
|
|
53877
|
+
fs9.writeFileSync(hookPath, fullHookContent, { mode: 493 });
|
|
53806
53878
|
console.log("Created pre-commit hook at .git/hooks/pre-commit");
|
|
53807
53879
|
}
|
|
53808
53880
|
console.log("ctxlint will now run automatically before each commit.");
|
|
@@ -53819,13 +53891,83 @@ async function promptYesNo(question) {
|
|
|
53819
53891
|
rl.close();
|
|
53820
53892
|
}
|
|
53821
53893
|
}
|
|
53894
|
+
function resolveSession(resolvedPath, opts) {
|
|
53895
|
+
const configPath = opts.config ? path12.resolve(opts.config) : void 0;
|
|
53896
|
+
const config2 = configPath ? loadConfigFromPath(configPath) : loadConfig(resolvedPath);
|
|
53897
|
+
const mcpGlobal = opts.mcpGlobal || config2?.mcpGlobal || false;
|
|
53898
|
+
const mcpOnly = opts.mcpOnly || config2?.mcpOnly || false;
|
|
53899
|
+
const mcpFlag = opts.mcp || mcpGlobal || mcpOnly || config2?.mcp || false;
|
|
53900
|
+
const mcphGlobal = opts.mcphGlobal || config2?.mcphGlobal || false;
|
|
53901
|
+
const mcphOnly = opts.mcphOnly || config2?.mcphOnly || false;
|
|
53902
|
+
const mcphFlag = opts.mcph || mcphGlobal || mcphOnly || config2?.mcph || false;
|
|
53903
|
+
const mcphStrictEnvToken = opts.mcphStrictEnvToken || config2?.mcphStrictEnvToken || false;
|
|
53904
|
+
const sessionOnly = opts.sessionOnly || config2?.sessionOnly || false;
|
|
53905
|
+
const sessionFlag = opts.session || sessionOnly || config2?.session || false;
|
|
53906
|
+
let explicitChecks = opts.checks ? validateCheckNames(
|
|
53907
|
+
opts.checks.split(",").map((c3) => c3.trim()),
|
|
53908
|
+
"--checks"
|
|
53909
|
+
) : null;
|
|
53910
|
+
if (explicitChecks?.length === 0) explicitChecks = null;
|
|
53911
|
+
const hasMcpInChecks = explicitChecks?.some((c3) => c3.startsWith("mcp-") && !c3.startsWith("mcph-")) || false;
|
|
53912
|
+
const hasMcphInChecks = explicitChecks?.some((c3) => c3.startsWith("mcph-")) || false;
|
|
53913
|
+
const hasSessionInChecks = explicitChecks?.some((c3) => c3.startsWith("session-")) || false;
|
|
53914
|
+
const effectiveMcp = mcpFlag || hasMcpInChecks;
|
|
53915
|
+
const effectiveMcph = mcphFlag || hasMcphInChecks;
|
|
53916
|
+
const effectiveSession = sessionFlag || sessionOnly || hasSessionInChecks;
|
|
53917
|
+
let checks;
|
|
53918
|
+
if (explicitChecks) {
|
|
53919
|
+
checks = explicitChecks;
|
|
53920
|
+
} else if (sessionOnly) {
|
|
53921
|
+
checks = ALL_SESSION_CHECKS;
|
|
53922
|
+
} else if (mcpOnly) {
|
|
53923
|
+
checks = ALL_MCP_CHECKS;
|
|
53924
|
+
} else if (mcphOnly) {
|
|
53925
|
+
checks = ALL_MCPH_CHECKS;
|
|
53926
|
+
} else {
|
|
53927
|
+
const base = config2?.checks || ALL_CHECKS;
|
|
53928
|
+
checks = [
|
|
53929
|
+
...base,
|
|
53930
|
+
...effectiveMcp ? ALL_MCP_CHECKS : [],
|
|
53931
|
+
...effectiveMcph ? ALL_MCPH_CHECKS : [],
|
|
53932
|
+
...effectiveSession ? ALL_SESSION_CHECKS : []
|
|
53933
|
+
];
|
|
53934
|
+
}
|
|
53935
|
+
const options = {
|
|
53936
|
+
projectPath: resolvedPath,
|
|
53937
|
+
checks,
|
|
53938
|
+
strict: opts.strict || config2?.strict || false,
|
|
53939
|
+
format: opts.format,
|
|
53940
|
+
verbose: opts.verbose,
|
|
53941
|
+
fix: opts.fix,
|
|
53942
|
+
ignore: opts.ignore ? validateCheckNames(
|
|
53943
|
+
opts.ignore.split(",").map((c3) => c3.trim()),
|
|
53944
|
+
"--ignore"
|
|
53945
|
+
) : config2?.ignore || [],
|
|
53946
|
+
tokensOnly: opts.tokens,
|
|
53947
|
+
quiet: opts.quiet,
|
|
53948
|
+
depth: Math.max(0, Math.min(parseInt(opts.depth, 10) || 2, 10)),
|
|
53949
|
+
mcp: effectiveMcp,
|
|
53950
|
+
mcpOnly,
|
|
53951
|
+
mcpGlobal,
|
|
53952
|
+
mcph: effectiveMcph,
|
|
53953
|
+
mcphOnly,
|
|
53954
|
+
mcphGlobal,
|
|
53955
|
+
mcphStrictEnvToken,
|
|
53956
|
+
session: effectiveSession,
|
|
53957
|
+
sessionOnly
|
|
53958
|
+
};
|
|
53959
|
+
if (config2?.tokenThresholds) {
|
|
53960
|
+
setTokenThresholds(config2.tokenThresholds);
|
|
53961
|
+
}
|
|
53962
|
+
const activeChecks = options.checks.filter((c3) => !options.ignore.includes(c3));
|
|
53963
|
+
return { config: config2, options, activeChecks };
|
|
53964
|
+
}
|
|
53822
53965
|
function loadConfigFromPath(configPath) {
|
|
53823
53966
|
try {
|
|
53824
|
-
|
|
53825
|
-
return JSON.parse(content);
|
|
53967
|
+
return loadConfigFromExplicitPath(configPath);
|
|
53826
53968
|
} catch (err) {
|
|
53827
53969
|
const detail = err instanceof Error ? err.message : String(err);
|
|
53828
|
-
console.error(`Error:
|
|
53970
|
+
console.error(`Error: ${detail}`);
|
|
53829
53971
|
process.exit(2);
|
|
53830
53972
|
}
|
|
53831
53973
|
}
|