crewforth 3.0.0 → 3.0.1-rc.2

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +1 -1
  3. package/VERSION +1 -1
  4. package/adopt.sh +222 -19
  5. package/kit/CLAUDE.md +5 -4
  6. package/kit/README.md +1 -1
  7. package/kit/agents/crew-frontend-expert.md +6 -6
  8. package/kit/agents/crew-session-manager.md +1 -1
  9. package/kit/eval/doctor.sh +77 -18
  10. package/kit/eval/golden-routing.txt +15 -0
  11. package/kit/eval/lib/git-bash.sh +108 -0
  12. package/kit/eval/preflight.sh +2 -2
  13. package/kit/eval/smoke-test.sh +761 -29
  14. package/kit/hooks/board-sync.sh +1 -1
  15. package/kit/hooks/board.sh +4 -3
  16. package/kit/hooks/guard-bash.sh +195 -21
  17. package/kit/hooks/guard-commit-scan.sh +2 -2
  18. package/kit/hooks/guard-powershell.sh +328 -0
  19. package/kit/hooks/guard-write.sh +28 -3
  20. package/kit/hooks/route-hint.sh +5 -1
  21. package/kit/hooks/session-update-check.sh +2 -2
  22. package/kit/hooks/skill-trust.sh +57 -14
  23. package/kit/legacy-blobs.tsv +208 -0
  24. package/kit/settings.json +21 -0
  25. package/kit/skills/automode-policy/SKILL.md +1 -1
  26. package/kit/skills/automode-policy/scripts/check.sh +2 -2
  27. package/kit/skills/crew-board/SKILL.md +1 -1
  28. package/kit/skills/crew-doctor/SKILL.md +13 -5
  29. package/kit/skills/crew-gates/SKILL.md +2 -1
  30. package/kit/skills/crew-handoff/SKILL.md +1 -1
  31. package/kit/skills/crew-skill/SKILL.md +2 -2
  32. package/kit/skills/crew-studio/SKILL.md +3 -2
  33. package/kit/skills/crew-update/SKILL.md +3 -3
  34. package/kit/skills/frontend/SKILL.md +26 -2
  35. package/kit/skills/frontend-rn-expo/SKILL.md +3 -0
  36. package/kit/skills/handoff/SKILL.md +2 -2
  37. package/kit/skills/reflect/SKILL.md +2 -2
  38. package/kit/skills/teamboard/SKILL.md +1 -1
  39. package/kit/skills/token-budget/SKILL.md +2 -2
  40. package/kit/skills/trace-scan/SKILL.md +4 -3
  41. package/kit/studio/README.md +1 -1
  42. package/kit/studio/server/lib/permissions.js +3 -0
  43. package/package.json +5 -4
  44. package/start.sh +15 -8
@@ -38,7 +38,7 @@ Appends a single line to the very END of the response:
38
38
 
39
39
  **Actual fill is MEASURED, guessing is FORBIDDEN.** The `UserPromptSubmit` hook runs `context-usage.sh` each turn,
40
40
  automatically injecting the real `🔋 Session: %.. (token) → level` line into the context — use that value. If you want an
41
- exact/fresh reading, run it by hand: `bash .claude/hooks/context-usage.sh`
41
+ exact/fresh reading, run it by hand with the Bash tool, not PowerShell: `bash .claude/hooks/context-usage.sh`
42
42
  (the `input + cache_read + cache_creation` of the last main-context turn in the transcript = the `/context` count).
43
43
  If there's no injected line (hook off / transcript unreachable) **don't invent a %** — run `bash .claude/hooks/context-usage.sh --verbose` once; if that also fails, say so once, drop the 🔋 line for the rest of the session, and only report a topic change.
44
44
 
@@ -59,6 +59,9 @@ _mt() {
59
59
  "no .claude/ in '%s' — is Crewforth installed here?") s="'%s' içinde .claude/ yok — Crewforth burada kurulu mu?" ;;
60
60
  'VERSION present (%s)') s='VERSION var (%s)' ;;
61
61
  'VERSION missing') s='VERSION yok' ;;
