crewforth 3.1.0 โ 3.2.0-rc.1
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 +151 -0
- package/README.md +4 -3
- package/VERSION +1 -1
- package/adopt.sh +91 -11
- package/kit/AGENT_TEMPLATE.md +2 -1
- package/kit/CLAUDE.md +9 -8
- package/kit/agents/crew-commit-agent.md +7 -2
- package/kit/agents/crew-docs-agent.md +71 -0
- package/kit/agents/crew-planner.md +2 -0
- package/kit/agents/crew-refuter.md +77 -0
- package/kit/agents/crew-security-expert.md +3 -1
- package/kit/agents/crew-session-manager.md +11 -9
- package/kit/eval/doctor.sh +91 -3
- package/kit/eval/golden-routing.txt +9 -0
- package/kit/eval/lib/crew-map/crew-map.sh +26 -0
- package/kit/eval/lib/crew-map/detect.mjs +238 -0
- package/kit/eval/lib/crew-map/narrative.mjs +98 -0
- package/kit/eval/lib/crew-map/parse.mjs +305 -0
- package/kit/eval/lib/crew-map/project.mjs +163 -0
- package/kit/eval/lib/crew-map/rules/names.json +38 -0
- package/kit/eval/lib/crew-map/rules/packages.json +142 -0
- package/kit/eval/lib/crew-map/rules/python-stdlib.json +197 -0
- package/kit/eval/lib/crew-map/scan.mjs +214 -0
- package/kit/eval/lib/crew-map/stacks.mjs +441 -0
- package/kit/eval/lib/crew-map/surface.mjs +457 -0
- package/kit/eval/lib/findings/findings.mjs +410 -0
- package/kit/eval/lib/findings/findings.schema.json +122 -0
- package/kit/eval/lib/findings/findings.sh +29 -0
- package/kit/eval/lib/settings-json.awk +5 -0
- package/kit/eval/lib/star.sh +23 -7
- package/kit/eval/lib/statusline.settings.json +6 -0
- package/kit/eval/lib/statusline.sh +115 -0
- package/kit/eval/smoke-test.sh +465 -38
- package/kit/hooks/agent-outcome.sh +6 -3
- package/kit/hooks/guard-agent-model.sh +15 -5
- package/kit/hooks/guard-bash.sh +240 -182
- package/kit/hooks/guard-question.sh +73 -0
- package/kit/hooks/guard-write.sh +21 -0
- package/kit/hooks/prompt-approval.sh +320 -103
- package/kit/hooks/refuter-ledger.sh +80 -0
- package/kit/owned-blobs.tsv +4 -1
- package/kit/settings.json +33 -0
- package/kit/skills/crew-approve/SKILL.md +7 -0
- package/kit/skills/crew-doctor/SKILL.md +5 -1
- package/kit/skills/crew-handoff/SKILL.md +3 -2
- package/kit/skills/crew-map/SKILL.md +44 -0
- package/kit/skills/crew-review/SKILL.md +2 -0
- package/kit/skills/crew-update/SKILL.md +1 -1
- package/kit/skills/incident-runbook/SKILL.md +2 -2
- package/kit/skills/security-scan/references/verify.md +6 -3
- package/kit/studio/README.md +12 -0
- package/kit/studio/server/index.js +114 -11
- package/kit/studio/server/lib/crew-map.js +113 -0
- package/kit/studio/server/lib/model-outcomes.js +130 -15
- package/kit/studio/server/lib/pricing.js +3 -0
- package/kit/studio/server/lib/remote.js +99 -0
- package/kit/studio/server/lib/usage.js +74 -14
- package/kit/studio/web/app.js +214 -12
- package/kit/studio/web/canvas.js +44 -120
- package/kit/studio/web/graph-plan.js +10 -4
- package/kit/studio/web/index.html +10 -5
- package/kit/studio/web/map-plan.js +341 -0
- package/kit/studio/web/map.js +503 -0
- package/kit/studio/web/models-plan.js +61 -7
- package/kit/studio/web/models.js +19 -3
- package/kit/studio/web/style.css +125 -0
- package/kit/studio/web/usage.js +12 -0
- package/kit/studio/web/viewport.js +160 -0
- package/package.json +6 -5
- package/start.sh +10 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# statusline.sh โ Crewforth's status line: one line, from what Claude Code hands it on stdin and what the hooks
|
|
3
|
+
# have already written. It decides nothing and blocks nothing; it only says.
|
|
4
|
+
#
|
|
5
|
+
# ๐ก BLOCK ยง4.2 ยท โ commit approved 24m ยท โ 2 crew agents ยท ๐ 34% ยท ~$1.20
|
|
6
|
+
#
|
|
7
|
+
# Each part is shown only when there is something to say, and only for THIS session:
|
|
8
|
+
# ๐ก the gate's last word in this session: the last line of the gate log, if it was written after the session's
|
|
9
|
+
# first status line (the log carries no time, so a line from last week must not read as now)
|
|
10
|
+
# โ an approval the user gave for a commit or a push that still holds (the record prompt-approval.sh keeps in
|
|
11
|
+
# the git directory, 30 minutes, emptied at the user's next message)
|
|
12
|
+
# โ crew agents started in this session that have not stopped yet (model routing's records)
|
|
13
|
+
# ๐ the context fill Claude Code measured (context_window.used_percentage), never an estimate
|
|
14
|
+
# ~$ what Claude Code puts the session's cost at (cost.total_cost_usd), at API list price
|
|
15
|
+
#
|
|
16
|
+
# Wired by the installers only where no status line is set already (theirs is never replaced), from
|
|
17
|
+
# statusline.settings.json beside this file.
|
|
18
|
+
# COST. Claude Code runs this after every change, debounced at 300 ms. Measured: awk (the stdin JSON) and tail (the
|
|
19
|
+
# gate log), and on bash older than 4.2 one date; the rest is builtins. No git, no jq, no python.
|
|
20
|
+
set -u
|
|
21
|
+
_here="${BASH_SOURCE%[/\\]*}"; [ "$_here" = "${BASH_SOURCE}" ] && _here=.
|
|
22
|
+
|
|
23
|
+
# --install, from the project root: put this status line into .claude/settings.json only where NO status line is
|
|
24
|
+
# set (the project's settings, its local settings, or the user's own); a user's line is never replaced, because
|
|
25
|
+
# the project's setting would win over it. Prints one word: installed ยท kept (one is set) ยท none (no settings.json)
|
|
26
|
+
# ยท failed (the file is left as it was). A managed settings layer is not read. The merge is Crewforth's own JSON reader.
|
|
27
|
+
if [ "${1:-}" = --install ]; then
|
|
28
|
+
P=".claude/settings.json"; SJ="$_here/settings-json.awk"
|
|
29
|
+
[ -f "$P" ] && [ -f "$SJ" ] || { echo none; exit 0; }
|
|
30
|
+
for f in "$P" ".claude/settings.local.json" "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/settings.json"; do
|
|
31
|
+
[ -f "$f" ] && awk -v op=get -v path=statusLine -f "$SJ" "$f" >/dev/null 2>&1 && { echo kept; exit 0; }
|
|
32
|
+
done
|
|
33
|
+
# The setting itself is data beside this file (statusline.settings.json): one definition, read here and nowhere else.
|
|
34
|
+
K="$_here/statusline.settings.json"; [ -f "$K" ] || { echo failed; exit 0; }
|
|
35
|
+
t="$P.statusline.$$"
|
|
36
|
+
r=failed
|
|
37
|
+
# The project's file goes FIRST: the merge refreshes the first file's .claude/hooks/ entries from the first file,
|
|
38
|
+
# so put second it would lose every Crewforth hook (measured: the installed project's own smoke failed 30
|
|
39
|
+
# checks). The second file has one member, statusLine, which the first lacks: that is the one change. Written
|
|
40
|
+
# through the file, so a symlink and its mode survive.
|
|
41
|
+
if awk -v op=merge -v retired= -f "$SJ" "$P" "$K" > "$t" 2>/dev/null && [ -s "$t" ] \
|
|
42
|
+
&& awk -v op=validate -f "$SJ" "$t" 2>/dev/null && awk -v op=get -v path=statusLine -f "$SJ" "$t" >/dev/null 2>&1; then
|
|
43
|
+
cat "$t" > "$P" && r=installed
|
|
44
|
+
fi
|
|
45
|
+
rm -f "$t"; echo "$r"; exit 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
IFS= read -r -d '' IN || true
|
|
49
|
+
[ -n "$IN" ] || exit 0
|
|
50
|
+
# One read of the four values the line needs.
|
|
51
|
+
F="$(printf '%s' "$IN" | awk -v op=gets -v 'path=session_id|context_window.used_percentage|cost.total_cost_usd|workspace.project_dir' -f "$_here/settings-json.awk" - 2>/dev/null)" || F=""
|
|
52
|
+
IFS=$'\t' read -r SID PCT COST PDIR <<< "$F"
|
|
53
|
+
# The reader prints a string with its quotes; taken off by expansion, not a subshell (this runs every few seconds).
|
|
54
|
+
SID="${SID:-}"; SID="${SID#\"}"; SID="${SID%\"}"; PDIR="${PDIR:-}"; PDIR="${PDIR#\"}"; PDIR="${PDIR%\"}"
|
|
55
|
+
case "$SID" in ''|*[!A-Za-z0-9._-]*) SID="" ;; esac
|
|
56
|
+
[ -n "$PDIR" ] && [ -d "$PDIR/.claude" ] && cd "$PDIR" 2>/dev/null
|
|
57
|
+
|
|
58
|
+
OUT=()
|
|
59
|
+
# The session's baseline: made on its first status line. What is newer than it happened in this session.
|
|
60
|
+
BASE=""
|
|
61
|
+
if [ -n "$SID" ] && [ -d .claude ]; then
|
|
62
|
+
BASE=".claude/state/statusline/$SID"
|
|
63
|
+
if [ ! -e "$BASE" ]; then
|
|
64
|
+
mkdir -p .claude/state/statusline 2>/dev/null
|
|
65
|
+
: > "$BASE" 2>/dev/null || BASE=""
|
|
66
|
+
fi
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# ๐ก The gate's last word in this session.
|
|
70
|
+
GL="${CREW_GATE_LOG:-.claude/gate-log.tsv}"
|
|
71
|
+
if [ -n "$BASE" ] && [ -f "$GL" ] && [ "$GL" -nt "$BASE" ]; then
|
|
72
|
+
last="$(tail -n 1 "$GL" 2>/dev/null)"
|
|
73
|
+
IFS=$'\t' read -r verdict section _ <<< "$last"
|
|
74
|
+
case "$verdict" in BLOCK|ASK|ALLOW|NOTE) OUT+=("๐ก $verdict ${section:-}") ;; esac
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# โ An approval that still holds: the record is in the git directory (a worktree's .git is a file naming it).
|
|
78
|
+
G=""
|
|
79
|
+
if [ -d .git ]; then G=".git"
|
|
80
|
+
elif [ -f .git ]; then IFS= read -r l < .git 2>/dev/null; case "$l" in "gitdir: "*) G="${l#gitdir: }"; G="${G%$'\r'}" ;; esac; fi
|
|
81
|
+
if [ -n "$G" ] && [ -s "$G/crewforth-approval" ]; then
|
|
82
|
+
op=""; ts=""
|
|
83
|
+
while IFS='=' read -r k v; do v="${v%$'\r'}"; case "$k" in op) op="$v" ;; ts) ts="$v" ;; esac; done < "$G/crewforth-approval"
|
|
84
|
+
if [ "${BASH_VERSINFO[0]}" -ge 5 ] || { [ "${BASH_VERSINFO[0]}" -eq 4 ] && [ "${BASH_VERSINFO[1]}" -ge 2 ]; }; then printf -v now '%(%s)T' -1; else now="$(date +%s)"; fi
|
|
85
|
+
case "$ts" in ''|*[!0-9]*) ;; *)
|
|
86
|
+
left=$(( (1800 - (now - ts)) / 60 ))
|
|
87
|
+
case "$op" in commit|push|commit+push) [ "$left" -ge 0 ] && [ "$((now - ts))" -le 1800 ] && OUT+=("โ $op approved ${left}m") ;; esac ;;
|
|
88
|
+
esac
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# โ Crew agents started in this session and not stopped: a record under agents/ with no result beside it.
|
|
92
|
+
if [ -n "$BASE" ] && [ -d .claude/state/crew-model/agents ]; then
|
|
93
|
+
n=0
|
|
94
|
+
for a in .claude/state/crew-model/agents/*; do
|
|
95
|
+
[ -f "$a" ] || continue
|
|
96
|
+
case "$a" in *.claim|*.used) continue ;; esac
|
|
97
|
+
[ "$a" -nt "$BASE" ] || continue
|
|
98
|
+
[ -e ".claude/state/crew-model/results/${a##*/}" ] && continue
|
|
99
|
+
n=$((n + 1))
|
|
100
|
+
done
|
|
101
|
+
pl=s; [ "$n" -eq 1 ] && pl=""
|
|
102
|
+
[ "$n" -gt 0 ] && OUT+=("โ $n crew agent$pl")
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# ๐ and ~$: Claude Code's own numbers, shown as they are.
|
|
106
|
+
case "${PCT:-}" in ''|null|*[!0-9.]*) ;; *) OUT+=("๐ ${PCT%%.*}%") ;; esac
|
|
107
|
+
case "${COST:-}" in ''|null|*[!0-9.]*) ;; *)
|
|
108
|
+
printf -v c '%.2f' "$COST" 2>/dev/null && OUT+=("~\$$c") ;;
|
|
109
|
+
esac
|
|
110
|
+
|
|
111
|
+
[ "${#OUT[@]}" -gt 0 ] || exit 0
|
|
112
|
+
line="${OUT[0]}"
|
|
113
|
+
for p in "${OUT[@]:1}"; do line="$line ยท $p"; done
|
|
114
|
+
printf '%s\n' "$line"
|
|
115
|
+
exit 0
|