prizmkit 1.1.88 → 1.1.90
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/common.sh +0 -102
- package/bundled/dev-pipeline/run-bugfix.sh +0 -26
- package/bundled/dev-pipeline/run-feature.sh +5 -37
- package/bundled/dev-pipeline/run-refactor.sh +0 -26
- package/bundled/dev-pipeline/scripts/update-feature-status.py +2 -19
- package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +1 -65
- package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +2 -19
- package/bundled/skills/_metadata.json +1 -1
- package/package.json +1 -1
package/bundled/VERSION.json
CHANGED
|
@@ -713,107 +713,6 @@ PY
|
|
|
713
713
|
return 0
|
|
714
714
|
}
|
|
715
715
|
|
|
716
|
-
prizm_preserve_post_completion_dirty() {
|
|
717
|
-
local project_root="$1"
|
|
718
|
-
local artifact_dir="$2"
|
|
719
|
-
local feature_id="$3"
|
|
720
|
-
local session_id="${4:-}"
|
|
721
|
-
|
|
722
|
-
git -C "$project_root" rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 1
|
|
723
|
-
|
|
724
|
-
local dirty_status
|
|
725
|
-
dirty_status=$(git -C "$project_root" status --porcelain --untracked-files=all 2>/dev/null || true)
|
|
726
|
-
[[ -n "$dirty_status" ]] || return 0
|
|
727
|
-
|
|
728
|
-
mkdir -p "$artifact_dir" || return 1
|
|
729
|
-
|
|
730
|
-
local status_file="$artifact_dir/post-completion-status.txt"
|
|
731
|
-
local patch_file="$artifact_dir/post-completion-dirty.patch"
|
|
732
|
-
local staged_patch_file="$artifact_dir/post-completion-staged.patch"
|
|
733
|
-
local untracked_manifest="$artifact_dir/post-completion-untracked.txt"
|
|
734
|
-
local findings_file="$artifact_dir/post-completion-findings.md"
|
|
735
|
-
local untracked_dir="$artifact_dir/untracked"
|
|
736
|
-
|
|
737
|
-
printf '%s\n' "$dirty_status" > "$status_file" || return 1
|
|
738
|
-
git -C "$project_root" diff --binary > "$patch_file" 2>/dev/null || return 1
|
|
739
|
-
git -C "$project_root" diff --cached --binary > "$staged_patch_file" 2>/dev/null || return 1
|
|
740
|
-
|
|
741
|
-
: > "$untracked_manifest" || return 1
|
|
742
|
-
local untracked_tmp
|
|
743
|
-
untracked_tmp=$(mktemp 2>/dev/null || mktemp -t prizm-untracked) || return 1
|
|
744
|
-
git -C "$project_root" ls-files --others --exclude-standard -z > "$untracked_tmp" 2>/dev/null || {
|
|
745
|
-
rm -f "$untracked_tmp"
|
|
746
|
-
return 1
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
if [[ -s "$untracked_tmp" ]]; then
|
|
750
|
-
mkdir -p "$untracked_dir" || {
|
|
751
|
-
rm -f "$untracked_tmp"
|
|
752
|
-
return 1
|
|
753
|
-
}
|
|
754
|
-
while IFS= read -r -d '' rel_path; do
|
|
755
|
-
[[ -n "$rel_path" ]] || continue
|
|
756
|
-
printf '%s\n' "$rel_path" >> "$untracked_manifest" || {
|
|
757
|
-
rm -f "$untracked_tmp"
|
|
758
|
-
return 1
|
|
759
|
-
}
|
|
760
|
-
local source_path="$project_root/$rel_path"
|
|
761
|
-
local dest_path="$untracked_dir/$rel_path"
|
|
762
|
-
mkdir -p "$(dirname "$dest_path")" || {
|
|
763
|
-
rm -f "$untracked_tmp"
|
|
764
|
-
return 1
|
|
765
|
-
}
|
|
766
|
-
if [[ -f "$source_path" ]]; then
|
|
767
|
-
cp -p "$source_path" "$dest_path" || {
|
|
768
|
-
rm -f "$untracked_tmp"
|
|
769
|
-
return 1
|
|
770
|
-
}
|
|
771
|
-
elif [[ -d "$source_path" ]]; then
|
|
772
|
-
mkdir -p "$dest_path" || {
|
|
773
|
-
rm -f "$untracked_tmp"
|
|
774
|
-
return 1
|
|
775
|
-
}
|
|
776
|
-
fi
|
|
777
|
-
done < "$untracked_tmp"
|
|
778
|
-
fi
|
|
779
|
-
|
|
780
|
-
cat > "$findings_file" <<EOF
|
|
781
|
-
# Post-completion dirty changes preserved
|
|
782
|
-
|
|
783
|
-
- Feature: $feature_id
|
|
784
|
-
- Session: ${session_id:-unknown}
|
|
785
|
-
- Reason: workflow checkpoint and feature commit were already complete, but delayed post-commit activity left the working tree dirty.
|
|
786
|
-
|
|
787
|
-
## Recovery guidance
|
|
788
|
-
|
|
789
|
-
The finalized feature commit was kept unchanged for merge. Review these follow-up artifacts separately; do not assume they were merged:
|
|
790
|
-
|
|
791
|
-
- \`post-completion-status.txt\` — original dirty working tree status
|
|
792
|
-
- \`post-completion-dirty.patch\` — unstaged tracked changes
|
|
793
|
-
- \`post-completion-staged.patch\` — staged changes
|
|
794
|
-
- \`post-completion-untracked.txt\` and \`untracked/\` — untracked files copied before cleanup
|
|
795
|
-
EOF
|
|
796
|
-
|
|
797
|
-
git -C "$project_root" reset --hard >/dev/null 2>&1 || {
|
|
798
|
-
rm -f "$untracked_tmp"
|
|
799
|
-
return 1
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
while IFS= read -r -d '' rel_path; do
|
|
803
|
-
[[ -n "$rel_path" ]] || continue
|
|
804
|
-
case "$rel_path" in
|
|
805
|
-
.prizmkit/*) continue ;;
|
|
806
|
-
esac
|
|
807
|
-
rm -f "$project_root/$rel_path" 2>/dev/null || true
|
|
808
|
-
done < "$untracked_tmp"
|
|
809
|
-
rm -f "$untracked_tmp"
|
|
810
|
-
|
|
811
|
-
dirty_status=$(git -C "$project_root" status --porcelain --untracked-files=all 2>/dev/null | grep -v '^?? .prizmkit/' || true)
|
|
812
|
-
[[ -z "$dirty_status" ]] || return 1
|
|
813
|
-
|
|
814
|
-
return 0
|
|
815
|
-
}
|
|
816
|
-
|
|
817
716
|
prizm_synthesize_failure_log() {
|
|
818
717
|
local failure_log="$1"
|
|
819
718
|
local feature_id="$2"
|
|
@@ -934,7 +833,6 @@ $dirty_summary
|
|
|
934
833
|
## Recommended recovery action
|
|
935
834
|
|
|
936
835
|
- If this is an AI runtime/provider error before checkpoint completion, retry the session with a fresh context.
|
|
937
|
-
- If checkpoint completion and a feature commit both exist, inspect post-completion artifacts and finalize manually rather than rebuilding from scratch.
|
|
938
836
|
- If the working tree is dirty, preserve or review those changes before any reset or merge.
|
|
939
837
|
EOF
|
|
940
838
|
}
|
|
@@ -483,19 +483,6 @@ run_one() {
|
|
|
483
483
|
local bugs_count
|
|
484
484
|
bugs_count=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('bugs_count', 0))" 2>/dev/null || echo "0")
|
|
485
485
|
log_success "Bugfix pipeline initialized with $bugs_count bugs"
|
|
486
|
-
|
|
487
|
-
# Ensure state directory is gitignored
|
|
488
|
-
local _gitignore_path
|
|
489
|
-
_gitignore_path="$PROJECT_ROOT/.gitignore"
|
|
490
|
-
local _state_rel
|
|
491
|
-
_state_rel=$(python3 -c "import os; print(os.path.relpath('$STATE_DIR', '$PROJECT_ROOT'))" 2>/dev/null || echo ".prizmkit/state/bugfix")
|
|
492
|
-
if [[ -f "$_gitignore_path" ]]; then
|
|
493
|
-
if ! grep -qF "$_state_rel" "$_gitignore_path" 2>/dev/null; then
|
|
494
|
-
printf '\n# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" >> "$_gitignore_path"
|
|
495
|
-
fi
|
|
496
|
-
else
|
|
497
|
-
printf '# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" > "$_gitignore_path"
|
|
498
|
-
fi
|
|
499
486
|
fi
|
|
500
487
|
|
|
501
488
|
# Verify bug exists
|
|
@@ -843,19 +830,6 @@ main() {
|
|
|
843
830
|
local bugs_count
|
|
844
831
|
bugs_count=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('bugs_count', 0))" 2>/dev/null || echo "0")
|
|
845
832
|
log_success "Bugfix pipeline initialized with $bugs_count bugs"
|
|
846
|
-
|
|
847
|
-
# Ensure state directory is gitignored
|
|
848
|
-
local _gitignore_path
|
|
849
|
-
_gitignore_path="$PROJECT_ROOT/.gitignore"
|
|
850
|
-
local _state_rel
|
|
851
|
-
_state_rel=$(python3 -c "import os; print(os.path.relpath('$STATE_DIR', '$PROJECT_ROOT'))" 2>/dev/null || echo ".prizmkit/state/bugfix")
|
|
852
|
-
if [[ -f "$_gitignore_path" ]]; then
|
|
853
|
-
if ! grep -qF "$_state_rel" "$_gitignore_path" 2>/dev/null; then
|
|
854
|
-
printf '\n# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" >> "$_gitignore_path"
|
|
855
|
-
fi
|
|
856
|
-
else
|
|
857
|
-
printf '# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" > "$_gitignore_path"
|
|
858
|
-
fi
|
|
859
833
|
else
|
|
860
834
|
log_info "Resuming existing bugfix pipeline..."
|
|
861
835
|
fi
|
|
@@ -264,28 +264,11 @@ spawn_and_wait_session() {
|
|
|
264
264
|
local dirty_files=""
|
|
265
265
|
dirty_files=$(git -C "$project_root" status --porcelain 2>/dev/null || true)
|
|
266
266
|
if [[ -n "$dirty_files" ]]; then
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if [[ -n "$post_completion_slug" ]] && prizm_preserve_post_completion_dirty "$project_root" "$PRIZMKIT_DIR/specs/${post_completion_slug}" "$feature_id" "$session_id"; then
|
|
273
|
-
log_warn "Post-completion dirty changes preserved under $PRIZMKIT_DIR/specs/${post_completion_slug}/"
|
|
274
|
-
log_warn "They were not included in the finalized feature commit."
|
|
275
|
-
else
|
|
276
|
-
log_warn "Could not safely preserve post-completion dirty changes; preserving dev branch for manual finalization"
|
|
277
|
-
session_status="finalization_needed"
|
|
278
|
-
fi
|
|
279
|
-
else
|
|
280
|
-
# Auto-commit any remaining dirty files produced during a normal
|
|
281
|
-
# clean success path. Semantic finalization explicitly avoids this
|
|
282
|
-
# so delayed post-commit findings cannot be merged into main.
|
|
283
|
-
log_info "Auto-committing remaining session artifacts..."
|
|
284
|
-
git -C "$project_root" add -A 2>/dev/null || true
|
|
285
|
-
git -C "$project_root" commit --no-verify --amend --no-edit 2>/dev/null \
|
|
286
|
-
|| git -C "$project_root" commit --no-verify -m "chore($feature_id): include remaining session artifacts" 2>/dev/null \
|
|
287
|
-
|| true
|
|
288
|
-
fi
|
|
267
|
+
log_info "Auto-committing remaining session artifacts..."
|
|
268
|
+
git -C "$project_root" add -A 2>/dev/null || true
|
|
269
|
+
git -C "$project_root" commit --no-verify --amend --no-edit 2>/dev/null \
|
|
270
|
+
|| git -C "$project_root" commit --no-verify -m "chore($feature_id): include remaining session artifacts" 2>/dev/null \
|
|
271
|
+
|| true
|
|
289
272
|
fi
|
|
290
273
|
fi
|
|
291
274
|
fi
|
|
@@ -1084,21 +1067,6 @@ main() {
|
|
|
1084
1067
|
local features_count
|
|
1085
1068
|
features_count=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('features_count', 0))" 2>/dev/null || echo "0")
|
|
1086
1069
|
log_success "Pipeline initialized with $features_count features"
|
|
1087
|
-
|
|
1088
|
-
# Ensure state directory is gitignored (prevents branch-switch state loss)
|
|
1089
|
-
local _gitignore_path
|
|
1090
|
-
_gitignore_path="$PROJECT_ROOT/.gitignore"
|
|
1091
|
-
local _state_rel
|
|
1092
|
-
_state_rel=$(python3 -c "import os; print(os.path.relpath('$STATE_DIR', '$PROJECT_ROOT'))" 2>/dev/null || echo ".prizmkit/state/features")
|
|
1093
|
-
if [[ -f "$_gitignore_path" ]]; then
|
|
1094
|
-
if ! grep -qF "$_state_rel" "$_gitignore_path" 2>/dev/null; then
|
|
1095
|
-
printf '\n# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" >> "$_gitignore_path"
|
|
1096
|
-
log_info "Added $_state_rel/ to .gitignore"
|
|
1097
|
-
fi
|
|
1098
|
-
else
|
|
1099
|
-
printf '# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" > "$_gitignore_path"
|
|
1100
|
-
log_info "Created .gitignore with $_state_rel/"
|
|
1101
|
-
fi
|
|
1102
1070
|
else
|
|
1103
1071
|
log_info "Resuming existing pipeline..."
|
|
1104
1072
|
fi
|
|
@@ -510,19 +510,6 @@ run_one() {
|
|
|
510
510
|
local refactors_count
|
|
511
511
|
refactors_count=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('refactors_count', 0))" 2>/dev/null || echo "0")
|
|
512
512
|
log_success "Refactor pipeline initialized with $refactors_count refactors"
|
|
513
|
-
|
|
514
|
-
# Ensure state directory is gitignored
|
|
515
|
-
local _gitignore_path
|
|
516
|
-
_gitignore_path="$PROJECT_ROOT/.gitignore"
|
|
517
|
-
local _state_rel
|
|
518
|
-
_state_rel=$(python3 -c "import os; print(os.path.relpath('$STATE_DIR', '$PROJECT_ROOT'))" 2>/dev/null || echo ".prizmkit/state/refactor")
|
|
519
|
-
if [[ -f "$_gitignore_path" ]]; then
|
|
520
|
-
if ! grep -qF "$_state_rel" "$_gitignore_path" 2>/dev/null; then
|
|
521
|
-
printf '\n# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" >> "$_gitignore_path"
|
|
522
|
-
fi
|
|
523
|
-
else
|
|
524
|
-
printf '# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" > "$_gitignore_path"
|
|
525
|
-
fi
|
|
526
513
|
fi
|
|
527
514
|
|
|
528
515
|
# Verify refactor exists
|
|
@@ -873,19 +860,6 @@ main() {
|
|
|
873
860
|
local refactors_count
|
|
874
861
|
refactors_count=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('refactors_count', 0))" 2>/dev/null || echo "0")
|
|
875
862
|
log_success "Refactor pipeline initialized with $refactors_count refactors"
|
|
876
|
-
|
|
877
|
-
# Ensure state directory is gitignored
|
|
878
|
-
local _gitignore_path
|
|
879
|
-
_gitignore_path="$PROJECT_ROOT/.gitignore"
|
|
880
|
-
local _state_rel
|
|
881
|
-
_state_rel=$(python3 -c "import os; print(os.path.relpath('$STATE_DIR', '$PROJECT_ROOT'))" 2>/dev/null || echo ".prizmkit/state/refactor")
|
|
882
|
-
if [[ -f "$_gitignore_path" ]]; then
|
|
883
|
-
if ! grep -qF "$_state_rel" "$_gitignore_path" 2>/dev/null; then
|
|
884
|
-
printf '\n# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" >> "$_gitignore_path"
|
|
885
|
-
fi
|
|
886
|
-
else
|
|
887
|
-
printf '# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" > "$_gitignore_path"
|
|
888
|
-
fi
|
|
889
863
|
else
|
|
890
864
|
log_info "Resuming existing refactor pipeline..."
|
|
891
865
|
fi
|
|
@@ -49,7 +49,6 @@ SESSION_STATUS_VALUES = [
|
|
|
49
49
|
"commit_missing",
|
|
50
50
|
"docs_missing",
|
|
51
51
|
"merge_conflict",
|
|
52
|
-
"finalization_needed",
|
|
53
52
|
]
|
|
54
53
|
|
|
55
54
|
TERMINAL_STATUSES = {"completed", "failed", "skipped", "auto_skipped", "split"}
|
|
@@ -649,22 +648,6 @@ def action_update(args, feature_list_path, state_dir):
|
|
|
649
648
|
fs["last_session_id"] = session_id
|
|
650
649
|
fs["last_failed_session_id"] = session_id
|
|
651
650
|
|
|
652
|
-
err = update_feature_in_list(feature_list_path, feature_id, new_status)
|
|
653
|
-
if err:
|
|
654
|
-
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
655
|
-
return
|
|
656
|
-
elif session_status == "finalization_needed":
|
|
657
|
-
# Runtime preserved dirty post-completion changes but could not safely
|
|
658
|
-
# clean them for automatic merge. Preserve the dev branch and stop for
|
|
659
|
-
# manual finalization instead of spending code retry budget.
|
|
660
|
-
new_status = "failed"
|
|
661
|
-
fs["degraded_reason"] = session_status
|
|
662
|
-
fs["resume_from_phase"] = None
|
|
663
|
-
fs["finalization_needed_count"] = fs.get("finalization_needed_count", 0) + 1
|
|
664
|
-
if session_id:
|
|
665
|
-
fs["last_session_id"] = session_id
|
|
666
|
-
fs["last_failed_session_id"] = session_id
|
|
667
|
-
|
|
668
651
|
err = update_feature_in_list(feature_list_path, feature_id, new_status)
|
|
669
652
|
if err:
|
|
670
653
|
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
@@ -736,9 +719,9 @@ def action_update(args, feature_list_path, state_dir):
|
|
|
736
719
|
}
|
|
737
720
|
if auto_skipped_features:
|
|
738
721
|
summary["auto_skipped"] = [info["feature_id"] for info in auto_skipped_features]
|
|
739
|
-
if session_status in ("commit_missing", "docs_missing", "merge_conflict"
|
|
722
|
+
if session_status in ("commit_missing", "docs_missing", "merge_conflict"):
|
|
740
723
|
summary["degraded_reason"] = session_status
|
|
741
|
-
summary["restart_policy"] = "
|
|
724
|
+
summary["restart_policy"] = "finalization_retry"
|
|
742
725
|
elif session_status == "infra_error":
|
|
743
726
|
summary["restart_policy"] = "infra_retry"
|
|
744
727
|
summary["infra_error_count"] = fs.get("infra_error_count", 0)
|
|
@@ -438,60 +438,6 @@ function Invoke-PrizmPipeline {
|
|
|
438
438
|
return [pscustomobject]@{ Slug = $slug; CommitSha = $commitSha; CheckpointPath = $checkpointPath }
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
-
function Save-PrizmPostCompletionDirtyArtifacts {
|
|
442
|
-
param([string]$ProjectRoot, [string]$ArtifactDir, [string]$ItemId, [string]$SessionId)
|
|
443
|
-
$status = & git -C $ProjectRoot status --porcelain --untracked-files=all 2>$null
|
|
444
|
-
if ([string]::IsNullOrWhiteSpace(($status -join "`n"))) { return $true }
|
|
445
|
-
|
|
446
|
-
New-Item -ItemType Directory -Force -Path $ArtifactDir | Out-Null
|
|
447
|
-
($status -join "`n") | Set-Content -Path (Join-Path $ArtifactDir 'post-completion-status.txt') -Encoding UTF8
|
|
448
|
-
& git -C $ProjectRoot diff --binary | Set-Content -Path (Join-Path $ArtifactDir 'post-completion-dirty.patch') -Encoding UTF8
|
|
449
|
-
if ($LASTEXITCODE -ne 0) { return $false }
|
|
450
|
-
& git -C $ProjectRoot diff --cached --binary | Set-Content -Path (Join-Path $ArtifactDir 'post-completion-staged.patch') -Encoding UTF8
|
|
451
|
-
if ($LASTEXITCODE -ne 0) { return $false }
|
|
452
|
-
|
|
453
|
-
$untracked = & git -C $ProjectRoot ls-files --others --exclude-standard 2>$null
|
|
454
|
-
$manifest = Join-Path $ArtifactDir 'post-completion-untracked.txt'
|
|
455
|
-
@($untracked) | Set-Content -Path $manifest -Encoding UTF8
|
|
456
|
-
$untrackedDir = Join-Path $ArtifactDir 'untracked'
|
|
457
|
-
foreach ($rel in @($untracked)) {
|
|
458
|
-
if (-not $rel) { continue }
|
|
459
|
-
$source = Join-Path $ProjectRoot $rel
|
|
460
|
-
$dest = Join-Path $untrackedDir $rel
|
|
461
|
-
$destParent = Split-Path $dest -Parent
|
|
462
|
-
if ($destParent) { New-Item -ItemType Directory -Force -Path $destParent | Out-Null }
|
|
463
|
-
if (Test-Path $source -PathType Leaf) { Copy-Item -LiteralPath $source -Destination $dest -Force }
|
|
464
|
-
elseif (Test-Path $source -PathType Container) { New-Item -ItemType Directory -Force -Path $dest | Out-Null }
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
@(
|
|
468
|
-
'# Post-completion dirty changes preserved',
|
|
469
|
-
'',
|
|
470
|
-
"- Feature: $ItemId",
|
|
471
|
-
"- Session: $SessionId",
|
|
472
|
-
'- Reason: workflow checkpoint and feature commit were already complete, but delayed post-commit activity left the working tree dirty.',
|
|
473
|
-
'',
|
|
474
|
-
'## Recovery guidance',
|
|
475
|
-
'',
|
|
476
|
-
'The finalized feature commit was kept unchanged for merge. Review these follow-up artifacts separately; do not assume they were merged:',
|
|
477
|
-
'',
|
|
478
|
-
'- `post-completion-status.txt` — original dirty working tree status',
|
|
479
|
-
'- `post-completion-dirty.patch` — unstaged tracked changes',
|
|
480
|
-
'- `post-completion-staged.patch` — staged changes',
|
|
481
|
-
'- `post-completion-untracked.txt` and `untracked/` — untracked files copied before cleanup'
|
|
482
|
-
) | Set-Content -Path (Join-Path $ArtifactDir 'post-completion-findings.md') -Encoding UTF8
|
|
483
|
-
|
|
484
|
-
& git -C $ProjectRoot reset --hard *> $null
|
|
485
|
-
if ($LASTEXITCODE -ne 0) { return $false }
|
|
486
|
-
foreach ($rel in @($untracked)) {
|
|
487
|
-
if (-not $rel -or $rel -like '.prizmkit/*') { continue }
|
|
488
|
-
$target = Join-Path $ProjectRoot $rel
|
|
489
|
-
if (Test-Path $target) { Remove-Item -LiteralPath $target -Recurse -Force -ErrorAction SilentlyContinue }
|
|
490
|
-
}
|
|
491
|
-
$remaining = & git -C $ProjectRoot status --porcelain --untracked-files=all 2>$null | Where-Object { $_ -notmatch '^\?\? \.prizmkit/' }
|
|
492
|
-
return [string]::IsNullOrWhiteSpace(($remaining -join "`n"))
|
|
493
|
-
}
|
|
494
|
-
|
|
495
441
|
function Write-PrizmRuntimeFailureLog {
|
|
496
442
|
param(
|
|
497
443
|
[string]$FailureLog,
|
|
@@ -573,7 +519,6 @@ function Invoke-PrizmPipeline {
|
|
|
573
519
|
'## Recommended recovery action',
|
|
574
520
|
'',
|
|
575
521
|
'- If this is an AI runtime/provider error before checkpoint completion, retry the session with a fresh context.',
|
|
576
|
-
'- If checkpoint completion and a feature commit both exist, inspect post-completion artifacts and finalize manually rather than rebuilding from scratch.',
|
|
577
522
|
'- If the working tree is dirty, preserve or review those changes before any reset or merge.'
|
|
578
523
|
) | Set-Content -Path $FailureLog -Encoding UTF8
|
|
579
524
|
}
|
|
@@ -946,16 +891,7 @@ function Invoke-PrizmPipeline {
|
|
|
946
891
|
$itemListStatus = ''
|
|
947
892
|
if ($status -eq 'success') {
|
|
948
893
|
if (Test-PrizmGitDirty $paths.ProjectRoot) {
|
|
949
|
-
if ($
|
|
950
|
-
$artifactDir = Join-Path $paths.PrizmkitDir "specs\$($semanticCompletion.Slug)"
|
|
951
|
-
if (Save-PrizmPostCompletionDirtyArtifacts $paths.ProjectRoot $artifactDir $CurrentItemId $sessionId) {
|
|
952
|
-
Write-PrizmWarn "Post-completion dirty changes preserved under $artifactDir"
|
|
953
|
-
Write-PrizmWarn "They were not included in the finalized feature commit."
|
|
954
|
-
} else {
|
|
955
|
-
Write-PrizmWarn "Could not safely preserve post-completion dirty changes; preserving dev branch for manual finalization"
|
|
956
|
-
$status = 'finalization_needed'
|
|
957
|
-
}
|
|
958
|
-
} elseif ($hadDirtyBaseline) {
|
|
894
|
+
if ($hadDirtyBaseline) {
|
|
959
895
|
Write-PrizmInfo "Auto-committing pipeline bookkeeping artifacts only."
|
|
960
896
|
Invoke-PrizmGitIncludeBookkeepingArtifacts $paths.ProjectRoot $stateDir $listPath
|
|
961
897
|
} else {
|
|
@@ -49,7 +49,6 @@ SESSION_STATUS_VALUES = [
|
|
|
49
49
|
"commit_missing",
|
|
50
50
|
"docs_missing",
|
|
51
51
|
"merge_conflict",
|
|
52
|
-
"finalization_needed",
|
|
53
52
|
]
|
|
54
53
|
|
|
55
54
|
TERMINAL_STATUSES = {"completed", "failed", "skipped", "auto_skipped", "split"}
|
|
@@ -649,22 +648,6 @@ def action_update(args, feature_list_path, state_dir):
|
|
|
649
648
|
fs["last_session_id"] = session_id
|
|
650
649
|
fs["last_failed_session_id"] = session_id
|
|
651
650
|
|
|
652
|
-
err = update_feature_in_list(feature_list_path, feature_id, new_status)
|
|
653
|
-
if err:
|
|
654
|
-
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
655
|
-
return
|
|
656
|
-
elif session_status == "finalization_needed":
|
|
657
|
-
# Runtime preserved dirty post-completion changes but could not safely
|
|
658
|
-
# clean them for automatic merge. Preserve the dev branch and stop for
|
|
659
|
-
# manual finalization instead of spending code retry budget.
|
|
660
|
-
new_status = "failed"
|
|
661
|
-
fs["degraded_reason"] = session_status
|
|
662
|
-
fs["resume_from_phase"] = None
|
|
663
|
-
fs["finalization_needed_count"] = fs.get("finalization_needed_count", 0) + 1
|
|
664
|
-
if session_id:
|
|
665
|
-
fs["last_session_id"] = session_id
|
|
666
|
-
fs["last_failed_session_id"] = session_id
|
|
667
|
-
|
|
668
651
|
err = update_feature_in_list(feature_list_path, feature_id, new_status)
|
|
669
652
|
if err:
|
|
670
653
|
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
@@ -736,9 +719,9 @@ def action_update(args, feature_list_path, state_dir):
|
|
|
736
719
|
}
|
|
737
720
|
if auto_skipped_features:
|
|
738
721
|
summary["auto_skipped"] = [info["feature_id"] for info in auto_skipped_features]
|
|
739
|
-
if session_status in ("commit_missing", "docs_missing", "merge_conflict"
|
|
722
|
+
if session_status in ("commit_missing", "docs_missing", "merge_conflict"):
|
|
740
723
|
summary["degraded_reason"] = session_status
|
|
741
|
-
summary["restart_policy"] = "
|
|
724
|
+
summary["restart_policy"] = "finalization_retry"
|
|
742
725
|
elif session_status == "infra_error":
|
|
743
726
|
summary["restart_policy"] = "infra_retry"
|
|
744
727
|
summary["infra_error_count"] = fs.get("infra_error_count", 0)
|