62
+ "no install trace: VERSION is here but .claude/kit-manifest.txt is not — the last update did not finish, or .claude/ was copied; run: npx crewforth update --here (information only — nothing was changed)") s="kurulum izi yok: VERSION var ama .claude/kit-manifest.txt yok — son güncelleme bitmemiş ya da .claude/ kopyalanmış; çalıştırın: npx crewforth update --here (yalnız bilgi — hiçbir şey değiştirilmedi)" ;;
63
+ 'no install trace: components the install manifest lists are not here (%s) — the last update did not finish, or .claude/ was copied; run: npx crewforth update --here (information only — nothing was changed; if you removed a component on purpose, ignore this line)') s='kurulum izi yok: kurulum manifestinin listelediği bileşenler burada yok (%s) — son güncelleme bitmemiş ya da .claude/ kopyalanmış; çalıştırın: npx crewforth update --here (yalnız bilgi — hiçbir şey değiştirilmedi; bir bileşeni bilerek sildiyseniz bu satırı yok sayın)' ;;
64
+ 'install trace: the components on disk match the install manifest') s='kurulum izi: diskteki bileşenler kurulum manifestiyle uyuşuyor' ;;
62
65
  'reinstall or update Crewforth (npx crewforth update)') s="Crewforth'u yeniden kurun ya da güncelleyin (npx crewforth update)" ;;
63
66
  'Crewforth v%s installed, v%s published — update with /crew-update') s='Crewforth v%s kurulu, v%s yayında — /crew-update ile güncelleyin' ;;
64
67
  'required git hooks present (pre-commit, commit-msg)') s="gerekli git hook'ları yerinde (pre-commit, commit-msg)" ;;
@@ -96,9 +99,9 @@ _mt() {
96
99
  'skill listing: %s skill(s) use when_to_use or a folded description — a shape the count was not measured on') s='skill listesi: %s skill when_to_use ya da katlanmış açıklama kullanıyor — sayımın ölçülmediği bir biçim' ;;
97
100
  'skill listing %s chars for %s skills fits the %s-char budget (fraction %s from %s, %s-token window%s)') s="skill listesi %s karakter, %s skill; %s karakterlik bütçeye sığıyor (kesir %s, kaynak %s; %s token'lık pencere%s)" ;;
98
101
  'skill listing %s chars for %s skills EXCEEDS the %s-char budget (fraction %s from %s, %s-token window%s)') s="skill listesi %s karakter, %s skill; %s karakterlik bütçeyi AŞIYOR (kesir %s, kaynak %s; %s token'lık pencere%s)" ;;
99
- ' — Claude Code drops the descriptions of the least-used skills, and those stop matching requests.') s=" — Claude Code en az kullanılan skill'lerin açıklamalarını düşürür; o skill'ler isteklerle eşleşmez olur." ;;
102
+ ' — Claude Code drops the descriptions of the least-used skills, and those are less likely to be picked on their own.') s=" — Claude Code en az kullanılan skill'lerin açıklamalarını düşürür; o skill'lerin kendiliğinden seçilmesi zorlaşır." ;;
100
103
  ' Fixes: raise %s in settings, or set rarely-used skills to %s in %s.') s=" Çözüm: ayarlarda %s değerini yükseltin ya da nadir kullanılan skill'leri %s olarak %s içine yazın." ;;
101
- ' Which skills? bash .claude/eval/utilization.sh — it reports the ones nothing in this project reached.') s=" Hangileri? bash .claude/eval/utilization.sh — bu projede hiçbir şeyin ulaşmadığı skill'leri listeler." ;;
104
+ ' Which skills? bash .claude/eval/utilization.sh (Bash tool, not PowerShell) — it reports the ones nothing in this project reached.') s=" Hangileri? bash .claude/eval/utilization.sh (PowerShell değil, Bash aracıyla) — bu projede hiçbir şeyin ulaşmadığı skill'leri listeler." ;;
102
105
  "on a 200,000-token model the whole listing would be ~%s chars (Crewforth %s + your personal skills %s + Claude Code's own ~%s, measured) against %s at fraction %s — the least-used skills there lose their descriptions.") s="200 000 token'lık bir modelde listenin tamamı ~%s karakter olur (Crewforth %s + kişisel skill'leriniz %s + Claude Code'un kendi ~%s, ölçüldü); bütçe ise %s karakter (kesir %s). Orada en az kullanılan skill'ler açıklamalarını kaybeder." ;;
103
106
  ' If you use such a model, one line in %s/settings.json fixes it: %s') s=' Böyle bir model kullanıyorsanız %s/settings.json dosyasına tek satır yeter: %s' ;;
104
107
  ' What it costs: the listing is sent every turn. At 0.04 it stays whole — ~%s chars, about %s tokens,') s=" Bedeli: liste her turda gönderilir. 0.04'te bütün kalır — ~%s karakter, yaklaşık %s token," ;;
@@ -126,6 +129,9 @@ _mt() {
126
129
  'DOCTOR: %s issue(s) ❌ — apply the fixes above%s') s='DOCTOR: %s sorun ❌ — yukarıdaki çözümleri uygulayın%s' ;;
