@iceinvein/agent-skills 0.23.3 → 0.23.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iceinvein/agent-skills",
3
- "version": "0.23.3",
3
+ "version": "0.23.4",
4
4
  "description": "Install agent skills into AI coding tools",
5
5
  "author": "iceinvein",
6
6
  "license": "MIT",
package/skills/index.json CHANGED
@@ -295,7 +295,7 @@
295
295
  "name": "sluice",
296
296
  "description": "Routes work by change shape into four channels (bypass, fast, main, deep) and applies only the rules each channel needs, so a one-line fix does not pay the cost of a multi-subsystem build. Carries nine rules as one-liners in the router and the full treatment in references read only on friction. Checks the finished plan with plan.sh validate rather than trusting it to memory, seeds the run state from it, keeps a deep run's task breakdown in .sluice/run.json so a statusline segment, one status command and a SessionStart hook can answer where the run is (the hook prints a live run at every session start, compaction included), and closes each run with a ledger read out of the session transcript: elapsed, tools, tokens, and what each dispatched agent cost where the transcript recorded it. Two Stop hooks hold a handback: one refuses a tree that moved since its last recorded check, the other refuses a changed existing test not proven to fail on the session's starting code (or recorded with a reason). Claude Code only; stands down where the superpowers pipeline governs the repo.",
297
297
  "type": "prompt",
298
- "version": "0.25.3"
298
+ "version": "0.25.4"
299
299
  },
300
300
  {
301
301
  "name": "temporal-coupling-detector",
@@ -596,12 +596,17 @@ $(cd "$MAIN_ROOT" && pwd -P)"
596
596
  exit 0
597
597
  fi
598
598
 
599
- mk_dir "$TREE/.sluice" "$TREE"
600
- # As in verify: a record git can see moves the tree it records.
601
- git -C "$TREE" check-ignore -q .sluice/tests-changed || {
602
- err "$TREE/.sluice/.gitignore does not ignore tests-changed, so the record would move the tree it records; add * to it"
603
- exit 1
604
- }
599
+ # In the repo's common git dir rather than the tree, so every worktree reads
600
+ # the same records: a test recorded where it was edited still counts in the
601
+ # tree it is merged into. Inside the git dir it is never content of the tree,
602
+ # so it cannot move the tree it records. One file per call, because sessions
603
+ # in several worktrees record at once and bash splits a long append into
604
+ # several writes that interleave. The tree's own .sluice/tests-changed is
605
+ # where records were written before, and is still read.
606
+ COMMON="$(git -C "$TREE" rev-parse --path-format=absolute --git-common-dir 2>/dev/null)"
607
+ [ -n "$COMMON" ] || { err "could not find the git dir of $TREE, so nothing was recorded"; exit 1; }
608
+ RECORDS="$COMMON/sluice/tests-changed"
609
+ mkdir -p "$RECORDS" || { err "could not make $RECORDS"; exit 1; }
605
610
 
606
611
  # Hashed path-aware, so filters apply, the way the stop gate hashes it. A
607
612
  # directory where the file was (a fixture split into many) is that file's
@@ -630,14 +635,16 @@ $(cd "$MAIN_ROOT" && pwd -P)"
630
635
  while IFS= read -r p; do
631
636
  sha="$(current_blob "$p")" || exit 1
632
637
  found=""
633
- if [ -f "$TREE/.sluice/tests-changed" ]; then
638
+ for rec in "$RECORDS"/* "$TREE/.sluice/tests-changed"; do
639
+ [ -f "$rec" ] || continue
634
640
  while IFS=$'\t' read -r rec_sha rec_path rest; do
635
641
  if [ "$rec_sha" = "$sha" ] && [ "$rec_path" = "$p" ]; then
636
642
  found=1
637
643
  break
638
644
  fi
639
- done <"$TREE/.sluice/tests-changed"
640
- fi
645
+ done <"$rec"
646
+ [ -n "$found" ] && break
647
+ done
641
648
  [ -n "$found" ] || UNRECORDED="$UNRECORDED$p"$'\n'
642
649
  done <<<"$FLAGGED"
643
650
  FLAGGED="${UNRECORDED%$'\n'}"
@@ -754,7 +761,13 @@ $(cd "$MAIN_ROOT" && pwd -P)"
754
761
  "
755
762
  COUNT=$((COUNT + 1))
756
763
  done <<<"$FLAGGED"
757
- printf '%s' "$LINES" >>"$TREE/.sluice/tests-changed" || { err "could not write $TREE/.sluice/tests-changed"; exit 1; }
764
+ # Written under a dot name and renamed, so a reader never sees half of it.
765
+ NEW="$(mktemp "$RECORDS/.XXXXXX")" || { err "could not make a record file in $RECORDS"; exit 1; }
766
+ printf '%s' "$LINES" >"$NEW" && mv "$NEW" "$RECORDS/${NEW##*/.}" || {
767
+ rm -f "$NEW"
768
+ err "could not write a record to $RECORDS"
769
+ exit 1
770
+ }
758
771
  echo "sluice: recorded $COUNT changed test(s) as $STATUS"
759
772
  [ -z "$SKIPPED" ] || echo "sluice: not recorded, since no run can prove a deletion: $SKIPPED; record it with --none <reason>"
760
773
  exit 0
@@ -240,7 +240,7 @@ fi
240
240
  # A test edited until it agrees with the new code proves nothing about that
241
241
  # code, and a passing check cannot tell that edit from an honest one. So a
242
242
  # changed existing test (a removed line, a deletion, a skip or focus marker,
