@spardutti/claude-skills 2.55.0 → 2.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,7 +36,7 @@ npx @spardutti/claude-skills
36
36
  ```
37
37
 
38
38
  ```text
39
- Claude Skills Installer v2.55.0
39
+ Claude Skills Installer v2.56.0
40
40
 
41
41
  ── Frontend ──────────────────────────────
42
42
  ◉ react ◯ tanstack-query
@@ -200,7 +200,7 @@ scripts/ validate-skills.mjs — checks skill length caps and reference in
200
200
  edit-check.sh — PostToolUse check on each edited file: line-limit.sh, lint-ratchet.mjs, .edit-rules.json
201
201
  diary-check.mjs — run at the end of /ship; says when the diaries hold enough for /add-rule
202
202
  line-limit.sh — the 200-line ratchet, shared by the edit check, the ship gate and preflight
203
- gauntlet-selftest.sh — behavioural tests for the hooks (runs on pre-push)
203
+ gauntlet-selftest.sh — behavioural tests for the hooks (runs in preflight)
204
204
  gauntlet-survey.sh — what the hook would do in every repo under a directory
205
205
  preflight.sh — everything that must pass before a release
206
206
  check-freshness.mjs — compares each skill's `tracks:` versions to the registries
@@ -226,7 +226,7 @@ Skills live in `skills/<name>/SKILL.md`. Authoring conventions are in [CLAUDE.md
226
226
  - Before any release, run `bash scripts/preflight.sh` — validator, self-tests, a check that the
227
227
  hook scripts embedded in the CLI still match `scripts/`, detection against every repo under
228
228
  `~/projects`, and that the version is ahead of the registry. Do not publish while it is red.
229
- - Changing `scripts/gauntlet.sh`? Run `bash scripts/gauntlet-selftest.sh` (also on `pre-push`),
229
+ - Changing `scripts/gauntlet.sh`? Run `bash scripts/gauntlet-selftest.sh` (also in preflight),
230
230
  and run `bash scripts/gauntlet-survey.sh ~/projects` before releasing. Detection is where
231
231
  this hook keeps breaking, because real repos are shaped in ways invented test repos aren't —
232
232
  the survey is a dry run that reports what each of your repos would get without executing
@@ -35,31 +35,40 @@ test_then() { # test_then <snapshot> <test>: its content when the snapshot was
35
35
  else git show "$BASE:$2" 2>/dev/null; fi
36
36
  }
37
37
 
38
- # Never `| grep -q` under pipefail: diff exits 1 on any difference, and an early
39
- # grep exit fails the writer, so a match reads as none.
40
- tests_lost_lines() { # tests_lost_lines <snapshot> <family>
38
+ # The repo-relative paths a test names in quotes (./, ../, @/ or ~/), extension dropped.
39
+ test_names() { # test_names <test path> <owner prefix> < test text
40
+ grep -oE "['\"](\.{1,2}/|@/|~/)[^'\"]+['\"]" | tr -d "'\"" | while IFS= read -r s; do
41
+ case "$s" in @/*|~/*) printf '%s%s\n' "$2" "${s#?/}" ;; *) printf '%s/%s\n' "$(dirname "$1")" "$s" ;; esac
42
+ done | awk -F/ '{ n = 0; for (i = 1; i <= NF; i++) { if ($i == "..") n--; else if ($i != "." && $i != "") p[++n] = $i }
43
+ o = p[1]; for (i = 2; i <= n; i++) o = o "/" p[i]; print o }' | sed -E 's/\.(m|c)?[jt]sx?$//; s#/index$##'
44
+ }
45
+
46
+ # A test that lost a line can revive mutants only in the files it names, so only those lose their pass.
47
+ # Never `| grep -q` under pipefail: diff exits 1 on any difference, and an early grep exit fails the writer.
48
+ tests_lost_lines() { # tests_lost_lines <snapshot> <family> <file> <owner prefix>
41
49
  [ -f "$1/manifest" ] || return 0
50
+ local f="${3%.*}"; f=${f%/index}
42
51
  while IFS= read -r t; do
43
52
  [ -n "$t" ] || continue
44
- case "$(diff <(test_then "$1" "$t") <(cat "$t" 2>/dev/null))" in *$'\n<'*) return 0 ;; esac
53
+ case "$(diff <(test_then "$1" "$t") <(cat "$t" 2>/dev/null))" in *$'\n<'*) ;; *) continue ;; esac
54
+ [ -n "$({ test_then "$1" "$t"; cat "$t" 2>/dev/null || true; } | test_names "$t" "$4" | grep -xF "$f")" ] && return 0
45
55
  done <<< "$({ cat "$1/manifest"; changed_tests "$2"; } | sort -u)"
46
56
  return 1
47
57
  }
48
58
 
49
59
  # Sets OWNED to the files that still need mutating.
50
60
  files_split() { # files_split <context> <owner> <label>
51
- fam=$(family_of "$2/."); kept=""; rest=""
61
+ fam=$(family_of "$2/."); kept=""; rest=""; b=""; [ "$2" != "." ] && b="$2/"
52
62
  while IFS= read -r f; do
53
63
  [ -n "$f" ] || continue
54
64
  r=$(file_receipt "$1" "$f")
55
- if [ -f "$r" ] && ! tests_lost_lines "$(cat "$r")" "$fam"; then kept="$kept ${f#"$2"/}"
65
+ if [ -f "$r" ] && ! tests_lost_lines "$(cat "$r")" "$fam" "$f" "${b}"; then kept="$kept ${f#"$2"/}"
56
66
  else rest="$rest$f"$'\n'; fi
57
67
  done <<< "$OWNED"
58
68
  OWNED=${rest%$'\n'}
59
69
  [ -n "$kept" ] || return 0
60
70
  echo " $3 stryker — ok, not re-run: passed and unchanged since:$kept"
61
71
  echo " A change in a file they call is not re-checked."
62
- b=""; [ "$2" != "." ] && b="$2/"
63
72
  [ -z "$OWNED" ] && stryker_page_tests "$b" "$3"
64
73
  return 0
65
74
  }
@@ -14,7 +14,7 @@ function records(dir) {
14
14
  export function tally(findings) {
15
15
  const by = {};
16
16
  for (const f of findings) {
17
- const s = (by[f.by.split(":")[0]] ??= { found: 0, confirmed: 0, refuted: 0, unconfirmed: 0, fixed: 0 });
17
+ const s = (by[f.by.split(":")[0]] ??= { found: 0, confirmed: 0, refuted: 0, unconfirmed: 0, skipped: 0, fixed: 0 });
18
18
  s.found++; s[f.verdict]++; if (f.fixed) s.fixed++;
19
19
  }
20
20
  return by;
@@ -6,7 +6,7 @@ import { git, parseReport, prSize } from "./ship-log-parse.mjs";
6
6
  import { printReport, tally } from "./ship-log-report.mjs";
7
7
 
8
8
  const HERE = dirname(resolve(process.argv[1]));
9
- const VERDICTS = ["confirmed", "refuted", "unconfirmed"];
9
+ const VERDICTS = ["confirmed", "refuted", "unconfirmed", "skipped"];
10
10
  const now = () => new Date().toISOString().replace(/\.\d+Z$/, "Z");
11
11
 
12
12
  // gate-config.sh owns the config files and their order, so the gate and this agree on "on".
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spardutti/claude-skills",
3
- "version": "2.55.0",
3
+ "version": "2.56.0",
4
4
  "description": "Guardrails for Claude Code — best-practice skills, planning commands, and delivery gates.",
5
5
  "type": "module",
6
6
  "repository": {