127
130
  'shell gates watch both Bash and PowerShell') s="kabuk kapıları hem Bash'i hem PowerShell'i izliyor" ;;
128
131
  'shell gates watch only Bash — PowerShell commands bypass every §4.5 rule') s="kabuk kapıları yalnız Bash'i izliyor — PowerShell komutları her §4.5 kuralını atlıyor" ;;
132
+ 'shell gates watch only PowerShell — Bash commands bypass every §4.5 rule') s="kabuk kapıları yalnız PowerShell'i izliyor — Bash komutları her §4.5 kuralını atlıyor" ;;
133
+ 'guard-bash.sh is not wired in PreToolUse — every shell command bypasses §4.4/§4.5') s="guard-bash.sh PreToolUse'a bağlı değil — her kabuk komutu §4.4/§4.5'i atlıyor" ;;
134
+ 'update Crewforth (npx crewforth update), which rewires it') s="Crewforth'u güncelleyin (npx crewforth update); bağlantıyı yeniden kurar" ;;
129
135
  'update Crewforth (npx crewforth update), or set the PreToolUse matcher to') s="Crewforth'u güncelleyin (npx crewforth update) ya da PreToolUse matcher'ını şuna ayarlayın:" ;;
130
136
  'auto-mode classifier config: built-ins intact, Crewforth rules present (config, not a gate)') s='auto-mode sınıflandırıcı ayarı: yerleşik kurallar sağlam, Crewforth kuralları var (ayar, kapı değil)' ;;
131
137
  'auto-mode classifier BUILT-INS DROPPED — an autoMode array lacks %s') s='auto-mode sınıflandırıcının YERLEŞİK KURALLARI DÜŞMÜŞ — bir autoMode dizisinde %s yok' ;;
@@ -191,6 +197,31 @@ if [ -f .claude/VERSION ] && [ -f .claude/.state/update-check ]; then
191
197
  fi
192
198
  fi
193
199
 
200
+ # 1c) Install trace. An update leaves VERSION, the install manifest and the components on disk agreeing; when they do
201
+ # not, the last update did not finish or .claude/ came from somewhere else (a copy from another project), and the
202
+ # update's own steps — the legacy sweep, the pattern skill's trust — never ran here. Information only: nothing is
203
+ # changed, the fix is the update. Measured case: a project whose trust record was missing after a 3.0 update.
204
+ if [ -f .claude/VERSION ]; then
205
+ if [ ! -f .claude/kit-manifest.txt ]; then
206
+ warn "no install trace: VERSION is here but .claude/kit-manifest.txt is not — the last update did not finish, or .claude/ was copied; run: npx crewforth update --here (information only — nothing was changed)"
207
+ else
208
+ DTMISS=""
209
+ while IFS= read -r e || [ -n "$e" ]; do
210
+ e="${e%$'\r'}"; case "$e" in ''|'#'*) continue ;; esac
211
+ [ -e ".claude/$e" ] || DTMISS="$DTMISS $e"
212
+ done < .claude/kit-manifest.txt
213
+ # Only "listed but absent" is a signal. A crew-* component on disk that the manifest does not list may be the user's
214
+ # own (review: a user's skills/crew-mine read as a broken install), so it is not reported.
215
+ # A component the user deleted on purpose looks exactly like one an interrupted update never wrote: nothing on disk
216
+ # tells the two apart, and recording deletions would be a new file to keep in step. So the line says it instead.
217
+ if [ -n "$DTMISS" ]; then
218
+ warn "no install trace: components the install manifest lists are not here (%s) — the last update did not finish, or .claude/ was copied; run: npx crewforth update --here (information only — nothing was changed; if you removed a component on purpose, ignore this line)" "${DTMISS# }"
219
+ else
220
+ ok "install trace: the components on disk match the install manifest"
221
+ fi
222
+ fi
223
+ fi
224
+
194
225
  # 2) Hooks present + executable. The .sh set is a glob (extras ok); pre-commit + commit-msg are REQUIRED — they
195
226
  # ARE the §4.1/§4.2 trace/secret gate, so a MISSING one is a failure, not a silent skip.
196
227
  NX=""; GONE=""
@@ -318,9 +349,9 @@ EOF_SLA
318
349
  ok "skill listing %s chars for %s skills fits the %s-char budget (fraction %s from %s, %s-token window%s)" "$LISTING" "$NLISTED" "$BUDGET" "$FRAC" "$FROM" "$CW" "$EST"
319
350
  else
