mirror of
https://github.com/Donchitos/Claude-Code-Game-Studios.git
synced 2026-10-16 09:58:36 +00:00
Release 1.1.2 — the default path works end to end
Fix release for 1.1.1: the minimal path end to end, engine commands that run on Godot, Unity and Unreal, hook warnings you can see, and verdicts that say when they could not check. Details in CHANGELOG.md; upgrade steps in UPGRADING.md (v1.1.1 → v1.1.2). Fixes #67 Fixes #131 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WuJn2FdynEybfL5KC697nJ
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7ed2c3e9c4
commit
b21fa0f7f2
+99
-20
@@ -35,14 +35,17 @@ fi
|
||||
input=$(cat)
|
||||
|
||||
# --- Parse JSON (jq with grep fallback) ---
|
||||
# project_dir first: current_dir follows every `cd`, so after `cd src` the
|
||||
# status line looked for project.yaml in src/ and fell back to guessing.
|
||||
if command -v jq &>/dev/null; then
|
||||
model=$(echo "$input" | jq -r '.model.display_name // "Unknown"')
|
||||
used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
|
||||
cwd=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // ""')
|
||||
cwd=$(echo "$input" | jq -r '.workspace.project_dir // .workspace.current_dir // .cwd // ""')
|
||||
else
|
||||
model=$(echo "$input" | grep -oE '"display_name"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
|
||||
used_pct=$(echo "$input" | grep -oE '"used_percentage"[[:space:]]*:[[:space:]]*[0-9]+' | head -1 | sed 's/.*: *//')
|
||||
cwd=$(echo "$input" | grep -oE '"current_dir"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
|
||||
cwd=$(echo "$input" | grep -oE '"project_dir"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
|
||||
[ -z "$cwd" ] && cwd=$(echo "$input" | grep -oE '"current_dir"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
|
||||
[ -z "$model" ] && model="Unknown"
|
||||
fi
|
||||
|
||||
@@ -57,13 +60,26 @@ else
|
||||
ctx_label="ctx: --"
|
||||
fi
|
||||
|
||||
# --- Config helper, sourced ONCE, interpreter resolved ONCE ---
|
||||
# Every read is `$(get_yaml_key ...)`, a subshell, so the interpreter the
|
||||
# helper caches on first use never reached this shell, and every read probed
|
||||
# for Python again first -- one interpreter spawn per setting read instead of
|
||||
# one for the whole render. Resolving it here, in this shell, lets every
|
||||
# subshell inherit it. Success is whether the function exists, not the
|
||||
# source's exit status.
|
||||
project_yaml="$cwd/project.yaml"
|
||||
yaml_helper="$cwd/.claude/hooks/yaml-helper.sh"
|
||||
helper=false
|
||||
if [ -f "$yaml_helper" ]; then
|
||||
source "$yaml_helper" 2>/dev/null
|
||||
command -v get_yaml_key >/dev/null 2>&1 && helper=true
|
||||
[ "$helper" = true ] && [ -f "$project_yaml" ] && _yaml_helper_resolve_python >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# --- Production stage ---
|
||||
# Priority 1: project.stage from project.yaml
|
||||
stage=""
|
||||
project_yaml="$cwd/project.yaml"
|
||||
yaml_helper="$cwd/.claude/hooks/yaml-helper.sh"
|
||||
if [ -f "$project_yaml" ] && [ -f "$yaml_helper" ]; then
|
||||
source "$yaml_helper"
|
||||
if [ -f "$project_yaml" ] && [ "$helper" = true ]; then
|
||||
stage=$(get_yaml_key "$project_yaml" project.stage 2>/dev/null)
|
||||
fi
|
||||
# Priority 2: legacy stage.txt fallback
|
||||
@@ -89,9 +105,7 @@ if [ -z "$stage" ]; then
|
||||
[ -f "$systems_file" ] && has_systems=true
|
||||
|
||||
# Check if engine is configured (project.yaml first, fall back to technical-preferences.md)
|
||||
if [ -f "$project_yaml" ] && [ -f "$yaml_helper" ]; then
|
||||
# yaml-helper may have been sourced above for stage; sourcing again is idempotent
|
||||
source "$yaml_helper"
|
||||
if [ -f "$project_yaml" ] && [ "$helper" = true ]; then
|
||||
engine_name=$(get_yaml_key "$project_yaml" engine.name 2>/dev/null)
|
||||
[ -n "$engine_name" ] && engine_configured=true
|
||||
fi
|
||||
@@ -108,9 +122,17 @@ if [ -z "$stage" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Count source files (language-agnostic)
|
||||
if [ -d "$cwd/src" ]; then
|
||||
src_count=$(find "$cwd/src" -type f \( -name "*.gd" -o -name "*.cs" -o -name "*.cpp" -o -name "*.h" -o -name "*.py" -o -name "*.rs" -o -name "*.lua" -o -name "*.tscn" -o -name "*.tres" \) 2>/dev/null | wc -l | tr -d ' ')
|
||||
# Count source files (language-agnostic) under the engine's code root --
|
||||
# src/, Assets/ or Source/ (directory-structure.md). Counting src/ alone left
|
||||
# every Unity and Unreal project at 0, so this ladder never reached
|
||||
# Production. Capped at the threshold below: the status line runs on every
|
||||
# turn, and Unity's Assets/ can hold thousands of files, so find stops at 10.
|
||||
code_root=""
|
||||
if [ "$helper" = true ] && command -v resolve_code_root >/dev/null 2>&1; then
|
||||
code_root=$(cd "$cwd" 2>/dev/null && resolve_code_root 2>/dev/null | cut -f1)
|
||||
fi
|
||||
if [ -n "$code_root" ] && [ -d "$cwd/$code_root" ]; then
|
||||
src_count=$(find "$cwd/$code_root" -type f \( -name "*.gd" -o -name "*.cs" -o -name "*.cpp" -o -name "*.h" -o -name "*.py" -o -name "*.rs" -o -name "*.lua" -o -name "*.tscn" -o -name "*.tres" \) 2>/dev/null | head -n 10 | wc -l | tr -d ' ')
|
||||
fi
|
||||
|
||||
# Check for ADRs (signals Pre-Production phase)
|
||||
@@ -137,11 +159,11 @@ fi
|
||||
|
||||
# --- Process posture (modes.rigor) ---
|
||||
# Locked to project.yaml (not locally overridable) with a plain terminal default
|
||||
# of 'standard', so a direct get_yaml_key read + default is exact. Deliberately
|
||||
# NOT resolve_setting: that assumes PWD is the project root, unsafe here since the
|
||||
# status line works from an absolute $cwd and never cd's.
|
||||
# in _yaml_helper_defaults, so a direct get_yaml_key read + default is exact.
|
||||
# Deliberately NOT resolve_setting: that assumes PWD is the project root, unsafe
|
||||
# here since the status line works from an absolute $cwd and never cd's.
|
||||
#
|
||||
# The 'standard' default applies ONLY when nothing contradicts it. If `rigor` is
|
||||
# The default applies ONLY when nothing contradicts it. If `rigor` is
|
||||
# unset but a knob it fronts is set explicitly, the project's real process weight
|
||||
# is whatever that knob says, and printing 'standard' actively misreports it —
|
||||
# migration is the common case, writing `modes.review_mode` and no `modes.rigor`,
|
||||
@@ -150,11 +172,21 @@ fi
|
||||
# config, no claim. Suppression is correct rather than lossy — the fronted knobs
|
||||
# disagree with each other in this state, so there is no single honest posture.
|
||||
rigor=""
|
||||
if [ -f "$project_yaml" ] && [ -f "$yaml_helper" ]; then
|
||||
source "$yaml_helper"
|
||||
rigor_val="" # the resolved rigor, kept even when the displayed posture is suppressed
|
||||
if [ -f "$project_yaml" ] && [ "$helper" = true ]; then
|
||||
rigor=$(get_yaml_key "$project_yaml" modes.rigor 2>/dev/null)
|
||||
rigor_val="$rigor"
|
||||
if [ -z "$rigor" ]; then
|
||||
rigor="standard"
|
||||
# The default comes from its single source. This line hard-coded 'standard'
|
||||
# and kept printing it after 1.1.0 flipped the default to 'minimal' --
|
||||
# 'Concept · standard' on the shipped project.yaml while every skill resolved
|
||||
# minimal. Read in-process: a $(get_yaml_default ...) is a spawn every turn.
|
||||
while IFS= read -r _d; do
|
||||
case "$_d" in "modes.rigor::"*) rigor="${_d#modes.rigor::}"; break ;; esac
|
||||
done <<EOF
|
||||
$_yaml_helper_defaults
|
||||
EOF
|
||||
rigor_val="$rigor"
|
||||
# Cheap pre-filter first. This hook runs every turn, and the common case
|
||||
# (nothing fronted set) must not cost a get_yaml_key subprocess per key.
|
||||
# The grep is a deliberate SUPERSET — it matches the leaf names anywhere at
|
||||
@@ -174,6 +206,52 @@ if [ -f "$project_yaml" ] && [ -f "$yaml_helper" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Minimal path position (workflow: minimal) ---
|
||||
# Nothing on the minimal path runs /gate-check, so project.stage never leaves
|
||||
# Concept there: 'Concept · minimal' for a project with most of its stories
|
||||
# built. At that tier the path position is the honest stage -- stories Complete
|
||||
# of stories written, from the header Status lines /dev-story and /story-done
|
||||
# keep. project.stage itself is left alone: only a /gate-check PASS (or a
|
||||
# CONCERNS whose risks you accepted) moves it.
|
||||
# Gated on the RESOLVED workflow: an explicit modes.workflow wins, otherwise it
|
||||
# follows rigor. Gating on rigor alone left an explicit `workflow: minimal`
|
||||
# under another rigor showing Concept. Builtins only -- no spawn per story.
|
||||
path_pos=""
|
||||
_wf=""
|
||||
if [ -f "$project_yaml" ] && [ "$helper" = true ]; then
|
||||
_wf="$rigor_val"
|
||||
IFS= read -r -d '' _yaml < "$project_yaml"
|
||||
case "$_yaml" in
|
||||
*[[:space:]]workflow:*)
|
||||
_w=$(get_yaml_key "$project_yaml" modes.workflow 2>/dev/null)
|
||||
[ -n "$_w" ] && _wf="$_w" ;;
|
||||
esac
|
||||
fi
|
||||
if [ "$_wf" = "minimal" ]; then
|
||||
_total=0; _done=0
|
||||
for _s in "$cwd"/production/epics/*/story-*.md; do
|
||||
[ -f "$_s" ] || continue
|
||||
_total=$((_total+1))
|
||||
while IFS= read -r _line || [ -n "$_line" ]; do
|
||||
# Normalise `> **Status**: X`, `**Status:** X`, `- Status: X` to
|
||||
# `Status: X`, then match the value's leading word EXACTLY, in any case:
|
||||
# a substring match on *Done* counted "Not Done". The word ends at the
|
||||
# first non-letter, so `Done.` and `Complete, verified` count -- the
|
||||
# rule story-status.sh applies, which /help and /sprint-status read.
|
||||
# `|| [ -n ]` reads a last line with no newline, which read -r drops.
|
||||
_l="${_line%$'\r'}"; _l="${_l#"${_l%%[![:space:]]*}"}"; _l="${_l#> }"; _l="${_l#- }"; _l="${_l//\*/}"
|
||||
case "$_l" in
|
||||
Status:*)
|
||||
_v="${_l#Status:}"; _v="${_v#"${_v%%[![:space:]]*}"}"; _v="${_v%%[!A-Za-z]*}"
|
||||
case "$_v" in [Cc][Oo][Mm][Pp][Ll][Ee][Tt][Ee]|[Dd][Oo][Nn][Ee]) _done=$((_done+1)) ;; esac
|
||||
break ;;
|
||||
esac
|
||||
done < "$_s"
|
||||
done
|
||||
if [ "$_total" -gt 0 ]; then path_pos="Minimal · ${_done}/${_total} stories"
|
||||
else path_pos="Minimal · brief"; fi
|
||||
fi
|
||||
|
||||
# --- Epic/Feature/Task breadcrumb (Production+ only) ---
|
||||
breadcrumb=""
|
||||
if [ "$stage" = "Production" ] || [ "$stage" = "Polish" ] || [ "$stage" = "Release" ]; then
|
||||
@@ -206,4 +284,5 @@ if [ "$stage" = "Production" ] || [ "$stage" = "Polish" ] || [ "$stage" = "Relea
|
||||
fi
|
||||
|
||||
# --- Assemble ---
|
||||
printf "%s" "${ctx_label} | ${model} | ${stage}${rigor:+ · $rigor}${breadcrumb}"
|
||||
if [ -n "$path_pos" ]; then segment="$path_pos"; else segment="${stage}${rigor:+ · $rigor}"; fi
|
||||
printf "%s" "${ctx_label} | ${model} | ${segment}${breadcrumb}"
|
||||
|
||||
Reference in New Issue
Block a user