@yawlabs/ctxlint 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pre-commit-hooks.yaml +1 -1
- package/AGENT_SESSION_LINT_SPEC.md +34 -2
- package/CONTEXT_LINT_SPEC.md +782 -746
- package/README.md +2 -2
- package/agent-session-lint-rules.json +10 -0
- package/context-lint-rules.json +20 -0
- package/dist/index.js +960 -319
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1330,8 +1330,8 @@ var require_semaphore = __commonJS({
|
|
|
1330
1330
|
this._waiting = [];
|
|
1331
1331
|
}
|
|
1332
1332
|
lock(thunk) {
|
|
1333
|
-
return new Promise((
|
|
1334
|
-
this._waiting.push({ thunk, resolve:
|
|
1333
|
+
return new Promise((resolve19, reject) => {
|
|
1334
|
+
this._waiting.push({ thunk, resolve: resolve19, reject });
|
|
1335
1335
|
this.runNext();
|
|
1336
1336
|
});
|
|
1337
1337
|
}
|
|
@@ -2960,9 +2960,9 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
2960
2960
|
if (typeof cancellationStrategy.sender.enableCancellation === "function") {
|
|
2961
2961
|
cancellationStrategy.sender.enableCancellation(requestMessage);
|
|
2962
2962
|
}
|
|
2963
|
-
return new Promise(async (
|
|
2963
|
+
return new Promise(async (resolve19, reject) => {
|
|
2964
2964
|
const resolveWithCleanup = (r2) => {
|
|
2965
|
-
|
|
2965
|
+
resolve19(r2);
|
|
2966
2966
|
cancellationStrategy.sender.cleanup(id);
|
|
2967
2967
|
disposable?.dispose();
|
|
2968
2968
|
};
|
|
@@ -8089,7 +8089,7 @@ var require_server = __commonJS({
|
|
|
8089
8089
|
exports.createConnection = createConnection2;
|
|
8090
8090
|
var vscode_languageserver_protocol_1 = require_api2();
|
|
8091
8091
|
var Is3 = __importStar(require_is());
|
|
8092
|
-
var
|
|
8092
|
+
var UUID2 = __importStar(require_uuid());
|
|
8093
8093
|
var progress_1 = require_progress();
|
|
8094
8094
|
var configuration_1 = require_configuration();
|
|
8095
8095
|
var workspaceFolder_1 = require_workspaceFolder();
|
|
@@ -8231,7 +8231,7 @@ var require_server = __commonJS({
|
|
|
8231
8231
|
if (this._registered.has(method)) {
|
|
8232
8232
|
throw new Error(`${method} is already added to this registration`);
|
|
8233
8233
|
}
|
|
8234
|
-
const id =
|
|
8234
|
+
const id = UUID2.generateUuid();
|
|
8235
8235
|
this._registrations.push({
|
|
8236
8236
|
id,
|
|
8237
8237
|
method,
|
|
@@ -8325,7 +8325,7 @@ var require_server = __commonJS({
|
|
|
8325
8325
|
}
|
|
8326
8326
|
registerSingle1(unregistration, type, registerOptions) {
|
|
8327
8327
|
const method = Is3.string(type) ? type : type.method;
|
|
8328
|
-
const id =
|
|
8328
|
+
const id = UUID2.generateUuid();
|
|
8329
8329
|
const params = {
|
|
8330
8330
|
registrations: [{ id, method, registerOptions: registerOptions || {} }]
|
|
8331
8331
|
};
|
|
@@ -8342,7 +8342,7 @@ var require_server = __commonJS({
|
|
|
8342
8342
|
}
|
|
8343
8343
|
registerSingle2(type, registerOptions) {
|
|
8344
8344
|
const method = Is3.string(type) ? type : type.method;
|
|
8345
|
-
const id =
|
|
8345
|
+
const id = UUID2.generateUuid();
|
|
8346
8346
|
const params = {
|
|
8347
8347
|
registrations: [{ id, method, registerOptions: registerOptions || {} }]
|
|
8348
8348
|
};
|
|
@@ -8590,8 +8590,8 @@ var require_server = __commonJS({
|
|
|
8590
8590
|
if (value instanceof Promise) {
|
|
8591
8591
|
return value;
|
|
8592
8592
|
} else if (Is3.thenable(value)) {
|
|
8593
|
-
return new Promise((
|
|
8594
|
-
value.then((resolved) =>
|
|
8593
|
+
return new Promise((resolve19, reject) => {
|
|
8594
|
+
value.then((resolved) => resolve19(resolved), (error52) => reject(error52));
|
|
8595
8595
|
});
|
|
8596
8596
|
} else {
|
|
8597
8597
|
return Promise.resolve(value);
|
|
@@ -8873,13 +8873,13 @@ var require_files = __commonJS({
|
|
|
8873
8873
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8874
8874
|
exports.FileSystem = void 0;
|
|
8875
8875
|
exports.uriToFilePath = uriToFilePath;
|
|
8876
|
-
exports.resolve =
|
|
8876
|
+
exports.resolve = resolve19;
|
|
8877
8877
|
exports.resolveGlobalNodePath = resolveGlobalNodePath;
|
|
8878
8878
|
exports.resolveGlobalYarnPath = resolveGlobalYarnPath;
|
|
8879
8879
|
exports.resolveModulePath = resolveModulePath;
|
|
8880
8880
|
var url2 = __importStar(__require("url"));
|
|
8881
|
-
var
|
|
8882
|
-
var
|
|
8881
|
+
var path21 = __importStar(__require("path"));
|
|
8882
|
+
var fs16 = __importStar(__require("fs"));
|
|
8883
8883
|
var child_process_1 = __require("child_process");
|
|
8884
8884
|
function uriToFilePath(uri) {
|
|
8885
8885
|
const parsed = url2.parse(uri);
|
|
@@ -8897,12 +8897,12 @@ var require_files = __commonJS({
|
|
|
8897
8897
|
segments.shift();
|
|
8898
8898
|
}
|
|
8899
8899
|
}
|
|
8900
|
-
return
|
|
8900
|
+
return path21.normalize(segments.join("/"));
|
|
8901
8901
|
}
|
|
8902
8902
|
function isWindows() {
|
|
8903
8903
|
return process.platform === "win32";
|
|
8904
8904
|
}
|
|
8905
|
-
function
|
|
8905
|
+
function resolve19(moduleName, nodePath, cwd, tracer) {
|
|
8906
8906
|
const nodePathKey = "NODE_PATH";
|
|
8907
8907
|
const app = [
|
|
8908
8908
|
"var p = process;",
|
|
@@ -8921,13 +8921,13 @@ var require_files = __commonJS({
|
|
|
8921
8921
|
"}",
|
|
8922
8922
|
"});"
|
|
8923
8923
|
].join("");
|
|
8924
|
-
return new Promise((
|
|
8924
|
+
return new Promise((resolve20, reject) => {
|
|
8925
8925
|
const env2 = process.env;
|
|
8926
8926
|
const newEnv = /* @__PURE__ */ Object.create(null);
|
|
8927
8927
|
Object.keys(env2).forEach((key) => newEnv[key] = env2[key]);
|
|
8928
|
-
if (nodePath &&
|
|
8928
|
+
if (nodePath && fs16.existsSync(nodePath)) {
|
|
8929
8929
|
if (newEnv[nodePathKey]) {
|
|
8930
|
-
newEnv[nodePathKey] = nodePath +
|
|
8930
|
+
newEnv[nodePathKey] = nodePath + path21.delimiter + newEnv[nodePathKey];
|
|
8931
8931
|
} else {
|
|
8932
8932
|
newEnv[nodePathKey] = nodePath;
|
|
8933
8933
|
}
|
|
@@ -8953,7 +8953,7 @@ var require_files = __commonJS({
|
|
|
8953
8953
|
if (message2.c === "r") {
|
|
8954
8954
|
cp.send({ c: "e" });
|
|
8955
8955
|
if (message2.s) {
|
|
8956
|
-
|
|
8956
|
+
resolve20(message2.r);
|
|
8957
8957
|
} else {
|
|
8958
8958
|
reject(new Error(`Failed to resolve module: ${moduleName}`));
|
|
8959
8959
|
}
|
|
@@ -8999,9 +8999,9 @@ var require_files = __commonJS({
|
|
|
8999
8999
|
}
|
|
9000
9000
|
if (prefix.length > 0) {
|
|
9001
9001
|
if (isWindows()) {
|
|
9002
|
-
return
|
|
9002
|
+
return path21.join(prefix, "node_modules");
|
|
9003
9003
|
} else {
|
|
9004
|
-
return
|
|
9004
|
+
return path21.join(prefix, "lib", "node_modules");
|
|
9005
9005
|
}
|
|
9006
9006
|
}
|
|
9007
9007
|
return void 0;
|
|
@@ -9040,7 +9040,7 @@ var require_files = __commonJS({
|
|
|
9040
9040
|
try {
|
|
9041
9041
|
const yarn = JSON.parse(line);
|
|
9042
9042
|
if (yarn.type === "log") {
|
|
9043
|
-
return
|
|
9043
|
+
return path21.join(yarn.data, "node_modules");
|
|
9044
9044
|
}
|
|
9045
9045
|
} catch (e) {
|
|
9046
9046
|
}
|
|
@@ -9062,36 +9062,36 @@ var require_files = __commonJS({
|
|
|
9062
9062
|
if (process.platform === "win32") {
|
|
9063
9063
|
_isCaseSensitive = false;
|
|
9064
9064
|
} else {
|
|
9065
|
-
_isCaseSensitive = !
|
|
9065
|
+
_isCaseSensitive = !fs16.existsSync(__filename.toUpperCase()) || !fs16.existsSync(__filename.toLowerCase());
|
|
9066
9066
|
}
|
|
9067
9067
|
return _isCaseSensitive;
|
|
9068
9068
|
}
|
|
9069
9069
|
FileSystem2.isCaseSensitive = isCaseSensitive;
|
|
9070
9070
|
function isParent(parent, child) {
|
|
9071
9071
|
if (isCaseSensitive()) {
|
|
9072
|
-
return
|
|
9072
|
+
return path21.normalize(child).indexOf(path21.normalize(parent)) === 0;
|
|
9073
9073
|
} else {
|
|
9074
|
-
return
|
|
9074
|
+
return path21.normalize(child).toLowerCase().indexOf(path21.normalize(parent).toLowerCase()) === 0;
|
|
9075
9075
|
}
|
|
9076
9076
|
}
|
|
9077
9077
|
FileSystem2.isParent = isParent;
|
|
9078
9078
|
})(FileSystem || (exports.FileSystem = FileSystem = {}));
|
|
9079
9079
|
function resolveModulePath(workspaceRoot, moduleName, nodePath, tracer) {
|
|
9080
9080
|
if (nodePath) {
|
|
9081
|
-
if (!
|
|
9082
|
-
nodePath =
|
|
9081
|
+
if (!path21.isAbsolute(nodePath)) {
|
|
9082
|
+
nodePath = path21.join(workspaceRoot, nodePath);
|
|
9083
9083
|
}
|
|
9084
|
-
return
|
|
9084
|
+
return resolve19(moduleName, nodePath, nodePath, tracer).then((value) => {
|
|
9085
9085
|
if (FileSystem.isParent(nodePath, value)) {
|
|
9086
9086
|
return value;
|
|
9087
9087
|
} else {
|
|
9088
9088
|
return Promise.reject(new Error(`Failed to load ${moduleName} from node path location.`));
|
|
9089
9089
|
}
|
|
9090
9090
|
}).then(void 0, (_error) => {
|
|
9091
|
-
return
|
|
9091
|
+
return resolve19(moduleName, resolveGlobalNodePath(tracer), workspaceRoot, tracer);
|
|
9092
9092
|
});
|
|
9093
9093
|
} else {
|
|
9094
|
-
return
|
|
9094
|
+
return resolve19(moduleName, resolveGlobalNodePath(tracer), workspaceRoot, tracer);
|
|
9095
9095
|
}
|
|
9096
9096
|
}
|
|
9097
9097
|
}
|
|
@@ -9174,10 +9174,10 @@ var require_ril = __commonJS({
|
|
|
9174
9174
|
return api_1.Disposable.create(() => this.stream.off("end", listener));
|
|
9175
9175
|
}
|
|
9176
9176
|
write(data, encoding) {
|
|
9177
|
-
return new Promise((
|
|
9177
|
+
return new Promise((resolve19, reject) => {
|
|
9178
9178
|
const callback = (error52) => {
|
|
9179
9179
|
if (error52 === void 0 || error52 === null) {
|
|
9180
|
-
|
|
9180
|
+
resolve19();
|
|
9181
9181
|
} else {
|
|
9182
9182
|
reject(error52);
|
|
9183
9183
|
}
|
|
@@ -9314,9 +9314,9 @@ var require_main = __commonJS({
|
|
|
9314
9314
|
exports.createMessageConnection = createMessageConnection;
|
|
9315
9315
|
var ril_1 = __importDefault(require_ril());
|
|
9316
9316
|
ril_1.default.install();
|
|
9317
|
-
var
|
|
9317
|
+
var path21 = __importStar(__require("path"));
|
|
9318
9318
|
var os7 = __importStar(__require("os"));
|
|
9319
|
-
var
|
|
9319
|
+
var fs16 = __importStar(__require("fs"));
|
|
9320
9320
|
var crypto_1 = __require("crypto");
|
|
9321
9321
|
var net_1 = __require("net");
|
|
9322
9322
|
var api_1 = require_api();
|
|
@@ -9457,7 +9457,7 @@ var require_main = __commonJS({
|
|
|
9457
9457
|
}
|
|
9458
9458
|
let randomLength = 32;
|
|
9459
9459
|
const fixedLength = "/lsp-.sock".length;
|
|
9460
|
-
const tmpDir =
|
|
9460
|
+
const tmpDir = fs16.realpathSync(XDG_RUNTIME_DIR ?? os7.tmpdir());
|
|
9461
9461
|
const limit = safeIpcPathLengths.get(process.platform);
|
|
9462
9462
|
if (limit !== void 0) {
|
|
9463
9463
|
randomLength = Math.min(limit - tmpDir.length - fixedLength, randomLength);
|
|
@@ -9466,14 +9466,14 @@ var require_main = __commonJS({
|
|
|
9466
9466
|
throw new Error(`Unable to generate a random pipe name with ${randomLength} characters.`);
|
|
9467
9467
|
}
|
|
9468
9468
|
const randomSuffix = (0, crypto_1.randomBytes)(Math.floor(randomLength / 2)).toString("hex");
|
|
9469
|
-
return
|
|
9469
|
+
return path21.join(tmpDir, `lsp-${randomSuffix}.sock`);
|
|
9470
9470
|
}
|
|
9471
9471
|
function createClientPipeTransport(pipeName, encoding = "utf-8") {
|
|
9472
9472
|
let connectResolve;
|
|
9473
|
-
const connected = new Promise((
|
|
9474
|
-
connectResolve =
|
|
9473
|
+
const connected = new Promise((resolve19, _reject) => {
|
|
9474
|
+
connectResolve = resolve19;
|
|
9475
9475
|
});
|
|
9476
|
-
return new Promise((
|
|
9476
|
+
return new Promise((resolve19, reject) => {
|
|
9477
9477
|
const server2 = (0, net_1.createServer)((socket) => {
|
|
9478
9478
|
server2.close();
|
|
9479
9479
|
connectResolve([
|
|
@@ -9484,7 +9484,7 @@ var require_main = __commonJS({
|
|
|
9484
9484
|
server2.on("error", reject);
|
|
9485
9485
|
server2.listen(pipeName, () => {
|
|
9486
9486
|
server2.removeListener("error", reject);
|
|
9487
|
-
|
|
9487
|
+
resolve19({
|
|
9488
9488
|
onConnected: () => {
|
|
9489
9489
|
return connected;
|
|
9490
9490
|
}
|
|
@@ -9501,10 +9501,10 @@ var require_main = __commonJS({
|
|
|
9501
9501
|
}
|
|
9502
9502
|
function createClientSocketTransport(port, encoding = "utf-8") {
|
|
9503
9503
|
let connectResolve;
|
|
9504
|
-
const connected = new Promise((
|
|
9505
|
-
connectResolve =
|
|
9504
|
+
const connected = new Promise((resolve19, _reject) => {
|
|
9505
|
+
connectResolve = resolve19;
|
|
9506
9506
|
});
|
|
9507
|
-
return new Promise((
|
|
9507
|
+
return new Promise((resolve19, reject) => {
|
|
9508
9508
|
const server2 = (0, net_1.createServer)((socket) => {
|
|
9509
9509
|
server2.close();
|
|
9510
9510
|
connectResolve([
|
|
@@ -9515,7 +9515,7 @@ var require_main = __commonJS({
|
|
|
9515
9515
|
server2.on("error", reject);
|
|
9516
9516
|
server2.listen(port, "127.0.0.1", () => {
|
|
9517
9517
|
server2.removeListener("error", reject);
|
|
9518
|
-
|
|
9518
|
+
resolve19({
|
|
9519
9519
|
onConnected: () => {
|
|
9520
9520
|
return connected;
|
|
9521
9521
|
}
|
|
@@ -14733,10 +14733,10 @@ var require_src2 = __commonJS({
|
|
|
14733
14733
|
var fs_1 = __require("fs");
|
|
14734
14734
|
var debug_1 = __importDefault(require_src());
|
|
14735
14735
|
var log = debug_1.default("@kwsites/file-exists");
|
|
14736
|
-
function check2(
|
|
14737
|
-
log(`checking %s`,
|
|
14736
|
+
function check2(path21, isFile, isDirectory2) {
|
|
14737
|
+
log(`checking %s`, path21);
|
|
14738
14738
|
try {
|
|
14739
|
-
const stat3 = fs_1.statSync(
|
|
14739
|
+
const stat3 = fs_1.statSync(path21);
|
|
14740
14740
|
if (stat3.isFile() && isFile) {
|
|
14741
14741
|
log(`[OK] path represents a file`);
|
|
14742
14742
|
return true;
|
|
@@ -14756,8 +14756,8 @@ var require_src2 = __commonJS({
|
|
|
14756
14756
|
throw e;
|
|
14757
14757
|
}
|
|
14758
14758
|
}
|
|
14759
|
-
function exists2(
|
|
14760
|
-
return check2(
|
|
14759
|
+
function exists2(path21, type = exports.READABLE) {
|
|
14760
|
+
return check2(path21, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
14761
14761
|
}
|
|
14762
14762
|
exports.exists = exists2;
|
|
14763
14763
|
exports.FILE = 1;
|
|
@@ -15355,8 +15355,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
15355
15355
|
function forEachLineWithContent(input, callback) {
|
|
15356
15356
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
15357
15357
|
}
|
|
15358
|
-
function folderExists(
|
|
15359
|
-
return (0, import_file_exists.exists)(
|
|
15358
|
+
function folderExists(path21) {
|
|
15359
|
+
return (0, import_file_exists.exists)(path21, import_file_exists.FOLDER);
|
|
15360
15360
|
}
|
|
15361
15361
|
function append(target, item) {
|
|
15362
15362
|
if (Array.isArray(target)) {
|
|
@@ -15547,8 +15547,8 @@ function checkIsRepoRootTask() {
|
|
|
15547
15547
|
commands,
|
|
15548
15548
|
format: "utf-8",
|
|
15549
15549
|
onError,
|
|
15550
|
-
parser(
|
|
15551
|
-
return /^\.(git)?$/.test(
|
|
15550
|
+
parser(path21) {
|
|
15551
|
+
return /^\.(git)?$/.test(path21.trim());
|
|
15552
15552
|
}
|
|
15553
15553
|
};
|
|
15554
15554
|
}
|
|
@@ -15804,11 +15804,11 @@ function parseGrep(grep) {
|
|
|
15804
15804
|
const paths = /* @__PURE__ */ new Set();
|
|
15805
15805
|
const results = {};
|
|
15806
15806
|
forEachLineWithContent(grep, (input) => {
|
|
15807
|
-
const [
|
|
15808
|
-
paths.add(
|
|
15809
|
-
(results[
|
|
15807
|
+
const [path21, line, preview] = input.split(NULL);
|
|
15808
|
+
paths.add(path21);
|
|
15809
|
+
(results[path21] = results[path21] || []).push({
|
|
15810
15810
|
line: asNumber(line),
|
|
15811
|
-
path:
|
|
15811
|
+
path: path21,
|
|
15812
15812
|
preview
|
|
15813
15813
|
});
|
|
15814
15814
|
});
|
|
@@ -16105,14 +16105,14 @@ function hashObjectTask(filePath, write) {
|
|
|
16105
16105
|
}
|
|
16106
16106
|
return straightThroughStringTask(commands, true);
|
|
16107
16107
|
}
|
|
16108
|
-
function parseInit(bare,
|
|
16108
|
+
function parseInit(bare, path21, text) {
|
|
16109
16109
|
const response = String(text).trim();
|
|
16110
16110
|
let result;
|
|
16111
16111
|
if (result = initResponseRegex.exec(response)) {
|
|
16112
|
-
return new InitSummary(bare,
|
|
16112
|
+
return new InitSummary(bare, path21, false, result[1]);
|
|
16113
16113
|
}
|
|
16114
16114
|
if (result = reInitResponseRegex.exec(response)) {
|
|
16115
|
-
return new InitSummary(bare,
|
|
16115
|
+
return new InitSummary(bare, path21, true, result[1]);
|
|
16116
16116
|
}
|
|
16117
16117
|
let gitDir = "";
|
|
16118
16118
|
const tokens = response.split(" ");
|
|
@@ -16123,12 +16123,12 @@ function parseInit(bare, path20, text) {
|
|
|
16123
16123
|
break;
|
|
16124
16124
|
}
|
|
16125
16125
|
}
|
|
16126
|
-
return new InitSummary(bare,
|
|
16126
|
+
return new InitSummary(bare, path21, /^re/i.test(response), gitDir);
|
|
16127
16127
|
}
|
|
16128
16128
|
function hasBareCommand(command) {
|
|
16129
16129
|
return command.includes(bareCommand);
|
|
16130
16130
|
}
|
|
16131
|
-
function initTask(bare = false,
|
|
16131
|
+
function initTask(bare = false, path21, customArgs) {
|
|
16132
16132
|
const commands = ["init", ...customArgs];
|
|
16133
16133
|
if (bare && !hasBareCommand(commands)) {
|
|
16134
16134
|
commands.splice(1, 0, bareCommand);
|
|
@@ -16137,7 +16137,7 @@ function initTask(bare = false, path20, customArgs) {
|
|
|
16137
16137
|
commands,
|
|
16138
16138
|
format: "utf-8",
|
|
16139
16139
|
parser(text) {
|
|
16140
|
-
return parseInit(commands.includes("--bare"),
|
|
16140
|
+
return parseInit(commands.includes("--bare"), path21, text);
|
|
16141
16141
|
}
|
|
16142
16142
|
};
|
|
16143
16143
|
}
|
|
@@ -16416,14 +16416,14 @@ function splitLine(result, lineStr) {
|
|
|
16416
16416
|
default:
|
|
16417
16417
|
return;
|
|
16418
16418
|
}
|
|
16419
|
-
function data(index, workingDir,
|
|
16419
|
+
function data(index, workingDir, path21) {
|
|
16420
16420
|
const raw = `${index}${workingDir}`;
|
|
16421
16421
|
const handler = parsers6.get(raw);
|
|
16422
16422
|
if (handler) {
|
|
16423
|
-
handler(result,
|
|
16423
|
+
handler(result, path21);
|
|
16424
16424
|
}
|
|
16425
16425
|
if (raw !== "##" && raw !== "!!") {
|
|
16426
|
-
result.files.push(new FileStatusSummary(
|
|
16426
|
+
result.files.push(new FileStatusSummary(path21, index, workingDir));
|
|
16427
16427
|
}
|
|
16428
16428
|
}
|
|
16429
16429
|
}
|
|
@@ -16610,8 +16610,8 @@ function deleteBranchTask(branch, forceDelete = false) {
|
|
|
16610
16610
|
return task;
|
|
16611
16611
|
}
|
|
16612
16612
|
function toPath(input) {
|
|
16613
|
-
const
|
|
16614
|
-
return
|
|
16613
|
+
const path21 = input.trim().replace(/^["']|["']$/g, "");
|
|
16614
|
+
return path21 && normalize2(path21);
|
|
16615
16615
|
}
|
|
16616
16616
|
function checkIgnoreTask(paths) {
|
|
16617
16617
|
return {
|
|
@@ -16750,8 +16750,8 @@ function stashListTask(opt = {}, customArgs) {
|
|
|
16750
16750
|
parser: parser4
|
|
16751
16751
|
};
|
|
16752
16752
|
}
|
|
16753
|
-
function addSubModuleTask(repo,
|
|
16754
|
-
return subModuleTask(["add", repo,
|
|
16753
|
+
function addSubModuleTask(repo, path21) {
|
|
16754
|
+
return subModuleTask(["add", repo, path21]);
|
|
16755
16755
|
}
|
|
16756
16756
|
function initSubModuleTask(customArgs) {
|
|
16757
16757
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -18014,9 +18014,9 @@ var init_esm = __esm({
|
|
|
18014
18014
|
"src/lib/responses/InitSummary.ts"() {
|
|
18015
18015
|
"use strict";
|
|
18016
18016
|
InitSummary = class {
|
|
18017
|
-
constructor(bare,
|
|
18017
|
+
constructor(bare, path21, existing, gitDir) {
|
|
18018
18018
|
this.bare = bare;
|
|
18019
|
-
this.path =
|
|
18019
|
+
this.path = path21;
|
|
18020
18020
|
this.existing = existing;
|
|
18021
18021
|
this.gitDir = gitDir;
|
|
18022
18022
|
}
|
|
@@ -18549,12 +18549,12 @@ var init_esm = __esm({
|
|
|
18549
18549
|
"use strict";
|
|
18550
18550
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
18551
18551
|
FileStatusSummary = class {
|
|
18552
|
-
constructor(
|
|
18553
|
-
this.path =
|
|
18552
|
+
constructor(path21, index, working_dir) {
|
|
18553
|
+
this.path = path21;
|
|
18554
18554
|
this.index = index;
|
|
18555
18555
|
this.working_dir = working_dir;
|
|
18556
18556
|
if (index === "R" || working_dir === "R") {
|
|
18557
|
-
const detail = fromPathRegex.exec(
|
|
18557
|
+
const detail = fromPathRegex.exec(path21) || [null, path21, path21];
|
|
18558
18558
|
this.from = detail[2] || "";
|
|
18559
18559
|
this.path = detail[1] || "";
|
|
18560
18560
|
}
|
|
@@ -18816,9 +18816,9 @@ var init_esm = __esm({
|
|
|
18816
18816
|
next
|
|
18817
18817
|
);
|
|
18818
18818
|
}
|
|
18819
|
-
hashObject(
|
|
18819
|
+
hashObject(path21, write) {
|
|
18820
18820
|
return this._runTask(
|
|
18821
|
-
hashObjectTask(
|
|
18821
|
+
hashObjectTask(path21, write === true),
|
|
18822
18822
|
trailingFunctionArgument(arguments)
|
|
18823
18823
|
);
|
|
18824
18824
|
}
|
|
@@ -19455,8 +19455,8 @@ var init_esm = __esm({
|
|
|
19455
19455
|
}
|
|
19456
19456
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
19457
19457
|
};
|
|
19458
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
19459
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
19458
|
+
Git2.prototype.submoduleAdd = function(repo, path21, then) {
|
|
19459
|
+
return this._runTask(addSubModuleTask2(repo, path21), trailingFunctionArgument2(arguments));
|
|
19460
19460
|
};
|
|
19461
19461
|
Git2.prototype.submoduleUpdate = function(args2, then) {
|
|
19462
19462
|
return this._runTask(
|
|
@@ -19772,7 +19772,7 @@ async function getCommitsSinceBatch(projectRoot, paths, since) {
|
|
|
19772
19772
|
}
|
|
19773
19773
|
try {
|
|
19774
19774
|
const git = getGit(projectRoot);
|
|
19775
|
-
const
|
|
19775
|
+
const SENTINEL2 = "___CTXLINT_COMMIT___";
|
|
19776
19776
|
const pathspecs = [];
|
|
19777
19777
|
for (const p2 of paths) {
|
|
19778
19778
|
const spec = toGitPathspec(p2, projectRoot);
|
|
@@ -19791,7 +19791,7 @@ async function getCommitsSinceBatch(projectRoot, paths, since) {
|
|
|
19791
19791
|
// %n emits a newline; prefixing with a valid format placeholder is
|
|
19792
19792
|
// what keeps git from rejecting the sentinel as an invalid --pretty
|
|
19793
19793
|
// format ("fatal: invalid --pretty format: ___CTXLINT_COMMIT___").
|
|
19794
|
-
`--format=%n${
|
|
19794
|
+
`--format=%n${SENTINEL2}`
|
|
19795
19795
|
];
|
|
19796
19796
|
if (pathspecs.length > 0) {
|
|
19797
19797
|
logArgs.push("--", ...pathspecs);
|
|
@@ -19808,7 +19808,7 @@ async function getCommitsSinceBatch(projectRoot, paths, since) {
|
|
|
19808
19808
|
seenThisCommit.clear();
|
|
19809
19809
|
};
|
|
19810
19810
|
for (const line of lines) {
|
|
19811
|
-
if (line ===
|
|
19811
|
+
if (line === SENTINEL2) {
|
|
19812
19812
|
if (inCommit) flush();
|
|
19813
19813
|
inCommit = true;
|
|
19814
19814
|
continue;
|
|
@@ -21258,12 +21258,12 @@ function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
|
|
|
21258
21258
|
}
|
|
21259
21259
|
return result;
|
|
21260
21260
|
}
|
|
21261
|
-
function findNodeAtLocation(root,
|
|
21261
|
+
function findNodeAtLocation(root, path21) {
|
|
21262
21262
|
if (!root) {
|
|
21263
21263
|
return void 0;
|
|
21264
21264
|
}
|
|
21265
21265
|
let node = root;
|
|
21266
|
-
for (let segment of
|
|
21266
|
+
for (let segment of path21) {
|
|
21267
21267
|
if (typeof segment === "string") {
|
|
21268
21268
|
if (node.type !== "object" || !Array.isArray(node.children)) {
|
|
21269
21269
|
return void 0;
|
|
@@ -21760,9 +21760,495 @@ var init_main3 = __esm({
|
|
|
21760
21760
|
}
|
|
21761
21761
|
});
|
|
21762
21762
|
|
|
21763
|
-
// src/core/checks/
|
|
21763
|
+
// src/core/checks/exit-status.ts
|
|
21764
|
+
function splitSegments(cmd) {
|
|
21765
|
+
const out = [];
|
|
21766
|
+
let buf = "";
|
|
21767
|
+
let op = "";
|
|
21768
|
+
let quote = null;
|
|
21769
|
+
for (let i2 = 0; i2 < cmd.length; i2++) {
|
|
21770
|
+
const ch = cmd[i2];
|
|
21771
|
+
if (quote) {
|
|
21772
|
+
buf += ch;
|
|
21773
|
+
if (ch === "\\" && quote !== "'") {
|
|
21774
|
+
if (i2 + 1 < cmd.length) buf += cmd[++i2];
|
|
21775
|
+
continue;
|
|
21776
|
+
}
|
|
21777
|
+
if (ch === quote) quote = null;
|
|
21778
|
+
continue;
|
|
21779
|
+
}
|
|
21780
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
21781
|
+
quote = ch;
|
|
21782
|
+
buf += ch;
|
|
21783
|
+
continue;
|
|
21784
|
+
}
|
|
21785
|
+
if (ch === "\\" && i2 + 1 < cmd.length) {
|
|
21786
|
+
buf += ch + cmd[++i2];
|
|
21787
|
+
continue;
|
|
21788
|
+
}
|
|
21789
|
+
if (ch === "&" && cmd[i2 + 1] === "&") {
|
|
21790
|
+
out.push({ op, text: buf.trim() });
|
|
21791
|
+
op = "&&";
|
|
21792
|
+
buf = "";
|
|
21793
|
+
i2++;
|
|
21794
|
+
continue;
|
|
21795
|
+
}
|
|
21796
|
+
if (ch === "|" && cmd[i2 + 1] === "|") {
|
|
21797
|
+
out.push({ op, text: buf.trim() });
|
|
21798
|
+
op = "||";
|
|
21799
|
+
buf = "";
|
|
21800
|
+
i2++;
|
|
21801
|
+
continue;
|
|
21802
|
+
}
|
|
21803
|
+
if (ch === ";") {
|
|
21804
|
+
out.push({ op, text: buf.trim() });
|
|
21805
|
+
op = ";";
|
|
21806
|
+
buf = "";
|
|
21807
|
+
continue;
|
|
21808
|
+
}
|
|
21809
|
+
buf += ch;
|
|
21810
|
+
}
|
|
21811
|
+
out.push({ op, text: buf.trim() });
|
|
21812
|
+
return out.filter((s) => s.text.length > 0);
|
|
21813
|
+
}
|
|
21814
|
+
function splitPipes(segment) {
|
|
21815
|
+
const out = [];
|
|
21816
|
+
let buf = "";
|
|
21817
|
+
let quote = null;
|
|
21818
|
+
for (let i2 = 0; i2 < segment.length; i2++) {
|
|
21819
|
+
const ch = segment[i2];
|
|
21820
|
+
if (quote) {
|
|
21821
|
+
buf += ch;
|
|
21822
|
+
if (ch === "\\" && quote !== "'") {
|
|
21823
|
+
if (i2 + 1 < segment.length) buf += segment[++i2];
|
|
21824
|
+
continue;
|
|
21825
|
+
}
|
|
21826
|
+
if (ch === quote) quote = null;
|
|
21827
|
+
continue;
|
|
21828
|
+
}
|
|
21829
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
21830
|
+
quote = ch;
|
|
21831
|
+
buf += ch;
|
|
21832
|
+
continue;
|
|
21833
|
+
}
|
|
21834
|
+
if (ch === "\\" && i2 + 1 < segment.length) {
|
|
21835
|
+
buf += ch + segment[++i2];
|
|
21836
|
+
continue;
|
|
21837
|
+
}
|
|
21838
|
+
if (ch === "|") {
|
|
21839
|
+
out.push(buf.trim());
|
|
21840
|
+
buf = "";
|
|
21841
|
+
continue;
|
|
21842
|
+
}
|
|
21843
|
+
buf += ch;
|
|
21844
|
+
}
|
|
21845
|
+
out.push(buf.trim());
|
|
21846
|
+
return out.map((s) => s.trim());
|
|
21847
|
+
}
|
|
21848
|
+
function unwrap(part) {
|
|
21849
|
+
let s = part.trim();
|
|
21850
|
+
s = s.replace(/^(?:[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|'[^']*'|\S*)\s+)+/, "");
|
|
21851
|
+
const execMatch = s.match(EXEC_WRAPPER_PATTERN);
|
|
21852
|
+
if (execMatch) s = s.slice(execMatch[0].length).trim();
|
|
21853
|
+
while (WRAPPER_PATTERN.test(s)) {
|
|
21854
|
+
const tokens = s.split(/\s+/).slice(1);
|
|
21855
|
+
let i2 = 0;
|
|
21856
|
+
while (i2 < tokens.length && tokens[i2].startsWith("-")) {
|
|
21857
|
+
if (tokens[i2] === "-p" || tokens[i2] === "--package") i2++;
|
|
21858
|
+
i2++;
|
|
21859
|
+
}
|
|
21860
|
+
const next = tokens.slice(i2).join(" ");
|
|
21861
|
+
if (!next || next === s) break;
|
|
21862
|
+
s = next;
|
|
21863
|
+
}
|
|
21864
|
+
return s.trim();
|
|
21865
|
+
}
|
|
21866
|
+
function verifierName(part, scripts) {
|
|
21867
|
+
const s = unwrap(part);
|
|
21868
|
+
if (!s) return null;
|
|
21869
|
+
for (const re2 of VERIFIER_PAIRS) {
|
|
21870
|
+
const m = s.match(re2);
|
|
21871
|
+
if (m) return m[0].replace(/\s+/g, " ");
|
|
21872
|
+
}
|
|
21873
|
+
const direct = s.match(VERIFIER_PATTERN);
|
|
21874
|
+
if (direct) return direct[1];
|
|
21875
|
+
const scriptName = (s.match(SCRIPT_RUNNER) ?? s.match(SCRIPT_SHORTHAND))?.[1];
|
|
21876
|
+
if (scriptName && scripts) {
|
|
21877
|
+
const body = scripts[scriptName];
|
|
21878
|
+
if (typeof body === "string") {
|
|
21879
|
+
const first2 = splitPipes(splitSegments(body)[0]?.text ?? "")[0] ?? "";
|
|
21880
|
+
const inner = unwrap(first2);
|
|
21881
|
+
for (const re2 of VERIFIER_PAIRS) {
|
|
21882
|
+
const m = inner.match(re2);
|
|
21883
|
+
if (m) return m[0].replace(/\s+/g, " ");
|
|
21884
|
+
}
|
|
21885
|
+
const d = inner.match(VERIFIER_PATTERN);
|
|
21886
|
+
if (d) return d[1];
|
|
21887
|
+
}
|
|
21888
|
+
}
|
|
21889
|
+
return null;
|
|
21890
|
+
}
|
|
21891
|
+
function filterName(part) {
|
|
21892
|
+
const m = unwrap(part).match(FILTER_PATTERN);
|
|
21893
|
+
return m ? m[1] : null;
|
|
21894
|
+
}
|
|
21895
|
+
function isSuccessClaim(segment) {
|
|
21896
|
+
if (!/^(echo|printf)\b/.test(unwrap(segment))) return false;
|
|
21897
|
+
return SUCCESS_WORD.test(segment);
|
|
21898
|
+
}
|
|
21899
|
+
function isStatusEcho(segment) {
|
|
21900
|
+
if (!/^(echo|printf)\b/.test(unwrap(segment))) return false;
|
|
21901
|
+
if (/PIPESTATUS/.test(segment)) return false;
|
|
21902
|
+
return /\$\?/.test(segment);
|
|
21903
|
+
}
|
|
21904
|
+
function analyzeMaskedExitStatus(cmd, scripts) {
|
|
21905
|
+
const segments = splitSegments(cmd);
|
|
21906
|
+
if (segments.length < 2) return null;
|
|
21907
|
+
for (let i2 = 0; i2 < segments.length - 1; i2++) {
|
|
21908
|
+
if (segments.slice(0, i2 + 1).some((s) => PIPEFAIL.test(s.text))) return null;
|
|
21909
|
+
const parts = splitPipes(segments[i2].text);
|
|
21910
|
+
if (parts.length < 2) continue;
|
|
21911
|
+
const verifier = verifierName(parts[0], scripts);
|
|
21912
|
+
if (!verifier) continue;
|
|
21913
|
+
const filter = filterName(parts[parts.length - 1]);
|
|
21914
|
+
if (!filter) continue;
|
|
21915
|
+
const next = segments[i2 + 1];
|
|
21916
|
+
if (next.op !== "&&" && next.op !== ";") continue;
|
|
21917
|
+
if (next.op === "&&" && isSuccessClaim(next.text)) {
|
|
21918
|
+
return { verifier, filter, claim: next.text, kind: "success-claim" };
|
|
21919
|
+
}
|
|
21920
|
+
if (isStatusEcho(next.text)) {
|
|
21921
|
+
return { verifier, filter, claim: next.text, kind: "status-echo" };
|
|
21922
|
+
}
|
|
21923
|
+
}
|
|
21924
|
+
return null;
|
|
21925
|
+
}
|
|
21926
|
+
function pipefailInScope(content, line) {
|
|
21927
|
+
const lines = content.split("\n");
|
|
21928
|
+
const idx = line - 1;
|
|
21929
|
+
if (idx < 0 || idx >= lines.length) return false;
|
|
21930
|
+
let fenceStart = -1;
|
|
21931
|
+
let open = false;
|
|
21932
|
+
for (let i2 = 0; i2 < idx; i2++) {
|
|
21933
|
+
if (/^\s*```/.test(lines[i2])) {
|
|
21934
|
+
open = !open;
|
|
21935
|
+
fenceStart = open ? i2 + 1 : -1;
|
|
21936
|
+
}
|
|
21937
|
+
}
|
|
21938
|
+
if (!open || fenceStart < 0) return false;
|
|
21939
|
+
for (let i2 = fenceStart; i2 < idx; i2++) {
|
|
21940
|
+
if (PIPEFAIL.test(lines[i2])) return true;
|
|
21941
|
+
}
|
|
21942
|
+
return false;
|
|
21943
|
+
}
|
|
21944
|
+
var VERIFIER_PATTERN, VERIFIER_PAIRS, FILTER_PATTERN, SCRIPT_RUNNER, SCRIPT_SHORTHAND, WRAPPER_PATTERN, EXEC_WRAPPER_PATTERN, SUCCESS_WORD, PIPEFAIL;
|
|
21945
|
+
var init_exit_status = __esm({
|
|
21946
|
+
"src/core/checks/exit-status.ts"() {
|
|
21947
|
+
"use strict";
|
|
21948
|
+
init_define_WEB_FIRST_SEGMENTS();
|
|
21949
|
+
VERIFIER_PATTERN = /^(tsc|eslint|biome|vitest|jest|pytest|mypy|ruff|oxlint)\b/;
|
|
21950
|
+
VERIFIER_PAIRS = [/^cargo\s+(test|clippy|check)\b/, /^go\s+(test|vet|build)\b/];
|
|
21951
|
+
FILTER_PATTERN = /^(head|tail|grep|egrep|fgrep|sed|awk|less|more|cat|tee|wc)\b/;
|
|
21952
|
+
SCRIPT_RUNNER = /^(?:npm\s+run|(?:pnpm|yarn|bun)(?:\s+run)?)\s+(\S+)/;
|
|
21953
|
+
SCRIPT_SHORTHAND = /^(?:npm|pnpm|yarn|bun)\s+(test|start|build|dev|lint|format|check|typecheck|type-check|clean|serve|preview|e2e)\b/;
|
|
21954
|
+
WRAPPER_PATTERN = /^(npx|bunx|sudo|time|command|nice)\b/;
|
|
21955
|
+
EXEC_WRAPPER_PATTERN = /^(?:pnpm|npm|yarn|bun)\s+(?:exec|dlx)\b/;
|
|
21956
|
+
SUCCESS_WORD = /\b(ok|okay|clean|pass|passed|passes|passing|green|success|successful|done|all\s+good|no\s+errors|looks\s+good)\b/i;
|
|
21957
|
+
PIPEFAIL = /\bset\s+[-\w\s]*\bpipefail\b/;
|
|
21958
|
+
}
|
|
21959
|
+
});
|
|
21960
|
+
|
|
21961
|
+
// src/core/checks/cli-subcommands.ts
|
|
21764
21962
|
import * as fs4 from "node:fs";
|
|
21765
21963
|
import * as path5 from "node:path";
|
|
21964
|
+
function ownedBins(pkgJson) {
|
|
21965
|
+
if (!pkgJson || !pkgJson.bin) return [];
|
|
21966
|
+
const out = [];
|
|
21967
|
+
if (typeof pkgJson.bin === "string") {
|
|
21968
|
+
const raw = pkgJson.name ?? "";
|
|
21969
|
+
const name = raw.includes("/") ? raw.slice(raw.lastIndexOf("/") + 1) : raw;
|
|
21970
|
+
if (name) out.push({ name, entry: pkgJson.bin });
|
|
21971
|
+
return out;
|
|
21972
|
+
}
|
|
21973
|
+
for (const [name, entry] of Object.entries(pkgJson.bin)) {
|
|
21974
|
+
if (typeof entry === "string" && name) out.push({ name, entry });
|
|
21975
|
+
}
|
|
21976
|
+
return out;
|
|
21977
|
+
}
|
|
21978
|
+
function commandNameOf(token) {
|
|
21979
|
+
let t2 = token.trim().replace(/^["']|["']$/g, "");
|
|
21980
|
+
if (!t2) return null;
|
|
21981
|
+
const cut = Math.max(t2.lastIndexOf("/"), t2.lastIndexOf("\\"));
|
|
21982
|
+
if (cut >= 0) t2 = t2.slice(cut + 1);
|
|
21983
|
+
t2 = t2.replace(BIN_EXT, "");
|
|
21984
|
+
return t2 || null;
|
|
21985
|
+
}
|
|
21986
|
+
function resolveEntry(projectRoot, entry) {
|
|
21987
|
+
const base = path5.resolve(projectRoot, entry);
|
|
21988
|
+
const candidates = [base, `${base}.js`, `${base}.mjs`, `${base}.cjs`, `${base}.ts`];
|
|
21989
|
+
for (const c3 of candidates) {
|
|
21990
|
+
try {
|
|
21991
|
+
if (fs4.statSync(c3).isFile()) return c3;
|
|
21992
|
+
} catch {
|
|
21993
|
+
}
|
|
21994
|
+
}
|
|
21995
|
+
return null;
|
|
21996
|
+
}
|
|
21997
|
+
function readEntry(abs) {
|
|
21998
|
+
let src;
|
|
21999
|
+
try {
|
|
22000
|
+
const stat3 = fs4.statSync(abs);
|
|
22001
|
+
if (stat3.size > MAX_ENTRY_BYTES) return null;
|
|
22002
|
+
src = stripBom(fs4.readFileSync(abs, "utf-8"));
|
|
22003
|
+
} catch {
|
|
22004
|
+
return null;
|
|
22005
|
+
}
|
|
22006
|
+
for (const line of src.split("\n")) {
|
|
22007
|
+
if (line.length > MAX_ENTRY_LINE) return null;
|
|
22008
|
+
}
|
|
22009
|
+
return src;
|
|
22010
|
+
}
|
|
22011
|
+
function shimTarget(src) {
|
|
22012
|
+
const meaningful = src.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#!") && !l.startsWith("//") && !l.startsWith("*"));
|
|
22013
|
+
if (meaningful.length > 12) return null;
|
|
22014
|
+
const specs = /* @__PURE__ */ new Set();
|
|
22015
|
+
for (const m of src.matchAll(/(?:^|\s)(?:import|require)\s*\(?\s*['"](\.[^'"]+)['"]/g)) {
|
|
22016
|
+
specs.add(m[1]);
|
|
22017
|
+
}
|
|
22018
|
+
for (const m of src.matchAll(/^\s*import\s+[^'"]*from\s*['"](\.[^'"]+)['"]/gm)) {
|
|
22019
|
+
specs.add(m[1]);
|
|
22020
|
+
}
|
|
22021
|
+
return specs.size === 1 ? [...specs][0] : null;
|
|
22022
|
+
}
|
|
22023
|
+
function stripComments2(src) {
|
|
22024
|
+
let code = "";
|
|
22025
|
+
let literals = "";
|
|
22026
|
+
let i2 = 0;
|
|
22027
|
+
const push = (ch, inString) => {
|
|
22028
|
+
literals += ch;
|
|
22029
|
+
code += inString && ch !== "\n" ? " " : ch;
|
|
22030
|
+
};
|
|
22031
|
+
while (i2 < src.length) {
|
|
22032
|
+
const ch = src[i2];
|
|
22033
|
+
const next = src[i2 + 1];
|
|
22034
|
+
if (ch === "/" && next === "/") {
|
|
22035
|
+
while (i2 < src.length && src[i2] !== "\n") i2++;
|
|
22036
|
+
continue;
|
|
22037
|
+
}
|
|
22038
|
+
if (ch === "/" && next === "*") {
|
|
22039
|
+
i2 += 2;
|
|
22040
|
+
while (i2 < src.length && !(src[i2] === "*" && src[i2 + 1] === "/")) {
|
|
22041
|
+
if (src[i2] === "\n") push("\n", false);
|
|
22042
|
+
i2++;
|
|
22043
|
+
}
|
|
22044
|
+
i2 += 2;
|
|
22045
|
+
continue;
|
|
22046
|
+
}
|
|
22047
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
22048
|
+
const quote = ch;
|
|
22049
|
+
push(ch, false);
|
|
22050
|
+
i2++;
|
|
22051
|
+
while (i2 < src.length) {
|
|
22052
|
+
if (src[i2] === "\\") {
|
|
22053
|
+
push(src[i2], true);
|
|
22054
|
+
if (i2 + 1 < src.length) push(src[i2 + 1], true);
|
|
22055
|
+
i2 += 2;
|
|
22056
|
+
continue;
|
|
22057
|
+
}
|
|
22058
|
+
if (src[i2] === quote) break;
|
|
22059
|
+
push(src[i2], true);
|
|
22060
|
+
i2++;
|
|
22061
|
+
}
|
|
22062
|
+
if (i2 < src.length) push(src[i2], false);
|
|
22063
|
+
i2++;
|
|
22064
|
+
continue;
|
|
22065
|
+
}
|
|
22066
|
+
push(ch, false);
|
|
22067
|
+
i2++;
|
|
22068
|
+
}
|
|
22069
|
+
return { code, literals };
|
|
22070
|
+
}
|
|
22071
|
+
function commanderIsOpen(code) {
|
|
22072
|
+
return /\.command\(\s*[^'"`\s)]/.test(code);
|
|
22073
|
+
}
|
|
22074
|
+
function commanderSubcommands(code, literals) {
|
|
22075
|
+
if (commanderIsOpen(code)) return null;
|
|
22076
|
+
const found = /* @__PURE__ */ new Set();
|
|
22077
|
+
for (const m of literals.matchAll(/\.command\(\s*(['"`])([^'"`\n]+)\1/g)) {
|
|
22078
|
+
const name = m[2].trim().split(/\s+/)[0];
|
|
22079
|
+
if (name && !name.startsWith("<") && !name.startsWith("[")) found.add(name);
|
|
22080
|
+
}
|
|
22081
|
+
return found.size > 0 ? found : null;
|
|
22082
|
+
}
|
|
22083
|
+
function argvSubcommands(code, literals) {
|
|
22084
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
22085
|
+
for (const m of code.matchAll(
|
|
22086
|
+
/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:process\.)?argv\[2\]/g
|
|
22087
|
+
)) {
|
|
22088
|
+
aliases.add(m[1]);
|
|
22089
|
+
}
|
|
22090
|
+
for (const m of code.matchAll(
|
|
22091
|
+
/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:process\.)?argv\.slice\(\s*2\s*\)\s*\[\s*0\s*\]/g
|
|
22092
|
+
)) {
|
|
22093
|
+
aliases.add(m[1]);
|
|
22094
|
+
}
|
|
22095
|
+
for (const m of code.matchAll(
|
|
22096
|
+
/\b(?:const|let|var)\s*\[\s*,\s*,\s*([A-Za-z_$][\w$]*)\s*\]\s*=\s*process\.argv/g
|
|
22097
|
+
)) {
|
|
22098
|
+
aliases.add(m[1]);
|
|
22099
|
+
}
|
|
22100
|
+
const tokens = [...aliases].map((a) => `\\b${a}\\b`);
|
|
22101
|
+
if (/(?:process\.)?argv\[2\]/.test(code)) tokens.push("(?:process\\.)?argv\\[2\\]");
|
|
22102
|
+
if (tokens.length === 0) return null;
|
|
22103
|
+
const tok = `(?:${tokens.join("|")})`;
|
|
22104
|
+
const cmpIdent = new RegExp(`${tok}\\s*[=!]==?\\s*([A-Za-z_$][\\w$.]*)`, "g");
|
|
22105
|
+
for (const m of code.matchAll(cmpIdent)) {
|
|
22106
|
+
if (!SENTINEL.test(m[1])) return null;
|
|
22107
|
+
}
|
|
22108
|
+
const identCmp = new RegExp(`([A-Za-z_$][\\w$.]*)\\s*[=!]==?\\s*${tok}`, "g");
|
|
22109
|
+
for (const m of code.matchAll(identCmp)) {
|
|
22110
|
+
if (!SENTINEL.test(m[1])) return null;
|
|
22111
|
+
}
|
|
22112
|
+
if (new RegExp(`\\[\\s*${tok}\\s*\\]`).test(code)) return null;
|
|
22113
|
+
if (new RegExp(`Object\\.(keys|values|entries)\\([^)]*\\)[^\\n]*${tok}`).test(code)) return null;
|
|
22114
|
+
if (new RegExp(`${tok}\\s+in\\s+`).test(code)) return null;
|
|
22115
|
+
if (new RegExp(`\\bhasOwnProperty\\(\\s*${tok}`).test(code)) return null;
|
|
22116
|
+
const includesRe = new RegExp(`(\\S*)\\.includes\\(\\s*${tok}\\s*\\)`, "g");
|
|
22117
|
+
for (const m of code.matchAll(includesRe)) {
|
|
22118
|
+
if (!m[1].endsWith("]")) return null;
|
|
22119
|
+
}
|
|
22120
|
+
const found = /* @__PURE__ */ new Set();
|
|
22121
|
+
const eqLit = new RegExp(`${tok}\\s*[=!]==?\\s*(['"\`])([^'"\`\\n]*)\\1`, "g");
|
|
22122
|
+
for (const m of literals.matchAll(eqLit)) if (m[2]) found.add(m[2]);
|
|
22123
|
+
const litEq = new RegExp(`(['"\`])([^'"\`\\n]*)\\1\\s*[=!]==?\\s*${tok}`, "g");
|
|
22124
|
+
for (const m of literals.matchAll(litEq)) if (m[2]) found.add(m[2]);
|
|
22125
|
+
const switchRe = new RegExp(`switch\\s*\\(\\s*${tok}\\s*\\)\\s*\\{`, "g");
|
|
22126
|
+
for (const m of literals.matchAll(switchRe)) {
|
|
22127
|
+
const body = literals.slice((m.index ?? 0) + m[0].length);
|
|
22128
|
+
const end = body.indexOf("\n}");
|
|
22129
|
+
const block = end >= 0 ? body.slice(0, end) : body;
|
|
22130
|
+
for (const c3 of block.matchAll(/\bcase\s+(['"`])([^'"`\n]*)\1/g)) {
|
|
22131
|
+
if (c3[2]) found.add(c3[2]);
|
|
22132
|
+
}
|
|
22133
|
+
}
|
|
22134
|
+
const arrIncludes = new RegExp(`\\[([^\\]\\n]*)\\]\\.includes\\(\\s*${tok}\\s*\\)`, "g");
|
|
22135
|
+
for (const m of literals.matchAll(arrIncludes)) {
|
|
22136
|
+
for (const lit of m[1].matchAll(/(['"`])([^'"`]*)\1/g)) {
|
|
22137
|
+
if (lit[2]) found.add(lit[2]);
|
|
22138
|
+
}
|
|
22139
|
+
}
|
|
22140
|
+
return found.size > 0 ? found : null;
|
|
22141
|
+
}
|
|
22142
|
+
function knownSubcommands(projectRoot, entry) {
|
|
22143
|
+
let abs = resolveEntry(projectRoot, entry);
|
|
22144
|
+
for (let hop = 0; abs && hop <= MAX_FOLLOW; hop++) {
|
|
22145
|
+
const src = readEntry(abs);
|
|
22146
|
+
if (src === null) return null;
|
|
22147
|
+
const { code, literals } = stripComments2(src);
|
|
22148
|
+
const commander = commanderSubcommands(code, literals);
|
|
22149
|
+
if (commander) return commander;
|
|
22150
|
+
if (commanderIsOpen(code)) return null;
|
|
22151
|
+
const argv = argvSubcommands(code, literals);
|
|
22152
|
+
if (argv) return argv;
|
|
22153
|
+
if (hop === MAX_FOLLOW) break;
|
|
22154
|
+
const target = shimTarget(src);
|
|
22155
|
+
if (!target) break;
|
|
22156
|
+
abs = resolveEntry(path5.dirname(abs), target);
|
|
22157
|
+
}
|
|
22158
|
+
return null;
|
|
22159
|
+
}
|
|
22160
|
+
function findBinInvocations(content, binNames) {
|
|
22161
|
+
if (binNames.size === 0) return [];
|
|
22162
|
+
const out = [];
|
|
22163
|
+
const lines = content.split("\n");
|
|
22164
|
+
let inFence = false;
|
|
22165
|
+
let fenceLang = "";
|
|
22166
|
+
let inHtmlComment = false;
|
|
22167
|
+
for (let i2 = 0; i2 < lines.length; i2++) {
|
|
22168
|
+
const line = lines[i2];
|
|
22169
|
+
const trimmed2 = line.trim();
|
|
22170
|
+
if (!inHtmlComment && trimmed2.includes("<!--")) {
|
|
22171
|
+
inHtmlComment = !trimmed2.includes("-->");
|
|
22172
|
+
continue;
|
|
22173
|
+
}
|
|
22174
|
+
if (inHtmlComment) {
|
|
22175
|
+
if (trimmed2.includes("-->")) inHtmlComment = false;
|
|
22176
|
+
continue;
|
|
22177
|
+
}
|
|
22178
|
+
if (trimmed2.startsWith("```")) {
|
|
22179
|
+
if (!inFence) {
|
|
22180
|
+
inFence = true;
|
|
22181
|
+
fenceLang = trimmed2.slice(3).trim().toLowerCase();
|
|
22182
|
+
} else {
|
|
22183
|
+
inFence = false;
|
|
22184
|
+
fenceLang = "";
|
|
22185
|
+
}
|
|
22186
|
+
continue;
|
|
22187
|
+
}
|
|
22188
|
+
const candidates = [];
|
|
22189
|
+
if (inFence) {
|
|
22190
|
+
if (["bash", "sh", "shell", "zsh", "console", ""].includes(fenceLang)) {
|
|
22191
|
+
if (trimmed2 && !trimmed2.startsWith("#") && !trimmed2.startsWith("//")) {
|
|
22192
|
+
candidates.push(trimmed2.replace(/^[$>]\s*/, ""));
|
|
22193
|
+
}
|
|
22194
|
+
}
|
|
22195
|
+
} else {
|
|
22196
|
+
if (/^[$>]\s+/.test(trimmed2)) candidates.push(trimmed2.replace(/^[$>]\s*/, ""));
|
|
22197
|
+
for (const m of line.matchAll(/`([^`]+)`/g)) candidates.push(m[1].trim());
|
|
22198
|
+
}
|
|
22199
|
+
for (const candidate of candidates) {
|
|
22200
|
+
const hit = matchBinInvocation(candidate, binNames);
|
|
22201
|
+
if (hit) out.push({ ...hit, cmd: candidate, line: i2 + 1 });
|
|
22202
|
+
}
|
|
22203
|
+
}
|
|
22204
|
+
return out;
|
|
22205
|
+
}
|
|
22206
|
+
function matchBinInvocation(candidate, binNames) {
|
|
22207
|
+
let s = candidate.trim();
|
|
22208
|
+
const stop = s.search(/&&|\|\||[;|]/);
|
|
22209
|
+
if (stop >= 0) s = s.slice(0, stop).trim();
|
|
22210
|
+
s = s.replace(TWO_TOKEN_DELEGATORS, "");
|
|
22211
|
+
let tokens = s.split(/\s+/).filter(Boolean);
|
|
22212
|
+
while (tokens.length > 0) {
|
|
22213
|
+
const head = commandNameOf(tokens[0]);
|
|
22214
|
+
if (head && DELEGATORS.has(head)) {
|
|
22215
|
+
tokens = tokens.slice(1);
|
|
22216
|
+
while (tokens.length > 0 && tokens[0].startsWith("-")) tokens = tokens.slice(1);
|
|
22217
|
+
continue;
|
|
22218
|
+
}
|
|
22219
|
+
break;
|
|
22220
|
+
}
|
|
22221
|
+
if (tokens.length < 2) return null;
|
|
22222
|
+
const bin = commandNameOf(tokens[0]);
|
|
22223
|
+
if (!bin || !binNames.has(bin)) return null;
|
|
22224
|
+
for (const raw of tokens.slice(1)) {
|
|
22225
|
+
if (raw.startsWith("-")) continue;
|
|
22226
|
+
const t2 = raw.replace(/^["']|["']$/g, "");
|
|
22227
|
+
if (!SUBCOMMAND_SHAPE.test(t2)) return null;
|
|
22228
|
+
return { bin, sub: t2 };
|
|
22229
|
+
}
|
|
22230
|
+
return null;
|
|
22231
|
+
}
|
|
22232
|
+
var BIN_EXT, MAX_ENTRY_BYTES, MAX_ENTRY_LINE, MAX_FOLLOW, SENTINEL, DELEGATORS, TWO_TOKEN_DELEGATORS, SUBCOMMAND_SHAPE;
|
|
22233
|
+
var init_cli_subcommands = __esm({
|
|
22234
|
+
"src/core/checks/cli-subcommands.ts"() {
|
|
22235
|
+
"use strict";
|
|
22236
|
+
init_define_WEB_FIRST_SEGMENTS();
|
|
22237
|
+
init_fs();
|
|
22238
|
+
BIN_EXT = /\.(exe|cmd|bat|ps1|js|mjs|cjs|ts)$/i;
|
|
22239
|
+
MAX_ENTRY_BYTES = 15e4;
|
|
22240
|
+
MAX_ENTRY_LINE = 500;
|
|
22241
|
+
MAX_FOLLOW = 1;
|
|
22242
|
+
SENTINEL = /^(undefined|null|NaN|void)$/;
|
|
22243
|
+
DELEGATORS = /* @__PURE__ */ new Set(["npx", "bunx", "sudo", "time"]);
|
|
22244
|
+
TWO_TOKEN_DELEGATORS = /^(?:pnpm|npm|yarn|bun)\s+(?:exec|dlx)\s+/;
|
|
22245
|
+
SUBCOMMAND_SHAPE = /^[a-z][a-z0-9:_-]*$/i;
|
|
22246
|
+
}
|
|
22247
|
+
});
|
|
22248
|
+
|
|
22249
|
+
// src/core/checks/commands.ts
|
|
22250
|
+
import * as fs5 from "node:fs";
|
|
22251
|
+
import * as path6 from "node:path";
|
|
21766
22252
|
function isManagerBuiltin(manager, sub) {
|
|
21767
22253
|
return PM_MANAGER_BUILTINS[manager]?.has(sub) ?? false;
|
|
21768
22254
|
}
|
|
@@ -21803,7 +22289,7 @@ function loadDeniedCommandPrefixes(projectRoot) {
|
|
|
21803
22289
|
for (const rel of ["settings.json", "settings.local.json"]) {
|
|
21804
22290
|
let content;
|
|
21805
22291
|
try {
|
|
21806
|
-
content = stripBom(
|
|
22292
|
+
content = stripBom(fs5.readFileSync(path6.join(projectRoot, ".claude", rel), "utf-8"));
|
|
21807
22293
|
} catch {
|
|
21808
22294
|
continue;
|
|
21809
22295
|
}
|
|
@@ -21840,8 +22326,21 @@ async function checkCommands(file2, projectRoot) {
|
|
|
21840
22326
|
});
|
|
21841
22327
|
}
|
|
21842
22328
|
}
|
|
22329
|
+
issues.push(...checkUnknownSubcommand(file2, projectRoot, pkgJson));
|
|
21843
22330
|
for (const ref of file2.references.commands) {
|
|
21844
22331
|
const cmd = ref.value;
|
|
22332
|
+
const masked = analyzeMaskedExitStatus(cmd, pkgJson?.scripts);
|
|
22333
|
+
if (masked && !pipefailInScope(file2.content, ref.line)) {
|
|
22334
|
+
const why = masked.kind === "success-claim" ? "the success claim cannot fail" : "`$?` reports the filter, not the verifier";
|
|
22335
|
+
issues.push({
|
|
22336
|
+
severity: "warning",
|
|
22337
|
+
check: "commands",
|
|
22338
|
+
ruleId: "commands/exit-status-masked",
|
|
22339
|
+
line: ref.line,
|
|
22340
|
+
message: `"${cmd}" \u2014 exit status comes from "${masked.filter}", not "${masked.verifier}"; ${why}`,
|
|
22341
|
+
suggestion: "Add `set -o pipefail` before the pipeline, drop the filter, or read `${PIPESTATUS[0]}` instead of `$?`."
|
|
22342
|
+
});
|
|
22343
|
+
}
|
|
21845
22344
|
const scriptMatch = cmd.match(NPM_SCRIPT_PATTERN);
|
|
21846
22345
|
if (scriptMatch && pkgJson) {
|
|
21847
22346
|
const scriptName = scriptNameFromMatch(scriptMatch);
|
|
@@ -21885,9 +22384,9 @@ async function checkCommands(file2, projectRoot) {
|
|
|
21885
22384
|
};
|
|
21886
22385
|
if (!(pkgName in allDeps)) {
|
|
21887
22386
|
if (isDeniedCommand(cmd, deniedPrefixes)) continue;
|
|
21888
|
-
const binPath =
|
|
22387
|
+
const binPath = path6.join(projectRoot, "node_modules", ".bin", pkgName);
|
|
21889
22388
|
try {
|
|
21890
|
-
|
|
22389
|
+
fs5.accessSync(binPath);
|
|
21891
22390
|
} catch {
|
|
21892
22391
|
issues.push({
|
|
21893
22392
|
severity: "warning",
|
|
@@ -21935,9 +22434,9 @@ async function checkCommands(file2, projectRoot) {
|
|
|
21935
22434
|
...pkgJson.optionalDependencies
|
|
21936
22435
|
};
|
|
21937
22436
|
if (!(pkgName in allDeps)) {
|
|
21938
|
-
const binPath =
|
|
22437
|
+
const binPath = path6.join(projectRoot, "node_modules", ".bin", tool);
|
|
21939
22438
|
try {
|
|
21940
|
-
|
|
22439
|
+
fs5.accessSync(binPath);
|
|
21941
22440
|
} catch {
|
|
21942
22441
|
issues.push({
|
|
21943
22442
|
severity: "warning",
|
|
@@ -21952,9 +22451,36 @@ async function checkCommands(file2, projectRoot) {
|
|
|
21952
22451
|
}
|
|
21953
22452
|
return issues;
|
|
21954
22453
|
}
|
|
22454
|
+
function checkUnknownSubcommand(file2, projectRoot, pkgJson) {
|
|
22455
|
+
const bins = ownedBins(pkgJson);
|
|
22456
|
+
if (bins.length === 0) return [];
|
|
22457
|
+
const invocations = findBinInvocations(file2.content, new Set(bins.map((b2) => b2.name)));
|
|
22458
|
+
if (invocations.length === 0) return [];
|
|
22459
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
22460
|
+
const issues = [];
|
|
22461
|
+
for (const inv of invocations) {
|
|
22462
|
+
if (!resolved.has(inv.bin)) {
|
|
22463
|
+
const bin = bins.find((b2) => b2.name === inv.bin);
|
|
22464
|
+
resolved.set(inv.bin, bin ? knownSubcommands(projectRoot, bin.entry) : null);
|
|
22465
|
+
}
|
|
22466
|
+
const known = resolved.get(inv.bin);
|
|
22467
|
+
if (!known || known.size === 0) continue;
|
|
22468
|
+
if (known.has(inv.sub)) continue;
|
|
22469
|
+
const listed = [...known].sort().join(", ");
|
|
22470
|
+
issues.push({
|
|
22471
|
+
severity: "error",
|
|
22472
|
+
check: "commands",
|
|
22473
|
+
ruleId: "commands/unknown-subcommand",
|
|
22474
|
+
line: inv.line,
|
|
22475
|
+
message: `"${inv.cmd}" \u2014 "${inv.sub}" is not a subcommand of ${inv.bin} (known: ${listed})`,
|
|
22476
|
+
suggestion: `Use one of the subcommands ${inv.bin} implements, or remove the invocation.`
|
|
22477
|
+
});
|
|
22478
|
+
}
|
|
22479
|
+
return issues;
|
|
22480
|
+
}
|
|
21955
22481
|
function loadMakefile(projectRoot) {
|
|
21956
22482
|
try {
|
|
21957
|
-
return stripBom(
|
|
22483
|
+
return stripBom(fs5.readFileSync(path6.join(projectRoot, "Makefile"), "utf-8"));
|
|
21958
22484
|
} catch {
|
|
21959
22485
|
return null;
|
|
21960
22486
|
}
|
|
@@ -21979,6 +22505,8 @@ var init_commands = __esm({
|
|
|
21979
22505
|
init_define_WEB_FIRST_SEGMENTS();
|
|
21980
22506
|
init_main3();
|
|
21981
22507
|
init_fs();
|
|
22508
|
+
init_exit_status();
|
|
22509
|
+
init_cli_subcommands();
|
|
21982
22510
|
NPM_SCRIPT_PATTERN = /^(?:npm\s+run|(pnpm|yarn|bun)(?:\s+(run))?)\s+(\S+)/;
|
|
21983
22511
|
MAKE_PATTERN = /^make\s+\S/;
|
|
21984
22512
|
PM_BUILTIN_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -22052,13 +22580,13 @@ var init_commands = __esm({
|
|
|
22052
22580
|
});
|
|
22053
22581
|
|
|
22054
22582
|
// src/core/checks/staleness.ts
|
|
22055
|
-
import * as
|
|
22583
|
+
import * as path7 from "node:path";
|
|
22056
22584
|
async function checkStaleness(file2, projectRoot) {
|
|
22057
22585
|
const issues = [];
|
|
22058
22586
|
if (!await isGitRepo(projectRoot)) {
|
|
22059
22587
|
return issues;
|
|
22060
22588
|
}
|
|
22061
|
-
const relativePath =
|
|
22589
|
+
const relativePath = path7.relative(projectRoot, file2.filePath).replace(/\\/g, "/");
|
|
22062
22590
|
const lastModified = await getFileLastModified(projectRoot, relativePath);
|
|
22063
22591
|
if (!lastModified || isNaN(lastModified.getTime())) {
|
|
22064
22592
|
return issues;
|
|
@@ -22249,9 +22777,9 @@ var init_tokens2 = __esm({
|
|
|
22249
22777
|
});
|
|
22250
22778
|
|
|
22251
22779
|
// src/core/checks/tier-tokens.ts
|
|
22252
|
-
import * as
|
|
22780
|
+
import * as fs6 from "node:fs";
|
|
22253
22781
|
import * as os2 from "node:os";
|
|
22254
|
-
import * as
|
|
22782
|
+
import * as path8 from "node:path";
|
|
22255
22783
|
function hasFrontmatterList(content, field) {
|
|
22256
22784
|
const lines = content.split("\n");
|
|
22257
22785
|
if (lines[0]?.trim() !== "---") return false;
|
|
@@ -22321,7 +22849,7 @@ function computeSectionCosts(file2) {
|
|
|
22321
22849
|
function fingerprintFiles(paths) {
|
|
22322
22850
|
return paths.map((p2) => {
|
|
22323
22851
|
try {
|
|
22324
|
-
const st2 =
|
|
22852
|
+
const st2 = fs6.statSync(p2);
|
|
22325
22853
|
return `${st2.mtimeMs}:${st2.size}`;
|
|
22326
22854
|
} catch {
|
|
22327
22855
|
return "absent";
|
|
@@ -22330,11 +22858,11 @@ function fingerprintFiles(paths) {
|
|
|
22330
22858
|
}
|
|
22331
22859
|
function loadSettingsSources(projectRoot, includeGlobal) {
|
|
22332
22860
|
const candidates = [
|
|
22333
|
-
|
|
22334
|
-
|
|
22861
|
+
path8.join(projectRoot, ".claude", "settings.json"),
|
|
22862
|
+
path8.join(projectRoot, ".claude", "settings.local.json")
|
|
22335
22863
|
];
|
|
22336
22864
|
if (includeGlobal) {
|
|
22337
|
-
candidates.push(
|
|
22865
|
+
candidates.push(path8.join(os2.homedir(), ".claude", "settings.json"));
|
|
22338
22866
|
}
|
|
22339
22867
|
const fingerprint = fingerprintFiles(candidates);
|
|
22340
22868
|
if (settingsCache?.root === projectRoot && settingsCache.includeGlobal === includeGlobal && settingsCache.fingerprint === fingerprint) {
|
|
@@ -22344,7 +22872,7 @@ function loadSettingsSources(projectRoot, includeGlobal) {
|
|
|
22344
22872
|
for (const p2 of candidates) {
|
|
22345
22873
|
let content;
|
|
22346
22874
|
try {
|
|
22347
|
-
content = stripBom(
|
|
22875
|
+
content = stripBom(fs6.readFileSync(p2, "utf-8"));
|
|
22348
22876
|
} catch {
|
|
22349
22877
|
continue;
|
|
22350
22878
|
}
|
|
@@ -22518,7 +23046,7 @@ var init_similarity = __esm({
|
|
|
22518
23046
|
});
|
|
22519
23047
|
|
|
22520
23048
|
// src/core/checks/redundancy.ts
|
|
22521
|
-
import * as
|
|
23049
|
+
import * as path9 from "node:path";
|
|
22522
23050
|
function compilePatterns(allDeps) {
|
|
22523
23051
|
const compiled = [];
|
|
22524
23052
|
for (const [pkg, mentions] of Object.entries(PACKAGE_TECH_MAP)) {
|
|
@@ -22598,8 +23126,8 @@ async function checkRedundancy(file2, projectRoot) {
|
|
|
22598
23126
|
);
|
|
22599
23127
|
if (dirMatch) {
|
|
22600
23128
|
const dir = dirMatch[1].replace(/[`"]/g, "");
|
|
22601
|
-
const baseDir = dir.startsWith("./") || dir.startsWith("../") ?
|
|
22602
|
-
const fullPath =
|
|
23129
|
+
const baseDir = dir.startsWith("./") || dir.startsWith("../") ? path9.dirname(file2.filePath) : projectRoot;
|
|
23130
|
+
const fullPath = path9.resolve(baseDir, dir);
|
|
22603
23131
|
if (isDirectory(fullPath)) {
|
|
22604
23132
|
issues.push({
|
|
22605
23133
|
severity: "info",
|
|
@@ -23627,8 +24155,8 @@ var init_security = __esm({
|
|
|
23627
24155
|
});
|
|
23628
24156
|
|
|
23629
24157
|
// src/core/checks/mcp/commands.ts
|
|
23630
|
-
import * as
|
|
23631
|
-
import * as
|
|
24158
|
+
import * as fs7 from "node:fs";
|
|
24159
|
+
import * as path10 from "node:path";
|
|
23632
24160
|
async function checkMcpCommands(config2, projectRoot) {
|
|
23633
24161
|
const issues = [];
|
|
23634
24162
|
if (config2.parseErrors.length > 0) return issues;
|
|
@@ -23645,7 +24173,7 @@ async function checkMcpCommands(config2, projectRoot) {
|
|
|
23645
24173
|
});
|
|
23646
24174
|
}
|
|
23647
24175
|
if (config2.scope === "project" && LOCAL_PATH_PATTERN.test(server2.command)) {
|
|
23648
|
-
const resolved =
|
|
24176
|
+
const resolved = path10.resolve(projectRoot, server2.command);
|
|
23649
24177
|
if (!fileExistsSafe(resolved)) {
|
|
23650
24178
|
issues.push({
|
|
23651
24179
|
severity: "warning",
|
|
@@ -23660,8 +24188,8 @@ async function checkMcpCommands(config2, projectRoot) {
|
|
|
23660
24188
|
for (const arg of server2.args) {
|
|
23661
24189
|
if (URL_PREFIX.test(arg)) continue;
|
|
23662
24190
|
if (!LOCAL_PATH_PATTERN.test(arg) && !FILE_PATH_PATTERN.test(arg)) continue;
|
|
23663
|
-
if (config2.scope !== "project" && !
|
|
23664
|
-
const resolved =
|
|
24191
|
+
if (config2.scope !== "project" && !path10.isAbsolute(arg)) continue;
|
|
24192
|
+
const resolved = path10.resolve(projectRoot, arg);
|
|
23665
24193
|
if (!fileExistsSafe(resolved)) {
|
|
23666
24194
|
issues.push({
|
|
23667
24195
|
severity: "warning",
|
|
@@ -23678,7 +24206,7 @@ async function checkMcpCommands(config2, projectRoot) {
|
|
|
23678
24206
|
}
|
|
23679
24207
|
function fileExistsSafe(filePath) {
|
|
23680
24208
|
try {
|
|
23681
|
-
|
|
24209
|
+
fs7.accessSync(filePath);
|
|
23682
24210
|
return true;
|
|
23683
24211
|
} catch {
|
|
23684
24212
|
return false;
|
|
@@ -24109,16 +24637,16 @@ var init_redundancy2 = __esm({
|
|
|
24109
24637
|
|
|
24110
24638
|
// src/core/session-parser.ts
|
|
24111
24639
|
import { readFile } from "node:fs/promises";
|
|
24112
|
-
import { readFileSync as
|
|
24113
|
-
import { dirname as
|
|
24640
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
24641
|
+
import { dirname as dirname4, resolve as resolve7 } from "node:path";
|
|
24114
24642
|
import { fileURLToPath } from "node:url";
|
|
24115
24643
|
function loadWebFirstSegments() {
|
|
24116
24644
|
if (typeof define_WEB_FIRST_SEGMENTS_default !== "undefined") {
|
|
24117
24645
|
return new Set(define_WEB_FIRST_SEGMENTS_default);
|
|
24118
24646
|
}
|
|
24119
|
-
const __dir =
|
|
24120
|
-
const fixturePath =
|
|
24121
|
-
const raw = JSON.parse(
|
|
24647
|
+
const __dir = dirname4(fileURLToPath(import.meta.url));
|
|
24648
|
+
const fixturePath = resolve7(__dir, "../../tests/fixtures/web-first-segments.json");
|
|
24649
|
+
const raw = JSON.parse(readFileSync5(fixturePath, "utf-8"));
|
|
24122
24650
|
const list = Array.isArray(raw) ? raw : raw.segments;
|
|
24123
24651
|
return new Set(list);
|
|
24124
24652
|
}
|
|
@@ -24240,7 +24768,7 @@ import { readdir, stat } from "node:fs/promises";
|
|
|
24240
24768
|
import { createReadStream } from "node:fs";
|
|
24241
24769
|
import { homedir as homedir3 } from "node:os";
|
|
24242
24770
|
import { createInterface } from "node:readline";
|
|
24243
|
-
import { dirname as
|
|
24771
|
+
import { dirname as dirname5, join as join5, resolve as resolve8 } from "node:path";
|
|
24244
24772
|
import { existsSync } from "node:fs";
|
|
24245
24773
|
function detectProviders() {
|
|
24246
24774
|
if (!home) return [];
|
|
@@ -24355,7 +24883,7 @@ async function mapWithConcurrency(items, limit, fn) {
|
|
|
24355
24883
|
return results;
|
|
24356
24884
|
}
|
|
24357
24885
|
async function detectSiblings(projectRoot) {
|
|
24358
|
-
const parentDir =
|
|
24886
|
+
const parentDir = dirname5(resolve8(projectRoot));
|
|
24359
24887
|
let entries;
|
|
24360
24888
|
try {
|
|
24361
24889
|
entries = await readdir(parentDir);
|
|
@@ -24366,8 +24894,8 @@ async function detectSiblings(projectRoot) {
|
|
|
24366
24894
|
for (const entry of entries) {
|
|
24367
24895
|
if (entry.startsWith(".") || entry === "node_modules") continue;
|
|
24368
24896
|
const fullPath = join5(parentDir, entry);
|
|
24369
|
-
const entryPath =
|
|
24370
|
-
if (entryPath ===
|
|
24897
|
+
const entryPath = resolve8(fullPath);
|
|
24898
|
+
if (entryPath === resolve8(projectRoot)) continue;
|
|
24371
24899
|
try {
|
|
24372
24900
|
const s = await stat(fullPath);
|
|
24373
24901
|
if (!s.isDirectory()) continue;
|
|
@@ -24434,7 +24962,7 @@ async function scanSessionData(projectRoot) {
|
|
|
24434
24962
|
history: histories,
|
|
24435
24963
|
memories,
|
|
24436
24964
|
siblings,
|
|
24437
|
-
currentProject:
|
|
24965
|
+
currentProject: resolve8(projectRoot).replace(/\\/g, "/"),
|
|
24438
24966
|
providers
|
|
24439
24967
|
};
|
|
24440
24968
|
}
|
|
@@ -24475,9 +25003,9 @@ var init_session_scanner = __esm({
|
|
|
24475
25003
|
});
|
|
24476
25004
|
|
|
24477
25005
|
// src/core/checks/session/missing-secret.ts
|
|
24478
|
-
import { resolve as
|
|
25006
|
+
import { resolve as resolve9, basename as basename3 } from "node:path";
|
|
24479
25007
|
function normalizePath2(p2) {
|
|
24480
|
-
return
|
|
25008
|
+
return resolve9(p2).replace(/\\/g, "/").toLowerCase();
|
|
24481
25009
|
}
|
|
24482
25010
|
function extractSecretName(display) {
|
|
24483
25011
|
const prefixMatch = display.match(SECRET_SET_PREFIX);
|
|
@@ -24595,7 +25123,7 @@ var init_missing_secret = __esm({
|
|
|
24595
25123
|
|
|
24596
25124
|
// src/core/checks/session/diverged-file.ts
|
|
24597
25125
|
import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
24598
|
-
import { join as join6, resolve as
|
|
25126
|
+
import { join as join6, resolve as resolve10 } from "node:path";
|
|
24599
25127
|
import { existsSync as existsSync2 } from "node:fs";
|
|
24600
25128
|
async function loadLineSet(absPath) {
|
|
24601
25129
|
let mtimeMs;
|
|
@@ -24647,7 +25175,7 @@ async function checkDivergedFile(ctx) {
|
|
|
24647
25175
|
diverged.push({
|
|
24648
25176
|
sibling: sib.name,
|
|
24649
25177
|
overlap: Math.round(overlap * 100),
|
|
24650
|
-
path:
|
|
25178
|
+
path: resolve10(sibPath)
|
|
24651
25179
|
});
|
|
24652
25180
|
}
|
|
24653
25181
|
}
|
|
@@ -24662,7 +25190,7 @@ async function checkDivergedFile(ctx) {
|
|
|
24662
25190
|
line: 0,
|
|
24663
25191
|
message: `${fileName} has diverged from sibling repos: ${details}`,
|
|
24664
25192
|
suggestion: `Compare with sibling versions to identify unintentional drift`,
|
|
24665
|
-
detail: `File: ${
|
|
25193
|
+
detail: `File: ${resolve10(currentPath)}
|
|
24666
25194
|
Diverged siblings:
|
|
24667
25195
|
${sibPaths}`
|
|
24668
25196
|
});
|
|
@@ -24752,15 +25280,15 @@ var init_missing_workflow = __esm({
|
|
|
24752
25280
|
// src/core/checks/session/stale-memory.ts
|
|
24753
25281
|
import { existsSync as existsSync4 } from "node:fs";
|
|
24754
25282
|
import { homedir as homedir4 } from "node:os";
|
|
24755
|
-
import { resolve as
|
|
25283
|
+
import { resolve as resolve11, isAbsolute as isAbsolute5 } from "node:path";
|
|
24756
25284
|
function resolveRef(ref, projectRoot) {
|
|
24757
25285
|
if (ref.startsWith("~/") || ref === "~") {
|
|
24758
25286
|
const home2 = process.env.HOME || process.env.USERPROFILE || homedir4();
|
|
24759
25287
|
if (!home2) return null;
|
|
24760
|
-
return ref === "~" ? home2 :
|
|
25288
|
+
return ref === "~" ? home2 : resolve11(home2, ref.slice(2));
|
|
24761
25289
|
}
|
|
24762
25290
|
if (isAbsolute5(ref)) return ref;
|
|
24763
|
-
return
|
|
25291
|
+
return resolve11(projectRoot, ref);
|
|
24764
25292
|
}
|
|
24765
25293
|
async function checkStaleMemory(ctx) {
|
|
24766
25294
|
const issues = [];
|
|
@@ -24857,9 +25385,9 @@ var init_duplicate_memory = __esm({
|
|
|
24857
25385
|
});
|
|
24858
25386
|
|
|
24859
25387
|
// src/core/checks/session/loop-detection.ts
|
|
24860
|
-
import { resolve as
|
|
25388
|
+
import { resolve as resolve12 } from "node:path";
|
|
24861
25389
|
function normalizeProject(p2) {
|
|
24862
|
-
return
|
|
25390
|
+
return resolve12(p2).replace(/\\/g, "/");
|
|
24863
25391
|
}
|
|
24864
25392
|
function findConsecutiveRepeats(displays) {
|
|
24865
25393
|
const results = [];
|
|
@@ -25074,7 +25602,7 @@ var init_memory_index_overflow = __esm({
|
|
|
25074
25602
|
});
|
|
25075
25603
|
|
|
25076
25604
|
// src/core/transcript.ts
|
|
25077
|
-
import { createReadStream as createReadStream2, existsSync as existsSync5, statSync as
|
|
25605
|
+
import { createReadStream as createReadStream2, existsSync as existsSync5, statSync as statSync5 } from "node:fs";
|
|
25078
25606
|
import { readdir as readdir3 } from "node:fs/promises";
|
|
25079
25607
|
import { homedir as homedir6 } from "node:os";
|
|
25080
25608
|
import { join as join9 } from "node:path";
|
|
@@ -25116,7 +25644,7 @@ async function readUncached(project, home2) {
|
|
|
25116
25644
|
const files = names.filter(({ name }) => name.endsWith(".jsonl")).map(({ dir, name }) => {
|
|
25117
25645
|
const p2 = join9(dir, name);
|
|
25118
25646
|
try {
|
|
25119
|
-
return { p: p2, mtime:
|
|
25647
|
+
return { p: p2, mtime: statSync5(p2).mtimeMs };
|
|
25120
25648
|
} catch {
|
|
25121
25649
|
return null;
|
|
25122
25650
|
}
|
|
@@ -25486,6 +26014,106 @@ var init_default_branch_accumulation = __esm({
|
|
|
25486
26014
|
}
|
|
25487
26015
|
});
|
|
25488
26016
|
|
|
26017
|
+
// src/core/checks/session/unresolvable-sha.ts
|
|
26018
|
+
function stripFences(text) {
|
|
26019
|
+
const lines = text.split("\n");
|
|
26020
|
+
let inFence = false;
|
|
26021
|
+
return lines.map((line) => {
|
|
26022
|
+
if (line.trimStart().startsWith("```")) {
|
|
26023
|
+
inFence = !inFence;
|
|
26024
|
+
return "";
|
|
26025
|
+
}
|
|
26026
|
+
return inFence ? "" : line;
|
|
26027
|
+
}).join("\n");
|
|
26028
|
+
}
|
|
26029
|
+
function extractShaCitations(text) {
|
|
26030
|
+
const out = [];
|
|
26031
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26032
|
+
for (const rawLine of stripFences(text).split("\n")) {
|
|
26033
|
+
const line = rawLine.replace(UUID, " ");
|
|
26034
|
+
HEX_TOKEN.lastIndex = 0;
|
|
26035
|
+
for (const m of line.matchAll(HEX_TOKEN)) {
|
|
26036
|
+
const sha = m[0];
|
|
26037
|
+
const start = m.index ?? 0;
|
|
26038
|
+
const before = line.slice(0, start);
|
|
26039
|
+
const after = line.slice(start + sha.length);
|
|
26040
|
+
if (/^\d+$/.test(sha)) continue;
|
|
26041
|
+
if (/[#]$/.test(before) || /0x$/i.test(before)) continue;
|
|
26042
|
+
if (DIGEST_PREFIX.test(before)) continue;
|
|
26043
|
+
if (/[-.]$/.test(before) && /[\w]$/.test(before.slice(0, -1))) continue;
|
|
26044
|
+
if (/^[-.][0-9a-z]/i.test(after)) continue;
|
|
26045
|
+
if (/[/\\]$/.test(before) && /^[/\\]/.test(after)) continue;
|
|
26046
|
+
const window2 = before.slice(-CUE_WINDOW);
|
|
26047
|
+
if (!CITATION_CUE.test(window2)) continue;
|
|
26048
|
+
if (seen.has(sha)) continue;
|
|
26049
|
+
seen.add(sha);
|
|
26050
|
+
out.push({ sha, context: rawLine.trim().slice(0, 160) });
|
|
26051
|
+
}
|
|
26052
|
+
}
|
|
26053
|
+
return out;
|
|
26054
|
+
}
|
|
26055
|
+
async function checkUnresolvableSha(ctx) {
|
|
26056
|
+
const projectMemories = ctx.memories.filter(
|
|
26057
|
+
(m) => projectDirMatchesPath(m.projectDir, ctx.currentProject)
|
|
26058
|
+
);
|
|
26059
|
+
if (projectMemories.length === 0) return [];
|
|
26060
|
+
if (!await isGitRepo(ctx.currentProject)) return [];
|
|
26061
|
+
const git = getGit(ctx.currentProject);
|
|
26062
|
+
const resolvedCache = /* @__PURE__ */ new Map();
|
|
26063
|
+
let budget = MAX_RESOLVE;
|
|
26064
|
+
async function resolves(sha) {
|
|
26065
|
+
const cached2 = resolvedCache.get(sha);
|
|
26066
|
+
if (cached2 !== void 0) return cached2;
|
|
26067
|
+
if (budget <= 0) return null;
|
|
26068
|
+
budget--;
|
|
26069
|
+
let ok;
|
|
26070
|
+
try {
|
|
26071
|
+
const type = await git.raw(["cat-file", "-t", sha]);
|
|
26072
|
+
ok = type.trim().length > 0;
|
|
26073
|
+
} catch {
|
|
26074
|
+
ok = false;
|
|
26075
|
+
}
|
|
26076
|
+
resolvedCache.set(sha, ok);
|
|
26077
|
+
return ok;
|
|
26078
|
+
}
|
|
26079
|
+
const issues = [];
|
|
26080
|
+
for (const mem of projectMemories) {
|
|
26081
|
+
const dead = [];
|
|
26082
|
+
for (const cite of extractShaCitations(mem.content)) {
|
|
26083
|
+
const ok = await resolves(cite.sha);
|
|
26084
|
+
if (ok === false) dead.push(cite);
|
|
26085
|
+
}
|
|
26086
|
+
if (dead.length === 0) continue;
|
|
26087
|
+
const name = mem.name || mem.filePath.split(/[/\\]/).pop() || "unknown";
|
|
26088
|
+
const list = dead.map((d) => d.sha).join(", ");
|
|
26089
|
+
issues.push({
|
|
26090
|
+
severity: "warning",
|
|
26091
|
+
check: "session-unresolvable-sha",
|
|
26092
|
+
ruleId: "session-unresolvable-sha/unresolvable-sha",
|
|
26093
|
+
line: 0,
|
|
26094
|
+
message: `Memory "${name}" cites ${dead.length} commit(s) that do not resolve in this repository: ${list}`,
|
|
26095
|
+
detail: dead.map((d) => `${d.sha}: ${d.context}`).join("\n"),
|
|
26096
|
+
suggestion: `Re-resolve the citation and update ${mem.filePath}. A squash-merge or rebase rewrites SHAs, so a memory written before the merge points at a commit that no longer exists -- cite the landed commit, or the PR number, which survives the rewrite.`
|
|
26097
|
+
});
|
|
26098
|
+
}
|
|
26099
|
+
return issues;
|
|
26100
|
+
}
|
|
26101
|
+
var HEX_TOKEN, UUID, CITATION_CUE, CUE_WINDOW, DIGEST_PREFIX, MAX_RESOLVE;
|
|
26102
|
+
var init_unresolvable_sha = __esm({
|
|
26103
|
+
"src/core/checks/session/unresolvable-sha.ts"() {
|
|
26104
|
+
"use strict";
|
|
26105
|
+
init_define_WEB_FIRST_SEGMENTS();
|
|
26106
|
+
init_git();
|
|
26107
|
+
init_session_parser();
|
|
26108
|
+
HEX_TOKEN = /\b[0-9a-f]{7,40}\b/g;
|
|
26109
|
+
UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
|
|
26110
|
+
CITATION_CUE = /\b(commit|commits|committed|sha|revision|revs?|git|head|tag|tagged|branch|pr|landed|merged|shipped|introduced|reverted|cherry-?picked|backported|fixed|removed|added|renamed|bumped|released)\b/i;
|
|
26111
|
+
CUE_WINDOW = 80;
|
|
26112
|
+
DIGEST_PREFIX = /(sha\d{3}|md5|blake\d*|crc\d*)\s*[:=]\s*$/i;
|
|
26113
|
+
MAX_RESOLVE = 40;
|
|
26114
|
+
}
|
|
26115
|
+
});
|
|
26116
|
+
|
|
25489
26117
|
// src/core/checks/ci-coverage.ts
|
|
25490
26118
|
import { readdir as readdir4, readFile as readFile4 } from "node:fs/promises";
|
|
25491
26119
|
import { join as join10 } from "node:path";
|
|
@@ -25897,26 +26525,26 @@ var init_positions = __esm({
|
|
|
25897
26525
|
});
|
|
25898
26526
|
|
|
25899
26527
|
// src/core/checks/hook-coverage.ts
|
|
25900
|
-
import * as
|
|
26528
|
+
import * as fs8 from "node:fs";
|
|
25901
26529
|
import * as os3 from "node:os";
|
|
25902
|
-
import * as
|
|
26530
|
+
import * as path11 from "node:path";
|
|
25903
26531
|
function loadSettingsSources2(projectRoot, homeDir, includeUserGlobal) {
|
|
25904
26532
|
const home2 = homeDir;
|
|
25905
26533
|
const candidates = [
|
|
25906
26534
|
{
|
|
25907
|
-
filePath:
|
|
25908
|
-
displayPath:
|
|
26535
|
+
filePath: path11.join(projectRoot, ".claude", "settings.json"),
|
|
26536
|
+
displayPath: path11.join(".claude", "settings.json"),
|
|
25909
26537
|
isUserGlobal: false
|
|
25910
26538
|
},
|
|
25911
26539
|
{
|
|
25912
|
-
filePath:
|
|
25913
|
-
displayPath:
|
|
26540
|
+
filePath: path11.join(projectRoot, ".claude", "settings.local.json"),
|
|
26541
|
+
displayPath: path11.join(".claude", "settings.local.json"),
|
|
25914
26542
|
isUserGlobal: false
|
|
25915
26543
|
}
|
|
25916
26544
|
];
|
|
25917
26545
|
if (includeUserGlobal) {
|
|
25918
26546
|
candidates.push({
|
|
25919
|
-
filePath:
|
|
26547
|
+
filePath: path11.join(home2, ".claude", "settings.json"),
|
|
25920
26548
|
displayPath: "~/.claude/settings.json",
|
|
25921
26549
|
isUserGlobal: true
|
|
25922
26550
|
});
|
|
@@ -25925,7 +26553,7 @@ function loadSettingsSources2(projectRoot, homeDir, includeUserGlobal) {
|
|
|
25925
26553
|
for (const c3 of candidates) {
|
|
25926
26554
|
let content;
|
|
25927
26555
|
try {
|
|
25928
|
-
content = stripBom(
|
|
26556
|
+
content = stripBom(fs8.readFileSync(c3.filePath, "utf-8"));
|
|
25929
26557
|
} catch {
|
|
25930
26558
|
continue;
|
|
25931
26559
|
}
|
|
@@ -25937,11 +26565,11 @@ function loadSettingsSources2(projectRoot, homeDir, includeUserGlobal) {
|
|
|
25937
26565
|
function expandPath(raw, projectRoot, homeDir, platform) {
|
|
25938
26566
|
let s = raw;
|
|
25939
26567
|
if (s === "~" || s.startsWith("~/") || s.startsWith("~\\")) {
|
|
25940
|
-
s =
|
|
26568
|
+
s = path11.join(homeDir, s.slice(1));
|
|
25941
26569
|
}
|
|
25942
26570
|
const replacements = {
|
|
25943
26571
|
CLAUDE_PROJECT_DIR: projectRoot,
|
|
25944
|
-
CLAUDE_CONFIG_DIR:
|
|
26572
|
+
CLAUDE_CONFIG_DIR: path11.join(homeDir, ".claude"),
|
|
25945
26573
|
HOME: homeDir,
|
|
25946
26574
|
USERPROFILE: homeDir
|
|
25947
26575
|
};
|
|
@@ -25956,7 +26584,7 @@ function expandPath(raw, projectRoot, homeDir, platform) {
|
|
|
25956
26584
|
if (/\$\{?[A-Za-z_]/.test(s)) return null;
|
|
25957
26585
|
if (/%[A-Za-z_][A-Za-z0-9_]*%/.test(s)) return null;
|
|
25958
26586
|
s = translateMsysDrivePath(s, platform);
|
|
25959
|
-
if (!
|
|
26587
|
+
if (!path11.isAbsolute(s)) s = path11.resolve(projectRoot, s);
|
|
25960
26588
|
return s;
|
|
25961
26589
|
}
|
|
25962
26590
|
function looksLikePath(token) {
|
|
@@ -26094,19 +26722,19 @@ var init_hook_coverage = __esm({
|
|
|
26094
26722
|
});
|
|
26095
26723
|
|
|
26096
26724
|
// src/core/skill-scanner.ts
|
|
26097
|
-
import * as
|
|
26725
|
+
import * as fs9 from "node:fs";
|
|
26098
26726
|
import * as os4 from "node:os";
|
|
26099
|
-
import * as
|
|
26727
|
+
import * as path12 from "node:path";
|
|
26100
26728
|
function defaultHome() {
|
|
26101
26729
|
return process.env.HOME || process.env.USERPROFILE || os4.homedir();
|
|
26102
26730
|
}
|
|
26103
26731
|
function scanSkillFiles(homeDir = defaultHome()) {
|
|
26104
26732
|
const files = [];
|
|
26105
26733
|
const orphanedSkillDirs = [];
|
|
26106
|
-
const claudeDir =
|
|
26107
|
-
const skillsRoot =
|
|
26734
|
+
const claudeDir = path12.join(homeDir, ".claude");
|
|
26735
|
+
const skillsRoot = path12.join(claudeDir, "skills");
|
|
26108
26736
|
for (const name of safeReadDir(skillsRoot, "dir")) {
|
|
26109
|
-
const skillMd =
|
|
26737
|
+
const skillMd = path12.join(skillsRoot, name, "SKILL.md");
|
|
26110
26738
|
const content = safeRead(skillMd);
|
|
26111
26739
|
if (content === null) {
|
|
26112
26740
|
orphanedSkillDirs.push({ name, displayPath: `~/.claude/skills/${name}/` });
|
|
@@ -26120,10 +26748,10 @@ function scanSkillFiles(homeDir = defaultHome()) {
|
|
|
26120
26748
|
content
|
|
26121
26749
|
});
|
|
26122
26750
|
}
|
|
26123
|
-
const agentsRoot =
|
|
26751
|
+
const agentsRoot = path12.join(claudeDir, "agents");
|
|
26124
26752
|
for (const fileName of safeReadDir(agentsRoot, "file")) {
|
|
26125
26753
|
if (!fileName.endsWith(".md")) continue;
|
|
26126
|
-
const agentMd =
|
|
26754
|
+
const agentMd = path12.join(agentsRoot, fileName);
|
|
26127
26755
|
const content = safeRead(agentMd);
|
|
26128
26756
|
if (content === null) continue;
|
|
26129
26757
|
files.push({
|
|
@@ -26139,7 +26767,7 @@ function scanSkillFiles(homeDir = defaultHome()) {
|
|
|
26139
26767
|
function safeReadDir(dir, want) {
|
|
26140
26768
|
let entries;
|
|
26141
26769
|
try {
|
|
26142
|
-
entries =
|
|
26770
|
+
entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
26143
26771
|
} catch {
|
|
26144
26772
|
return [];
|
|
26145
26773
|
}
|
|
@@ -26147,7 +26775,7 @@ function safeReadDir(dir, want) {
|
|
|
26147
26775
|
if (want === "dir" ? e.isDirectory() : e.isFile()) return true;
|
|
26148
26776
|
if (!e.isSymbolicLink()) return false;
|
|
26149
26777
|
try {
|
|
26150
|
-
const target =
|
|
26778
|
+
const target = fs9.statSync(path12.join(dir, e.name));
|
|
26151
26779
|
return want === "dir" ? target.isDirectory() : target.isFile();
|
|
26152
26780
|
} catch {
|
|
26153
26781
|
return false;
|
|
@@ -26156,7 +26784,7 @@ function safeReadDir(dir, want) {
|
|
|
26156
26784
|
}
|
|
26157
26785
|
function safeRead(file2) {
|
|
26158
26786
|
try {
|
|
26159
|
-
return stripBom(
|
|
26787
|
+
return stripBom(fs9.readFileSync(file2, "utf-8"));
|
|
26160
26788
|
} catch {
|
|
26161
26789
|
return null;
|
|
26162
26790
|
}
|
|
@@ -26170,7 +26798,7 @@ var init_skill_scanner = __esm({
|
|
|
26170
26798
|
});
|
|
26171
26799
|
|
|
26172
26800
|
// src/core/checks/skills.ts
|
|
26173
|
-
import * as
|
|
26801
|
+
import * as path13 from "node:path";
|
|
26174
26802
|
function parseFrontmatter3(content) {
|
|
26175
26803
|
const lines = content.split("\n");
|
|
26176
26804
|
if (lines[0]?.trim() !== "---") {
|
|
@@ -26247,7 +26875,7 @@ function checkMissingFrontmatter(file2, fm) {
|
|
|
26247
26875
|
}
|
|
26248
26876
|
function checkBrokenRefs(file2, fmEndLine) {
|
|
26249
26877
|
const issues = [];
|
|
26250
|
-
const skillDir =
|
|
26878
|
+
const skillDir = path13.dirname(file2.filePath);
|
|
26251
26879
|
const lines = file2.content.split("\n");
|
|
26252
26880
|
let inCode = false;
|
|
26253
26881
|
let codeLang = "";
|
|
@@ -26267,7 +26895,7 @@ function checkBrokenRefs(file2, fmEndLine) {
|
|
|
26267
26895
|
if (PATH_SKIP.test(value)) continue;
|
|
26268
26896
|
if (!value.startsWith("./") && !value.startsWith("../")) continue;
|
|
26269
26897
|
while (/[.,;:]$/.test(value)) value = value.slice(0, -1);
|
|
26270
|
-
const resolved =
|
|
26898
|
+
const resolved = path13.resolve(skillDir, value);
|
|
26271
26899
|
if (fileExists(resolved) || isDirectory(resolved)) continue;
|
|
26272
26900
|
issues.push({
|
|
26273
26901
|
severity: "warning",
|
|
@@ -26775,8 +27403,8 @@ var require_utils = __commonJS({
|
|
|
26775
27403
|
}
|
|
26776
27404
|
return output;
|
|
26777
27405
|
};
|
|
26778
|
-
exports.basename = (
|
|
26779
|
-
const segs =
|
|
27406
|
+
exports.basename = (path21, { windows } = {}) => {
|
|
27407
|
+
const segs = path21.split(windows ? /[\\/]/ : "/");
|
|
26780
27408
|
const last2 = segs[segs.length - 1];
|
|
26781
27409
|
if (last2 === "") {
|
|
26782
27410
|
return segs[segs.length - 2];
|
|
@@ -28275,16 +28903,16 @@ var require_picomatch2 = __commonJS({
|
|
|
28275
28903
|
});
|
|
28276
28904
|
|
|
28277
28905
|
// src/core/ignore-file.ts
|
|
28278
|
-
import
|
|
28279
|
-
import
|
|
28906
|
+
import fs10 from "node:fs";
|
|
28907
|
+
import path14 from "node:path";
|
|
28280
28908
|
function matchesGlob(filePath, glob) {
|
|
28281
28909
|
return (0, import_picomatch.default)(glob, { dot: true })(filePath);
|
|
28282
28910
|
}
|
|
28283
28911
|
function loadIgnoreFile(projectRoot) {
|
|
28284
|
-
const ignoreFilePath =
|
|
28912
|
+
const ignoreFilePath = path14.join(projectRoot, ".ctxlintignore");
|
|
28285
28913
|
let content;
|
|
28286
28914
|
try {
|
|
28287
|
-
content =
|
|
28915
|
+
content = fs10.readFileSync(ignoreFilePath, "utf-8");
|
|
28288
28916
|
} catch {
|
|
28289
28917
|
return [];
|
|
28290
28918
|
}
|
|
@@ -28330,15 +28958,15 @@ var init_types = __esm({
|
|
|
28330
28958
|
});
|
|
28331
28959
|
|
|
28332
28960
|
// src/version.ts
|
|
28333
|
-
import { readFileSync as
|
|
28334
|
-
import { resolve as
|
|
28961
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
28962
|
+
import { resolve as resolve15, dirname as dirname7 } from "node:path";
|
|
28335
28963
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
28336
28964
|
function loadVersion() {
|
|
28337
|
-
if (true) return "0.
|
|
28965
|
+
if (true) return "0.19.0";
|
|
28338
28966
|
try {
|
|
28339
|
-
const __dir =
|
|
28340
|
-
const pkgPath =
|
|
28341
|
-
const pkg = JSON.parse(
|
|
28967
|
+
const __dir = dirname7(fileURLToPath2(import.meta.url));
|
|
28968
|
+
const pkgPath = resolve15(__dir, "../package.json");
|
|
28969
|
+
const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
28342
28970
|
return pkg.version ?? "0.0.0-dev";
|
|
28343
28971
|
} catch {
|
|
28344
28972
|
return "0.0.0-dev";
|
|
@@ -28354,9 +28982,9 @@ var init_version2 = __esm({
|
|
|
28354
28982
|
});
|
|
28355
28983
|
|
|
28356
28984
|
// src/core/audit.ts
|
|
28357
|
-
import * as
|
|
28985
|
+
import * as fs11 from "node:fs";
|
|
28358
28986
|
import * as os5 from "node:os";
|
|
28359
|
-
import * as
|
|
28987
|
+
import * as path15 from "node:path";
|
|
28360
28988
|
function hasMcpChecks(checks) {
|
|
28361
28989
|
return checks.some((c3) => c3.startsWith("mcp-"));
|
|
28362
28990
|
}
|
|
@@ -28392,7 +29020,7 @@ async function runAudit(projectRoot, activeChecks, options = {}) {
|
|
|
28392
29020
|
const absPath = discoveredFile.absolutePath;
|
|
28393
29021
|
let stat3 = null;
|
|
28394
29022
|
try {
|
|
28395
|
-
const s =
|
|
29023
|
+
const s = fs11.statSync(absPath);
|
|
28396
29024
|
stat3 = { mtimeMs: s.mtimeMs, size: s.size };
|
|
28397
29025
|
} catch {
|
|
28398
29026
|
}
|
|
@@ -28405,7 +29033,8 @@ async function runAudit(projectRoot, activeChecks, options = {}) {
|
|
|
28405
29033
|
const parseResult = parseContextFile(discoveredFile);
|
|
28406
29034
|
parsed.push(parseResult);
|
|
28407
29035
|
const checkPromises = [];
|
|
28408
|
-
if (activeChecks.includes("paths"))
|
|
29036
|
+
if (activeChecks.includes("paths"))
|
|
29037
|
+
checkPromises.push(checkPaths(parseResult, projectRoot));
|
|
28409
29038
|
if (activeChecks.includes("commands"))
|
|
28410
29039
|
checkPromises.push(checkCommands(parseResult, projectRoot));
|
|
28411
29040
|
if (activeChecks.includes("staleness"))
|
|
@@ -28579,6 +29208,8 @@ async function runAudit(projectRoot, activeChecks, options = {}) {
|
|
|
28579
29208
|
sessionPromises.push(checkUnverifiedGateClaimedClean(sessionCtx));
|
|
28580
29209
|
if (sessionChecksToRun.includes("session-default-branch-accumulation"))
|
|
28581
29210
|
sessionPromises.push(checkDefaultBranchAccumulation(sessionCtx));
|
|
29211
|
+
if (sessionChecksToRun.includes("session-unresolvable-sha"))
|
|
29212
|
+
sessionPromises.push(checkUnresolvableSha(sessionCtx));
|
|
28582
29213
|
const sessionResults = await Promise.all(sessionPromises);
|
|
28583
29214
|
const sessionIssues = sessionResults.flat();
|
|
28584
29215
|
fileResults.push({
|
|
@@ -28640,10 +29271,7 @@ async function runAudit(projectRoot, activeChecks, options = {}) {
|
|
|
28640
29271
|
globUnusedRules = globScopedRules.filter((r2) => !firedGlobRules.has(r2)).map(({ _fileGlob: _unused, ...rest }) => rest);
|
|
28641
29272
|
globRulesMissingReason = globScopedRules.filter((r2) => !r2.reason).map(({ _fileGlob: _unused, ...rest }) => rest);
|
|
28642
29273
|
}
|
|
28643
|
-
const allIgnoreRules = [
|
|
28644
|
-
...options.ignoreRules ?? [],
|
|
28645
|
-
...globalFileRules
|
|
28646
|
-
];
|
|
29274
|
+
const allIgnoreRules = [...options.ignoreRules ?? [], ...globalFileRules];
|
|
28647
29275
|
let ignoreReport;
|
|
28648
29276
|
if (allIgnoreRules.length > 0 || globDropped > 0) {
|
|
28649
29277
|
let flatDropped = 0;
|
|
@@ -28717,29 +29345,33 @@ async function runAudit(projectRoot, activeChecks, options = {}) {
|
|
|
28717
29345
|
return result;
|
|
28718
29346
|
}
|
|
28719
29347
|
async function runAuditOnContent(filePath, content, projectRoot, options = {}) {
|
|
28720
|
-
const tmpDir =
|
|
28721
|
-
const ext =
|
|
28722
|
-
const tmpFile =
|
|
29348
|
+
const tmpDir = fs11.mkdtempSync(path15.join(os5.tmpdir(), "ctxlint-lsp-"));
|
|
29349
|
+
const ext = path15.extname(filePath) || ".md";
|
|
29350
|
+
const tmpFile = path15.join(tmpDir, "content" + ext);
|
|
28723
29351
|
try {
|
|
28724
|
-
|
|
28725
|
-
const tmpRelative =
|
|
28726
|
-
const rawResult = await runAudit(
|
|
28727
|
-
|
|
28728
|
-
|
|
28729
|
-
|
|
28730
|
-
|
|
28731
|
-
|
|
28732
|
-
|
|
28733
|
-
|
|
28734
|
-
|
|
29352
|
+
fs11.writeFileSync(tmpFile, content, "utf-8");
|
|
29353
|
+
const tmpRelative = path15.relative(tmpDir, tmpFile);
|
|
29354
|
+
const rawResult = await runAudit(
|
|
29355
|
+
tmpDir,
|
|
29356
|
+
options.depth !== void 0 ? ALL_CHECKS : ALL_CHECKS,
|
|
29357
|
+
{
|
|
29358
|
+
...options,
|
|
29359
|
+
extraPatterns: [tmpRelative],
|
|
29360
|
+
// Disable cross-project checks that need the real project tree.
|
|
29361
|
+
session: false,
|
|
29362
|
+
sessionOnly: false,
|
|
29363
|
+
skills: false,
|
|
29364
|
+
skillsOnly: false
|
|
29365
|
+
}
|
|
29366
|
+
);
|
|
28735
29367
|
const remapped = rawResult.files.map((fr) => {
|
|
28736
|
-
const isTmp = fr.path === tmpRelative || fr.path === tmpFile ||
|
|
29368
|
+
const isTmp = fr.path === tmpRelative || fr.path === tmpFile || path15.resolve(tmpDir, fr.path) === tmpFile;
|
|
28737
29369
|
return isTmp ? { ...fr, path: filePath } : fr;
|
|
28738
29370
|
});
|
|
28739
29371
|
return { ...rawResult, files: remapped, projectRoot };
|
|
28740
29372
|
} finally {
|
|
28741
29373
|
try {
|
|
28742
|
-
|
|
29374
|
+
fs11.rmSync(tmpDir, { recursive: true, force: true });
|
|
28743
29375
|
} catch {
|
|
28744
29376
|
}
|
|
28745
29377
|
}
|
|
@@ -28782,6 +29414,7 @@ var init_audit = __esm({
|
|
|
28782
29414
|
init_shared_temp_path();
|
|
28783
29415
|
init_unverified_gate_claimed_clean();
|
|
28784
29416
|
init_default_branch_accumulation();
|
|
29417
|
+
init_unresolvable_sha();
|
|
28785
29418
|
init_ci_coverage();
|
|
28786
29419
|
init_ci_secrets();
|
|
28787
29420
|
init_content_secrets();
|
|
@@ -28826,7 +29459,8 @@ var init_audit = __esm({
|
|
|
28826
29459
|
"session-memory-index-overflow",
|
|
28827
29460
|
"session-shared-temp-path",
|
|
28828
29461
|
"session-unverified-gate-claimed-clean",
|
|
28829
|
-
"session-default-branch-accumulation"
|
|
29462
|
+
"session-default-branch-accumulation",
|
|
29463
|
+
"session-unresolvable-sha"
|
|
28830
29464
|
];
|
|
28831
29465
|
ALL_SKILL_CHECKS = [
|
|
28832
29466
|
"skill-frontmatter",
|
|
@@ -28843,7 +29477,7 @@ var server_exports = {};
|
|
|
28843
29477
|
__export(server_exports, {
|
|
28844
29478
|
startLspServer: () => startLspServer
|
|
28845
29479
|
});
|
|
28846
|
-
import * as
|
|
29480
|
+
import * as path16 from "node:path";
|
|
28847
29481
|
async function startLspServer() {
|
|
28848
29482
|
const connection = (0, import_node.createConnection)(import_node.ProposedFeatures.all);
|
|
28849
29483
|
const documents = new import_node.TextDocuments(TextDocument2);
|
|
@@ -28858,7 +29492,7 @@ async function startLspServer() {
|
|
|
28858
29492
|
const uri = doc.uri;
|
|
28859
29493
|
let filePath = uri.startsWith("file://") ? decodeURIComponent(uri.slice(7)) : uri;
|
|
28860
29494
|
filePath = filePath.replace(/^\/([A-Za-z]:)/, "$1");
|
|
28861
|
-
const projectRoot =
|
|
29495
|
+
const projectRoot = path16.dirname(filePath);
|
|
28862
29496
|
try {
|
|
28863
29497
|
const result = await runAuditOnContent(filePath, doc.getText(), projectRoot, {
|
|
28864
29498
|
depth: 2
|
|
@@ -29310,8 +29944,8 @@ var init_parseUtil = __esm({
|
|
|
29310
29944
|
init_errors();
|
|
29311
29945
|
init_en();
|
|
29312
29946
|
makeIssue = (params) => {
|
|
29313
|
-
const { data, path:
|
|
29314
|
-
const fullPath = [...
|
|
29947
|
+
const { data, path: path21, errorMaps, issueData } = params;
|
|
29948
|
+
const fullPath = [...path21, ...issueData.path || []];
|
|
29315
29949
|
const fullIssue = {
|
|
29316
29950
|
...issueData,
|
|
29317
29951
|
path: fullPath
|
|
@@ -29594,11 +30228,11 @@ var init_types2 = __esm({
|
|
|
29594
30228
|
init_parseUtil();
|
|
29595
30229
|
init_util2();
|
|
29596
30230
|
ParseInputLazyPath = class {
|
|
29597
|
-
constructor(parent, value,
|
|
30231
|
+
constructor(parent, value, path21, key) {
|
|
29598
30232
|
this._cachedPath = [];
|
|
29599
30233
|
this.parent = parent;
|
|
29600
30234
|
this.data = value;
|
|
29601
|
-
this._path =
|
|
30235
|
+
this._path = path21;
|
|
29602
30236
|
this._key = key;
|
|
29603
30237
|
}
|
|
29604
30238
|
get path() {
|
|
@@ -33100,10 +33734,10 @@ function mergeDefs(...defs) {
|
|
|
33100
33734
|
function cloneDef(schema) {
|
|
33101
33735
|
return mergeDefs(schema._zod.def);
|
|
33102
33736
|
}
|
|
33103
|
-
function getElementAtPath(obj,
|
|
33104
|
-
if (!
|
|
33737
|
+
function getElementAtPath(obj, path21) {
|
|
33738
|
+
if (!path21)
|
|
33105
33739
|
return obj;
|
|
33106
|
-
return
|
|
33740
|
+
return path21.reduce((acc, key) => acc?.[key], obj);
|
|
33107
33741
|
}
|
|
33108
33742
|
function promiseAllObject(promisesObj) {
|
|
33109
33743
|
const keys = Object.keys(promisesObj);
|
|
@@ -33431,11 +34065,11 @@ function explicitlyAborted(x3, startIndex = 0) {
|
|
|
33431
34065
|
}
|
|
33432
34066
|
return false;
|
|
33433
34067
|
}
|
|
33434
|
-
function prefixIssues(
|
|
34068
|
+
function prefixIssues(path21, issues) {
|
|
33435
34069
|
return issues.map((iss) => {
|
|
33436
34070
|
var _a4;
|
|
33437
34071
|
(_a4 = iss).path ?? (_a4.path = []);
|
|
33438
|
-
iss.path.unshift(
|
|
34072
|
+
iss.path.unshift(path21);
|
|
33439
34073
|
return iss;
|
|
33440
34074
|
});
|
|
33441
34075
|
}
|
|
@@ -33653,16 +34287,16 @@ function flattenError(error52, mapper = (issue2) => issue2.message) {
|
|
|
33653
34287
|
}
|
|
33654
34288
|
function formatError(error52, mapper = (issue2) => issue2.message) {
|
|
33655
34289
|
const fieldErrors = { _errors: [] };
|
|
33656
|
-
const processError = (error53,
|
|
34290
|
+
const processError = (error53, path21 = []) => {
|
|
33657
34291
|
for (const issue2 of error53.issues) {
|
|
33658
34292
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
33659
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
34293
|
+
issue2.errors.map((issues) => processError({ issues }, [...path21, ...issue2.path]));
|
|
33660
34294
|
} else if (issue2.code === "invalid_key") {
|
|
33661
|
-
processError({ issues: issue2.issues }, [...
|
|
34295
|
+
processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
|
|
33662
34296
|
} else if (issue2.code === "invalid_element") {
|
|
33663
|
-
processError({ issues: issue2.issues }, [...
|
|
34297
|
+
processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
|
|
33664
34298
|
} else {
|
|
33665
|
-
const fullpath = [...
|
|
34299
|
+
const fullpath = [...path21, ...issue2.path];
|
|
33666
34300
|
if (fullpath.length === 0) {
|
|
33667
34301
|
fieldErrors._errors.push(mapper(issue2));
|
|
33668
34302
|
} else {
|
|
@@ -33689,17 +34323,17 @@ function formatError(error52, mapper = (issue2) => issue2.message) {
|
|
|
33689
34323
|
}
|
|
33690
34324
|
function treeifyError(error52, mapper = (issue2) => issue2.message) {
|
|
33691
34325
|
const result = { errors: [] };
|
|
33692
|
-
const processError = (error53,
|
|
34326
|
+
const processError = (error53, path21 = []) => {
|
|
33693
34327
|
var _a4, _b;
|
|
33694
34328
|
for (const issue2 of error53.issues) {
|
|
33695
34329
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
33696
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
34330
|
+
issue2.errors.map((issues) => processError({ issues }, [...path21, ...issue2.path]));
|
|
33697
34331
|
} else if (issue2.code === "invalid_key") {
|
|
33698
|
-
processError({ issues: issue2.issues }, [...
|
|
34332
|
+
processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
|
|
33699
34333
|
} else if (issue2.code === "invalid_element") {
|
|
33700
|
-
processError({ issues: issue2.issues }, [...
|
|
34334
|
+
processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
|
|
33701
34335
|
} else {
|
|
33702
|
-
const fullpath = [...
|
|
34336
|
+
const fullpath = [...path21, ...issue2.path];
|
|
33703
34337
|
if (fullpath.length === 0) {
|
|
33704
34338
|
result.errors.push(mapper(issue2));
|
|
33705
34339
|
continue;
|
|
@@ -33731,8 +34365,8 @@ function treeifyError(error52, mapper = (issue2) => issue2.message) {
|
|
|
33731
34365
|
}
|
|
33732
34366
|
function toDotPath(_path) {
|
|
33733
34367
|
const segs = [];
|
|
33734
|
-
const
|
|
33735
|
-
for (const seg of
|
|
34368
|
+
const path21 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
34369
|
+
for (const seg of path21) {
|
|
33736
34370
|
if (typeof seg === "number")
|
|
33737
34371
|
segs.push(`[${seg}]`);
|
|
33738
34372
|
else if (typeof seg === "symbol")
|
|
@@ -47493,13 +48127,13 @@ function resolveRef2(ref, ctx) {
|
|
|
47493
48127
|
if (!ref.startsWith("#")) {
|
|
47494
48128
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
47495
48129
|
}
|
|
47496
|
-
const
|
|
47497
|
-
if (
|
|
48130
|
+
const path21 = ref.slice(1).split("/").filter(Boolean);
|
|
48131
|
+
if (path21.length === 0) {
|
|
47498
48132
|
return ctx.rootSchema;
|
|
47499
48133
|
}
|
|
47500
48134
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
47501
|
-
if (
|
|
47502
|
-
const key =
|
|
48135
|
+
if (path21[0] === defsKey) {
|
|
48136
|
+
const key = path21[1];
|
|
47503
48137
|
if (!key || !ctx.defs[key]) {
|
|
47504
48138
|
throw new Error(`Reference not found: ${ref}`);
|
|
47505
48139
|
}
|
|
@@ -52013,7 +52647,7 @@ var init_protocol = __esm({
|
|
|
52013
52647
|
return;
|
|
52014
52648
|
}
|
|
52015
52649
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
52016
|
-
await new Promise((
|
|
52650
|
+
await new Promise((resolve19) => setTimeout(resolve19, pollInterval));
|
|
52017
52651
|
options?.signal?.throwIfAborted();
|
|
52018
52652
|
}
|
|
52019
52653
|
} catch (error52) {
|
|
@@ -52030,7 +52664,7 @@ var init_protocol = __esm({
|
|
|
52030
52664
|
*/
|
|
52031
52665
|
request(request, resultSchema, options) {
|
|
52032
52666
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
52033
|
-
return new Promise((
|
|
52667
|
+
return new Promise((resolve19, reject) => {
|
|
52034
52668
|
const earlyReject = (error52) => {
|
|
52035
52669
|
reject(error52);
|
|
52036
52670
|
};
|
|
@@ -52108,7 +52742,7 @@ var init_protocol = __esm({
|
|
|
52108
52742
|
if (!parseResult.success) {
|
|
52109
52743
|
reject(parseResult.error);
|
|
52110
52744
|
} else {
|
|
52111
|
-
|
|
52745
|
+
resolve19(parseResult.data);
|
|
52112
52746
|
}
|
|
52113
52747
|
} catch (error52) {
|
|
52114
52748
|
reject(error52);
|
|
@@ -52369,12 +53003,12 @@ var init_protocol = __esm({
|
|
|
52369
53003
|
}
|
|
52370
53004
|
} catch {
|
|
52371
53005
|
}
|
|
52372
|
-
return new Promise((
|
|
53006
|
+
return new Promise((resolve19, reject) => {
|
|
52373
53007
|
if (signal.aborted) {
|
|
52374
53008
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
52375
53009
|
return;
|
|
52376
53010
|
}
|
|
52377
|
-
const timeoutId = setTimeout(
|
|
53011
|
+
const timeoutId = setTimeout(resolve19, interval);
|
|
52378
53012
|
signal.addEventListener("abort", () => {
|
|
52379
53013
|
clearTimeout(timeoutId);
|
|
52380
53014
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -55422,7 +56056,7 @@ var require_compile = __commonJS({
|
|
|
55422
56056
|
const schOrFunc = root.refs[ref];
|
|
55423
56057
|
if (schOrFunc)
|
|
55424
56058
|
return schOrFunc;
|
|
55425
|
-
let _sch =
|
|
56059
|
+
let _sch = resolve19.call(this, root, ref);
|
|
55426
56060
|
if (_sch === void 0) {
|
|
55427
56061
|
const schema = (_a4 = root.localRefs) === null || _a4 === void 0 ? void 0 : _a4[ref];
|
|
55428
56062
|
const { schemaId } = this.opts;
|
|
@@ -55449,7 +56083,7 @@ var require_compile = __commonJS({
|
|
|
55449
56083
|
function sameSchemaEnv(s1, s2) {
|
|
55450
56084
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
55451
56085
|
}
|
|
55452
|
-
function
|
|
56086
|
+
function resolve19(root, ref) {
|
|
55453
56087
|
let sch;
|
|
55454
56088
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
55455
56089
|
ref = sch;
|
|
@@ -55668,8 +56302,8 @@ var require_utils2 = __commonJS({
|
|
|
55668
56302
|
}
|
|
55669
56303
|
return ind;
|
|
55670
56304
|
}
|
|
55671
|
-
function removeDotSegments(
|
|
55672
|
-
let input =
|
|
56305
|
+
function removeDotSegments(path21) {
|
|
56306
|
+
let input = path21;
|
|
55673
56307
|
const output = [];
|
|
55674
56308
|
let nextSlash = -1;
|
|
55675
56309
|
let len = 0;
|
|
@@ -55922,8 +56556,8 @@ var require_schemes = __commonJS({
|
|
|
55922
56556
|
wsComponent.secure = void 0;
|
|
55923
56557
|
}
|
|
55924
56558
|
if (wsComponent.resourceName) {
|
|
55925
|
-
const [
|
|
55926
|
-
wsComponent.path =
|
|
56559
|
+
const [path21, query] = wsComponent.resourceName.split("?");
|
|
56560
|
+
wsComponent.path = path21 && path21 !== "/" ? path21 : void 0;
|
|
55927
56561
|
wsComponent.query = query;
|
|
55928
56562
|
wsComponent.resourceName = void 0;
|
|
55929
56563
|
}
|
|
@@ -56083,7 +56717,7 @@ var require_fast_uri = __commonJS({
|
|
|
56083
56717
|
}
|
|
56084
56718
|
return uri;
|
|
56085
56719
|
}
|
|
56086
|
-
function
|
|
56720
|
+
function resolve19(baseURI, relativeURI, options) {
|
|
56087
56721
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
56088
56722
|
const resolved = resolveComponent(parse5(baseURI, schemelessOptions), parse5(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
56089
56723
|
schemelessOptions.skipEscape = true;
|
|
@@ -56341,7 +56975,7 @@ var require_fast_uri = __commonJS({
|
|
|
56341
56975
|
var fastUri = {
|
|
56342
56976
|
SCHEMES,
|
|
56343
56977
|
normalize: normalize4,
|
|
56344
|
-
resolve:
|
|
56978
|
+
resolve: resolve19,
|
|
56345
56979
|
resolveComponent,
|
|
56346
56980
|
equal,
|
|
56347
56981
|
serialize,
|
|
@@ -59362,12 +59996,12 @@ var require_dist3 = __commonJS({
|
|
|
59362
59996
|
throw new Error(`Unknown format "${name}"`);
|
|
59363
59997
|
return f;
|
|
59364
59998
|
};
|
|
59365
|
-
function addFormats(ajv, list,
|
|
59999
|
+
function addFormats(ajv, list, fs16, exportName) {
|
|
59366
60000
|
var _a4;
|
|
59367
60001
|
var _b;
|
|
59368
60002
|
(_a4 = (_b = ajv.opts.code).formats) !== null && _a4 !== void 0 ? _a4 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
59369
60003
|
for (const f of list)
|
|
59370
|
-
ajv.addFormat(f,
|
|
60004
|
+
ajv.addFormat(f, fs16[f]);
|
|
59371
60005
|
}
|
|
59372
60006
|
module.exports = exports = formatsPlugin;
|
|
59373
60007
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -60523,7 +61157,7 @@ var init_mcp = __esm({
|
|
|
60523
61157
|
let task = createTaskResult.task;
|
|
60524
61158
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
60525
61159
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
60526
|
-
await new Promise((
|
|
61160
|
+
await new Promise((resolve19) => setTimeout(resolve19, pollInterval));
|
|
60527
61161
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
60528
61162
|
if (!updatedTask) {
|
|
60529
61163
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -61119,12 +61753,12 @@ var init_stdio2 = __esm({
|
|
|
61119
61753
|
this.onclose?.();
|
|
61120
61754
|
}
|
|
61121
61755
|
send(message) {
|
|
61122
|
-
return new Promise((
|
|
61756
|
+
return new Promise((resolve19) => {
|
|
61123
61757
|
const json2 = serializeMessage(message);
|
|
61124
61758
|
if (this._stdout.write(json2)) {
|
|
61125
|
-
|
|
61759
|
+
resolve19();
|
|
61126
61760
|
} else {
|
|
61127
|
-
this._stdout.once("drain",
|
|
61761
|
+
this._stdout.once("drain", resolve19);
|
|
61128
61762
|
}
|
|
61129
61763
|
});
|
|
61130
61764
|
}
|
|
@@ -61675,7 +62309,7 @@ var init_source = __esm({
|
|
|
61675
62309
|
});
|
|
61676
62310
|
|
|
61677
62311
|
// src/core/fixer.ts
|
|
61678
|
-
import * as
|
|
62312
|
+
import * as fs12 from "node:fs";
|
|
61679
62313
|
function applyFixes(result, options = {}) {
|
|
61680
62314
|
const log = options.quiet ? () => {
|
|
61681
62315
|
} : console.log.bind(console);
|
|
@@ -61713,7 +62347,7 @@ function applyFixes(result, options = {}) {
|
|
|
61713
62347
|
for (const [filePath, fixes] of fixesByFile) {
|
|
61714
62348
|
let content;
|
|
61715
62349
|
try {
|
|
61716
|
-
content =
|
|
62350
|
+
content = fs12.readFileSync(filePath, "utf-8");
|
|
61717
62351
|
} catch (err) {
|
|
61718
62352
|
log(source_default.yellow(" Skipped") + ` ${filePath}: ${err.message}`);
|
|
61719
62353
|
continue;
|
|
@@ -61798,7 +62432,7 @@ function applyFixes(result, options = {}) {
|
|
|
61798
62432
|
}
|
|
61799
62433
|
if (!dryRun) {
|
|
61800
62434
|
try {
|
|
61801
|
-
|
|
62435
|
+
fs12.writeFileSync(filePath, newContent, "utf-8");
|
|
61802
62436
|
} catch (err) {
|
|
61803
62437
|
log(source_default.yellow(" Skipped") + ` ${filePath}: ${err.message}`);
|
|
61804
62438
|
continue;
|
|
@@ -61820,8 +62454,8 @@ var init_fixer = __esm({
|
|
|
61820
62454
|
});
|
|
61821
62455
|
|
|
61822
62456
|
// src/core/config.ts
|
|
61823
|
-
import * as
|
|
61824
|
-
import * as
|
|
62457
|
+
import * as fs13 from "node:fs";
|
|
62458
|
+
import * as path17 from "node:path";
|
|
61825
62459
|
function formatJsonError(content, err) {
|
|
61826
62460
|
const msg = err instanceof Error ? err.message : String(err);
|
|
61827
62461
|
const posMatch = msg.match(/position (\d+)/);
|
|
@@ -61919,10 +62553,10 @@ function warnIgnoreRulePathPatternMisuse(config2, source) {
|
|
|
61919
62553
|
}
|
|
61920
62554
|
function loadConfig(projectRoot) {
|
|
61921
62555
|
for (const filename of CONFIG_FILENAMES) {
|
|
61922
|
-
const filePath =
|
|
62556
|
+
const filePath = path17.join(projectRoot, filename);
|
|
61923
62557
|
let content;
|
|
61924
62558
|
try {
|
|
61925
|
-
content = stripBom(
|
|
62559
|
+
content = stripBom(fs13.readFileSync(filePath, "utf-8"));
|
|
61926
62560
|
} catch {
|
|
61927
62561
|
continue;
|
|
61928
62562
|
}
|
|
@@ -61933,7 +62567,7 @@ function loadConfig(projectRoot) {
|
|
|
61933
62567
|
function loadConfigFromExplicitPath(configPath) {
|
|
61934
62568
|
let content;
|
|
61935
62569
|
try {
|
|
61936
|
-
content = stripBom(
|
|
62570
|
+
content = stripBom(fs13.readFileSync(configPath, "utf-8"));
|
|
61937
62571
|
} catch (err) {
|
|
61938
62572
|
const detail = err instanceof Error ? err.message : String(err);
|
|
61939
62573
|
throw new Error(`could not load config from ${configPath}: ${detail}`, { cause: err });
|
|
@@ -61975,7 +62609,7 @@ __export(server_exports2, {
|
|
|
61975
62609
|
server: () => server,
|
|
61976
62610
|
startServer: () => startServer
|
|
61977
62611
|
});
|
|
61978
|
-
import * as
|
|
62612
|
+
import * as path18 from "node:path";
|
|
61979
62613
|
function describeDisallowed(rawPath) {
|
|
61980
62614
|
const m = rawPath.match(PATH_DISALLOWED);
|
|
61981
62615
|
if (!m) return "unknown";
|
|
@@ -61988,7 +62622,7 @@ function validateProjectPath(rawPath) {
|
|
|
61988
62622
|
`projectPath contains disallowed character ${describeDisallowed(rawPath)} (control chars and shell metacharacters are rejected)`
|
|
61989
62623
|
);
|
|
61990
62624
|
}
|
|
61991
|
-
const resolved =
|
|
62625
|
+
const resolved = path18.resolve(rawPath);
|
|
61992
62626
|
if (!isDirectory(resolved)) {
|
|
61993
62627
|
throw new Error("projectPath is not an existing directory");
|
|
61994
62628
|
}
|
|
@@ -62012,10 +62646,10 @@ function validateFilePathInput(rawPath) {
|
|
|
62012
62646
|
}
|
|
62013
62647
|
}
|
|
62014
62648
|
function resolveWithinRoot(filePath, root) {
|
|
62015
|
-
const resolvedRoot =
|
|
62016
|
-
const resolved =
|
|
62017
|
-
const rel =
|
|
62018
|
-
if (rel.startsWith("..") ||
|
|
62649
|
+
const resolvedRoot = path18.resolve(root);
|
|
62650
|
+
const resolved = path18.resolve(resolvedRoot, filePath);
|
|
62651
|
+
const rel = path18.relative(resolvedRoot, resolved);
|
|
62652
|
+
if (rel.startsWith("..") || path18.isAbsolute(rel)) {
|
|
62019
62653
|
throw new Error("path escapes the project root");
|
|
62020
62654
|
}
|
|
62021
62655
|
return resolved;
|
|
@@ -62112,7 +62746,7 @@ var init_server4 = __esm({
|
|
|
62112
62746
|
exists: fileExists(resolved) || isDirectory(resolved)
|
|
62113
62747
|
};
|
|
62114
62748
|
if (!result.exists) {
|
|
62115
|
-
const rename = await findRenames(root,
|
|
62749
|
+
const rename = await findRenames(root, path18.relative(root, resolved));
|
|
62116
62750
|
if (rename) {
|
|
62117
62751
|
result.renamed = true;
|
|
62118
62752
|
result.newPath = rename.newPath;
|
|
@@ -63530,8 +64164,8 @@ var init_suggestSimilar = __esm({
|
|
|
63530
64164
|
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/command.js
|
|
63531
64165
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
63532
64166
|
import childProcess from "node:child_process";
|
|
63533
|
-
import
|
|
63534
|
-
import
|
|
64167
|
+
import path19 from "node:path";
|
|
64168
|
+
import fs14 from "node:fs";
|
|
63535
64169
|
import process5 from "node:process";
|
|
63536
64170
|
import { stripVTControlCharacters as stripVTControlCharacters2 } from "node:util";
|
|
63537
64171
|
function incrementNodeInspectorPort(args2) {
|
|
@@ -64569,7 +65203,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
64569
65203
|
* @param {string} subcommandName
|
|
64570
65204
|
*/
|
|
64571
65205
|
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
|
|
64572
|
-
if (
|
|
65206
|
+
if (fs14.existsSync(executableFile)) return;
|
|
64573
65207
|
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";
|
|
64574
65208
|
const executableMissing = `'${executableFile}' does not exist
|
|
64575
65209
|
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
@@ -64586,11 +65220,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
64586
65220
|
args2 = args2.slice();
|
|
64587
65221
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
64588
65222
|
function findFile(baseDir, baseName) {
|
|
64589
|
-
const localBin =
|
|
64590
|
-
if (
|
|
64591
|
-
if (sourceExt.includes(
|
|
65223
|
+
const localBin = path19.resolve(baseDir, baseName);
|
|
65224
|
+
if (fs14.existsSync(localBin)) return localBin;
|
|
65225
|
+
if (sourceExt.includes(path19.extname(baseName))) return void 0;
|
|
64592
65226
|
const foundExt = sourceExt.find(
|
|
64593
|
-
(ext) =>
|
|
65227
|
+
(ext) => fs14.existsSync(`${localBin}${ext}`)
|
|
64594
65228
|
);
|
|
64595
65229
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
64596
65230
|
return void 0;
|
|
@@ -64602,21 +65236,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
64602
65236
|
if (this._scriptPath) {
|
|
64603
65237
|
let resolvedScriptPath;
|
|
64604
65238
|
try {
|
|
64605
|
-
resolvedScriptPath =
|
|
65239
|
+
resolvedScriptPath = fs14.realpathSync(this._scriptPath);
|
|
64606
65240
|
} catch {
|
|
64607
65241
|
resolvedScriptPath = this._scriptPath;
|
|
64608
65242
|
}
|
|
64609
|
-
executableDir =
|
|
64610
|
-
|
|
65243
|
+
executableDir = path19.resolve(
|
|
65244
|
+
path19.dirname(resolvedScriptPath),
|
|
64611
65245
|
executableDir
|
|
64612
65246
|
);
|
|
64613
65247
|
}
|
|
64614
65248
|
if (executableDir) {
|
|
64615
65249
|
let localFile = findFile(executableDir, executableFile);
|
|
64616
65250
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
64617
|
-
const legacyName =
|
|
65251
|
+
const legacyName = path19.basename(
|
|
64618
65252
|
this._scriptPath,
|
|
64619
|
-
|
|
65253
|
+
path19.extname(this._scriptPath)
|
|
64620
65254
|
);
|
|
64621
65255
|
if (legacyName !== this._name) {
|
|
64622
65256
|
localFile = findFile(
|
|
@@ -64627,7 +65261,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
64627
65261
|
}
|
|
64628
65262
|
executableFile = localFile || executableFile;
|
|
64629
65263
|
}
|
|
64630
|
-
const launchWithNode = sourceExt.includes(
|
|
65264
|
+
const launchWithNode = sourceExt.includes(path19.extname(executableFile));
|
|
64631
65265
|
let proc;
|
|
64632
65266
|
if (process5.platform !== "win32") {
|
|
64633
65267
|
if (launchWithNode) {
|
|
@@ -65544,7 +66178,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
65544
66178
|
* @return {Command}
|
|
65545
66179
|
*/
|
|
65546
66180
|
nameFromFilename(filename) {
|
|
65547
|
-
this._name =
|
|
66181
|
+
this._name = path19.basename(filename, path19.extname(filename));
|
|
65548
66182
|
return this;
|
|
65549
66183
|
}
|
|
65550
66184
|
/**
|
|
@@ -65558,9 +66192,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
65558
66192
|
* @param {string} [path]
|
|
65559
66193
|
* @return {(string|null|Command)}
|
|
65560
66194
|
*/
|
|
65561
|
-
executableDir(
|
|
65562
|
-
if (
|
|
65563
|
-
this._executableDir =
|
|
66195
|
+
executableDir(path21) {
|
|
66196
|
+
if (path21 === void 0) return this._executableDir;
|
|
66197
|
+
this._executableDir = path21;
|
|
65564
66198
|
return this;
|
|
65565
66199
|
}
|
|
65566
66200
|
/**
|
|
@@ -68893,7 +69527,7 @@ var init_ora = __esm({
|
|
|
68893
69527
|
});
|
|
68894
69528
|
|
|
68895
69529
|
// src/core/reporter.ts
|
|
68896
|
-
import { existsSync as existsSync8, readFileSync as
|
|
69530
|
+
import { existsSync as existsSync8, readFileSync as readFileSync11 } from "node:fs";
|
|
68897
69531
|
import { join as join16 } from "node:path";
|
|
68898
69532
|
function classifyFile(f) {
|
|
68899
69533
|
if (f.path === "(project)") return "context";
|
|
@@ -68920,7 +69554,7 @@ function detectVersionSkew(projectRoot, runningVersion) {
|
|
|
68920
69554
|
try {
|
|
68921
69555
|
const pkgPath = join16(projectRoot, "package.json");
|
|
68922
69556
|
if (!existsSync8(pkgPath)) return null;
|
|
68923
|
-
const raw =
|
|
69557
|
+
const raw = readFileSync11(pkgPath, "utf8").replace(/^\uFEFF/, "");
|
|
68924
69558
|
const pkg = JSON.parse(raw);
|
|
68925
69559
|
const name = pkg.name ?? "";
|
|
68926
69560
|
if (name !== "ctxlint" && name !== "@yawlabs/ctxlint") return null;
|
|
@@ -69336,6 +69970,13 @@ function buildRuleDescriptors() {
|
|
|
69336
69970
|
},
|
|
69337
69971
|
helpUri: "https://github.com/yawlabs/ctxlint#what-it-checks"
|
|
69338
69972
|
},
|
|
69973
|
+
{
|
|
69974
|
+
id: "ctxlint/session-unresolvable-sha",
|
|
69975
|
+
shortDescription: {
|
|
69976
|
+
text: "Memory cites a git SHA that no longer resolves in the repository"
|
|
69977
|
+
},
|
|
69978
|
+
helpUri: "https://github.com/yawlabs/ctxlint#what-it-checks"
|
|
69979
|
+
},
|
|
69339
69980
|
{
|
|
69340
69981
|
id: "ctxlint/skill-frontmatter",
|
|
69341
69982
|
shortDescription: { text: "Skill/agent definition missing required frontmatter" },
|
|
@@ -69406,8 +70047,8 @@ __export(cli_exports, {
|
|
|
69406
70047
|
promptYesNo: () => promptYesNo,
|
|
69407
70048
|
runCli: () => runCli
|
|
69408
70049
|
});
|
|
69409
|
-
import * as
|
|
69410
|
-
import * as
|
|
70050
|
+
import * as fs15 from "node:fs";
|
|
70051
|
+
import * as path20 from "node:path";
|
|
69411
70052
|
function validateCheckNames(names, source) {
|
|
69412
70053
|
const invalid = names.filter((n7) => n7 && !VALID_CHECKS.has(n7));
|
|
69413
70054
|
if (invalid.length > 0) {
|
|
@@ -69430,7 +70071,7 @@ async function runCli() {
|
|
|
69430
70071
|
"Also scan the user-global ~/.claude/settings.json in the dead-hook check (off by default; the standard run only reads project .claude/settings.json[.local])",
|
|
69431
70072
|
false
|
|
69432
70073
|
).option("--no-ignore-file", "Disable .ctxlintignore suppression (see all findings)").option("--watch", "Re-lint on context file changes", false).action(async (projectPath, opts) => {
|
|
69433
|
-
const resolvedPath =
|
|
70074
|
+
const resolvedPath = path20.resolve(projectPath);
|
|
69434
70075
|
const { config: config2, options, activeChecks } = resolveSession(resolvedPath, opts);
|
|
69435
70076
|
const spinner = options.format === "text" && !options.quiet ? ora("Scanning for context files...").start() : void 0;
|
|
69436
70077
|
try {
|
|
@@ -69561,41 +70202,41 @@ Fixed ${applied.totalFixes} issue${applied.totalFixes !== 1 ? "s" : ""} in ${app
|
|
|
69561
70202
|
const chalk2 = (await Promise.resolve().then(() => (init_source(), source_exports))).default;
|
|
69562
70203
|
console.log(chalk2.dim("\nWatching for changes... (Ctrl+C to stop)\n"));
|
|
69563
70204
|
const watchPaths = [
|
|
69564
|
-
|
|
69565
|
-
|
|
69566
|
-
|
|
69567
|
-
|
|
69568
|
-
|
|
69569
|
-
|
|
69570
|
-
|
|
69571
|
-
|
|
69572
|
-
|
|
69573
|
-
|
|
69574
|
-
|
|
69575
|
-
|
|
69576
|
-
|
|
69577
|
-
|
|
69578
|
-
|
|
70205
|
+
path20.join(resolvedPath, "CLAUDE.md"),
|
|
70206
|
+
path20.join(resolvedPath, "CLAUDE.local.md"),
|
|
70207
|
+
path20.join(resolvedPath, "AGENTS.md"),
|
|
70208
|
+
path20.join(resolvedPath, "AGENT.md"),
|
|
70209
|
+
path20.join(resolvedPath, ".cursorrules"),
|
|
70210
|
+
path20.join(resolvedPath, ".windsurfrules"),
|
|
70211
|
+
path20.join(resolvedPath, ".clinerules"),
|
|
70212
|
+
path20.join(resolvedPath, ".aiderules"),
|
|
70213
|
+
path20.join(resolvedPath, ".continuerules"),
|
|
70214
|
+
path20.join(resolvedPath, ".rules"),
|
|
70215
|
+
path20.join(resolvedPath, ".goosehints"),
|
|
70216
|
+
path20.join(resolvedPath, "GEMINI.md"),
|
|
70217
|
+
path20.join(resolvedPath, "replit.md"),
|
|
70218
|
+
path20.join(resolvedPath, "package.json"),
|
|
70219
|
+
path20.join(resolvedPath, ".mcp.json"),
|
|
69579
70220
|
// ctxlint config — re-resolve on edit so threshold changes,
|
|
69580
70221
|
// ignore-list edits, and check-list overrides take effect without
|
|
69581
70222
|
// restarting the watcher.
|
|
69582
|
-
|
|
69583
|
-
|
|
70223
|
+
path20.join(resolvedPath, ".ctxlintrc"),
|
|
70224
|
+
path20.join(resolvedPath, ".ctxlintrc.json"),
|
|
69584
70225
|
// .ctxlintignore — re-lint when suppression rules change.
|
|
69585
|
-
|
|
70226
|
+
path20.join(resolvedPath, ".ctxlintignore")
|
|
69586
70227
|
];
|
|
69587
70228
|
const watchDirs = [
|
|
69588
|
-
|
|
69589
|
-
|
|
69590
|
-
|
|
69591
|
-
|
|
69592
|
-
|
|
69593
|
-
|
|
69594
|
-
|
|
69595
|
-
|
|
69596
|
-
|
|
69597
|
-
|
|
69598
|
-
|
|
70229
|
+
path20.join(resolvedPath, ".claude"),
|
|
70230
|
+
path20.join(resolvedPath, ".cursor"),
|
|
70231
|
+
path20.join(resolvedPath, ".github"),
|
|
70232
|
+
path20.join(resolvedPath, ".windsurf"),
|
|
70233
|
+
path20.join(resolvedPath, ".aide"),
|
|
70234
|
+
path20.join(resolvedPath, ".amazonq"),
|
|
70235
|
+
path20.join(resolvedPath, ".goose"),
|
|
70236
|
+
path20.join(resolvedPath, ".junie"),
|
|
70237
|
+
path20.join(resolvedPath, ".aiassistant"),
|
|
70238
|
+
path20.join(resolvedPath, ".continue"),
|
|
70239
|
+
path20.join(resolvedPath, ".vscode")
|
|
69599
70240
|
];
|
|
69600
70241
|
const watchers = [];
|
|
69601
70242
|
let debounceTimer = null;
|
|
@@ -69657,13 +70298,13 @@ Fixed ${applied.totalFixes} issue${applied.totalFixes !== 1 ? "s" : ""} in ${app
|
|
|
69657
70298
|
};
|
|
69658
70299
|
for (const filePath of watchPaths) {
|
|
69659
70300
|
try {
|
|
69660
|
-
watchers.push(
|
|
70301
|
+
watchers.push(fs15.watch(filePath, rerun));
|
|
69661
70302
|
} catch {
|
|
69662
70303
|
}
|
|
69663
70304
|
}
|
|
69664
70305
|
for (const dir of watchDirs) {
|
|
69665
70306
|
try {
|
|
69666
|
-
watchers.push(
|
|
70307
|
+
watchers.push(fs15.watch(dir, { recursive: true }, rerun));
|
|
69667
70308
|
} catch {
|
|
69668
70309
|
}
|
|
69669
70310
|
}
|
|
@@ -69684,17 +70325,17 @@ Fixed ${applied.totalFixes} issue${applied.totalFixes !== 1 ? "s" : ""} in ${app
|
|
|
69684
70325
|
}
|
|
69685
70326
|
});
|
|
69686
70327
|
program2.command("init").description("Set up a git pre-commit hook that runs ctxlint --strict").argument("[path]", "Project directory", ".").action(async (projectPath) => {
|
|
69687
|
-
const resolvedRoot =
|
|
69688
|
-
const gitDir =
|
|
69689
|
-
const hooksDir =
|
|
69690
|
-
if (!
|
|
70328
|
+
const resolvedRoot = path20.resolve(projectPath);
|
|
70329
|
+
const gitDir = path20.join(resolvedRoot, ".git");
|
|
70330
|
+
const hooksDir = path20.join(gitDir, "hooks");
|
|
70331
|
+
if (!fs15.existsSync(gitDir)) {
|
|
69691
70332
|
console.error('Error: not a git repository. Run "git init" first.');
|
|
69692
70333
|
process.exit(1);
|
|
69693
70334
|
}
|
|
69694
|
-
if (!
|
|
69695
|
-
|
|
70335
|
+
if (!fs15.existsSync(hooksDir)) {
|
|
70336
|
+
fs15.mkdirSync(hooksDir, { recursive: true });
|
|
69696
70337
|
}
|
|
69697
|
-
const hookPath =
|
|
70338
|
+
const hookPath = path20.join(hooksDir, "pre-commit");
|
|
69698
70339
|
const fullHookContent = `#!/bin/sh
|
|
69699
70340
|
# ctxlint pre-commit hook
|
|
69700
70341
|
npx @yawlabs/ctxlint@${VERSION} --strict
|
|
@@ -69703,15 +70344,15 @@ npx @yawlabs/ctxlint@${VERSION} --strict
|
|
|
69703
70344
|
# ctxlint pre-commit hook
|
|
69704
70345
|
npx @yawlabs/ctxlint@${VERSION} --strict
|
|
69705
70346
|
`;
|
|
69706
|
-
if (
|
|
69707
|
-
const existing =
|
|
70347
|
+
if (fs15.existsSync(hookPath)) {
|
|
70348
|
+
const existing = fs15.readFileSync(hookPath, "utf-8");
|
|
69708
70349
|
const installed = existing.match(
|
|
69709
70350
|
/^[^#\r\n]*\bnpx\s+(?:-y\s+|--yes\s+)?@yawlabs\/ctxlint(?:@(\d+\.\d+\.\d+))?/m
|
|
69710
70351
|
);
|
|
69711
70352
|
if (installed) {
|
|
69712
70353
|
const pinned = installed[1];
|
|
69713
70354
|
if (pinned && pinned !== VERSION) {
|
|
69714
|
-
|
|
70355
|
+
fs15.writeFileSync(
|
|
69715
70356
|
hookPath,
|
|
69716
70357
|
existing.replace(/(@yawlabs\/ctxlint@)\d+\.\d+\.\d+/g, `$1${VERSION}`)
|
|
69717
70358
|
);
|
|
@@ -69721,10 +70362,10 @@ npx @yawlabs/ctxlint@${VERSION} --strict
|
|
|
69721
70362
|
}
|
|
69722
70363
|
return;
|
|
69723
70364
|
}
|
|
69724
|
-
|
|
70365
|
+
fs15.appendFileSync(hookPath, appendHookContent);
|
|
69725
70366
|
console.log("Added ctxlint to existing pre-commit hook.");
|
|
69726
70367
|
} else {
|
|
69727
|
-
|
|
70368
|
+
fs15.writeFileSync(hookPath, fullHookContent, { mode: 493 });
|
|
69728
70369
|
console.log("Created pre-commit hook at .git/hooks/pre-commit");
|
|
69729
70370
|
}
|
|
69730
70371
|
console.log("ctxlint will now run automatically before each commit.");
|
|
@@ -69746,7 +70387,7 @@ function resolveDepth(raw) {
|
|
|
69746
70387
|
return Number.isNaN(parsed) ? 2 : Math.max(0, Math.min(parsed, 10));
|
|
69747
70388
|
}
|
|
69748
70389
|
function resolveSession(resolvedPath, opts, throwOnConfigError = false) {
|
|
69749
|
-
const configPath = opts.config ?
|
|
70390
|
+
const configPath = opts.config ? path20.resolve(opts.config) : void 0;
|
|
69750
70391
|
const config2 = configPath ? loadConfigFromPath(configPath, throwOnConfigError) : loadConfig(resolvedPath);
|
|
69751
70392
|
const mcpGlobal = opts.mcpGlobal || config2?.mcpGlobal || false;
|
|
69752
70393
|
const mcpOnly = opts.mcpOnly || config2?.mcpOnly || false;
|