320
351
  warn "skill listing %s chars for %s skills EXCEEDS the %s-char budget (fraction %s from %s, %s-token window%s)" "$LISTING" "$NLISTED" "$BUDGET" "$FRAC" "$FROM" "$CW" "$EST"
321
- warn " — Claude Code drops the descriptions of the least-used skills, and those stop matching requests."
352
+ warn " — Claude Code drops the descriptions of the least-used skills, and those are less likely to be picked on their own."
322
353
  warn " Fixes: raise %s in settings, or set rarely-used skills to %s in %s." '"skillListingBudgetFraction"' '"name-only"' '"skillOverrides"'
323
- warn " Which skills? bash .claude/eval/utilization.sh — it reports the ones nothing in this project reached."
354
+ warn " Which skills? bash .claude/eval/utilization.sh (Bash tool, not PowerShell) — it reports the ones nothing in this project reached."
324
355
  fi
325
356
  # The whole listing, not only Crewforth's share: the user's personal skills and Claude Code's own bundled skills
326
357
  # sit in the same budget. The bundled ones were measured once (14 skills, 5898 chars, Claude Code v2.1.282, an
@@ -465,6 +496,48 @@ if [ -f .claude/DISCIPLINE.md ]; then
465
496
  fi
466
497
  fi
467
498
 
499
+ # 8b) The shell matcher. Claude Code's hooks reference is explicit: inspect shell commands with
500
+ # `Bash|PowerShell`, because wherever the PowerShell tool is enabled it IS the shell — and it is on by
501
+ # default for claude.ai and Console accounts on Windows. An install from before 2.5.0 watches only `Bash`,
502
+ # so every PowerShell command walks past the §4.5 rules with nothing firing. Nothing about the session
503
+ # looks wrong, which is why this is a check and not a release note.
504
+ # The matcher read is the one of the PreToolUse entry that runs guard-bash.sh, through the one JSON reader.
505
+ # Any matcher naming PowerShell used to pass — and 3.0.1 wires guard-powershell.sh on a PowerShell-only entry, so
506
+ # an install whose guard-bash watched only Bash read as healthy (measured). A line-by-line read also answered
507
+ # wrong on another key order or on one-line JSON. Placed BEFORE the verdict, so a failure here counts in it.
508
+ # An entry with no matcher applies to every tool.
509
+ SJ8="${SJ:-.claude/eval/lib/settings-json.awk}"
510
+ if [ -f .claude/settings.json ] && [ -f "$SJ8" ] && awk -v op=validate -f "$SJ8" .claude/settings.json 2>/dev/null; then
511
+ _n8="$(awk -v op=len -v path=hooks.PreToolUse -f "$SJ8" .claude/settings.json 2>/dev/null)" || _n8=0
512
+ _gbm="none"; _i8=0
513
+ while [ "$_i8" -lt "${_n8:-0}" ] 2>/dev/null; do
514
+ case "$(awk -v op=get -v path="hooks.PreToolUse.$_i8.hooks" -f "$SJ8" .claude/settings.json 2>/dev/null)" in
515
+ *guard-bash.sh*) _gbm="$(awk -v op=get -v path="hooks.PreToolUse.$_i8.matcher" -f "$SJ8" .claude/settings.json 2>/dev/null)" || _gbm='"*"'
516
+ _gbm="${_gbm#\"}"; _gbm="${_gbm%\"}"; break ;;
517
+ esac
518
+ _i8=$((_i8+1))
519
+ done
520
+ case "|$_gbm|" in
521
+ "|none|") BAD_TAIL=''
522
+ bad "guard-bash.sh is not wired in PreToolUse — every shell command bypasses §4.4/§4.5" \
523
+ "update Crewforth (npx crewforth update), which rewires it" ;;
524
+ "|*|"|"||"|*"|PowerShell|"*) case "|$_gbm|" in *"|Bash|"*|"|*|"|"||") ok "shell gates watch both Bash and PowerShell" ;;
525
+ *) BAD_TAIL=' "Bash|PowerShell"'
526
+ bad "shell gates watch only PowerShell — Bash commands bypass every §4.5 rule" \
527
+ "update Crewforth (npx crewforth update), or set the PreToolUse matcher to" ;; esac ;;
528
+ *"|Bash|"*) BAD_TAIL=' "Bash|PowerShell"'
529
+ bad "shell gates watch only Bash — PowerShell commands bypass every §4.5 rule" \
530
+ "update Crewforth (npx crewforth update), or set the PreToolUse matcher to" ;;
531
+ *) BAD_TAIL=''
532
+ bad "guard-bash.sh is not wired in PreToolUse — every shell command bypasses §4.4/§4.5" \
533
+ "update Crewforth (npx crewforth update), which rewires it" ;;
534
+ esac
535
+ fi
536
+ # 8c) Windows: can Claude Code find Git Bash? Without one it runs every hook through PowerShell and no gate runs.
537
+ # The check lives in ONE script, eval/lib/git-bash.sh, which the plugin edition's /crew-doctor runs as well. It
538
+ # prints nothing off Windows, and its exit 1 (not found) counts in this verdict.
539
+ _gbs="$(dirname "$0")/lib/git-bash.sh"
540
+ if [ -f "$_gbs" ]; then bash "$_gbs"; [ "$?" = 1 ] && FAIL=$((FAIL+1)); fi
468
541
  echo "---"
