crewforth 3.2.1 → 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.
@@ -43,8 +43,9 @@ that never landed and has to be written down explicitly this time. Missing scrip
43
43
 
44
44
  ## Holding a board item? The handover is not finished until the TEAM has it
45
45
  `docs/SESSION_STATE.md` is gitignored — it survives your `/clear`, and nobody else can read it. So when a
46
- `teamboard` claim is open, **the handover is not complete until it is on the board**. This is not an optional
47
- extra step:
46
+ `teamboard` claim is open, **the handover is not complete until it is on the board**. Whether one is open is
47
+ read from `bash .claude/hooks/board.sh status` (Bash tool, not PowerShell; a row marked `<- you`), not guessed;
48
+ no board or no such row → the handover says nothing about the board. This is not an optional extra step:
48
49
  - Still on it → `board.sh note <id> "<where it stands, and why the rejected path was rejected>"`.
49
50
  - Not coming back → `board.sh drop <id> "<same>"`, which puts it back in circulation with your context attached.
50
51
  - Anything settled here that changes how OTHER items must be done → `board.sh decide "<what>" "<why + what it
@@ -31,10 +31,11 @@ git diff --cached --unified=0 | grep -E '^\+' | grep -Ev '^\+\+\+' \
31
31
  ```
32
32
 
33
33
  ## Hook setup (full install only — a plugin cannot set `core.hooksPath`)
34
- `start.sh` sets `git config core.hooksPath .claude/hooks` (if there is a git repo). The hooks live
35
- under `.claude` → they are in gitignore and stay local (§4.3). To do it later for a repo:
34
+ `start.sh` sets `core.hooksPath` to the absolute path of `.claude/hooks` (if there is a git repo). The hooks live
35
+ under `.claude` → they are in gitignore and stay local (§4.3), so a relative path would leave a linked worktree with
36
+ no hook at all. To do it later for a repo, from its root:
36
37
  ```bash
37
- git config core.hooksPath .claude/hooks
38
+ git config core.hooksPath "$(git rev-parse --show-toplevel)/.claude/hooks"
38
39
  chmod +x .claude/hooks/pre-commit .claude/hooks/commit-msg
39
40
  ```
40
41
 
@@ -145,8 +145,11 @@ const firstTry = (r) => r.verify === 'pass' && r.fixes === 0;
145
145
  */
146
146
  export function floorOfRow(r, ruleFloors = [], floors = []) {
147
147
  let f = rankOf(AGENT_FLOORS[r.agent]);
148
- if (r.verify === 'none') f = Math.max(f, 2);
148
+ const commitAgent = r.agent === 'crew-commit-agent';
149
+ if (r.verify === 'none' && r.change !== 'text' && !commitAgent) f = Math.max(f, 2);
149
150
  if (r.change === 'test-write' || r.change === 'audit') f = Math.max(f, 2);
151
+ // The table's sonnet row, as the gate holds it: feature, fix-known and refactor, except for the commit agent.
152
+ if (!commitAgent && (r.change === 'feature' || r.change === 'fix-known' || r.change === 'refactor')) f = Math.max(f, 2);
150
153
  if (r.risk === 'critical' && r.change !== 'test-run') f = Math.max(f, 3);
151
154
  const any = (want, v) => want === '*' || want === v;
152
155
  for (const x of ruleFloors) if (any(x.agent, r.agent) && any(x.change, r.change) && any(x.risk, r.risk)) f = Math.max(f, rankOf(x.model));
@@ -250,6 +253,9 @@ export function suggestionsOf(rows, floors = [], loosened = [], need = LOOSEN_AF
250
253
  const k = keyOf(f);
251
254
  // Once for each raise: a floor whose lowering stands is not offered again (the same rule the gate reads it by).
252
255
  if (loweringOf(f, loosened)) continue;
256
+ // Not below the class's own floor: /crew-loosen refuses that, since the gate would refuse the lowered model anyway
257
+ // (a feature class raised to sonnet by the record of haiku runs from before its own floor was sonnet).
258
+ if (rankOf(TIERS[tier - 1]) < floorOfRow({ agent: f.agent, change: f.change, risk: f.risk, verify: 'pass' })) continue;
253
259
  const passed = passedLatest(rows, k, f.model, Date.parse(f.when ?? '') || 0, need);
254
260
  if (!passed) continue;
255
261
  out.push({ key: k, agent: f.agent, change: f.change, risk: f.risk, from: f.model, to: TIERS[tier - 1], passed, heldSince: f.when ?? null });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crewforth",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "Crewforth \u2014 your engineering crew for Claude Code: agents, skills and tool-level gates, in any stack.",
5
5
  "bin": {
6
6
  "crewforth": "bin/cli.js"
package/start.sh CHANGED
@@ -760,10 +760,14 @@ fi
760
760
  # `--show-prefix` is the question itself: empty at the work-tree root, `sub/dir/` below it, non-zero exit
761
761
  # outside a repo — and it carries no path spelling to disagree about. Verified here at a normal root, a
762
762
  # worktree root, a subdirectory and a non-repo.
763
- if PFX="$(git rev-parse --show-prefix 2>/dev/null)" && [ -z "$PFX" ] && git config core.hooksPath .claude/hooks 2>/dev/null; then
763
+ # ABSOLUTE, from git's own answer for the toplevel. A relative value resolves against the work tree a commit runs
764
+ # in, and a linked worktree (one Claude Code opens included) has no .claude/ when it is gitignored: measured, the
765
+ # trace scan blocked a commit at the root and let the same commit through in a worktree, with no hook run at all.
766
+ if PFX="$(git rev-parse --show-prefix 2>/dev/null)" && [ -z "$PFX" ] && TOP="$(git rev-parse --show-toplevel 2>/dev/null)" \
767
+ && [ -n "$TOP" ] && git config core.hooksPath "$TOP/.claude/hooks" 2>/dev/null; then
764
768
  { _mt 'trace scan: core.hooksPath -> .claude/hooks (§4.1/§4.2 commit gate active)'; echo " ${_M}"; }
765
769
  else
766
- { _mt 'NOTE: no git repository at this level; after %s run: %s' "'git init'" 'git config core.hooksPath .claude/hooks'; echo " ${_M}"; }
770
+ { _mt 'NOTE: no git repository at this level; after %s run: %s' "'git init'" "git config core.hooksPath \"\$PWD/.claude/hooks\""; echo " ${_M}"; }
767
771
  fi
768
772
  rm -rf "$SRC"
769
773
  echo