crewforth 3.0.0-rc.2 → 3.0.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 CHANGED
@@ -5,7 +5,7 @@ Crewforth was named Claude Starter Kit until 3.0.0.
5
5
  Notable changes to this project are recorded here. Format follows [Keep a Changelog](https://keepachangelog.com/en/),
6
6
  versioning follows [SemVer](https://semver.org/).
7
7
 
8
- ## [Unreleased] — 3.0.0
8
+ ## [3.0.0] — 2026-09-28
9
9
 
10
10
  ### BREAKING — Claude Starter Kit is now Crewforth
11
11
 
@@ -141,7 +141,8 @@ One name everywhere: the package, the components, the variables, the payload. **
141
141
  - the `.NET` pattern skill the update keeps is not flagged as unvetted in the next session;
142
142
  - the 2.x template sentences in `CLAUDE.md` are brought up to date, and your own lines are left alone.
143
143
  - **The 2.x package name** says which package it forwards to.
144
- - **Replies stay in your language** even when a skill's text is English.
144
+ - **Replies stay in your language** even when a skill's text is English, and a Turkish install says so at every session
145
+ start, so a bare command such as `/crew-doctor` is answered in Turkish too.
145
146
  - **`/crew-review`** runs the closing reviewer whenever the audits leave no critical or high finding; medium and low
146
147
  findings go into its prompt and the report.
147
148
  - **Release asset:** a release candidate's archive carries its own version in the file name.
@@ -4028,6 +4028,30 @@ case "$o" in *'"additionalContext"'*SESSION_STATE*) pass "handover present -> in
4028
4028
  *) fail "session-rehydrate did not inject a pointer when SESSION_STATE.md exists" ;; esac
4029
4029
  if [ -n "$JSONQ" ]; then printf '%s' "$o" | json_ok && pass "rehydrate output is valid JSON ($JSONQ)" || fail "rehydrate output is not valid JSON";
4030
4030
  else skip tool "the rehydrate output JSON-validity check (no working jq)"; fi
