@iceinvein/agent-skills 0.23.5 → 0.23.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/package.json +1 -1
- package/skills/index.json +2 -2
- package/skills/sluice/SKILL.md +8 -0
- package/skills/sluice/evals/README.md +3 -2
- package/skills/sluice/evals/deep-plan-traces-the-example/case.yaml +4 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/fixture.sh +151 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/graders/announces-deep-channel.md +12 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/graders/design-written-to-docs.md +5 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/graders/no-source-edit.md +11 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/graders/no-source-write.md +11 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/graders/sluice-fired.md +5 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/graders/spec-has-a-trace.md +7 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/graders/stopped-for-signoff.md +8 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/graders/trace-finds-no-accepted-slide.md +27 -0
- package/skills/sluice/evals/deep-plan-traces-the-example/prompt.md +17 -0
- package/skills/sluice/evals/rules.json +12 -2
- package/skills/sluice/references/deep-channel.md +38 -0
- package/skills/sluice/references/status.md +95 -4
- package/skills/sluice/scripts/board-index.sh +160 -0
- package/skills/sluice/scripts/board.sh +304 -0
- package/skills/sluice/scripts/status.sh +50 -3
- package/skills/sluice/scripts/stop-guard.sh +107 -44
- package/skills/sluice/skill.json +2 -2
|
@@ -62,6 +62,106 @@ if [ -n "$input" ]; then
|
|
|
62
62
|
sid="$(printf '%s' "$input" | jq -r '.session_id // empty' 2>/dev/null || true)"
|
|
63
63
|
transcript="$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/null || true)"
|
|
64
64
|
fi
|
|
65
|
+
|
|
66
|
+
# The run the session's own tree answers for, and only that: the state beside
|
|
67
|
+
# it, or the state it forwarded into a worktree when `move` sent the run on
|
|
68
|
+
# without the session. status.sh also lets a tree with no run of its own read
|
|
69
|
+
# the main worktree's, and that one is not taken here: a Stop in such a tree may
|
|
70
|
+
# be an unrelated session, and a remedy printed to it would reach into somebody
|
|
71
|
+
# else's run.
|
|
72
|
+
#
|
|
73
|
+
# The forward is read here rather than left to status.sh's resolution because
|
|
74
|
+
# the two questions differ. Resolution answers "which run can this tree read",
|
|
75
|
+
# which is the right question for a render and the wrong one for a refusal. The
|
|
76
|
+
# tree named in the note is then passed as `--dir`, so what follows asks about
|
|
77
|
+
# one named tree and carries no layout knowledge of its own.
|
|
78
|
+
#
|
|
79
|
+
# The run this session opened in a worktree it never entered is its own too,
|
|
80
|
+
# found through the pointer `init` left at the main tree, and it comes ahead of
|
|
81
|
+
# the forward: the forward names whichever run was moved last, which with
|
|
82
|
+
# several controllers in the main tree may be another session's.
|
|
83
|
+
#
|
|
84
|
+
# Sets top to the stop's tree and run_tree to the tree holding that run, or
|
|
85
|
+
# leaves run_tree empty when there is none. One function for the run guard and
|
|
86
|
+
# the board, so the run that keeps a deep session off the board is the run the
|
|
87
|
+
# guard would refuse over.
|
|
88
|
+
top=""
|
|
89
|
+
run_tree=""
|
|
90
|
+
resolved=""
|
|
91
|
+
resolve_run_tree() {
|
|
92
|
+
local main session_tree="" forward=""
|
|
93
|
+
resolved=1
|
|
94
|
+
run_tree=""
|
|
95
|
+
top="$(git -C "$cwd" rev-parse --show-toplevel 2>/dev/null)"
|
|
96
|
+
[ -n "$top" ] || top="$cwd"
|
|
97
|
+
case "$sid" in
|
|
98
|
+
"" | */* | .*) ;;
|
|
99
|
+
*)
|
|
100
|
+
main="$(git -C "$cwd" worktree list --porcelain 2>/dev/null | sed -n '1s/^worktree //p')"
|
|
101
|
+
[ -n "$main" ] && [ -f "$main/.sluice/sessions/$sid" ] \
|
|
102
|
+
&& IFS= read -r session_tree <"$main/.sluice/sessions/$sid" 2>/dev/null
|
|
103
|
+
if [ -z "$session_tree" ] || [ ! -f "$session_tree/.sluice/run.json" ] \
|
|
104
|
+
|| [ "$(jq -r '.session // empty' "$session_tree/.sluice/run.json" 2>/dev/null)" != "$sid" ]; then
|
|
105
|
+
session_tree=""
|
|
106
|
+
fi
|
|
107
|
+
;;
|
|
108
|
+
esac
|
|
109
|
+
if [ -f "$top/.sluice/run.json" ]; then
|
|
110
|
+
run_tree="$top"
|
|
111
|
+
elif [ -n "$session_tree" ]; then
|
|
112
|
+
run_tree="$session_tree"
|
|
113
|
+
elif [ -f "$top/.sluice/run.at" ]; then
|
|
114
|
+
IFS= read -r forward <"$top/.sluice/run.at" 2>/dev/null || return 0
|
|
115
|
+
# A note outliving the run it named is stale, not a run to refuse a stop over.
|
|
116
|
+
[ -n "$forward" ] && [ -f "$forward/.sluice/run.json" ] || return 0
|
|
117
|
+
run_tree="$forward"
|
|
118
|
+
fi
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# A stop let through is the session handing back, so the board marks it. A
|
|
122
|
+
# trap rather than a call before each exit: the hook lets a stop through from
|
|
123
|
+
# a dozen places, and a new one added later is covered without anyone having
|
|
124
|
+
# to remember the board. Every block decision sets refused first, since a
|
|
125
|
+
# refused stop is the session still working. The board's output and failure
|
|
126
|
+
# are dropped: stdout carries the decision, and the hook always exits 0.
|
|
127
|
+
#
|
|
128
|
+
# A deep session whose run is live keeps its entry, because the board draws the
|
|
129
|
+
# run's bar for it. Whether the run is live is asked here rather than taken
|
|
130
|
+
# from the run guard, since most exits come before the guard runs, and a deep
|
|
131
|
+
# session mid-run must not read as handed back on any of them. Resolving costs
|
|
132
|
+
# git calls on every stop, so it is skipped for a session with no entry, and
|
|
133
|
+
# not repeated when the run guard already did it.
|
|
134
|
+
#
|
|
135
|
+
# The run resolved is only the one this tree can reach, which through a forward
|
|
136
|
+
# or a shared tree may be another session's; that run's bar is not this
|
|
137
|
+
# session's work, so the entry is kept only for a run that names this session.
|
|
138
|
+
# A run naming no session is no session's own, as the board draws it, and a
|
|
139
|
+
# state file that cannot be read names nobody it can be kept for.
|
|
140
|
+
refused=""
|
|
141
|
+
board_handback() {
|
|
142
|
+
local keep="" root owner
|
|
143
|
+
[ -z "$refused" ] && [ -n "$sid" ] || return 0
|
|
144
|
+
case "$sid" in */* | .*) return 0 ;; esac
|
|
145
|
+
# Must match the root board-index.sh and board.sh resolve.
|
|
146
|
+
if [ -n "${SLUICE_BOARD_DIR:-}" ]; then
|
|
147
|
+
root="$SLUICE_BOARD_DIR"
|
|
148
|
+
elif [ -n "${CLAUDE_CONFIG_DIR:-}" ]; then
|
|
149
|
+
root="$CLAUDE_CONFIG_DIR/sluice/board"
|
|
150
|
+
elif [ -n "${HOME:-}" ]; then
|
|
151
|
+
root="$HOME/.claude/sluice/board"
|
|
152
|
+
else
|
|
153
|
+
return 0
|
|
154
|
+
fi
|
|
155
|
+
[ -f "$root/sessions/$sid.json" ] || return 0
|
|
156
|
+
[ -n "$resolved" ] || resolve_run_tree
|
|
157
|
+
if [ -n "$run_tree" ] && owner="$(jq -r '.session // empty' "$run_tree/.sluice/run.json" 2>/dev/null)" \
|
|
158
|
+
&& [ "$owner" = "$sid" ]; then
|
|
159
|
+
keep="--keep-deep"
|
|
160
|
+
fi
|
|
161
|
+
bash "$here/board-index.sh" handback "$sid" $keep >/dev/null 2>&1 || true
|
|
162
|
+
}
|
|
163
|
+
trap board_handback EXIT
|
|
164
|
+
|
|
65
165
|
[ "$active" = "true" ] && exit 0
|
|
66
166
|
[ -d "$cwd" ] || exit 0
|
|
67
167
|
|
|
@@ -175,6 +275,7 @@ entry_nudge() {
|
|
|
175
275
|
|
|
176
276
|
mkdir -p "$root/nudged" 2>/dev/null || true
|
|
177
277
|
: >"$root/nudged/$sid" 2>/dev/null || true
|
|
278
|
+
refused=1
|
|
178
279
|
jq -n '{
|
|
179
280
|
decision: "block",
|
|
180
281
|
reason: "sluice: this session has changed the tree since it opened and no channel was ever announced, so the work is running with none of the rules that its shape calls for and nothing to meter it from. Invoke the sluice skill now, route what you have been doing, and say which channel it is. If it genuinely changed nothing you own (a scratch file, or an edit that was not yours), say so and stop; this will not ask twice."
|
|
@@ -225,6 +326,7 @@ verify_gate() {
|
|
|
225
326
|
[ -f "$moved_tree/.sluice/verified" ] && recorded="$(sed -n '1p' "$moved_tree/.sluice/verified" 2>/dev/null)"
|
|
226
327
|
[ "$recorded" = "$now" ] && return 0
|
|
227
328
|
|
|
329
|
+
refused=1
|
|
228
330
|
jq -n --arg channel "$channel" '{
|
|
229
331
|
decision: "block",
|
|
230
332
|
reason: ("sluice: this \($channel) session has changed the tree and no passing check is recorded against it as it stands now, so the handback would carry a change nothing has proved. Run the check that proves it through the recorder: status.sh verify -- <cmd> (the tests, the build, whatever exercises this change). If no check can cover it (docs, config), record why: status.sh verify --none \"<reason>\". Then hand back.")
|
|
@@ -305,6 +407,7 @@ test_gate() {
|
|
|
305
407
|
|
|
306
408
|
# Paths land in a reason the harness prints, so control bytes are stripped
|
|
307
409
|
# as the run guard strips them from the topic and tree.
|
|
410
|
+
refused=1
|
|
308
411
|
jq -n --arg paths "$missing" --arg base "$base" '{
|
|
309
412
|
decision: "block",
|
|
310
413
|
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: "
|
|
@@ -320,50 +423,9 @@ fi
|
|
|
320
423
|
|
|
321
424
|
[ -f "$STATUS" ] || exit 0
|
|
322
425
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
# the main worktree's, and that one is not taken here: a Stop in such a tree may
|
|
327
|
-
# be an unrelated session, and a remedy printed to it would reach into somebody
|
|
328
|
-
# else's run.
|
|
329
|
-
#
|
|
330
|
-
# The forward is read here rather than left to status.sh's resolution because
|
|
331
|
-
# the two questions differ. Resolution answers "which run can this tree read",
|
|
332
|
-
# which is the right question for a render and the wrong one for a refusal. The
|
|
333
|
-
# tree named in the note is then passed as `--dir`, so what follows asks about
|
|
334
|
-
# one named tree and carries no layout knowledge of its own.
|
|
335
|
-
#
|
|
336
|
-
# The run this session opened in a worktree it never entered is its own too,
|
|
337
|
-
# found through the pointer `init` left at the main tree, and it comes ahead of
|
|
338
|
-
# the forward: the forward names whichever run was moved last, which with
|
|
339
|
-
# several controllers in the main tree may be another session's.
|
|
340
|
-
top="$(git -C "$cwd" rev-parse --show-toplevel 2>/dev/null)"
|
|
341
|
-
[ -n "$top" ] || top="$cwd"
|
|
342
|
-
session_tree=""
|
|
343
|
-
case "$sid" in
|
|
344
|
-
"" | */* | .*) ;;
|
|
345
|
-
*)
|
|
346
|
-
main="$(git -C "$cwd" worktree list --porcelain 2>/dev/null | sed -n '1s/^worktree //p')"
|
|
347
|
-
[ -n "$main" ] && [ -f "$main/.sluice/sessions/$sid" ] \
|
|
348
|
-
&& IFS= read -r session_tree <"$main/.sluice/sessions/$sid" 2>/dev/null
|
|
349
|
-
if [ -z "$session_tree" ] || [ ! -f "$session_tree/.sluice/run.json" ] \
|
|
350
|
-
|| [ "$(jq -r '.session // empty' "$session_tree/.sluice/run.json" 2>/dev/null)" != "$sid" ]; then
|
|
351
|
-
session_tree=""
|
|
352
|
-
fi
|
|
353
|
-
;;
|
|
354
|
-
esac
|
|
355
|
-
if [ -f "$top/.sluice/run.json" ]; then
|
|
356
|
-
tree="$top"
|
|
357
|
-
elif [ -n "$session_tree" ]; then
|
|
358
|
-
tree="$session_tree"
|
|
359
|
-
elif [ -f "$top/.sluice/run.at" ]; then
|
|
360
|
-
tree=""
|
|
361
|
-
IFS= read -r tree <"$top/.sluice/run.at" 2>/dev/null || exit 0
|
|
362
|
-
# A note outliving the run it named is stale, not a run to refuse a stop over.
|
|
363
|
-
[ -n "$tree" ] && [ -f "$tree/.sluice/run.json" ] || exit 0
|
|
364
|
-
else
|
|
365
|
-
exit 0
|
|
366
|
-
fi
|
|
426
|
+
resolve_run_tree
|
|
427
|
+
[ -n "$run_tree" ] || exit 0
|
|
428
|
+
tree="$run_tree"
|
|
367
429
|
|
|
368
430
|
run="$(bash "$STATUS" show --json --dir "$tree" 2>/dev/null)" || exit 0
|
|
369
431
|
[ -n "$run" ] || exit 0
|
|
@@ -413,6 +475,7 @@ verdict="$(printf '%s' "$run" | jq -c --argjson now "$(date -u +%s)" --arg tree
|
|
|
413
475
|
# anyone into. What replaces it is the step `move` could not take -- the session
|
|
414
476
|
# following the run -- because a controller guarded here is a controller sitting
|
|
415
477
|
# in the tree its own run left.
|
|
478
|
+
refused=1
|
|
416
479
|
printf '%s' "$verdict" | jq 2>/dev/null '{
|
|
417
480
|
decision: "block",
|
|
418
481
|
reason: ("sluice: the deep run \(.topic) is \(.progress) done with tasks still to go and nothing marked blocked or paused, so ending the turn here hands a live run back with nothing for your partner to decide. Still open: \(.open)."
|
package/skills/sluice/skill.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sluice",
|
|
3
|
-
"version": "0.
|
|
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.",
|
|
3
|
+
"version": "0.27.0",
|
|
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), lists every live deep run and routed fast or main session on the machine in one board.sh view (drawn once, watched, or as JSON), 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",
|
|
7
7
|
"tools": [
|