prizmkit 1.1.20 → 1.1.23
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/lib/branch.sh +187 -23
- package/bundled/dev-pipeline/reset-bug.sh +21 -13
- package/bundled/dev-pipeline/reset-feature.sh +21 -13
- package/bundled/dev-pipeline/reset-refactor.sh +21 -13
- package/bundled/dev-pipeline/run-bugfix.sh +113 -26
- package/bundled/dev-pipeline/run-feature.sh +113 -27
- package/bundled/dev-pipeline/run-refactor.sh +113 -26
- package/bundled/dev-pipeline/scripts/detect-stuck.py +25 -14
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +32 -0
- package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +0 -5
- package/bundled/dev-pipeline/scripts/init-pipeline.py +0 -5
- package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +0 -5
- package/bundled/dev-pipeline/scripts/update-bug-status.py +40 -31
- package/bundled/dev-pipeline/scripts/update-feature-status.py +54 -60
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +43 -34
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +22 -7
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +22 -7
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +22 -7
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +22 -7
- package/bundled/dev-pipeline/tests/test_auto_skip.py +10 -3
- package/bundled/skills/_metadata.json +1 -1
- package/package.json +1 -1
package/bundled/VERSION.json
CHANGED
|
@@ -2,18 +2,21 @@
|
|
|
2
2
|
# ============================================================
|
|
3
3
|
# dev-pipeline/lib/branch.sh - Git Branch Lifecycle Library
|
|
4
4
|
#
|
|
5
|
-
# Shared by run-feature.sh
|
|
6
|
-
# development. Each pipeline run creates
|
|
7
|
-
# features/bugs commit
|
|
5
|
+
# Shared by run-feature.sh, run-bugfix.sh, and run-refactor.sh
|
|
6
|
+
# for branch-based serial development. Each pipeline run creates
|
|
7
|
+
# a dev branch and all features/bugs/refactors commit on it.
|
|
8
8
|
#
|
|
9
9
|
# Functions:
|
|
10
|
-
# branch_create
|
|
11
|
-
# branch_return
|
|
12
|
-
# branch_merge
|
|
10
|
+
# branch_create — Create and checkout a new branch
|
|
11
|
+
# branch_return — Checkout back to original branch
|
|
12
|
+
# branch_merge — Merge dev branch into original and optionally push
|
|
13
|
+
# branch_ensure_return — Guaranteed return to original branch (try/finally)
|
|
13
14
|
#
|
|
14
15
|
# Environment:
|
|
15
|
-
#
|
|
16
|
-
#
|
|
16
|
+
# _ORIGINAL_BRANCH Set by caller before branch_create
|
|
17
|
+
# _DEV_BRANCH_NAME Set by caller after branch_create
|
|
18
|
+
# DEV_BRANCH Optional custom branch name override
|
|
19
|
+
# AUTO_PUSH Set to 1 to auto-push after successful feature
|
|
17
20
|
# ============================================================
|
|
18
21
|
|
|
19
22
|
# branch_create <project_root> <branch_name> <source_branch>
|
|
@@ -80,11 +83,15 @@ branch_return() {
|
|
|
80
83
|
#
|
|
81
84
|
# Merges dev_branch into original_branch, then optionally pushes.
|
|
82
85
|
# Steps:
|
|
83
|
-
# 1.
|
|
86
|
+
# 1. Stash tracked dirty files (NOT untracked — .prizmkit/state/ is gitignored)
|
|
84
87
|
# 2. Rebase dev_branch onto original_branch (handles diverged main)
|
|
85
88
|
# 3. Fast-forward merge original_branch to rebased dev tip
|
|
86
89
|
# 4. Push to remote if auto_push == "1"
|
|
87
90
|
# 5. Delete dev_branch (local only, it's been merged)
|
|
91
|
+
# 6. Restore stashed files
|
|
92
|
+
#
|
|
93
|
+
# IMPORTANT: On failure, caller MUST still call branch_ensure_return()
|
|
94
|
+
# to guarantee return to the original branch.
|
|
88
95
|
#
|
|
89
96
|
# Returns 0 on success, 1 on failure.
|
|
90
97
|
branch_merge() {
|
|
@@ -93,16 +100,21 @@ branch_merge() {
|
|
|
93
100
|
local original_branch="$3"
|
|
94
101
|
local auto_push="${4:-0}"
|
|
95
102
|
|
|
96
|
-
# Step 1:
|
|
97
|
-
#
|
|
103
|
+
# Step 1: Stash any tracked uncommitted changes so checkout is not blocked.
|
|
104
|
+
# Only stash tracked changes (not untracked). Untracked files like
|
|
105
|
+
# .prizmkit/state/ are gitignored and survive checkout without issue.
|
|
106
|
+
# Using --include-untracked causes stash pop conflicts and can lose
|
|
107
|
+
# state/ files that are needed for pipeline status tracking.
|
|
98
108
|
local had_stash=false
|
|
99
|
-
local
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
109
|
+
local tracked_dirty
|
|
110
|
+
tracked_dirty=$(git -C "$project_root" diff --name-only 2>/dev/null || true)
|
|
111
|
+
local staged_dirty
|
|
112
|
+
staged_dirty=$(git -C "$project_root" diff --cached --name-only 2>/dev/null || true)
|
|
113
|
+
if [[ -n "$tracked_dirty" || -n "$staged_dirty" ]]; then
|
|
114
|
+
if git -C "$project_root" stash push -m "pipeline-merge-stash" 2>/dev/null; then
|
|
103
115
|
had_stash=true
|
|
104
116
|
else
|
|
105
|
-
log_warn "git stash failed — uncommitted changes may not be preserved during merge"
|
|
117
|
+
log_warn "git stash failed — uncommitted tracked changes may not be preserved during merge"
|
|
106
118
|
had_stash=false
|
|
107
119
|
fi
|
|
108
120
|
fi
|
|
@@ -116,14 +128,21 @@ branch_merge() {
|
|
|
116
128
|
log_error "Rebase of $dev_branch onto $original_branch failed — resolve manually:"
|
|
117
129
|
log_error " git rebase --abort # then resolve conflicts and retry"
|
|
118
130
|
git -C "$project_root" rebase --abort 2>/dev/null || true
|
|
119
|
-
|
|
120
|
-
|
|
131
|
+
if [[ "$had_stash" == true ]]; then
|
|
132
|
+
if ! git -C "$project_root" stash pop 2>/dev/null; then
|
|
133
|
+
log_warn "git stash pop failed after rebase abort — run 'git stash list' to check"
|
|
134
|
+
fi
|
|
135
|
+
fi
|
|
121
136
|
return 1
|
|
122
137
|
fi
|
|
123
138
|
# After the rebase we are on dev_branch — checkout original for the fast-forward
|
|
124
139
|
if ! git -C "$project_root" checkout "$original_branch" 2>/dev/null; then
|
|
125
140
|
log_error "Failed to checkout $original_branch for merge"
|
|
126
|
-
[[ "$had_stash" == true ]]
|
|
141
|
+
if [[ "$had_stash" == true ]]; then
|
|
142
|
+
if ! git -C "$project_root" stash pop 2>/dev/null; then
|
|
143
|
+
log_warn "git stash pop failed after checkout failure — run 'git stash list' to check"
|
|
144
|
+
fi
|
|
145
|
+
fi
|
|
127
146
|
return 1
|
|
128
147
|
fi
|
|
129
148
|
|
|
@@ -131,8 +150,11 @@ branch_merge() {
|
|
|
131
150
|
if ! git -C "$project_root" merge --ff-only "$dev_branch" 2>&1; then
|
|
132
151
|
log_error "Merge failed after rebase — this should not happen, resolve manually:"
|
|
133
152
|
log_error " git checkout $original_branch && git rebase $dev_branch"
|
|
134
|
-
|
|
135
|
-
|
|
153
|
+
if [[ "$had_stash" == true ]]; then
|
|
154
|
+
if ! git -C "$project_root" stash pop 2>/dev/null; then
|
|
155
|
+
log_warn "git stash pop failed after merge failure — run 'git stash list' to check"
|
|
156
|
+
fi
|
|
157
|
+
fi
|
|
136
158
|
return 1
|
|
137
159
|
fi
|
|
138
160
|
|
|
@@ -152,8 +174,150 @@ branch_merge() {
|
|
|
152
174
|
git -C "$project_root" branch -d "$dev_branch" 2>/dev/null && \
|
|
153
175
|
log_info "Deleted merged branch: $dev_branch" || true
|
|
154
176
|
|
|
155
|
-
# Step 6: Restore stashed
|
|
156
|
-
[[ "$had_stash" == true ]]
|
|
177
|
+
# Step 6: Restore stashed files
|
|
178
|
+
if [[ "$had_stash" == true ]]; then
|
|
179
|
+
if ! git -C "$project_root" stash pop 2>/dev/null; then
|
|
180
|
+
log_warn "git stash pop failed after merge — stashed changes may be lost. Run 'git stash list' to check."
|
|
181
|
+
fi
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
return 0
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# branch_save_wip <project_root> <dev_branch>
|
|
188
|
+
#
|
|
189
|
+
# Saves any uncommitted work-in-progress on the dev branch before returning
|
|
190
|
+
# to the original branch. Called during interrupt/crash cleanup to preserve
|
|
191
|
+
# partially completed AI work that hasn't been committed yet.
|
|
192
|
+
#
|
|
193
|
+
# Commits ALL changes (tracked + untracked, excluding gitignored) with a
|
|
194
|
+
# "wip:" prefix message so it's easy to identify and squash later.
|
|
195
|
+
#
|
|
196
|
+
# Safe to call when the working tree is clean — it simply does nothing.
|
|
197
|
+
# Never fails — errors are logged but the function always returns 0.
|
|
198
|
+
branch_save_wip() {
|
|
199
|
+
local project_root="$1"
|
|
200
|
+
local dev_branch="$2"
|
|
201
|
+
|
|
202
|
+
# Nothing to save if dev_branch is empty
|
|
203
|
+
if [[ -z "$dev_branch" ]]; then
|
|
204
|
+
return 0
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
# Verify we're actually on the dev branch
|
|
208
|
+
local current_branch
|
|
209
|
+
current_branch=$(git -C "$project_root" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
210
|
+
if [[ "$current_branch" != "$dev_branch" ]]; then
|
|
211
|
+
return 0
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
# Check if there are any uncommitted changes (tracked or untracked, excluding gitignored)
|
|
215
|
+
local has_changes
|
|
216
|
+
has_changes=$(git -C "$project_root" status --porcelain 2>/dev/null || true)
|
|
217
|
+
if [[ -z "$has_changes" ]]; then
|
|
218
|
+
return 0
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
log_warn "Saving uncommitted work-in-progress on branch: $dev_branch"
|
|
222
|
+
|
|
223
|
+
# Stage all changes (tracked + untracked, respects .gitignore)
|
|
224
|
+
if ! git -C "$project_root" add -A 2>/dev/null; then
|
|
225
|
+
log_warn "git add -A failed — uncommitted work may be lost on branch switch"
|
|
226
|
+
return 0
|
|
227
|
+
fi
|
|
228
|
+
|
|
229
|
+
# Commit with WIP marker
|
|
230
|
+
if git -C "$project_root" commit --no-verify \
|
|
231
|
+
-m "wip($dev_branch): interrupted — uncommitted work saved" \
|
|
232
|
+
-m "Pipeline was interrupted by signal. This commit preserves work-in-progress." \
|
|
233
|
+
-m "To resume: git checkout $dev_branch" 2>/dev/null; then
|
|
234
|
+
log_info "Saved uncommitted work on branch $dev_branch"
|
|
235
|
+
else
|
|
236
|
+
log_warn "git commit failed — uncommitted work may be lost on branch switch"
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
return 0
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
# branch_ensure_return <project_root> <original_branch> [dev_branch]
|
|
243
|
+
#
|
|
244
|
+
# GUARANTEED return to the original branch. Like a try/finally block.
|
|
245
|
+
# Must be called in EVERY exit path: success, failure, interrupt, crash.
|
|
246
|
+
# This is the single point of truth for "always go back to original branch".
|
|
247
|
+
#
|
|
248
|
+
# If dev_branch is provided and we're currently on it, any uncommitted
|
|
249
|
+
# work is saved as a WIP commit before switching (via branch_save_wip).
|
|
250
|
+
#
|
|
251
|
+
# Handles:
|
|
252
|
+
# - Saving uncommitted WIP on dev branch (if dev_branch provided)
|
|
253
|
+
# - Aborting any in-progress rebase (leftover from branch_merge failure)
|
|
254
|
+
# - Stashing any tracked dirty files that block checkout
|
|
255
|
+
# - Checking out original_branch
|
|
256
|
+
# - Restoring stashed files
|
|
257
|
+
# - Logging for diagnostics
|
|
258
|
+
#
|
|
259
|
+
# Never fails — errors are logged but the function always returns 0
|
|
260
|
+
# so it can be used in cleanup traps without breaking error handling.
|
|
261
|
+
branch_ensure_return() {
|
|
262
|
+
local project_root="$1"
|
|
263
|
+
local original_branch="$2"
|
|
264
|
+
local dev_branch="${3:-}"
|
|
265
|
+
|
|
266
|
+
# If original_branch is empty or unset, nothing to return to
|
|
267
|
+
if [[ -z "$original_branch" ]]; then
|
|
268
|
+
return 0
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
# Abort any in-progress rebase (can happen if branch_merge failed mid-way)
|
|
272
|
+
if git -C "$project_root" rebase --show-current-patch >/dev/null 2>&1; then
|
|
273
|
+
log_warn "Aborting in-progress rebase..."
|
|
274
|
+
git -C "$project_root" rebase --abort 2>/dev/null || true
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
# Check current branch
|
|
278
|
+
local current_branch
|
|
279
|
+
current_branch=$(git -C "$project_root" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
280
|
+
|
|
281
|
+
if [[ "$current_branch" == "$original_branch" ]]; then
|
|
282
|
+
return 0
|
|
283
|
+
fi
|
|
284
|
+
|
|
285
|
+
# Save any uncommitted WIP on dev branch before switching away
|
|
286
|
+
# Use dev_branch if provided; otherwise infer from current_branch
|
|
287
|
+
local _wip_branch="${dev_branch:-$current_branch}"
|
|
288
|
+
if [[ -n "$_wip_branch" && "$_wip_branch" != "$original_branch" ]]; then
|
|
289
|
+
branch_save_wip "$project_root" "$_wip_branch"
|
|
290
|
+
fi
|
|
291
|
+
|
|
292
|
+
log_info "Ensuring return to original branch: $original_branch (currently on: ${current_branch:-unknown})"
|
|
293
|
+
|
|
294
|
+
# Stash any tracked dirty files that would block checkout
|
|
295
|
+
# (branch_save_wip should have committed everything, but this is a safety net
|
|
296
|
+
# in case the commit failed or new files appeared)
|
|
297
|
+
local had_stash=false
|
|
298
|
+
local tracked_dirty
|
|
299
|
+
tracked_dirty=$(git -C "$project_root" diff --name-only 2>/dev/null || true)
|
|
300
|
+
local staged_dirty
|
|
301
|
+
staged_dirty=$(git -C "$project_root" diff --cached --name-only 2>/dev/null || true)
|
|
302
|
+
if [[ -n "$tracked_dirty" || -n "$staged_dirty" ]]; then
|
|
303
|
+
if git -C "$project_root" stash push -m "pipeline-ensure-return-stash" 2>/dev/null; then
|
|
304
|
+
had_stash=true
|
|
305
|
+
fi
|
|
306
|
+
fi
|
|
307
|
+
|
|
308
|
+
# Checkout original branch
|
|
309
|
+
if git -C "$project_root" checkout "$original_branch" 2>/dev/null; then
|
|
310
|
+
log_info "Returned to branch: $original_branch"
|
|
311
|
+
else
|
|
312
|
+
log_error "Failed to checkout $original_branch — manual recovery needed"
|
|
313
|
+
fi
|
|
314
|
+
|
|
315
|
+
# Restore stashed files
|
|
316
|
+
if [[ "$had_stash" == true ]]; then
|
|
317
|
+
if ! git -C "$project_root" stash pop 2>/dev/null; then
|
|
318
|
+
log_warn "git stash pop failed during branch return — stashed changes may be lost. Run 'git stash list' to check."
|
|
319
|
+
fi
|
|
320
|
+
fi
|
|
157
321
|
|
|
158
322
|
return 0
|
|
159
323
|
}
|
|
@@ -139,22 +139,20 @@ fi
|
|
|
139
139
|
BUG_IDS=()
|
|
140
140
|
|
|
141
141
|
if [[ -n "$FILTER_MODE" ]]; then
|
|
142
|
-
# Filter by status from .
|
|
142
|
+
# Filter by status from bug-fix-list.json (single source of truth)
|
|
143
143
|
while IFS= read -r bid; do
|
|
144
144
|
[[ -n "$bid" ]] && BUG_IDS+=("$bid")
|
|
145
145
|
done < <(python3 -c "
|
|
146
|
-
import json,
|
|
147
|
-
state_dir = '$STATE_DIR'
|
|
146
|
+
import json, sys
|
|
148
147
|
filter_mode = '$FILTER_MODE'
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
for
|
|
153
|
-
|
|
154
|
-
if not os.path.isfile(status_file):
|
|
148
|
+
bug_list = '$BUG_LIST'
|
|
149
|
+
with open(bug_list) as f:
|
|
150
|
+
data = json.load(f)
|
|
151
|
+
for bug in data.get('bugs', []):
|
|
152
|
+
if not isinstance(bug, dict):
|
|
155
153
|
continue
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
bid = bug.get('id', '')
|
|
155
|
+
status = bug.get('status', '')
|
|
158
156
|
if filter_mode == 'auto_skipped' and status == 'auto_skipped':
|
|
159
157
|
print(bid)
|
|
160
158
|
elif filter_mode == 'failed' and status == 'failed':
|
|
@@ -244,13 +242,23 @@ sys.exit(1)
|
|
|
244
242
|
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
245
243
|
|
|
246
244
|
STATUS_FILE="$STATE_DIR/bugs/$CUR_BUG_ID/status.json"
|
|
245
|
+
# Read status from bug-fix-list.json (single source of truth)
|
|
246
|
+
CURRENT_STATUS=$(python3 -c "
|
|
247
|
+
import json, sys
|
|
248
|
+
with open('$BUG_LIST') as f:
|
|
249
|
+
data = json.load(f)
|
|
250
|
+
for bug in data.get('bugs', []):
|
|
251
|
+
if isinstance(bug, dict) and bug.get('id') == '$CUR_BUG_ID':
|
|
252
|
+
print(bug.get('status', '?'))
|
|
253
|
+
sys.exit(0)
|
|
254
|
+
print('?')
|
|
255
|
+
" 2>/dev/null || echo "?")
|
|
247
256
|
if [[ -f "$STATUS_FILE" ]]; then
|
|
248
|
-
CURRENT_STATUS=$(python3 -c "import json; d=json.load(open('$STATUS_FILE')); print(d.get('status','?'))")
|
|
249
257
|
CURRENT_RETRY=$(python3 -c "import json; d=json.load(open('$STATUS_FILE')); print(d.get('retry_count',0))")
|
|
250
258
|
SESSION_COUNT=$(python3 -c "import json; d=json.load(open('$STATUS_FILE')); print(len(d.get('sessions',[])))")
|
|
251
259
|
log_info "Current status: $CURRENT_STATUS (retry $CURRENT_RETRY, $SESSION_COUNT sessions)"
|
|
252
260
|
else
|
|
253
|
-
log_info "
|
|
261
|
+
log_info "Current status: $CURRENT_STATUS (no runtime state file)"
|
|
254
262
|
fi
|
|
255
263
|
|
|
256
264
|
BUGFIX_DIR="$PROJECT_ROOT/.prizmkit/bugfix/$CUR_BUG_ID"
|
|
@@ -139,22 +139,20 @@ fi
|
|
|
139
139
|
FEATURE_IDS=()
|
|
140
140
|
|
|
141
141
|
if [[ -n "$FILTER_MODE" ]]; then
|
|
142
|
-
# Filter by status from
|
|
142
|
+
# Filter by status from feature-list.json (single source of truth)
|
|
143
143
|
while IFS= read -r fid; do
|
|
144
144
|
[[ -n "$fid" ]] && FEATURE_IDS+=("$fid")
|
|
145
145
|
done < <(python3 -c "
|
|
146
|
-
import json,
|
|
147
|
-
state_dir = '$STATE_DIR'
|
|
146
|
+
import json, sys
|
|
148
147
|
filter_mode = '$FILTER_MODE'
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
for
|
|
153
|
-
|
|
154
|
-
if not os.path.isfile(status_file):
|
|
148
|
+
feature_list = '$FEATURE_LIST'
|
|
149
|
+
with open(feature_list) as f:
|
|
150
|
+
data = json.load(f)
|
|
151
|
+
for feat in data.get('features', []):
|
|
152
|
+
if not isinstance(feat, dict):
|
|
155
153
|
continue
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
fid = feat.get('id', '')
|
|
155
|
+
status = feat.get('status', '')
|
|
158
156
|
if filter_mode == 'auto_skipped' and status == 'auto_skipped':
|
|
159
157
|
print(fid)
|
|
160
158
|
elif filter_mode == 'failed' and status == 'failed':
|
|
@@ -253,13 +251,23 @@ sys.exit(1)
|
|
|
253
251
|
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
254
252
|
|
|
255
253
|
STATUS_FILE="$STATE_DIR/features/$CUR_FEATURE_ID/status.json"
|
|
254
|
+
# Read status from feature-list.json (single source of truth)
|
|
255
|
+
CURRENT_STATUS=$(python3 -c "
|
|
256
|
+
import json, sys
|
|
257
|
+
with open('$FEATURE_LIST') as f:
|
|
258
|
+
data = json.load(f)
|
|
259
|
+
for feat in data.get('features', []):
|
|
260
|
+
if isinstance(feat, dict) and feat.get('id') == '$CUR_FEATURE_ID':
|
|
261
|
+
print(feat.get('status', '?'))
|
|
262
|
+
sys.exit(0)
|
|
263
|
+
print('?')
|
|
264
|
+
" 2>/dev/null || echo "?")
|
|
256
265
|
if [[ -f "$STATUS_FILE" ]]; then
|
|
257
|
-
CURRENT_STATUS=$(python3 -c "import json; d=json.load(open('$STATUS_FILE')); print(d.get('status','?'))")
|
|
258
266
|
CURRENT_RETRY=$(python3 -c "import json; d=json.load(open('$STATUS_FILE')); print(d.get('retry_count',0))")
|
|
259
267
|
SESSION_COUNT=$(python3 -c "import json; d=json.load(open('$STATUS_FILE')); print(len(d.get('sessions',[])))")
|
|
260
268
|
log_info "Current status: $CURRENT_STATUS (retry $CURRENT_RETRY, $SESSION_COUNT sessions)"
|
|
261
269
|
else
|
|
262
|
-
log_info "
|
|
270
|
+
log_info "Current status: $CURRENT_STATUS (no runtime state file)"
|
|
263
271
|
fi
|
|
264
272
|
|
|
265
273
|
SPECS_DIR="$PROJECT_ROOT/.prizmkit/specs/$FEATURE_SLUG"
|
|
@@ -129,22 +129,20 @@ fi
|
|
|
129
129
|
REFACTOR_IDS=()
|
|
130
130
|
|
|
131
131
|
if [[ -n "$FILTER_MODE" ]]; then
|
|
132
|
-
# Filter by status from
|
|
132
|
+
# Filter by status from refactor-list.json (single source of truth)
|
|
133
133
|
while IFS= read -r rid; do
|
|
134
134
|
[[ -n "$rid" ]] && REFACTOR_IDS+=("$rid")
|
|
135
135
|
done < <(python3 -c "
|
|
136
|
-
import json,
|
|
137
|
-
state_dir = '$STATE_DIR'
|
|
136
|
+
import json, sys
|
|
138
137
|
filter_mode = '$FILTER_MODE'
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
for
|
|
143
|
-
|
|
144
|
-
if not os.path.isfile(status_file):
|
|
138
|
+
refactor_list = '$REFACTOR_LIST'
|
|
139
|
+
with open(refactor_list) as f:
|
|
140
|
+
data = json.load(f)
|
|
141
|
+
for r in data.get('refactors', []):
|
|
142
|
+
if not isinstance(r, dict):
|
|
145
143
|
continue
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
rid = r.get('id', '')
|
|
145
|
+
status = r.get('status', '')
|
|
148
146
|
if filter_mode == 'auto_skipped' and status == 'auto_skipped':
|
|
149
147
|
print(rid)
|
|
150
148
|
elif filter_mode == 'failed' and status == 'failed':
|
|
@@ -242,13 +240,23 @@ sys.exit(1)
|
|
|
242
240
|
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
243
241
|
|
|
244
242
|
STATUS_FILE="$STATE_DIR/refactors/$CUR_REFACTOR_ID/status.json"
|
|
243
|
+
# Read status from refactor-list.json (single source of truth)
|
|
244
|
+
CURRENT_STATUS=$(python3 -c "
|
|
245
|
+
import json, sys
|
|
246
|
+
with open('$REFACTOR_LIST') as f:
|
|
247
|
+
data = json.load(f)
|
|
248
|
+
for r in data.get('refactors', []):
|
|
249
|
+
if isinstance(r, dict) and r.get('id') == '$CUR_REFACTOR_ID':
|
|
250
|
+
print(r.get('status', '?'))
|
|
251
|
+
sys.exit(0)
|
|
252
|
+
print('?')
|
|
253
|
+
" 2>/dev/null || echo "?")
|
|
245
254
|
if [[ -f "$STATUS_FILE" ]]; then
|
|
246
|
-
CURRENT_STATUS=$(python3 -c "import json; d=json.load(open('$STATUS_FILE')); print(d.get('status','?'))")
|
|
247
255
|
CURRENT_RETRY=$(python3 -c "import json; d=json.load(open('$STATUS_FILE')); print(d.get('retry_count',0))")
|
|
248
256
|
SESSION_COUNT=$(python3 -c "import json; d=json.load(open('$STATUS_FILE')); print(len(d.get('sessions',[])))")
|
|
249
257
|
log_info "Current status: $CURRENT_STATUS (retry $CURRENT_RETRY, $SESSION_COUNT sessions)"
|
|
250
258
|
else
|
|
251
|
-
log_info "
|
|
259
|
+
log_info "Current status: $CURRENT_STATUS (no runtime state file)"
|
|
252
260
|
fi
|
|
253
261
|
|
|
254
262
|
SPECS_DIR="$PROJECT_ROOT/.prizmkit/specs/$REFACTOR_SLUG"
|