243
- # as test-changes.sh decides) needs a line in .sluice/tests-changed naming its
243
+ # as test-changes.sh decides) needs a line in the repo's tests-changed record naming its
244
244
  # current content: either proved red on the session's base by
245
245
  # `status.sh tests-changed -- <cmd>`, or recorded unproven with a reason. An
246
246
  # edit made after its record names other content and is refused again. A new
@@ -261,6 +261,17 @@ test_gate() {
261
261
  flagged="$(bash "$here/test-changes.sh" "$moved_tree" "$base" 2>/dev/null)" || return 0
262
262
  [ -n "$flagged" ] || return 0
263
263
 
264
+ # Records live in the repo's common git dir, one file per status.sh call,
265
+ # shared by every worktree, so a test recorded in the worktree it was edited
266
+ # in still counts once merged here. A record names content, not a tree, so it
267
+ # holds wherever that content is. The tree's own .sluice/tests-changed is
268
+ # where records were written before, and those still stand.
269
+ local common records rec
270
+ common="$(git -C "$moved_tree" rev-parse --path-format=absolute --git-common-dir 2>/dev/null)"
271
+ records=()
272
+ [ -n "$common" ] && records+=("$common/sluice/tests-changed"/*)
273
+ records+=("$moved_tree/.sluice/tests-changed")
274
+
264
275
  missing=""
265
276
  while IFS= read -r p; do
266
277
  if [ -f "$moved_tree/$p" ]; then
@@ -278,14 +289,16 @@ test_gate() {
278
289
  sha="-"
279
290
  fi
280
291
  found=""
281
- if [ -f "$moved_tree/.sluice/tests-changed" ]; then
292
+ for rec in "${records[@]}"; do
293
+ [ -f "$rec" ] || continue
282
294
  while IFS=$'\t' read -r rec_sha rec_path rest; do
283
295
  if [ "$rec_sha" = "$sha" ] && [ "$rec_path" = "$p" ]; then
284
296
  found=1
285
297
  break
286
298
  fi
287
- done <"$moved_tree/.sluice/tests-changed"
288
- fi
299
+ done <"$rec"
300
+ [ -n "$found" ] && break
301
+ done
289
302
  [ -n "$found" ] || missing="$missing$p"$'\n'
290
303
  done <<<"$flagged"
291
304
  [ -n "$missing" ] || return 0
@@ -296,7 +309,7 @@ test_gate() {
296
309
  decision: "block",
297
310
  reason: ("sluice: this session changed existing tests in a way that asks less of the code (an edited or removed assertion, a deleted test, a skip or focus marker), and nothing records why: "
298
311
  + ($paths | split("\n") | map(select(. != "") | gsub("[\u0000-\u001f\u007f]"; "")) | join(", "))
299
- + ". A test bent to fit new code proves nothing about it, so each one needs a record against the session base \($base). Prove it fails on the old code: status.sh tests-changed --because \"<the behaviour the change replaces>\" -- <the suite, scoped to these files> (the run is in a scratch worktree of the base, so a node suite usually needs --with node_modules). If it cannot run on the old code, record why: status.sh tests-changed --because \"<the behaviour the change replaces>\" --none \"<why it cannot run on the old code>\". No run can prove a deleted test, so prove the edited ones first, then record each deletion with --none. --only <path> proves or records just those paths, so a fixture that cannot be proved can go to --none --only <fixture> on its own. Then name each changed test, and why it changed, in your reply.")
312
+ + ". A test bent to fit new code proves nothing about it, so each one needs a record against the session base \($base). Prove it fails on the old code: status.sh tests-changed --because \"<the behaviour the change replaces>\" -- <the suite, scoped to these files> (the run is in a scratch worktree of the base, so a node suite usually needs --with node_modules). If it cannot run on the old code, record why: status.sh tests-changed --because \"<the behaviour the change replaces>\" --none \"<why it cannot run on the old code>\". No run can prove a deleted test, so prove the edited ones first, then record each deletion with --none. --only <path> proves or records just those paths, so a fixture that cannot be proved can go to --none --only <fixture> on its own. Then name each changed test, and why it changed, in your reply. The base is where this tree stood when the session opened, so a test that arrived through a merge of another session into this tree since then is listed too. Do not give a reason for a change that is not yours: record it as what it is, status.sh tests-changed --because \"arrived through the merge of <branch>, not from this session\" --none \"not this session to prove\" --only <path>, and name it in your reply as not from this session.")
300
313
  }'
301
314
  return 1
302
315
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sluice",
3
- "version": "0.25.3",
3
+ "version": "0.25.4",
4
4
  "description": "Routes work by change shape into four channels (bypass, fast, main, deep) and applies only the rules each channel needs, so a one-line fix does not pay the cost of a multi-subsystem build. Carries nine rules as one-liners in the router and the full treatment in references read only on friction. Checks the finished plan with plan.sh validate rather than trusting it to memory, seeds the run state from it, keeps a deep run's task breakdown in .sluice/run.json so a statusline segment, one status command and a SessionStart hook can answer where the run is (the hook prints a live run at every session start, compaction included), and closes each run with a ledger read out of the session transcript: elapsed, tools, tokens, and what each dispatched agent cost where the transcript recorded it. Two Stop hooks hold a handback: one refuses a tree that moved since its last recorded check, the other refuses a changed existing test not proven to fail on the session's starting code (or recorded with a reason). Claude Code only; stands down where the superpowers pipeline governs the repo.",
5
5
  "author": "iceinvein",
6
6
  "type": "prompt",