prizmkit 1.1.10 → 1.1.12
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/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/README.md +10 -46
- package/bundled/dev-pipeline/reset-bug.sh +84 -10
- package/bundled/dev-pipeline/reset-feature.sh +86 -10
- package/bundled/dev-pipeline/reset-refactor.sh +68 -4
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +47 -46
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +7 -12
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +124 -20
- package/bundled/dev-pipeline/scripts/utils.py +20 -0
- package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +13 -7
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +62 -66
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +37 -40
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +35 -48
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +135 -182
- package/bundled/dev-pipeline/templates/feature-list-schema.json +6 -21
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +9 -9
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +1 -1
- package/bundled/dev-pipeline/templates/sections/feature-context.md +4 -0
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +41 -24
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +4 -12
- package/bundled/dev-pipeline/templates/sections/phase-deploy-verification.md +9 -17
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +3 -2
- package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +4 -2
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +0 -18
- package/bundled/dev-pipeline/templates/sections/session-context.md +1 -2
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +75 -0
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +66 -0
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +3 -8
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +4 -16
- package/bundled/skills/feature-planner/SKILL.md +8 -4
- package/bundled/skills/feature-planner/assets/planning-guide.md +16 -11
- package/bundled/skills/feature-planner/references/browser-interaction.md +9 -8
- package/bundled/skills/feature-planner/references/completeness-review.md +1 -1
- package/bundled/skills/feature-planner/references/error-recovery.md +1 -1
- package/bundled/skills/feature-planner/references/incremental-feature-planning.md +1 -1
- package/bundled/skills/feature-planner/scripts/validate-and-generate.py +10 -7
- package/bundled/skills/recovery-workflow/SKILL.md +3 -3
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +4 -15
- package/package.json +1 -1
- package/bundled/dev-pipeline/retry-bugfix.sh +0 -429
- package/bundled/dev-pipeline/retry-feature.sh +0 -445
- package/bundled/dev-pipeline/retry-refactor.sh +0 -441
- package/bundled/dev-pipeline/templates/sections/failure-log-check.md +0 -9
- package/bundled/dev-pipeline/templates/sections/resume-header.md +0 -5
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery.md +0 -75
|
@@ -1,445 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
# ============================================================
|
|
5
|
-
# dev-pipeline/retry-feature.sh - Retry a single failed feature
|
|
6
|
-
#
|
|
7
|
-
# Runs exactly ONE AI CLI session for the specified feature, then exits.
|
|
8
|
-
# Use this to manually retry a failed feature without restarting
|
|
9
|
-
# the full pipeline.
|
|
10
|
-
#
|
|
11
|
-
# Usage:
|
|
12
|
-
# ./retry-feature.sh <feature-id> [.prizmkit/plans/feature-list.json]
|
|
13
|
-
#
|
|
14
|
-
# Examples:
|
|
15
|
-
# ./retry-feature.sh F-007
|
|
16
|
-
# ./retry-feature.sh F-007 .prizmkit/plans/feature-list.json
|
|
17
|
-
# SESSION_TIMEOUT=3600 ./retry-feature.sh F-007 # with 1h timeout
|
|
18
|
-
# ============================================================
|
|
19
|
-
|
|
20
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
21
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
22
|
-
STATE_DIR="${PROJECT_ROOT}/.prizmkit/state/features"
|
|
23
|
-
SCRIPTS_DIR="$SCRIPT_DIR/scripts"
|
|
24
|
-
|
|
25
|
-
SESSION_TIMEOUT=${SESSION_TIMEOUT:-0}
|
|
26
|
-
HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-30}
|
|
27
|
-
|
|
28
|
-
# Source shared common helpers (CLI/platform detection + logs + deps)
|
|
29
|
-
source "$SCRIPT_DIR/lib/common.sh"
|
|
30
|
-
prizm_detect_cli_and_platform
|
|
31
|
-
|
|
32
|
-
# Source shared heartbeat library
|
|
33
|
-
source "$SCRIPT_DIR/lib/heartbeat.sh"
|
|
34
|
-
|
|
35
|
-
# Source shared branch library
|
|
36
|
-
source "$SCRIPT_DIR/lib/branch.sh"
|
|
37
|
-
|
|
38
|
-
# Detect stream-json support
|
|
39
|
-
detect_stream_json_support "$CLI_CMD"
|
|
40
|
-
|
|
41
|
-
# Branch tracking
|
|
42
|
-
_ORIGINAL_BRANCH=""
|
|
43
|
-
_DEV_BRANCH_NAME=""
|
|
44
|
-
AUTO_PUSH=${AUTO_PUSH:-0}
|
|
45
|
-
|
|
46
|
-
# ============================================================
|
|
47
|
-
# Args
|
|
48
|
-
# ============================================================
|
|
49
|
-
|
|
50
|
-
if [[ $# -lt 1 ]]; then
|
|
51
|
-
echo "Usage: $0 <feature-id> [.prizmkit/plans/feature-list.json]"
|
|
52
|
-
echo ""
|
|
53
|
-
echo " feature-id Feature to retry (e.g. F-007)"
|
|
54
|
-
echo " feature-list.json Path to feature list (default: .prizmkit/plans/feature-list.json)"
|
|
55
|
-
echo ""
|
|
56
|
-
echo "Environment Variables:"
|
|
57
|
-
echo " SESSION_TIMEOUT Timeout in seconds (default: 0 = no limit)"
|
|
58
|
-
echo " HEARTBEAT_INTERVAL Heartbeat interval in seconds (default: 30)"
|
|
59
|
-
echo " AI_CLI AI CLI command (auto-detected: cbc or claude)"
|
|
60
|
-
exit 1
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
FEATURE_ID="$1"
|
|
64
|
-
FEATURE_LIST="${2:-.prizmkit/plans/feature-list.json}"
|
|
65
|
-
|
|
66
|
-
# Resolve absolute path
|
|
67
|
-
if [[ ! "$FEATURE_LIST" = /* ]]; then
|
|
68
|
-
FEATURE_LIST="$(pwd)/$FEATURE_LIST"
|
|
69
|
-
fi
|
|
70
|
-
|
|
71
|
-
# ============================================================
|
|
72
|
-
# Validation
|
|
73
|
-
# ============================================================
|
|
74
|
-
|
|
75
|
-
if [[ ! -f "$FEATURE_LIST" ]]; then
|
|
76
|
-
log_error "Feature list not found: $FEATURE_LIST"
|
|
77
|
-
exit 1
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
|
-
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
81
|
-
log_error "No pipeline state found. Run './run-feature.sh run' first to initialize."
|
|
82
|
-
exit 1
|
|
83
|
-
fi
|
|
84
|
-
|
|
85
|
-
if ! command -v jq &>/dev/null; then
|
|
86
|
-
log_error "jq is required. Install with: brew install jq"
|
|
87
|
-
exit 1
|
|
88
|
-
fi
|
|
89
|
-
|
|
90
|
-
# Verify feature exists in feature list
|
|
91
|
-
FEATURE_TITLE=$(python3 -c "
|
|
92
|
-
import json, sys
|
|
93
|
-
with open('$FEATURE_LIST') as f:
|
|
94
|
-
data = json.load(f)
|
|
95
|
-
for feat in data.get('features', []):
|
|
96
|
-
if feat.get('id') == '$FEATURE_ID':
|
|
97
|
-
print(feat.get('title', ''))
|
|
98
|
-
sys.exit(0)
|
|
99
|
-
sys.exit(1)
|
|
100
|
-
" 2>/dev/null) || {
|
|
101
|
-
log_error "Feature $FEATURE_ID not found in $FEATURE_LIST"
|
|
102
|
-
exit 1
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
# ============================================================
|
|
106
|
-
# Clean feature artifacts + reset status for a full restart
|
|
107
|
-
# ============================================================
|
|
108
|
-
|
|
109
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
110
|
-
ORIGINAL_BRANCH=$(git -C "$PROJECT_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
|
|
111
|
-
_ORIGINAL_BRANCH="$ORIGINAL_BRANCH"
|
|
112
|
-
FEATURE_SLUG=$(FEATURE_ID="$FEATURE_ID" FEATURE_TITLE="$FEATURE_TITLE" python3 -c "
|
|
113
|
-
import os, re
|
|
114
|
-
fid = os.environ['FEATURE_ID'].replace('F-', '').replace('f-', '').zfill(3)
|
|
115
|
-
title = os.environ.get('FEATURE_TITLE', '').lower()
|
|
116
|
-
title = re.sub(r'[^a-z0-9\s-]', '', title)
|
|
117
|
-
title = re.sub(r'[\s]+', '-', title.strip())
|
|
118
|
-
title = re.sub(r'-+', '-', title).strip('-') or 'feature'
|
|
119
|
-
print(f'{fid}-{title}')
|
|
120
|
-
" 2>/dev/null)
|
|
121
|
-
|
|
122
|
-
log_info "Reading retry state for $FEATURE_ID..."
|
|
123
|
-
RETRY_COUNT=$(python3 -c "
|
|
124
|
-
import json, os
|
|
125
|
-
status_path = os.path.join('$STATE_DIR', 'features', '$FEATURE_ID', 'status.json')
|
|
126
|
-
if os.path.isfile(status_path):
|
|
127
|
-
with open(status_path) as f:
|
|
128
|
-
d = json.load(f)
|
|
129
|
-
print(d.get('retry_count', 0))
|
|
130
|
-
else:
|
|
131
|
-
print(0)
|
|
132
|
-
" 2>/dev/null || echo "0")
|
|
133
|
-
RESUME_PHASE=$(python3 -c "
|
|
134
|
-
import json, os
|
|
135
|
-
status_path = os.path.join('$STATE_DIR', 'features', '$FEATURE_ID', 'status.json')
|
|
136
|
-
if os.path.isfile(status_path):
|
|
137
|
-
with open(status_path) as f:
|
|
138
|
-
d = json.load(f)
|
|
139
|
-
print(d.get('resume_from_phase') or 'null')
|
|
140
|
-
else:
|
|
141
|
-
print('null')
|
|
142
|
-
" 2>/dev/null || echo "null")
|
|
143
|
-
log_info "Retry count: $RETRY_COUNT, Resume phase: $RESUME_PHASE"
|
|
144
|
-
|
|
145
|
-
# ============================================================
|
|
146
|
-
# Generate bootstrap prompt
|
|
147
|
-
# ============================================================
|
|
148
|
-
|
|
149
|
-
RUN_ID=$(jq -r '.run_id' "$STATE_DIR/pipeline.json")
|
|
150
|
-
SESSION_ID="${FEATURE_ID}-$(date +%Y%m%d%H%M%S)"
|
|
151
|
-
SESSION_DIR="$STATE_DIR/features/$FEATURE_ID/sessions/$SESSION_ID"
|
|
152
|
-
mkdir -p "$SESSION_DIR/logs"
|
|
153
|
-
|
|
154
|
-
BOOTSTRAP_PROMPT="$SESSION_DIR/bootstrap-prompt.md"
|
|
155
|
-
|
|
156
|
-
log_info "Generating bootstrap prompt..."
|
|
157
|
-
GEN_ARGS=(
|
|
158
|
-
--feature-list "$FEATURE_LIST"
|
|
159
|
-
--feature-id "$FEATURE_ID"
|
|
160
|
-
--session-id "$SESSION_ID"
|
|
161
|
-
--run-id "$RUN_ID"
|
|
162
|
-
--retry-count "$RETRY_COUNT"
|
|
163
|
-
--resume-phase "$RESUME_PHASE"
|
|
164
|
-
--state-dir "$STATE_DIR"
|
|
165
|
-
--output "$BOOTSTRAP_PROMPT"
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
# Support PIPELINE_MODE env var
|
|
169
|
-
if [[ -n "${PIPELINE_MODE:-}" ]]; then
|
|
170
|
-
GEN_ARGS+=(--mode "$PIPELINE_MODE")
|
|
171
|
-
fi
|
|
172
|
-
|
|
173
|
-
# Support ENABLE_CRITIC env var
|
|
174
|
-
if [[ "${ENABLE_CRITIC:-}" == "true" || "${ENABLE_CRITIC:-}" == "1" ]]; then
|
|
175
|
-
GEN_ARGS+=(--critic "true")
|
|
176
|
-
elif [[ "${ENABLE_CRITIC:-}" == "false" || "${ENABLE_CRITIC:-}" == "0" ]]; then
|
|
177
|
-
GEN_ARGS+=(--critic "false")
|
|
178
|
-
fi
|
|
179
|
-
|
|
180
|
-
GEN_OUTPUT=$(python3 "$SCRIPTS_DIR/generate-bootstrap-prompt.py" "${GEN_ARGS[@]}" 2>/dev/null) || {
|
|
181
|
-
log_error "Failed to generate bootstrap prompt"
|
|
182
|
-
exit 1
|
|
183
|
-
}
|
|
184
|
-
FEATURE_MODEL=$(echo "$GEN_OUTPUT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('model',''))" 2>/dev/null || echo "")
|
|
185
|
-
|
|
186
|
-
# ============================================================
|
|
187
|
-
# Run single AI CLI session
|
|
188
|
-
# ============================================================
|
|
189
|
-
|
|
190
|
-
echo ""
|
|
191
|
-
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
192
|
-
echo -e "${BOLD} Retry: $FEATURE_ID — $FEATURE_TITLE${NC}"
|
|
193
|
-
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
194
|
-
log_info "CLI: $CLI_CMD (platform: $PLATFORM)"
|
|
195
|
-
EFFECTIVE_MODEL="${FEATURE_MODEL:-${MODEL:-}}"
|
|
196
|
-
if [[ -n "$EFFECTIVE_MODEL" ]]; then
|
|
197
|
-
log_info "Model: $EFFECTIVE_MODEL"
|
|
198
|
-
else
|
|
199
|
-
log_info "Model: (CLI default)"
|
|
200
|
-
fi
|
|
201
|
-
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
202
|
-
log_info "Session timeout: ${SESSION_TIMEOUT}s"
|
|
203
|
-
else
|
|
204
|
-
log_info "Session timeout: none"
|
|
205
|
-
fi
|
|
206
|
-
log_info "Prompt: $BOOTSTRAP_PROMPT"
|
|
207
|
-
log_info "Log: $SESSION_DIR/logs/session.log"
|
|
208
|
-
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
209
|
-
echo ""
|
|
210
|
-
|
|
211
|
-
# Create per-feature dev branch (consistent with run-feature.sh behavior)
|
|
212
|
-
_feature_branch="${DEV_BRANCH:-dev/${FEATURE_ID}-retry-$(date +%Y%m%d%H%M)}"
|
|
213
|
-
if branch_create "$PROJECT_ROOT" "$_feature_branch" "$_ORIGINAL_BRANCH"; then
|
|
214
|
-
_DEV_BRANCH_NAME="$_feature_branch"
|
|
215
|
-
log_info "Dev branch: $_feature_branch"
|
|
216
|
-
else
|
|
217
|
-
log_warn "Failed to create dev branch; running on current branch"
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
SESSION_LOG="$SESSION_DIR/logs/session.log"
|
|
221
|
-
PROGRESS_JSON="$SESSION_DIR/logs/progress.json"
|
|
222
|
-
|
|
223
|
-
# Build stream-json flag
|
|
224
|
-
STREAM_JSON_FLAG=""
|
|
225
|
-
if [[ "$USE_STREAM_JSON" == "true" ]]; then
|
|
226
|
-
STREAM_JSON_FLAG="--output-format stream-json"
|
|
227
|
-
fi
|
|
228
|
-
|
|
229
|
-
# claude-internal requires --verbose when using stream-json with -p/--print
|
|
230
|
-
VERBOSE_FLAG=""
|
|
231
|
-
if [[ "$USE_STREAM_JSON" == "true" ]]; then
|
|
232
|
-
VERBOSE_FLAG="--verbose"
|
|
233
|
-
fi
|
|
234
|
-
|
|
235
|
-
# Mark feature as in-progress before spawning session
|
|
236
|
-
python3 "$SCRIPTS_DIR/update-feature-status.py" \
|
|
237
|
-
--feature-list "$FEATURE_LIST" \
|
|
238
|
-
--state-dir "$STATE_DIR" \
|
|
239
|
-
--feature-id "$FEATURE_ID" \
|
|
240
|
-
--action start >/dev/null 2>&1 || true
|
|
241
|
-
|
|
242
|
-
# Spawn AI CLI session
|
|
243
|
-
# Spawn AI CLI session — model priority: feature.model > $MODEL env > none
|
|
244
|
-
EFFECTIVE_MODEL="${FEATURE_MODEL:-${MODEL:-}}"
|
|
245
|
-
MODEL_FLAG=""
|
|
246
|
-
if [[ -n "$EFFECTIVE_MODEL" ]]; then
|
|
247
|
-
MODEL_FLAG="--model $EFFECTIVE_MODEL"
|
|
248
|
-
log_info "Model: $EFFECTIVE_MODEL"
|
|
249
|
-
fi
|
|
250
|
-
|
|
251
|
-
unset CLAUDECODE 2>/dev/null || true
|
|
252
|
-
|
|
253
|
-
# Log bootstrap prompt in test mode
|
|
254
|
-
prizm_log_bootstrap_prompt "$BOOTSTRAP_PROMPT" "$FEATURE_ID"
|
|
255
|
-
|
|
256
|
-
case "$CLI_CMD" in
|
|
257
|
-
*claude*)
|
|
258
|
-
# Claude Code: prompt via -p argument, --dangerously-skip-permissions for auto-accept
|
|
259
|
-
"$CLI_CMD" \
|
|
260
|
-
-p "$(cat "$BOOTSTRAP_PROMPT")" \
|
|
261
|
-
--dangerously-skip-permissions \
|
|
262
|
-
$VERBOSE_FLAG \
|
|
263
|
-
$STREAM_JSON_FLAG \
|
|
264
|
-
$MODEL_FLAG \
|
|
265
|
-
> "$SESSION_LOG" 2>&1 &
|
|
266
|
-
;;
|
|
267
|
-
*)
|
|
268
|
-
# CodeBuddy (cbc) and others: prompt via stdin
|
|
269
|
-
"$CLI_CMD" \
|
|
270
|
-
--print \
|
|
271
|
-
-y \
|
|
272
|
-
$STREAM_JSON_FLAG \
|
|
273
|
-
$MODEL_FLAG \
|
|
274
|
-
< "$BOOTSTRAP_PROMPT" \
|
|
275
|
-
> "$SESSION_LOG" 2>&1 &
|
|
276
|
-
;;
|
|
277
|
-
esac
|
|
278
|
-
CBC_PID=$!
|
|
279
|
-
|
|
280
|
-
# Start progress parser (no-op if stream-json not supported)
|
|
281
|
-
start_progress_parser "$SESSION_LOG" "$PROGRESS_JSON" "$SCRIPTS_DIR"
|
|
282
|
-
PARSER_PID="${_PARSER_PID:-}"
|
|
283
|
-
|
|
284
|
-
# Timeout watchdog (only if SESSION_TIMEOUT > 0)
|
|
285
|
-
WATCHER_PID=""
|
|
286
|
-
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
287
|
-
( sleep "$SESSION_TIMEOUT" && kill -TERM "$CBC_PID" 2>/dev/null ) &
|
|
288
|
-
WATCHER_PID=$!
|
|
289
|
-
fi
|
|
290
|
-
|
|
291
|
-
# Heartbeat
|
|
292
|
-
start_heartbeat "$CBC_PID" "$SESSION_LOG" "$PROGRESS_JSON" "$HEARTBEAT_INTERVAL"
|
|
293
|
-
HEARTBEAT_PID="${_HEARTBEAT_PID:-}"
|
|
294
|
-
|
|
295
|
-
# Ctrl+C cleanup
|
|
296
|
-
cleanup() {
|
|
297
|
-
echo ""
|
|
298
|
-
log_warn "Interrupted. Killing session..."
|
|
299
|
-
kill "$CBC_PID" 2>/dev/null || true
|
|
300
|
-
[[ -n "$WATCHER_PID" ]] && kill "$WATCHER_PID" 2>/dev/null || true
|
|
301
|
-
stop_heartbeat "$HEARTBEAT_PID"
|
|
302
|
-
stop_progress_parser "$PARSER_PID"
|
|
303
|
-
wait "$CBC_PID" 2>/dev/null || true
|
|
304
|
-
[[ -n "$WATCHER_PID" ]] && wait "$WATCHER_PID" 2>/dev/null || true
|
|
305
|
-
log_info "Session log: $SESSION_LOG"
|
|
306
|
-
exit 130
|
|
307
|
-
}
|
|
308
|
-
trap cleanup SIGINT SIGTERM
|
|
309
|
-
|
|
310
|
-
# Wait
|
|
311
|
-
EXIT_CODE=0
|
|
312
|
-
if wait "$CBC_PID" 2>/dev/null; then
|
|
313
|
-
EXIT_CODE=0
|
|
314
|
-
else
|
|
315
|
-
EXIT_CODE=$?
|
|
316
|
-
fi
|
|
317
|
-
|
|
318
|
-
# Cleanup background processes
|
|
319
|
-
[[ -n "$WATCHER_PID" ]] && kill "$WATCHER_PID" 2>/dev/null || true
|
|
320
|
-
stop_heartbeat "$HEARTBEAT_PID"
|
|
321
|
-
stop_progress_parser "$PARSER_PID"
|
|
322
|
-
[[ -n "$WATCHER_PID" ]] && wait "$WATCHER_PID" 2>/dev/null || true
|
|
323
|
-
|
|
324
|
-
[[ $EXIT_CODE -eq 143 ]] && EXIT_CODE=124
|
|
325
|
-
|
|
326
|
-
# ============================================================
|
|
327
|
-
# Check result
|
|
328
|
-
# ============================================================
|
|
329
|
-
|
|
330
|
-
echo ""
|
|
331
|
-
if [[ -f "$SESSION_LOG" ]]; then
|
|
332
|
-
FINAL_LINES=$(wc -l < "$SESSION_LOG" 2>/dev/null | tr -d ' ')
|
|
333
|
-
FINAL_SIZE=$(wc -c < "$SESSION_LOG" 2>/dev/null | tr -d ' ')
|
|
334
|
-
log_info "Session log: $FINAL_LINES lines, $((FINAL_SIZE / 1024))KB"
|
|
335
|
-
fi
|
|
336
|
-
log_info "exit_code=$EXIT_CODE"
|
|
337
|
-
|
|
338
|
-
# ── Determine session outcome from observable signals ──────────────
|
|
339
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
340
|
-
DEFAULT_BRANCH="$ORIGINAL_BRANCH"
|
|
341
|
-
|
|
342
|
-
if [[ $EXIT_CODE -eq 124 ]]; then
|
|
343
|
-
log_warn "Session timed out after ${SESSION_TIMEOUT}s"
|
|
344
|
-
SESSION_STATUS="timed_out"
|
|
345
|
-
elif [[ $EXIT_CODE -ne 0 ]]; then
|
|
346
|
-
log_warn "Session exited with code $EXIT_CODE"
|
|
347
|
-
SESSION_STATUS="crashed"
|
|
348
|
-
else
|
|
349
|
-
# Exit code 0 — check if the session produced commits
|
|
350
|
-
HAS_COMMITS=""
|
|
351
|
-
if git -C "$PROJECT_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
352
|
-
HAS_COMMITS=$(git -C "$PROJECT_ROOT" log "${DEFAULT_BRANCH}..HEAD" --oneline 2>/dev/null | head -1)
|
|
353
|
-
fi
|
|
354
|
-
|
|
355
|
-
if [[ -n "$HAS_COMMITS" ]]; then
|
|
356
|
-
SESSION_STATUS="success"
|
|
357
|
-
else
|
|
358
|
-
UNCOMMITTED=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null | head -1 || true)
|
|
359
|
-
if [[ -n "$UNCOMMITTED" ]]; then
|
|
360
|
-
log_warn "Session exited cleanly but produced no commits (uncommitted changes found) — auto-committing..."
|
|
361
|
-
git -C "$PROJECT_ROOT" add -A 2>/dev/null || true
|
|
362
|
-
if git -C "$PROJECT_ROOT" commit --no-verify -m "chore($FEATURE_ID): auto-commit session work" 2>/dev/null; then
|
|
363
|
-
log_info "Auto-commit succeeded"
|
|
364
|
-
SESSION_STATUS="success"
|
|
365
|
-
else
|
|
366
|
-
log_warn "Auto-commit failed — no changes to commit"
|
|
367
|
-
SESSION_STATUS="crashed"
|
|
368
|
-
fi
|
|
369
|
-
else
|
|
370
|
-
log_warn "Session exited cleanly but produced no commits and no changes"
|
|
371
|
-
SESSION_STATUS="crashed"
|
|
372
|
-
fi
|
|
373
|
-
fi
|
|
374
|
-
fi
|
|
375
|
-
|
|
376
|
-
# ── Post-success validation ──────────────────────────────────────────
|
|
377
|
-
if [[ "$SESSION_STATUS" == "success" ]]; then
|
|
378
|
-
if git -C "$PROJECT_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
379
|
-
DIRTY_FILES=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null || true)
|
|
380
|
-
if [[ -n "$DIRTY_FILES" ]]; then
|
|
381
|
-
log_info "Auto-committing remaining session artifacts..."
|
|
382
|
-
git -C "$PROJECT_ROOT" add -A 2>/dev/null || true
|
|
383
|
-
git -C "$PROJECT_ROOT" commit --no-verify --amend --no-edit -a 2>/dev/null \
|
|
384
|
-
|| git -C "$PROJECT_ROOT" commit --no-verify -m "chore($FEATURE_ID): include remaining session artifacts" 2>/dev/null \
|
|
385
|
-
|| true
|
|
386
|
-
fi
|
|
387
|
-
fi
|
|
388
|
-
fi
|
|
389
|
-
|
|
390
|
-
# ── Propagate completion notes for dependency context ─────────────────
|
|
391
|
-
if [[ "$SESSION_STATUS" == "success" && -n "$FEATURE_SLUG" ]]; then
|
|
392
|
-
SUMMARY_PATH="$PROJECT_ROOT/.prizmkit/specs/$FEATURE_SLUG/completion-summary.json"
|
|
393
|
-
if [[ -f "$SUMMARY_PATH" ]]; then
|
|
394
|
-
python3 "$SCRIPTS_DIR/patch-completion-notes.py" \
|
|
395
|
-
--feature-list "$FEATURE_LIST" \
|
|
396
|
-
--feature-id "$FEATURE_ID" \
|
|
397
|
-
--summary "$SUMMARY_PATH" >/dev/null 2>&1 && {
|
|
398
|
-
log_info "Propagated completion notes for $FEATURE_ID"
|
|
399
|
-
} || {
|
|
400
|
-
log_warn "Failed to propagate completion notes for $FEATURE_ID"
|
|
401
|
-
}
|
|
402
|
-
fi
|
|
403
|
-
fi
|
|
404
|
-
|
|
405
|
-
# Update feature status
|
|
406
|
-
python3 "$SCRIPTS_DIR/update-feature-status.py" \
|
|
407
|
-
--feature-list "$FEATURE_LIST" \
|
|
408
|
-
--state-dir "$STATE_DIR" \
|
|
409
|
-
--feature-id "$FEATURE_ID" \
|
|
410
|
-
--session-status "$SESSION_STATUS" \
|
|
411
|
-
--session-id "$SESSION_ID" \
|
|
412
|
-
--max-retries 999 \
|
|
413
|
-
--action update >/dev/null 2>&1 || true
|
|
414
|
-
|
|
415
|
-
# Commit feature-list.json status update (pipeline management commit)
|
|
416
|
-
if ! git -C "$PROJECT_ROOT" diff --quiet "$FEATURE_LIST" 2>/dev/null; then
|
|
417
|
-
git -C "$PROJECT_ROOT" add "$FEATURE_LIST"
|
|
418
|
-
git -C "$PROJECT_ROOT" commit --no-verify -m "chore($FEATURE_ID): update feature status" 2>/dev/null || true
|
|
419
|
-
fi
|
|
420
|
-
|
|
421
|
-
# Merge dev branch back to original on success
|
|
422
|
-
if [[ "$SESSION_STATUS" == "success" && -n "$_DEV_BRANCH_NAME" ]]; then
|
|
423
|
-
if branch_merge "$PROJECT_ROOT" "$_DEV_BRANCH_NAME" "$_ORIGINAL_BRANCH" "$AUTO_PUSH"; then
|
|
424
|
-
_DEV_BRANCH_NAME=""
|
|
425
|
-
else
|
|
426
|
-
log_warn "Auto-merge failed — dev branch preserved: $_DEV_BRANCH_NAME"
|
|
427
|
-
fi
|
|
428
|
-
elif [[ -n "$_DEV_BRANCH_NAME" ]]; then
|
|
429
|
-
# Session failed — return to original branch, preserve dev branch for inspection
|
|
430
|
-
git -C "$PROJECT_ROOT" checkout "$_ORIGINAL_BRANCH" 2>/dev/null || true
|
|
431
|
-
log_warn "Session failed — dev branch preserved for inspection: $_DEV_BRANCH_NAME"
|
|
432
|
-
_DEV_BRANCH_NAME=""
|
|
433
|
-
fi
|
|
434
|
-
|
|
435
|
-
echo ""
|
|
436
|
-
if [[ "$SESSION_STATUS" == "success" ]]; then
|
|
437
|
-
log_success "════════════════════════════════════════════════════"
|
|
438
|
-
log_success " $FEATURE_ID completed successfully!"
|
|
439
|
-
log_success "════════════════════════════════════════════════════"
|
|
440
|
-
else
|
|
441
|
-
log_error "════════════════════════════════════════════════════"
|
|
442
|
-
log_error " $FEATURE_ID result: $SESSION_STATUS"
|
|
443
|
-
log_error " Review log: $SESSION_LOG"
|
|
444
|
-
log_error "════════════════════════════════════════════════════"
|
|
445
|
-
fi
|