4031
+ # The install language (RC-2 rehearsal: a bare /crew-doctor in a Turkish install came back in English). The hook
4032
+ # now runs on startup too and tells the model the install language; the handover is still offered only on a
4033
+ # boundary. Six states, each read by what the hook actually printed: a Turkish install gets the language line on
4034
+ # startup and on a boundary; an English install gets none; startup never offers the handover, a boundary does.
4035
+ # JSON validity is asked of Crewforth's own reader, so it holds on a machine without jq.
4036
+ _rh(){ printf '{"hook_event_name":"SessionStart","cwd":"%s","source":"%s"}' "$RHD" "$1" | CLAUDE_PROJECT_DIR= bash "$HOOKS/session-rehydrate.sh" 2>/dev/null; }
4037
+ _rk(){ case "$1" in *'handover'*) printf 'H' ;; esac; case "$1" in *'installed in Turkish'*) printf 'L' ;; esac; }
4038
+ mkdir -p "$RHD/.claude"
4039
+ printf 'lang=tr\n' > "$RHD/.claude/kit.conf"; _o1="$(_rh startup)"; _o2="$(_rh compact)"
4040
+ printf 'lang=en\n' > "$RHD/.claude/kit.conf"; _o3="$(_rh startup)"; _o4="$(_rh compact)"
4041
+ rm -f "$RHD/docs/SESSION_STATE.md"; _o5="$(_rh startup)"
4042
+ printf 'lang=tr\n' > "$RHD/.claude/kit.conf"; _o6="$(_rh clear)"
4043
+ _got="$(_rk "$_o1")/$(_rk "$_o2")/$(_rk "$_o3")/$(_rk "$_o4")/$(_rk "$_o5")/$(_rk "$_o6")"
4044
+ [ "$_got" = "L/HL//H//L" ] && pass "SessionStart names a Turkish install's language on startup and on a boundary; English adds nothing; startup never offers the handover (6 states)" \
4045
+ || fail "session-rehydrate language/handover states read '$_got', want 'L/HL//H//L' (tr startup · tr compact+handover · en startup · en compact+handover · en startup no handover · tr clear no handover)"
4046
+ _rj=0; for _o in "$_o1" "$_o2" "$_o4" "$_o6"; do printf '%s' "$_o" > "$RHD/o.json"; awk -v op=validate -f "$ROOT/eval/lib/settings-json.awk" "$RHD/o.json" 2>/dev/null || _rj=$((_rj+1)); done
4047
+ [ "$_rj" = 0 ] && pass "each language/handover output is valid JSON (Crewforth's reader, 4 of 4)" || fail "$_rj session-rehydrate output(s) are not valid JSON"
4048
+ # Asked of the entry that carries session-rehydrate, not of the file: skill-trust's entry has the same matcher.
4049
+ _rw(){ _n="$(awk -v op=len -v path=hooks.SessionStart -f "$ROOT/eval/lib/settings-json.awk" "$1" 2>/dev/null)"; _i=0
4050
+ while [ "$_i" -lt "${_n:-0}" ]; do _e="$(awk -v op=get -v path="hooks.SessionStart.$_i" -f "$ROOT/eval/lib/settings-json.awk" "$1" 2>/dev/null)"
4051
+ case "$_e" in *session-rehydrate*) case "$_e" in *'"matcher"'*startup*) return 0 ;; esac ;; esac; _i=$((_i+1)); done; return 1; }
4052
+ sed 's/"startup|resume|clear|compact|fork"/"compact|clear|resume|fork"/' "$ROOT/settings.json" > "$RHD/s-twin.json"
4053
+ if _rw "$ROOT/settings.json" && ! _rw "$RHD/s-twin.json"; then pass "settings.json runs session-rehydrate on startup too; a copy wired as before (no startup) is caught"
4054
+ else fail "session-rehydrate is not wired on startup (or the check cannot tell) — a Turkish install's first session would not be told its language"; fi
4031
4055
  rm -rf "$RHD"
4032
4056
  # board-sync builds its JSON with one awk escaper on every machine. The no-jq escaper it replaced handled only the
4033
4057
  # quote, the backslash and the newline, so a TAB in an item title produced JSON the CLI cannot parse and the board
@@ -8,8 +8,14 @@
8
8
  # - SessionStart is the right event: its stdout / hookSpecificOutput.additionalContext is injected into the
9
9
  # model's context (docs: "Re-inject context after compaction"). PreCompact is NOT used — it can only block
10
10
  # compaction, not add instructions to the summary, and blocking is not what we want.
11
- # - Matched on compact|clear|resume, NOT startup: those three are explicit "continue where I left off" boundaries.
12
- # startup fires on every unrelated session open and would keep surfacing a stale handover — that would nag.
11
+ # - The HANDOVER is offered on compact|clear|resume|fork only, NOT on startup: those are explicit "continue where I
12
+ # left off" boundaries, while startup fires on every unrelated session open and would keep surfacing a stale
13
+ # handover — that would nag. The hook itself also runs on startup, for the language line below; it reads the
14
+ # payload's `source` to tell the two apart (no `source` -> treated as a boundary, the pre-3.0 payload shape).
15
+ # - THE LANGUAGE LINE. A project installed in Turkish (`lang=tr` in .claude/kit.conf) is told so at every session
16
+ # start: reply in Turkish unless the user writes in another language. The RC-2 rehearsal typed a bare
17
+ # `/crew-doctor` in a Turkish install: the doctor printed Turkish and the summary came back in English, because a
18
+ # bare command has no word to take the language from. An English install adds nothing (English is the default).
13
19
  # - CLAUDE.md itself reloads on /compact and /clear on its own, so this hook does NOT re-inject the discipline —
14
20
  # only the session-specific state the reload can't recover.
15
21
  # - Fails OPEN and SILENT: no handover file, no output. It never blocks the session (always exits 0).