469
542
  # The verdict is the line people read, and some read only it. The preflight block
470
543
  # below reports a missing node, but it prints AFTER this — so on a machine that
@@ -494,20 +567,6 @@ if [ "$FAIL" -eq 0 ]; then _mt "DOCTOR: healthy ✅%s" "$PANEL_NOTE"; echo "$_M"
494
567
  [ -f "$(dirname "$0")/lib/star.sh" ] && bash "$(dirname "$0")/lib/star.sh" --once .
495
568
  else _mt "DOCTOR: %s issue(s) ❌ — apply the fixes above%s" "$FAIL" "$PANEL_NOTE"; echo "$_M"; fi
496
569
 
497
- # 8b) The shell matcher. Claude Code's hooks reference is explicit: inspect shell commands with
498
- # `Bash|PowerShell`, because wherever the PowerShell tool is enabled it IS the shell — and it is on by
499
- # default for claude.ai and Console accounts on Windows. An install from before 2.5.0 watches only `Bash`,
500
- # so every PowerShell command walks past the §4.5 rules with nothing firing. Nothing about the session
501
- # looks wrong, which is why this is a check and not a release note.
502
- if [ -f .claude/settings.json ]; then
503
- if grep -q '"matcher"[[:space:]]*:[[:space:]]*"[^"]*PowerShell' .claude/settings.json; then
504
- ok "shell gates watch both Bash and PowerShell"
505
- elif grep -q '"matcher"[[:space:]]*:[[:space:]]*"Bash"' .claude/settings.json; then
506
- BAD_TAIL=' "Bash|PowerShell"'
507
- bad "shell gates watch only Bash — PowerShell commands bypass every §4.5 rule" \
508
- "update Crewforth (npx crewforth update), or set the PreToolUse matcher to"
509
- fi
510
- fi
511
570
  # 9) The auto-mode classifier. Since 2026-08-14 auto mode is the default permission mode on Pro/Max/Team, so a
512
571
  # classifier answers permission prompts the user used to answer. Two things can be wrong and neither shows
513
572
  # up in a session. Only ONE of them is a real gate finding: a custom autoMode block that dropped the
@@ -14,12 +14,20 @@ add a new handler for the order endpoint|crew-backend-expert
14
14
  write a migration for this table|crew-database-expert
15
15
  build a responsive component for the login screen|crew-frontend-expert
16
16
  # Positive twins of the seven over-broad-word rows below: the replacement phrase must still route.
17
+ add a settings screen in the frontend|frontend
18
+ frontend'de bir ekran ekle|frontend
19
+ the UI component re-renders on every keystroke|frontend
17
20
  cut a release and tag it|release
18
21
  review the code in this PR|crew-code-review
19
22
  the page layout is broken on mobile|frontend-design
20
23
  requests are timing out under load|crew-performance-expert
21
24
  add client routing to the app|crew-frontend-expert
22
25
  add a new rn screen with expo router|frontend-rn-expo
26
+ # The client side is stack-neutral (3.0.1): a mobile request on another stack goes to the frontend owner, never to
27
+ # the React Native layer. Turkish as typed in the field, and English.
28
+ flutter ekranı ekle|crew-frontend-expert
29
+ add a SwiftUI view for the profile|crew-frontend-expert
30
+ build a Jetpack Compose screen for settings|crew-frontend-expert
23
31
  run an OWASP check and a full security scan|crew-security-expert
24
32
  we need a kvkk privacy audit|crew-privacy-agent
25
33
  commit the changes|crew-commit-agent
@@ -92,6 +100,13 @@ set up the project structure for a new API|backend-architecture
92
100
  choose a database for this service|backend-architecture
93
101
 
94
102
  # --- Negative: prompt must NOT route to target (over-broad-trigger guard) ---
