@the-bearded-bear/claude-craft 8.26.0-next.2a54921 → 8.26.0-next.3cb6254
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/Dev/i18n/de/Common/commands/ralph-run.md +6 -0
- package/Dev/i18n/en/Common/commands/ralph-run.md +6 -0
- package/Dev/i18n/es/Common/commands/ralph-run.md +6 -0
- package/Dev/i18n/fr/Common/commands/ralph-run.md +6 -0
- package/Dev/i18n/pt/Common/commands/ralph-run.md +6 -0
- package/Dev/scripts/install-common-rules.sh +8 -0
- package/README.md +2 -2
- package/Tools/Ralph/lib/checkpoint.sh +3 -3
- package/Tools/Ralph/lib/circuit-breaker.sh +10 -10
- package/Tools/Ralph/lib/context-manager.sh +56 -65
- package/Tools/Ralph/lib/context-reconstruction.sh +46 -79
- package/Tools/Ralph/lib/dod-templates.sh +2 -2
- package/Tools/Ralph/lib/dod-validator.sh +18 -18
- package/Tools/Ralph/lib/escalation-service.sh +9 -7
- package/Tools/Ralph/lib/hooks-generator.sh +2 -1
- package/Tools/Ralph/lib/loop-finalizer.sh +1 -1
- package/Tools/Ralph/lib/loop.sh +44 -10
- package/Tools/Ralph/lib/metrics-exporter.sh +1 -1
- package/Tools/Ralph/lib/parallel-manager.sh +173 -88
- package/Tools/Ralph/lib/project-detector.sh +3 -3
- package/Tools/Ralph/lib/recovery-engine.sh +8 -8
- package/Tools/Ralph/lib/session.sh +2 -2
- package/Tools/Ralph/lib/sprint-conductor.sh +167 -124
- package/Tools/Ralph/lib/sprint-progress.sh +9 -9
- package/Tools/Ralph/ralph.sh +66 -38
- package/Tools/StatusLine/statusline.sh +0 -0
- package/Tools/i18n/ralph/de.sh +165 -33
- package/Tools/i18n/ralph/en.sh +132 -0
- package/Tools/i18n/ralph/es.sh +209 -77
- package/Tools/i18n/ralph/fr.sh +234 -102
- package/Tools/i18n/ralph/pt.sh +227 -95
- package/bundles/cursor/.cursorrules +1 -1
- package/bundles/windsurf/.windsurfrules +1 -1
- package/package.json +1 -1
|
@@ -51,6 +51,12 @@ Führt Claude in einer kontinuierlichen Schleife aus, bis die Aufgabe abgeschlos
|
|
|
51
51
|
- Maximale Iterationen, Timeouts, DoD-Kriterien festlegen
|
|
52
52
|
- Hooks initialisieren, falls aktiviert
|
|
53
53
|
|
|
54
|
+
#### Isolierung von Sessions und parallelen Workern
|
|
55
|
+
|
|
56
|
+
- **Explizite Claude-Session**: Jede Ralph-Session legt ihre eigene Claude-Konversations-ID fest — `claude --session-id <uuid>` in der ersten Iteration, danach `claude --resume <uuid>`. Die UUID wird in `.ralph/sessions/<session>/claude_session_id` gespeichert, sodass `--continue=<session>` die richtige Konversation fortsetzt. Ralph verwendet `claude --continue` nicht mehr, das „die neueste Konversation im Verzeichnis“ fortsetzte (geteilt zwischen Workern oder sogar mit der interaktiven Session des Benutzers).
|
|
57
|
+
- **Ein Git-Worktree pro Worker** (paralleler Modus, `lib/parallel-manager.sh`): Jede Story läuft in einem eigenen Worktree `.ralph/parallel/worktrees/<session>` auf dem Branch `ralph/<session>`, mit ihrem Ralph-Zustand unter `.ralph/parallel/sessions/<session>/ralph/`. Am Ende des Laufs werden verbleibende Änderungen als `wip(ralph): <story>` auf diesem Branch committet, danach wird der Worktree entfernt (`git worktree remove`). Schlägt dieser Commit fehl, bleibt der Worktree erhalten (kein Datenverlust) und wird in `output.log` gemeldet. Die Arbeit wird durch Mergen der `ralph/*`-Branches übernommen.
|
|
58
|
+
- **Außerhalb eines Git-Repositorys**: kein Worktree; der Worker läuft im aktuellen Verzeichnis (eine Warnung wird ausgegeben), die Isolierung der Claude-Sessions bleibt bestehen.
|
|
59
|
+
|
|
54
60
|
### 2. Hauptschleife mit Dashboard
|
|
55
61
|
|
|
56
62
|
```
|
|
@@ -51,6 +51,12 @@ Execute Claude in a continuous loop until the task is complete or the Definition
|
|
|
51
51
|
- Set max iterations, timeouts, DoD criteria
|
|
52
52
|
- Initialize hooks if enabled
|
|
53
53
|
|
|
54
|
+
#### Session and parallel worker isolation
|
|
55
|
+
|
|
56
|
+
- **Explicit Claude session**: each Ralph session pins its own Claude conversation ID — `claude --session-id <uuid>` on the first iteration, then `claude --resume <uuid>`. The UUID is stored in `.ralph/sessions/<session>/claude_session_id`, so `--continue=<session>` resumes the right conversation. Ralph no longer uses `claude --continue`, which resumed "the most recent conversation in the directory" (shared between workers, or even with the user's interactive session).
|
|
57
|
+
- **One git worktree per worker** (parallel mode, `lib/parallel-manager.sh`): each story runs in a dedicated worktree `.ralph/parallel/worktrees/<session>` on branch `ralph/<session>`, with its Ralph state under `.ralph/parallel/sessions/<session>/ralph/`. At the end of the run, leftover changes are committed as `wip(ralph): <story>` on that branch, then the worktree is removed (`git worktree remove`). If that commit fails, the worktree is kept (no data loss) and reported in `output.log`. Collect the work by merging the `ralph/*` branches.
|
|
58
|
+
- **Outside a git repository**: no worktree; the worker runs in the current directory (a warning is printed), Claude session isolation still applies.
|
|
59
|
+
|
|
54
60
|
### 2. Main Loop with Dashboard
|
|
55
61
|
|
|
56
62
|
```
|
|
@@ -51,6 +51,12 @@ Ejecuta Claude en un bucle continuo hasta que la tarea esté completa o se cumpl
|
|
|
51
51
|
- Establecer máximo de iteraciones, timeouts y criterios DoD
|
|
52
52
|
- Inicializar hooks si están habilitados
|
|
53
53
|
|
|
54
|
+
#### Aislamiento de sesiones y workers paralelos
|
|
55
|
+
|
|
56
|
+
- **Sesión de Claude explícita**: cada sesión de Ralph fija su propio identificador de conversación de Claude — `claude --session-id <uuid>` en la primera iteración y luego `claude --resume <uuid>`. El UUID se guarda en `.ralph/sessions/<session>/claude_session_id`, de modo que `--continue=<session>` reanuda la conversación correcta. Ralph ya no usa `claude --continue`, que reanudaba «la conversación más reciente del directorio» (compartida entre workers, o incluso con la sesión interactiva del usuario).
|
|
57
|
+
- **Un worktree de git por worker** (modo paralelo, `lib/parallel-manager.sh`): cada historia se ejecuta en un worktree dedicado `.ralph/parallel/worktrees/<session>` sobre la rama `ralph/<session>`, con su estado de Ralph en `.ralph/parallel/sessions/<session>/ralph/`. Al final de la ejecución, los cambios pendientes se confirman como `wip(ralph): <story>` en esa rama y después se elimina el worktree (`git worktree remove`). Si ese commit falla, el worktree se conserva (sin pérdida de datos) y se indica en `output.log`. El trabajo se recupera fusionando las ramas `ralph/*`.
|
|
58
|
+
- **Fuera de un repositorio git**: sin worktree; el worker se ejecuta en el directorio actual (se muestra un aviso) y el aislamiento de sesiones de Claude se mantiene.
|
|
59
|
+
|
|
54
60
|
### 2. Bucle Principal con Dashboard
|
|
55
61
|
|
|
56
62
|
```
|
|
@@ -51,6 +51,12 @@ Exécuter Claude en boucle continue jusqu'à ce que la tâche soit terminée ou
|
|
|
51
51
|
- Définir les itérations max, les timeouts, les critères DoD
|
|
52
52
|
- Initialiser les hooks si activés
|
|
53
53
|
|
|
54
|
+
#### Isolation des sessions et des workers parallèles
|
|
55
|
+
|
|
56
|
+
- **Session Claude explicite** : chaque session Ralph fixe son propre identifiant de conversation Claude — `claude --session-id <uuid>` à la première itération, puis `claude --resume <uuid>`. L'UUID est stocké dans `.ralph/sessions/<session>/claude_session_id`, ce qui permet à `--continue=<session>` de reprendre la bonne conversation. Ralph n'utilise plus `claude --continue`, qui reprenait « la conversation la plus récente du répertoire » (partagée entre workers, voire avec une session interactive de l'utilisateur).
|
|
57
|
+
- **Worktree git par worker** (mode parallèle, `lib/parallel-manager.sh`) : chaque story s'exécute dans un worktree dédié `.ralph/parallel/worktrees/<session>` sur la branche `ralph/<session>`, avec son état Ralph sous `.ralph/parallel/sessions/<session>/ralph/`. En fin de run, les modifications restantes sont commitées en `wip(ralph): <story>` sur cette branche, puis le worktree est retiré (`git worktree remove`). Si ce commit échoue, le worktree est conservé (aucune perte) et signalé dans `output.log`. Le travail se récupère en fusionnant les branches `ralph/*`.
|
|
58
|
+
- **Hors dépôt git** : pas de worktree ; le worker s'exécute dans le répertoire courant (avertissement affiché), l'isolation des sessions Claude restant assurée.
|
|
59
|
+
|
|
54
60
|
### 2. Boucle principale avec Dashboard
|
|
55
61
|
|
|
56
62
|
```
|
|
@@ -51,6 +51,12 @@ Executa o Claude em loop contínuo até que a tarefa seja concluída ou os crit
|
|
|
51
51
|
- Definir máximo de iterações, timeouts e critérios de DoD
|
|
52
52
|
- Inicializar hooks se habilitados
|
|
53
53
|
|
|
54
|
+
#### Isolamento de sessões e workers paralelos
|
|
55
|
+
|
|
56
|
+
- **Sessão Claude explícita**: cada sessão Ralph fixa seu próprio identificador de conversa Claude — `claude --session-id <uuid>` na primeira iteração e depois `claude --resume <uuid>`. O UUID é armazenado em `.ralph/sessions/<session>/claude_session_id`, para que `--continue=<session>` retome a conversa correta. O Ralph não usa mais `claude --continue`, que retomava "a conversa mais recente do diretório" (compartilhada entre workers, ou até com a sessão interativa do usuário).
|
|
57
|
+
- **Um worktree git por worker** (modo paralelo, `lib/parallel-manager.sh`): cada história é executada em um worktree dedicado `.ralph/parallel/worktrees/<session>` na branch `ralph/<session>`, com seu estado Ralph em `.ralph/parallel/sessions/<session>/ralph/`. No fim da execução, as alterações restantes são commitadas como `wip(ralph): <story>` nessa branch e o worktree é removido (`git worktree remove`). Se esse commit falhar, o worktree é mantido (sem perda de dados) e sinalizado em `output.log`. O trabalho é recuperado fazendo merge das branches `ralph/*`.
|
|
58
|
+
- **Fora de um repositório git**: sem worktree; o worker é executado no diretório atual (um aviso é exibido) e o isolamento das sessões Claude continua garantido.
|
|
59
|
+
|
|
54
60
|
### 2. Loop Principal com Painel
|
|
55
61
|
|
|
56
62
|
```
|
|
@@ -465,6 +465,14 @@ install_commands() {
|
|
|
465
465
|
done
|
|
466
466
|
IFS="$OLD_IFS"
|
|
467
467
|
|
|
468
|
+
# The deprecated common:pre-commit-check|pre-merge-check|release-checklist
|
|
469
|
+
# stubs redirect to /gate:check, which otherwise ships only with the Project
|
|
470
|
+
# package: install it here too so a Dev-only install keeps them working.
|
|
471
|
+
local gate_check="$SCRIPT_DIR/../../Project/i18n/$lang/Gate/commands/check.md"
|
|
472
|
+
if [[ -f "$gate_check" ]]; then
|
|
473
|
+
copy_file "$gate_check" "$target_dir/.claude/commands/gate/check.md"
|
|
474
|
+
fi
|
|
475
|
+
|
|
468
476
|
# Delete commands retired from the distribution (config/removed-commands.yaml)
|
|
469
477
|
$dry_run || bash "$SCRIPT_DIR/prune-removed-commands.sh" "$target_dir"
|
|
470
478
|
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ Plus **11 stack-specific reviewers** (@symfony-reviewer, @react-reviewer, @pytho
|
|
|
26
26
|
[](https://opensource.org/licenses/MIT)
|
|
27
27
|
[](https://dashboard.stryker-mutator.io/reports/github.com/TheBeardedBearSAS/claude-craft/main)
|
|
28
28
|
|
|
29
|
-
A comprehensive framework for AI-assisted development with [Claude Code](https://claude.ai/code). Install standardized rules, agents, and commands for your projects across multiple technology stacks — **33 specialized agents (+39 infra agents on-demand),
|
|
29
|
+
A comprehensive framework for AI-assisted development with [Claude Code](https://claude.ai/code). Install standardized rules, agents, and commands for your projects across multiple technology stacks — **33 specialized agents (+39 infra agents on-demand), 140 commands across 18 namespaces (238 total, including deprecated redirect stubs kept until 9.0), 55 skills**, all token-optimized via `context: fork` and sub-agent model routing.
|
|
30
30
|
|
|
31
31
|
## What's New in v8.26.0
|
|
32
32
|
|
|
@@ -187,7 +187,7 @@ Claude Code is powerful on its own. Claude Craft makes it **consistent and team-
|
|
|
187
187
|
|
|
188
188
|
- **Standardized rules** -- SOLID, Clean Architecture, TDD enforced across your team, not just suggested
|
|
189
189
|
- **33 default agents + 39 infra agents on-demand** -- reviewers, architects, coaches that know your stack deeply (72 total potentially installable)
|
|
190
|
-
- **
|
|
190
|
+
- **140 slash commands across 18 namespaces** -- repeatable workflows for audits, code generation, sprint management
|
|
191
191
|
- **Quality gates** -- automated checks at every stage from PRD to deployment
|
|
192
192
|
- **5 languages** -- English, French, Spanish, German, Portuguese
|
|
193
193
|
|
|
@@ -207,12 +207,12 @@ list_checkpoints() {
|
|
|
207
207
|
|
|
208
208
|
# Find commits matching the checkpoint pattern
|
|
209
209
|
local commits
|
|
210
|
-
commits=$(git log --oneline --grep="checkpoint: Ralph" 2>/dev/null | head -20)
|
|
210
|
+
commits=$(git log --oneline --grep="checkpoint: Ralph" 2>/dev/null | head -20) || true
|
|
211
211
|
|
|
212
212
|
if [[ -n "$commits" ]]; then
|
|
213
213
|
echo "$commits" | while read -r line; do
|
|
214
|
-
local hash=$(echo "$line" | cut -d' ' -f1)
|
|
215
|
-
local msg=$(echo "$line" | cut -d' ' -f2-)
|
|
214
|
+
local hash=$(echo "$line" | cut -d' ' -f1) || true
|
|
215
|
+
local msg=$(echo "$line" | cut -d' ' -f2-) || true
|
|
216
216
|
echo "{\"hash\":\"$hash\",\"message\":\"$msg\"}"
|
|
217
217
|
done | jq -s '.'
|
|
218
218
|
else
|
|
@@ -30,35 +30,35 @@ CB_LEARNING_MIN_SAMPLES=5
|
|
|
30
30
|
# =============================================================================
|
|
31
31
|
# Each profile defines thresholds optimized for different task types
|
|
32
32
|
|
|
33
|
-
declare -
|
|
33
|
+
declare -gA CB_PROFILE_QUICK_FIX=(
|
|
34
34
|
["no_changes"]=2
|
|
35
35
|
["errors"]=3
|
|
36
36
|
["max_iterations"]=10
|
|
37
37
|
["keywords"]="fix bug typo hotfix patch"
|
|
38
38
|
)
|
|
39
39
|
|
|
40
|
-
declare -
|
|
40
|
+
declare -gA CB_PROFILE_SMALL_FEATURE=(
|
|
41
41
|
["no_changes"]=3
|
|
42
42
|
["errors"]=4
|
|
43
43
|
["max_iterations"]=15
|
|
44
44
|
["keywords"]="add implement small simple"
|
|
45
45
|
)
|
|
46
46
|
|
|
47
|
-
declare -
|
|
47
|
+
declare -gA CB_PROFILE_MEDIUM_FEATURE=(
|
|
48
48
|
["no_changes"]=4
|
|
49
49
|
["errors"]=6
|
|
50
50
|
["max_iterations"]=25
|
|
51
51
|
["keywords"]="feature create with tests"
|
|
52
52
|
)
|
|
53
53
|
|
|
54
|
-
declare -
|
|
54
|
+
declare -gA CB_PROFILE_LARGE_FEATURE=(
|
|
55
55
|
["no_changes"]=5
|
|
56
56
|
["errors"]=8
|
|
57
57
|
["max_iterations"]=50
|
|
58
58
|
["keywords"]="refactor migrate complex large"
|
|
59
59
|
)
|
|
60
60
|
|
|
61
|
-
declare -
|
|
61
|
+
declare -gA CB_PROFILE_EXPLORATION=(
|
|
62
62
|
["no_changes"]=10
|
|
63
63
|
["errors"]=15
|
|
64
64
|
["max_iterations"]=100
|
|
@@ -66,7 +66,7 @@ declare -A CB_PROFILE_EXPLORATION=(
|
|
|
66
66
|
)
|
|
67
67
|
|
|
68
68
|
# Autonomous profile for overnight/unattended runs
|
|
69
|
-
declare -
|
|
69
|
+
declare -gA CB_PROFILE_AUTONOMOUS=(
|
|
70
70
|
["no_changes"]=5
|
|
71
71
|
["errors"]=8
|
|
72
72
|
["max_iterations"]=50
|
|
@@ -162,7 +162,7 @@ init_circuit_breaker() {
|
|
|
162
162
|
detect_task_profile() {
|
|
163
163
|
local prompt="$1"
|
|
164
164
|
local prompt_lower
|
|
165
|
-
prompt_lower=$(echo "$prompt" | tr '[:upper:]' '[:lower:]')
|
|
165
|
+
prompt_lower=$(echo "$prompt" | tr '[:upper:]' '[:lower:]') || true
|
|
166
166
|
|
|
167
167
|
# Check each profile's keywords
|
|
168
168
|
local profiles=("quick_fix" "small_feature" "medium_feature" "large_feature" "exploration" "autonomous")
|
|
@@ -265,7 +265,7 @@ apply_learned_adjustments() {
|
|
|
265
265
|
' "$history_file" 2>/dev/null)
|
|
266
266
|
|
|
267
267
|
local samples
|
|
268
|
-
samples=$(echo "$profile_data" | jq -r '.samples // 0')
|
|
268
|
+
samples=$(echo "$profile_data" | jq -r '.samples // 0') || samples=0
|
|
269
269
|
|
|
270
270
|
if [[ $samples -lt $CB_LEARNING_MIN_SAMPLES ]]; then
|
|
271
271
|
print_verbose "Not enough samples for learning ($samples < $CB_LEARNING_MIN_SAMPLES)"
|
|
@@ -274,10 +274,10 @@ apply_learned_adjustments() {
|
|
|
274
274
|
|
|
275
275
|
# Apply adjustments based on historical success rate
|
|
276
276
|
local success_rate
|
|
277
|
-
success_rate=$(echo "$profile_data" | jq -r '.success_rate // 0')
|
|
277
|
+
success_rate=$(echo "$profile_data" | jq -r '.success_rate // 0') || success_rate=0
|
|
278
278
|
|
|
279
279
|
local avg_iterations
|
|
280
|
-
avg_iterations=$(echo "$profile_data" | jq -r '.avg_iterations // 0')
|
|
280
|
+
avg_iterations=$(echo "$profile_data" | jq -r '.avg_iterations // 0') || avg_iterations=0
|
|
281
281
|
|
|
282
282
|
# If success rate is low, increase thresholds
|
|
283
283
|
if [[ $success_rate -lt 50 ]]; then
|
|
@@ -32,6 +32,9 @@ IFS=' ' read -r -a CLAUDE_CMD <<< "$CLAUDE_COMMAND"
|
|
|
32
32
|
CONTEXT_COMPACT_COUNT=0
|
|
33
33
|
CONTEXT_CONTINUATION_COUNT=0
|
|
34
34
|
CONTEXT_CONTINUATION_PROMPT=""
|
|
35
|
+
# Set by run_auto_compact (return 3) / handle_max_compacts_reached: call them
|
|
36
|
+
# in this shell, never in `$(...)`, or the counters above are lost.
|
|
37
|
+
CONTEXT_NEW_SESSION_ID=""
|
|
35
38
|
|
|
36
39
|
# =============================================================================
|
|
37
40
|
# Context Limit Detection
|
|
@@ -106,6 +109,17 @@ init_context_manager() {
|
|
|
106
109
|
print_verbose " - Smart reconstruction: $CONTEXT_SMART_RECONSTRUCTION"
|
|
107
110
|
}
|
|
108
111
|
|
|
112
|
+
# Print the first lines of `/context` for a Claude session UUID.
|
|
113
|
+
# Best effort: prints nothing on failure, always succeeds (set -e safe).
|
|
114
|
+
probe_context_usage() {
|
|
115
|
+
local claude_uuid="$1"
|
|
116
|
+
if command -v timeout &> /dev/null; then
|
|
117
|
+
timeout 10s "${CLAUDE_CMD[@]}" --resume "$claude_uuid" -p "/context" 2>/dev/null | head -5 || true
|
|
118
|
+
else
|
|
119
|
+
"${CLAUDE_CMD[@]}" --resume "$claude_uuid" -p "/context" 2>/dev/null | head -5 || true
|
|
120
|
+
fi
|
|
121
|
+
}
|
|
122
|
+
|
|
109
123
|
# =============================================================================
|
|
110
124
|
# Auto-Compact
|
|
111
125
|
# =============================================================================
|
|
@@ -120,20 +134,27 @@ run_auto_compact() {
|
|
|
120
134
|
return 1
|
|
121
135
|
fi
|
|
122
136
|
|
|
137
|
+
# /context and /compact must target this Ralph session's Claude session,
|
|
138
|
+
# never "the most recent conversation in this directory" (--continue).
|
|
139
|
+
local claude_uuid
|
|
140
|
+
claude_uuid=$(get_claude_session_uuid "$session_id")
|
|
141
|
+
if [[ -z "$claude_uuid" ]]; then
|
|
142
|
+
log_session "$session_id" "WARN" "No Claude session yet, nothing to compact"
|
|
143
|
+
return 1
|
|
144
|
+
fi
|
|
145
|
+
|
|
123
146
|
# Check if context is above minimum threshold before compacting
|
|
124
147
|
if [[ "$CONTEXT_MIN_THRESHOLD" -gt 0 ]]; then
|
|
125
148
|
local context_info
|
|
126
|
-
|
|
127
|
-
context_info=$(timeout 10s "${CLAUDE_CMD[@]}" -p "/context" 2>/dev/null | head -5)
|
|
128
|
-
else
|
|
129
|
-
context_info=$("${CLAUDE_CMD[@]}" -p "/context" 2>/dev/null | head -5)
|
|
130
|
-
fi
|
|
149
|
+
context_info=$(probe_context_usage "$claude_uuid")
|
|
131
150
|
local current_usage
|
|
132
|
-
current_usage=$(echo "$context_info" | grep -oP '\d+(?=%)' | head -1)
|
|
151
|
+
current_usage=$(echo "$context_info" | grep -oP '\d+(?=%)' | head -1 || true)
|
|
133
152
|
|
|
134
153
|
if [[ -n "$current_usage" && "$current_usage" -lt "$CONTEXT_MIN_THRESHOLD" ]]; then
|
|
135
154
|
log_session "$session_id" "INFO" "Context at ${current_usage}% - below minimum threshold (${CONTEXT_MIN_THRESHOLD}%), skipping compact"
|
|
136
|
-
|
|
155
|
+
local msg="${MSG_CONTEXT_BELOW_MIN:-"Context at {0}% - below minimum threshold ({1}%), skipping compact"}"
|
|
156
|
+
msg="${msg//\{0\}/"$current_usage"}"
|
|
157
|
+
print_verbose "${msg//\{1\}/"$CONTEXT_MIN_THRESHOLD"}"
|
|
137
158
|
return 1
|
|
138
159
|
fi
|
|
139
160
|
fi
|
|
@@ -144,13 +165,12 @@ run_auto_compact() {
|
|
|
144
165
|
print_warning "${MSG_CONTEXT_MAX_REACHED:-Maximum compacts reached} ($CONTEXT_MAX_COMPACTS)"
|
|
145
166
|
|
|
146
167
|
# Handle overflow strategy
|
|
147
|
-
local
|
|
148
|
-
|
|
149
|
-
|
|
168
|
+
local overflow_status=0
|
|
169
|
+
CONTEXT_NEW_SESSION_ID=""
|
|
170
|
+
handle_max_compacts_reached "$session_id" || overflow_status=$?
|
|
150
171
|
|
|
151
|
-
if [[ $overflow_status -eq 0 && -n "$
|
|
152
|
-
# New session ID
|
|
153
|
-
echo "$overflow_result"
|
|
172
|
+
if [[ $overflow_status -eq 0 && -n "$CONTEXT_NEW_SESSION_ID" ]]; then
|
|
173
|
+
# New session ID in CONTEXT_NEW_SESSION_ID - signal continuation
|
|
154
174
|
return 3 # Special return code for session continuation
|
|
155
175
|
fi
|
|
156
176
|
|
|
@@ -185,11 +205,10 @@ run_auto_compact() {
|
|
|
185
205
|
|
|
186
206
|
# Execute /compact via Claude CLI
|
|
187
207
|
local compact_output
|
|
188
|
-
local compact_status
|
|
208
|
+
local compact_status=0
|
|
189
209
|
|
|
190
210
|
if command -v timeout &> /dev/null; then
|
|
191
|
-
compact_output=$(timeout 60s "${CLAUDE_CMD[@]}" --
|
|
192
|
-
compact_status=$?
|
|
211
|
+
compact_output=$(timeout 60s "${CLAUDE_CMD[@]}" --resume "$claude_uuid" -p "/compact" 2>&1) || compact_status=$?
|
|
193
212
|
|
|
194
213
|
# Handle timeout specifically (exit code 124)
|
|
195
214
|
if [[ $compact_status -eq 124 ]]; then
|
|
@@ -198,8 +217,7 @@ run_auto_compact() {
|
|
|
198
217
|
return 1
|
|
199
218
|
fi
|
|
200
219
|
else
|
|
201
|
-
compact_output=$("${CLAUDE_CMD[@]}" --
|
|
202
|
-
compact_status=$?
|
|
220
|
+
compact_output=$("${CLAUDE_CMD[@]}" --resume "$claude_uuid" -p "/compact" 2>&1) || compact_status=$?
|
|
203
221
|
fi
|
|
204
222
|
|
|
205
223
|
if [[ $compact_status -eq 0 ]]; then
|
|
@@ -313,10 +331,12 @@ handle_max_compacts_reached() {
|
|
|
313
331
|
new_session_id=$(create_continuation_session "$session_id")
|
|
314
332
|
|
|
315
333
|
if [[ -n "$new_session_id" ]]; then
|
|
334
|
+
# Reset here: create_continuation_session ran in a subshell
|
|
335
|
+
CONTEXT_COMPACT_COUNT=0
|
|
316
336
|
CONTEXT_CONTINUATION_COUNT=$((CONTEXT_CONTINUATION_COUNT + 1))
|
|
317
337
|
print_success "${MSG_CONTEXT_CONTINUATION_CREATED:-Continuation session created}: $new_session_id"
|
|
318
338
|
log_session "$session_id" "INFO" "Created continuation session: $new_session_id"
|
|
319
|
-
|
|
339
|
+
CONTEXT_NEW_SESSION_ID="$new_session_id"
|
|
320
340
|
return 0
|
|
321
341
|
else
|
|
322
342
|
print_error "Failed to create continuation session"
|
|
@@ -349,30 +369,11 @@ handle_max_compacts_reached() {
|
|
|
349
369
|
create_continuation_session() {
|
|
350
370
|
local previous_session="$1"
|
|
351
371
|
|
|
352
|
-
#
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if type generate_random_suffix &>/dev/null; then
|
|
358
|
-
random_suffix=$(generate_random_suffix 4)
|
|
359
|
-
elif command -v xxd &>/dev/null; then
|
|
360
|
-
random_suffix=$(head -c 4 /dev/urandom | xxd -p)
|
|
361
|
-
elif command -v od &>/dev/null; then
|
|
362
|
-
random_suffix=$(head -c 4 /dev/urandom | od -An -tx1 | tr -d ' \n')
|
|
363
|
-
else
|
|
364
|
-
# Fallback: use $RANDOM (less entropy but portable)
|
|
365
|
-
random_suffix=$(printf '%04x%04x' $RANDOM $RANDOM | head -c 8)
|
|
366
|
-
fi
|
|
367
|
-
|
|
368
|
-
local new_session_id="ralph-cont-${timestamp}-${random_suffix}"
|
|
369
|
-
|
|
370
|
-
# Create session directory if create_session is available
|
|
371
|
-
if type create_session &>/dev/null; then
|
|
372
|
-
if ! create_session "$new_session_id" 2>/dev/null; then
|
|
373
|
-
print_warning "Failed to create session directory for $new_session_id"
|
|
374
|
-
fi
|
|
375
|
-
fi
|
|
372
|
+
# create_session takes a prompt and prints the id it created (with its
|
|
373
|
+
# state.json and session.log): the id must come from it, or the session
|
|
374
|
+
# directory is an orphan and the continuation id has no state.
|
|
375
|
+
local new_session_id
|
|
376
|
+
new_session_id=$(create_session "Continuation of $previous_session") || return 1
|
|
376
377
|
|
|
377
378
|
# Link sessions in state files (with error handling)
|
|
378
379
|
if type update_session_state &>/dev/null; then
|
|
@@ -385,10 +386,6 @@ create_continuation_session() {
|
|
|
385
386
|
link_session_to_progress "$new_session_id" || print_verbose "Failed to link session to progress"
|
|
386
387
|
fi
|
|
387
388
|
|
|
388
|
-
# Reset context manager for new session
|
|
389
|
-
CONTEXT_COMPACT_COUNT=0
|
|
390
|
-
CONTEXT_CONTINUATION_COUNT=$((CONTEXT_CONTINUATION_COUNT)) # Keep continuation count
|
|
391
|
-
|
|
392
389
|
echo "$new_session_id"
|
|
393
390
|
}
|
|
394
391
|
|
|
@@ -404,26 +401,28 @@ check_preventive_compact() {
|
|
|
404
401
|
return 1
|
|
405
402
|
fi
|
|
406
403
|
|
|
404
|
+
# Nothing to measure before the first Claude call of this session.
|
|
405
|
+
local claude_uuid
|
|
406
|
+
claude_uuid=$(get_claude_session_uuid "$session_id")
|
|
407
|
+
[[ -z "$claude_uuid" ]] && return 1
|
|
408
|
+
|
|
407
409
|
# Try to get context usage from Claude CLI
|
|
408
410
|
# Note: This is a best-effort check, Claude may not always report usage
|
|
409
411
|
local context_info
|
|
410
|
-
|
|
411
|
-
context_info=$(timeout 10s "${CLAUDE_CMD[@]}" -p "/context" 2>/dev/null | head -5)
|
|
412
|
-
else
|
|
413
|
-
context_info=$("${CLAUDE_CMD[@]}" -p "/context" 2>/dev/null | head -5)
|
|
414
|
-
fi
|
|
412
|
+
context_info=$(probe_context_usage "$claude_uuid")
|
|
415
413
|
|
|
416
414
|
# Try to extract percentage from output
|
|
417
415
|
local usage
|
|
418
|
-
usage=$(echo "$context_info" | grep -oP '\d+(?=%)' | head -1)
|
|
416
|
+
usage=$(echo "$context_info" | grep -oP '\d+(?=%)' | head -1 || true)
|
|
419
417
|
|
|
420
418
|
if [[ -n "$usage" && "$usage" -ge "$CONTEXT_PREVENTIVE_THRESHOLD" ]]; then
|
|
421
|
-
|
|
419
|
+
local msg="${MSG_CONTEXT_PREVENTIVE:-Context at ${usage}% - running preventive compact}"
|
|
420
|
+
print_warning "${msg//\{0\}/$usage}"
|
|
422
421
|
log_session "$session_id" "INFO" "Preventive compact triggered at ${usage}%"
|
|
423
422
|
|
|
424
423
|
# Save progress before preventive compact
|
|
425
424
|
if type save_sprint_progress &>/dev/null; then
|
|
426
|
-
save_sprint_progress "$session_id"
|
|
425
|
+
save_sprint_progress "$session_id" || print_verbose "No sprint progress file to save"
|
|
427
426
|
fi
|
|
428
427
|
|
|
429
428
|
run_auto_compact "$session_id"
|
|
@@ -437,23 +436,15 @@ check_preventive_compact() {
|
|
|
437
436
|
# Context Continuation Prompt
|
|
438
437
|
# =============================================================================
|
|
439
438
|
|
|
439
|
+
# Print the continuation prompt stored by a real compaction, if any.
|
|
440
|
+
# Callers using `$(...)` must reset CONTEXT_CONTINUATION_PROMPT themselves.
|
|
440
441
|
get_context_continuation_prompt() {
|
|
441
|
-
# Return the stored continuation prompt if available
|
|
442
442
|
if [[ -n "$CONTEXT_CONTINUATION_PROMPT" ]]; then
|
|
443
443
|
echo "$CONTEXT_CONTINUATION_PROMPT"
|
|
444
|
-
# Clear after use
|
|
445
444
|
CONTEXT_CONTINUATION_PROMPT=""
|
|
446
445
|
return 0
|
|
447
446
|
fi
|
|
448
447
|
|
|
449
|
-
# Generate fresh if smart reconstruction is enabled
|
|
450
|
-
if [[ "$CONTEXT_SMART_RECONSTRUCTION" == "true" ]]; then
|
|
451
|
-
if type generate_continuation_prompt &>/dev/null; then
|
|
452
|
-
generate_continuation_prompt
|
|
453
|
-
return 0
|
|
454
|
-
fi
|
|
455
|
-
fi
|
|
456
|
-
|
|
457
448
|
return 1
|
|
458
449
|
}
|
|
459
450
|
|