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 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`, your own message approves a commit or a push.** Those modes answer a permission prompt
94
- with software, so the commit gate fails closed there and the only way through was to switch mode for every commit.
95
- Now a message that is nothing but `approve: commit`, `approve: push` or `approve: commit+push` (`onay:` works too)
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
- - **10 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`.
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, present the message, and the user approves by sending a message that is only
91
- `approve: commit` (`approve: push`, `approve: commit+push`; `onay:` too). It covers what is staged on that HEAD.
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
@@ -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