@chimix/agentscan 0.4.0 → 0.5.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/README.md +77 -41
- package/dist/cli.js +1038 -772
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -18,7 +18,7 @@ var __export = (target, all) => {
|
|
|
18
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
19
|
|
|
20
20
|
// node_modules/yaml/dist/nodes/identity.js
|
|
21
|
-
var require_identity = __commonJS((exports)
|
|
21
|
+
var require_identity = __commonJS(function(exports) {
|
|
22
22
|
var ALIAS = Symbol.for("yaml.alias");
|
|
23
23
|
var DOC = Symbol.for("yaml.document");
|
|
24
24
|
var MAP = Symbol.for("yaml.map");
|
|
@@ -72,7 +72,7 @@ var require_identity = __commonJS((exports) => {
|
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
// node_modules/yaml/dist/visit.js
|
|
75
|
-
var require_visit = __commonJS((exports)
|
|
75
|
+
var require_visit = __commonJS(function(exports) {
|
|
76
76
|
var identity = require_identity();
|
|
77
77
|
var BREAK = Symbol("break visit");
|
|
78
78
|
var SKIP = Symbol("skip children");
|
|
@@ -227,7 +227,7 @@ var require_visit = __commonJS((exports) => {
|
|
|
227
227
|
});
|
|
228
228
|
|
|
229
229
|
// node_modules/yaml/dist/doc/directives.js
|
|
230
|
-
var require_directives = __commonJS((exports)
|
|
230
|
+
var require_directives = __commonJS(function(exports) {
|
|
231
231
|
var identity = require_identity();
|
|
232
232
|
var visit = require_visit();
|
|
233
233
|
var escapeChars = {
|
|
@@ -379,7 +379,7 @@ var require_directives = __commonJS((exports) => {
|
|
|
379
379
|
});
|
|
380
380
|
|
|
381
381
|
// node_modules/yaml/dist/doc/anchors.js
|
|
382
|
-
var require_anchors = __commonJS((exports)
|
|
382
|
+
var require_anchors = __commonJS(function(exports) {
|
|
383
383
|
var identity = require_identity();
|
|
384
384
|
var visit = require_visit();
|
|
385
385
|
function anchorIsValid(anchor) {
|
|
@@ -441,7 +441,7 @@ var require_anchors = __commonJS((exports) => {
|
|
|
441
441
|
});
|
|
442
442
|
|
|
443
443
|
// node_modules/yaml/dist/doc/applyReviver.js
|
|
444
|
-
var require_applyReviver = __commonJS((exports)
|
|
444
|
+
var require_applyReviver = __commonJS(function(exports) {
|
|
445
445
|
function applyReviver(reviver, obj, key, val) {
|
|
446
446
|
if (val && typeof val === "object") {
|
|
447
447
|
if (Array.isArray(val)) {
|
|
@@ -488,7 +488,7 @@ var require_applyReviver = __commonJS((exports) => {
|
|
|
488
488
|
});
|
|
489
489
|
|
|
490
490
|
// node_modules/yaml/dist/nodes/toJS.js
|
|
491
|
-
var require_toJS = __commonJS((exports)
|
|
491
|
+
var require_toJS = __commonJS(function(exports) {
|
|
492
492
|
var identity = require_identity();
|
|
493
493
|
function toJS(value, arg, ctx) {
|
|
494
494
|
if (Array.isArray(value))
|
|
@@ -515,7 +515,7 @@ var require_toJS = __commonJS((exports) => {
|
|
|
515
515
|
});
|
|
516
516
|
|
|
517
517
|
// node_modules/yaml/dist/nodes/Node.js
|
|
518
|
-
var require_Node = __commonJS((exports)
|
|
518
|
+
var require_Node = __commonJS(function(exports) {
|
|
519
519
|
var applyReviver = require_applyReviver();
|
|
520
520
|
var identity = require_identity();
|
|
521
521
|
var toJS = require_toJS();
|
|
@@ -552,7 +552,7 @@ var require_Node = __commonJS((exports) => {
|
|
|
552
552
|
});
|
|
553
553
|
|
|
554
554
|
// node_modules/yaml/dist/nodes/Alias.js
|
|
555
|
-
var require_Alias = __commonJS((exports)
|
|
555
|
+
var require_Alias = __commonJS(function(exports) {
|
|
556
556
|
var anchors = require_anchors();
|
|
557
557
|
var visit = require_visit();
|
|
558
558
|
var identity = require_identity();
|
|
@@ -662,7 +662,7 @@ var require_Alias = __commonJS((exports) => {
|
|
|
662
662
|
});
|
|
663
663
|
|
|
664
664
|
// node_modules/yaml/dist/nodes/Scalar.js
|
|
665
|
-
var require_Scalar = __commonJS((exports)
|
|
665
|
+
var require_Scalar = __commonJS(function(exports) {
|
|
666
666
|
var identity = require_identity();
|
|
667
667
|
var Node = require_Node();
|
|
668
668
|
var toJS = require_toJS();
|
|
@@ -690,7 +690,7 @@ var require_Scalar = __commonJS((exports) => {
|
|
|
690
690
|
});
|
|
691
691
|
|
|
692
692
|
// node_modules/yaml/dist/doc/createNode.js
|
|
693
|
-
var require_createNode = __commonJS((exports)
|
|
693
|
+
var require_createNode = __commonJS(function(exports) {
|
|
694
694
|
var Alias = require_Alias();
|
|
695
695
|
var identity = require_identity();
|
|
696
696
|
var Scalar = require_Scalar();
|
|
@@ -762,7 +762,7 @@ var require_createNode = __commonJS((exports) => {
|
|
|
762
762
|
});
|
|
763
763
|
|
|
764
764
|
// node_modules/yaml/dist/nodes/Collection.js
|
|
765
|
-
var require_Collection = __commonJS((exports)
|
|
765
|
+
var require_Collection = __commonJS(function(exports) {
|
|
766
766
|
var createNode = require_createNode();
|
|
767
767
|
var identity = require_identity();
|
|
768
768
|
var Node = require_Node();
|
|
@@ -877,7 +877,7 @@ var require_Collection = __commonJS((exports) => {
|
|
|
877
877
|
});
|
|
878
878
|
|
|
879
879
|
// node_modules/yaml/dist/stringify/stringifyComment.js
|
|
880
|
-
var require_stringifyComment = __commonJS((exports)
|
|
880
|
+
var require_stringifyComment = __commonJS(function(exports) {
|
|
881
881
|
var stringifyComment = (str) => str.replace(/^(?!$)(?: $)?/gm, "#");
|
|
882
882
|
function indentComment(comment, indent) {
|
|
883
883
|
if (/^\n+$/.test(comment))
|
|
@@ -894,7 +894,7 @@ var require_stringifyComment = __commonJS((exports) => {
|
|
|
894
894
|
});
|
|
895
895
|
|
|
896
896
|
// node_modules/yaml/dist/stringify/foldFlowLines.js
|
|
897
|
-
var require_foldFlowLines = __commonJS((exports)
|
|
897
|
+
var require_foldFlowLines = __commonJS(function(exports) {
|
|
898
898
|
var FOLD_FLOW = "flow";
|
|
899
899
|
var FOLD_BLOCK = "block";
|
|
900
900
|
var FOLD_QUOTED = "quoted";
|
|
@@ -1031,7 +1031,7 @@ ${indent}${text.slice(fold + 1, end2)}`;
|
|
|
1031
1031
|
});
|
|
1032
1032
|
|
|
1033
1033
|
// node_modules/yaml/dist/stringify/stringifyString.js
|
|
1034
|
-
var require_stringifyString = __commonJS((exports)
|
|
1034
|
+
var require_stringifyString = __commonJS(function(exports) {
|
|
1035
1035
|
var Scalar = require_Scalar();
|
|
1036
1036
|
var foldFlowLines = require_foldFlowLines();
|
|
1037
1037
|
var getFoldOptions = (ctx, isBlock) => ({
|
|
@@ -1329,7 +1329,7 @@ ${indent}`);
|
|
|
1329
1329
|
});
|
|
1330
1330
|
|
|
1331
1331
|
// node_modules/yaml/dist/stringify/stringify.js
|
|
1332
|
-
var require_stringify = __commonJS((exports)
|
|
1332
|
+
var require_stringify = __commonJS(function(exports) {
|
|
1333
1333
|
var anchors = require_anchors();
|
|
1334
1334
|
var identity = require_identity();
|
|
1335
1335
|
var stringifyComment = require_stringifyComment();
|
|
@@ -1450,7 +1450,7 @@ ${ctx.indent}${str}`;
|
|
|
1450
1450
|
});
|
|
1451
1451
|
|
|
1452
1452
|
// node_modules/yaml/dist/stringify/stringifyPair.js
|
|
1453
|
-
var require_stringifyPair = __commonJS((exports)
|
|
1453
|
+
var require_stringifyPair = __commonJS(function(exports) {
|
|
1454
1454
|
var identity = require_identity();
|
|
1455
1455
|
var Scalar = require_Scalar();
|
|
1456
1456
|
var stringify = require_stringify();
|
|
@@ -1586,7 +1586,7 @@ ${ctx.indent}`;
|
|
|
1586
1586
|
});
|
|
1587
1587
|
|
|
1588
1588
|
// node_modules/yaml/dist/log.js
|
|
1589
|
-
var require_log = __commonJS((exports)
|
|
1589
|
+
var require_log = __commonJS(function(exports) {
|
|
1590
1590
|
var node_process = __require("process");
|
|
1591
1591
|
function debug(logLevel, ...messages) {
|
|
1592
1592
|
if (logLevel === "debug")
|
|
@@ -1605,7 +1605,7 @@ var require_log = __commonJS((exports) => {
|
|
|
1605
1605
|
});
|
|
1606
1606
|
|
|
1607
1607
|
// node_modules/yaml/dist/schema/yaml-1.1/merge.js
|
|
1608
|
-
var require_merge = __commonJS((exports)
|
|
1608
|
+
var require_merge = __commonJS(function(exports) {
|
|
1609
1609
|
var identity = require_identity();
|
|
1610
1610
|
var Scalar = require_Scalar();
|
|
1611
1611
|
var MERGE_KEY = "<<";
|
|
@@ -1662,7 +1662,7 @@ var require_merge = __commonJS((exports) => {
|
|
|
1662
1662
|
});
|
|
1663
1663
|
|
|
1664
1664
|
// node_modules/yaml/dist/nodes/addPairToJSMap.js
|
|
1665
|
-
var require_addPairToJSMap = __commonJS((exports)
|
|
1665
|
+
var require_addPairToJSMap = __commonJS(function(exports) {
|
|
1666
1666
|
var log = require_log();
|
|
1667
1667
|
var merge = require_merge();
|
|
1668
1668
|
var stringify = require_stringify();
|
|
@@ -1723,7 +1723,7 @@ var require_addPairToJSMap = __commonJS((exports) => {
|
|
|
1723
1723
|
});
|
|
1724
1724
|
|
|
1725
1725
|
// node_modules/yaml/dist/nodes/Pair.js
|
|
1726
|
-
var require_Pair = __commonJS((exports)
|
|
1726
|
+
var require_Pair = __commonJS(function(exports) {
|
|
1727
1727
|
var createNode = require_createNode();
|
|
1728
1728
|
var stringifyPair = require_stringifyPair();
|
|
1729
1729
|
var addPairToJSMap = require_addPairToJSMap();
|
|
@@ -1761,7 +1761,7 @@ var require_Pair = __commonJS((exports) => {
|
|
|
1761
1761
|
});
|
|
1762
1762
|
|
|
1763
1763
|
// node_modules/yaml/dist/stringify/stringifyCollection.js
|
|
1764
|
-
var require_stringifyCollection = __commonJS((exports)
|
|
1764
|
+
var require_stringifyCollection = __commonJS(function(exports) {
|
|
1765
1765
|
var identity = require_identity();
|
|
1766
1766
|
var stringify = require_stringify();
|
|
1767
1767
|
var stringifyComment = require_stringifyComment();
|
|
@@ -1913,7 +1913,7 @@ ${indent}${end}`;
|
|
|
1913
1913
|
});
|
|
1914
1914
|
|
|
1915
1915
|
// node_modules/yaml/dist/nodes/YAMLMap.js
|
|
1916
|
-
var require_YAMLMap = __commonJS((exports)
|
|
1916
|
+
var require_YAMLMap = __commonJS(function(exports) {
|
|
1917
1917
|
var stringifyCollection = require_stringifyCollection();
|
|
1918
1918
|
var addPairToJSMap = require_addPairToJSMap();
|
|
1919
1919
|
var Collection = require_Collection();
|
|
@@ -2040,7 +2040,7 @@ var require_YAMLMap = __commonJS((exports) => {
|
|
|
2040
2040
|
});
|
|
2041
2041
|
|
|
2042
2042
|
// node_modules/yaml/dist/schema/common/map.js
|
|
2043
|
-
var require_map = __commonJS((exports)
|
|
2043
|
+
var require_map = __commonJS(function(exports) {
|
|
2044
2044
|
var identity = require_identity();
|
|
2045
2045
|
var YAMLMap = require_YAMLMap();
|
|
2046
2046
|
var map = {
|
|
@@ -2059,7 +2059,7 @@ var require_map = __commonJS((exports) => {
|
|
|
2059
2059
|
});
|
|
2060
2060
|
|
|
2061
2061
|
// node_modules/yaml/dist/nodes/YAMLSeq.js
|
|
2062
|
-
var require_YAMLSeq = __commonJS((exports)
|
|
2062
|
+
var require_YAMLSeq = __commonJS(function(exports) {
|
|
2063
2063
|
var createNode = require_createNode();
|
|
2064
2064
|
var stringifyCollection = require_stringifyCollection();
|
|
2065
2065
|
var Collection = require_Collection();
|
|
@@ -2152,7 +2152,7 @@ var require_YAMLSeq = __commonJS((exports) => {
|
|
|
2152
2152
|
});
|
|
2153
2153
|
|
|
2154
2154
|
// node_modules/yaml/dist/schema/common/seq.js
|
|
2155
|
-
var require_seq = __commonJS((exports)
|
|
2155
|
+
var require_seq = __commonJS(function(exports) {
|
|
2156
2156
|
var identity = require_identity();
|
|
2157
2157
|
var YAMLSeq = require_YAMLSeq();
|
|
2158
2158
|
var seq = {
|
|
@@ -2171,7 +2171,7 @@ var require_seq = __commonJS((exports) => {
|
|
|
2171
2171
|
});
|
|
2172
2172
|
|
|
2173
2173
|
// node_modules/yaml/dist/schema/common/string.js
|
|
2174
|
-
var require_string = __commonJS((exports)
|
|
2174
|
+
var require_string = __commonJS(function(exports) {
|
|
2175
2175
|
var stringifyString = require_stringifyString();
|
|
2176
2176
|
var string = {
|
|
2177
2177
|
identify: (value) => typeof value === "string",
|
|
@@ -2187,7 +2187,7 @@ var require_string = __commonJS((exports) => {
|
|
|
2187
2187
|
});
|
|
2188
2188
|
|
|
2189
2189
|
// node_modules/yaml/dist/schema/common/null.js
|
|
2190
|
-
var require_null = __commonJS((exports)
|
|
2190
|
+
var require_null = __commonJS(function(exports) {
|
|
2191
2191
|
var Scalar = require_Scalar();
|
|
2192
2192
|
var nullTag = {
|
|
2193
2193
|
identify: (value) => value == null,
|
|
@@ -2202,7 +2202,7 @@ var require_null = __commonJS((exports) => {
|
|
|
2202
2202
|
});
|
|
2203
2203
|
|
|
2204
2204
|
// node_modules/yaml/dist/schema/core/bool.js
|
|
2205
|
-
var require_bool = __commonJS((exports)
|
|
2205
|
+
var require_bool = __commonJS(function(exports) {
|
|
2206
2206
|
var Scalar = require_Scalar();
|
|
2207
2207
|
var boolTag = {
|
|
2208
2208
|
identify: (value) => typeof value === "boolean",
|
|
@@ -2223,7 +2223,7 @@ var require_bool = __commonJS((exports) => {
|
|
|
2223
2223
|
});
|
|
2224
2224
|
|
|
2225
2225
|
// node_modules/yaml/dist/stringify/stringifyNumber.js
|
|
2226
|
-
var require_stringifyNumber = __commonJS((exports)
|
|
2226
|
+
var require_stringifyNumber = __commonJS(function(exports) {
|
|
2227
2227
|
function stringifyNumber({ format, minFractionDigits, tag, value }) {
|
|
2228
2228
|
if (typeof value === "bigint")
|
|
2229
2229
|
return String(value);
|
|
@@ -2247,7 +2247,7 @@ var require_stringifyNumber = __commonJS((exports) => {
|
|
|
2247
2247
|
});
|
|
2248
2248
|
|
|
2249
2249
|
// node_modules/yaml/dist/schema/core/float.js
|
|
2250
|
-
var require_float = __commonJS((exports)
|
|
2250
|
+
var require_float = __commonJS(function(exports) {
|
|
2251
2251
|
var Scalar = require_Scalar();
|
|
2252
2252
|
var stringifyNumber = require_stringifyNumber();
|
|
2253
2253
|
var floatNaN = {
|
|
@@ -2290,7 +2290,7 @@ var require_float = __commonJS((exports) => {
|
|
|
2290
2290
|
});
|
|
2291
2291
|
|
|
2292
2292
|
// node_modules/yaml/dist/schema/core/int.js
|
|
2293
|
-
var require_int = __commonJS((exports)
|
|
2293
|
+
var require_int = __commonJS(function(exports) {
|
|
2294
2294
|
var stringifyNumber = require_stringifyNumber();
|
|
2295
2295
|
var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
2296
2296
|
var intResolve = (str, offset, radix, { intAsBigInt }) => intAsBigInt ? BigInt(str) : parseInt(str.substring(offset), radix);
|
|
@@ -2332,7 +2332,7 @@ var require_int = __commonJS((exports) => {
|
|
|
2332
2332
|
});
|
|
2333
2333
|
|
|
2334
2334
|
// node_modules/yaml/dist/schema/core/schema.js
|
|
2335
|
-
var require_schema = __commonJS((exports)
|
|
2335
|
+
var require_schema = __commonJS(function(exports) {
|
|
2336
2336
|
var map = require_map();
|
|
2337
2337
|
var _null = require_null();
|
|
2338
2338
|
var seq = require_seq();
|
|
@@ -2357,7 +2357,7 @@ var require_schema = __commonJS((exports) => {
|
|
|
2357
2357
|
});
|
|
2358
2358
|
|
|
2359
2359
|
// node_modules/yaml/dist/schema/json/schema.js
|
|
2360
|
-
var require_schema2 = __commonJS((exports)
|
|
2360
|
+
var require_schema2 = __commonJS(function(exports) {
|
|
2361
2361
|
var Scalar = require_Scalar();
|
|
2362
2362
|
var map = require_map();
|
|
2363
2363
|
var seq = require_seq();
|
|
@@ -2421,7 +2421,7 @@ var require_schema2 = __commonJS((exports) => {
|
|
|
2421
2421
|
});
|
|
2422
2422
|
|
|
2423
2423
|
// node_modules/yaml/dist/schema/yaml-1.1/binary.js
|
|
2424
|
-
var require_binary = __commonJS((exports)
|
|
2424
|
+
var require_binary = __commonJS(function(exports) {
|
|
2425
2425
|
var node_buffer = __require("buffer");
|
|
2426
2426
|
var Scalar = require_Scalar();
|
|
2427
2427
|
var stringifyString = require_stringifyString();
|
|
@@ -2476,7 +2476,7 @@ var require_binary = __commonJS((exports) => {
|
|
|
2476
2476
|
});
|
|
2477
2477
|
|
|
2478
2478
|
// node_modules/yaml/dist/schema/yaml-1.1/pairs.js
|
|
2479
|
-
var require_pairs = __commonJS((exports)
|
|
2479
|
+
var require_pairs = __commonJS(function(exports) {
|
|
2480
2480
|
var identity = require_identity();
|
|
2481
2481
|
var Pair = require_Pair();
|
|
2482
2482
|
var Scalar = require_Scalar();
|
|
@@ -2551,7 +2551,7 @@ ${cn.comment}` : item.comment;
|
|
|
2551
2551
|
});
|
|
2552
2552
|
|
|
2553
2553
|
// node_modules/yaml/dist/schema/yaml-1.1/omap.js
|
|
2554
|
-
var require_omap = __commonJS((exports)
|
|
2554
|
+
var require_omap = __commonJS(function(exports) {
|
|
2555
2555
|
var identity = require_identity();
|
|
2556
2556
|
var toJS = require_toJS();
|
|
2557
2557
|
var YAMLMap = require_YAMLMap();
|
|
@@ -2623,7 +2623,7 @@ var require_omap = __commonJS((exports) => {
|
|
|
2623
2623
|
});
|
|
2624
2624
|
|
|
2625
2625
|
// node_modules/yaml/dist/schema/yaml-1.1/bool.js
|
|
2626
|
-
var require_bool2 = __commonJS((exports)
|
|
2626
|
+
var require_bool2 = __commonJS(function(exports) {
|
|
2627
2627
|
var Scalar = require_Scalar();
|
|
2628
2628
|
function boolStringify({ value, source }, ctx) {
|
|
2629
2629
|
const boolObj = value ? trueTag : falseTag;
|
|
@@ -2652,7 +2652,7 @@ var require_bool2 = __commonJS((exports) => {
|
|
|
2652
2652
|
});
|
|
2653
2653
|
|
|
2654
2654
|
// node_modules/yaml/dist/schema/yaml-1.1/float.js
|
|
2655
|
-
var require_float2 = __commonJS((exports)
|
|
2655
|
+
var require_float2 = __commonJS(function(exports) {
|
|
2656
2656
|
var Scalar = require_Scalar();
|
|
2657
2657
|
var stringifyNumber = require_stringifyNumber();
|
|
2658
2658
|
var floatNaN = {
|
|
@@ -2698,7 +2698,7 @@ var require_float2 = __commonJS((exports) => {
|
|
|
2698
2698
|
});
|
|
2699
2699
|
|
|
2700
2700
|
// node_modules/yaml/dist/schema/yaml-1.1/int.js
|
|
2701
|
-
var require_int2 = __commonJS((exports)
|
|
2701
|
+
var require_int2 = __commonJS(function(exports) {
|
|
2702
2702
|
var stringifyNumber = require_stringifyNumber();
|
|
2703
2703
|
var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
2704
2704
|
function intResolve(str, offset, radix, { intAsBigInt }) {
|
|
@@ -2774,7 +2774,7 @@ var require_int2 = __commonJS((exports) => {
|
|
|
2774
2774
|
});
|
|
2775
2775
|
|
|
2776
2776
|
// node_modules/yaml/dist/schema/yaml-1.1/set.js
|
|
2777
|
-
var require_set = __commonJS((exports)
|
|
2777
|
+
var require_set = __commonJS(function(exports) {
|
|
2778
2778
|
var identity = require_identity();
|
|
2779
2779
|
var Pair = require_Pair();
|
|
2780
2780
|
var YAMLMap = require_YAMLMap();
|
|
@@ -2857,7 +2857,7 @@ var require_set = __commonJS((exports) => {
|
|
|
2857
2857
|
});
|
|
2858
2858
|
|
|
2859
2859
|
// node_modules/yaml/dist/schema/yaml-1.1/timestamp.js
|
|
2860
|
-
var require_timestamp = __commonJS((exports)
|
|
2860
|
+
var require_timestamp = __commonJS(function(exports) {
|
|
2861
2861
|
var stringifyNumber = require_stringifyNumber();
|
|
2862
2862
|
function parseSexagesimal(str, asBigInt) {
|
|
2863
2863
|
const sign = str[0];
|
|
@@ -2939,7 +2939,7 @@ var require_timestamp = __commonJS((exports) => {
|
|
|
2939
2939
|
});
|
|
2940
2940
|
|
|
2941
2941
|
// node_modules/yaml/dist/schema/yaml-1.1/schema.js
|
|
2942
|
-
var require_schema3 = __commonJS((exports)
|
|
2942
|
+
var require_schema3 = __commonJS(function(exports) {
|
|
2943
2943
|
var map = require_map();
|
|
2944
2944
|
var _null = require_null();
|
|
2945
2945
|
var seq = require_seq();
|
|
@@ -2980,7 +2980,7 @@ var require_schema3 = __commonJS((exports) => {
|
|
|
2980
2980
|
});
|
|
2981
2981
|
|
|
2982
2982
|
// node_modules/yaml/dist/schema/tags.js
|
|
2983
|
-
var require_tags = __commonJS((exports)
|
|
2983
|
+
var require_tags = __commonJS(function(exports) {
|
|
2984
2984
|
var map = require_map();
|
|
2985
2985
|
var _null = require_null();
|
|
2986
2986
|
var seq = require_seq();
|
|
@@ -3071,7 +3071,7 @@ var require_tags = __commonJS((exports) => {
|
|
|
3071
3071
|
});
|
|
3072
3072
|
|
|
3073
3073
|
// node_modules/yaml/dist/schema/Schema.js
|
|
3074
|
-
var require_Schema = __commonJS((exports)
|
|
3074
|
+
var require_Schema = __commonJS(function(exports) {
|
|
3075
3075
|
var identity = require_identity();
|
|
3076
3076
|
var map = require_map();
|
|
3077
3077
|
var seq = require_seq();
|
|
@@ -3101,7 +3101,7 @@ var require_Schema = __commonJS((exports) => {
|
|
|
3101
3101
|
});
|
|
3102
3102
|
|
|
3103
3103
|
// node_modules/yaml/dist/stringify/stringifyDocument.js
|
|
3104
|
-
var require_stringifyDocument = __commonJS((exports)
|
|
3104
|
+
var require_stringifyDocument = __commonJS(function(exports) {
|
|
3105
3105
|
var identity = require_identity();
|
|
3106
3106
|
var stringify = require_stringify();
|
|
3107
3107
|
var stringifyComment = require_stringifyComment();
|
|
@@ -3181,7 +3181,7 @@ var require_stringifyDocument = __commonJS((exports) => {
|
|
|
3181
3181
|
});
|
|
3182
3182
|
|
|
3183
3183
|
// node_modules/yaml/dist/doc/Document.js
|
|
3184
|
-
var require_Document = __commonJS((exports)
|
|
3184
|
+
var require_Document = __commonJS(function(exports) {
|
|
3185
3185
|
var Alias = require_Alias();
|
|
3186
3186
|
var Collection = require_Collection();
|
|
3187
3187
|
var identity = require_identity();
|
|
@@ -3416,7 +3416,7 @@ var require_Document = __commonJS((exports) => {
|
|
|
3416
3416
|
});
|
|
3417
3417
|
|
|
3418
3418
|
// node_modules/yaml/dist/errors.js
|
|
3419
|
-
var require_errors = __commonJS((exports)
|
|
3419
|
+
var require_errors = __commonJS(function(exports) {
|
|
3420
3420
|
class YAMLError extends Error {
|
|
3421
3421
|
constructor(name, pos, code, message) {
|
|
3422
3422
|
super();
|
|
@@ -3481,7 +3481,7 @@ ${pointer}
|
|
|
3481
3481
|
});
|
|
3482
3482
|
|
|
3483
3483
|
// node_modules/yaml/dist/compose/resolve-props.js
|
|
3484
|
-
var require_resolve_props = __commonJS((exports)
|
|
3484
|
+
var require_resolve_props = __commonJS(function(exports) {
|
|
3485
3485
|
function resolveProps(tokens, { flow, indicator, next, offset, onError, parentIndent, startOnNewline }) {
|
|
3486
3486
|
let spaceBefore = false;
|
|
3487
3487
|
let atNewline = startOnNewline;
|
|
@@ -3611,7 +3611,7 @@ var require_resolve_props = __commonJS((exports) => {
|
|
|
3611
3611
|
});
|
|
3612
3612
|
|
|
3613
3613
|
// node_modules/yaml/dist/compose/util-contains-newline.js
|
|
3614
|
-
var require_util_contains_newline = __commonJS((exports)
|
|
3614
|
+
var require_util_contains_newline = __commonJS(function(exports) {
|
|
3615
3615
|
function containsNewline(key) {
|
|
3616
3616
|
if (!key)
|
|
3617
3617
|
return null;
|
|
@@ -3651,7 +3651,7 @@ var require_util_contains_newline = __commonJS((exports) => {
|
|
|
3651
3651
|
});
|
|
3652
3652
|
|
|
3653
3653
|
// node_modules/yaml/dist/compose/util-flow-indent-check.js
|
|
3654
|
-
var require_util_flow_indent_check = __commonJS((exports)
|
|
3654
|
+
var require_util_flow_indent_check = __commonJS(function(exports) {
|
|
3655
3655
|
var utilContainsNewline = require_util_contains_newline();
|
|
3656
3656
|
function flowIndentCheck(indent, fc, onError) {
|
|
3657
3657
|
if (fc?.type === "flow-collection") {
|
|
@@ -3666,7 +3666,7 @@ var require_util_flow_indent_check = __commonJS((exports) => {
|
|
|
3666
3666
|
});
|
|
3667
3667
|
|
|
3668
3668
|
// node_modules/yaml/dist/compose/util-map-includes.js
|
|
3669
|
-
var require_util_map_includes = __commonJS((exports)
|
|
3669
|
+
var require_util_map_includes = __commonJS(function(exports) {
|
|
3670
3670
|
var identity = require_identity();
|
|
3671
3671
|
function mapIncludes(ctx, items, search) {
|
|
3672
3672
|
const { uniqueKeys } = ctx.options;
|
|
@@ -3679,7 +3679,7 @@ var require_util_map_includes = __commonJS((exports) => {
|
|
|
3679
3679
|
});
|
|
3680
3680
|
|
|
3681
3681
|
// node_modules/yaml/dist/compose/resolve-block-map.js
|
|
3682
|
-
var require_resolve_block_map = __commonJS((exports)
|
|
3682
|
+
var require_resolve_block_map = __commonJS(function(exports) {
|
|
3683
3683
|
var Pair = require_Pair();
|
|
3684
3684
|
var YAMLMap = require_YAMLMap();
|
|
3685
3685
|
var resolveProps = require_resolve_props();
|
|
@@ -3786,7 +3786,7 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
3786
3786
|
});
|
|
3787
3787
|
|
|
3788
3788
|
// node_modules/yaml/dist/compose/resolve-block-seq.js
|
|
3789
|
-
var require_resolve_block_seq = __commonJS((exports)
|
|
3789
|
+
var require_resolve_block_seq = __commonJS(function(exports) {
|
|
3790
3790
|
var YAMLSeq = require_YAMLSeq();
|
|
3791
3791
|
var resolveProps = require_resolve_props();
|
|
3792
3792
|
var utilFlowIndentCheck = require_util_flow_indent_check();
|
|
@@ -3834,7 +3834,7 @@ var require_resolve_block_seq = __commonJS((exports) => {
|
|
|
3834
3834
|
});
|
|
3835
3835
|
|
|
3836
3836
|
// node_modules/yaml/dist/compose/resolve-end.js
|
|
3837
|
-
var require_resolve_end = __commonJS((exports)
|
|
3837
|
+
var require_resolve_end = __commonJS(function(exports) {
|
|
3838
3838
|
function resolveEnd(end, offset, reqSpace, onError) {
|
|
3839
3839
|
let comment = "";
|
|
3840
3840
|
if (end) {
|
|
@@ -3874,7 +3874,7 @@ var require_resolve_end = __commonJS((exports) => {
|
|
|
3874
3874
|
});
|
|
3875
3875
|
|
|
3876
3876
|
// node_modules/yaml/dist/compose/resolve-flow-collection.js
|
|
3877
|
-
var require_resolve_flow_collection = __commonJS((exports)
|
|
3877
|
+
var require_resolve_flow_collection = __commonJS(function(exports) {
|
|
3878
3878
|
var identity = require_identity();
|
|
3879
3879
|
var Pair = require_Pair();
|
|
3880
3880
|
var YAMLMap = require_YAMLMap();
|
|
@@ -4065,7 +4065,7 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
4065
4065
|
});
|
|
4066
4066
|
|
|
4067
4067
|
// node_modules/yaml/dist/compose/compose-collection.js
|
|
4068
|
-
var require_compose_collection = __commonJS((exports)
|
|
4068
|
+
var require_compose_collection = __commonJS(function(exports) {
|
|
4069
4069
|
var identity = require_identity();
|
|
4070
4070
|
var Scalar = require_Scalar();
|
|
4071
4071
|
var YAMLMap = require_YAMLMap();
|
|
@@ -4127,7 +4127,7 @@ var require_compose_collection = __commonJS((exports) => {
|
|
|
4127
4127
|
});
|
|
4128
4128
|
|
|
4129
4129
|
// node_modules/yaml/dist/compose/resolve-block-scalar.js
|
|
4130
|
-
var require_resolve_block_scalar = __commonJS((exports)
|
|
4130
|
+
var require_resolve_block_scalar = __commonJS(function(exports) {
|
|
4131
4131
|
var Scalar = require_Scalar();
|
|
4132
4132
|
function resolveBlockScalar(ctx, scalar, onError) {
|
|
4133
4133
|
const start = scalar.offset;
|
|
@@ -4320,7 +4320,7 @@ var require_resolve_block_scalar = __commonJS((exports) => {
|
|
|
4320
4320
|
});
|
|
4321
4321
|
|
|
4322
4322
|
// node_modules/yaml/dist/compose/resolve-flow-scalar.js
|
|
4323
|
-
var require_resolve_flow_scalar = __commonJS((exports)
|
|
4323
|
+
var require_resolve_flow_scalar = __commonJS(function(exports) {
|
|
4324
4324
|
var Scalar = require_Scalar();
|
|
4325
4325
|
var resolveEnd = require_resolve_end();
|
|
4326
4326
|
function resolveFlowScalar(scalar, strict, onError) {
|
|
@@ -4537,7 +4537,7 @@ var require_resolve_flow_scalar = __commonJS((exports) => {
|
|
|
4537
4537
|
});
|
|
4538
4538
|
|
|
4539
4539
|
// node_modules/yaml/dist/compose/compose-scalar.js
|
|
4540
|
-
var require_compose_scalar = __commonJS((exports)
|
|
4540
|
+
var require_compose_scalar = __commonJS(function(exports) {
|
|
4541
4541
|
var identity = require_identity();
|
|
4542
4542
|
var Scalar = require_Scalar();
|
|
4543
4543
|
var resolveBlockScalar = require_resolve_block_scalar();
|
|
@@ -4615,7 +4615,7 @@ var require_compose_scalar = __commonJS((exports) => {
|
|
|
4615
4615
|
});
|
|
4616
4616
|
|
|
4617
4617
|
// node_modules/yaml/dist/compose/util-empty-scalar-position.js
|
|
4618
|
-
var require_util_empty_scalar_position = __commonJS((exports)
|
|
4618
|
+
var require_util_empty_scalar_position = __commonJS(function(exports) {
|
|
4619
4619
|
function emptyScalarPosition(offset, before, pos) {
|
|
4620
4620
|
if (before) {
|
|
4621
4621
|
pos ?? (pos = before.length);
|
|
@@ -4642,7 +4642,7 @@ var require_util_empty_scalar_position = __commonJS((exports) => {
|
|
|
4642
4642
|
});
|
|
4643
4643
|
|
|
4644
4644
|
// node_modules/yaml/dist/compose/compose-node.js
|
|
4645
|
-
var require_compose_node = __commonJS((exports)
|
|
4645
|
+
var require_compose_node = __commonJS(function(exports) {
|
|
4646
4646
|
var Alias = require_Alias();
|
|
4647
4647
|
var identity = require_identity();
|
|
4648
4648
|
var composeCollection = require_compose_collection();
|
|
@@ -4745,7 +4745,7 @@ var require_compose_node = __commonJS((exports) => {
|
|
|
4745
4745
|
});
|
|
4746
4746
|
|
|
4747
4747
|
// node_modules/yaml/dist/compose/compose-doc.js
|
|
4748
|
-
var require_compose_doc = __commonJS((exports)
|
|
4748
|
+
var require_compose_doc = __commonJS(function(exports) {
|
|
4749
4749
|
var Document = require_Document();
|
|
4750
4750
|
var composeNode = require_compose_node();
|
|
4751
4751
|
var resolveEnd = require_resolve_end();
|
|
@@ -4785,7 +4785,7 @@ var require_compose_doc = __commonJS((exports) => {
|
|
|
4785
4785
|
});
|
|
4786
4786
|
|
|
4787
4787
|
// node_modules/yaml/dist/compose/composer.js
|
|
4788
|
-
var require_composer = __commonJS((exports)
|
|
4788
|
+
var require_composer = __commonJS(function(exports) {
|
|
4789
4789
|
var node_process = __require("process");
|
|
4790
4790
|
var directives = require_directives();
|
|
4791
4791
|
var Document = require_Document();
|
|
@@ -4976,7 +4976,7 @@ ${end.comment}` : end.comment;
|
|
|
4976
4976
|
});
|
|
4977
4977
|
|
|
4978
4978
|
// node_modules/yaml/dist/parse/cst-scalar.js
|
|
4979
|
-
var require_cst_scalar = __commonJS((exports)
|
|
4979
|
+
var require_cst_scalar = __commonJS(function(exports) {
|
|
4980
4980
|
var resolveBlockScalar = require_resolve_block_scalar();
|
|
4981
4981
|
var resolveFlowScalar = require_resolve_flow_scalar();
|
|
4982
4982
|
var errors2 = require_errors();
|
|
@@ -5166,7 +5166,7 @@ var require_cst_scalar = __commonJS((exports) => {
|
|
|
5166
5166
|
});
|
|
5167
5167
|
|
|
5168
5168
|
// node_modules/yaml/dist/parse/cst-stringify.js
|
|
5169
|
-
var require_cst_stringify = __commonJS((exports)
|
|
5169
|
+
var require_cst_stringify = __commonJS(function(exports) {
|
|
5170
5170
|
var stringify = (cst) => ("type" in cst) ? stringifyToken(cst) : stringifyItem(cst);
|
|
5171
5171
|
function stringifyToken(token) {
|
|
5172
5172
|
switch (token.type) {
|
|
@@ -5224,7 +5224,7 @@ var require_cst_stringify = __commonJS((exports) => {
|
|
|
5224
5224
|
});
|
|
5225
5225
|
|
|
5226
5226
|
// node_modules/yaml/dist/parse/cst-visit.js
|
|
5227
|
-
var require_cst_visit = __commonJS((exports)
|
|
5227
|
+
var require_cst_visit = __commonJS(function(exports) {
|
|
5228
5228
|
var BREAK = Symbol("break visit");
|
|
5229
5229
|
var SKIP = Symbol("skip children");
|
|
5230
5230
|
var REMOVE = Symbol("remove item");
|
|
@@ -5283,7 +5283,7 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
5283
5283
|
});
|
|
5284
5284
|
|
|
5285
5285
|
// node_modules/yaml/dist/parse/cst.js
|
|
5286
|
-
var require_cst = __commonJS((exports)
|
|
5286
|
+
var require_cst = __commonJS(function(exports) {
|
|
5287
5287
|
var cstScalar = require_cst_scalar();
|
|
5288
5288
|
var cstStringify = require_cst_stringify();
|
|
5289
5289
|
var cstVisit = require_cst_visit();
|
|
@@ -5384,7 +5384,7 @@ var require_cst = __commonJS((exports) => {
|
|
|
5384
5384
|
});
|
|
5385
5385
|
|
|
5386
5386
|
// node_modules/yaml/dist/parse/lexer.js
|
|
5387
|
-
var require_lexer = __commonJS((exports)
|
|
5387
|
+
var require_lexer = __commonJS(function(exports) {
|
|
5388
5388
|
var cst = require_cst();
|
|
5389
5389
|
function isEmpty(ch) {
|
|
5390
5390
|
switch (ch) {
|
|
@@ -5981,7 +5981,7 @@ var require_lexer = __commonJS((exports) => {
|
|
|
5981
5981
|
});
|
|
5982
5982
|
|
|
5983
5983
|
// node_modules/yaml/dist/parse/line-counter.js
|
|
5984
|
-
var require_line_counter = __commonJS((exports)
|
|
5984
|
+
var require_line_counter = __commonJS(function(exports) {
|
|
5985
5985
|
class LineCounter {
|
|
5986
5986
|
constructor() {
|
|
5987
5987
|
this.lineStarts = [];
|
|
@@ -6009,7 +6009,7 @@ var require_line_counter = __commonJS((exports) => {
|
|
|
6009
6009
|
});
|
|
6010
6010
|
|
|
6011
6011
|
// node_modules/yaml/dist/parse/parser.js
|
|
6012
|
-
var require_parser = __commonJS((exports)
|
|
6012
|
+
var require_parser = __commonJS(function(exports) {
|
|
6013
6013
|
var node_process = __require("process");
|
|
6014
6014
|
var cst = require_cst();
|
|
6015
6015
|
var lexer = require_lexer();
|
|
@@ -6865,7 +6865,7 @@ var require_parser = __commonJS((exports) => {
|
|
|
6865
6865
|
});
|
|
6866
6866
|
|
|
6867
6867
|
// node_modules/yaml/dist/public-api.js
|
|
6868
|
-
var require_public_api = __commonJS((exports)
|
|
6868
|
+
var require_public_api = __commonJS(function(exports) {
|
|
6869
6869
|
var composer = require_composer();
|
|
6870
6870
|
var Document = require_Document();
|
|
6871
6871
|
var errors2 = require_errors();
|
|
@@ -6962,10 +6962,7 @@ var require_public_api = __commonJS((exports) => {
|
|
|
6962
6962
|
import { parseArgs } from "node:util";
|
|
6963
6963
|
|
|
6964
6964
|
// src/analyze.ts
|
|
6965
|
-
import { resolve as
|
|
6966
|
-
|
|
6967
|
-
// src/checks/index.ts
|
|
6968
|
-
import { basename as basename2 } from "node:path";
|
|
6965
|
+
import { resolve as resolve4 } from "node:path";
|
|
6969
6966
|
|
|
6970
6967
|
// src/checks/budgets.ts
|
|
6971
6968
|
import { basename } from "node:path";
|
|
@@ -7042,28 +7039,6 @@ function countFinding(args) {
|
|
|
7042
7039
|
})
|
|
7043
7040
|
];
|
|
7044
7041
|
}
|
|
7045
|
-
function packageManagerDrift(facts) {
|
|
7046
|
-
if (facts.packageManager !== "bun") {
|
|
7047
|
-
return [];
|
|
7048
|
-
}
|
|
7049
|
-
const hits = facts.policyFiles.filter((p) => p.text.includes("npm install"));
|
|
7050
|
-
if (hits.length === 0) {
|
|
7051
|
-
return [];
|
|
7052
|
-
}
|
|
7053
|
-
return [
|
|
7054
|
-
make("policy.package-manager-drift", "policy:package-manager", {
|
|
7055
|
-
action: "drift",
|
|
7056
|
-
severity: "info",
|
|
7057
|
-
message: "Policy mentions npm install but packageManager is bun",
|
|
7058
|
-
reason: "Docs drift vs packageManager field / lockfile convention",
|
|
7059
|
-
evidence: [
|
|
7060
|
-
{ kind: "packageManager", value: facts.packageManager },
|
|
7061
|
-
...hits.map((p) => ({ kind: "policy", value: p.path }))
|
|
7062
|
-
],
|
|
7063
|
-
suggest: "Prefer bun install in AGENTS.md / CLAUDE.md"
|
|
7064
|
-
})
|
|
7065
|
-
];
|
|
7066
|
-
}
|
|
7067
7042
|
function runBudgets(facts, options) {
|
|
7068
7043
|
return [
|
|
7069
7044
|
...policyLengthFinding({
|
|
@@ -7099,114 +7074,80 @@ function runBudgets(facts, options) {
|
|
|
7099
7074
|
message: `MCP surface above sweet spot (${facts.mcp.length} > ${options.mcp})`,
|
|
7100
7075
|
reason: "What actually degrades an agent is the number of tool definitions in context, not the number of servers: benchmarks show large models near-perfect at ~20 tools and failing outright past ~100, and a typical server carries tens of tools. Server count is the only proxy available without connecting to them, so treat this as a hint to go count the tools, not as a measurement.",
|
|
7101
7076
|
suggest: "Count the tools your servers actually expose; disable unused servers in mcp.json or set thresholds.mcp in .agentscanrc.json"
|
|
7102
|
-
})
|
|
7103
|
-
...packageManagerDrift(facts)
|
|
7077
|
+
})
|
|
7104
7078
|
];
|
|
7105
7079
|
}
|
|
7106
7080
|
|
|
7107
|
-
// src/checks/
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
}
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
{
|
|
7178
|
-
id: "mcp.literal-env",
|
|
7179
|
-
description: "MCP env value is a long literal instead of ${VAR}"
|
|
7180
|
-
},
|
|
7181
|
-
{
|
|
7182
|
-
id: "budget.agents-md",
|
|
7183
|
-
description: "AGENTS.md longer than the point where added lines stop helping (>150 lines)"
|
|
7184
|
-
},
|
|
7185
|
-
{
|
|
7186
|
-
id: "budget.claude-md",
|
|
7187
|
-
description: "CLAUDE.md longer than the instruction budget a model reliably follows (>200 lines)"
|
|
7188
|
-
},
|
|
7189
|
-
{
|
|
7190
|
-
id: "budget.agents",
|
|
7191
|
-
description: "More agent definitions than a focused set (>8 files in .claude/agents)"
|
|
7192
|
-
},
|
|
7193
|
-
{
|
|
7194
|
-
id: "budget.mcp",
|
|
7195
|
-
description: "Project MCP server count above the point where tool selection degrades"
|
|
7196
|
-
},
|
|
7197
|
-
{
|
|
7198
|
-
id: "policy.package-manager-drift",
|
|
7199
|
-
description: "Policy mentions npm install while packageManager is bun"
|
|
7200
|
-
}
|
|
7201
|
-
];
|
|
7202
|
-
var SECRET_PATTERNS = [
|
|
7203
|
-
{ label: "Anthropic key", re: /\bsk-ant-[A-Za-z0-9_-]{16,}/ },
|
|
7204
|
-
{ label: "OpenAI-style key", re: /\bsk-[A-Za-z0-9_]{20,}\b/ },
|
|
7205
|
-
{ label: "GitHub token", re: /\bgh[pousr]_[A-Za-z0-9]{20,}/ },
|
|
7206
|
-
{ label: "Google API key", re: /\bAIza[A-Za-z0-9_-]{20,}/ },
|
|
7207
|
-
{ label: "Slack token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}/ },
|
|
7208
|
-
{ label: "AWS access key id", re: /\bAKIA[0-9A-Z]{16}\b/ }
|
|
7209
|
-
];
|
|
7081
|
+
// src/checks/agents.ts
|
|
7082
|
+
function checkAgents(facts) {
|
|
7083
|
+
const out = [];
|
|
7084
|
+
const names = new Map;
|
|
7085
|
+
for (const agent of facts.agents) {
|
|
7086
|
+
if (agent.unreadable === true || agent.unparseableFrontmatter === true) {
|
|
7087
|
+
continue;
|
|
7088
|
+
}
|
|
7089
|
+
if (!agent.hasFrontmatter) {
|
|
7090
|
+
out.push(make("agent.missing-frontmatter", `agent:${agent.name}`, {
|
|
7091
|
+
action: "warn",
|
|
7092
|
+
severity: "error",
|
|
7093
|
+
message: "Agent definition has no YAML frontmatter block",
|
|
7094
|
+
reason: "An agent is selected by its declared description; without a frontmatter block there is nothing to select on, and the file is unlikely to load as an agent at all.",
|
|
7095
|
+
evidence: [{ kind: "agent", value: agent.path }],
|
|
7096
|
+
suggest: "Add a --- delimited block with a description"
|
|
7097
|
+
}));
|
|
7098
|
+
continue;
|
|
7099
|
+
}
|
|
7100
|
+
if (agent.description === undefined) {
|
|
7101
|
+
out.push(make("agent.missing-description", `agent:${agent.name}`, {
|
|
7102
|
+
action: "warn",
|
|
7103
|
+
severity: "error",
|
|
7104
|
+
message: "Agent frontmatter has no `description`",
|
|
7105
|
+
reason: "The description is how the main session decides which agent to dispatch. Without one the agent can still be named explicitly, but it will not be chosen on its own.",
|
|
7106
|
+
evidence: [{ kind: "agent", value: agent.path }],
|
|
7107
|
+
suggest: "Add a one-line description saying when to dispatch it"
|
|
7108
|
+
}));
|
|
7109
|
+
}
|
|
7110
|
+
if (agent.frontmatterName === undefined) {
|
|
7111
|
+
out.push(make("agent.missing-name", `agent:${agent.name}`, {
|
|
7112
|
+
action: "warn",
|
|
7113
|
+
severity: "error",
|
|
7114
|
+
message: "Agent frontmatter has no `name`",
|
|
7115
|
+
reason: "Agent identity is declared by the required frontmatter name.",
|
|
7116
|
+
evidence: [{ kind: "agent", value: agent.path }],
|
|
7117
|
+
suggest: "Add a `name` field to the frontmatter"
|
|
7118
|
+
}));
|
|
7119
|
+
} else {
|
|
7120
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(agent.frontmatterName)) {
|
|
7121
|
+
out.push(make("agent.invalid-name", `agent:${agent.name}`, {
|
|
7122
|
+
action: "warn",
|
|
7123
|
+
severity: "error",
|
|
7124
|
+
message: `Agent name "${agent.frontmatterName}" is not a valid identifier`,
|
|
7125
|
+
reason: "Agent names use lowercase letters, numbers, and hyphens so dispatch can address them reliably.",
|
|
7126
|
+
evidence: [{ kind: "agent", value: agent.path }],
|
|
7127
|
+
suggest: "Use lowercase letters, numbers, and hyphens in the `name` field"
|
|
7128
|
+
}));
|
|
7129
|
+
}
|
|
7130
|
+
const list = names.get(agent.frontmatterName) ?? [];
|
|
7131
|
+
list.push(agent.path);
|
|
7132
|
+
names.set(agent.frontmatterName, list);
|
|
7133
|
+
}
|
|
7134
|
+
}
|
|
7135
|
+
for (const [name, paths] of names)
|
|
7136
|
+
if (paths.length > 1) {
|
|
7137
|
+
out.push(make("agent.duplicate-name", `agent:${name}`, {
|
|
7138
|
+
action: "warn",
|
|
7139
|
+
severity: "error",
|
|
7140
|
+
message: `Agent name "${name}" is declared by multiple files`,
|
|
7141
|
+
reason: "Duplicate names make dispatch ambiguous.",
|
|
7142
|
+
evidence: paths.map((path) => ({ kind: "agent", value: path })),
|
|
7143
|
+
suggest: "Give each agent a unique frontmatter name"
|
|
7144
|
+
}));
|
|
7145
|
+
}
|
|
7146
|
+
return out;
|
|
7147
|
+
}
|
|
7148
|
+
|
|
7149
|
+
// src/checks/config.ts
|
|
7150
|
+
import { basename as basename2 } from "node:path";
|
|
7210
7151
|
function safeDetail(detail) {
|
|
7211
7152
|
const position = detail.match(/\bline \d+(?:, column \d+)?/i)?.[0];
|
|
7212
7153
|
const kind = detail.split(/[:(]/)[0]?.trim().slice(0, 60);
|
|
@@ -7229,6 +7170,8 @@ function checkConfigErrors(facts) {
|
|
|
7229
7170
|
});
|
|
7230
7171
|
});
|
|
7231
7172
|
}
|
|
7173
|
+
|
|
7174
|
+
// src/checks/hooks.ts
|
|
7232
7175
|
var KNOWN_HOOK_EVENTS = new Set([
|
|
7233
7176
|
"SessionStart",
|
|
7234
7177
|
"Setup",
|
|
@@ -7314,6 +7257,84 @@ function checkHooks(facts) {
|
|
|
7314
7257
|
}
|
|
7315
7258
|
return out;
|
|
7316
7259
|
}
|
|
7260
|
+
|
|
7261
|
+
// src/checks/mcp.ts
|
|
7262
|
+
var SECRET_PATTERNS = [
|
|
7263
|
+
{ label: "Anthropic key", re: /\bsk-ant-[A-Za-z0-9_-]{16,}/ },
|
|
7264
|
+
{ label: "OpenAI project key", re: /\bsk-proj-[A-Za-z0-9_-]{16,}/ },
|
|
7265
|
+
{ label: "OpenAI service-account key", re: /\bsk-svcacct-[A-Za-z0-9_-]{16,}/ },
|
|
7266
|
+
{ label: "OpenAI-style key", re: /\bsk-[A-Za-z0-9_]{20,}\b/ },
|
|
7267
|
+
{ label: "GitHub token", re: /\bgh[pousr]_[A-Za-z0-9]{20,}/ },
|
|
7268
|
+
{ label: "Google API key", re: /\bAIza[A-Za-z0-9_-]{20,}/ },
|
|
7269
|
+
{ label: "Slack token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}/ },
|
|
7270
|
+
{ label: "AWS access key id", re: /\bAKIA[0-9A-Z]{16}\b/ }
|
|
7271
|
+
];
|
|
7272
|
+
function checkMcp(facts) {
|
|
7273
|
+
const out = [];
|
|
7274
|
+
for (const server of facts.mcp) {
|
|
7275
|
+
if (!(server.hasCommand || server.hasUrl)) {
|
|
7276
|
+
out.push(make("mcp.no-launch", `mcp:${server.name}@${server.path}`, {
|
|
7277
|
+
action: "warn",
|
|
7278
|
+
severity: "error",
|
|
7279
|
+
message: `MCP server "${server.name}" declares neither command nor url`,
|
|
7280
|
+
reason: "Without a command or url the entry is not a launchable MCP server by schema — its tools will not be available, and the entry is dead weight that still costs a config read.",
|
|
7281
|
+
evidence: [{ kind: "mcp", value: `${server.name} @ ${server.path}` }],
|
|
7282
|
+
suggest: `Add a command (or url) for "${server.name}", or remove it`
|
|
7283
|
+
}));
|
|
7284
|
+
}
|
|
7285
|
+
if (server.command !== undefined && server.commandExists === false) {
|
|
7286
|
+
out.push(make("mcp.command-missing", `mcp:${server.name}@${server.path}`, {
|
|
7287
|
+
action: "warn",
|
|
7288
|
+
severity: "error",
|
|
7289
|
+
message: `MCP server "${server.name}" points at a command path that does not exist: ${server.command}`,
|
|
7290
|
+
reason: "The server declares a filesystem command, but that path is not a file on disk, so the entry is not launchable as configured. Bare PATH binaries are not checked — only path-like values this tool can resolve honestly.",
|
|
7291
|
+
evidence: [
|
|
7292
|
+
{ kind: "mcp", value: `${server.name} @ ${server.path}` },
|
|
7293
|
+
{ kind: "command", value: server.command }
|
|
7294
|
+
],
|
|
7295
|
+
suggest: `Restore ${server.command} or fix the command path for "${server.name}"`
|
|
7296
|
+
}));
|
|
7297
|
+
}
|
|
7298
|
+
if (server.hasUrl && server.transport === undefined) {
|
|
7299
|
+
out.push(make("mcp.url-without-type", `mcp:${server.name}@${server.path}`, {
|
|
7300
|
+
action: "warn",
|
|
7301
|
+
severity: "error",
|
|
7302
|
+
message: `MCP server "${server.name}" has a url but no transport type`,
|
|
7303
|
+
reason: "An entry with no `type` is read as a stdio server, so a remote server declared this way is misconfigured by schema and is skipped — its tools never appear, with no error in the report you are reading. See docs/spec/mcp.md.",
|
|
7304
|
+
evidence: [{ kind: "mcp", value: `${server.name} @ ${server.path}` }],
|
|
7305
|
+
suggest: `Add "type": "http" (or "sse" / "ws") to "${server.name}"`
|
|
7306
|
+
}));
|
|
7307
|
+
}
|
|
7308
|
+
const hit = SECRET_PATTERNS.find((p) => p.re.test(server.raw));
|
|
7309
|
+
if (hit !== undefined) {
|
|
7310
|
+
out.push(make("mcp.hardcoded-secret", `mcp:${server.name}@${server.path}`, {
|
|
7311
|
+
action: "warn",
|
|
7312
|
+
severity: "error",
|
|
7313
|
+
message: `MCP server "${server.name}" contains what looks like a hardcoded credential (${hit.label})`,
|
|
7314
|
+
reason: "Credentials in a config file get committed, shared and cached. Treat it as leaked: rotate the key, then reference it through an environment variable.",
|
|
7315
|
+
evidence: [{ kind: "mcp", value: `${server.name} @ ${server.path}` }],
|
|
7316
|
+
suggest: "Rotate the credential, then replace the literal with ${ENV_VAR}"
|
|
7317
|
+
}));
|
|
7318
|
+
continue;
|
|
7319
|
+
}
|
|
7320
|
+
if (server.literalEnvKeys.length > 0) {
|
|
7321
|
+
out.push(make("mcp.literal-env", `mcp:${server.name}@${server.path}`, {
|
|
7322
|
+
action: "warn",
|
|
7323
|
+
severity: "warning",
|
|
7324
|
+
message: `MCP server "${server.name}" has literal env values: ${server.literalEnvKeys.join(", ")}`,
|
|
7325
|
+
reason: "Long literal env values in config are usually secrets that should be indirected through ${VAR} so they are never committed.",
|
|
7326
|
+
evidence: [
|
|
7327
|
+
{ kind: "mcp", value: `${server.name} @ ${server.path}` },
|
|
7328
|
+
{ kind: "env", value: server.literalEnvKeys.join(",") }
|
|
7329
|
+
],
|
|
7330
|
+
suggest: "Replace the literals with ${ENV_VAR} references"
|
|
7331
|
+
}));
|
|
7332
|
+
}
|
|
7333
|
+
}
|
|
7334
|
+
return out;
|
|
7335
|
+
}
|
|
7336
|
+
|
|
7337
|
+
// src/checks/skills.ts
|
|
7317
7338
|
function skillEvidence(skill, value) {
|
|
7318
7339
|
const evidence = [{ kind: "skill", value }];
|
|
7319
7340
|
if (skill.source === "global") {
|
|
@@ -7321,6 +7342,9 @@ function skillEvidence(skill, value) {
|
|
|
7321
7342
|
}
|
|
7322
7343
|
return evidence;
|
|
7323
7344
|
}
|
|
7345
|
+
function skillSubject(skill) {
|
|
7346
|
+
return `skill:${skill.instanceId ?? skill.id}`;
|
|
7347
|
+
}
|
|
7324
7348
|
function checkSkillStructure(facts) {
|
|
7325
7349
|
const out = [];
|
|
7326
7350
|
for (const skill of facts.skills) {
|
|
@@ -7328,7 +7352,7 @@ function checkSkillStructure(facts) {
|
|
|
7328
7352
|
continue;
|
|
7329
7353
|
}
|
|
7330
7354
|
if (!skill.hasSkillMd) {
|
|
7331
|
-
out.push(make("skill.missing-skill-md",
|
|
7355
|
+
out.push(make("skill.missing-skill-md", skillSubject(skill), {
|
|
7332
7356
|
action: "warn",
|
|
7333
7357
|
severity: "warning",
|
|
7334
7358
|
message: `Skill directory has no SKILL.md`,
|
|
@@ -7341,8 +7365,8 @@ function checkSkillStructure(facts) {
|
|
|
7341
7365
|
if (skill.unparseableFrontmatter === true) {
|
|
7342
7366
|
continue;
|
|
7343
7367
|
}
|
|
7344
|
-
if (!skill.hasFrontmatter) {
|
|
7345
|
-
out.push(make("skill.missing-frontmatter",
|
|
7368
|
+
if (skill.runtime !== "agents" && !skill.hasFrontmatter) {
|
|
7369
|
+
out.push(make("skill.missing-frontmatter", skillSubject(skill), {
|
|
7346
7370
|
action: "warn",
|
|
7347
7371
|
severity: "warning",
|
|
7348
7372
|
message: "SKILL.md has no YAML frontmatter block",
|
|
@@ -7353,10 +7377,10 @@ function checkSkillStructure(facts) {
|
|
|
7353
7377
|
continue;
|
|
7354
7378
|
}
|
|
7355
7379
|
const broken = skill.brokenReferences;
|
|
7356
|
-
if (broken !== undefined && broken.length > 0) {
|
|
7380
|
+
if (skill.runtime !== "agents" && broken !== undefined && broken.length > 0) {
|
|
7357
7381
|
const shown = broken.slice(0, 3).join(", ");
|
|
7358
7382
|
const rest = broken.length - Math.min(3, broken.length);
|
|
7359
|
-
out.push(make("skill.broken-reference",
|
|
7383
|
+
out.push(make("skill.broken-reference", skillSubject(skill), {
|
|
7360
7384
|
action: "warn",
|
|
7361
7385
|
severity: "warning",
|
|
7362
7386
|
message: `SKILL.md points at ${broken.length} file${broken.length === 1 ? "" : "s"} that do not exist: ${shown}${rest > 0 ? ` (+${rest} more)` : ""}`,
|
|
@@ -7368,8 +7392,8 @@ function checkSkillStructure(facts) {
|
|
|
7368
7392
|
suggest: `Restore the missing files under ${skill.path}, or drop the references from SKILL.md`
|
|
7369
7393
|
}));
|
|
7370
7394
|
}
|
|
7371
|
-
if (skill.description === undefined) {
|
|
7372
|
-
out.push(make("skill.missing-description",
|
|
7395
|
+
if (skill.runtime !== "agents" && skill.description === undefined) {
|
|
7396
|
+
out.push(make("skill.missing-description", skillSubject(skill), {
|
|
7373
7397
|
action: "warn",
|
|
7374
7398
|
severity: "info",
|
|
7375
7399
|
message: "SKILL.md frontmatter has no `description`",
|
|
@@ -7397,13 +7421,16 @@ function checkLockIntegrity(facts, options) {
|
|
|
7397
7421
|
}
|
|
7398
7422
|
return out;
|
|
7399
7423
|
}
|
|
7424
|
+
if (facts.skillsLockInvalid === true) {
|
|
7425
|
+
return out;
|
|
7426
|
+
}
|
|
7400
7427
|
const onDisk = new Set(projectSkills.map((s) => s.id));
|
|
7401
7428
|
const locked = new Map(facts.lockedSkills.map((l) => [l.id, l]));
|
|
7402
7429
|
for (const skill of projectSkills) {
|
|
7403
7430
|
if (locked.has(skill.id)) {
|
|
7404
7431
|
continue;
|
|
7405
7432
|
}
|
|
7406
|
-
out.push(make("skill.not-in-lock",
|
|
7433
|
+
out.push(make("skill.not-in-lock", skillSubject(skill), {
|
|
7407
7434
|
action: "warn",
|
|
7408
7435
|
severity: "info",
|
|
7409
7436
|
message: "Skill is not in skills-lock.json — local and unpinned",
|
|
@@ -7437,11 +7464,20 @@ function checkDuplicateDescriptions(facts) {
|
|
|
7437
7464
|
if (skill.source !== "project" || skill.description === undefined) {
|
|
7438
7465
|
continue;
|
|
7439
7466
|
}
|
|
7440
|
-
|
|
7467
|
+
if (skill.runtime === "agents") {
|
|
7468
|
+
continue;
|
|
7469
|
+
}
|
|
7470
|
+
const path = skill.path.replaceAll("\\", "/");
|
|
7471
|
+
const namespace = path.includes(".claude/skills/") ? "claude" : path.includes(".agents/skills/") ? "agents" : skill.source;
|
|
7472
|
+
const key = `${namespace}\x00${skill.description.trim().replace(/\s+/g, " ").toLowerCase()}`;
|
|
7441
7473
|
if (key.length === 0) {
|
|
7442
7474
|
continue;
|
|
7443
7475
|
}
|
|
7444
|
-
|
|
7476
|
+
const ids = groups.get(key);
|
|
7477
|
+
if (ids === undefined)
|
|
7478
|
+
groups.set(key, [skill.instanceId ?? skill.id]);
|
|
7479
|
+
else
|
|
7480
|
+
ids.push(skill.instanceId ?? skill.id);
|
|
7445
7481
|
}
|
|
7446
7482
|
const out = [];
|
|
7447
7483
|
for (const ids of groups.values()) {
|
|
@@ -7484,87 +7520,106 @@ function checkDescriptionBudget(facts, options) {
|
|
|
7484
7520
|
})
|
|
7485
7521
|
];
|
|
7486
7522
|
}
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
}
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7523
|
+
// src/checks/registry.ts
|
|
7524
|
+
var STRUCTURAL_CHECKS = [
|
|
7525
|
+
{
|
|
7526
|
+
id: "config.unreadable",
|
|
7527
|
+
description: "Config file is not valid JSON or cannot be read"
|
|
7528
|
+
},
|
|
7529
|
+
{
|
|
7530
|
+
id: "hook.unknown-event",
|
|
7531
|
+
description: "Hook registered under an event name that is never dispatched"
|
|
7532
|
+
},
|
|
7533
|
+
{
|
|
7534
|
+
id: "hook.missing-script",
|
|
7535
|
+
description: "Hook points at a script that does not exist, so it never runs"
|
|
7536
|
+
},
|
|
7537
|
+
{
|
|
7538
|
+
id: "skill.missing-skill-md",
|
|
7539
|
+
description: "Skill directory has no SKILL.md"
|
|
7540
|
+
},
|
|
7541
|
+
{
|
|
7542
|
+
id: "skill.missing-frontmatter",
|
|
7543
|
+
description: "SKILL.md has no YAML frontmatter block"
|
|
7544
|
+
},
|
|
7545
|
+
{
|
|
7546
|
+
id: "skill.missing-description",
|
|
7547
|
+
description: "SKILL.md frontmatter has no description (recommended field)"
|
|
7548
|
+
},
|
|
7549
|
+
{
|
|
7550
|
+
id: "skill.not-in-lock",
|
|
7551
|
+
description: "Skill on disk is not tracked by skills-lock.json"
|
|
7552
|
+
},
|
|
7553
|
+
{
|
|
7554
|
+
id: "skill.locked-not-installed",
|
|
7555
|
+
description: "skills-lock.json pins a skill that is not installed"
|
|
7556
|
+
},
|
|
7557
|
+
{
|
|
7558
|
+
id: "skill.broken-reference",
|
|
7559
|
+
description: "SKILL.md points at a bundled file that does not exist"
|
|
7560
|
+
},
|
|
7561
|
+
{
|
|
7562
|
+
id: "skill.duplicate-description",
|
|
7563
|
+
description: "Two or more skills share an identical description"
|
|
7564
|
+
},
|
|
7565
|
+
{
|
|
7566
|
+
id: "skill.description-budget",
|
|
7567
|
+
description: "Skill descriptions exceed the startup character budget"
|
|
7568
|
+
},
|
|
7569
|
+
{
|
|
7570
|
+
id: "skill.no-lockfile",
|
|
7571
|
+
description: "Skills present with no skills-lock.json (requireLock only)"
|
|
7572
|
+
},
|
|
7573
|
+
{
|
|
7574
|
+
id: "agent.missing-frontmatter",
|
|
7575
|
+
description: "Agent definition has no YAML frontmatter block"
|
|
7576
|
+
},
|
|
7577
|
+
{
|
|
7578
|
+
id: "agent.missing-description",
|
|
7579
|
+
description: "Agent frontmatter has no description"
|
|
7580
|
+
},
|
|
7581
|
+
{ id: "agent.missing-name", description: "Agent frontmatter has no name" },
|
|
7582
|
+
{ id: "agent.duplicate-name", description: "Agent names are duplicated" },
|
|
7583
|
+
{ id: "agent.invalid-name", description: "Agent frontmatter name is not a valid identifier" },
|
|
7584
|
+
{
|
|
7585
|
+
id: "mcp.no-launch",
|
|
7586
|
+
description: "MCP server declares neither command nor url"
|
|
7587
|
+
},
|
|
7588
|
+
{
|
|
7589
|
+
id: "mcp.command-missing",
|
|
7590
|
+
description: "MCP server command is a path that does not exist on disk"
|
|
7591
|
+
},
|
|
7592
|
+
{
|
|
7593
|
+
id: "mcp.url-without-type",
|
|
7594
|
+
description: "Remote MCP server has a url but no transport type"
|
|
7595
|
+
},
|
|
7596
|
+
{
|
|
7597
|
+
id: "mcp.hardcoded-secret",
|
|
7598
|
+
description: "MCP config contains a token-shaped literal"
|
|
7599
|
+
},
|
|
7600
|
+
{
|
|
7601
|
+
id: "mcp.literal-env",
|
|
7602
|
+
description: "MCP env value is a long literal instead of ${VAR}"
|
|
7603
|
+
},
|
|
7604
|
+
{
|
|
7605
|
+
id: "budget.agents-md",
|
|
7606
|
+
description: "AGENTS.md longer than the point where added lines stop helping (>150 lines)"
|
|
7607
|
+
},
|
|
7608
|
+
{
|
|
7609
|
+
id: "budget.claude-md",
|
|
7610
|
+
description: "CLAUDE.md longer than the instruction budget a model reliably follows (>200 lines)"
|
|
7611
|
+
},
|
|
7612
|
+
{
|
|
7613
|
+
id: "budget.agents",
|
|
7614
|
+
description: "More agent definitions than a focused set (>8 files in .claude/agents)"
|
|
7615
|
+
},
|
|
7616
|
+
{
|
|
7617
|
+
id: "budget.mcp",
|
|
7618
|
+
description: "Project MCP server count above the point where tool selection degrades"
|
|
7565
7619
|
}
|
|
7566
|
-
|
|
7567
|
-
|
|
7620
|
+
];
|
|
7621
|
+
|
|
7622
|
+
// src/checks/index.ts
|
|
7568
7623
|
function runChecks(facts, options = {}) {
|
|
7569
7624
|
return [
|
|
7570
7625
|
...checkConfigErrors(facts),
|
|
@@ -7587,113 +7642,113 @@ import { join } from "node:path";
|
|
|
7587
7642
|
// node_modules/zod/v3/external.js
|
|
7588
7643
|
var exports_external = {};
|
|
7589
7644
|
__export(exports_external, {
|
|
7590
|
-
|
|
7591
|
-
util: () => util,
|
|
7592
|
-
unknown: () => unknownType,
|
|
7593
|
-
union: () => unionType,
|
|
7594
|
-
undefined: () => undefinedType,
|
|
7595
|
-
tuple: () => tupleType,
|
|
7596
|
-
transformer: () => effectsType,
|
|
7597
|
-
symbol: () => symbolType,
|
|
7598
|
-
string: () => stringType,
|
|
7599
|
-
strictObject: () => strictObjectType,
|
|
7600
|
-
setErrorMap: () => setErrorMap,
|
|
7601
|
-
set: () => setType,
|
|
7602
|
-
record: () => recordType,
|
|
7603
|
-
quotelessJson: () => quotelessJson,
|
|
7604
|
-
promise: () => promiseType,
|
|
7605
|
-
preprocess: () => preprocessType,
|
|
7606
|
-
pipeline: () => pipelineType,
|
|
7607
|
-
ostring: () => ostring,
|
|
7608
|
-
optional: () => optionalType,
|
|
7609
|
-
onumber: () => onumber,
|
|
7610
|
-
oboolean: () => oboolean,
|
|
7611
|
-
objectUtil: () => objectUtil,
|
|
7612
|
-
object: () => objectType,
|
|
7613
|
-
number: () => numberType,
|
|
7614
|
-
nullable: () => nullableType,
|
|
7615
|
-
null: () => nullType,
|
|
7616
|
-
never: () => neverType,
|
|
7617
|
-
nativeEnum: () => nativeEnumType,
|
|
7618
|
-
nan: () => nanType,
|
|
7619
|
-
map: () => mapType,
|
|
7620
|
-
makeIssue: () => makeIssue,
|
|
7621
|
-
literal: () => literalType,
|
|
7622
|
-
lazy: () => lazyType,
|
|
7623
|
-
late: () => late,
|
|
7624
|
-
isValid: () => isValid,
|
|
7625
|
-
isDirty: () => isDirty,
|
|
7626
|
-
isAsync: () => isAsync,
|
|
7627
|
-
isAborted: () => isAborted,
|
|
7628
|
-
intersection: () => intersectionType,
|
|
7629
|
-
instanceof: () => instanceOfType,
|
|
7630
|
-
getParsedType: () => getParsedType,
|
|
7631
|
-
getErrorMap: () => getErrorMap,
|
|
7632
|
-
function: () => functionType,
|
|
7633
|
-
enum: () => enumType,
|
|
7634
|
-
effect: () => effectsType,
|
|
7635
|
-
discriminatedUnion: () => discriminatedUnionType,
|
|
7636
|
-
defaultErrorMap: () => en_default,
|
|
7637
|
-
datetimeRegex: () => datetimeRegex,
|
|
7638
|
-
date: () => dateType,
|
|
7639
|
-
custom: () => custom,
|
|
7640
|
-
coerce: () => coerce,
|
|
7641
|
-
boolean: () => booleanType,
|
|
7642
|
-
bigint: () => bigIntType,
|
|
7643
|
-
array: () => arrayType,
|
|
7644
|
-
any: () => anyType,
|
|
7645
|
-
addIssueToContext: () => addIssueToContext,
|
|
7646
|
-
ZodVoid: () => ZodVoid,
|
|
7647
|
-
ZodUnknown: () => ZodUnknown,
|
|
7648
|
-
ZodUnion: () => ZodUnion,
|
|
7649
|
-
ZodUndefined: () => ZodUndefined,
|
|
7650
|
-
ZodType: () => ZodType,
|
|
7651
|
-
ZodTuple: () => ZodTuple,
|
|
7652
|
-
ZodTransformer: () => ZodEffects,
|
|
7653
|
-
ZodSymbol: () => ZodSymbol,
|
|
7654
|
-
ZodString: () => ZodString,
|
|
7655
|
-
ZodSet: () => ZodSet,
|
|
7656
|
-
ZodSchema: () => ZodType,
|
|
7657
|
-
ZodRecord: () => ZodRecord,
|
|
7658
|
-
ZodReadonly: () => ZodReadonly,
|
|
7659
|
-
ZodPromise: () => ZodPromise,
|
|
7660
|
-
ZodPipeline: () => ZodPipeline,
|
|
7661
|
-
ZodParsedType: () => ZodParsedType,
|
|
7662
|
-
ZodOptional: () => ZodOptional,
|
|
7663
|
-
ZodObject: () => ZodObject,
|
|
7664
|
-
ZodNumber: () => ZodNumber,
|
|
7665
|
-
ZodNullable: () => ZodNullable,
|
|
7666
|
-
ZodNull: () => ZodNull,
|
|
7667
|
-
ZodNever: () => ZodNever,
|
|
7668
|
-
ZodNativeEnum: () => ZodNativeEnum,
|
|
7669
|
-
ZodNaN: () => ZodNaN,
|
|
7670
|
-
ZodMap: () => ZodMap,
|
|
7671
|
-
ZodLiteral: () => ZodLiteral,
|
|
7672
|
-
ZodLazy: () => ZodLazy,
|
|
7673
|
-
ZodIssueCode: () => ZodIssueCode,
|
|
7674
|
-
ZodIntersection: () => ZodIntersection,
|
|
7675
|
-
ZodFunction: () => ZodFunction,
|
|
7676
|
-
ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
|
|
7677
|
-
ZodError: () => ZodError,
|
|
7678
|
-
ZodEnum: () => ZodEnum,
|
|
7679
|
-
ZodEffects: () => ZodEffects,
|
|
7680
|
-
ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
|
|
7681
|
-
ZodDefault: () => ZodDefault,
|
|
7682
|
-
ZodDate: () => ZodDate,
|
|
7683
|
-
ZodCatch: () => ZodCatch,
|
|
7684
|
-
ZodBranded: () => ZodBranded,
|
|
7685
|
-
ZodBoolean: () => ZodBoolean,
|
|
7686
|
-
ZodBigInt: () => ZodBigInt,
|
|
7687
|
-
ZodArray: () => ZodArray,
|
|
7688
|
-
ZodAny: () => ZodAny,
|
|
7689
|
-
Schema: () => ZodType,
|
|
7690
|
-
ParseStatus: () => ParseStatus,
|
|
7691
|
-
OK: () => OK,
|
|
7692
|
-
NEVER: () => NEVER,
|
|
7693
|
-
INVALID: () => INVALID,
|
|
7694
|
-
EMPTY_PATH: () => EMPTY_PATH,
|
|
7645
|
+
BRAND: () => BRAND,
|
|
7695
7646
|
DIRTY: () => DIRTY,
|
|
7696
|
-
|
|
7647
|
+
EMPTY_PATH: () => EMPTY_PATH,
|
|
7648
|
+
INVALID: () => INVALID,
|
|
7649
|
+
NEVER: () => NEVER,
|
|
7650
|
+
OK: () => OK,
|
|
7651
|
+
ParseStatus: () => ParseStatus,
|
|
7652
|
+
Schema: () => ZodType,
|
|
7653
|
+
ZodAny: () => ZodAny,
|
|
7654
|
+
ZodArray: () => ZodArray,
|
|
7655
|
+
ZodBigInt: () => ZodBigInt,
|
|
7656
|
+
ZodBoolean: () => ZodBoolean,
|
|
7657
|
+
ZodBranded: () => ZodBranded,
|
|
7658
|
+
ZodCatch: () => ZodCatch,
|
|
7659
|
+
ZodDate: () => ZodDate,
|
|
7660
|
+
ZodDefault: () => ZodDefault,
|
|
7661
|
+
ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
|
|
7662
|
+
ZodEffects: () => ZodEffects,
|
|
7663
|
+
ZodEnum: () => ZodEnum,
|
|
7664
|
+
ZodError: () => ZodError,
|
|
7665
|
+
ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
|
|
7666
|
+
ZodFunction: () => ZodFunction,
|
|
7667
|
+
ZodIntersection: () => ZodIntersection,
|
|
7668
|
+
ZodIssueCode: () => ZodIssueCode,
|
|
7669
|
+
ZodLazy: () => ZodLazy,
|
|
7670
|
+
ZodLiteral: () => ZodLiteral,
|
|
7671
|
+
ZodMap: () => ZodMap,
|
|
7672
|
+
ZodNaN: () => ZodNaN,
|
|
7673
|
+
ZodNativeEnum: () => ZodNativeEnum,
|
|
7674
|
+
ZodNever: () => ZodNever,
|
|
7675
|
+
ZodNull: () => ZodNull,
|
|
7676
|
+
ZodNullable: () => ZodNullable,
|
|
7677
|
+
ZodNumber: () => ZodNumber,
|
|
7678
|
+
ZodObject: () => ZodObject,
|
|
7679
|
+
ZodOptional: () => ZodOptional,
|
|
7680
|
+
ZodParsedType: () => ZodParsedType,
|
|
7681
|
+
ZodPipeline: () => ZodPipeline,
|
|
7682
|
+
ZodPromise: () => ZodPromise,
|
|
7683
|
+
ZodReadonly: () => ZodReadonly,
|
|
7684
|
+
ZodRecord: () => ZodRecord,
|
|
7685
|
+
ZodSchema: () => ZodType,
|
|
7686
|
+
ZodSet: () => ZodSet,
|
|
7687
|
+
ZodString: () => ZodString,
|
|
7688
|
+
ZodSymbol: () => ZodSymbol,
|
|
7689
|
+
ZodTransformer: () => ZodEffects,
|
|
7690
|
+
ZodTuple: () => ZodTuple,
|
|
7691
|
+
ZodType: () => ZodType,
|
|
7692
|
+
ZodUndefined: () => ZodUndefined,
|
|
7693
|
+
ZodUnion: () => ZodUnion,
|
|
7694
|
+
ZodUnknown: () => ZodUnknown,
|
|
7695
|
+
ZodVoid: () => ZodVoid,
|
|
7696
|
+
addIssueToContext: () => addIssueToContext,
|
|
7697
|
+
any: () => anyType,
|
|
7698
|
+
array: () => arrayType,
|
|
7699
|
+
bigint: () => bigIntType,
|
|
7700
|
+
boolean: () => booleanType,
|
|
7701
|
+
coerce: () => coerce,
|
|
7702
|
+
custom: () => custom,
|
|
7703
|
+
date: () => dateType,
|
|
7704
|
+
datetimeRegex: () => datetimeRegex,
|
|
7705
|
+
defaultErrorMap: () => en_default,
|
|
7706
|
+
discriminatedUnion: () => discriminatedUnionType,
|
|
7707
|
+
effect: () => effectsType,
|
|
7708
|
+
enum: () => enumType,
|
|
7709
|
+
function: () => functionType,
|
|
7710
|
+
getErrorMap: () => getErrorMap,
|
|
7711
|
+
getParsedType: () => getParsedType,
|
|
7712
|
+
instanceof: () => instanceOfType,
|
|
7713
|
+
intersection: () => intersectionType,
|
|
7714
|
+
isAborted: () => isAborted,
|
|
7715
|
+
isAsync: () => isAsync,
|
|
7716
|
+
isDirty: () => isDirty,
|
|
7717
|
+
isValid: () => isValid,
|
|
7718
|
+
late: () => late,
|
|
7719
|
+
lazy: () => lazyType,
|
|
7720
|
+
literal: () => literalType,
|
|
7721
|
+
makeIssue: () => makeIssue,
|
|
7722
|
+
map: () => mapType,
|
|
7723
|
+
nan: () => nanType,
|
|
7724
|
+
nativeEnum: () => nativeEnumType,
|
|
7725
|
+
never: () => neverType,
|
|
7726
|
+
null: () => nullType,
|
|
7727
|
+
nullable: () => nullableType,
|
|
7728
|
+
number: () => numberType,
|
|
7729
|
+
object: () => objectType,
|
|
7730
|
+
objectUtil: () => objectUtil,
|
|
7731
|
+
oboolean: () => oboolean,
|
|
7732
|
+
onumber: () => onumber,
|
|
7733
|
+
optional: () => optionalType,
|
|
7734
|
+
ostring: () => ostring,
|
|
7735
|
+
pipeline: () => pipelineType,
|
|
7736
|
+
preprocess: () => preprocessType,
|
|
7737
|
+
promise: () => promiseType,
|
|
7738
|
+
quotelessJson: () => quotelessJson,
|
|
7739
|
+
record: () => recordType,
|
|
7740
|
+
set: () => setType,
|
|
7741
|
+
setErrorMap: () => setErrorMap,
|
|
7742
|
+
strictObject: () => strictObjectType,
|
|
7743
|
+
string: () => stringType,
|
|
7744
|
+
symbol: () => symbolType,
|
|
7745
|
+
transformer: () => effectsType,
|
|
7746
|
+
tuple: () => tupleType,
|
|
7747
|
+
undefined: () => undefinedType,
|
|
7748
|
+
union: () => unionType,
|
|
7749
|
+
unknown: () => unknownType,
|
|
7750
|
+
util: () => util,
|
|
7751
|
+
void: () => voidType
|
|
7697
7752
|
});
|
|
7698
7753
|
|
|
7699
7754
|
// node_modules/zod/v3/helpers/util.js
|
|
@@ -11560,7 +11615,6 @@ var NEVER = INVALID;
|
|
|
11560
11615
|
// src/config/schema.ts
|
|
11561
11616
|
var defaultThresholds = {
|
|
11562
11617
|
skillDescriptionBytes: 16000,
|
|
11563
|
-
skills: 30,
|
|
11564
11618
|
mcp: 5,
|
|
11565
11619
|
agentsMdLines: 150,
|
|
11566
11620
|
claudeMdLines: 200,
|
|
@@ -11580,12 +11634,12 @@ var defaultConfig = {
|
|
|
11580
11634
|
};
|
|
11581
11635
|
var thresholdsSchema = exports_external.object({
|
|
11582
11636
|
skillDescriptionBytes: exports_external.number().int().positive().default(defaultThresholds.skillDescriptionBytes),
|
|
11583
|
-
skills: exports_external.number().int().positive().
|
|
11637
|
+
skills: exports_external.number().int().positive().optional(),
|
|
11584
11638
|
mcp: exports_external.number().int().positive().default(defaultThresholds.mcp),
|
|
11585
11639
|
agentsMdLines: exports_external.number().int().positive().default(defaultThresholds.agentsMdLines),
|
|
11586
11640
|
claudeMdLines: exports_external.number().int().positive().default(defaultThresholds.claudeMdLines),
|
|
11587
11641
|
agents: exports_external.number().int().positive().default(defaultThresholds.agents)
|
|
11588
|
-
});
|
|
11642
|
+
}).strict();
|
|
11589
11643
|
var configSchema = exports_external.object({
|
|
11590
11644
|
skillPaths: exports_external.array(exports_external.string()).default(defaultConfig.skillPaths),
|
|
11591
11645
|
mcpPaths: exports_external.array(exports_external.string()).default(defaultConfig.mcpPaths),
|
|
@@ -11597,7 +11651,7 @@ var configSchema = exports_external.object({
|
|
|
11597
11651
|
includeGlobal: exports_external.boolean().default(false),
|
|
11598
11652
|
requireLock: exports_external.boolean().default(false),
|
|
11599
11653
|
thresholds: thresholdsSchema.default(defaultThresholds)
|
|
11600
|
-
});
|
|
11654
|
+
}).strict();
|
|
11601
11655
|
|
|
11602
11656
|
// src/config/load.ts
|
|
11603
11657
|
function loadConfig(root, configPath) {
|
|
@@ -11617,9 +11671,16 @@ function loadConfig(root, configPath) {
|
|
|
11617
11671
|
}
|
|
11618
11672
|
|
|
11619
11673
|
// src/discover/index.ts
|
|
11620
|
-
import {
|
|
11621
|
-
import {
|
|
11622
|
-
|
|
11674
|
+
import { homedir as homedir3 } from "node:os";
|
|
11675
|
+
import { join as join8, resolve as resolve3 } from "node:path";
|
|
11676
|
+
|
|
11677
|
+
// src/discover/agents.ts
|
|
11678
|
+
import { existsSync as existsSync3, readdirSync, statSync } from "node:fs";
|
|
11679
|
+
import { join as join3 } from "node:path";
|
|
11680
|
+
|
|
11681
|
+
// src/discover/shared.ts
|
|
11682
|
+
import { closeSync, existsSync as existsSync2, openSync, readFileSync as readFileSync2, readSync } from "node:fs";
|
|
11683
|
+
import { join as join2, resolve } from "node:path";
|
|
11623
11684
|
|
|
11624
11685
|
// node_modules/yaml/dist/index.js
|
|
11625
11686
|
var composer = require_composer();
|
|
@@ -11667,18 +11728,40 @@ var $stringify = publicApi.stringify;
|
|
|
11667
11728
|
var $visit = visit.visit;
|
|
11668
11729
|
var $visitAsync = visit.visitAsync;
|
|
11669
11730
|
|
|
11670
|
-
// src/discover/
|
|
11731
|
+
// src/discover/shared.ts
|
|
11671
11732
|
var POLICY_CAP = 1e5;
|
|
11672
11733
|
var SKILL_MD_CAP = 65536;
|
|
11734
|
+
function readCapped(path, cap) {
|
|
11735
|
+
const fd = openSync(path, "r");
|
|
11736
|
+
try {
|
|
11737
|
+
const buf = Buffer.allocUnsafe(cap + 1);
|
|
11738
|
+
const bytes = readSync(fd, buf, 0, cap + 1, 0);
|
|
11739
|
+
return { buf: buf.subarray(0, bytes), truncated: bytes > cap };
|
|
11740
|
+
} finally {
|
|
11741
|
+
closeSync(fd);
|
|
11742
|
+
}
|
|
11743
|
+
}
|
|
11744
|
+
var AGENT_CONFIG_SIGNALS = [
|
|
11745
|
+
".claude",
|
|
11746
|
+
".agents",
|
|
11747
|
+
".mcp.json",
|
|
11748
|
+
"mcp.json",
|
|
11749
|
+
"AGENTS.md",
|
|
11750
|
+
"CLAUDE.md",
|
|
11751
|
+
"skills-lock.json"
|
|
11752
|
+
];
|
|
11753
|
+
function hasAgentConfigSignal(dir) {
|
|
11754
|
+
return AGENT_CONFIG_SIGNALS.some((name) => existsSync2(join2(dir, name)));
|
|
11755
|
+
}
|
|
11673
11756
|
function resolveRoot(startDir) {
|
|
11674
11757
|
let dir = resolve(startDir);
|
|
11675
11758
|
for (;; ) {
|
|
11676
|
-
if (existsSync2(join2(dir, "package.json"))) {
|
|
11759
|
+
if (existsSync2(join2(dir, "package.json")) || hasAgentConfigSignal(dir)) {
|
|
11677
11760
|
return dir;
|
|
11678
11761
|
}
|
|
11679
11762
|
const parent = resolve(dir, "..");
|
|
11680
11763
|
if (parent === dir) {
|
|
11681
|
-
throw new Error(`No package.json found walking up from ${resolve(startDir)}`);
|
|
11764
|
+
throw new Error(`No package.json or agent configuration found walking up from ${resolve(startDir)}`);
|
|
11682
11765
|
}
|
|
11683
11766
|
dir = parent;
|
|
11684
11767
|
}
|
|
@@ -11706,25 +11789,6 @@ function readJsonConfig(path, errors3) {
|
|
|
11706
11789
|
return;
|
|
11707
11790
|
}
|
|
11708
11791
|
}
|
|
11709
|
-
var BUNDLED = "scripts|references|assets|templates|examples";
|
|
11710
|
-
var REFERENCE_RE = new RegExp(`(?<![\\w/.-])(?:\\./)?((?:${BUNDLED})/[A-Za-z0-9_./-]+\\.[A-Za-z0-9]{1,10})(?![A-Za-z0-9_.-])`, "g");
|
|
11711
|
-
var FENCE_BLOCK = /^[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?(?:^[ \t]*\1[ \t]*$|$)/gm;
|
|
11712
|
-
var INLINE_CODE = /`[^`\n]*`/g;
|
|
11713
|
-
var URLS = /\b[a-z][a-z0-9+.-]*:\/\/\S+/gi;
|
|
11714
|
-
function skillReferences(body) {
|
|
11715
|
-
const prose = body.replace(FENCE_BLOCK, "").replace(INLINE_CODE, "").replace(URLS, "");
|
|
11716
|
-
const out = [];
|
|
11717
|
-
const seen = new Set;
|
|
11718
|
-
for (const match of prose.matchAll(REFERENCE_RE)) {
|
|
11719
|
-
const path = match[1];
|
|
11720
|
-
if (path === undefined || seen.has(path)) {
|
|
11721
|
-
continue;
|
|
11722
|
-
}
|
|
11723
|
-
seen.add(path);
|
|
11724
|
-
out.push(path);
|
|
11725
|
-
}
|
|
11726
|
-
return out;
|
|
11727
|
-
}
|
|
11728
11792
|
function scalar(value) {
|
|
11729
11793
|
if (typeof value === "string") {
|
|
11730
11794
|
const trimmed = value.trim();
|
|
@@ -11739,14 +11803,18 @@ function readFrontmatter(skillMdPath, errors3) {
|
|
|
11739
11803
|
let text;
|
|
11740
11804
|
let truncated = false;
|
|
11741
11805
|
try {
|
|
11742
|
-
const
|
|
11743
|
-
truncated =
|
|
11744
|
-
text = buf.subarray(0, SKILL_MD_CAP).toString("utf8");
|
|
11806
|
+
const result = readCapped(skillMdPath, SKILL_MD_CAP);
|
|
11807
|
+
truncated = result.truncated;
|
|
11808
|
+
text = result.buf.subarray(0, SKILL_MD_CAP).toString("utf8");
|
|
11745
11809
|
if (text.charCodeAt(0) === 65279) {
|
|
11746
11810
|
text = text.slice(1);
|
|
11747
11811
|
}
|
|
11748
11812
|
text = text.replace(/\r\n/g, `
|
|
11749
11813
|
`);
|
|
11814
|
+
if (truncated) {
|
|
11815
|
+
errors3.push({ path: skillMdPath, kind: "unexpected-shape", detail: `file exceeds ${SKILL_MD_CAP} byte scan cap` });
|
|
11816
|
+
return { hasFrontmatter: true, unparseable: true };
|
|
11817
|
+
}
|
|
11750
11818
|
} catch (err) {
|
|
11751
11819
|
errors3.push({
|
|
11752
11820
|
path: skillMdPath,
|
|
@@ -11803,23 +11871,12 @@ function readFrontmatter(skillMdPath, errors3) {
|
|
|
11803
11871
|
}
|
|
11804
11872
|
return out;
|
|
11805
11873
|
}
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
return statSync(p).isFile();
|
|
11810
|
-
} catch {
|
|
11811
|
-
return false;
|
|
11812
|
-
}
|
|
11813
|
-
};
|
|
11814
|
-
return skillReferences(body).filter((rel) => !isFile(join2(skillDir, rel)) && !isFile(join2(root, rel)));
|
|
11815
|
-
}
|
|
11816
|
-
function discoverSkillsInDir(dir, source, errors3, root) {
|
|
11817
|
-
if (!existsSync2(dir)) {
|
|
11818
|
-
return [];
|
|
11819
|
-
}
|
|
11874
|
+
|
|
11875
|
+
// src/discover/agents.ts
|
|
11876
|
+
function agentFiles(dir, errors3) {
|
|
11820
11877
|
let entries;
|
|
11821
11878
|
try {
|
|
11822
|
-
entries = readdirSync(dir);
|
|
11879
|
+
entries = readdirSync(dir, { withFileTypes: true }).map((e) => e.isDirectory() ? `${e.name}/` : e.name);
|
|
11823
11880
|
} catch (err) {
|
|
11824
11881
|
errors3.push({
|
|
11825
11882
|
path: dir,
|
|
@@ -11828,144 +11885,66 @@ function discoverSkillsInDir(dir, source, errors3, root) {
|
|
|
11828
11885
|
});
|
|
11829
11886
|
return [];
|
|
11830
11887
|
}
|
|
11831
|
-
const
|
|
11832
|
-
for (const
|
|
11833
|
-
if (
|
|
11888
|
+
const out = [];
|
|
11889
|
+
for (const entry of entries) {
|
|
11890
|
+
if (entry.startsWith(".")) {
|
|
11834
11891
|
continue;
|
|
11835
11892
|
}
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
try {
|
|
11839
|
-
st = statSync(skillDir);
|
|
11840
|
-
} catch {
|
|
11893
|
+
if (entry.endsWith("/")) {
|
|
11894
|
+
out.push(...agentFiles(join3(dir, entry.slice(0, -1)), errors3).map((p) => join3(entry.slice(0, -1), p)));
|
|
11841
11895
|
continue;
|
|
11842
11896
|
}
|
|
11843
|
-
|
|
11897
|
+
out.push(entry);
|
|
11898
|
+
}
|
|
11899
|
+
return out;
|
|
11900
|
+
}
|
|
11901
|
+
function discoverAgents(root, errors3) {
|
|
11902
|
+
const dir = join3(root, ".claude", "agents");
|
|
11903
|
+
if (!existsSync3(dir)) {
|
|
11904
|
+
return [];
|
|
11905
|
+
}
|
|
11906
|
+
const entries = agentFiles(dir, errors3);
|
|
11907
|
+
const facts = [];
|
|
11908
|
+
for (const name of entries) {
|
|
11909
|
+
if (!name.endsWith(".md")) {
|
|
11844
11910
|
continue;
|
|
11845
11911
|
}
|
|
11846
|
-
const
|
|
11847
|
-
let dirReadable = true;
|
|
11912
|
+
const filePath = join3(dir, name);
|
|
11848
11913
|
try {
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
detail: err instanceof Error ? err.message : String(err)
|
|
11856
|
-
});
|
|
11914
|
+
const st = statSync(filePath);
|
|
11915
|
+
if (!st.isFile()) {
|
|
11916
|
+
continue;
|
|
11917
|
+
}
|
|
11918
|
+
} catch {
|
|
11919
|
+
continue;
|
|
11857
11920
|
}
|
|
11858
|
-
const
|
|
11859
|
-
const fm = hasSkillMd ? readFrontmatter(skillMd, errors3) : { hasFrontmatter: false };
|
|
11921
|
+
const fm = readFrontmatter(filePath, errors3);
|
|
11860
11922
|
const fact = {
|
|
11861
|
-
|
|
11862
|
-
path:
|
|
11863
|
-
source,
|
|
11864
|
-
hasSkillMd,
|
|
11923
|
+
name: name.slice(0, -".md".length),
|
|
11924
|
+
path: filePath,
|
|
11865
11925
|
hasFrontmatter: fm.hasFrontmatter
|
|
11866
11926
|
};
|
|
11867
|
-
if (fm.unreadable === true
|
|
11927
|
+
if (fm.unreadable === true) {
|
|
11868
11928
|
fact.unreadable = true;
|
|
11869
11929
|
}
|
|
11870
11930
|
if (fm.unparseable === true) {
|
|
11871
11931
|
fact.unparseableFrontmatter = true;
|
|
11872
11932
|
}
|
|
11873
|
-
if (fm.body !== undefined) {
|
|
11874
|
-
const broken = brokenReferences(fm.body, skillDir, root);
|
|
11875
|
-
if (broken.length > 0) {
|
|
11876
|
-
fact.brokenReferences = broken;
|
|
11877
|
-
}
|
|
11878
|
-
}
|
|
11879
|
-
if (fm.description !== undefined) {
|
|
11880
|
-
fact.description = fm.description;
|
|
11881
|
-
}
|
|
11882
11933
|
if (fm.name !== undefined) {
|
|
11883
11934
|
fact.frontmatterName = fm.name;
|
|
11884
11935
|
}
|
|
11885
|
-
|
|
11886
|
-
|
|
11887
|
-
return skills;
|
|
11888
|
-
}
|
|
11889
|
-
function parseMcpServers(raw, filePath, errors3) {
|
|
11890
|
-
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
11891
|
-
errors3.push({
|
|
11892
|
-
path: filePath,
|
|
11893
|
-
kind: "unexpected-shape",
|
|
11894
|
-
detail: "MCP config root is not a JSON object"
|
|
11895
|
-
});
|
|
11896
|
-
return [];
|
|
11897
|
-
}
|
|
11898
|
-
const obj = raw;
|
|
11899
|
-
let servers;
|
|
11900
|
-
if ("mcpServers" in obj && obj.mcpServers !== null && typeof obj.mcpServers === "object" && !Array.isArray(obj.mcpServers)) {
|
|
11901
|
-
servers = obj.mcpServers;
|
|
11902
|
-
} else if (!("mcpServers" in obj) && Object.keys(obj).length > 0 && Object.values(obj).every((v) => v !== null && typeof v === "object" && !Array.isArray(v) && (("command" in v) || ("url" in v) || ("type" in v)))) {
|
|
11903
|
-
servers = obj;
|
|
11904
|
-
} else {
|
|
11905
|
-
errors3.push({
|
|
11906
|
-
path: filePath,
|
|
11907
|
-
kind: "unexpected-shape",
|
|
11908
|
-
detail: "no usable `mcpServers` object and the root is not a server map"
|
|
11909
|
-
});
|
|
11910
|
-
return [];
|
|
11911
|
-
}
|
|
11912
|
-
const facts = [];
|
|
11913
|
-
for (const [name, value] of Object.entries(servers)) {
|
|
11914
|
-
let hasCommand = false;
|
|
11915
|
-
let hasUrl = false;
|
|
11916
|
-
let transport;
|
|
11917
|
-
const literalEnvKeys = [];
|
|
11918
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
11919
|
-
const entry = value;
|
|
11920
|
-
hasCommand = typeof entry.command === "string" && entry.command.length > 0;
|
|
11921
|
-
hasUrl = typeof entry.url === "string" && entry.url.length > 0;
|
|
11922
|
-
if (typeof entry.type === "string" && entry.type.length > 0) {
|
|
11923
|
-
transport = entry.type;
|
|
11924
|
-
}
|
|
11925
|
-
const env = entry.env;
|
|
11926
|
-
if (env !== null && typeof env === "object" && !Array.isArray(env)) {
|
|
11927
|
-
for (const [key, val] of Object.entries(env)) {
|
|
11928
|
-
if (typeof val === "string" && val.length > 0 && !val.includes("${") && !val.startsWith("$") && /(?:TOKEN|SECRET|KEY|PASSWORD|PASSWD|CREDENTIAL)S?$/i.test(key)) {
|
|
11929
|
-
literalEnvKeys.push(key);
|
|
11930
|
-
}
|
|
11931
|
-
}
|
|
11932
|
-
}
|
|
11933
|
-
}
|
|
11934
|
-
facts.push({
|
|
11935
|
-
name,
|
|
11936
|
-
path: filePath,
|
|
11937
|
-
hasCommand,
|
|
11938
|
-
hasUrl,
|
|
11939
|
-
...transport === undefined ? {} : { transport },
|
|
11940
|
-
literalEnvKeys,
|
|
11941
|
-
raw: JSON.stringify(value)
|
|
11942
|
-
});
|
|
11943
|
-
}
|
|
11944
|
-
return facts;
|
|
11945
|
-
}
|
|
11946
|
-
function discoverMcp(root, mcpPaths, errors3) {
|
|
11947
|
-
const facts = [];
|
|
11948
|
-
const seen = new Set;
|
|
11949
|
-
for (const rel of mcpPaths) {
|
|
11950
|
-
const filePath = join2(root, rel);
|
|
11951
|
-
if (!existsSync2(filePath)) {
|
|
11952
|
-
continue;
|
|
11953
|
-
}
|
|
11954
|
-
const raw = readJsonConfig(filePath, errors3);
|
|
11955
|
-
if (raw === undefined) {
|
|
11956
|
-
continue;
|
|
11957
|
-
}
|
|
11958
|
-
for (const fact of parseMcpServers(raw, filePath, errors3)) {
|
|
11959
|
-
const key = `${fact.name}@${fact.path}`;
|
|
11960
|
-
if (seen.has(key)) {
|
|
11961
|
-
continue;
|
|
11962
|
-
}
|
|
11963
|
-
seen.add(key);
|
|
11964
|
-
facts.push(fact);
|
|
11936
|
+
if (fm.description !== undefined) {
|
|
11937
|
+
fact.description = fm.description;
|
|
11965
11938
|
}
|
|
11939
|
+
facts.push(fact);
|
|
11966
11940
|
}
|
|
11967
11941
|
return facts;
|
|
11968
11942
|
}
|
|
11943
|
+
|
|
11944
|
+
// src/discover/hooks.ts
|
|
11945
|
+
import { existsSync as existsSync4, statSync as statSync2 } from "node:fs";
|
|
11946
|
+
import { homedir } from "node:os";
|
|
11947
|
+
import { isAbsolute, join as join4 } from "node:path";
|
|
11969
11948
|
var INTERPRETERS = /^(?:bash|sh|zsh|python3?|node|bun|deno)$/;
|
|
11970
11949
|
var INLINE_CODE_FLAGS = /^-(?:e|p|c)$/;
|
|
11971
11950
|
var SHELL_METACHARS = /[|;&`]|\$\(|\|\||&&/;
|
|
@@ -11981,7 +11960,9 @@ function hookScriptPath(command) {
|
|
|
11981
11960
|
const unquote = (t) => t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'") ? t.slice(1, -1) : t;
|
|
11982
11961
|
let i = 0;
|
|
11983
11962
|
const first = unquote(tokens[0]);
|
|
11963
|
+
let interpreted = false;
|
|
11984
11964
|
if (INTERPRETERS.test(first)) {
|
|
11965
|
+
interpreted = true;
|
|
11985
11966
|
i = 1;
|
|
11986
11967
|
while (i < tokens.length) {
|
|
11987
11968
|
const flag = unquote(tokens[i]);
|
|
@@ -11995,7 +11976,7 @@ function hookScriptPath(command) {
|
|
|
11995
11976
|
}
|
|
11996
11977
|
}
|
|
11997
11978
|
const candidate = tokens[i] === undefined ? undefined : unquote(tokens[i]);
|
|
11998
|
-
if (candidate === undefined || !candidate.includes("/")) {
|
|
11979
|
+
if (candidate === undefined || !candidate.includes("/") && !(interpreted && /\.(?:js|mjs|cjs|ts|py|sh|bash|zsh)$/i.test(candidate))) {
|
|
11999
11980
|
return;
|
|
12000
11981
|
}
|
|
12001
11982
|
if (/^[A-Za-z]:[/\\]/.test(candidate)) {
|
|
@@ -12016,21 +11997,25 @@ function resolveHookScript(root, raw) {
|
|
|
12016
11997
|
}
|
|
12017
11998
|
let expanded = extracted;
|
|
12018
11999
|
if (expanded.startsWith("~/")) {
|
|
12019
|
-
expanded =
|
|
12000
|
+
expanded = join4(homedir(), expanded.slice(2));
|
|
12020
12001
|
} else if (expanded.startsWith("$")) {
|
|
12021
12002
|
expanded = expanded.replace(/^\$(?:CLAUDE_PROJECT_DIR|\{CLAUDE_PROJECT_DIR\})\/?/, "");
|
|
12022
12003
|
}
|
|
12023
|
-
const abs = isAbsolute(expanded) ? expanded :
|
|
12024
|
-
|
|
12004
|
+
const abs = isAbsolute(expanded) ? expanded : join4(root, expanded);
|
|
12005
|
+
try {
|
|
12006
|
+
return { scriptPath: extracted, exists: statSync2(abs).isFile() };
|
|
12007
|
+
} catch {
|
|
12008
|
+
return { scriptPath: extracted, exists: false };
|
|
12009
|
+
}
|
|
12025
12010
|
}
|
|
12026
12011
|
function discoverHooks(root, errors3) {
|
|
12027
12012
|
const files = [
|
|
12028
|
-
|
|
12029
|
-
|
|
12013
|
+
join4(root, ".claude", "settings.json"),
|
|
12014
|
+
join4(root, ".claude", "settings.local.json")
|
|
12030
12015
|
];
|
|
12031
12016
|
const facts = [];
|
|
12032
12017
|
for (const filePath of files) {
|
|
12033
|
-
if (!
|
|
12018
|
+
if (!existsSync4(filePath)) {
|
|
12034
12019
|
continue;
|
|
12035
12020
|
}
|
|
12036
12021
|
const raw = readJsonConfig(filePath, errors3);
|
|
@@ -12058,6 +12043,25 @@ function discoverHooks(root, errors3) {
|
|
|
12058
12043
|
continue;
|
|
12059
12044
|
}
|
|
12060
12045
|
for (const [event, groups] of Object.entries(hooks)) {
|
|
12046
|
+
const malformed = !Array.isArray(groups) || groups.some((group) => {
|
|
12047
|
+
if (group === null || typeof group !== "object" || Array.isArray(group)) {
|
|
12048
|
+
return true;
|
|
12049
|
+
}
|
|
12050
|
+
const inner = group.hooks;
|
|
12051
|
+
if (!Array.isArray(inner))
|
|
12052
|
+
return true;
|
|
12053
|
+
return inner.some((entry) => {
|
|
12054
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
|
|
12055
|
+
return true;
|
|
12056
|
+
}
|
|
12057
|
+
const item = entry;
|
|
12058
|
+
return item.command !== undefined && (typeof item.command !== "string" || item.command.length === 0) || item.type === "command" && typeof item.command !== "string";
|
|
12059
|
+
});
|
|
12060
|
+
});
|
|
12061
|
+
if (malformed) {
|
|
12062
|
+
errors3.push({ path: filePath, kind: "unexpected-shape", detail: `invalid hook groups for ${event}` });
|
|
12063
|
+
continue;
|
|
12064
|
+
}
|
|
12061
12065
|
const commands = collectHookCommands(groups);
|
|
12062
12066
|
if (commands.length === 0) {
|
|
12063
12067
|
facts.push({ name: event, path: filePath, event });
|
|
@@ -12098,87 +12102,160 @@ function collectHookCommands(groups) {
|
|
|
12098
12102
|
out.push(command);
|
|
12099
12103
|
}
|
|
12100
12104
|
}
|
|
12101
|
-
}
|
|
12102
|
-
return out;
|
|
12103
|
-
}
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
|
|
12105
|
+
}
|
|
12106
|
+
return out;
|
|
12107
|
+
}
|
|
12108
|
+
|
|
12109
|
+
// src/discover/mcp.ts
|
|
12110
|
+
import { existsSync as existsSync5, statSync as statSync3 } from "node:fs";
|
|
12111
|
+
import { homedir as homedir2 } from "node:os";
|
|
12112
|
+
import { isAbsolute as isAbsolute2, join as join5 } from "node:path";
|
|
12113
|
+
var SHELL_METACHARS2 = /[|;&`]|\$\(|\|\||&&|\s/;
|
|
12114
|
+
function mcpCommandPath(command) {
|
|
12115
|
+
const trimmed = command.trim();
|
|
12116
|
+
if (trimmed.length === 0 || SHELL_METACHARS2.test(trimmed)) {
|
|
12117
|
+
return;
|
|
12118
|
+
}
|
|
12119
|
+
if (/^[A-Za-z]:[/\\]/.test(trimmed)) {
|
|
12120
|
+
return;
|
|
12121
|
+
}
|
|
12122
|
+
if (trimmed.startsWith("$")) {
|
|
12123
|
+
return /^\$(?:CLAUDE_PROJECT_DIR\b|\{CLAUDE_PROJECT_DIR\})/.test(trimmed) ? trimmed : undefined;
|
|
12124
|
+
}
|
|
12125
|
+
if (trimmed.startsWith("/") || trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed.startsWith("~/") || trimmed.startsWith(".")) {
|
|
12126
|
+
return trimmed;
|
|
12127
|
+
}
|
|
12128
|
+
if (trimmed.includes("/")) {
|
|
12129
|
+
return trimmed;
|
|
12130
|
+
}
|
|
12131
|
+
return;
|
|
12132
|
+
}
|
|
12133
|
+
function resolveMcpCommand(root, raw) {
|
|
12134
|
+
const extracted = mcpCommandPath(raw);
|
|
12135
|
+
if (extracted === undefined) {
|
|
12136
|
+
return;
|
|
12137
|
+
}
|
|
12138
|
+
let expanded = extracted;
|
|
12139
|
+
if (expanded.startsWith("~/")) {
|
|
12140
|
+
expanded = join5(homedir2(), expanded.slice(2));
|
|
12141
|
+
} else if (expanded.startsWith("$")) {
|
|
12142
|
+
expanded = expanded.replace(/^\$(?:CLAUDE_PROJECT_DIR|\{CLAUDE_PROJECT_DIR\})\/?/, "");
|
|
12143
|
+
}
|
|
12144
|
+
const abs = isAbsolute2(expanded) ? expanded : join5(root, expanded);
|
|
12145
|
+
try {
|
|
12146
|
+
return { command: extracted, exists: statSync3(abs).isFile() };
|
|
12147
|
+
} catch {
|
|
12148
|
+
return { command: extracted, exists: false };
|
|
12149
|
+
}
|
|
12150
|
+
}
|
|
12151
|
+
function parseMcpServers(raw, filePath, root, errors3) {
|
|
12152
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
12153
|
+
errors3.push({
|
|
12154
|
+
path: filePath,
|
|
12155
|
+
kind: "unexpected-shape",
|
|
12156
|
+
detail: "MCP config root is not a JSON object"
|
|
12157
|
+
});
|
|
12158
|
+
return [];
|
|
12159
|
+
}
|
|
12160
|
+
const obj = raw;
|
|
12161
|
+
let servers;
|
|
12162
|
+
if ("mcpServers" in obj && obj.mcpServers !== null && typeof obj.mcpServers === "object" && !Array.isArray(obj.mcpServers)) {
|
|
12163
|
+
servers = obj.mcpServers;
|
|
12164
|
+
} else if (!("mcpServers" in obj) && Object.keys(obj).length > 0 && Object.values(obj).every((v) => v !== null && typeof v === "object" && !Array.isArray(v) && (("command" in v) || ("url" in v) || ("type" in v)))) {
|
|
12165
|
+
servers = obj;
|
|
12166
|
+
} else {
|
|
12167
|
+
errors3.push({
|
|
12168
|
+
path: filePath,
|
|
12169
|
+
kind: "unexpected-shape",
|
|
12170
|
+
detail: "no usable `mcpServers` object and the root is not a server map"
|
|
12171
|
+
});
|
|
12172
|
+
return [];
|
|
12173
|
+
}
|
|
12174
|
+
const facts = [];
|
|
12175
|
+
for (const [name, value] of Object.entries(servers)) {
|
|
12176
|
+
let hasCommand = false;
|
|
12177
|
+
let hasUrl = false;
|
|
12178
|
+
let command;
|
|
12179
|
+
let commandExists;
|
|
12180
|
+
let transport;
|
|
12181
|
+
const literalEnvKeys = [];
|
|
12182
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
12183
|
+
const entry = value;
|
|
12184
|
+
hasCommand = typeof entry.command === "string" && entry.command.length > 0;
|
|
12185
|
+
if (typeof entry.command === "string" && entry.command.length > 0) {
|
|
12186
|
+
command = entry.command;
|
|
12187
|
+
const resolved = resolveMcpCommand(root, entry.command);
|
|
12188
|
+
if (resolved !== undefined) {
|
|
12189
|
+
commandExists = resolved.exists;
|
|
12190
|
+
}
|
|
12191
|
+
}
|
|
12192
|
+
hasUrl = typeof entry.url === "string" && entry.url.length > 0;
|
|
12193
|
+
if (typeof entry.type === "string" && entry.type.length > 0) {
|
|
12194
|
+
transport = entry.type;
|
|
12195
|
+
}
|
|
12196
|
+
const env = entry.env;
|
|
12197
|
+
if (env !== null && typeof env === "object" && !Array.isArray(env)) {
|
|
12198
|
+
for (const [key, val] of Object.entries(env)) {
|
|
12199
|
+
if (typeof val === "string" && val.length > 0 && !/\$\{[A-Za-z_][A-Za-z0-9_]*(?::-[^}]*)?\}/.test(val) && /(?:TOKEN|SECRET|KEY|PASSWORD|PASSWD|CREDENTIAL)S?$/i.test(key)) {
|
|
12200
|
+
literalEnvKeys.push(key);
|
|
12201
|
+
}
|
|
12202
|
+
}
|
|
12203
|
+
}
|
|
12204
|
+
}
|
|
12205
|
+
facts.push({
|
|
12206
|
+
name,
|
|
12207
|
+
path: filePath,
|
|
12208
|
+
hasCommand,
|
|
12209
|
+
hasUrl,
|
|
12210
|
+
...command === undefined ? {} : { command },
|
|
12211
|
+
...commandExists === undefined ? {} : { commandExists },
|
|
12212
|
+
...transport === undefined ? {} : { transport },
|
|
12213
|
+
literalEnvKeys,
|
|
12214
|
+
raw: JSON.stringify(value)
|
|
12113
12215
|
});
|
|
12114
|
-
return [];
|
|
12115
|
-
}
|
|
12116
|
-
const out = [];
|
|
12117
|
-
for (const entry of entries) {
|
|
12118
|
-
if (entry.startsWith(".")) {
|
|
12119
|
-
continue;
|
|
12120
|
-
}
|
|
12121
|
-
if (entry.endsWith("/")) {
|
|
12122
|
-
out.push(...agentFiles(join2(dir, entry.slice(0, -1)), errors3).map((p) => join2(entry.slice(0, -1), p)));
|
|
12123
|
-
continue;
|
|
12124
|
-
}
|
|
12125
|
-
out.push(entry);
|
|
12126
12216
|
}
|
|
12127
|
-
return
|
|
12217
|
+
return facts;
|
|
12128
12218
|
}
|
|
12129
|
-
function
|
|
12130
|
-
const dir = join2(root, ".claude", "agents");
|
|
12131
|
-
if (!existsSync2(dir)) {
|
|
12132
|
-
return [];
|
|
12133
|
-
}
|
|
12134
|
-
const entries = agentFiles(dir, errors3);
|
|
12219
|
+
function discoverMcp(root, mcpPaths, errors3) {
|
|
12135
12220
|
const facts = [];
|
|
12136
|
-
|
|
12137
|
-
|
|
12221
|
+
const seen = new Set;
|
|
12222
|
+
for (const rel of mcpPaths) {
|
|
12223
|
+
const filePath = join5(root, rel);
|
|
12224
|
+
if (!existsSync5(filePath)) {
|
|
12138
12225
|
continue;
|
|
12139
12226
|
}
|
|
12140
|
-
const
|
|
12141
|
-
|
|
12142
|
-
const st = statSync(filePath);
|
|
12143
|
-
if (!st.isFile()) {
|
|
12144
|
-
continue;
|
|
12145
|
-
}
|
|
12146
|
-
} catch {
|
|
12227
|
+
const raw = readJsonConfig(filePath, errors3);
|
|
12228
|
+
if (raw === undefined) {
|
|
12147
12229
|
continue;
|
|
12148
12230
|
}
|
|
12149
|
-
const
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
fact.unreadable = true;
|
|
12157
|
-
}
|
|
12158
|
-
if (fm.unparseable === true) {
|
|
12159
|
-
fact.unparseableFrontmatter = true;
|
|
12160
|
-
}
|
|
12161
|
-
if (fm.name !== undefined) {
|
|
12162
|
-
fact.frontmatterName = fm.name;
|
|
12163
|
-
}
|
|
12164
|
-
if (fm.description !== undefined) {
|
|
12165
|
-
fact.description = fm.description;
|
|
12231
|
+
for (const fact of parseMcpServers(raw, filePath, root, errors3)) {
|
|
12232
|
+
const key = `${fact.name}@${fact.path}`;
|
|
12233
|
+
if (seen.has(key)) {
|
|
12234
|
+
continue;
|
|
12235
|
+
}
|
|
12236
|
+
seen.add(key);
|
|
12237
|
+
facts.push(fact);
|
|
12166
12238
|
}
|
|
12167
|
-
facts.push(fact);
|
|
12168
12239
|
}
|
|
12169
12240
|
return facts;
|
|
12170
12241
|
}
|
|
12242
|
+
|
|
12243
|
+
// src/discover/policy.ts
|
|
12244
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
12245
|
+
import { join as join6 } from "node:path";
|
|
12171
12246
|
function discoverPolicyFiles(root, policyFiles, errors3) {
|
|
12172
12247
|
const out = [];
|
|
12173
12248
|
for (const rel of policyFiles) {
|
|
12174
|
-
const filePath =
|
|
12175
|
-
if (!
|
|
12249
|
+
const filePath = join6(root, rel);
|
|
12250
|
+
if (!existsSync6(filePath)) {
|
|
12176
12251
|
continue;
|
|
12177
12252
|
}
|
|
12178
12253
|
try {
|
|
12179
|
-
const
|
|
12180
|
-
const text = buf.subarray(0, POLICY_CAP).toString("utf8");
|
|
12254
|
+
const result = readCapped(filePath, POLICY_CAP);
|
|
12255
|
+
const text = result.buf.subarray(0, POLICY_CAP).toString("utf8");
|
|
12181
12256
|
out.push({ path: filePath, text });
|
|
12257
|
+
if (result.truncated)
|
|
12258
|
+
errors3.push({ path: filePath, kind: "unexpected-shape", detail: `file exceeds ${POLICY_CAP} byte scan cap` });
|
|
12182
12259
|
} catch (err) {
|
|
12183
12260
|
errors3.push({
|
|
12184
12261
|
path: filePath,
|
|
@@ -12190,13 +12267,13 @@ function discoverPolicyFiles(root, policyFiles, errors3) {
|
|
|
12190
12267
|
return out;
|
|
12191
12268
|
}
|
|
12192
12269
|
function discoverSkillsLock(root, errors3) {
|
|
12193
|
-
const filePath =
|
|
12194
|
-
if (!
|
|
12270
|
+
const filePath = join6(root, "skills-lock.json");
|
|
12271
|
+
if (!existsSync6(filePath)) {
|
|
12195
12272
|
return { locked: [], present: false };
|
|
12196
12273
|
}
|
|
12197
12274
|
const raw = readJsonConfig(filePath, errors3);
|
|
12198
12275
|
if (raw === undefined) {
|
|
12199
|
-
return { locked: [], present: true };
|
|
12276
|
+
return { locked: [], present: true, invalid: true };
|
|
12200
12277
|
}
|
|
12201
12278
|
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
12202
12279
|
errors3.push({
|
|
@@ -12204,7 +12281,7 @@ function discoverSkillsLock(root, errors3) {
|
|
|
12204
12281
|
kind: "unexpected-shape",
|
|
12205
12282
|
detail: "skills-lock.json is not a JSON object"
|
|
12206
12283
|
});
|
|
12207
|
-
return { locked: [], present: true };
|
|
12284
|
+
return { locked: [], present: true, invalid: true };
|
|
12208
12285
|
}
|
|
12209
12286
|
const skills = raw.skills;
|
|
12210
12287
|
if (skills === null || typeof skills !== "object" || Array.isArray(skills)) {
|
|
@@ -12213,7 +12290,7 @@ function discoverSkillsLock(root, errors3) {
|
|
|
12213
12290
|
kind: "unexpected-shape",
|
|
12214
12291
|
detail: "skills-lock.json has no `skills` object"
|
|
12215
12292
|
});
|
|
12216
|
-
return { locked: [], present: true };
|
|
12293
|
+
return { locked: [], present: true, invalid: true };
|
|
12217
12294
|
}
|
|
12218
12295
|
const locked = [];
|
|
12219
12296
|
for (const [id, value] of Object.entries(skills)) {
|
|
@@ -12234,50 +12311,219 @@ function discoverSkillsLock(root, errors3) {
|
|
|
12234
12311
|
}
|
|
12235
12312
|
return { locked, present: true };
|
|
12236
12313
|
}
|
|
12314
|
+
|
|
12315
|
+
// src/discover/skills.ts
|
|
12316
|
+
import { existsSync as existsSync7, readdirSync as readdirSync2, statSync as statSync4 } from "node:fs";
|
|
12317
|
+
import { join as join7, resolve as resolve2 } from "node:path";
|
|
12318
|
+
var BUNDLED = "scripts|references|assets|templates|examples";
|
|
12319
|
+
var REFERENCE_RE = new RegExp(`(?<![\\w/.-])(?:\\./)?((?:${BUNDLED})/[A-Za-z0-9_./-]+\\.[A-Za-z0-9]{1,10})(?![A-Za-z0-9_.-])`, "g");
|
|
12320
|
+
var FENCE_BLOCK = /^[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?(?:^[ \t]*\1[ \t]*$|$)/gm;
|
|
12321
|
+
var INLINE_CODE = /`[^`\n]*`/g;
|
|
12322
|
+
var URLS = /\b[a-z][a-z0-9+.-]*:\/\/\S+/gi;
|
|
12323
|
+
function skillReferences(body) {
|
|
12324
|
+
const prose = body.replace(FENCE_BLOCK, "").replace(INLINE_CODE, (code) => /(?:scripts|references|assets|templates|examples)\/[A-Za-z0-9_./-]+\.[A-Za-z0-9]{1,10}/.test(code) ? code : "").replace(URLS, "");
|
|
12325
|
+
const out = [];
|
|
12326
|
+
const seen = new Set;
|
|
12327
|
+
for (const match of prose.matchAll(REFERENCE_RE)) {
|
|
12328
|
+
const path = match[1];
|
|
12329
|
+
if (path === undefined || seen.has(path)) {
|
|
12330
|
+
continue;
|
|
12331
|
+
}
|
|
12332
|
+
seen.add(path);
|
|
12333
|
+
out.push(path);
|
|
12334
|
+
}
|
|
12335
|
+
return out;
|
|
12336
|
+
}
|
|
12337
|
+
function brokenReferences(body, skillDir, root) {
|
|
12338
|
+
const isFile = (p) => {
|
|
12339
|
+
try {
|
|
12340
|
+
return statSync4(p).isFile();
|
|
12341
|
+
} catch {
|
|
12342
|
+
return false;
|
|
12343
|
+
}
|
|
12344
|
+
};
|
|
12345
|
+
return skillReferences(body).filter((rel) => !isFile(join7(skillDir, rel)) && !isFile(join7(root, rel)));
|
|
12346
|
+
}
|
|
12347
|
+
function discoverSkillsInDir(dir, source, errors3, root) {
|
|
12348
|
+
if (!existsSync7(dir)) {
|
|
12349
|
+
return [];
|
|
12350
|
+
}
|
|
12351
|
+
let entries;
|
|
12352
|
+
try {
|
|
12353
|
+
entries = readdirSync2(dir);
|
|
12354
|
+
} catch (err) {
|
|
12355
|
+
errors3.push({
|
|
12356
|
+
path: dir,
|
|
12357
|
+
kind: "unreadable",
|
|
12358
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
12359
|
+
});
|
|
12360
|
+
return [];
|
|
12361
|
+
}
|
|
12362
|
+
const skills = [];
|
|
12363
|
+
const normalizedDir = dir.replaceAll("\\", "/");
|
|
12364
|
+
const runtime = normalizedDir.includes("/.claude/skills") || normalizedDir.endsWith("/.claude/skills") ? "claude" : normalizedDir.includes("/.agents/skills") || normalizedDir.endsWith("/.agents/skills") ? "agents" : "unknown";
|
|
12365
|
+
for (const name of entries) {
|
|
12366
|
+
if (name.startsWith(".") || name === "node_modules") {
|
|
12367
|
+
continue;
|
|
12368
|
+
}
|
|
12369
|
+
const skillDir = join7(dir, name);
|
|
12370
|
+
let st;
|
|
12371
|
+
try {
|
|
12372
|
+
st = statSync4(skillDir);
|
|
12373
|
+
} catch {
|
|
12374
|
+
continue;
|
|
12375
|
+
}
|
|
12376
|
+
if (!st.isDirectory()) {
|
|
12377
|
+
continue;
|
|
12378
|
+
}
|
|
12379
|
+
const skillMd = join7(skillDir, "SKILL.md");
|
|
12380
|
+
let dirReadable = true;
|
|
12381
|
+
try {
|
|
12382
|
+
readdirSync2(skillDir);
|
|
12383
|
+
} catch (err) {
|
|
12384
|
+
dirReadable = false;
|
|
12385
|
+
errors3.push({
|
|
12386
|
+
path: skillDir,
|
|
12387
|
+
kind: "unreadable",
|
|
12388
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
12389
|
+
});
|
|
12390
|
+
}
|
|
12391
|
+
const hasSkillMd = dirReadable && existsSync7(skillMd);
|
|
12392
|
+
const fm = hasSkillMd ? readFrontmatter(skillMd, errors3) : { hasFrontmatter: false };
|
|
12393
|
+
const fact = {
|
|
12394
|
+
id: name,
|
|
12395
|
+
runtime,
|
|
12396
|
+
path: skillDir,
|
|
12397
|
+
source,
|
|
12398
|
+
hasSkillMd,
|
|
12399
|
+
hasFrontmatter: fm.hasFrontmatter
|
|
12400
|
+
};
|
|
12401
|
+
if (fm.unreadable === true || !dirReadable) {
|
|
12402
|
+
fact.unreadable = true;
|
|
12403
|
+
}
|
|
12404
|
+
if (fm.unparseable === true) {
|
|
12405
|
+
fact.unparseableFrontmatter = true;
|
|
12406
|
+
}
|
|
12407
|
+
if (fm.body !== undefined) {
|
|
12408
|
+
const broken = brokenReferences(fm.body, skillDir, root);
|
|
12409
|
+
if (broken.length > 0) {
|
|
12410
|
+
fact.brokenReferences = broken;
|
|
12411
|
+
}
|
|
12412
|
+
}
|
|
12413
|
+
if (fm.description !== undefined) {
|
|
12414
|
+
fact.description = fm.description;
|
|
12415
|
+
}
|
|
12416
|
+
if (fm.name !== undefined) {
|
|
12417
|
+
fact.frontmatterName = fm.name;
|
|
12418
|
+
}
|
|
12419
|
+
skills.push(fact);
|
|
12420
|
+
}
|
|
12421
|
+
return skills;
|
|
12422
|
+
}
|
|
12423
|
+
var NESTED_DISCOVERY_MAX_DEPTH = 8;
|
|
12424
|
+
var NESTED_DISCOVERY_SKIP = new Set([
|
|
12425
|
+
".git",
|
|
12426
|
+
"node_modules",
|
|
12427
|
+
".next",
|
|
12428
|
+
"dist",
|
|
12429
|
+
"build",
|
|
12430
|
+
"coverage",
|
|
12431
|
+
"vendor"
|
|
12432
|
+
]);
|
|
12433
|
+
function discoverNestedClaudeSkills(root, configuredRoots, errors3, options = {}) {
|
|
12434
|
+
const out = [];
|
|
12435
|
+
const read = (dir) => {
|
|
12436
|
+
options.onDirectoryRead?.();
|
|
12437
|
+
try {
|
|
12438
|
+
return readdirSync2(dir, { withFileTypes: true });
|
|
12439
|
+
} catch {
|
|
12440
|
+
errors3.push({ path: dir, kind: "unreadable", detail: "could not read nested skill directories" });
|
|
12441
|
+
return;
|
|
12442
|
+
}
|
|
12443
|
+
};
|
|
12444
|
+
const inspectClaude = (dir) => {
|
|
12445
|
+
const entries = read(dir);
|
|
12446
|
+
if (entries === undefined)
|
|
12447
|
+
return;
|
|
12448
|
+
for (const entry of entries) {
|
|
12449
|
+
if (!entry.isDirectory() || entry.name !== "skills")
|
|
12450
|
+
continue;
|
|
12451
|
+
const child = join7(dir, entry.name);
|
|
12452
|
+
if (configuredRoots.has(resolve2(child)))
|
|
12453
|
+
continue;
|
|
12454
|
+
out.push(...discoverSkillsInDir(child, "project", errors3, root));
|
|
12455
|
+
}
|
|
12456
|
+
};
|
|
12457
|
+
const walk = (dir, depth) => {
|
|
12458
|
+
const entries = read(dir);
|
|
12459
|
+
if (entries === undefined)
|
|
12460
|
+
return;
|
|
12461
|
+
for (const entry of entries) {
|
|
12462
|
+
if (!entry.isDirectory() || NESTED_DISCOVERY_SKIP.has(entry.name))
|
|
12463
|
+
continue;
|
|
12464
|
+
if (entry.name.startsWith(".") && entry.name !== ".claude")
|
|
12465
|
+
continue;
|
|
12466
|
+
const child = join7(dir, entry.name);
|
|
12467
|
+
if (entry.name === ".claude") {
|
|
12468
|
+
inspectClaude(child);
|
|
12469
|
+
continue;
|
|
12470
|
+
}
|
|
12471
|
+
if (depth >= NESTED_DISCOVERY_MAX_DEPTH)
|
|
12472
|
+
continue;
|
|
12473
|
+
walk(child, depth + 1);
|
|
12474
|
+
}
|
|
12475
|
+
};
|
|
12476
|
+
walk(root, 0);
|
|
12477
|
+
return out;
|
|
12478
|
+
}
|
|
12479
|
+
function disambiguateSkills(skills, root) {
|
|
12480
|
+
const counts = new Map;
|
|
12481
|
+
for (const skill of skills)
|
|
12482
|
+
counts.set(skill.id, (counts.get(skill.id) ?? 0) + 1);
|
|
12483
|
+
return skills.map((skill) => {
|
|
12484
|
+
if ((counts.get(skill.id) ?? 0) < 2)
|
|
12485
|
+
return skill;
|
|
12486
|
+
const location = skill.source === "project" ? skill.path.slice(root.length + 1) : `global:${skill.path}`;
|
|
12487
|
+
return { ...skill, instanceId: `${skill.id}@${location}` };
|
|
12488
|
+
});
|
|
12489
|
+
}
|
|
12490
|
+
|
|
12491
|
+
// src/discover/index.ts
|
|
12237
12492
|
function discoverAgentSurface(root, config, opts) {
|
|
12238
12493
|
const configErrors = [];
|
|
12239
12494
|
const skills = [];
|
|
12240
12495
|
for (const rel of config.skillPaths) {
|
|
12241
|
-
skills.push(...discoverSkillsInDir(
|
|
12496
|
+
skills.push(...discoverSkillsInDir(join8(root, rel), "project", configErrors, root));
|
|
12242
12497
|
}
|
|
12498
|
+
const configuredRoots = new Set(config.skillPaths.map((rel) => resolve3(root, rel)));
|
|
12499
|
+
skills.push(...discoverNestedClaudeSkills(root, configuredRoots, configErrors, {
|
|
12500
|
+
onDirectoryRead: opts.onNestedDirectoryRead
|
|
12501
|
+
}));
|
|
12243
12502
|
if (opts.includeGlobal) {
|
|
12244
|
-
const home =
|
|
12245
|
-
skills.push(...discoverSkillsInDir(
|
|
12246
|
-
skills.push(...discoverSkillsInDir(
|
|
12503
|
+
const home = homedir3();
|
|
12504
|
+
skills.push(...discoverSkillsInDir(join8(home, ".claude", "skills"), "global", configErrors, root));
|
|
12505
|
+
skills.push(...discoverSkillsInDir(join8(home, ".codex", "skills"), "global", configErrors, root));
|
|
12247
12506
|
}
|
|
12248
12507
|
const lock = discoverSkillsLock(root, configErrors);
|
|
12249
12508
|
return {
|
|
12250
|
-
skills:
|
|
12509
|
+
skills: disambiguateSkills(skills, root),
|
|
12251
12510
|
agents: discoverAgents(root, configErrors),
|
|
12252
12511
|
hooks: discoverHooks(root, configErrors),
|
|
12253
12512
|
mcp: discoverMcp(root, config.mcpPaths, configErrors),
|
|
12254
12513
|
policyFiles: discoverPolicyFiles(root, config.policyFiles, configErrors),
|
|
12255
12514
|
lockedSkills: lock.locked,
|
|
12256
12515
|
hasSkillsLock: lock.present,
|
|
12516
|
+
skillsLockInvalid: lock.invalid,
|
|
12257
12517
|
configErrors
|
|
12258
12518
|
};
|
|
12259
12519
|
}
|
|
12260
|
-
function dedupeSkillsById(skills) {
|
|
12261
|
-
const byId = new Map;
|
|
12262
|
-
for (const skill of skills) {
|
|
12263
|
-
const existing = byId.get(skill.id);
|
|
12264
|
-
if (!existing) {
|
|
12265
|
-
byId.set(skill.id, skill);
|
|
12266
|
-
continue;
|
|
12267
|
-
}
|
|
12268
|
-
if (existing.source === "global" && skill.source === "project") {
|
|
12269
|
-
byId.set(skill.id, skill);
|
|
12270
|
-
}
|
|
12271
|
-
}
|
|
12272
|
-
return [...byId.values()];
|
|
12273
|
-
}
|
|
12274
12520
|
|
|
12275
12521
|
// src/facts/extract.ts
|
|
12276
|
-
import { existsSync as
|
|
12277
|
-
import { join as
|
|
12522
|
+
import { existsSync as existsSync8, readFileSync as readFileSync3 } from "node:fs";
|
|
12523
|
+
import { join as join9 } from "node:path";
|
|
12278
12524
|
function readPackageJson(root, errors3) {
|
|
12279
|
-
const path =
|
|
12280
|
-
if (!
|
|
12525
|
+
const path = join9(root, "package.json");
|
|
12526
|
+
if (!existsSync8(path)) {
|
|
12281
12527
|
return {};
|
|
12282
12528
|
}
|
|
12283
12529
|
let text;
|
|
@@ -12315,7 +12561,7 @@ function readPackageJson(root, errors3) {
|
|
|
12315
12561
|
if (typeof obj.packageManager === "string") {
|
|
12316
12562
|
pkg.packageManager = obj.packageManager;
|
|
12317
12563
|
}
|
|
12318
|
-
for (const field of ["dependencies", "devDependencies"
|
|
12564
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
12319
12565
|
const raw2 = obj[field];
|
|
12320
12566
|
const kept = stringEntries(raw2);
|
|
12321
12567
|
if (kept === undefined) {
|
|
@@ -12337,6 +12583,19 @@ function readPackageJson(root, errors3) {
|
|
|
12337
12583
|
}
|
|
12338
12584
|
pkg[field] = kept.values;
|
|
12339
12585
|
}
|
|
12586
|
+
const scripts = obj.scripts;
|
|
12587
|
+
if (scripts !== undefined) {
|
|
12588
|
+
const kept = stringEntries(scripts);
|
|
12589
|
+
if (kept === undefined) {
|
|
12590
|
+
errors3.push({ path, kind: "unexpected-shape", detail: "scripts is not an object" });
|
|
12591
|
+
} else if (kept.dropped > 0) {
|
|
12592
|
+
errors3.push({
|
|
12593
|
+
path,
|
|
12594
|
+
kind: "unexpected-shape",
|
|
12595
|
+
detail: `scripts: ${kept.dropped} entr${kept.dropped === 1 ? "y" : "ies"} ignored (value is not a string)`
|
|
12596
|
+
});
|
|
12597
|
+
}
|
|
12598
|
+
}
|
|
12340
12599
|
return pkg;
|
|
12341
12600
|
}
|
|
12342
12601
|
function stringEntries(value) {
|
|
@@ -12362,95 +12621,32 @@ function inferPackageManager(root, pkg) {
|
|
|
12362
12621
|
return prefix;
|
|
12363
12622
|
}
|
|
12364
12623
|
}
|
|
12365
|
-
if (
|
|
12624
|
+
if (existsSync8(join9(root, "bun.lock")) || existsSync8(join9(root, "bun.lockb"))) {
|
|
12366
12625
|
return "bun";
|
|
12367
12626
|
}
|
|
12368
|
-
if (
|
|
12627
|
+
if (existsSync8(join9(root, "pnpm-lock.yaml"))) {
|
|
12369
12628
|
return "pnpm";
|
|
12370
12629
|
}
|
|
12371
|
-
if (
|
|
12630
|
+
if (existsSync8(join9(root, "yarn.lock"))) {
|
|
12372
12631
|
return "yarn";
|
|
12373
12632
|
}
|
|
12374
|
-
if (
|
|
12633
|
+
if (existsSync8(join9(root, "package-lock.json"))) {
|
|
12375
12634
|
return "npm";
|
|
12376
12635
|
}
|
|
12377
12636
|
return "unknown";
|
|
12378
12637
|
}
|
|
12379
|
-
function hasNextConfig(root) {
|
|
12380
|
-
try {
|
|
12381
|
-
const entries = readdirSync2(root);
|
|
12382
|
-
return entries.some((name) => name === "next.config.js" || name === "next.config.mjs" || name === "next.config.cjs" || name === "next.config.ts" || name === "next.config.mts");
|
|
12383
|
-
} catch {
|
|
12384
|
-
return false;
|
|
12385
|
-
}
|
|
12386
|
-
}
|
|
12387
|
-
function readNextConfigText(root) {
|
|
12388
|
-
const candidates = [
|
|
12389
|
-
"next.config.ts",
|
|
12390
|
-
"next.config.mjs",
|
|
12391
|
-
"next.config.js",
|
|
12392
|
-
"next.config.mts",
|
|
12393
|
-
"next.config.cjs"
|
|
12394
|
-
];
|
|
12395
|
-
for (const name of candidates) {
|
|
12396
|
-
const path = join3(root, name);
|
|
12397
|
-
if (!existsSync3(path)) {
|
|
12398
|
-
continue;
|
|
12399
|
-
}
|
|
12400
|
-
try {
|
|
12401
|
-
return readFileSync3(path, "utf8");
|
|
12402
|
-
} catch {
|
|
12403
|
-
return;
|
|
12404
|
-
}
|
|
12405
|
-
}
|
|
12406
|
-
return;
|
|
12407
|
-
}
|
|
12408
|
-
function extractConfigs(root, deps, devDeps, scripts) {
|
|
12409
|
-
const configs = {};
|
|
12410
|
-
if (existsSync3(join3(root, "components.json"))) {
|
|
12411
|
-
configs.shadcn = true;
|
|
12412
|
-
}
|
|
12413
|
-
if (existsSync3(join3(root, "biome.json")) || existsSync3(join3(root, "biome.jsonc"))) {
|
|
12414
|
-
configs.biome = true;
|
|
12415
|
-
}
|
|
12416
|
-
const allDeps = { ...deps, ...devDeps };
|
|
12417
|
-
const hasUltraciteDep = "ultracite" in allDeps;
|
|
12418
|
-
const hasUltraciteScript = Object.values(scripts).some((s) => s.includes("ultracite"));
|
|
12419
|
-
if (hasUltraciteDep || hasUltraciteScript) {
|
|
12420
|
-
configs.ultracite = true;
|
|
12421
|
-
}
|
|
12422
|
-
if ("next" in allDeps) {
|
|
12423
|
-
const next = {};
|
|
12424
|
-
if (hasNextConfig(root)) {
|
|
12425
|
-
next.appRouter = true;
|
|
12426
|
-
const text = readNextConfigText(root);
|
|
12427
|
-
if (text !== undefined) {
|
|
12428
|
-
if (/\bcacheComponents\s*:\s*true\b/.test(text) || /\bcacheComponents\s*:\s*!0\b/.test(text)) {
|
|
12429
|
-
next.cacheComponents = true;
|
|
12430
|
-
} else if (/\bcacheComponents\s*:\s*false\b/.test(text) || /\bcacheComponents\s*:\s*!1\b/.test(text)) {
|
|
12431
|
-
next.cacheComponents = false;
|
|
12432
|
-
}
|
|
12433
|
-
}
|
|
12434
|
-
}
|
|
12435
|
-
configs.next = next;
|
|
12436
|
-
}
|
|
12437
|
-
return configs;
|
|
12438
|
-
}
|
|
12439
12638
|
function extractFacts(root, config, opts) {
|
|
12440
12639
|
const includeGlobal = opts?.includeGlobal ?? config.includeGlobal;
|
|
12441
12640
|
const packageErrors = [];
|
|
12442
12641
|
const pkg = readPackageJson(root, packageErrors);
|
|
12443
12642
|
const dependencies = { ...pkg.dependencies ?? {} };
|
|
12444
12643
|
const devDependencies = { ...pkg.devDependencies ?? {} };
|
|
12445
|
-
const scripts = { ...pkg.scripts ?? {} };
|
|
12446
12644
|
const surface = discoverAgentSurface(root, config, { includeGlobal });
|
|
12447
12645
|
return {
|
|
12448
12646
|
root,
|
|
12449
12647
|
packageManager: inferPackageManager(root, pkg),
|
|
12450
12648
|
dependencies,
|
|
12451
12649
|
devDependencies,
|
|
12452
|
-
scripts,
|
|
12453
|
-
configs: extractConfigs(root, dependencies, devDependencies, scripts),
|
|
12454
12650
|
skills: surface.skills,
|
|
12455
12651
|
agents: surface.agents,
|
|
12456
12652
|
hooks: surface.hooks,
|
|
@@ -12458,6 +12654,7 @@ function extractFacts(root, config, opts) {
|
|
|
12458
12654
|
policyFiles: surface.policyFiles,
|
|
12459
12655
|
lockedSkills: surface.lockedSkills,
|
|
12460
12656
|
hasSkillsLock: surface.hasSkillsLock,
|
|
12657
|
+
skillsLockInvalid: surface.skillsLockInvalid,
|
|
12461
12658
|
configErrors: [...packageErrors, ...surface.configErrors]
|
|
12462
12659
|
};
|
|
12463
12660
|
}
|
|
@@ -12487,7 +12684,7 @@ function compareAction(a, b) {
|
|
|
12487
12684
|
|
|
12488
12685
|
// src/analyze.ts
|
|
12489
12686
|
function analyze(options = {}) {
|
|
12490
|
-
const requested =
|
|
12687
|
+
const requested = resolve4(options.dir ?? process.cwd());
|
|
12491
12688
|
const root = resolveRoot(requested);
|
|
12492
12689
|
const loaded = loadConfig(root, options.configPath);
|
|
12493
12690
|
const config = {
|
|
@@ -12508,7 +12705,7 @@ function analyze(options = {}) {
|
|
|
12508
12705
|
agents: config.thresholds.agents,
|
|
12509
12706
|
mcp: config.thresholds.mcp
|
|
12510
12707
|
}
|
|
12511
|
-
}).filter((f) => !ignoredRules.has(f.ruleId) && !(f.subject.startsWith("skill:") && ignoredSkills.has(f.subject.slice("skill:".length))));
|
|
12708
|
+
}).filter((f) => !ignoredRules.has(f.ruleId) && !(f.subject.startsWith("skill:") && ignoredSkills.has(f.subject.slice("skill:".length).split("@", 1)[0] ?? "")));
|
|
12512
12709
|
const ignoredFindings = new Set(config.ignoreFindings);
|
|
12513
12710
|
const findings = sortFindings(structural.filter((f) => !ignoredFindings.has(f.id)));
|
|
12514
12711
|
return {
|
|
@@ -12741,16 +12938,13 @@ function shouldColour(args) {
|
|
|
12741
12938
|
}
|
|
12742
12939
|
|
|
12743
12940
|
// src/report/text.ts
|
|
12744
|
-
var
|
|
12745
|
-
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
refresh: "REFRESH",
|
|
12749
|
-
warn: "WARN",
|
|
12750
|
-
drift: "DRIFT"
|
|
12941
|
+
var SEVERITY_LABEL = {
|
|
12942
|
+
error: "ERROR",
|
|
12943
|
+
warning: "WARN",
|
|
12944
|
+
info: "INFO"
|
|
12751
12945
|
};
|
|
12752
|
-
function
|
|
12753
|
-
return
|
|
12946
|
+
function severityColumn(severity) {
|
|
12947
|
+
return SEVERITY_LABEL[severity].padEnd(7, " ");
|
|
12754
12948
|
}
|
|
12755
12949
|
function renderText(args) {
|
|
12756
12950
|
const { version, facts, verbose, quiet } = args;
|
|
@@ -12830,21 +13024,19 @@ function groupByRule(findings) {
|
|
|
12830
13024
|
function shortPath(value, root) {
|
|
12831
13025
|
return value.split(`${root}/`).join("");
|
|
12832
13026
|
}
|
|
12833
|
-
var
|
|
12834
|
-
|
|
12835
|
-
|
|
12836
|
-
|
|
12837
|
-
add: "green",
|
|
12838
|
-
refresh: "green"
|
|
13027
|
+
var SEVERITY_TONE = {
|
|
13028
|
+
error: "red",
|
|
13029
|
+
warning: "yellow",
|
|
13030
|
+
info: undefined
|
|
12839
13031
|
};
|
|
12840
13032
|
function formatGroup(group, root, ink) {
|
|
12841
13033
|
const first = group[0];
|
|
12842
13034
|
const count = group.length;
|
|
12843
13035
|
const out = [];
|
|
12844
|
-
const tone =
|
|
12845
|
-
const label =
|
|
13036
|
+
const tone = SEVERITY_TONE[first.severity];
|
|
13037
|
+
const label = severityColumn(first.severity);
|
|
12846
13038
|
out.push(`${tone === undefined ? ink.dim(label) : ink.tone(tone, label)} ${ink.dim(`rule:${safe(first.ruleId)}`)}${count > 1 ? ink.bold(` ×${count}`) : ""}`);
|
|
12847
|
-
out.push(` ${safe(count === 1 ? first.message :
|
|
13039
|
+
out.push(` ${safe(count === 1 ? first.message : groupHeadline(group))}`);
|
|
12848
13040
|
for (const f of group) {
|
|
12849
13041
|
const where = f.evidence.filter((e) => e.kind !== "count" && e.kind !== "threshold").map((e) => shortPath(e.value, root));
|
|
12850
13042
|
const location = where.length > 0 ? where.join(" · ") : f.subject;
|
|
@@ -12852,40 +13044,55 @@ function formatGroup(group, root, ink) {
|
|
|
12852
13044
|
}
|
|
12853
13045
|
return out;
|
|
12854
13046
|
}
|
|
12855
|
-
function
|
|
12856
|
-
const
|
|
12857
|
-
|
|
13047
|
+
function groupHeadline(group) {
|
|
13048
|
+
const stripped = group.map((f) => {
|
|
13049
|
+
const cut = f.message.indexOf(": ");
|
|
13050
|
+
return cut === -1 ? f.message : f.message.slice(0, cut);
|
|
13051
|
+
});
|
|
13052
|
+
if (new Set(stripped).size === 1) {
|
|
13053
|
+
return stripped[0];
|
|
13054
|
+
}
|
|
13055
|
+
const deEvented = stripped.map((s) => s.replace(/^[A-Za-z][A-Za-z0-9]* hook /, "Hook "));
|
|
13056
|
+
if (new Set(deEvented).size === 1) {
|
|
13057
|
+
return deEvented[0];
|
|
13058
|
+
}
|
|
13059
|
+
return `${group.length} findings`;
|
|
12858
13060
|
}
|
|
12859
13061
|
function countsLine(findings, verbose) {
|
|
12860
|
-
const parts =
|
|
13062
|
+
const parts = severityParts(findings, verbose);
|
|
12861
13063
|
return parts.length === 0 ? "no findings" : parts.join(" · ");
|
|
12862
13064
|
}
|
|
12863
|
-
function
|
|
13065
|
+
function severityParts(findings, verbose) {
|
|
12864
13066
|
const counts = {
|
|
12865
|
-
|
|
12866
|
-
|
|
12867
|
-
|
|
12868
|
-
refresh: 0,
|
|
12869
|
-
warn: 0,
|
|
12870
|
-
drift: 0
|
|
13067
|
+
error: 0,
|
|
13068
|
+
warning: 0,
|
|
13069
|
+
info: 0
|
|
12871
13070
|
};
|
|
12872
13071
|
let infoHidden = 0;
|
|
12873
13072
|
for (const f of findings) {
|
|
13073
|
+
if (!verbose && f.action === "keep") {
|
|
13074
|
+
continue;
|
|
13075
|
+
}
|
|
12874
13076
|
if (!verbose && f.severity === "info") {
|
|
12875
13077
|
infoHidden += 1;
|
|
12876
13078
|
continue;
|
|
12877
13079
|
}
|
|
12878
|
-
counts[f.
|
|
13080
|
+
counts[f.severity] += 1;
|
|
12879
13081
|
}
|
|
12880
|
-
const order = ["
|
|
12881
|
-
const
|
|
13082
|
+
const order = ["error", "warning", "info"];
|
|
13083
|
+
const labels = {
|
|
13084
|
+
error: "error",
|
|
13085
|
+
warning: "warning",
|
|
13086
|
+
info: "info"
|
|
13087
|
+
};
|
|
13088
|
+
const parts = order.filter((severity) => counts[severity] > 0).map((severity) => `${counts[severity]} ${labels[severity]}`);
|
|
12882
13089
|
if (!verbose && infoHidden > 0) {
|
|
12883
13090
|
parts.push(`${infoHidden} info hidden (--verbose)`);
|
|
12884
13091
|
}
|
|
12885
13092
|
return parts;
|
|
12886
13093
|
}
|
|
12887
13094
|
function formatSummary(findings, verbose, ink) {
|
|
12888
|
-
const parts =
|
|
13095
|
+
const parts = severityParts(findings, verbose);
|
|
12889
13096
|
const points = score(findings);
|
|
12890
13097
|
const scored = `score ${ink.tone(scoreTone(points), `${points}/100 ${scoreLabel(points)}`)}`;
|
|
12891
13098
|
if (parts.length === 0) {
|
|
@@ -12895,7 +13102,7 @@ function formatSummary(findings, verbose, ink) {
|
|
|
12895
13102
|
}
|
|
12896
13103
|
|
|
12897
13104
|
// src/version.ts
|
|
12898
|
-
var VERSION = "0.
|
|
13105
|
+
var VERSION = "0.5.0";
|
|
12899
13106
|
|
|
12900
13107
|
// src/commands/check.ts
|
|
12901
13108
|
async function runCheck(options) {
|
|
@@ -12934,6 +13141,54 @@ async function runCheck(options) {
|
|
|
12934
13141
|
};
|
|
12935
13142
|
}
|
|
12936
13143
|
|
|
13144
|
+
// src/commands/demo.ts
|
|
13145
|
+
import {
|
|
13146
|
+
mkdirSync,
|
|
13147
|
+
mkdtempSync,
|
|
13148
|
+
rmSync,
|
|
13149
|
+
writeFileSync
|
|
13150
|
+
} from "node:fs";
|
|
13151
|
+
import { tmpdir } from "node:os";
|
|
13152
|
+
import { join as join10 } from "node:path";
|
|
13153
|
+
async function runDemo() {
|
|
13154
|
+
const root = mkdtempSync(join10(tmpdir(), "agentscan-demo-"));
|
|
13155
|
+
try {
|
|
13156
|
+
const claude = join10(root, ".claude");
|
|
13157
|
+
mkdirSync(claude, { recursive: true });
|
|
13158
|
+
writeFileSync(join10(claude, "settings.json"), `${JSON.stringify({
|
|
13159
|
+
hooks: {
|
|
13160
|
+
PreToolUse: [
|
|
13161
|
+
{
|
|
13162
|
+
hooks: [
|
|
13163
|
+
{
|
|
13164
|
+
type: "command",
|
|
13165
|
+
command: ".claude/hooks/guard-destructive-bash.js"
|
|
13166
|
+
}
|
|
13167
|
+
]
|
|
13168
|
+
}
|
|
13169
|
+
]
|
|
13170
|
+
}
|
|
13171
|
+
}, null, 2)}
|
|
13172
|
+
`, "utf8");
|
|
13173
|
+
const result = await runCheck({
|
|
13174
|
+
dir: root,
|
|
13175
|
+
failOn: "never",
|
|
13176
|
+
colour: false
|
|
13177
|
+
});
|
|
13178
|
+
const intro = `Demo fixture: PreToolUse hook points at a script that is not on disk.
|
|
13179
|
+
` + `This is the failure agentscan exists for — the agent starts normally; the guard does not.
|
|
13180
|
+
|
|
13181
|
+
`;
|
|
13182
|
+
return {
|
|
13183
|
+
exitCode: 0,
|
|
13184
|
+
stdout: intro + result.stdout,
|
|
13185
|
+
stderr: ""
|
|
13186
|
+
};
|
|
13187
|
+
} finally {
|
|
13188
|
+
rmSync(root, { recursive: true, force: true });
|
|
13189
|
+
}
|
|
13190
|
+
}
|
|
13191
|
+
|
|
12937
13192
|
// src/commands/explain.ts
|
|
12938
13193
|
async function runExplain(findingId, options = {}) {
|
|
12939
13194
|
const { findings } = analyze(options);
|
|
@@ -12974,12 +13229,12 @@ function formatExplain(f) {
|
|
|
12974
13229
|
}
|
|
12975
13230
|
|
|
12976
13231
|
// src/commands/init.ts
|
|
12977
|
-
import { existsSync as
|
|
12978
|
-
import { join as
|
|
13232
|
+
import { existsSync as existsSync9, writeFileSync as writeFileSync2 } from "node:fs";
|
|
13233
|
+
import { join as join11, resolve as resolve5 } from "node:path";
|
|
12979
13234
|
async function runInit(dir, options = {}) {
|
|
12980
|
-
const root =
|
|
12981
|
-
const path =
|
|
12982
|
-
if (
|
|
13235
|
+
const root = resolve5(dir ?? process.cwd());
|
|
13236
|
+
const path = join11(root, ".agentscanrc.json");
|
|
13237
|
+
if (existsSync9(path) && !options.force) {
|
|
12983
13238
|
return {
|
|
12984
13239
|
exitCode: 2,
|
|
12985
13240
|
stdout: "",
|
|
@@ -12989,7 +13244,7 @@ async function runInit(dir, options = {}) {
|
|
|
12989
13244
|
}
|
|
12990
13245
|
const body = `${JSON.stringify(defaultConfig, null, 2)}
|
|
12991
13246
|
`;
|
|
12992
|
-
|
|
13247
|
+
writeFileSync2(path, body, "utf8");
|
|
12993
13248
|
return {
|
|
12994
13249
|
exitCode: 0,
|
|
12995
13250
|
stdout: `Wrote ${path}
|
|
@@ -13015,7 +13270,7 @@ async function runRulesCommand(options = {}) {
|
|
|
13015
13270
|
// src/report/clipboard.ts
|
|
13016
13271
|
import { spawn } from "node:child_process";
|
|
13017
13272
|
import { accessSync, constants } from "node:fs";
|
|
13018
|
-
import { delimiter, join as
|
|
13273
|
+
import { delimiter, join as join12 } from "node:path";
|
|
13019
13274
|
var TOOLS = [
|
|
13020
13275
|
["wl-copy"],
|
|
13021
13276
|
["xclip", "-selection", "clipboard"],
|
|
@@ -13024,15 +13279,15 @@ var TOOLS = [
|
|
|
13024
13279
|
["clip.exe"]
|
|
13025
13280
|
];
|
|
13026
13281
|
var TIMEOUT_MS = 3000;
|
|
13027
|
-
function clipboardCandidates(onPath = (name) =>
|
|
13282
|
+
function clipboardCandidates(onPath = (name) => resolve6(name) !== null) {
|
|
13028
13283
|
return TOOLS.filter((t) => onPath(t[0])).map((t) => [...t]);
|
|
13029
13284
|
}
|
|
13030
|
-
function
|
|
13285
|
+
function resolve6(name) {
|
|
13031
13286
|
for (const dir of (process.env.PATH ?? "").split(delimiter)) {
|
|
13032
13287
|
if (dir.length === 0) {
|
|
13033
13288
|
continue;
|
|
13034
13289
|
}
|
|
13035
|
-
const candidate =
|
|
13290
|
+
const candidate = join12(dir, name);
|
|
13036
13291
|
try {
|
|
13037
13292
|
accessSync(candidate, constants.X_OK);
|
|
13038
13293
|
return candidate;
|
|
@@ -13051,7 +13306,7 @@ async function copyToClipboard(text) {
|
|
|
13051
13306
|
const failures = [];
|
|
13052
13307
|
for (const argv of candidates) {
|
|
13053
13308
|
const tool = argv[0];
|
|
13054
|
-
const bin =
|
|
13309
|
+
const bin = resolve6(tool);
|
|
13055
13310
|
if (bin === null) {
|
|
13056
13311
|
continue;
|
|
13057
13312
|
}
|
|
@@ -13087,6 +13342,7 @@ function printHelp() {
|
|
|
13087
13342
|
Usage:
|
|
13088
13343
|
agentscan scan the current directory
|
|
13089
13344
|
agentscan check [dir] [options]
|
|
13345
|
+
agentscan demo one-shot fixture (no project required)
|
|
13090
13346
|
agentscan explain <findingId> [dir]
|
|
13091
13347
|
agentscan rules [dir]
|
|
13092
13348
|
agentscan init [dir] [--force]
|
|
@@ -13252,6 +13508,16 @@ async function main(argv) {
|
|
|
13252
13508
|
}
|
|
13253
13509
|
return result.exitCode;
|
|
13254
13510
|
}
|
|
13511
|
+
case "demo": {
|
|
13512
|
+
const result = await runDemo();
|
|
13513
|
+
if (result.stderr.length > 0) {
|
|
13514
|
+
process.stderr.write(result.stderr);
|
|
13515
|
+
}
|
|
13516
|
+
if (result.stdout.length > 0) {
|
|
13517
|
+
process.stdout.write(result.stdout);
|
|
13518
|
+
}
|
|
13519
|
+
return result.exitCode;
|
|
13520
|
+
}
|
|
13255
13521
|
case "help":
|
|
13256
13522
|
printHelp();
|
|
13257
13523
|
return 0;
|