@@ -28,13 +34,26 @@ fi
28
34
  # Undo the JSON escaping first (`\\`), then fold any lone separator. Both are no-ops on a POSIX path.
29
35
  ROOT="${ROOT//\\\\//}"; ROOT="${ROOT//\\//}"
30
36
 
31
- STATE="$ROOT/docs/SESSION_STATE.md"
32
- [ -s "$STATE" ] || exit 0 # no (non-empty) handover → nothing to rehydrate, stay silent
37
+ SRC=""
38
+ case "$IN" in *'"source"'*) SRC="${IN#*\"source\"}"; SRC="${SRC#*\"}"; SRC="${SRC%%\"*}" ;; esac
39
+
40
+ LANGMSG=""
41
+ if [ -f "$ROOT/.claude/kit.conf" ]; then
42
+ while IFS= read -r _l || [ -n "$_l" ]; do
43
+ case "${_l%$'\r'}" in lang=tr) LANGMSG="This project was installed in Turkish (lang=tr in .claude/kit.conf). Reply in Turkish unless the user writes in another language, including after a bare command such as /crew-doctor. Commands, paths, file names and identifiers stay as written." ;; esac
44
+ done < "$ROOT/.claude/kit.conf"
45
+ fi
33
46
 
47
+ MSG=""
48
+ STATE="$ROOT/docs/SESSION_STATE.md"
49
+ if [ "$SRC" != startup ] && [ -s "$STATE" ]; then
34
50
  MSG="A session handover from before this context boundary exists at docs/SESSION_STATE.md. If the user's request continues that work, read it first — it holds the in-progress task state, open decisions, and the intended next step — and do not restart from scratch. If the request is about something else, do not bring it up."
51
+ fi
52
+ [ -n "$LANGMSG" ] && MSG="${MSG:+$MSG }$LANGMSG"
53
+ [ -n "$MSG" ] || exit 0 # no handover to offer and nothing to say about language -> stay silent
35
54
 
36
55
  # hookSpecificOutput.additionalContext is the documented channel that injects text into the model's context.
37
- # ONE PATH, no jq: MSG is a fixed constant with no quote, backslash, control character or newline, so it needs no
56
+ # ONE PATH, no jq: MSG is built from fixed constants with no quote, backslash, control character or newline, so it needs no
38
57
  # escaping and every machine emits the same bytes. If you ever make MSG dynamic, escape it the way board-sync.sh
39
58
  # does (jq-identical, measured) — a raw quote or tab here makes JSON the CLI silently drops.
40
59
  printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"%s"}}\n' "$MSG"
package/kit/settings.json CHANGED
@@ -93,7 +93,7 @@
93
93
  ],
94
94
  "SessionStart": [
95
95
  {
96
- "matcher": "compact|clear|resume|fork",
96
+ "matcher": "startup|resume|clear|compact|fork",
97
97
  "hooks": [
98
98
  {
99
99
  "type": "command",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "crewforth",
3
- "version": "3.0.0-rc.2",
4
- "description": "Crewforth — your engineering crew for Claude Code: agents, skills and tool-level gates, in any stack.",
3
+ "version": "3.0.0",
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"
7
7
  },
@@ -15,8 +15,7 @@
15
15
  "kit/",
16
16
  "VERSION",
17
17
  "LICENSE",
18
- "README.md",
19
- "CHANGELOG.md"
18
+ "README.md", "CHANGELOG.md"
20
19
  ],
21
20
  "engines": {
22
21
  "node": ">=20"
@@ -43,7 +42,7 @@
43
42
  "code-review",
44
43
  "git-hooks"
45
44
  ],
46
- "author": "Barış Yerlikaya",
45
+ "author": "Bar\u0131\u015f Yerlikaya",
47
46
  "repository": {
48
47
  "type": "git",
49
48
  "url": "git+https://github.com/Crewforth/crewforth.git"