skill-checker 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -206,15 +206,12 @@ ${tailContent}` : headContent;
206
206
  // src/checks/structural.ts
207
207
  var HYPHEN_CASE_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
208
208
  var MAX_NAME_LENGTH = 64;
209
- var EXECUTABLE_EXTENSIONS = /* @__PURE__ */ new Set([
210
- ".exe",
211
- ".bat",
212
- ".cmd",
209
+ var SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
213
210
  ".sh",
214
211
  ".bash",
215
212
  ".ps1",
216
- ".com",
217
- ".msi"
213
+ ".bat",
214
+ ".cmd"
218
215
  ]);
219
216
  var BINARY_EXTENSIONS2 = /* @__PURE__ */ new Set([
220
217
  ".exe",
@@ -226,6 +223,10 @@ var BINARY_EXTENSIONS2 = /* @__PURE__ */ new Set([
226
223
  ".class",
227
224
  ".pyc"
228
225
  ]);
226
+ var INSTALLER_EXTENSIONS = /* @__PURE__ */ new Set([
227
+ ".com",
228
+ ".msi"
229
+ ]);
229
230
  var structuralChecks = {
230
231
  name: "Structural Validity",
231
232
  category: "STRUCT",
@@ -279,7 +280,7 @@ var structuralChecks = {
279
280
  }
280
281
  for (const file of skill.files) {
281
282
  const ext = file.extension.toLowerCase();
282
- if (BINARY_EXTENSIONS2.has(ext) || EXECUTABLE_EXTENSIONS.has(ext)) {
283
+ if (BINARY_EXTENSIONS2.has(ext) || INSTALLER_EXTENSIONS.has(ext)) {
283
284
  results.push({
284
285
  id: "STRUCT-006",
285
286
  category: "STRUCT",
@@ -288,6 +289,15 @@ var structuralChecks = {
288
289
  message: `Found unexpected file: ${file.path} (${ext})`,
289
290
  source: file.path
290
291
  });
292
+ } else if (SCRIPT_EXTENSIONS.has(ext)) {
293
+ results.push({
294
+ id: "STRUCT-006",
295
+ category: "STRUCT",
296
+ severity: "LOW",
297
+ title: "Script file present",
298
+ message: `Found script file: ${file.path} (${ext}). Content is scanned separately.`,
299
+ source: file.path
300
+ });
291
301
  }
292
302
  }
293
303
  const name = skill.frontmatter.name;
@@ -372,6 +382,15 @@ function isInDocumentationContext(lines, lineIndex) {
372
382
  }
373
383
  return false;
374
384
  }
385
+ function isNearDocumentationHeader(lines, lineIndex) {
386
+ for (let i = lineIndex; i >= Math.max(0, lineIndex - 15); i--) {
387
+ const l = lines[i];
388
+ if (/^#{1,4}\s+.*(install|setup|prerequisite|requirement|depend|getting\s+started|quickstart)/i.test(l)) {
389
+ return true;
390
+ }
391
+ }
392
+ return false;
393
+ }
375
394
  function isLicenseFile(filePath) {
376
395
  const name = filePath.split("/").pop()?.toUpperCase() ?? "";
377
396
  const base = name.replace(/\.[^.]+$/, "");
@@ -1715,14 +1734,58 @@ var supplyChainChecks = {
1715
1734
  if (NPM_INSTALL_PATTERN.test(line) || PIP_INSTALL_PATTERN.test(line)) {
1716
1735
  const allLines = getAllLines(skill);
1717
1736
  const globalIdx = findGlobalLineIndex(allLines, source, lineNum);
1718
- const isDoc = globalIdx >= 0 && isInDocumentationContext(
1737
+ const isDoc = source === "SKILL.md" && globalIdx >= 0 && isInDocumentationContext(
1719
1738
  allLines.map((l) => l.line),
1720
1739
  globalIdx
1721
1740
  );
1722
- if (!isDoc) {
1741
+ const srcLines = getLinesForSource(skill, source);
1742
+ const localIdx = getLocalIndex(source, lineNum, skill.bodyStartLine);
1743
+ const inCodeBlock = localIdx >= 0 && isInCodeBlock(srcLines, localIdx);
1744
+ if (isDoc && !inCodeBlock) {
1745
+ } else {
1723
1746
  let severity = "HIGH";
1724
1747
  let reducedFrom;
1725
1748
  let msgSuffix = "";
1749
+ if (inCodeBlock) {
1750
+ const isNearDoc = source === "SKILL.md" && globalIdx >= 0 && isNearDocumentationHeader(
1751
+ allLines.map((l) => l.line),
1752
+ globalIdx
1753
+ );
1754
+ if (isNearDoc) {
1755
+ severity = "LOW";
1756
+ reducedFrom = "HIGH";
1757
+ msgSuffix = " [reduced: in code block within documentation]";
1758
+ } else {
1759
+ const r = reduceSeverity(severity, "in code block");
1760
+ severity = r.severity;
1761
+ reducedFrom = r.reducedFrom;
1762
+ msgSuffix = ` ${r.annotation}`;
1763
+ }
1764
+ }
1765
+ results.push({
1766
+ id: "SUPPLY-003",
1767
+ category: "SUPPLY",
1768
+ severity,
1769
+ title: "Package installation command",
1770
+ message: `${source}:${lineNum}: Installs packages. Verify package names are legitimate.${msgSuffix}`,
1771
+ line: lineNum,
1772
+ snippet: line.trim().slice(0, 120),
1773
+ source,
1774
+ reducedFrom
1775
+ });
1776
+ }
1777
+ }
1778
+ if (GIT_CLONE_PATTERN.test(line)) {
1779
+ const allLines = getAllLines(skill);
1780
+ const globalIdx = findGlobalLineIndex(allLines, source, lineNum);
1781
+ const isDoc = source === "SKILL.md" && globalIdx >= 0 && isInDocumentationContext(
1782
+ allLines.map((l) => l.line),
1783
+ globalIdx
1784
+ );
1785
+ if (!isDoc) {
1786
+ let severity = "MEDIUM";
1787
+ let reducedFrom;
1788
+ let msgSuffix = "";
1726
1789
  const srcLines = getLinesForSource(skill, source);
1727
1790
  const localIdx = getLocalIndex(source, lineNum, skill.bodyStartLine);
1728
1791
  if (localIdx >= 0 && isInCodeBlock(srcLines, localIdx)) {
@@ -1732,11 +1795,11 @@ var supplyChainChecks = {
1732
1795
  msgSuffix = ` ${r.annotation}`;
1733
1796
  }
1734
1797
  results.push({
1735
- id: "SUPPLY-003",
1798
+ id: "SUPPLY-006",
1736
1799
  category: "SUPPLY",
1737
1800
  severity,
1738
- title: "Package installation command",
1739
- message: `${source}:${lineNum}: Installs packages. Verify package names are legitimate.${msgSuffix}`,
1801
+ title: "git clone command",
1802
+ message: `${source}:${lineNum}: Clones a git repository. Verify the source.${msgSuffix}`,
1740
1803
  line: lineNum,
1741
1804
  snippet: line.trim().slice(0, 120),
1742
1805
  source,
@@ -1744,18 +1807,6 @@ var supplyChainChecks = {
1744
1807
  });
1745
1808
  }
1746
1809
  }
1747
- if (GIT_CLONE_PATTERN.test(line)) {
1748
- results.push({
1749
- id: "SUPPLY-006",
1750
- category: "SUPPLY",
1751
- severity: "MEDIUM",
1752
- title: "git clone command",
1753
- message: `${source}:${lineNum}: Clones a git repository. Verify the source.`,
1754
- line: lineNum,
1755
- snippet: line.trim().slice(0, 120),
1756
- source
1757
- });
1758
- }
1759
1810
  const urls = line.match(URL_PATTERN) || [];
1760
1811
  for (const url of urls) {
1761
1812
  if (url.startsWith("http://")) {