103
+ flutter ekranı ekle|!frontend-rn-expo
104
+ add a SwiftUI view for the profile|!frontend-rn-expo
105
+ build a Jetpack Compose screen for settings|!frontend-rn-expo
106
+ # Field case (3.0.1, P2 case A): a user handing work over to another team named the area in passing — the bare word
107
+ # "frontend" and a project called <x>_ui each routed it to the frontend skill. Turkish as it was typed, and in English.
108
+ acme_ui için yapılacak iş varsa aktarır mısın? frontend tarafından o sorumlu|!frontend
109
+ if there is work for acme_ui, pass it over — the frontend team owns that|!frontend
95
110
  #
96
111
  # The seven rows below are the ones that were REPORTED FROM LIVE USE, not invented. Each generic English word
97
112
  # was a standalone trigger, and a single trigger of six characters or more clears the score floor on its own —
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env bash
2
+ # Can Claude Code find Git Bash on this Windows machine? The ONE copy of this check: doctor.sh runs it for a full
3
+ # install, and /crew-doctor runs it on a plugin install, where doctor.sh does not ship (eval/lib ships in both).
4
+ #
5
+ # bash eval/lib/git-bash.sh nothing off Windows; on Windows one line (and a fix line), in doctor's format
6
+ # exit 0 found, or not Windows · 1 NOT FOUND, a failure · 3 a warning · 4 not checked (no cygpath)
7
+ #
8
+ # WHY: Claude Code runs every hook through the bash it finds, and without one it runs them through PowerShell, where
9
+ # a Crewforth hook exits 0 and no gate runs — measured in the field (a `git push --force` went through). The lookup
10
+ # is Claude Code's own, read from its 2.1.284 binary, in its order: CLAUDE_CODE_GIT_BASH_PATH (a bash/sh binary that
11
+ # exists) · C:\Program Files\Git\bin\bash.exe · C:\Program Files (x86)\Git\bin\bash.exe ·
12
+ # <git.exe on PATH>\..\..\bin\bash.exe. The bash running THIS script proves nothing: it can come from anywhere on
13
+ # PATH. The last step depends on the PATH Claude Code starts with, which is not this shell's (Git Bash puts its own
14
+ # git first), so a bash found only there is a warning.
15
+ set -u
16
+ RC=0
17
+
18
+ # Language: CREW_LANG, else the install's kit.conf, else the locale — the doctor's rule, so both editions agree.
19
+ case "${CREW_LANG:-}" in tr|en) ;; *)
20
+ CREW_LANG=""
21
+ if [ -f .claude/kit.conf ]; then
22
+ while IFS= read -r _l || [ -n "$_l" ]; do case "$_l" in lang=*) CREW_LANG="${_l#lang=}"; CREW_LANG="${CREW_LANG%$'\r'}" ;; esac; done < .claude/kit.conf
23
+ fi
24
+ case "$CREW_LANG" in tr|en) ;; *)
25
+ _loc="${LC_ALL:-}"; [ -n "$_loc" ] || _loc="${LC_MESSAGES:-}"; [ -n "$_loc" ] || _loc="${LANG:-}"
26
+ case "$_loc" in tr*|TR*) CREW_LANG=tr ;; *) CREW_LANG=en ;; esac ;;
27
+ esac ;;
28
+ esac
29
+ # The English string is the key; a missing translation prints English and lands in CREW_I18N_MISS (smoke reads it).
30
+ _mt(){ local s="$1"; shift
31
+ if [ "$CREW_LANG" = tr ]; then
32
+ case "$s" in
33
+ 'fix: ') s='çözüm: ' ;;
34
+ 'Git Bash lookup not checked (no cygpath in this shell)') s='Git Bash araması denetlenmedi (bu kabukta cygpath yok)' ;;
35
+ 'CLAUDE_CODE_GIT_BASH_PATH (%s) is not a bash that exists — Claude Code ignores it') s='CLAUDE_CODE_GIT_BASH_PATH (%s) var olan bir bash değil — Claude Code onu yok sayıyor' ;;
36
+ 'Claude Code finds Git Bash (%s) — hooks run under bash') s="Claude Code Git Bash'i buluyor (%s) — hook'lar bash altında koşuyor" ;;
37
+ 'Claude Code finds Git Bash only through git on PATH (%s) — started without it on PATH, its hooks run under PowerShell and the gates do not run; set CLAUDE_CODE_GIT_BASH_PATH to that path') s="Claude Code Git Bash'i yalnız PATH'teki git üzerinden buluyor (%s) — PATH'te o yokken başlarsa hook'lar PowerShell altında koşar ve kapılar çalışmaz; CLAUDE_CODE_GIT_BASH_PATH'i bu yola ayarlayın" ;;
38
+ 'Git Bash is installed for this user only (%s), where Claude Code does not look — its hooks may run under PowerShell and the gates may not run') s="Git Bash yalnız bu kullanıcı için kurulu (%s) ve Claude Code oraya bakmıyor — hook'lar PowerShell altında koşabilir ve kapılar çalışmayabilir" ;;
39
+ 'set CLAUDE_CODE_GIT_BASH_PATH to') s="CLAUDE_CODE_GIT_BASH_PATH'i şuna ayarlayın:" ;;
40
+ "Claude Code cannot find Git Bash — its hooks run under PowerShell and Crewforth's gates do not run") s="Claude Code Git Bash'i bulamıyor — hook'lar PowerShell altında koşuyor ve Crewforth'un kapıları çalışmıyor" ;;
41
+ 'install Git for Windows in its default folder, or set CLAUDE_CODE_GIT_BASH_PATH to') s="Git for Windows'u varsayılan klasörüne kurun ya da CLAUDE_CODE_GIT_BASH_PATH'i şuna ayarlayın:" ;;
42
+ *) [ -n "${CREW_I18N_MISS:-}" ] && printf '%s\n' "$s" >> "$CREW_I18N_MISS" ;;
43
+ esac
44
+ fi
45
+ printf -v _M "$s" "$@"; }
46
+ ok(){ _mt "$@"; echo " ✅ $_M"; }
47
+ warn(){ _mt "$@"; echo " ⚠️ $_M"; [ "$RC" = 0 ] && RC=3; }
48
+ skip(){ _mt "$@"; echo " · $_M"; RC=4; }
49
+ # bad MESSAGE FIX [arguments for MESSAGE]: the fix takes none; what follows it goes in BAD_TAIL, printed once.
50
+ bad(){ local _m="$1" _x="$2"; shift 2; _mt "$_m" "$@"; echo " ❌ $_M"; _mt "fix: "; local _f="$_M"; _mt "$_x"
51
+ echo " ↳ $_f$_M${BAD_TAIL:-}"; BAD_TAIL=""; RC=1; }
52
+
53
+ case "$(uname -s 2>/dev/null)" in MINGW*|MSYS*|CYGWIN*)
54
+ if ! command -v cygpath >/dev/null 2>&1; then
55
+ skip "Git Bash lookup not checked (no cygpath in this shell)"
56
+ else
57
+ # Exists the way Claude Code's existsSync means it: MSYS answers `[ -f …/bash ]` true when only bash.exe is
58
+ # there, so a name without .exe must also appear in its folder's listing (case-insensitively, as Windows does).
59
+ _gbx(){ local u d f n; u="$(cygpath -u "$1" 2>/dev/null)" || return 1; [ -n "$u" ] && [ -f "$u" ] || return 1
60
+ case "$u" in *.[Ee][Xx][Ee]) return 0 ;; esac
61
+ d="${u%/*}"; n="$(printf '%s' "${u##*/}" | tr '[:upper:]' '[:lower:]')"
62
+ for f in "$d"/*; do [ "$(printf '%s' "${f##*/}" | tr '[:upper:]' '[:lower:]')" = "$n" ] && return 0; done; return 1; }
63
+ _gbf=""; _gbv="${CLAUDE_CODE_GIT_BASH_PATH:-}"
64
+ if [ -n "$_gbv" ]; then
65
+ _gbn="${_gbv##*[\\/]}"; _gbn="$(printf '%s' "$_gbn" | tr '[:upper:]' '[:lower:]')"
66
+ case "$_gbn" in bash.exe|sh.exe|bash|sh) _gbx "$_gbv" && _gbf="$_gbv" ;; esac
67
+ [ -n "$_gbf" ] || warn "CLAUDE_CODE_GIT_BASH_PATH (%s) is not a bash that exists — Claude Code ignores it" "$_gbv"
68
+ fi
69
+ if [ -z "$_gbf" ]; then
70
+ for _gbc in 'C:\Program Files\Git\bin\bash.exe' 'C:\Program Files (x86)\Git\bin\bash.exe'; do
71
+ _gbx "$_gbc" && { _gbf="$_gbc"; break; }
72
+ done
73
+ fi
74
+ if [ -n "$_gbf" ]; then ok "Claude Code finds Git Bash (%s) — hooks run under bash" "$_gbf"
75
+ else
76
+ # A per-user Git for Windows install lives in %LOCALAPPDATA%\Programs\Git — none of Claude Code's fixed folders.
77
+ # Checked FIRST and counted: such an install usually puts its cmd folder on PATH, so Claude Code's last step
78
+ # may find it, but that hangs on the PATH Claude Code starts with, and the field's per-user install ran its hooks
79
+ # under PowerShell. The path in the advice is the one that exists here, never a guess.
80
+ _gbu=""
81
+ if [ -n "${LOCALAPPDATA:-}" ] && _gbl="$(cygpath -u "$LOCALAPPDATA" 2>/dev/null)" && [ -n "$_gbl" ]; then
82
+ _gbu="$(cygpath -w "$_gbl/Programs/Git/bin/bash.exe" 2>/dev/null)" || _gbu=""
83
+ [ -n "$_gbu" ] && _gbx "$_gbu" || _gbu=""
84
+ fi
85
+ _gbp=""
86
+ [ -n "$_gbu" ] || while IFS= read -r _gbg; do
87
+ [ -n "$_gbg" ] || continue
88
+ _gbw="$(cygpath -w "$_gbg" 2>/dev/null)" || continue
89
+ _gbw="${_gbw%\\*}"; _gbw="${_gbw%\\*}"'\bin\bash.exe'
90
+ _gbx "$_gbw" && { _gbp="$_gbw"; break; }
91
+ done <<GBEOF
92
+ $(type -ap git 2>/dev/null)
93
+ GBEOF
94
+ if [ -n "$_gbu" ]; then
95
+ BAD_TAIL=" \"$_gbu\""
96
+ bad "Git Bash is installed for this user only (%s), where Claude Code does not look — its hooks may run under PowerShell and the gates may not run" \
97
+ "set CLAUDE_CODE_GIT_BASH_PATH to" "$_gbu"
98
+ elif [ -n "$_gbp" ]; then
99
+ warn "Claude Code finds Git Bash only through git on PATH (%s) — started without it on PATH, its hooks run under PowerShell and the gates do not run; set CLAUDE_CODE_GIT_BASH_PATH to that path" "$_gbp"
100
+ else
101
+ BAD_TAIL=' <Git>\bin\bash.exe' # a backslash in the key would be a printf escape
102
+ bad "Claude Code cannot find Git Bash — its hooks run under PowerShell and Crewforth's gates do not run" \
103
+ "install Git for Windows in its default folder, or set CLAUDE_CODE_GIT_BASH_PATH to"
104
+ fi
105
+ fi
106
+ fi ;;
107
+ esac
108
+ exit "$RC"
@@ -108,7 +108,7 @@ _mt() {
108
108
  "Optional gaps above are safe but worth closing.") s='Yukarıdaki isteğe bağlı eksikler sorun çıkarmaz ama gidermeye değer.' ;;
