crewforth 3.1.0-rc.2 → 3.1.0-rc.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/CHANGELOG.md +70 -4
- package/README.md +1 -1
- package/kit/agents/crew-commit-agent.md +5 -2
- package/kit/eval/doctor.sh +26 -0
- package/kit/eval/smoke-test.sh +274 -18
- package/kit/hooks/context-usage.sh +1 -1
- package/kit/hooks/guard-bash.sh +93 -6
- package/kit/hooks/guard-schedule.sh +92 -0
- package/kit/hooks/prompt-approval.sh +68 -21
- package/kit/settings.json +11 -0
- package/kit/skills/crew-approve/SKILL.md +26 -0
- package/kit/studio/server/index.js +18 -0
- package/kit/studio/server/lib/graph.js +137 -15
- package/kit/studio/server/lib/permissions.js +11 -3
- package/kit/studio/server/lib/pricing.js +63 -0
- package/kit/studio/server/lib/usage.js +144 -0
- package/kit/studio/web/app.js +159 -38
- package/kit/studio/web/approvals.js +20 -1
- package/kit/studio/web/canvas.js +158 -30
- package/kit/studio/web/chat.js +1 -0
- package/kit/studio/web/convo.js +4 -2
- package/kit/studio/web/dock.js +1 -0
- package/kit/studio/web/graph-plan.js +173 -13
- package/kit/studio/web/index.html +1 -0
- package/kit/studio/web/inspect.js +14 -1
- package/kit/studio/web/list-plan.js +4 -4
- package/kit/studio/web/list.js +2 -0
- package/kit/studio/web/names.js +44 -0
- package/kit/studio/web/style.css +64 -10
- package/kit/studio/web/timeline-plan.js +13 -5
- package/kit/studio/web/timeline.js +10 -4
- package/kit/studio/web/usage.js +77 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,21 @@ versioning follows [SemVer](https://semver.org/).
|
|
|
9
9
|
|
|
10
10
|
### Security
|
|
11
11
|
|
|
12
|
+
- **A session could start another one and hand it the approval.** `claude -p "/crew-approve commit"` starts a session
|
|
13
|
+
whose only message is the approval; it was recorded there, and that session would then commit and push: the first
|
|
14
|
+
session had approved for you. Two things changed. The recording hook writes nothing in a headless session
|
|
15
|
+
(Claude Code marks one with `CLAUDE_CODE_SESSION_ATTENDED=0`, whatever its caller sets), and nothing unless the
|
|
16
|
+
session's transcript is already on disk, so not at a session's first message and not in a session started inside
|
|
17
|
+
another, which keeps none; each refusal says why. And `guard-bash.sh` refuses a command that names `claude` (also
|
|
18
|
+
through `npx`, `bunx` or `node`) when one of its words is an approval, judged by the function that reads your own
|
|
19
|
+
prompt. An ordinary `claude -p "…"` is untouched. Known limit: a session started with an emptied environment and
|
|
20
|
+
typed into by a program, for a second message, passes both.
|
|
21
|
+
- **A session could schedule its own approval.** In `auto` and `dontAsk` the approval for a commit or a push is what
|
|
22
|
+
you type, and the hook that records it reads the prompt Claude Code hands it. A prompt that a tool schedules
|
|
23
|
+
(`CronCreate`, `ScheduleWakeup`, `RemoteTrigger`, an MCP tool that schedules) is handed to it in the same way when
|
|
24
|
+
it fires, so a session that scheduled `/crew-approve commit` would have approved its own commit. A new gate,
|
|
25
|
+
`guard-schedule.sh`, refuses such a call when any text in it is an approval, judged by the one function that reads
|
|
26
|
+
your own prompt. An ordinary scheduled prompt is untouched.
|
|
12
27
|
- **A git subcommand the shell fills in walked past every gate.** Each rule about a git command finds it by its name,
|
|
13
28
|
and with an expansion inside the word the name is not in the text: `git com${z}mit`, `c=commit; git "$c"`, `git
|
|
14
29
|
$(printf com)mit`, a backtick, and the same for `git pu${z}sh --force`, `git re$(:)set --hard`, `git cl${z}ean -fdx`
|
|
@@ -90,10 +105,10 @@ versioning follows [SemVer](https://semver.org/).
|
|
|
90
105
|
and no ad in a window that shows a sensitive screen. The rules were checked against Flutter's, Dart's and the
|
|
91
106
|
named packages' and platforms' own pages; the sources, and what was not checked, are in the skill's `references/`.
|
|
92
107
|
40 skills now.
|
|
93
|
-
- **In `auto` and `dontAsk`,
|
|
94
|
-
with software, so the commit gate fails closed there and the only way through was to switch
|
|
95
|
-
Now a message that is nothing but
|
|
96
|
-
is recorded by a new hook, `prompt-approval.sh`, with what git reports at that moment: the tree of what is staged
|
|
108
|
+
- **In `auto` and `dontAsk`, a command you type approves a commit or a push: `/crew-approve`.** Those modes answer
|
|
109
|
+
a permission prompt with software, so the commit gate fails closed there and the only way through was to switch
|
|
110
|
+
mode for every commit. Now a message that is nothing but `/crew-approve commit`, `/crew-approve push` or
|
|
111
|
+
`/crew-approve commit+push` is recorded by a new hook, `prompt-approval.sh`, with what git reports at that moment: the tree of what is staged
|
|
97
112
|
and `HEAD` for a commit; `HEAD`, the branch, its remote and the address that remote pushes to for a push; and the
|
|
98
113
|
session you wrote in. The confirmation you see names that address. `guard-bash.sh` then allows one call and no other: `git commit -m …` alone (a single-quoted
|
|
99
114
|
message, or one read from a here-document with a quoted delimiter; `-q`, `-s`, `-v`), or
|
|
@@ -118,9 +133,50 @@ versioning follows [SemVer](https://semver.org/).
|
|
|
118
133
|
- **Studio: a layout for a narrow window.** Below 640 px the panel is one column: the navigator is a drawer, the
|
|
119
134
|
inspector and the conversation take the whole stage and stop above the dock. Checked in a narrow desktop browser
|
|
120
135
|
window; not measured on a phone.
|
|
136
|
+
- **Studio: what a session spent.** A summary box on the canvas and one line in the navigator give the session's
|
|
137
|
+
time, its tokens (agents included) and an estimate of the cost, such as `51m · 2.8M · ~$3.22`. The cost is an
|
|
138
|
+
estimate at API list price and reads as one (a leading `~`; on a subscription it is not what you are billed). The
|
|
139
|
+
prices are one table, read from the pricing page on 2026-10-08; a model with no row in it shows `—`, never a guess.
|
|
140
|
+
Not checked against an invoice.
|
|
141
|
+
- **Studio: the order the session called its agents in.** Each agent's card says its place and the time
|
|
142
|
+
(`#3 · 09:14`). **Order**, in the Group menu, lays the agents out by wave: the agents called in one message are a
|
|
143
|
+
wave, waves run left to right, and the Timeline groups by the same waves. A later wave is wired, dotted, from each
|
|
144
|
+
agent that reported before it was called, with the words `after Planner reported`; that wire is inferred from the
|
|
145
|
+
order of events and is not a call from one agent to another, and the panel says so. Read from the transcript
|
|
146
|
+
alone. Agents a workflow started are not called by the session, so they carry no place.
|
|
147
|
+
- **Studio: background work is shown.** A Bash command sent to the background is listed on its session (`1 in
|
|
148
|
+
background` on the card, **In the background** in the inspector) until the notice that ends it arrives.
|
|
149
|
+
- **Studio: a question waiting in a terminal is named.** For a session started in a terminal, a permission question
|
|
150
|
+
can only be answered there; the view now says so, with the tool and the command: `Waiting for an answer in the
|
|
151
|
+
terminal: Bash · npm run build`.
|
|
152
|
+
- **Studio: the inspector can be resized** (drag its left edge, arrow keys, double-click for the default; 280 to
|
|
153
|
+
720 px, remembered).
|
|
121
154
|
|
|
122
155
|
### Changed
|
|
123
156
|
|
|
157
|
+
- **Studio: agents are named by their role.** `crew-backend-expert` reads Backend, `general-purpose` General Purpose,
|
|
158
|
+
in the graph, the Timeline, the List, the dock, the inspector and the conversation; the declared type is under the
|
|
159
|
+
name in the inspector and on hover. A task cut short on a card is said in full on hover.
|
|
160
|
+
- **Studio: a group of agents opens beside itself.** Several agents of one type are one card; in a window of 1024 px
|
|
161
|
+
and up, clicking it puts its agents in the next column as ordinary cards, and opening another group folds the
|
|
162
|
+
first. Below that width it opens downward as before.
|
|
163
|
+
- **The approval of 3.1.0's release candidates was a text, `approve: commit` (`onay: commit`); it is the command
|
|
164
|
+
`/crew-approve commit` now.** The same in every language, and recorded exactly as the text was. Only a command you
|
|
165
|
+
type counts: measured on Claude Code 2.1.284, a typed command reaches the recording hook as typed, a skill the
|
|
166
|
+
model starts itself does not reach it at all, and Claude Code refuses to let the model start this one. The text
|
|
167
|
+
still works; the refusals and the documentation name the command only.
|
|
168
|
+
- **In `auto` and `dontAsk`, a refused commit or push says what to ask and what to send back.** The refusal was a
|
|
169
|
+
paragraph with the approval text somewhere inside it, and the question the model made of it was as long. It now
|
|
170
|
+
asks for one shape: the commit message in one code block and, under it, one line with the command to send, named
|
|
171
|
+
for the call that was refused. A sentence that says yes is still not an approval, and nothing about what an
|
|
172
|
+
approval covers has changed.
|
|
173
|
+
- **Where the approval cannot be recorded, the refusal says so.** The record is written by `prompt-approval.sh`. In a
|
|
174
|
+
session whose settings do not wire it (a worktree that carries an older Crewforth, for one) the approval
|
|
175
|
+
recorded nothing, and the refusal went on asking for it. The gate now reads the settings it can
|
|
176
|
+
see (the plugin's `hooks.json`, the project's `settings.json` and `settings.local.json`, the user's
|
|
177
|
+
`settings.json`) and, when none wires the hook, says the approval path is closed in this session and names the
|
|
178
|
+
two ways that work: Shift+Tab, or your own terminal. The command is refused either way. `doctor.sh` warns about
|
|
179
|
+
the same thing, and about a worktree of the repository that carries another Crewforth version.
|
|
124
180
|
- **After a final release, npm's `next` no longer names something older than `latest`.** A final moved `latest`
|
|
125
181
|
only, so `npx crewforth@next` went on installing the rc before it. The release now moves `next` to the final when
|
|
126
182
|
what `next` names is older; an rc of a later version stays where it is.
|
|
@@ -205,6 +261,16 @@ versioning follows [SemVer](https://semver.org/).
|
|
|
205
261
|
the same (measured on Windows, in a real session), and the conversation says who refused it. Known limit: the dock
|
|
206
262
|
can ask about a call that another gate refuses anyway.
|
|
207
263
|
|
|
264
|
+
### Fixed
|
|
265
|
+
|
|
266
|
+
- **Studio: full screen keeps its panels.** In full screen the navigator, the inspector and the conversation could
|
|
267
|
+
not be opened, so a selected agent showed nothing and a request under "Needs you" could not be answered. A style
|
|
268
|
+
rule hid every panel there; it is gone, and full screen now only takes the browser away.
|
|
269
|
+
- **Studio: a background agent that is still working is no longer drawn "Done".** Claude Code sends a `completed`
|
|
270
|
+
notice each time a background agent stops, and the agent can be resumed after it; Studio took the first notice as
|
|
271
|
+
final. A notice now stands only until the agent writes to its transcript again, and while its session is running
|
|
272
|
+
an agent in the middle of a turn is drawn Running.
|
|
273
|
+
|
|
208
274
|
## [3.0.4] — 2026-10-05
|
|
209
275
|
|
|
210
276
|
### Security
|
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ Then open Claude Code and run `/crew-doctor` to confirm the setup. Requires bash
|
|
|
30
30
|
|
|
31
31
|
- **12 specialist agents**, from `crew-planner` to `crew-commit-agent`, each owning one domain.
|
|
32
32
|
- **40 skills** holding the method: testing, migrations, API contracts, observability, accessibility, deployment.
|
|
33
|
-
- **
|
|
33
|
+
- **11 commands**, each started with its `/crew-…` name: `/crew-plan`, `/crew-review`, `/crew-ship`, `/crew-handoff`, `/crew-brainstorm`, `/crew-update`, `/crew-doctor`, `/crew-gates`, `/crew-skill`, `/crew-studio`, `/crew-approve`.
|
|
34
34
|
- **Safe adoption.** `adopt` lands everything on a branch, staged and uncommitted; `main` is never touched.
|
|
35
35
|
|
|
36
36
|
## Updating
|
|
@@ -87,8 +87,11 @@ On a mixed/non-atomic diff, **propose a split**; do not commit before approval (
|
|
|
87
87
|
The tool-level gate `guard-bash.sh` intercepts commit/push in **every** permission mode: in normal modes it raises an
|
|
88
88
|
approval prompt only the user can answer — so present the message FIRST, then run the commit yourself and let the user
|
|
89
89
|
approve it at the prompt. Never hand the user a command to paste into their own terminal. In `auto` and `dontAsk`
|
|
90
|
-
the prompt reaches nobody: stage,
|
|
91
|
-
|
|
90
|
+
the prompt reaches nobody: stage, then ask in this shape and with nothing after it — the message in ONE code block,
|
|
91
|
+
and under it one line, the sentence in the user's language and the command as it is: "If you approve, send only
|
|
92
|
+
this: `/crew-approve commit`" (or `/crew-approve push`, `/crew-approve commit+push`). The user approves by sending
|
|
93
|
+
that command alone; a sentence that says yes is not an approval, and you cannot run `/crew-approve` for them. It covers what is staged on that HEAD. If the gate says the approval path is closed in this session (the
|
|
94
|
+
recording hook is not wired), say so and offer Shift+Tab or their own terminal instead.
|
|
92
95
|
Then run `git commit -m '…'` alone in its call (single-quoted, or from a here-document with a quoted delimiter),
|
|
93
96
|
and a push as `git push <remote> <branch>`. Never write that message yourself. Under `plan` and
|
|
94
97
|
`bypassPermissions` the gate fails closed; there the user must switch modes or pre-authorise with
|
package/kit/eval/doctor.sh
CHANGED
|
@@ -96,6 +96,10 @@ _mt() {
|
|
|
96
96
|
'SessionStart not wired — session rehydration after /compact or /clear is inactive (update Crewforth)') s="SessionStart bağlı değil — /compact ya da /clear sonrasında oturum toparlanmıyor (Crewforth'u güncelleyin)" ;;
|
|
97
97
|
'SessionStart wired (session rehydration active)') s='SessionStart bağlı (oturum toparlama devrede)' ;;
|
|
98
98
|
'settings.json is invalid JSON') s='settings.json geçersiz JSON' ;;
|
|
99
|
+
'approval by your own message is wired (auto / dontAsk: /crew-approve commit)') s='kendi mesajınızla onay bağlı (auto / dontAsk: /crew-approve commit)' ;;
|
|
100
|
+
"settings.json wires prompt-approval.sh but the script is missing — in auto and dontAsk '/crew-approve commit' records nothing; switch mode with Shift+Tab or commit in your own terminal (update Crewforth)") s="settings.json prompt-approval.sh'i bağlıyor ama betik yok — auto ve dontAsk modunda '/crew-approve commit' hiçbir şey kaydetmez; Shift+Tab ile mod değiştirin ya da kendi terminalinizden commit edin (Crewforth'u güncelleyin)" ;;
|
|
101
|
+
"prompt-approval.sh is not wired on UserPromptSubmit — in auto and dontAsk '/crew-approve commit' records nothing; switch mode with Shift+Tab or commit in your own terminal (update Crewforth)") s="prompt-approval.sh UserPromptSubmit'e bağlı değil — auto ve dontAsk modunda '/crew-approve commit' hiçbir şey kaydetmez; Shift+Tab ile mod değiştirin ya da kendi terminalinizden commit edin (Crewforth'u güncelleyin)" ;;
|
|
102
|
+
"worktree %s carries Crewforth %s, this one %s — a session there runs that version's gates and approval path (update Crewforth there)") s="%s worktree'sinde Crewforth %s var, burada %s — orada açılan oturum o sürümün kapılarını ve onay yolunu koşar (Crewforth'u orada güncelleyin)" ;;
|
|
99
103
|
"fix the syntax by hand — restoring Crewforth's file would drop any hooks you added") s="sözdizimini elle düzeltin — Crewforth'un dosyasını geri yüklemek eklediğiniz hook'ları siler" ;;
|
|
100
104
|
'settings.json wires hooks through the %s placeholder — on Windows its separators are stripped before bash runs, so NO hook launches and every gate is silently absent') s="settings.json hook'ları %s yer tutucusuyla bağlıyor — Windows'ta ayırıcılar bash çalışmadan silinir, bu yüzden HİÇBİR hook başlamaz ve bütün kapılar sessizce yok olur" ;;
|
|
101
105
|
'update Crewforth (npx crewforth adopt) — hook commands become:') s="Crewforth'u güncelleyin (npx crewforth adopt) — hook komutları şu olur:" ;;
|
|
@@ -349,6 +353,14 @@ if [ -f "$S" ]; then
|
|
|
349
353
|
|| bad "settings.json hook events empty or missing:%s — those gates won't fire" "restore settings.json from Crewforth (npx crewforth update)" "$EMPTY"
|
|
350
354
|
sn="$(awk -v op=len -v path=hooks.SessionStart -f "$SJ" "$S" 2>/dev/null)"
|
|
351
355
|
case "$sn" in ''|0) warn "SessionStart not wired — session rehydration after /compact or /clear is inactive (update Crewforth)" ;; *) ok "SessionStart wired (session rehydration active)" ;; esac
|
|
356
|
+
# In auto and dontAsk the only approval is the user's own message, and ONE hook records it. Where it is not wired
|
|
357
|
+
# the gate stays closed and '/crew-approve commit' records nothing (field report: a worktree on an older
|
|
358
|
+
# Crewforth). A warning, not a failure: commit and push still cannot happen without the user.
|
|
359
|
+
case "$(awk -v op=get -v path=hooks.UserPromptSubmit -f "$SJ" "$S" 2>/dev/null)" in
|
|
360
|
+
*prompt-approval.sh*) if [ -f .claude/hooks/prompt-approval.sh ]; then ok "approval by your own message is wired (auto / dontAsk: /crew-approve commit)"
|
|
361
|
+
else warn "settings.json wires prompt-approval.sh but the script is missing — in auto and dontAsk '/crew-approve commit' records nothing; switch mode with Shift+Tab or commit in your own terminal (update Crewforth)"; fi ;;
|
|
362
|
+
*) warn "prompt-approval.sh is not wired on UserPromptSubmit — in auto and dontAsk '/crew-approve commit' records nothing; switch mode with Shift+Tab or commit in your own terminal (update Crewforth)" ;;
|
|
363
|
+
esac
|
|
352
364
|
else bad "settings.json is invalid JSON" "fix the syntax by hand — restoring Crewforth's file would drop any hooks you added"; fi
|
|
353
365
|
# `${CLAUDE_PROJECT_DIR}` inside a hook command is the shape that breaks on Windows, and it breaks invisibly.
|
|
354
366
|
# Claude Code substitutes that placeholder into the command STRING before any shell sees it; on Windows the
|
|
@@ -370,6 +382,20 @@ if [ -f "$S" ]; then
|
|
|
370
382
|
else
|
|
371
383
|
bad "settings.json missing — the tool-level gates (commit approval, guards, context) are INACTIVE" "reinstall Crewforth"
|
|
372
384
|
fi
|
|
385
|
+
# 4b) Another worktree of this repository on another Crewforth. A session that moves there runs THAT version's hooks
|
|
386
|
+
# against this one's expectations: its gates, its approval path (3.0 has none for auto mode). `.claude/` is
|
|
387
|
+
# tracked in some projects, so a worktree cut from an older branch carries the older kit.
|
|
388
|
+
if [ -f .claude/VERSION ] && git rev-parse --git-dir >/dev/null 2>&1; then
|
|
389
|
+
_wv0="$(head -1 .claude/VERSION 2>/dev/null | tr -cd '0-9A-Za-z.-')"; _wt0="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
390
|
+
while IFS= read -r _wl; do
|
|
391
|
+
case "$_wl" in "worktree "*) _wp="${_wl#worktree }" ;; *) continue ;; esac
|
|
392
|
+
[ "$_wp" != "$_wt0" ] && [ -f "$_wp/.claude/VERSION" ] || continue
|
|
393
|
+
_wv="$(head -1 "$_wp/.claude/VERSION" 2>/dev/null | tr -cd '0-9A-Za-z.-')"
|
|
394
|
+
[ "$_wv" = "$_wv0" ] || warn "worktree %s carries Crewforth %s, this one %s — a session there runs that version's gates and approval path (update Crewforth there)" "$_wp" "${_wv:-?}" "$_wv0"
|
|
395
|
+
done <<EOF_WT
|
|
396
|
+
$(git worktree list --porcelain 2>/dev/null)
|
|
397
|
+
EOF_WT
|
|
398
|
+
fi
|
|
373
399
|
|
|
374
400
|
# 4a) Skill listing budget. Claude Code puts a listing of every model-invocable skill's name and description into
|
|
375
401
|
# context each turn and caps it at skillListingBudgetFraction of the context window (default 0.01); over the
|