crewforth 3.2.0 → 3.3.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/CHANGELOG.md +111 -0
- package/README.md +2 -2
- package/VERSION +1 -1
- package/adopt.sh +7 -3
- package/kit/AGENT_TEMPLATE.md +1 -0
- package/kit/CLAUDE.md +9 -8
- package/kit/agents/crew-session-manager.md +5 -3
- package/kit/eval/doctor.sh +126 -45
- package/kit/eval/golden-routing.txt +3 -0
- package/kit/eval/lib/node-advisory.tsv +9 -0
- package/kit/eval/lib/verify-cmd.sh +72 -0
- package/kit/eval/smoke-test.sh +409 -72
- package/kit/hooks/context-usage.sh +6 -3
- package/kit/hooks/guard-agent-model.sh +37 -8
- package/kit/hooks/guard-bash.sh +127 -2
- package/kit/hooks/guard-schedule.sh +4 -1
- package/kit/hooks/pre-commit +21 -0
- package/kit/hooks/prompt-approval.sh +80 -3
- package/kit/hooks/route-hint.sh +18 -1
- package/kit/hooks/session-rehydrate.sh +6 -2
- package/kit/owned-blobs.tsv +4 -2
- package/kit/skills/commit-message/SKILL.md +5 -0
- package/kit/skills/crew-allow-verify/SKILL.md +30 -0
- package/kit/skills/crew-doctor/SKILL.md +3 -1
- package/kit/skills/handoff/SKILL.md +3 -2
- package/kit/skills/trace-scan/SKILL.md +4 -3
- package/kit/studio/ensure-node.sh +1 -1
- package/kit/studio/server/index.js +3 -0
- package/kit/studio/server/lib/model-outcomes.js +7 -1
- package/kit/studio/server/lib/node-advisory.js +46 -0
- package/kit/studio/web/models-plan.js +3 -3
- package/package.json +1 -1
- package/start.sh +6 -2
|
@@ -15,3 +15,75 @@ crew_verify_split(){ # $1 = the command, $2 = the project root -> _AMVD the fol
|
|
|
15
15
|
[ -n "$r" ] && [ -d "$root/$d" ] || return 0
|
|
16
16
|
_AMVD="$d"; _AMVC="$r"
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
# The verify commands the hook was refused for want of a rule, read from the record of results: one definition, for
|
|
20
|
+
# doctor, which lists them, and for /crew-allow-verify (hooks/prompt-approval.sh), which adds the one the user names.
|
|
21
|
+
# Two lists, one entry per line: a command (the one a `verify <command>` line would allow, without its cd), and a line
|
|
22
|
+
# that is no command at all: a parenthesis or ` + `, or a first word that is no path, no assignment and nothing this
|
|
23
|
+
# machine runs ("measured numbers"). A command a `verify` line of crew-model-rules already allows is left out: it was
|
|
24
|
+
# refused before the user allowed it. Each is counted every time it was refused, and listed once.
|
|
25
|
+
crew_verify_blocked(){ # $1 = project root -> _VB_N _VB_CMDS, _VB_PN _VB_SENT (lists end in a newline)
|
|
26
|
+
local root="${1:-.}" f l vb vw vc v1 vs nl='
|
|
27
|
+
' allowed=""
|
|
28
|
+
_VB_N=0; _VB_CMDS=""; _VB_PN=0; _VB_SENT=""
|
|
29
|
+
if [ -f "$root/.claude/crew-model-rules" ]; then
|
|
30
|
+
while IFS= read -r l || [ -n "$l" ]; do l="${l%$'\r'}"; case "$l" in 'verify '*) allowed="$allowed${l#verify }$nl" ;; esac; done < "$root/.claude/crew-model-rules"
|
|
31
|
+
fi
|
|
32
|
+
for f in "$root"/.claude/state/crew-model/results/*; do
|
|
33
|
+
[ -f "$f" ] || continue
|
|
34
|
+
vb=0; vw=""; vc=""
|
|
35
|
+
while IFS= read -r l || [ -n "$l" ]; do
|
|
36
|
+
case "$l" in verify=blocked) vb=1 ;; whynot=*) vw="${l#whynot=}" ;; cmd=*) vc="${l#cmd=}" ;; esac
|
|
37
|
+
done < "$f"
|
|
38
|
+
[ "$vb" = 1 ] || continue
|
|
39
|
+
# Both ways of saying "nothing allows it": in auto/bypassPermissions (not on the runner list) and in the other
|
|
40
|
+
# modes (Claude Code itself would not run it unallowed). Measured on Windows: the second was not listed at all.
|
|
41
|
+
case "$vw" in *"not a test or build command on this hook's list"*|*"does not run a command the user has not allowed"*) ;; *) continue ;; esac
|
|
42
|
+
# A rule names the command alone: `cd sub && ./check.sh` is allowed by `verify ./check.sh` (measured on Windows:
|
|
43
|
+
# the line with the cd in it did not allow it).
|
|
44
|
+
crew_verify_split "$vc" "$root"; vc="$_AMVC"
|
|
45
|
+
[ -n "$vc" ] || continue
|
|
46
|
+
case "$nl$allowed" in *"$nl$vc$nl"*) continue ;; esac
|
|
47
|
+
v1="${vc%% *}"; vs=0
|
|
48
|
+
case "$vc" in *'('*|*' + '*) vs=1 ;; esac
|
|
49
|
+
case "$v1" in */*|*=*) ;; *) command -v -- "$v1" >/dev/null 2>&1 || vs=1 ;; esac
|
|
50
|
+
# A rule that would allow any command is not offered at all (see crew_verify_open_ended below).
|
|
51
|
+
[ "$vs" = 0 ] && declare -F crew_verify_open_ended >/dev/null && crew_verify_open_ended "$vc" && continue
|
|
52
|
+
if [ "$vs" = 1 ]; then
|
|
53
|
+
# Whole for a command (a rule cut short allows nothing); a sentence is shortened, at a word.
|
|
54
|
+
[ "${#vc}" -gt 80 ] && { vc="${vc:0:80}"; vc="${vc% *} …"; }
|
|
55
|
+
_VB_PN=$((_VB_PN+1)); case "$nl$_VB_SENT" in *"$nl$vc$nl"*) ;; *) _VB_SENT="$_VB_SENT$vc$nl" ;; esac
|
|
56
|
+
else
|
|
57
|
+
_VB_N=$((_VB_N+1)); case "$nl$_VB_CMDS" in *"$nl$vc$nl"*) ;; *) _VB_CMDS="$_VB_CMDS$vc$nl" ;; esac
|
|
58
|
+
fi
|
|
59
|
+
done
|
|
60
|
+
return 0
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# A rule that would let the hook run ANY command. A `verify` rule allows its command and the same command with more
|
|
64
|
+
# words after it (guard-agent-model.sh `_am_starts`), so `verify bash` allows `bash evil.sh` and `verify node -e`
|
|
65
|
+
# allows any script (found in review). Such a rule is neither offered nor written by /crew-allow-verify: an
|
|
66
|
+
# interpreter, a shell, a wrapper that runs what follows it, or a package runner that fetches what it runs, when
|
|
67
|
+
# nothing after it names the file or the task, or when what follows is an option (`bash -c`, `node -e`).
|
|
68
|
+
crew_verify_open_ended(){ # $1 = command -> 0 when the rule would allow any command
|
|
69
|
+
local c="$1" w1 w2 w3 rest
|
|
70
|
+
# Leading assignments and `env` decide nothing about what runs: `env FOO=1 python3` is `python3` (found in review).
|
|
71
|
+
while :; do
|
|
72
|
+
w1="${c%% *}"
|
|
73
|
+
case "$w1" in env|*/env) [ "$c" = "$w1" ] && return 0; c="${c#"$w1" }" ;; [A-Za-z_]*=*) [ "$c" = "$w1" ] && return 0; c="${c#"$w1" }" ;; *) break ;; esac
|
|
74
|
+
done
|
|
75
|
+
rest="${c#"$w1"}"; rest="${rest# }"; w2="${rest%% *}"; rest="${rest#"$w2"}"; rest="${rest# }"; w3="${rest%% *}"
|
|
76
|
+
case "${w1##*/}" in
|
|
77
|
+
python|python2|python3)
|
|
78
|
+
[ -z "$w2" ] && return 0
|
|
79
|
+
# `python3 -m pytest` names the module it runs; `-c`, `-` or a bare `-m` do not.
|
|
80
|
+
case "$w2" in -m) [ -z "$w3" ] && return 0; case "$w3" in -*) return 0 ;; esac; return 1 ;; -*) return 0 ;; esac ;;
|
|
81
|
+
bash|sh|zsh|dash|ksh|fish|pwsh|powershell|cmd|xargs|sudo|doas|nice|nohup|timeout|command|exec|eval|time|watch|node|deno|bun|ruby|perl|php|lua|osascript|npx|pnpx|bunx|curl|wget|rm|git|make|ssh|docker|kubectl)
|
|
82
|
+
[ -z "$w2" ] && return 0
|
|
83
|
+
case "$w2" in -*) return 0 ;; esac ;;
|
|
84
|
+
npm|pnpm|yarn)
|
|
85
|
+
[ -z "$w2" ] && return 0
|
|
86
|
+
case "$w2" in -*|exec|x|dlx|install|i|add|ci|create|init) return 0 ;; esac ;;
|
|
87
|
+
esac
|
|
88
|
+
return 1
|
|
89
|
+
}
|