109
109
  "Everything Crewforth needs is here.") s="Crewforth'un ihtiyaç duyduğu her şey kurulu." ;;
110
110
  "is the panel only — every gate still holds without it.") s='yalnızca panel için gerekli — o olmadan da tüm kapılar çalışır.' ;;
111
- "Or let Crewforth get one: %s") s='İsterseniz Crewforth sizin için indirebilir: %s' ;;
111
+ "Or let Crewforth get one (Bash tool, not PowerShell): %s") s='İsterseniz Crewforth sizin için indirebilir (PowerShell değil, Bash aracıyla): %s' ;;
112
112
  "fix: ") s='çözüm: ' ;;
113
113
  "node 18+") s='node 18+' ;;
114
114
  "sha256 tool") s='sha256 aracı' ;;
@@ -171,7 +171,7 @@ if [ -n "$MISSING_REQ" ]; then
171
171
  *node*) _mt 'is the panel only — every gate still holds without it.'; printf ' %snode%s %s\n' "$B" "$R" "$_M"
172
172
  # And it is not a dead end: Crewforth fetches a runtime for the panel itself, into one
173
173
  # directory under $HOME, verified against the published checksum. It asks first.
174
- printf ' %s\n' "$(m 'Or let Crewforth get one: %s' "${B}bash .claude/studio/ensure-node.sh --plan${R}")" ;;
174
+ printf ' %s\n' "$(m 'Or let Crewforth get one (Bash tool, not PowerShell): %s' "${B}bash .claude/studio/ensure-node.sh --plan${R}")" ;;
175
175
  esac
176
176
  elif [ -n "$MISSING_OPT" ]; then
177
177
  [ "$QUIET" = 1 ] || { _mt 'All required tools present.'; _a="$_M"; _mt 'Optional gaps above are safe but worth closing.'