vet-skills 0.5.2 → 0.7.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.
Files changed (2) hide show
  1. package/dist/index.js +1114 -216
  2. package/package.json +11 -10
package/dist/index.js CHANGED
@@ -111,7 +111,7 @@ var require_visit = __commonJS({
111
111
  "use strict";
112
112
  var identity = require_identity();
113
113
  var BREAK = /* @__PURE__ */ Symbol("break visit");
114
- var SKIP = /* @__PURE__ */ Symbol("skip children");
114
+ var SKIP3 = /* @__PURE__ */ Symbol("skip children");
115
115
  var REMOVE = /* @__PURE__ */ Symbol("remove node");
116
116
  function visit(node, visitor) {
117
117
  const visitor_ = initVisitor(visitor);
@@ -123,7 +123,7 @@ var require_visit = __commonJS({
123
123
  visit_(null, node, visitor_, Object.freeze([]));
124
124
  }
125
125
  visit.BREAK = BREAK;
126
- visit.SKIP = SKIP;
126
+ visit.SKIP = SKIP3;
127
127
  visit.REMOVE = REMOVE;
128
128
  function visit_(key, node, visitor, path) {
129
129
  const ctrl = callVisitor(key, node, visitor, path);
@@ -171,7 +171,7 @@ var require_visit = __commonJS({
171
171
  await visitAsync_(null, node, visitor_, Object.freeze([]));
172
172
  }
173
173
  visitAsync.BREAK = BREAK;
174
- visitAsync.SKIP = SKIP;
174
+ visitAsync.SKIP = SKIP3;
175
175
  visitAsync.REMOVE = REMOVE;
176
176
  async function visitAsync_(key, node, visitor, path) {
177
177
  const ctrl = await callVisitor(key, node, visitor, path);
@@ -995,13 +995,13 @@ var require_Collection = __commonJS({
995
995
  var require_stringifyComment = __commonJS({
996
996
  "../../node_modules/.pnpm/yaml@2.9.1/node_modules/yaml/dist/stringify/stringifyComment.js"(exports) {
997
997
  "use strict";
998
- var stringifyComment = (str) => str.replace(/^(?!$)(?: $)?/gm, "#");
998
+ var stringifyComment = (str2) => str2.replace(/^(?!$)(?: $)?/gm, "#");
999
999
  function indentComment(comment, indent) {
1000
1000
  if (/^\n+$/.test(comment))
1001
1001
  return comment.substring(1);
1002
1002
  return indent ? comment.replace(/^(?! *$)/gm, indent) : comment;
1003
1003
  }
1004
- var lineComment = (str, indent, comment) => str.endsWith("\n") ? indentComment(comment, indent) : comment.includes("\n") ? "\n" + indentComment(comment, indent) : (str.endsWith(" ") ? "" : " ") + comment;
1004
+ var lineComment = (str2, indent, comment) => str2.endsWith("\n") ? indentComment(comment, indent) : comment.includes("\n") ? "\n" + indentComment(comment, indent) : (str2.endsWith(" ") ? "" : " ") + comment;
1005
1005
  exports.indentComment = indentComment;
1006
1006
  exports.lineComment = lineComment;
1007
1007
  exports.stringifyComment = stringifyComment;
@@ -1155,16 +1155,16 @@ var require_stringifyString = __commonJS({
1155
1155
  lineWidth: ctx.options.lineWidth,
1156
1156
  minContentWidth: ctx.options.minContentWidth
1157
1157
  });
1158
- var containsDocumentMarker = (str) => /^(%|---|\.\.\.)/m.test(str);
1159
- function lineLengthOverLimit(str, lineWidth, indentLength) {
1158
+ var containsDocumentMarker = (str2) => /^(%|---|\.\.\.)/m.test(str2);
1159
+ function lineLengthOverLimit(str2, lineWidth, indentLength) {
1160
1160
  if (!lineWidth || lineWidth < 0)
1161
1161
  return false;
1162
1162
  const limit = lineWidth - indentLength;
1163
- const strLen = str.length;
1163
+ const strLen = str2.length;
1164
1164
  if (strLen <= limit)
1165
1165
  return false;
1166
1166
  for (let i = 0, start = 0; i < strLen; ++i) {
1167
- if (str[i] === "\n") {
1167
+ if (str2[i] === "\n") {
1168
1168
  if (i - start > limit)
1169
1169
  return true;
1170
1170
  start = i + 1;
@@ -1181,11 +1181,11 @@ var require_stringifyString = __commonJS({
1181
1181
  const { implicitKey } = ctx;
1182
1182
  const minMultiLineLength = ctx.options.doubleQuotedMinMultiLineLength;
1183
1183
  const indent = ctx.indent || (containsDocumentMarker(value) ? " " : "");
1184
- let str = "";
1184
+ let str2 = "";
1185
1185
  let start = 0;
1186
1186
  for (let i = 0, ch = json[i]; ch; ch = json[++i]) {
1187
1187
  if (ch === " " && json[i + 1] === "\\" && json[i + 2] === "n") {
1188
- str += json.slice(start, i) + "\\ ";
1188
+ str2 += json.slice(start, i) + "\\ ";
1189
1189
  i += 1;
1190
1190
  start = i;
1191
1191
  ch = "\\";
@@ -1194,38 +1194,38 @@ var require_stringifyString = __commonJS({
1194
1194
  switch (json[i + 1]) {
1195
1195
  case "u":
1196
1196
  {
1197
- str += json.slice(start, i);
1197
+ str2 += json.slice(start, i);
1198
1198
  const code = json.substr(i + 2, 4);
1199
1199
  switch (code) {
1200
1200
  case "0000":
1201
- str += "\\0";
1201
+ str2 += "\\0";
1202
1202
  break;
1203
1203
  case "0007":
1204
- str += "\\a";
1204
+ str2 += "\\a";
1205
1205
  break;
1206
1206
  case "000b":
1207
- str += "\\v";
1207
+ str2 += "\\v";
1208
1208
  break;
1209
1209
  case "001b":
1210
- str += "\\e";
1210
+ str2 += "\\e";
1211
1211
  break;
1212
1212
  case "0085":
1213
- str += "\\N";
1213
+ str2 += "\\N";
1214
1214
  break;
1215
1215
  case "00a0":
1216
- str += "\\_";
1216
+ str2 += "\\_";
1217
1217
  break;
1218
1218
  case "2028":
1219
- str += "\\L";
1219
+ str2 += "\\L";
1220
1220
  break;
1221
1221
  case "2029":
1222
- str += "\\P";
1222
+ str2 += "\\P";
1223
1223
  break;
1224
1224
  default:
1225
1225
  if (code.substr(0, 2) === "00")
1226
- str += "\\x" + code.substr(2);
1226
+ str2 += "\\x" + code.substr(2);
1227
1227
  else
1228
- str += json.substr(i, 6);
1228
+ str2 += json.substr(i, 6);
1229
1229
  }
1230
1230
  i += 5;
1231
1231
  start = i + 1;
@@ -1235,14 +1235,14 @@ var require_stringifyString = __commonJS({
1235
1235
  if (implicitKey || json[i + 2] === '"' || json.length < minMultiLineLength) {
1236
1236
  i += 1;
1237
1237
  } else {
1238
- str += json.slice(start, i) + "\n\n";
1238
+ str2 += json.slice(start, i) + "\n\n";
1239
1239
  while (json[i + 2] === "\\" && json[i + 3] === "n" && json[i + 4] !== '"') {
1240
- str += "\n";
1240
+ str2 += "\n";
1241
1241
  i += 2;
1242
1242
  }
1243
- str += indent;
1243
+ str2 += indent;
1244
1244
  if (json[i + 2] === " ")
1245
- str += "\\";
1245
+ str2 += "\\";
1246
1246
  i += 1;
1247
1247
  start = i + 1;
1248
1248
  }
@@ -1251,8 +1251,8 @@ var require_stringifyString = __commonJS({
1251
1251
  i += 1;
1252
1252
  }
1253
1253
  }
1254
- str = start ? str + json.slice(start) : json;
1255
- return implicitKey ? str : foldFlowLines.foldFlowLines(str, indent, foldFlowLines.FOLD_QUOTED, getFoldOptions(ctx, false));
1254
+ str2 = start ? str2 + json.slice(start) : json;
1255
+ return implicitKey ? str2 : foldFlowLines.foldFlowLines(str2, indent, foldFlowLines.FOLD_QUOTED, getFoldOptions(ctx, false));
1256
1256
  }
1257
1257
  function singleQuotedString(value, ctx) {
1258
1258
  if (ctx.options.singleQuote === false || ctx.implicitKey && value.includes("\n") || /[ \t]\n|\n[ \t]/.test(value))
@@ -1380,15 +1380,15 @@ ${indent}${start}${value}${end}`;
1380
1380
  return quotedString(value, ctx);
1381
1381
  }
1382
1382
  }
1383
- const str = value.replace(/\n+/g, `$&
1383
+ const str2 = value.replace(/\n+/g, `$&
1384
1384
  ${indent}`);
1385
1385
  if (actualString) {
1386
- const test = (tag) => tag.default && tag.tag !== "tag:yaml.org,2002:str" && tag.test?.test(str);
1386
+ const test = (tag) => tag.default && tag.tag !== "tag:yaml.org,2002:str" && tag.test?.test(str2);
1387
1387
  const { compat, tags } = ctx.doc.schema;
1388
1388
  if (tags.some(test) || compat?.some(test))
1389
1389
  return quotedString(value, ctx);
1390
1390
  }
1391
- return implicitKey ? str : foldFlowLines.foldFlowLines(str, indent, foldFlowLines.FOLD_FLOW, getFoldOptions(ctx, false));
1391
+ return implicitKey ? str2 : foldFlowLines.foldFlowLines(str2, indent, foldFlowLines.FOLD_FLOW, getFoldOptions(ctx, false));
1392
1392
  }
1393
1393
  function stringifyString(item, ctx, onComment, onChompKeep) {
1394
1394
  const { implicitKey, inFlow } = ctx;
@@ -1540,11 +1540,11 @@ var require_stringify = __commonJS({
1540
1540
  const props = stringifyProps(node, tagObj, ctx);
1541
1541
  if (props.length > 0)
1542
1542
  ctx.indentAtStart = (ctx.indentAtStart ?? 0) + props.length + 1;
1543
- const str = typeof tagObj.stringify === "function" ? tagObj.stringify(node, ctx, onComment, onChompKeep) : identity.isScalar(node) ? stringifyString.stringifyString(node, ctx, onComment, onChompKeep) : node.toString(ctx, onComment, onChompKeep);
1543
+ const str2 = typeof tagObj.stringify === "function" ? tagObj.stringify(node, ctx, onComment, onChompKeep) : identity.isScalar(node) ? stringifyString.stringifyString(node, ctx, onComment, onChompKeep) : node.toString(ctx, onComment, onChompKeep);
1544
1544
  if (!props)
1545
- return str;
1546
- return identity.isScalar(node) || str[0] === "{" || str[0] === "[" ? `${props} ${str}` : `${props}
1547
- ${ctx.indent}${str}`;
1545
+ return str2;
1546
+ return identity.isScalar(node) || str2[0] === "{" || str2[0] === "[" ? `${props} ${str2}` : `${props}
1547
+ ${ctx.indent}${str2}`;
1548
1548
  }
1549
1549
  exports.createStringifyContext = createStringifyContext;
1550
1550
  exports.stringify = stringify;
@@ -1579,8 +1579,8 @@ var require_stringifyPair = __commonJS({
1579
1579
  });
1580
1580
  let keyCommentDone = false;
1581
1581
  let chompKeep = false;
1582
- let str = stringify.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
1583
- if (!explicitKey && !ctx.inFlow && str.length > 1024) {
1582
+ let str2 = stringify.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
1583
+ if (!explicitKey && !ctx.inFlow && str2.length > 1024) {
1584
1584
  if (simpleKeys)
1585
1585
  throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
1586
1586
  explicitKey = true;
@@ -1589,27 +1589,27 @@ var require_stringifyPair = __commonJS({
1589
1589
  if (allNullValues || value == null) {
1590
1590
  if (keyCommentDone && onComment)
1591
1591
  onComment();
1592
- return str === "" ? "?" : explicitKey ? `? ${str}` : str;
1592
+ return str2 === "" ? "?" : explicitKey ? `? ${str2}` : str2;
1593
1593
  }
1594
1594
  } else if (allNullValues && !simpleKeys || value == null && explicitKey) {
1595
- str = `? ${str}`;
1595
+ str2 = `? ${str2}`;
1596
1596
  if (keyComment && !keyCommentDone) {
1597
- str += stringifyComment.lineComment(str, ctx.indent, commentString(keyComment));
1597
+ str2 += stringifyComment.lineComment(str2, ctx.indent, commentString(keyComment));
1598
1598
  } else if (chompKeep && onChompKeep)
1599
1599
  onChompKeep();
1600
- return str;
1600
+ return str2;
1601
1601
  }
1602
1602
  if (keyCommentDone)
1603
1603
  keyComment = null;
1604
1604
  if (explicitKey) {
1605
1605
  if (keyComment)
1606
- str += stringifyComment.lineComment(str, ctx.indent, commentString(keyComment));
1607
- str = `? ${str}
1606
+ str2 += stringifyComment.lineComment(str2, ctx.indent, commentString(keyComment));
1607
+ str2 = `? ${str2}
1608
1608
  ${indent}:`;
1609
1609
  } else {
1610
- str = `${str}:`;
1610
+ str2 = `${str2}:`;
1611
1611
  if (keyComment)
1612
- str += stringifyComment.lineComment(str, ctx.indent, commentString(keyComment));
1612
+ str2 += stringifyComment.lineComment(str2, ctx.indent, commentString(keyComment));
1613
1613
  }
1614
1614
  let vsb, vcb, valueComment;
1615
1615
  if (identity.isNode(value)) {
@@ -1625,7 +1625,7 @@ ${indent}:`;
1625
1625
  }
1626
1626
  ctx.implicitKey = false;
1627
1627
  if (!explicitKey && !keyComment && identity.isScalar(value))
1628
- ctx.indentAtStart = str.length + 1;
1628
+ ctx.indentAtStart = str2.length + 1;
1629
1629
  chompKeep = false;
1630
1630
  if (!indentSeq && indentStep.length >= 2 && !ctx.inFlow && !explicitKey && identity.isSeq(value) && !value.flow && !value.tag && !value.anchor) {
1631
1631
  ctx.indent = ctx.indent.substring(2);
@@ -1669,16 +1669,16 @@ ${ctx.indent}`;
1669
1669
  } else if (valueStr === "" || valueStr[0] === "\n") {
1670
1670
  ws = "";
1671
1671
  }
1672
- str += ws + valueStr;
1672
+ str2 += ws + valueStr;
1673
1673
  if (ctx.inFlow) {
1674
1674
  if (valueCommentDone && onComment)
1675
1675
  onComment();
1676
1676
  } else if (valueComment && !valueCommentDone) {
1677
- str += stringifyComment.lineComment(str, ctx.indent, commentString(valueComment));
1677
+ str2 += stringifyComment.lineComment(str2, ctx.indent, commentString(valueComment));
1678
1678
  } else if (chompKeep && onChompKeep) {
1679
1679
  onChompKeep();
1680
1680
  }
1681
- return str;
1681
+ return str2;
1682
1682
  }
1683
1683
  exports.stringifyPair = stringifyPair;
1684
1684
  }
@@ -1905,31 +1905,31 @@ var require_stringifyCollection = __commonJS({
1905
1905
  }
1906
1906
  }
1907
1907
  chompKeep = false;
1908
- let str2 = stringify.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
1908
+ let str3 = stringify.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
1909
1909
  if (comment2)
1910
- str2 += stringifyComment.lineComment(str2, itemIndent, commentString(comment2));
1910
+ str3 += stringifyComment.lineComment(str3, itemIndent, commentString(comment2));
1911
1911
  if (chompKeep && comment2)
1912
1912
  chompKeep = false;
1913
- lines.push(blockItemPrefix + str2);
1913
+ lines.push(blockItemPrefix + str3);
1914
1914
  }
1915
- let str;
1915
+ let str2;
1916
1916
  if (lines.length === 0) {
1917
- str = flowChars.start + flowChars.end;
1917
+ str2 = flowChars.start + flowChars.end;
1918
1918
  } else {
1919
- str = lines[0];
1919
+ str2 = lines[0];
1920
1920
  for (let i = 1; i < lines.length; ++i) {
1921
1921
  const line = lines[i];
1922
- str += line ? `
1922
+ str2 += line ? `
1923
1923
  ${indent}${line}` : "\n";
1924
1924
  }
1925
1925
  }
1926
1926
  if (comment) {
1927
- str += "\n" + stringifyComment.indentComment(commentString(comment), indent);
1927
+ str2 += "\n" + stringifyComment.indentComment(commentString(comment), indent);
1928
1928
  if (onComment)
1929
1929
  onComment();
1930
1930
  } else if (chompKeep && onChompKeep)
1931
1931
  onChompKeep();
1932
- return str;
1932
+ return str2;
1933
1933
  }
1934
1934
  function stringifyFlowCollection({ items }, ctx, { flowChars, itemIndent }) {
1935
1935
  const { indent, indentStep, flowCollectionPadding: fcPadding, options: { commentString } } = ctx;
@@ -1972,21 +1972,21 @@ ${indent}${line}` : "\n";
1972
1972
  }
1973
1973
  if (comment)
1974
1974
  reqNewline = true;
1975
- let str = stringify.stringify(item, itemCtx, () => comment = null);
1976
- reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
1975
+ let str2 = stringify.stringify(item, itemCtx, () => comment = null);
1976
+ reqNewline || (reqNewline = lines.length > linesAtValue || str2.includes("\n"));
1977
1977
  if (i < items.length - 1) {
1978
- str += ",";
1978
+ str2 += ",";
1979
1979
  } else if (ctx.options.trailingComma) {
1980
1980
  if (ctx.options.lineWidth > 0) {
1981
- reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str.length + 2) > ctx.options.lineWidth);
1981
+ reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str2.length + 2) > ctx.options.lineWidth);
1982
1982
  }
1983
1983
  if (reqNewline) {
1984
- str += ",";
1984
+ str2 += ",";
1985
1985
  }
1986
1986
  }
1987
1987
  if (comment)
1988
- str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
1989
- lines.push(str);
1988
+ str2 += stringifyComment.lineComment(str2, itemIndent, commentString(comment));
1989
+ lines.push(str2);
1990
1990
  linesAtValue = lines.length;
1991
1991
  }
1992
1992
  const { start, end } = flowChars;
@@ -1998,11 +1998,11 @@ ${indent}${line}` : "\n";
1998
1998
  reqNewline = ctx.options.lineWidth > 0 && len > ctx.options.lineWidth;
1999
1999
  }
2000
2000
  if (reqNewline) {
2001
- let str = start;
2001
+ let str2 = start;
2002
2002
  for (const line of lines)
2003
- str += line ? `
2003
+ str2 += line ? `
2004
2004
  ${indentStep}${indent}${line}` : "\n";
2005
- return `${str}
2005
+ return `${str2}
2006
2006
  ${indent}${end}`;
2007
2007
  } else {
2008
2008
  return `${start}${fcPadding}${lines.join(" ")}${fcPadding}${end}`;
@@ -2334,7 +2334,7 @@ var require_string = __commonJS({
2334
2334
  identify: (value) => typeof value === "string",
2335
2335
  default: true,
2336
2336
  tag: "tag:yaml.org,2002:str",
2337
- resolve: (str) => str,
2337
+ resolve: (str2) => str2,
2338
2338
  stringify(item, ctx, onComment, onChompKeep) {
2339
2339
  ctx = Object.assign({ actualString: true }, ctx);
2340
2340
  return stringifyString.stringifyString(item, ctx, onComment, onChompKeep);
@@ -2372,7 +2372,7 @@ var require_bool = __commonJS({
2372
2372
  default: true,
2373
2373
  tag: "tag:yaml.org,2002:bool",
2374
2374
  test: /^(?:[Tt]rue|TRUE|[Ff]alse|FALSE)$/,
2375
- resolve: (str) => new Scalar.Scalar(str[0] === "t" || str[0] === "T"),
2375
+ resolve: (str2) => new Scalar.Scalar(str2[0] === "t" || str2[0] === "T"),
2376
2376
  stringify({ source, value }, ctx) {
2377
2377
  if (source && boolTag.test.test(source)) {
2378
2378
  const sv = source[0] === "t" || source[0] === "T";
@@ -2424,7 +2424,7 @@ var require_float = __commonJS({
2424
2424
  default: true,
2425
2425
  tag: "tag:yaml.org,2002:float",
2426
2426
  test: /^(?:[-+]?\.(?:inf|Inf|INF)|\.nan|\.NaN|\.NAN)$/,
2427
- resolve: (str) => str.slice(-3).toLowerCase() === "nan" ? NaN : str[0] === "-" ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
2427
+ resolve: (str2) => str2.slice(-3).toLowerCase() === "nan" ? NaN : str2[0] === "-" ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
2428
2428
  stringify: stringifyNumber.stringifyNumber
2429
2429
  };
2430
2430
  var floatExp = {
@@ -2433,7 +2433,7 @@ var require_float = __commonJS({
2433
2433
  tag: "tag:yaml.org,2002:float",
2434
2434
  format: "EXP",
2435
2435
  test: /^[-+]?(?:\.[0-9]+|[0-9]+(?:\.[0-9]*)?)[eE][-+]?[0-9]+$/,
2436
- resolve: (str) => parseFloat(str),
2436
+ resolve: (str2) => parseFloat(str2),
2437
2437
  stringify(node) {
2438
2438
  const num = Number(node.value);
2439
2439
  return isFinite(num) ? num.toExponential() : stringifyNumber.stringifyNumber(node);
@@ -2444,11 +2444,11 @@ var require_float = __commonJS({
2444
2444
  default: true,
2445
2445
  tag: "tag:yaml.org,2002:float",
2446
2446
  test: /^[-+]?(?:\.[0-9]+|[0-9]+\.[0-9]*)$/,
2447
- resolve(str) {
2448
- const node = new Scalar.Scalar(parseFloat(str));
2449
- const dot = str.indexOf(".");
2450
- if (dot !== -1 && str[str.length - 1] === "0")
2451
- node.minFractionDigits = str.length - dot - 1;
2447
+ resolve(str2) {
2448
+ const node = new Scalar.Scalar(parseFloat(str2));
2449
+ const dot = str2.indexOf(".");
2450
+ if (dot !== -1 && str2[str2.length - 1] === "0")
2451
+ node.minFractionDigits = str2.length - dot - 1;
2452
2452
  return node;
2453
2453
  },
2454
2454
  stringify: stringifyNumber.stringifyNumber
@@ -2465,7 +2465,7 @@ var require_int = __commonJS({
2465
2465
  "use strict";
2466
2466
  var stringifyNumber = require_stringifyNumber();
2467
2467
  var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
2468
- var intResolve = (str, offset, radix, { intAsBigInt }) => intAsBigInt ? BigInt(str) : parseInt(str.substring(offset), radix);
2468
+ var intResolve = (str2, offset, radix, { intAsBigInt }) => intAsBigInt ? BigInt(str2) : parseInt(str2.substring(offset), radix);
2469
2469
  function intStringify(node, radix, prefix) {
2470
2470
  const { value } = node;
2471
2471
  if (intIdentify(value) && value >= 0)
@@ -2478,7 +2478,7 @@ var require_int = __commonJS({
2478
2478
  tag: "tag:yaml.org,2002:int",
2479
2479
  format: "OCT",
2480
2480
  test: /^0o[0-7]+$/,
2481
- resolve: (str, _onError, opt) => intResolve(str, 2, 8, opt),
2481
+ resolve: (str2, _onError, opt) => intResolve(str2, 2, 8, opt),
2482
2482
  stringify: (node) => intStringify(node, 8, "0o")
2483
2483
  };
2484
2484
  var int = {
@@ -2486,7 +2486,7 @@ var require_int = __commonJS({
2486
2486
  default: true,
2487
2487
  tag: "tag:yaml.org,2002:int",
2488
2488
  test: /^[-+]?[0-9]+$/,
2489
- resolve: (str, _onError, opt) => intResolve(str, 0, 10, opt),
2489
+ resolve: (str2, _onError, opt) => intResolve(str2, 0, 10, opt),
2490
2490
  stringify: stringifyNumber.stringifyNumber
2491
2491
  };
2492
2492
  var intHex = {
@@ -2495,7 +2495,7 @@ var require_int = __commonJS({
2495
2495
  tag: "tag:yaml.org,2002:int",
2496
2496
  format: "HEX",
2497
2497
  test: /^0x[0-9a-fA-F]+$/,
2498
- resolve: (str, _onError, opt) => intResolve(str, 2, 16, opt),
2498
+ resolve: (str2, _onError, opt) => intResolve(str2, 2, 16, opt),
2499
2499
  stringify: (node) => intStringify(node, 16, "0x")
2500
2500
  };
2501
2501
  exports.int = int;
@@ -2548,7 +2548,7 @@ var require_schema2 = __commonJS({
2548
2548
  identify: (value) => typeof value === "string",
2549
2549
  default: true,
2550
2550
  tag: "tag:yaml.org,2002:str",
2551
- resolve: (str) => str,
2551
+ resolve: (str2) => str2,
2552
2552
  stringify: stringifyJSON
2553
2553
  },
2554
2554
  {
@@ -2565,7 +2565,7 @@ var require_schema2 = __commonJS({
2565
2565
  default: true,
2566
2566
  tag: "tag:yaml.org,2002:bool",
2567
2567
  test: /^true$|^false$/,
2568
- resolve: (str) => str === "true",
2568
+ resolve: (str2) => str2 === "true",
2569
2569
  stringify: stringifyJSON
2570
2570
  },
2571
2571
  {
@@ -2573,7 +2573,7 @@ var require_schema2 = __commonJS({
2573
2573
  default: true,
2574
2574
  tag: "tag:yaml.org,2002:int",
2575
2575
  test: /^-?(?:0|[1-9][0-9]*)$/,
2576
- resolve: (str, _onError, { intAsBigInt }) => intAsBigInt ? BigInt(str) : parseInt(str, 10),
2576
+ resolve: (str2, _onError, { intAsBigInt }) => intAsBigInt ? BigInt(str2) : parseInt(str2, 10),
2577
2577
  stringify: ({ value }) => intIdentify(value) ? value.toString() : JSON.stringify(value)
2578
2578
  },
2579
2579
  {
@@ -2581,7 +2581,7 @@ var require_schema2 = __commonJS({
2581
2581
  default: true,
2582
2582
  tag: "tag:yaml.org,2002:float",
2583
2583
  test: /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]*)?(?:[eE][-+]?[0-9]+)?$/,
2584
- resolve: (str) => parseFloat(str),
2584
+ resolve: (str2) => parseFloat(str2),
2585
2585
  stringify: stringifyJSON
2586
2586
  }
2587
2587
  ];
@@ -2589,9 +2589,9 @@ var require_schema2 = __commonJS({
2589
2589
  default: true,
2590
2590
  tag: "",
2591
2591
  test: /^/,
2592
- resolve(str, onError) {
2593
- onError(`Unresolved plain scalar ${JSON.stringify(str)}`);
2594
- return str;
2592
+ resolve(str2, onError) {
2593
+ onError(`Unresolved plain scalar ${JSON.stringify(str2)}`);
2594
+ return str2;
2595
2595
  }
2596
2596
  };
2597
2597
  var schema = [map.map, seq.seq].concat(jsonScalars, jsonError);
@@ -2623,10 +2623,10 @@ var require_binary = __commonJS({
2623
2623
  if (typeof node_buffer.Buffer === "function") {
2624
2624
  return node_buffer.Buffer.from(src, "base64");
2625
2625
  } else if (typeof atob === "function") {
2626
- const str = atob(src.replace(/[\n\r]/g, ""));
2627
- const buffer = new Uint8Array(str.length);
2628
- for (let i = 0; i < str.length; ++i)
2629
- buffer[i] = str.charCodeAt(i);
2626
+ const str2 = atob(src.replace(/[\n\r]/g, ""));
2627
+ const buffer = new Uint8Array(str2.length);
2628
+ for (let i = 0; i < str2.length; ++i)
2629
+ buffer[i] = str2.charCodeAt(i);
2630
2630
  return buffer;
2631
2631
  } else {
2632
2632
  onError("This environment does not support reading binary tags; either Buffer or atob is required");
@@ -2637,28 +2637,28 @@ var require_binary = __commonJS({
2637
2637
  if (!value)
2638
2638
  return "";
2639
2639
  const buf = value;
2640
- let str;
2640
+ let str2;
2641
2641
  if (typeof node_buffer.Buffer === "function") {
2642
- str = buf instanceof node_buffer.Buffer ? buf.toString("base64") : node_buffer.Buffer.from(buf.buffer).toString("base64");
2642
+ str2 = buf instanceof node_buffer.Buffer ? buf.toString("base64") : node_buffer.Buffer.from(buf.buffer).toString("base64");
2643
2643
  } else if (typeof btoa === "function") {
2644
2644
  let s = "";
2645
2645
  for (let i = 0; i < buf.length; ++i)
2646
2646
  s += String.fromCharCode(buf[i]);
2647
- str = btoa(s);
2647
+ str2 = btoa(s);
2648
2648
  } else {
2649
2649
  throw new Error("This environment does not support writing binary tags; either Buffer or btoa is required");
2650
2650
  }
2651
2651
  type ?? (type = Scalar.Scalar.BLOCK_LITERAL);
2652
2652
  if (type !== Scalar.Scalar.QUOTE_DOUBLE) {
2653
2653
  const lineWidth = Math.max(ctx.options.lineWidth - ctx.indent.length, ctx.options.minContentWidth);
2654
- const n = Math.ceil(str.length / lineWidth);
2654
+ const n = Math.ceil(str2.length / lineWidth);
2655
2655
  const lines = new Array(n);
2656
2656
  for (let i = 0, o = 0; i < n; ++i, o += lineWidth) {
2657
- lines[i] = str.substr(o, lineWidth);
2657
+ lines[i] = str2.substr(o, lineWidth);
2658
2658
  }
2659
- str = lines.join(type === Scalar.Scalar.BLOCK_LITERAL ? "\n" : " ");
2659
+ str2 = lines.join(type === Scalar.Scalar.BLOCK_LITERAL ? "\n" : " ");
2660
2660
  }
2661
- return stringifyString.stringifyString({ comment, type, value: str }, ctx, onComment, onChompKeep);
2661
+ return stringifyString.stringifyString({ comment, type, value: str2 }, ctx, onComment, onChompKeep);
2662
2662
  }
2663
2663
  };
2664
2664
  exports.binary = binary;
@@ -2864,7 +2864,7 @@ var require_float2 = __commonJS({
2864
2864
  default: true,
2865
2865
  tag: "tag:yaml.org,2002:float",
2866
2866
  test: /^(?:[-+]?\.(?:inf|Inf|INF)|\.nan|\.NaN|\.NAN)$/,
2867
- resolve: (str) => str.slice(-3).toLowerCase() === "nan" ? NaN : str[0] === "-" ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
2867
+ resolve: (str2) => str2.slice(-3).toLowerCase() === "nan" ? NaN : str2[0] === "-" ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
2868
2868
  stringify: stringifyNumber.stringifyNumber
2869
2869
  };
2870
2870
  var floatExp = {
@@ -2873,7 +2873,7 @@ var require_float2 = __commonJS({
2873
2873
  tag: "tag:yaml.org,2002:float",
2874
2874
  format: "EXP",
2875
2875
  test: /^[-+]?(?:[0-9][0-9_]*)?(?:\.[0-9_]*)?[eE][-+]?[0-9]+$/,
2876
- resolve: (str) => parseFloat(str.replace(/_/g, "")),
2876
+ resolve: (str2) => parseFloat(str2.replace(/_/g, "")),
2877
2877
  stringify(node) {
2878
2878
  const num = Number(node.value);
2879
2879
  return isFinite(num) ? num.toExponential() : stringifyNumber.stringifyNumber(node);
@@ -2884,11 +2884,11 @@ var require_float2 = __commonJS({
2884
2884
  default: true,
2885
2885
  tag: "tag:yaml.org,2002:float",
2886
2886
  test: /^[-+]?(?:[0-9][0-9_]*)?\.[0-9_]*$/,
2887
- resolve(str) {
2888
- const node = new Scalar.Scalar(parseFloat(str.replace(/_/g, "")));
2889
- const dot = str.indexOf(".");
2887
+ resolve(str2) {
2888
+ const node = new Scalar.Scalar(parseFloat(str2.replace(/_/g, "")));
2889
+ const dot = str2.indexOf(".");
2890
2890
  if (dot !== -1) {
2891
- const f = str.substring(dot + 1).replace(/_/g, "");
2891
+ const f = str2.substring(dot + 1).replace(/_/g, "");
2892
2892
  if (f[f.length - 1] === "0")
2893
2893
  node.minFractionDigits = f.length;
2894
2894
  }
@@ -2908,34 +2908,34 @@ var require_int2 = __commonJS({
2908
2908
  "use strict";
2909
2909
  var stringifyNumber = require_stringifyNumber();
2910
2910
  var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
2911
- function intResolve(str, offset, radix, { intAsBigInt }) {
2912
- const sign = str[0];
2911
+ function intResolve(str2, offset, radix, { intAsBigInt }) {
2912
+ const sign = str2[0];
2913
2913
  if (sign === "-" || sign === "+")
2914
2914
  offset += 1;
2915
- str = str.substring(offset).replace(/_/g, "");
2915
+ str2 = str2.substring(offset).replace(/_/g, "");
2916
2916
  if (intAsBigInt) {
2917
2917
  switch (radix) {
2918
2918
  case 2:
2919
- str = `0b${str}`;
2919
+ str2 = `0b${str2}`;
2920
2920
  break;
2921
2921
  case 8:
2922
- str = `0o${str}`;
2922
+ str2 = `0o${str2}`;
2923
2923
  break;
2924
2924
  case 16:
2925
- str = `0x${str}`;
2925
+ str2 = `0x${str2}`;
2926
2926
  break;
2927
2927
  }
2928
- const n2 = BigInt(str);
2928
+ const n2 = BigInt(str2);
2929
2929
  return sign === "-" ? BigInt(-1) * n2 : n2;
2930
2930
  }
2931
- const n = parseInt(str, radix);
2931
+ const n = parseInt(str2, radix);
2932
2932
  return sign === "-" ? -1 * n : n;
2933
2933
  }
2934
2934
  function intStringify(node, radix, prefix) {
2935
2935
  const { value } = node;
2936
2936
  if (intIdentify(value)) {
2937
- const str = value.toString(radix);
2938
- return value < 0 ? "-" + prefix + str.substr(1) : prefix + str;
2937
+ const str2 = value.toString(radix);
2938
+ return value < 0 ? "-" + prefix + str2.substr(1) : prefix + str2;
2939
2939
  }
2940
2940
  return stringifyNumber.stringifyNumber(node);
2941
2941
  }
@@ -2945,7 +2945,7 @@ var require_int2 = __commonJS({
2945
2945
  tag: "tag:yaml.org,2002:int",
2946
2946
  format: "BIN",
2947
2947
  test: /^[-+]?0b[0-1_]+$/,
2948
- resolve: (str, _onError, opt) => intResolve(str, 2, 2, opt),
2948
+ resolve: (str2, _onError, opt) => intResolve(str2, 2, 2, opt),
2949
2949
  stringify: (node) => intStringify(node, 2, "0b")
2950
2950
  };
2951
2951
  var intOct = {
@@ -2954,7 +2954,7 @@ var require_int2 = __commonJS({
2954
2954
  tag: "tag:yaml.org,2002:int",
2955
2955
  format: "OCT",
2956
2956
  test: /^[-+]?0[0-7_]+$/,
2957
- resolve: (str, _onError, opt) => intResolve(str, 1, 8, opt),
2957
+ resolve: (str2, _onError, opt) => intResolve(str2, 1, 8, opt),
2958
2958
  stringify: (node) => intStringify(node, 8, "0")
2959
2959
  };
2960
2960
  var int = {
@@ -2962,7 +2962,7 @@ var require_int2 = __commonJS({
2962
2962
  default: true,
2963
2963
  tag: "tag:yaml.org,2002:int",
2964
2964
  test: /^[-+]?[0-9][0-9_]*$/,
2965
- resolve: (str, _onError, opt) => intResolve(str, 0, 10, opt),
2965
+ resolve: (str2, _onError, opt) => intResolve(str2, 0, 10, opt),
2966
2966
  stringify: stringifyNumber.stringifyNumber
2967
2967
  };
2968
2968
  var intHex = {
@@ -2971,7 +2971,7 @@ var require_int2 = __commonJS({
2971
2971
  tag: "tag:yaml.org,2002:int",
2972
2972
  format: "HEX",
2973
2973
  test: /^[-+]?0x[0-9a-fA-F_]+$/,
2974
- resolve: (str, _onError, opt) => intResolve(str, 2, 16, opt),
2974
+ resolve: (str2, _onError, opt) => intResolve(str2, 2, 16, opt),
2975
2975
  stringify: (node) => intStringify(node, 16, "0x")
2976
2976
  };
2977
2977
  exports.int = int;
@@ -3075,9 +3075,9 @@ var require_timestamp = __commonJS({
3075
3075
  "../../node_modules/.pnpm/yaml@2.9.1/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js"(exports) {
3076
3076
  "use strict";
3077
3077
  var stringifyNumber = require_stringifyNumber();
3078
- function parseSexagesimal(str, asBigInt) {
3079
- const sign = str[0];
3080
- const parts = sign === "-" || sign === "+" ? str.substring(1) : str;
3078
+ function parseSexagesimal(str2, asBigInt) {
3079
+ const sign = str2[0];
3080
+ const parts = sign === "-" || sign === "+" ? str2.substring(1) : str2;
3081
3081
  const num = (n) => asBigInt ? BigInt(n) : Number(n);
3082
3082
  const res = parts.replace(/_/g, "").split(":").reduce((res2, p) => res2 * num(60) + num(p), num(0));
3083
3083
  return sign === "-" ? num(-1) * res : res;
@@ -3114,7 +3114,7 @@ var require_timestamp = __commonJS({
3114
3114
  tag: "tag:yaml.org,2002:int",
3115
3115
  format: "TIME",
3116
3116
  test: /^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+$/,
3117
- resolve: (str, _onError, { intAsBigInt }) => parseSexagesimal(str, intAsBigInt),
3117
+ resolve: (str2, _onError, { intAsBigInt }) => parseSexagesimal(str2, intAsBigInt),
3118
3118
  stringify: stringifySexagesimal
3119
3119
  };
3120
3120
  var floatTime = {
@@ -3123,7 +3123,7 @@ var require_timestamp = __commonJS({
3123
3123
  tag: "tag:yaml.org,2002:float",
3124
3124
  format: "TIME",
3125
3125
  test: /^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*$/,
3126
- resolve: (str) => parseSexagesimal(str, false),
3126
+ resolve: (str2) => parseSexagesimal(str2, false),
3127
3127
  stringify: stringifySexagesimal
3128
3128
  };
3129
3129
  var timestamp = {
@@ -3134,8 +3134,8 @@ var require_timestamp = __commonJS({
3134
3134
  // may be omitted altogether, resulting in a date format. In such a case, the time part is
3135
3135
  // assumed to be 00:00:00Z (start of day, UTC).
3136
3136
  test: RegExp("^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})(?:(?:t|T|[ \\t]+)([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}(\\.[0-9]+)?)(?:[ \\t]*(Z|[-+][012]?[0-9](?::[0-9]{2})?))?)?$"),
3137
- resolve(str) {
3138
- const match = str.match(timestamp.test);
3137
+ resolve(str2) {
3138
+ const match = str2.match(timestamp.test);
3139
3139
  if (!match)
3140
3140
  throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");
3141
3141
  const [, year, month, day, hour, minute, second] = match.map(Number);
@@ -4011,10 +4011,10 @@ var require_resolve_block_map = __commonJS({
4011
4011
  let offset = bm.offset;
4012
4012
  let commentEnd = null;
4013
4013
  for (const collItem of bm.items) {
4014
- const { start, key, sep, value } = collItem;
4014
+ const { start, key, sep: sep2, value } = collItem;
4015
4015
  const keyProps = resolveProps.resolveProps(start, {
4016
4016
  indicator: "explicit-key-ind",
4017
- next: key ?? sep?.[0],
4017
+ next: key ?? sep2?.[0],
4018
4018
  offset,
4019
4019
  onError,
4020
4020
  parentIndent: bm.indent,
@@ -4028,7 +4028,7 @@ var require_resolve_block_map = __commonJS({
4028
4028
  else if ("indent" in key && key.indent !== bm.indent)
4029
4029
  onError(offset, "BAD_INDENT", startColMsg);
4030
4030
  }
4031
- if (!keyProps.anchor && !keyProps.tag && !sep) {
4031
+ if (!keyProps.anchor && !keyProps.tag && !sep2) {
4032
4032
  commentEnd = keyProps.end;
4033
4033
  if (keyProps.comment) {
4034
4034
  if (map.comment)
@@ -4052,7 +4052,7 @@ var require_resolve_block_map = __commonJS({
4052
4052
  ctx.atKey = false;
4053
4053
  if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
4054
4054
  onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
4055
- const valueProps = resolveProps.resolveProps(sep ?? [], {
4055
+ const valueProps = resolveProps.resolveProps(sep2 ?? [], {
4056
4056
  indicator: "map-value-ind",
4057
4057
  next: value,
4058
4058
  offset: keyNode.range[2],
@@ -4068,7 +4068,7 @@ var require_resolve_block_map = __commonJS({
4068
4068
  if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
4069
4069
  onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
4070
4070
  }
4071
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep, null, valueProps, onError);
4071
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep2, null, valueProps, onError);
4072
4072
  if (ctx.schema.compat)
4073
4073
  utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
4074
4074
  offset = valueNode.range[2];
@@ -4159,7 +4159,7 @@ var require_resolve_end = __commonJS({
4159
4159
  let comment = "";
4160
4160
  if (end) {
4161
4161
  let hasSpace = false;
4162
- let sep = "";
4162
+ let sep2 = "";
4163
4163
  for (const token of end) {
4164
4164
  const { source, type } = token;
4165
4165
  switch (type) {
@@ -4173,13 +4173,13 @@ var require_resolve_end = __commonJS({
4173
4173
  if (!comment)
4174
4174
  comment = cb;
4175
4175
  else
4176
- comment += sep + cb;
4177
- sep = "";
4176
+ comment += sep2 + cb;
4177
+ sep2 = "";
4178
4178
  break;
4179
4179
  }
4180
4180
  case "newline":
4181
4181
  if (comment)
4182
- sep += source;
4182
+ sep2 += source;
4183
4183
  hasSpace = true;
4184
4184
  break;
4185
4185
  default:
@@ -4222,18 +4222,18 @@ var require_resolve_flow_collection = __commonJS({
4222
4222
  let offset = fc.offset + fc.start.source.length;
4223
4223
  for (let i = 0; i < fc.items.length; ++i) {
4224
4224
  const collItem = fc.items[i];
4225
- const { start, key, sep, value } = collItem;
4225
+ const { start, key, sep: sep2, value } = collItem;
4226
4226
  const props = resolveProps.resolveProps(start, {
4227
4227
  flow: fcName,
4228
4228
  indicator: "explicit-key-ind",
4229
- next: key ?? sep?.[0],
4229
+ next: key ?? sep2?.[0],
4230
4230
  offset,
4231
4231
  onError,
4232
4232
  parentIndent: fc.indent,
4233
4233
  startOnNewline: false
4234
4234
  });
4235
4235
  if (!props.found) {
4236
- if (!props.anchor && !props.tag && !sep && !value) {
4236
+ if (!props.anchor && !props.tag && !sep2 && !value) {
4237
4237
  if (i === 0 && props.comma)
4238
4238
  onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
4239
4239
  else if (i < fc.items.length - 1)
@@ -4287,8 +4287,8 @@ var require_resolve_flow_collection = __commonJS({
4287
4287
  }
4288
4288
  }
4289
4289
  }
4290
- if (!isMap && !sep && !props.found) {
4291
- const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep, null, props, onError);
4290
+ if (!isMap && !sep2 && !props.found) {
4291
+ const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep2, null, props, onError);
4292
4292
  coll.items.push(valueNode);
4293
4293
  offset = valueNode.range[2];
4294
4294
  if (isBlock(value))
@@ -4300,7 +4300,7 @@ var require_resolve_flow_collection = __commonJS({
4300
4300
  if (isBlock(key))
4301
4301
  onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
4302
4302
  ctx.atKey = false;
4303
- const valueProps = resolveProps.resolveProps(sep ?? [], {
4303
+ const valueProps = resolveProps.resolveProps(sep2 ?? [], {
4304
4304
  flow: fcName,
4305
4305
  indicator: "map-value-ind",
4306
4306
  next: value,
@@ -4311,8 +4311,8 @@ var require_resolve_flow_collection = __commonJS({
4311
4311
  });
4312
4312
  if (valueProps.found) {
4313
4313
  if (!isMap && !props.found && ctx.options.strict) {
4314
- if (sep)
4315
- for (const st of sep) {
4314
+ if (sep2)
4315
+ for (const st of sep2) {
4316
4316
  if (st === valueProps.found)
4317
4317
  break;
4318
4318
  if (st.type === "newline") {
@@ -4329,7 +4329,7 @@ var require_resolve_flow_collection = __commonJS({
4329
4329
  else
4330
4330
  onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
4331
4331
  }
4332
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep, null, valueProps, onError) : null;
4332
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep2, null, valueProps, onError) : null;
4333
4333
  if (valueNode) {
4334
4334
  if (isBlock(value))
4335
4335
  onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
@@ -4509,7 +4509,7 @@ var require_resolve_block_scalar = __commonJS({
4509
4509
  chompStart = i + 1;
4510
4510
  }
4511
4511
  let value = "";
4512
- let sep = "";
4512
+ let sep2 = "";
4513
4513
  let prevMoreIndented = false;
4514
4514
  for (let i = 0; i < contentStart; ++i)
4515
4515
  value += lines[i][0].slice(trimIndent) + "\n";
@@ -4526,24 +4526,24 @@ var require_resolve_block_scalar = __commonJS({
4526
4526
  indent = "";
4527
4527
  }
4528
4528
  if (type === Scalar.Scalar.BLOCK_LITERAL) {
4529
- value += sep + indent.slice(trimIndent) + content;
4530
- sep = "\n";
4529
+ value += sep2 + indent.slice(trimIndent) + content;
4530
+ sep2 = "\n";
4531
4531
  } else if (indent.length > trimIndent || content[0] === " ") {
4532
- if (sep === " ")
4533
- sep = "\n";
4534
- else if (!prevMoreIndented && sep === "\n")
4535
- sep = "\n\n";
4536
- value += sep + indent.slice(trimIndent) + content;
4537
- sep = "\n";
4532
+ if (sep2 === " ")
4533
+ sep2 = "\n";
4534
+ else if (!prevMoreIndented && sep2 === "\n")
4535
+ sep2 = "\n\n";
4536
+ value += sep2 + indent.slice(trimIndent) + content;
4537
+ sep2 = "\n";
4538
4538
  prevMoreIndented = true;
4539
4539
  } else if (content === "") {
4540
- if (sep === "\n")
4540
+ if (sep2 === "\n")
4541
4541
  value += "\n";
4542
4542
  else
4543
- sep = "\n";
4543
+ sep2 = "\n";
4544
4544
  } else {
4545
- value += sep + content;
4546
- sep = " ";
4545
+ value += sep2 + content;
4546
+ sep2 = " ";
4547
4547
  prevMoreIndented = false;
4548
4548
  }
4549
4549
  }
@@ -4726,25 +4726,25 @@ var require_resolve_flow_scalar = __commonJS({
4726
4726
  trimBoth = /^[ \t]+|[ \t]+$/g;
4727
4727
  }
4728
4728
  let res = match[1].replace(trimEnd, "");
4729
- let sep = " ";
4729
+ let sep2 = " ";
4730
4730
  let pos = line.lastIndex;
4731
4731
  while (match = line.exec(source)) {
4732
4732
  const lm = match[1].replace(trimBoth, "");
4733
4733
  if (lm === "") {
4734
- if (sep === "\n")
4735
- res += sep;
4734
+ if (sep2 === "\n")
4735
+ res += sep2;
4736
4736
  else
4737
- sep = "\n";
4737
+ sep2 = "\n";
4738
4738
  } else {
4739
- res += sep + lm;
4740
- sep = " ";
4739
+ res += sep2 + lm;
4740
+ sep2 = " ";
4741
4741
  }
4742
4742
  pos = line.lastIndex;
4743
4743
  }
4744
4744
  const last = /[ \t]*(.*)/sy;
4745
4745
  last.lastIndex = pos;
4746
4746
  match = last.exec(source);
4747
- return res + sep + (match?.[1] ?? "");
4747
+ return res + sep2 + (match?.[1] ?? "");
4748
4748
  }
4749
4749
  function doubleQuotedValue(source, onError) {
4750
4750
  let res = "";
@@ -5554,14 +5554,14 @@ var require_cst_stringify = __commonJS({
5554
5554
  }
5555
5555
  }
5556
5556
  }
5557
- function stringifyItem({ start, key, sep, value }) {
5557
+ function stringifyItem({ start, key, sep: sep2, value }) {
5558
5558
  let res = "";
5559
5559
  for (const st of start)
5560
5560
  res += st.source;
5561
5561
  if (key)
5562
5562
  res += stringifyToken(key);
5563
- if (sep)
5564
- for (const st of sep)
5563
+ if (sep2)
5564
+ for (const st of sep2)
5565
5565
  res += st.source;
5566
5566
  if (value)
5567
5567
  res += stringifyToken(value);
@@ -5576,7 +5576,7 @@ var require_cst_visit = __commonJS({
5576
5576
  "../../node_modules/.pnpm/yaml@2.9.1/node_modules/yaml/dist/parse/cst-visit.js"(exports) {
5577
5577
  "use strict";
5578
5578
  var BREAK = /* @__PURE__ */ Symbol("break visit");
5579
- var SKIP = /* @__PURE__ */ Symbol("skip children");
5579
+ var SKIP3 = /* @__PURE__ */ Symbol("skip children");
5580
5580
  var REMOVE = /* @__PURE__ */ Symbol("remove item");
5581
5581
  function visit(cst, visitor) {
5582
5582
  if ("type" in cst && cst.type === "document")
@@ -5584,7 +5584,7 @@ var require_cst_visit = __commonJS({
5584
5584
  _visit(Object.freeze([]), cst, visitor);
5585
5585
  }
5586
5586
  visit.BREAK = BREAK;
5587
- visit.SKIP = SKIP;
5587
+ visit.SKIP = SKIP3;
5588
5588
  visit.REMOVE = REMOVE;
5589
5589
  visit.itemAtPath = (cst, path) => {
5590
5590
  let item = cst;
@@ -6728,18 +6728,18 @@ var require_parser = __commonJS({
6728
6728
  if (this.type === "map-value-ind") {
6729
6729
  const prev = getPrevProps(this.peek(2));
6730
6730
  const start = getFirstKeyStartProps(prev);
6731
- let sep;
6731
+ let sep2;
6732
6732
  if (scalar.end) {
6733
- sep = scalar.end;
6734
- sep.push(this.sourceToken);
6733
+ sep2 = scalar.end;
6734
+ sep2.push(this.sourceToken);
6735
6735
  delete scalar.end;
6736
6736
  } else
6737
- sep = [this.sourceToken];
6737
+ sep2 = [this.sourceToken];
6738
6738
  const map = {
6739
6739
  type: "block-map",
6740
6740
  offset: scalar.offset,
6741
6741
  indent: scalar.indent,
6742
- items: [{ start, key: scalar, sep }]
6742
+ items: [{ start, key: scalar, sep: sep2 }]
6743
6743
  };
6744
6744
  this.onKeyLine = true;
6745
6745
  this.stack[this.stack.length - 1] = map;
@@ -6892,15 +6892,15 @@ var require_parser = __commonJS({
6892
6892
  } else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
6893
6893
  const start2 = getFirstKeyStartProps(it.start);
6894
6894
  const key = it.key;
6895
- const sep = it.sep;
6896
- sep.push(this.sourceToken);
6895
+ const sep2 = it.sep;
6896
+ sep2.push(this.sourceToken);
6897
6897
  delete it.key;
6898
6898
  delete it.sep;
6899
6899
  this.stack.push({
6900
6900
  type: "block-map",
6901
6901
  offset: this.offset,
6902
6902
  indent: this.indent,
6903
- items: [{ start: start2, key, sep }]
6903
+ items: [{ start: start2, key, sep: sep2 }]
6904
6904
  });
6905
6905
  } else if (start.length > 0) {
6906
6906
  it.sep = it.sep.concat(start, this.sourceToken);
@@ -7094,13 +7094,13 @@ var require_parser = __commonJS({
7094
7094
  const prev = getPrevProps(parent);
7095
7095
  const start = getFirstKeyStartProps(prev);
7096
7096
  fixFlowSeqItems(fc);
7097
- const sep = fc.end.splice(1, fc.end.length);
7098
- sep.push(this.sourceToken);
7097
+ const sep2 = fc.end.splice(1, fc.end.length);
7098
+ sep2.push(this.sourceToken);
7099
7099
  const map = {
7100
7100
  type: "block-map",
7101
7101
  offset: fc.offset,
7102
7102
  indent: fc.indent,
7103
- items: [{ start, key: fc, sep }]
7103
+ items: [{ start, key: fc, sep: sep2 }]
7104
7104
  };
7105
7105
  this.onKeyLine = true;
7106
7106
  this.stack[this.stack.length - 1] = map;
@@ -7378,37 +7378,317 @@ var require_dist = __commonJS({
7378
7378
  }
7379
7379
  });
7380
7380
 
7381
+ // ../policy/dist/discover.js
7382
+ function isAgentConfigPath(path) {
7383
+ return PROJECT_FILES.some((f) => f.re.test(path));
7384
+ }
7385
+ function agentFor(path) {
7386
+ const p = PROJECT_FILES.find((f) => f.re.test(path));
7387
+ if (p)
7388
+ return p.agent;
7389
+ const u = USER_CONFIG_FILES.find((f) => path.endsWith(f.path));
7390
+ return u?.agent ?? "any";
7391
+ }
7392
+ function parseJsonc(text) {
7393
+ try {
7394
+ return JSON.parse(text);
7395
+ } catch {
7396
+ }
7397
+ const noComments = text.replace(/("(?:\\.|[^"\\])*")|\/\/[^\n]*|\/\*[\s\S]*?\*\//g, (_m, s1) => s1 ?? "");
7398
+ try {
7399
+ return JSON.parse(noComments.replace(/,(\s*[}\]])/g, "$1"));
7400
+ } catch {
7401
+ return null;
7402
+ }
7403
+ }
7404
+ function stdioPackage(command, args) {
7405
+ const bin = command.split(/[\\/]/).pop()?.replace(/\.(cmd|exe)$/i, "") ?? "";
7406
+ const strip = (s) => s.replace(/(.)@[^@/]+$/, "$1");
7407
+ if (/^(npx|bunx|pnpx)$/.test(bin) || bin === "pnpm" && args[0] === "dlx") {
7408
+ const pkg = args.find((a) => !a.startsWith("-") && a !== "dlx" && a !== "exec");
7409
+ return pkg && /^(@[\w.-]+\/)?[\w.-]+(@[\w.^~<>=*-]+)?$/.test(pkg) ? { registry: "npm", name: strip(pkg) } : void 0;
7410
+ }
7411
+ if (/^(uvx|pipx)$/.test(bin) || bin === "uv" && args[0] === "tool") {
7412
+ const pkg = args.find((a) => !a.startsWith("-") && !["run", "tool"].includes(a));
7413
+ return pkg && /^[\w.\-[\]]+(==[\w.]+)?$/.test(pkg) ? { registry: "pypi", name: pkg.toLowerCase().replace(/\[.*\]$/, "").replace(/==.*$/, "").replace(/_/g, "-") } : void 0;
7414
+ }
7415
+ if (bin === "docker") {
7416
+ const img = args.find((a, i) => i > 0 && !a.startsWith("-") && /^([\w.-]+\.[\w]+\/)?[\w.-]+\/[\w.-]+(:[\w.-]+)?$/.test(a) && !/^-/.test(args[i - 1] ?? ""));
7417
+ if (!img)
7418
+ return void 0;
7419
+ return { registry: "docker", name: img.replace(/:[\w.-]+$/, "").replace(/^(docker\.io|ghcr\.io)\//, "") };
7420
+ }
7421
+ return void 0;
7422
+ }
7423
+ function hostOf(u) {
7424
+ if (!u)
7425
+ return void 0;
7426
+ try {
7427
+ return new URL(u).host.toLowerCase();
7428
+ } catch {
7429
+ return void 0;
7430
+ }
7431
+ }
7432
+ function serverComponents(servers, path, scope, agent) {
7433
+ if (!isObj(servers))
7434
+ return [];
7435
+ const out = [];
7436
+ for (const [name, raw] of Object.entries(servers).slice(0, 200)) {
7437
+ if (!isObj(raw))
7438
+ continue;
7439
+ const url = str(raw.url) ?? str(raw.serverUrl) ?? str(raw.httpUrl);
7440
+ const command = str(raw.command);
7441
+ const args = Array.isArray(raw.args) ? raw.args.filter((a) => typeof a === "string") : [];
7442
+ const envKeys = keysOf(raw.env);
7443
+ const headerKeys = keysOf(raw.headers);
7444
+ if (url)
7445
+ out.push({ kind: "mcp_server", name, path, scope, agent, transport: "http", urlHost: hostOf(url), envKeys, headerKeys });
7446
+ else if (command) {
7447
+ const parts = args.length ? [command, ...args] : command.split(/\s+/);
7448
+ const bin = parts[0];
7449
+ out.push({ kind: "mcp_server", name, path, scope, agent, transport: "stdio", command: bin.split(/[\\/]/).pop(), package: stdioPackage(bin, parts.slice(1)), envKeys, headerKeys });
7450
+ }
7451
+ }
7452
+ return out;
7453
+ }
7454
+ function claudeSettings(j, path, scope) {
7455
+ const out = [];
7456
+ const agent = "claude_code";
7457
+ if (isObj(j.enabledPlugins)) {
7458
+ for (const [id, on2] of Object.entries(j.enabledPlugins).slice(0, 200)) {
7459
+ if (on2 === false)
7460
+ continue;
7461
+ const [plugin, marketplace] = id.split("@");
7462
+ out.push({ kind: "plugin", name: plugin, path, scope, agent, envKeys: [], headerKeys: [], detail: marketplace ? `from ${marketplace}` : void 0 });
7463
+ }
7464
+ }
7465
+ if (isObj(j.hooks)) {
7466
+ for (const [event, groups] of Object.entries(j.hooks)) {
7467
+ if (!Array.isArray(groups))
7468
+ continue;
7469
+ for (const g of groups) {
7470
+ if (!isObj(g) || !Array.isArray(g.hooks))
7471
+ continue;
7472
+ for (const h of g.hooks) {
7473
+ if (!isObj(h))
7474
+ continue;
7475
+ const cmd2 = str(h.command);
7476
+ if (!cmd2)
7477
+ continue;
7478
+ const bin = cmd2.trim().split(/\s+/)[0];
7479
+ out.push({ kind: "hook", name: event, path, scope, agent, command: bin.split(/[\\/]/).pop(), envKeys: [], headerKeys: [], detail: str(g.matcher) ? `on ${str(g.matcher)}` : "on every tool call" });
7480
+ }
7481
+ }
7482
+ }
7483
+ }
7484
+ out.push(...serverComponents(j.mcpServers, path, scope, agent));
7485
+ return out;
7486
+ }
7487
+ function codexToml(text, path, scope) {
7488
+ const out = [];
7489
+ const blocks = text.split(/^\s*\[/m).slice(1);
7490
+ for (const b of blocks) {
7491
+ const head = b.match(/^mcp_servers\.("?)([\w.-]+)\1\]/);
7492
+ if (head) {
7493
+ const body = b.slice(b.indexOf("]") + 1);
7494
+ const command = body.match(/^\s*command\s*=\s*"([^"]+)"/m)?.[1];
7495
+ const args = [...(body.match(/^\s*args\s*=\s*\[([^\]]*)\]/m)?.[1] ?? "").matchAll(/"([^"]*)"/g)].map((m) => m[1]);
7496
+ const url = body.match(/^\s*url\s*=\s*"([^"]+)"/m)?.[1] ?? null;
7497
+ const envKeys = [...(body.match(/^\s*env\s*=\s*\{([^}]*)\}/m)?.[1] ?? "").matchAll(/([\w.-]+)\s*=/g)].map((m) => m[1]);
7498
+ if (url)
7499
+ out.push({ kind: "mcp_server", name: head[2], path, scope, agent: "codex", transport: "http", urlHost: hostOf(url), envKeys, headerKeys: [] });
7500
+ else if (command)
7501
+ out.push({ kind: "mcp_server", name: head[2], path, scope, agent: "codex", transport: "stdio", command: command.split(/[\\/]/).pop(), package: stdioPackage(command, args), envKeys, headerKeys: [] });
7502
+ }
7503
+ const envTable = b.match(/^mcp_servers\.("?)([\w.-]+)\1\.env\]/);
7504
+ if (envTable) {
7505
+ const target = out.find((c2) => c2.name === envTable[2]);
7506
+ if (target)
7507
+ target.envKeys.push(...[...b.slice(b.indexOf("]") + 1).matchAll(/^\s*([\w.-]+)\s*=/gm)].map((m) => m[1]));
7508
+ }
7509
+ }
7510
+ return out;
7511
+ }
7512
+ function skillName(path, text) {
7513
+ const fm = text.match(/^---\s*\n([\s\S]*?)\n---/);
7514
+ const n = fm?.[1].match(/^name:\s*["']?([^"'\n]+)["']?\s*$/m)?.[1]?.trim();
7515
+ return n || path.split("/").slice(-2, -1)[0] || "skill";
7516
+ }
7517
+ function parseAgentConfig(path, text, scope = "project") {
7518
+ const p = path.replace(/\\/g, "/");
7519
+ const agent = agentFor(p);
7520
+ const base = p.split("/").pop() ?? p;
7521
+ if (/\/SKILL\.md$/i.test(p))
7522
+ return [{ kind: "skill", name: skillName(p, text), path: p, scope, agent: "claude_code", envKeys: [], headerKeys: [] }];
7523
+ if (/\.(md|mdc)$/i.test(p) || /^\.(cursorrules|windsurfrules|clinerules)$/.test(base)) {
7524
+ const kind = /\/\.claude\/commands\//.test(`/${p}`) ? "slash command" : /\/\.claude\/agents\//.test(`/${p}`) ? "subagent" : "instructions";
7525
+ return [{ kind: "instructions", name: kind === "instructions" ? base : `${kind}: ${base.replace(/\.md$/i, "")}`, path: p, scope, agent, envKeys: [], headerKeys: [], detail: `${text.length.toLocaleString("en-US")} characters` }];
7526
+ }
7527
+ if (/config\.toml$/.test(p))
7528
+ return codexToml(text, p, scope);
7529
+ const j = parseJsonc(text);
7530
+ if (!isObj(j))
7531
+ return [];
7532
+ if (/\.claude\/settings(\.local)?\.json$/.test(p))
7533
+ return claudeSettings(j, p, scope);
7534
+ if (/\.vscode\/mcp\.json$/.test(p))
7535
+ return serverComponents(j.servers, p, scope, "vscode");
7536
+ if (base === ".claude.json") {
7537
+ const out = serverComponents(j.mcpServers, p, scope, "claude_code");
7538
+ if (isObj(j.projects)) {
7539
+ for (const [proj, cfg] of Object.entries(j.projects).slice(0, 100))
7540
+ if (isObj(cfg))
7541
+ for (const c2 of serverComponents(cfg.mcpServers, p, "project", "claude_code"))
7542
+ out.push({ ...c2, detail: `project ${proj.split(/[\\/]/).slice(-2).join("/")}` });
7543
+ }
7544
+ return out;
7545
+ }
7546
+ return serverComponents(j.mcpServers ?? j.servers, p, scope, agent);
7547
+ }
7548
+ function classifyCredential(name) {
7549
+ for (const [re, c2] of CRED_RULES)
7550
+ if (re.test(name))
7551
+ return c2;
7552
+ return null;
7553
+ }
7554
+ function blastRadius({ component: c2, verdict, trace }) {
7555
+ const reasons = [];
7556
+ const credentials = [...c2.envKeys, ...c2.headerKeys].map((name) => ({ name, class: classifyCredential(name) })).filter((x) => !!x.class);
7557
+ const hosts = /* @__PURE__ */ new Set();
7558
+ if (c2.urlHost)
7559
+ hosts.add(c2.urlHost);
7560
+ for (const h of trace?.egressHosts ?? [])
7561
+ hosts.add(h);
7562
+ let score = 0;
7563
+ const local = c2.transport === "stdio" || c2.kind === "hook";
7564
+ if (c2.kind === "hook") {
7565
+ score += 2;
7566
+ reasons.push(`runs \`${c2.command ?? "a command"}\` ${c2.detail ?? "on agent events"}, as the developer`);
7567
+ } else if (local) {
7568
+ score += 2;
7569
+ reasons.push("runs on the developer's machine with their files, network and shell");
7570
+ }
7571
+ if (c2.kind === "skill" || c2.kind === "plugin") {
7572
+ score += 1;
7573
+ reasons.push("adds instructions and scripts the agent will follow");
7574
+ }
7575
+ const strong = credentials.filter((x) => x.class !== "secret");
7576
+ if (credentials.length) {
7577
+ score += strong.some((x) => ["cloud", "source_control", "payments", "database"].includes(x.class)) ? 3 : 2;
7578
+ reasons.unshift(`is handed ${credentials.length === 1 ? "a credential" : `${credentials.length} credentials`}: ${credentials.slice(0, 4).map((x) => x.name).join(", ")}${credentials.length > 4 ? ", \u2026" : ""}`);
7579
+ }
7580
+ if (c2.transport === "http" && c2.urlHost) {
7581
+ score += 1;
7582
+ reasons.push(`sends the agent's tool calls and their data to ${c2.urlHost}`);
7583
+ }
7584
+ if (verdict?.label === "blocked") {
7585
+ score += 4;
7586
+ reasons.unshift(`its verdict is Blocked (${verdict.score}/100)`);
7587
+ } else if (verdict?.label === "caution") {
7588
+ score += 1;
7589
+ reasons.push(`its verdict is Caution (${verdict.score}/100)`);
7590
+ }
7591
+ if (trace?.credentialPathsRead.length) {
7592
+ score += 3;
7593
+ reasons.unshift(`read ${trace.credentialPathsRead.slice(0, 2).join(", ")} in the honeypot`);
7594
+ }
7595
+ if (trace?.memoryWrites) {
7596
+ score += 2;
7597
+ reasons.push("wrote to the agent's memory or instruction files in the honeypot");
7598
+ }
7599
+ if (c2.kind === "instructions")
7600
+ reasons.push("is read by the agent as instructions on every session");
7601
+ if (!verdict && c2.kind !== "instructions" && c2.kind !== "hook") {
7602
+ score += 1;
7603
+ reasons.push(c2.package || c2.kind !== "mcp_server" ? "has no KillerSkills verdict yet" : "is not a registry package, so there is no verdict to check");
7604
+ }
7605
+ const level = score >= 5 ? "high" : score >= 3 ? "medium" : "low";
7606
+ return { level, reasons, credentials, hosts: [...hosts].slice(0, 10) };
7607
+ }
7608
+ var PROJECT_FILES, USER_CONFIG_FILES, USER_SKILL_DIRS, isObj, str, keysOf, CRED_RULES;
7609
+ var init_discover = __esm({
7610
+ "../policy/dist/discover.js"() {
7611
+ "use strict";
7612
+ PROJECT_FILES = [
7613
+ { re: /(^|\/)\.mcp\.json$/, agent: "claude_code" },
7614
+ { re: /(^|\/)\.claude\/settings(\.local)?\.json$/, agent: "claude_code" },
7615
+ { re: /(^|\/)\.claude\/skills\/[^/]+\/SKILL\.md$/i, agent: "claude_code" },
7616
+ { re: /(^|\/)\.claude\/(commands|agents)\/[^/]+\.md$/i, agent: "claude_code" },
7617
+ { re: /(^|\/)\.cursor\/mcp\.json$/, agent: "cursor" },
7618
+ { re: /(^|\/)\.cursor\/rules\/[^/]+\.mdc?$/, agent: "cursor" },
7619
+ { re: /(^|\/)\.vscode\/mcp\.json$/, agent: "vscode" },
7620
+ { re: /(^|\/)\.gemini\/settings\.json$/, agent: "gemini_cli" },
7621
+ { re: /(^|\/)\.codex\/config\.toml$/, agent: "codex" },
7622
+ { re: /(^|\/)\.github\/copilot-instructions\.md$/, agent: "copilot" },
7623
+ { re: /(^|\/)(CLAUDE|AGENTS|GEMINI)\.md$/, agent: "any" },
7624
+ { re: /(^|\/)\.(cursorrules|windsurfrules|clinerules)$/, agent: "any" }
7625
+ ];
7626
+ USER_CONFIG_FILES = [
7627
+ { path: ".claude.json", agent: "claude_code" },
7628
+ { path: ".claude/settings.json", agent: "claude_code" },
7629
+ { path: ".claude/CLAUDE.md", agent: "claude_code" },
7630
+ { path: ".cursor/mcp.json", agent: "cursor" },
7631
+ { path: ".codeium/windsurf/mcp_config.json", agent: "windsurf" },
7632
+ { path: ".gemini/settings.json", agent: "gemini_cli" },
7633
+ { path: ".codex/config.toml", agent: "codex" },
7634
+ { path: "Library/Application Support/Claude/claude_desktop_config.json", agent: "claude_desktop" },
7635
+ { path: ".config/Claude/claude_desktop_config.json", agent: "claude_desktop" },
7636
+ { path: "AppData/Roaming/Claude/claude_desktop_config.json", agent: "claude_desktop" }
7637
+ ];
7638
+ USER_SKILL_DIRS = [".claude/skills"];
7639
+ isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
7640
+ str = (v) => typeof v === "string" ? v : null;
7641
+ keysOf = (v) => isObj(v) ? Object.keys(v).filter((k) => /^[\w.-]{1,120}$/.test(k)).slice(0, 50) : [];
7642
+ CRED_RULES = [
7643
+ [/^(AWS_|AZURE_|ARM_|GOOGLE_|GCP_|GCLOUD|CLOUDFLARE_|DIGITALOCEAN|DO_TOKEN|VERCEL_|NETLIFY_|HEROKU_|FLY_)/i, "cloud"],
7644
+ [/^(GITHUB_|GH_|GITLAB_|GL_|BITBUCKET_|GIT_)/i, "source_control"],
7645
+ [/^(STRIPE_|PAYPAL_|BRAINTREE_|ADYEN_|SQUARE_)/i, "payments"],
7646
+ [/(DATABASE_URL|_DSN$|^POSTGRES|^PG|^MYSQL|^MONGO|^REDIS|^SUPABASE_|^NEON_|^PLANETSCALE|^SNOWFLAKE_|^BIGQUERY)/i, "database"],
7647
+ [/^(OPENAI_|ANTHROPIC_|GEMINI_|MISTRAL_|COHERE_|GROQ_|HF_|HUGGINGFACE)/i, "ai_provider"],
7648
+ [/^(SLACK_|DISCORD_|TWILIO_|SENDGRID_|RESEND_|MAILGUN_|POSTMARK_)/i, "messaging"],
7649
+ [/(TOKEN|SECRET|PASSWORD|PASSWD|API_?KEY|PRIVATE_KEY|CREDENTIAL|AUTH)/i, "secret"]
7650
+ ];
7651
+ }
7652
+ });
7653
+
7381
7654
  // ../policy/dist/index.js
7382
7655
  var dist_exports = {};
7383
7656
  __export(dist_exports, {
7384
7657
  DEFAULT_POLICY: () => DEFAULT_POLICY,
7385
7658
  FLAG_LABEL: () => FLAG_LABEL,
7386
7659
  SOLO_POLICY: () => SOLO_POLICY,
7660
+ USER_CONFIG_FILES: () => USER_CONFIG_FILES,
7661
+ USER_SKILL_DIRS: () => USER_SKILL_DIRS,
7662
+ blastRadius: () => blastRadius,
7663
+ classifyCredential: () => classifyCredential,
7387
7664
  evaluate: () => evaluate,
7388
7665
  flagsFromTrace: () => flagsFromTrace,
7666
+ isAgentConfigPath: () => isAgentConfigPath,
7389
7667
  labelFor: () => labelFor,
7668
+ parseAgentConfig: () => parseAgentConfig,
7390
7669
  parsePolicyYaml: () => parsePolicyYaml,
7391
7670
  serializePolicyYaml: () => serializePolicyYaml,
7392
- simulate: () => simulate
7671
+ simulate: () => simulate,
7672
+ stdioPackage: () => stdioPackage
7393
7673
  });
7394
7674
  function parsePolicyYaml(text) {
7395
7675
  const y = import_yaml.default.parse(text) ?? {};
7396
7676
  const num = (v, d) => typeof v === "number" && Number.isFinite(v) ? v : d;
7397
- const str = (v, allowed, d) => allowed.includes(v) ? v : d;
7677
+ const str2 = (v, allowed, d) => allowed.includes(v) ? v : d;
7398
7678
  const list = (v) => Array.isArray(v) ? v.map(String) : [];
7399
7679
  const b = y.behavior ?? {};
7400
7680
  const p = y.publishers ?? {};
7401
7681
  const a = y.approvals ?? {};
7402
7682
  const behavior = { ...DEFAULT_POLICY.behavior };
7403
7683
  for (const f of FLAGS)
7404
- behavior[f] = str(b[f], ["block", "approval", "warn"], DEFAULT_POLICY.behavior[f]);
7684
+ behavior[f] = str2(b[f], ["block", "approval", "warn"], DEFAULT_POLICY.behavior[f]);
7405
7685
  return {
7406
7686
  name: typeof y.name === "string" ? y.name : DEFAULT_POLICY.name,
7407
7687
  version: num(y.version, 1),
7408
7688
  minScore: Math.min(100, Math.max(0, num(y.min_score, DEFAULT_POLICY.minScore))),
7409
- cautionAction: str(y.caution, ["sandbox", "approval", "allow", "block"], DEFAULT_POLICY.cautionAction),
7410
- unknownAction: str(y.unknown, ["detonate", "block", "approval", "allow"], DEFAULT_POLICY.unknownAction),
7411
- offlineAction: str(y.offline, ["allow", "block", "approval"], DEFAULT_POLICY.offlineAction),
7689
+ cautionAction: str2(y.caution, ["sandbox", "approval", "allow", "block"], DEFAULT_POLICY.cautionAction),
7690
+ unknownAction: str2(y.unknown, ["detonate", "block", "approval", "allow"], DEFAULT_POLICY.unknownAction),
7691
+ offlineAction: str2(y.offline, ["allow", "block", "approval"], DEFAULT_POLICY.offlineAction),
7412
7692
  behavior,
7413
7693
  publishers: {
7414
7694
  allow: list(p.allow),
@@ -7572,6 +7852,7 @@ var init_dist = __esm({
7572
7852
  "../policy/dist/index.js"() {
7573
7853
  "use strict";
7574
7854
  import_yaml = __toESM(require_dist(), 1);
7855
+ init_discover();
7575
7856
  DEFAULT_POLICY = {
7576
7857
  name: "default-strict",
7577
7858
  version: 1,
@@ -7614,11 +7895,11 @@ var init_dist = __esm({
7614
7895
  init_dist();
7615
7896
  import { parseArgs } from "node:util";
7616
7897
  import { spawnSync } from "node:child_process";
7617
- import { readFileSync as readFileSync3, existsSync as existsSync4 } from "node:fs";
7618
- import { resolve, join as join4, dirname, basename } from "node:path";
7898
+ import { readFileSync as readFileSync6, existsSync as existsSync7 } from "node:fs";
7899
+ import { resolve as resolve2, join as join7, dirname, basename } from "node:path";
7619
7900
  import { hostname, platform as platform2, userInfo } from "node:os";
7620
- import { createHash } from "node:crypto";
7621
- import { createInterface } from "node:readline";
7901
+ import { createHash as createHash2 } from "node:crypto";
7902
+ import { createInterface as createInterface2 } from "node:readline";
7622
7903
 
7623
7904
  // src/check.ts
7624
7905
  init_dist();
@@ -7629,7 +7910,7 @@ import { mkdirSync, readFileSync, writeFileSync, existsSync, appendFileSync, chm
7629
7910
  import { homedir } from "node:os";
7630
7911
  import { join } from "node:path";
7631
7912
  import { randomUUID } from "node:crypto";
7632
- var VERSION = "0.5.2";
7913
+ var VERSION = "0.7.0";
7633
7914
  var HOME = process.env.VET_SKILLS_HOME ?? join(homedir(), ".vet-skills");
7634
7915
  var API = (process.env.KILLERSKILLS_API ?? "https://killerskills.ai").replace(/\/$/, "");
7635
7916
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -7805,6 +8086,11 @@ function report(body) {
7805
8086
  if (!org) return Promise.resolve({ ok: false, error: "not joined", offline: false });
7806
8087
  return call(`/api/v1/orgs/${org.slug}/agents/${org.agentId}/report`, { method: "POST", body: JSON.stringify(body), headers: orgHeaders() }, 8e3);
7807
8088
  }
8089
+ function runtimeReport(body) {
8090
+ const org = readOrg();
8091
+ if (!org) return Promise.resolve({ ok: false, error: "not joined", offline: false });
8092
+ return call(`/api/v1/orgs/${org.slug}/agents/${org.agentId}/runtime`, { method: "POST", body: JSON.stringify(body), headers: orgHeaders() }, 6e3);
8093
+ }
7808
8094
  function confirmRemoval(removalId, body) {
7809
8095
  const org = readOrg();
7810
8096
  if (!org) return Promise.resolve({ ok: false, error: "not joined", offline: false });
@@ -7822,6 +8108,11 @@ function detonate(tgz, opts = {}) {
7822
8108
  function sendTelemetry(body) {
7823
8109
  return call("/api/v1/telemetry", { method: "POST", body: JSON.stringify(body) }, 1500);
7824
8110
  }
8111
+ function discoverReport(components) {
8112
+ const org = readOrg();
8113
+ if (!org) return Promise.resolve({ ok: false, error: "not joined", offline: false });
8114
+ return call(`/api/v1/orgs/${org.slug}/agents/${org.agentId}/discover`, { method: "POST", body: JSON.stringify({ components }), headers: orgHeaders() }, 15e3);
8115
+ }
7825
8116
 
7826
8117
  // src/check.ts
7827
8118
  import { platform } from "node:os";
@@ -7864,6 +8155,151 @@ function fmtInstalls(n) {
7864
8155
  return n.toLocaleString("en-US");
7865
8156
  }
7866
8157
 
8158
+ // src/attest.ts
8159
+ import { createHash, createPublicKey, verify as cryptoVerify } from "node:crypto";
8160
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
8161
+ import { homedir as homedir2 } from "node:os";
8162
+ import { join as join2, relative, resolve, sep } from "node:path";
8163
+ var LOCKFILE = "vet-skills.lock";
8164
+ var PAYLOAD_TYPE = "application/vnd.killerskills.verdict+json";
8165
+ var SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", ".pglite", ".next", "__pycache__", ".venv"]);
8166
+ function bundleHash(root) {
8167
+ const h = createHash("sha256");
8168
+ const walk2 = (dir) => {
8169
+ for (const name of readdirSync(dir).sort()) {
8170
+ if (SKIP.has(name)) continue;
8171
+ const p = join2(dir, name);
8172
+ const st = statSync2(p);
8173
+ if (st.isDirectory()) walk2(p);
8174
+ else if (st.isFile() && st.size <= 2 * 1024 * 1024) {
8175
+ h.update(relative(root, p).split(sep).join("/"));
8176
+ h.update("\0");
8177
+ h.update(readFileSync2(p));
8178
+ h.update("\0");
8179
+ }
8180
+ }
8181
+ };
8182
+ walk2(root);
8183
+ return h.digest("hex");
8184
+ }
8185
+ function pae(payloadType, payload) {
8186
+ const t = Buffer.from(payloadType);
8187
+ return Buffer.concat([Buffer.from(`DSSEv1 ${t.length} `), t, Buffer.from(` ${payload.length} `), payload]);
8188
+ }
8189
+ function verifyEnvelope(env, keys) {
8190
+ if (env.payloadType !== PAYLOAD_TYPE) return { ok: false, statement: null, kid: null, reason: `unexpected payload type ${env.payloadType}` };
8191
+ const payload = Buffer.from(env.payload, "base64");
8192
+ const trusted = (process.env.VET_SKILLS_TRUSTED_KEYS ?? "").split(",").map((s) => s.trim()).filter(Boolean);
8193
+ for (const sig of env.signatures) {
8194
+ const k = keys.find((x) => x.kid === sig.keyid);
8195
+ if (!k) continue;
8196
+ if (trusted.length && !trusted.includes(k.kid)) return { ok: false, statement: null, kid: k.kid, reason: `key ${k.kid} is not in VET_SKILLS_TRUSTED_KEYS` };
8197
+ if (k.dev) return { ok: false, statement: null, kid: k.kid, reason: "signed with a development key" };
8198
+ try {
8199
+ const pub = createPublicKey({ key: { kty: k.kty, crv: k.crv, x: k.x }, format: "jwk" });
8200
+ if (cryptoVerify(null, pae(env.payloadType, payload), pub, Buffer.from(sig.sig, "base64"))) return { ok: true, statement: JSON.parse(payload.toString("utf8")), kid: k.kid, reason: "signature valid" };
8201
+ return { ok: false, statement: null, kid: k.kid, reason: "signature does not verify" };
8202
+ } catch (e) {
8203
+ return { ok: false, statement: null, kid: k.kid, reason: e.message };
8204
+ }
8205
+ }
8206
+ return { ok: false, statement: null, kid: env.signatures[0]?.keyid ?? null, reason: "no known key for this signature" };
8207
+ }
8208
+ async function getJson(url) {
8209
+ try {
8210
+ const r = await fetch(url, { headers: { accept: "application/json", "user-agent": `vet-skills/${VERSION}` }, signal: AbortSignal.timeout(8e3) });
8211
+ return r.ok ? await r.json() : null;
8212
+ } catch {
8213
+ return null;
8214
+ }
8215
+ }
8216
+ async function fetchKeys() {
8217
+ const r = await getJson(`${API}/.well-known/killerskills-keys.json`);
8218
+ return r?.keys ?? [];
8219
+ }
8220
+ async function fetchAttestationByHash(hash) {
8221
+ return getJson(`${API}/api/v1/verdicts/${hash}/attestation`);
8222
+ }
8223
+ function installedSkills() {
8224
+ const out = [];
8225
+ for (const base of [join2(process.cwd(), ".claude", "skills"), join2(homedir2(), ".claude", "skills"), join2(homedir2(), ".claude", "plugins")]) {
8226
+ if (!existsSync2(base)) continue;
8227
+ for (const name of readdirSync(base).sort()) {
8228
+ const p = join2(base, name);
8229
+ if (statSync2(p).isDirectory() && !out.some((x) => x.name === name)) out.push({ name, path: p });
8230
+ }
8231
+ }
8232
+ return out;
8233
+ }
8234
+ async function verifyOne(target, keys) {
8235
+ const dir = resolve(target);
8236
+ let hash;
8237
+ let subject = target;
8238
+ let page = null;
8239
+ if (existsSync2(dir) && statSync2(dir).isDirectory()) {
8240
+ hash = bundleHash(dir);
8241
+ subject = `${target} (${hash.slice(0, 12)}\u2026)`;
8242
+ } else {
8243
+ const [name, ver] = target.split("@").length > 2 ? [target.slice(0, target.lastIndexOf("@")), target.slice(target.lastIndexOf("@") + 1)] : target.includes("@") && !target.startsWith("@") ? target.split("@") : [target, void 0];
8244
+ const r = await resolveSkill(name);
8245
+ if (!r.ok) return { subject, hash: "", ok: false, detail: r.offline ? "offline" : `not found: ${r.error}`, statement: null };
8246
+ if (ver && r.data.version.semver !== ver) return { subject, hash: "", ok: false, detail: `latest scored version is ${r.data.version.semver}; verify a local checkout of ${ver} with a path instead`, statement: null };
8247
+ hash = r.data.version.artifact_hash;
8248
+ page = r.data.skill.page;
8249
+ subject = `${r.data.skill.name}@${r.data.version.semver}`;
8250
+ const local = installedSkills().find((s) => s.name === r.data.skill.name);
8251
+ if (local) {
8252
+ const lh = bundleHash(local.path);
8253
+ if (lh !== hash) return { subject, hash: lh, ok: false, detail: `installed copy at ${local.path} hashes to ${lh.slice(0, 12)}\u2026, attested version is ${hash.slice(0, 12)}\u2026`, statement: null };
8254
+ }
8255
+ }
8256
+ const env = await fetchAttestationByHash(hash);
8257
+ if (!env) return { subject, hash, ok: false, detail: `no attestation for ${hash.slice(0, 12)}\u2026 (unscored, demo or signing not configured)${page ? ` \xB7 ${API}${page}` : ""}`, statement: null };
8258
+ const v = verifyEnvelope(env, keys);
8259
+ if (!v.ok || !v.statement) return { subject, hash, ok: false, detail: v.reason, statement: null };
8260
+ if (v.statement.subject.artifact_hash !== hash) return { subject, hash, ok: false, detail: "attestation is for a different artifact", statement: v.statement };
8261
+ return { subject, hash, ok: true, detail: `${v.statement.predicate.label} ${v.statement.predicate.score} \xB7 engine ${v.statement.predicate.engine_version} \xB7 signed by ${v.kid}${v.statement.predicate.superseded ? " \xB7 superseded" : ""}`, statement: v.statement };
8262
+ }
8263
+ async function writeLock(dir = process.cwd()) {
8264
+ const keys = await fetchKeys();
8265
+ const skills = [];
8266
+ const missing = [];
8267
+ for (const s of installedSkills()) {
8268
+ const hash = bundleHash(s.path);
8269
+ const env = await fetchAttestationByHash(hash);
8270
+ const v = env ? verifyEnvelope(env, keys) : null;
8271
+ if (!v?.ok || !v.statement) missing.push(s.name);
8272
+ skills.push({ name: s.name, path: s.path, artifact_hash: hash, verdict: v?.statement ? { id: v.statement.predicate.verdict_id, label: v.statement.predicate.label, score: v.statement.predicate.score, engine_version: v.statement.predicate.engine_version } : null, attestation: v?.ok ? env : null });
8273
+ }
8274
+ const lock = { version: 1, generated_at: (/* @__PURE__ */ new Date()).toISOString(), generated_by: `vet-skills ${VERSION}`, issuer: API, keys: keys.filter((k) => !k.dev), skills };
8275
+ const file = join2(dir, LOCKFILE);
8276
+ writeFileSync2(file, `${JSON.stringify(lock, null, 2)}
8277
+ `);
8278
+ return { file, lock, missing };
8279
+ }
8280
+ function readLock(dir = process.cwd()) {
8281
+ const file = join2(dir, LOCKFILE);
8282
+ if (!existsSync2(file)) return null;
8283
+ try {
8284
+ return JSON.parse(readFileSync2(file, "utf8"));
8285
+ } catch {
8286
+ return null;
8287
+ }
8288
+ }
8289
+ function verifyLock(lock) {
8290
+ return lock.skills.map((e) => {
8291
+ const path = existsSync2(e.path) ? e.path : installedSkills().find((s) => s.name === e.name)?.path;
8292
+ if (!path) return { subject: e.name, hash: e.artifact_hash, ok: false, detail: "not installed", statement: null };
8293
+ const hash = bundleHash(path);
8294
+ if (hash !== e.artifact_hash) return { subject: e.name, hash, ok: false, detail: `changed on disk: ${hash.slice(0, 12)}\u2026 (locked ${e.artifact_hash.slice(0, 12)}\u2026)`, statement: null };
8295
+ if (!e.attestation) return { subject: e.name, hash, ok: true, detail: "hash matches \xB7 pinned by hash only (no attestation when locked)", statement: null };
8296
+ const v = verifyEnvelope(e.attestation, lock.keys);
8297
+ if (!v.ok || !v.statement) return { subject: e.name, hash, ok: false, detail: v.reason, statement: null };
8298
+ if (v.statement.subject.artifact_hash !== hash) return { subject: e.name, hash, ok: false, detail: "attestation is for a different artifact", statement: v.statement };
8299
+ return { subject: e.name, hash, ok: true, detail: `${v.statement.predicate.label} ${v.statement.predicate.score} \xB7 engine ${v.statement.predicate.engine_version} \xB7 signed by ${v.kid}`, statement: v.statement };
8300
+ });
8301
+ }
8302
+
7867
8303
  // src/check.ts
7868
8304
  function toVerdictInput(r) {
7869
8305
  if (!r.verdict) return null;
@@ -7945,6 +8381,12 @@ async function check(q, opts = {}) {
7945
8381
  if (telemetryNoticePending()) process.stderr.write(c.muted("vet-skills sends anonymous usage (skill name, version, decision, agent type; never code, prompts or paths). Opt out: vet-skills telemetry off") + "\n");
7946
8382
  await sendTelemetry({ skill: resolved?.skill.name ?? q, semver: resolved?.version.semver ?? null, registry: resolved?.skill.registry ?? null, decision: decision.decision, would_be: decision.wouldBe ?? null, agent_kind: opts.agentKind ?? "other", hook_version: VERSION, os: platform(), offline }).catch(() => null);
7947
8383
  }
8384
+ const lock = readLock();
8385
+ const pinned = lock && resolved ? lock.skills.find((e) => e.name === resolved.skill.name) : null;
8386
+ if (pinned && resolved && pinned.artifact_hash !== resolved.version.artifact_hash) {
8387
+ const why = `vet-skills.lock pins ${resolved.skill.name} to ${pinned.artifact_hash.slice(0, 12)}\u2026; registry has ${resolved.version.artifact_hash.slice(0, 12)}\u2026 (${resolved.version.semver}). Run \`vet-skills lock\` to accept it.`;
8388
+ return { resolved, decision: { ...decision, decision: "block", wouldBe: "block", reason: why }, source, cacheAge, remote, offline, policyLabel };
8389
+ }
7948
8390
  return { resolved, decision, source, cacheAge, remote, offline, policyLabel };
7949
8391
  }
7950
8392
  function renderCheck(r) {
@@ -8027,18 +8469,183 @@ function restrictionText(r) {
8027
8469
  return parts.join(" \xB7 ") || "no restrictions";
8028
8470
  }
8029
8471
 
8030
- // src/hook.ts
8031
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
8472
+ // src/discover.ts
8473
+ init_dist();
8474
+ import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
8032
8475
  import { homedir as homedir3 } from "node:os";
8033
8476
  import { join as join3 } from "node:path";
8477
+ var MAX_BYTES = 2 * 1024 * 1024;
8478
+ function read(path) {
8479
+ try {
8480
+ const st = statSync3(path);
8481
+ if (!st.isFile() || st.size > MAX_BYTES) return null;
8482
+ return readFileSync3(path, "utf8");
8483
+ } catch {
8484
+ return null;
8485
+ }
8486
+ }
8487
+ function discoverLocal(opts = {}) {
8488
+ const home = opts.home ?? homedir3();
8489
+ const out = [];
8490
+ for (const f of USER_CONFIG_FILES) {
8491
+ const text = read(join3(home, f.path));
8492
+ if (text !== null) out.push(...parseAgentConfig(f.path, text, "user"));
8493
+ }
8494
+ for (const dir of USER_SKILL_DIRS) {
8495
+ const abs = join3(home, dir);
8496
+ if (!existsSync3(abs)) continue;
8497
+ for (const name of safeList(abs)) {
8498
+ const rel = `${dir}/${name}/SKILL.md`;
8499
+ const text = read(join3(home, rel));
8500
+ if (text !== null) out.push(...parseAgentConfig(rel, text, "user"));
8501
+ }
8502
+ }
8503
+ if (opts.project) for (const rel of walk(opts.project, "", 0)) {
8504
+ const text = read(join3(opts.project, rel));
8505
+ if (text !== null) out.push(...parseAgentConfig(rel, text, "project"));
8506
+ }
8507
+ const seen = /* @__PURE__ */ new Set();
8508
+ return out.filter((c2) => {
8509
+ const k = `${c2.kind}|${c2.name}|${c2.path}`;
8510
+ if (seen.has(k)) return false;
8511
+ seen.add(k);
8512
+ return true;
8513
+ });
8514
+ }
8515
+ function safeList(dir) {
8516
+ try {
8517
+ return readdirSync2(dir);
8518
+ } catch {
8519
+ return [];
8520
+ }
8521
+ }
8522
+ var SKIP2 = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "vendor", "target", ".venv", "venv"]);
8523
+ function walk(root, rel, depth) {
8524
+ if (depth > 6) return [];
8525
+ const out = [];
8526
+ for (const name of safeList(join3(root, rel))) {
8527
+ if (SKIP2.has(name)) continue;
8528
+ const r = rel ? `${rel}/${name}` : name;
8529
+ let st;
8530
+ try {
8531
+ st = statSync3(join3(root, r));
8532
+ } catch {
8533
+ continue;
8534
+ }
8535
+ if (st.isDirectory()) out.push(...walk(root, r, depth + 1));
8536
+ else if (isAgentConfigPath(r)) out.push(r);
8537
+ if (out.length > 200) break;
8538
+ }
8539
+ return out;
8540
+ }
8541
+
8542
+ // src/mcp.ts
8543
+ import { createInterface } from "node:readline";
8544
+ var TOOLS = [
8545
+ {
8546
+ name: "check_skill",
8547
+ title: "Check a skill or MCP server",
8548
+ description: 'Look up the KillerSkills security verdict for an agent skill, MCP server or plugin BEFORE installing it. Returns the score (0-100), label (verified / caution / blocked), what the sandbox saw it do (network hosts contacted, credential files read, memory writes), the top findings, and the last safe version when the latest is blocked. Use the package name for npm/PyPI MCP servers (e.g. "@modelcontextprotocol/server-github" with registry "npm").',
8549
+ inputSchema: {
8550
+ type: "object",
8551
+ properties: {
8552
+ name: { type: "string", description: 'Skill or package name: "name", "publisher/name", "@scope/pkg", optionally "@version".' },
8553
+ registry: { type: "string", enum: ["skills_sh", "clawhub", "npm", "pypi", "docker", "plugins", "partner"], description: "Registry, when known. Omit to search all public registries." }
8554
+ },
8555
+ required: ["name"]
8556
+ },
8557
+ annotations: { readOnlyHint: true, openWorldHint: true }
8558
+ },
8559
+ {
8560
+ name: "search_skills",
8561
+ title: "Search vetted skills",
8562
+ description: "Search the KillerSkills index (every public agent skill and MCP server, each detonated in a sandbox) by keyword. Returns the most-installed matches with their verdicts, so you can pick a verified option instead of an unvetted one.",
8563
+ inputSchema: { type: "object", properties: { query: { type: "string", description: 'Keywords, e.g. "postgres", "github mcp", "pdf".' } }, required: ["query"] },
8564
+ annotations: { readOnlyHint: true, openWorldHint: true }
8565
+ }
8566
+ ];
8567
+ async function checkSkill(name, registry) {
8568
+ const r = await resolveSkill(name, registry);
8569
+ if (!r.ok) return r.status === 404 ? `No skill or MCP server named "${name}" is indexed by KillerSkills${registry ? ` in ${registry}` : ""}. Treat it as unvetted.` : `KillerSkills lookup failed (${r.error}). Treat "${name}" as unvetted.`;
8570
+ const d = r.data;
8571
+ const page = `${API}${d.skill.page}`;
8572
+ if (!d.verdict) return `${d.skill.name} (${d.skill.registry_label}, publisher ${d.publisher.handle}) is indexed but not scored yet: unvetted. ${page}`;
8573
+ const lines = [
8574
+ `${d.skill.name}@${d.version.semver} (${d.skill.registry_label}, publisher ${d.publisher.handle}${d.publisher.verified ? ", verified publisher" : ""})`,
8575
+ `Verdict: ${d.verdict.label.toUpperCase()} \xB7 score ${d.verdict.score}/100 \xB7 ${d.verdict.scenarios_run} sandbox scenarios`
8576
+ ];
8577
+ const t = d.trace_summary;
8578
+ if (t) {
8579
+ const undeclared = t.egress_hosts.filter((h) => !h.declared).map((h) => h.host);
8580
+ lines.push(`Sandbox: contacted ${t.egress_hosts.length} host(s)${undeclared.length ? ` (undeclared: ${undeclared.slice(0, 5).join(", ")})` : ""}; read ${t.files_read.length} file(s); ${t.memory_writes.length} memory write(s)${t.tool_shadowing.length ? `; shadows tools: ${t.tool_shadowing.map((x) => x.tool).join(", ")}` : ""}.`);
8581
+ }
8582
+ for (const f of d.findings.slice(0, 5)) lines.push(`- [${f.severity}] ${f.title}`);
8583
+ if (d.verdict.label === "blocked" && d.last_safe_version) lines.push(`Last safe version: ${d.last_safe_version.semver} (score ${d.last_safe_version.score}).`);
8584
+ lines.push(d.verdict.label === "verified" ? "OK to install." : d.verdict.label === "caution" ? "Install only if the findings above are acceptable; tell the user what they are." : "Do not install. Tell the user why.");
8585
+ lines.push(`Evidence: ${page}`);
8586
+ return lines.join("\n");
8587
+ }
8588
+ async function searchSkills(query) {
8589
+ try {
8590
+ const res = await fetch(`${API}/api/v1/leaderboard?q=${encodeURIComponent(query)}`, { headers: { accept: "application/json", "user-agent": `vet-skills/${VERSION} mcp` }, signal: AbortSignal.timeout(1e4) });
8591
+ if (!res.ok) return `Search failed (HTTP ${res.status}).`;
8592
+ const d = await res.json();
8593
+ if (!d.rows.length) return `Nothing in the KillerSkills index matches "${query}".`;
8594
+ return [`${d.total} match(es) for "${query}", most installed first:`, ...d.rows.slice(0, 15).map((x) => `- ${x.skill.name} (${x.skill.registry}, ${x.skill.publisher}) \xB7 ${x.latest_verdict.label} ${x.latest_verdict.score} \xB7 ${x.install_count.toLocaleString()} installs \xB7 ${API}${x.skill.page}`)].join("\n");
8595
+ } catch (e) {
8596
+ return `Search failed (${e.message}).`;
8597
+ }
8598
+ }
8599
+ async function serveMcp() {
8600
+ const send = (msg) => process.stdout.write(JSON.stringify(msg) + "\n");
8601
+ const rl = createInterface({ input: process.stdin });
8602
+ for await (const line of rl) {
8603
+ if (!line.trim()) continue;
8604
+ let req;
8605
+ try {
8606
+ req = JSON.parse(line);
8607
+ } catch {
8608
+ send({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "parse error" } });
8609
+ continue;
8610
+ }
8611
+ if (req.id === void 0) continue;
8612
+ const ok = (result) => send({ jsonrpc: "2.0", id: req.id, result });
8613
+ switch (req.method) {
8614
+ case "initialize":
8615
+ ok({ protocolVersion: req.params?.protocolVersion ?? "2025-06-18", capabilities: { tools: {} }, serverInfo: { name: "killerskills", title: "KillerSkills", version: VERSION }, instructions: "Before installing any agent skill, plugin or MCP server, call check_skill. Do not install anything labelled blocked." });
8616
+ break;
8617
+ case "ping":
8618
+ ok({});
8619
+ break;
8620
+ case "tools/list":
8621
+ ok({ tools: TOOLS });
8622
+ break;
8623
+ case "tools/call": {
8624
+ const name = req.params?.name;
8625
+ const args = req.params?.arguments ?? {};
8626
+ const text = name === "check_skill" ? await checkSkill(String(args.name ?? ""), args.registry || void 0) : name === "search_skills" ? await searchSkills(String(args.query ?? "")) : null;
8627
+ if (text === null) send({ jsonrpc: "2.0", id: req.id, error: { code: -32602, message: `unknown tool ${name}` } });
8628
+ else ok({ content: [{ type: "text", text }], isError: false });
8629
+ break;
8630
+ }
8631
+ default:
8632
+ send({ jsonrpc: "2.0", id: req.id, error: { code: -32601, message: `method not found: ${req.method}` } });
8633
+ }
8634
+ }
8635
+ }
8636
+
8637
+ // src/hook.ts
8638
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
8639
+ import { homedir as homedir5 } from "node:os";
8640
+ import { join as join5 } from "node:path";
8034
8641
 
8035
8642
  // src/sync.ts
8036
- import { existsSync as existsSync2, rmSync } from "node:fs";
8037
- import { homedir as homedir2 } from "node:os";
8038
- import { join as join2 } from "node:path";
8643
+ import { existsSync as existsSync4, rmSync } from "node:fs";
8644
+ import { homedir as homedir4 } from "node:os";
8645
+ import { join as join4 } from "node:path";
8039
8646
  function skillDirs(name) {
8040
8647
  const bare = name.replace(/^.*\//, "").replace(/@.*$/, "");
8041
- return [join2(homedir2(), ".claude", "skills", bare), join2(process.cwd(), ".claude", "skills", bare), join2(homedir2(), ".claude", "plugins", bare)];
8648
+ return [join4(homedir4(), ".claude", "skills", bare), join4(process.cwd(), ".claude", "skills", bare), join4(homedir4(), ".claude", "plugins", bare)];
8042
8649
  }
8043
8650
  async function applyRemovals(pending, log = () => {
8044
8651
  }) {
@@ -8049,7 +8656,7 @@ async function applyRemovals(pending, log = () => {
8049
8656
  const detail = [];
8050
8657
  let failed = false;
8051
8658
  for (const it of items) {
8052
- const dirs = skillDirs(it.skill).filter((d) => existsSync2(d));
8659
+ const dirs = skillDirs(it.skill).filter((d) => existsSync4(d));
8053
8660
  if (!dirs.length) {
8054
8661
  detail.push(`${it.skill}: not on disk`);
8055
8662
  continue;
@@ -8200,24 +8807,201 @@ ${out}
8200
8807
  return 0;
8201
8808
  }
8202
8809
  function installClaudeCodeHook() {
8203
- const dir = join3(homedir3(), ".claude");
8204
- const path = join3(dir, "settings.json");
8205
- if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
8810
+ const dir = join5(homedir5(), ".claude");
8811
+ const path = join5(dir, "settings.json");
8812
+ if (!existsSync5(dir)) mkdirSync2(dir, { recursive: true });
8206
8813
  let settings = {};
8207
- if (existsSync3(path)) {
8814
+ if (existsSync5(path)) {
8208
8815
  try {
8209
- settings = JSON.parse(readFileSync2(path, "utf8"));
8816
+ settings = JSON.parse(readFileSync4(path, "utf8"));
8210
8817
  } catch {
8211
8818
  settings = {};
8212
8819
  }
8213
8820
  }
8214
8821
  const hooks = settings.hooks ??= {};
8215
8822
  const pre = hooks.PreToolUse ??= [];
8216
- const already = pre.some((h) => h.hooks?.some((x) => /vet-skills hook eval/.test(x.command)));
8217
- if (already) return { path, changed: false };
8218
- pre.push({ matcher: "Bash", hooks: [{ type: "command", command: "vet-skills hook eval" }] });
8219
- writeFileSync2(path, JSON.stringify(settings, null, 2) + "\n");
8220
- return { path, changed: true };
8823
+ const post = hooks.PostToolUse ??= [];
8824
+ let changed = false;
8825
+ if (!pre.some((h) => h.hooks?.some((x) => /vet-skills hook eval/.test(x.command)))) {
8826
+ pre.push({ matcher: "Bash", hooks: [{ type: "command", command: "vet-skills hook eval" }] });
8827
+ changed = true;
8828
+ }
8829
+ if (!post.some((h) => h.hooks?.some((x) => /vet-skills hook observe/.test(x.command)))) {
8830
+ post.push({ matcher: "Bash|Read|Write|Edit|MultiEdit|NotebookEdit|WebFetch|Skill|mcp__.*", hooks: [{ type: "command", command: "vet-skills hook observe" }] });
8831
+ changed = true;
8832
+ }
8833
+ if (changed) writeFileSync3(path, JSON.stringify(settings, null, 2) + "\n");
8834
+ return { path, changed };
8835
+ }
8836
+
8837
+ // src/runtime.ts
8838
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync as readdirSync3, statSync as statSync4, writeFileSync as writeFileSync4 } from "node:fs";
8839
+ import { homedir as homedir6 } from "node:os";
8840
+ import { join as join6 } from "node:path";
8841
+ var ACTIVE_MS = 30 * 6e4;
8842
+ var CRED = /(^|\/)(\.ssh|\.aws|\.npmrc|\.netrc|\.config\/gh|\.docker\/config\.json|\.kube\/config|\.gnupg|credentials|\.env(\.|$)|id_(rsa|ed25519|ecdsa)|keychain)/i;
8843
+ var MEMORY = /(^|\/)(MEMORY\.md|CLAUDE\.md|AGENTS\.md|\.cursorrules|\.clinerules|\.windsurfrules|GEMINI\.md|\.github\/copilot-instructions\.md)$/i;
8844
+ var DIR = join6(HOME, "runtime");
8845
+ function sessionFile(id) {
8846
+ return join6(DIR, `${id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 80)}.json`);
8847
+ }
8848
+ function readSession(id) {
8849
+ try {
8850
+ return JSON.parse(readFileSync5(sessionFile(id), "utf8"));
8851
+ } catch {
8852
+ return { active: null, verdicts: {}, reported: [] };
8853
+ }
8854
+ }
8855
+ function writeSession(id, s) {
8856
+ if (!existsSync6(DIR)) mkdirSync3(DIR, { recursive: true });
8857
+ writeFileSync4(sessionFile(id), JSON.stringify(s));
8858
+ }
8859
+ function hostsIn(cmd2) {
8860
+ const out = /* @__PURE__ */ new Set();
8861
+ for (const m of cmd2.matchAll(/https?:\/\/([a-zA-Z0-9.-]+\.[a-zA-Z]{2,}|\d{1,3}(?:\.\d{1,3}){3})(?::\d+)?/g)) out.add(m[1].toLowerCase());
8862
+ for (const m of cmd2.matchAll(/\b(?:ssh|scp|sftp|nc|ncat|netcat|telnet)\s+(?:-\S+\s+)*(?:[\w.-]+@)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,}|\d{1,3}(?:\.\d{1,3}){3})/g)) out.add(m[1].toLowerCase());
8863
+ return [...out];
8864
+ }
8865
+ function pathsIn(cmd2) {
8866
+ const read2 = /* @__PURE__ */ new Set();
8867
+ const written = /* @__PURE__ */ new Set();
8868
+ const norm = (p) => p.replace(/^\$HOME/, "~").replace(/^["']|["']$/g, "");
8869
+ for (const m of cmd2.matchAll(/(?:>>?|tee\s+(?:-a\s+)?)\s*["']?((?:~|\/|\$HOME)[^\s"'|;&]+)/g)) written.add(norm(m[1]));
8870
+ for (const m of cmd2.matchAll(/(?:^|[\s|;&(])(?:cat|less|head|tail|grep|cp|scp|base64|xxd|od|strings|python3?|node)\s+(?:-\S+\s+)*["']?((?:~|\/|\$HOME)[^\s"'|;&]+)/g)) read2.add(norm(m[1]));
8871
+ for (const m of cmd2.matchAll(/["']?((?:~|\$HOME)\/\.(?:ssh|aws|npmrc|netrc|config\/gh|docker|kube|gnupg)[^\s"'|;&]*)/g)) if (!written.has(norm(m[1]))) read2.add(norm(m[1]));
8872
+ return { read: [...read2], written: [...written] };
8873
+ }
8874
+ var isOutsideProject = (p) => (p.startsWith("~") || p.startsWith("/")) && !p.startsWith(process.cwd()) && !p.startsWith("/tmp") && !p.startsWith("/dev");
8875
+ var tilde = (p) => p.replace(homedir6(), "~");
8876
+ function attributed(session, toolName) {
8877
+ const m = toolName.match(/^mcp__([^_]+(?:_[^_]+)*?)__/);
8878
+ if (m) return m[1];
8879
+ if (session.active && Date.now() - session.active.since < ACTIVE_MS) return session.active.skill;
8880
+ return null;
8881
+ }
8882
+ async function verdictFor(session, skill) {
8883
+ const c2 = session.verdicts[skill];
8884
+ if (c2 && Date.now() - c2.at < 36e5) return c2.r;
8885
+ const r = await resolveSkill(skill).catch(() => null);
8886
+ session.verdicts[skill] = { at: Date.now(), r: r && r.ok ? r.data : null };
8887
+ return session.verdicts[skill].r;
8888
+ }
8889
+ function parseToolEvent(toolName, input) {
8890
+ const o = { kind: "other", hosts: [], read: [], written: [], skillInvoked: null };
8891
+ if (toolName === "Skill") {
8892
+ o.kind = "Skill";
8893
+ o.skillInvoked = String(input.skill ?? input.name ?? input.command ?? "").replace(/^\//, "").split(/\s/)[0] || null;
8894
+ return o;
8895
+ }
8896
+ if (toolName === "Bash" && typeof input.command === "string") {
8897
+ o.kind = "Bash";
8898
+ o.hosts = hostsIn(input.command);
8899
+ const p = pathsIn(input.command);
8900
+ o.read = p.read;
8901
+ o.written = p.written;
8902
+ return o;
8903
+ }
8904
+ if (toolName === "Read" && typeof input.file_path === "string") {
8905
+ o.kind = "Read";
8906
+ o.read = [tilde(input.file_path)];
8907
+ return o;
8908
+ }
8909
+ if ((toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit" || toolName === "NotebookEdit") && typeof input.file_path === "string") {
8910
+ o.kind = "Write";
8911
+ o.written = [tilde(input.file_path)];
8912
+ return o;
8913
+ }
8914
+ if (toolName === "WebFetch" && typeof input.url === "string") {
8915
+ o.kind = "WebFetch";
8916
+ try {
8917
+ o.hosts = [new URL(input.url).hostname.toLowerCase()];
8918
+ } catch {
8919
+ }
8920
+ return o;
8921
+ }
8922
+ if (toolName.startsWith("mcp__")) o.kind = "mcp";
8923
+ return o;
8924
+ }
8925
+ function deviations(skill, r, o, tool, session) {
8926
+ const out = [];
8927
+ const at = (/* @__PURE__ */ new Date()).toISOString();
8928
+ const semver = r?.version.semver ?? null;
8929
+ const page = r?.skill.page ?? null;
8930
+ const trace = r?.trace_summary ?? null;
8931
+ const declared = new Set((r?.version.declared_permissions.network ?? []).map((h) => h.toLowerCase()));
8932
+ const seenHosts = new Set((trace?.egress_hosts ?? []).map((h) => h.host.toLowerCase()));
8933
+ const seenReads = trace?.files_read ?? [];
8934
+ const seenWrites = trace?.files_written ?? [];
8935
+ const mk = (kind, detail) => out.push({ kind, skill, semver, detail, tool, at, session, page });
8936
+ for (const h of o.hosts) if (!declared.has(h) && !seenHosts.has(h) && !/^(localhost|127\.0\.0\.1|registry\.npmjs\.org|pypi\.org|files\.pythonhosted\.org|github\.com|api\.github\.com|raw\.githubusercontent\.com|killerskills\.ai)$/.test(h)) mk("egress_unexpected", `contacted ${h}; the sandbox saw ${seenHosts.size ? [...seenHosts].slice(0, 3).join(", ") : "no network activity"}${declared.size ? ` and it declares ${[...declared].join(", ")}` : ""}`);
8937
+ for (const p of o.read) if (CRED.test(p) && !seenReads.some((s) => s.includes(p.replace(/^~\//, "")))) mk("credential_read", `read ${p}; the sandbox never saw a credential path read`);
8938
+ for (const p of o.written) {
8939
+ if (MEMORY.test(p) && !trace?.memory_writes.length) mk("memory_write", `wrote ${p}; the sandbox saw no memory or instruction-file writes`);
8940
+ else if (isOutsideProject(p) && !CRED.test(p) && !MEMORY.test(p) && !seenWrites.some((s) => s.includes(p.replace(/^~\//, "")))) mk("outside_project_write", `wrote ${p}, outside the project; not seen in the sandbox`);
8941
+ }
8942
+ return out;
8943
+ }
8944
+ var LOG = join6(HOME, "runtime", "deviations.jsonl");
8945
+ function appendDeviations(ds) {
8946
+ if (!ds.length) return;
8947
+ if (!existsSync6(DIR)) mkdirSync3(DIR, { recursive: true });
8948
+ writeFileSync4(LOG, ds.map((d) => JSON.stringify(d)).join("\n") + "\n", { flag: "a" });
8949
+ }
8950
+ function readDeviations(days = 7) {
8951
+ if (!existsSync6(LOG)) return [];
8952
+ const since = Date.now() - days * 864e5;
8953
+ return readFileSync5(LOG, "utf8").split("\n").filter(Boolean).map((l) => {
8954
+ try {
8955
+ return JSON.parse(l);
8956
+ } catch {
8957
+ return null;
8958
+ }
8959
+ }).filter((d) => !!d && Date.parse(d.at) >= since);
8960
+ }
8961
+ async function observe(stdin) {
8962
+ let payload = {};
8963
+ try {
8964
+ payload = JSON.parse(stdin);
8965
+ } catch {
8966
+ return { code: 0, lines: [] };
8967
+ }
8968
+ const tool = payload.tool_name ?? "";
8969
+ const input = payload.tool_input ?? {};
8970
+ const sid = payload.session_id ?? "default";
8971
+ const session = readSession(sid);
8972
+ const o = parseToolEvent(tool, input);
8973
+ if (o.kind === "Skill") {
8974
+ if (o.skillInvoked) session.active = { skill: o.skillInvoked, since: Date.now() };
8975
+ writeSession(sid, session);
8976
+ return { code: 0, lines: [] };
8977
+ }
8978
+ const skill = attributed(session, tool);
8979
+ if (!skill || !o.hosts.length && !o.read.length && !o.written.length) return { code: 0, lines: [] };
8980
+ const r = await verdictFor(session, skill);
8981
+ const ds = deviations(skill, r, o, tool, payload.session_id ?? null).filter((d) => {
8982
+ const k = `${d.skill}|${d.kind}|${d.detail.split(";")[0]}`;
8983
+ if (session.reported.includes(k)) return false;
8984
+ session.reported.push(k);
8985
+ return true;
8986
+ });
8987
+ writeSession(sid, session);
8988
+ if (!ds.length) return { code: 0, lines: [] };
8989
+ appendDeviations(ds);
8990
+ if (readOrg()) await runtimeReport({ events: ds.map((d) => ({ skill: d.skill, semver: d.semver, kind: d.kind, detail: d.detail, tool: d.tool, at: d.at, session: d.session })) }).catch(() => null);
8991
+ const lines = ds.map((d) => `vet-skills \u26A0 ${d.skill}${d.semver ? `@${d.semver}` : ""} ${d.detail}. Not what its verdict is based on${d.page ? `: https://killerskills.ai${d.page}` : ""}`);
8992
+ const serious = ds.some((d) => d.kind === "egress_unexpected" || d.kind === "credential_read");
8993
+ return { code: serious ? 2 : 0, lines };
8994
+ }
8995
+ function pruneSessions() {
8996
+ if (!existsSync6(DIR)) return;
8997
+ for (const f of readdirSync3(DIR)) {
8998
+ if (!f.endsWith(".json")) continue;
8999
+ const p = join6(DIR, f);
9000
+ try {
9001
+ if (Date.now() - statSync4(p).mtimeMs > 864e5) writeFileSync4(p, "{}");
9002
+ } catch {
9003
+ }
9004
+ }
8221
9005
  }
8222
9006
 
8223
9007
  // src/index.ts
@@ -8228,10 +9012,13 @@ var { values, positionals } = parseArgs({
8228
9012
  reason: { type: "string" },
8229
9013
  org: { type: "string" },
8230
9014
  yes: { type: "boolean", short: "y" },
9015
+ lock: { type: "boolean" },
8231
9016
  json: { type: "boolean" },
8232
9017
  ci: { type: "boolean" },
8233
9018
  email: { type: "string" },
8234
9019
  help: { type: "boolean", short: "h" },
9020
+ project: { type: "boolean" },
9021
+ quiet: { type: "boolean", short: "q" },
8235
9022
  version: { type: "boolean", short: "v" },
8236
9023
  agent: { type: "string" },
8237
9024
  publisher: { type: "string" },
@@ -8240,7 +9027,7 @@ var { values, positionals } = parseArgs({
8240
9027
  });
8241
9028
  var [cmd, ...rest] = positionals;
8242
9029
  async function ask(question, choices) {
8243
- const rl = createInterface({ input: process.stdin, output: process.stderr });
9030
+ const rl = createInterface2({ input: process.stdin, output: process.stderr });
8244
9031
  return new Promise((res) => rl.question(question, (a) => {
8245
9032
  rl.close();
8246
9033
  const k = a.trim().toLowerCase()[0];
@@ -8264,9 +9051,15 @@ Get started:
8264
9051
  vet-skills policy show|set <file> view or replace the local policy
8265
9052
  vet-skills block <skill> [--reason] add to the personal block list
8266
9053
  vet-skills status org, policy version, last report, cache size
9054
+ vet-skills discover [--project] [--json] every MCP server, skill, plugin and hook on this machine, with verdicts
9055
+ vet-skills mcp run as an MCP server (check_skill, search_skills) for any agent
8267
9056
  vet-skills sync pull the org policy and apply pending removals
9057
+ vet-skills verify <skill|path> check the signed verdict against what is on disk
9058
+ vet-skills lock pin every installed skill's hash + attestation in vet-skills.lock
9059
+ vet-skills verify --lock offline: installed skills still match the lock and signatures verify
8268
9060
  vet-skills hook install claude-code register the Claude Code PreToolUse hook
8269
9061
  vet-skills hook eval (called by the agent) read hook JSON on stdin
9062
+ vet-skills runtime what installed skills did in real sessions that the sandbox never saw
8270
9063
 
8271
9064
  Docs: https://killerskills.ai/docs/cli
8272
9065
  `;
@@ -8344,8 +9137,8 @@ async function main() {
8344
9137
  usage();
8345
9138
  return 1;
8346
9139
  }
8347
- const dir = resolve(rest[0]);
8348
- if (!existsSync4(join4(dir, "SKILL.md")) && !existsSync4(join4(dir, "package.json"))) {
9140
+ const dir = resolve2(rest[0]);
9141
+ if (!existsSync7(join7(dir, "SKILL.md")) && !existsSync7(join7(dir, "package.json"))) {
8349
9142
  console.log(`${c.blocked("\u2717")} ${dir} has no SKILL.md or package.json`);
8350
9143
  return 1;
8351
9144
  }
@@ -8387,8 +9180,8 @@ async function main() {
8387
9180
  console.log(`${c.blocked("\u2717")} not enrolled in an organization. Run ${c.bold("vet-skills join <org> --token \u2026")} first.`);
8388
9181
  return 1;
8389
9182
  }
8390
- const dir = resolve(rest[0]);
8391
- if (!existsSync4(join4(dir, "SKILL.md"))) {
9183
+ const dir = resolve2(rest[0]);
9184
+ if (!existsSync7(join7(dir, "SKILL.md"))) {
8392
9185
  console.log(`${c.blocked("\u2717")} ${dir} has no SKILL.md (name and version come from its frontmatter)`);
8393
9186
  return 1;
8394
9187
  }
@@ -8432,7 +9225,7 @@ async function main() {
8432
9225
  console.error("usage: vet-skills join <org> --token <enroll token>");
8433
9226
  return 1;
8434
9227
  }
8435
- const machineId = createHash("sha256").update(`${hostname()}:${userInfo().username}`).digest("hex");
9228
+ const machineId = createHash2("sha256").update(`${hostname()}:${userInfo().username}`).digest("hex");
8436
9229
  const res = await enroll(slug, values.token, {
8437
9230
  developer_email: values.email,
8438
9231
  machine_id: machineId,
@@ -8480,7 +9273,7 @@ async function main() {
8480
9273
  console.error("usage: vet-skills policy set <file.yaml>");
8481
9274
  return 1;
8482
9275
  }
8483
- const text = readFileSync3(rest[1], "utf8");
9276
+ const text = readFileSync6(rest[1], "utf8");
8484
9277
  parsePolicyYaml(text);
8485
9278
  writePolicy(text);
8486
9279
  console.log(`${c.verified("\u2713")} Personal policy updated.`);
@@ -8550,6 +9343,99 @@ async function main() {
8550
9343
  }
8551
9344
  return 0;
8552
9345
  }
9346
+ case "verify": {
9347
+ if (values.lock) {
9348
+ const lock = readLock();
9349
+ if (!lock) {
9350
+ console.log(c.caution(`no ${LOCKFILE} in ${process.cwd()}; run \`vet-skills lock\` first`));
9351
+ return 1;
9352
+ }
9353
+ const rs = verifyLock(lock);
9354
+ for (const r2 of rs) console.log(`${r2.ok ? c.verified("\u2713") : c.blocked("\u2717")} ${r2.subject} ${c.muted(r2.detail)}`);
9355
+ const bad = rs.filter((r2) => !r2.ok).length;
9356
+ console.log(bad ? c.blocked(`${bad} of ${rs.length} failed`) : c.verified(`${rs.length} skill${rs.length === 1 ? "" : "s"} verified against ${LOCKFILE} (offline, ${lock.keys.length} pinned key${lock.keys.length === 1 ? "" : "s"})`));
9357
+ if (values.json) console.log(JSON.stringify(rs, null, 2));
9358
+ return bad ? 1 : 0;
9359
+ }
9360
+ if (!rest[0]) {
9361
+ console.log(c.caution("usage: vet-skills verify <skill>[@version] | <path> | --lock"));
9362
+ return 1;
9363
+ }
9364
+ const keys = await fetchKeys();
9365
+ if (!keys.length) console.log(c.caution(`could not fetch signing keys from ${API}/.well-known/killerskills-keys.json`));
9366
+ const r = await verifyOne(rest[0], keys);
9367
+ console.log(`${r.ok ? c.verified("\u2713 verified") : c.blocked("\u2717 not verified")} ${r.subject}
9368
+ ${r.detail}`);
9369
+ if (values.json) console.log(JSON.stringify(r, null, 2));
9370
+ return r.ok ? 0 : 1;
9371
+ }
9372
+ case "lock": {
9373
+ const { file, lock, missing } = await writeLock();
9374
+ console.log(`${c.verified("\u2713")} wrote ${file}: ${lock.skills.length} skill${lock.skills.length === 1 ? "" : "s"}, ${lock.keys.length} signing key${lock.keys.length === 1 ? "" : "s"} pinned`);
9375
+ for (const s of lock.skills) console.log(` ${s.attestation ? c.verified("\u2713") : c.caution("\xB7")} ${s.name} ${c.muted(s.verdict ? `${s.verdict.label} ${s.verdict.score}` : "no attestation (unscored or never crawled)")}`);
9376
+ if (missing.length) console.log(c.muted(`${missing.length} without an attestation are pinned by hash only; \`vet-skills verify --lock\` reports them.`));
9377
+ return 0;
9378
+ }
9379
+ case "runtime": {
9380
+ const ds = readDeviations(7);
9381
+ if (!ds.length) {
9382
+ console.log(c.muted("No deviations in the last 7 days: installed skills behaved the way the sandbox saw them (or no skill ran)."));
9383
+ return 0;
9384
+ }
9385
+ const by = /* @__PURE__ */ new Map();
9386
+ for (const d of ds) by.set(d.skill, [...by.get(d.skill) ?? [], d]);
9387
+ for (const [skill, list] of by) {
9388
+ console.log(`${c.caution("\u26A0")} ${skill}${list[0].semver ? `@${list[0].semver}` : ""} ${c.muted(`${list.length} deviation${list.length === 1 ? "" : "s"}${list[0].page ? ` \xB7 killerskills.ai${list[0].page}` : ""}`)}`);
9389
+ for (const d of list.slice(-6)) console.log(` ${d.at.slice(0, 16).replace("T", " ")} ${d.kind.replace("_", " ")} ${d.detail}`);
9390
+ }
9391
+ if (values.json) console.log(JSON.stringify(ds, null, 2));
9392
+ return 0;
9393
+ }
9394
+ case "discover": {
9395
+ const comps = discoverLocal({ project: values.project ? process.cwd() : void 0 });
9396
+ if (values.json) {
9397
+ console.log(JSON.stringify(comps, null, 2));
9398
+ } else if (!values.quiet) {
9399
+ if (!comps.length) console.log(c.muted("No agent configuration found in the usual places (~/.claude.json, ~/.cursor/mcp.json, Claude Desktop, Windsurf, Gemini CLI, Codex, ~/.claude/skills)."));
9400
+ const runnable = comps.filter((x) => x.kind === "mcp_server" || x.kind === "skill");
9401
+ const verdicts = /* @__PURE__ */ new Map();
9402
+ await Promise.all(runnable.slice(0, 40).map(async (x) => {
9403
+ const q = x.package ? x.package.name.replace(/^@/, "") : x.name;
9404
+ const r = await resolveSkill(q, x.package?.registry);
9405
+ const v = r.ok ? r.data.verdict : null;
9406
+ verdicts.set(`${x.kind}|${x.name}`, v?.label ? `${v.label} ${v.score ?? ""}`.trim() : "not vetted");
9407
+ }));
9408
+ const kinds = [["mcp_server", "MCP servers"], ["skill", "Skills"], ["plugin", "Plugins"], ["hook", "Hooks"], ["instructions", "Instruction files"]];
9409
+ for (const [k, label] of kinds) {
9410
+ const list = comps.filter((x) => x.kind === k);
9411
+ if (!list.length) continue;
9412
+ console.log(`
9413
+ ${label} (${list.length})`);
9414
+ for (const x of list) {
9415
+ const v = verdicts.get(`${x.kind}|${x.name}`);
9416
+ const tone = !v ? c.muted : v.startsWith("verified") ? c.verified : v.startsWith("blocked") ? c.blocked : c.caution;
9417
+ const what = x.package ? `${x.package.registry}:${x.package.name}` : x.urlHost ?? x.command ?? x.detail ?? "";
9418
+ const keys = x.envKeys.length || x.headerKeys.length ? c.muted(` \xB7 ${[...x.envKeys, ...x.headerKeys].slice(0, 4).join(", ")}`) : "";
9419
+ console.log(` ${x.name.padEnd(28)} ${tone((v ?? "").padEnd(14))} ${c.muted(what)}${keys} ${c.muted(x.path)}`);
9420
+ }
9421
+ }
9422
+ }
9423
+ if (readOrg()) {
9424
+ const r = await discoverReport(comps);
9425
+ if (r.ok) {
9426
+ if (!values.json) console.log(`
9427
+ ${c.verified("\u2713")} ${r.data.components} component${r.data.components === 1 ? "" : "s"} reported to ${readOrg().slug} (names only) \xB7 ${API}${r.data.dashboard}`);
9428
+ } else {
9429
+ console.error(c.caution(`report failed: ${r.error}`));
9430
+ return 1;
9431
+ }
9432
+ } else if (!values.json && !values.quiet) console.log(c.muted("\nNot enrolled: nothing was sent. `vet-skills join <org> --token <t>` reports this to your team's Discovery page."));
9433
+ return 0;
9434
+ }
9435
+ case "mcp": {
9436
+ await serveMcp();
9437
+ return 0;
9438
+ }
8553
9439
  case "sync": {
8554
9440
  if (!readOrg()) {
8555
9441
  console.log(c.muted("Not joined to an org; nothing to sync."));
@@ -8570,6 +9456,18 @@ async function main() {
8570
9456
  for await (const ch of process.stdin) chunks.push(ch);
8571
9457
  return hookEval(Buffer.concat(chunks).toString("utf8"));
8572
9458
  }
9459
+ if (sub === "observe") {
9460
+ const chunks = [];
9461
+ for await (const ch of process.stdin) chunks.push(ch);
9462
+ try {
9463
+ const r = await observe(Buffer.concat(chunks).toString("utf8"));
9464
+ for (const l of r.lines) process.stderr.write(l + "\n");
9465
+ if (Math.random() < 0.02) pruneSessions();
9466
+ return r.code;
9467
+ } catch {
9468
+ return 0;
9469
+ }
9470
+ }
8573
9471
  if (sub === "install") {
8574
9472
  const target = rest[1] ?? "claude-code";
8575
9473
  if (target !== "claude-code") {
@@ -8578,7 +9476,7 @@ async function main() {
8578
9476
  }
8579
9477
  const r = installClaudeCodeHook();
8580
9478
  console.log(r.changed ? `${c.verified("\u2713")} Claude Code hook installed in ${r.path}` : c.muted(`Hook already present in ${r.path}`));
8581
- console.log(c.muted("Every `skills add`, `claude plugin install`, and `claude mcp add` is now checked before it runs."));
9479
+ console.log(c.muted("Every `skills add`, `claude plugin install`, and `claude mcp add` is now checked before it runs, and what skills do in sessions is compared with their sandbox trace (vet-skills runtime)."));
8582
9480
  return 0;
8583
9481
  }
8584
9482
  usage();