prizmkit 1.1.8 → 1.1.10

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.
Files changed (123) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/codebuddy/skill-adapter.js +21 -7
  3. package/bundled/agents/prizm-dev-team-reviewer.md +53 -173
  4. package/bundled/dev-pipeline/.env.example +45 -0
  5. package/bundled/dev-pipeline/SCHEMA_ANALYSIS.md +535 -0
  6. package/bundled/dev-pipeline/assets/feature-list-example.json +0 -1
  7. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +57 -12
  8. package/bundled/dev-pipeline/launch-feature-daemon.sh +3 -1
  9. package/bundled/dev-pipeline/launch-refactor-daemon.sh +57 -12
  10. package/bundled/dev-pipeline/lib/branch.sh +6 -1
  11. package/bundled/dev-pipeline/lib/common.sh +71 -0
  12. package/bundled/dev-pipeline/lib/heartbeat.sh +2 -2
  13. package/bundled/dev-pipeline/retry-bugfix.sh +60 -23
  14. package/bundled/dev-pipeline/retry-feature.sh +47 -12
  15. package/bundled/dev-pipeline/retry-refactor.sh +105 -23
  16. package/bundled/dev-pipeline/run-bugfix.sh +265 -44
  17. package/bundled/dev-pipeline/run-feature.sh +35 -1
  18. package/bundled/dev-pipeline/run-refactor.sh +376 -51
  19. package/bundled/dev-pipeline/scripts/check-session-status.py +24 -1
  20. package/bundled/dev-pipeline/scripts/detect-stuck.py +195 -85
  21. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +31 -19
  22. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +19 -3
  23. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +98 -11
  24. package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +30 -5
  25. package/bundled/dev-pipeline/scripts/init-pipeline.py +3 -3
  26. package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +15 -4
  27. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +1 -5
  28. package/bundled/dev-pipeline/scripts/patch-completion-notes.py +191 -0
  29. package/bundled/dev-pipeline/scripts/update-bug-status.py +159 -14
  30. package/bundled/dev-pipeline/scripts/update-feature-status.py +79 -37
  31. package/bundled/dev-pipeline/scripts/update-refactor-status.py +343 -13
  32. package/bundled/dev-pipeline/templates/agent-prompts/dev-fix.md +1 -1
  33. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +7 -11
  34. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +41 -7
  35. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +27 -3
  36. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +43 -19
  37. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +54 -26
  38. package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +5 -14
  39. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +36 -25
  40. package/bundled/dev-pipeline/templates/feature-list-schema.json +23 -11
  41. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +270 -0
  42. package/bundled/dev-pipeline/templates/refactor-list-schema.json +10 -2
  43. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +3 -1
  44. package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +1 -0
  45. package/bundled/dev-pipeline/templates/sections/feature-context.md +2 -0
  46. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +29 -2
  47. package/bundled/dev-pipeline/templates/sections/phase-commit.md +22 -0
  48. package/bundled/dev-pipeline/templates/sections/phase-deploy-verification.md +2 -2
  49. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +8 -6
  50. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +7 -5
  51. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +3 -3
  52. package/bundled/skills/_metadata.json +5 -22
  53. package/bundled/skills/app-planner/SKILL.md +92 -66
  54. package/bundled/skills/app-planner/assets/app-design-guide.md +1 -1
  55. package/bundled/skills/app-planner/references/architecture-decisions.md +1 -1
  56. package/bundled/skills/app-planner/references/project-brief-guide.md +69 -66
  57. package/bundled/skills/bug-fix-workflow/SKILL.md +47 -4
  58. package/bundled/skills/bug-planner/SKILL.md +130 -188
  59. package/bundled/skills/bug-planner/assets/bug-confirmation-template.md +43 -0
  60. package/bundled/skills/bug-planner/references/critic-and-verification.md +44 -0
  61. package/bundled/skills/bug-planner/references/error-recovery.md +73 -0
  62. package/bundled/skills/bug-planner/references/input-formats.md +53 -0
  63. package/bundled/skills/bug-planner/references/schema-validation.md +25 -0
  64. package/bundled/skills/bug-planner/references/severity-rules.md +16 -0
  65. package/bundled/skills/bug-planner/scripts/validate-bug-list.py +1 -5
  66. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +5 -10
  67. package/bundled/skills/feature-pipeline-launcher/SKILL.md +16 -3
  68. package/bundled/skills/feature-planner/SKILL.md +33 -122
  69. package/bundled/skills/feature-planner/assets/evaluation-guide.md +1 -1
  70. package/bundled/skills/feature-planner/assets/planning-guide.md +21 -5
  71. package/bundled/skills/feature-planner/references/browser-interaction.md +2 -4
  72. package/bundled/skills/feature-planner/references/completeness-review.md +57 -0
  73. package/bundled/skills/feature-planner/references/error-recovery.md +15 -34
  74. package/bundled/skills/feature-planner/references/incremental-feature-planning.md +1 -1
  75. package/bundled/skills/feature-planner/references/new-project-planning.md +2 -2
  76. package/bundled/skills/feature-planner/scripts/validate-and-generate.py +1 -2
  77. package/bundled/skills/feature-workflow/SKILL.md +3 -4
  78. package/bundled/skills/prizm-kit/SKILL.md +39 -49
  79. package/bundled/skills/prizmkit-code-review/SKILL.md +51 -64
  80. package/bundled/skills/prizmkit-code-review/rules/dimensions.md +85 -0
  81. package/bundled/skills/prizmkit-code-review/rules/fix-strategy.md +11 -11
  82. package/bundled/skills/prizmkit-committer/SKILL.md +3 -31
  83. package/bundled/skills/prizmkit-deploy/SKILL.md +34 -31
  84. package/bundled/skills/prizmkit-deploy/assets/deploy-template.md +1 -1
  85. package/bundled/skills/prizmkit-implement/SKILL.md +35 -68
  86. package/bundled/skills/prizmkit-init/SKILL.md +112 -65
  87. package/bundled/skills/prizmkit-init/assets/project-brief-template.md +82 -0
  88. package/bundled/skills/prizmkit-plan/SKILL.md +120 -79
  89. package/bundled/skills/prizmkit-plan/assets/plan-template.md +28 -18
  90. package/bundled/skills/prizmkit-plan/assets/spec-template.md +28 -11
  91. package/bundled/skills/prizmkit-plan/references/clarify-guide.md +3 -3
  92. package/bundled/skills/prizmkit-plan/references/verification-checklist.md +60 -0
  93. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +10 -81
  94. package/bundled/skills/prizmkit-prizm-docs/assets/{PRIZM-SPEC.md → prizm-docs-format.md} +41 -526
  95. package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +46 -0
  96. package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +16 -0
  97. package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +14 -0
  98. package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +19 -0
  99. package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +17 -0
  100. package/bundled/skills/prizmkit-retrospective/SKILL.md +27 -65
  101. package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +3 -4
  102. package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +7 -25
  103. package/bundled/skills/recovery-workflow/SKILL.md +8 -8
  104. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +17 -9
  105. package/bundled/skills/refactor-planner/SKILL.md +23 -41
  106. package/bundled/skills/refactor-workflow/SKILL.md +1 -2
  107. package/bundled/team/prizm-dev-team.json +1 -1
  108. package/bundled/{skills/prizm-kit/assets → templates}/project-memory-template.md +1 -1
  109. package/package.json +1 -1
  110. package/src/clean.js +0 -1
  111. package/src/gitignore-template.js +0 -1
  112. package/src/scaffold.js +10 -3
  113. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-analyze.md +0 -5
  114. package/bundled/dev-pipeline/templates/sections/phase-analyze-agent.md +0 -19
  115. package/bundled/dev-pipeline/templates/sections/phase-analyze-full.md +0 -19
  116. package/bundled/skills/app-planner/references/project-conventions.md +0 -93
  117. package/bundled/skills/prizmkit-analyze/SKILL.md +0 -207
  118. package/bundled/skills/prizmkit-code-review/rules/dimensions-bugfix.md +0 -25
  119. package/bundled/skills/prizmkit-code-review/rules/dimensions-feature.md +0 -43
  120. package/bundled/skills/prizmkit-code-review/rules/dimensions-refactor.md +0 -25
  121. package/bundled/skills/prizmkit-implement/references/deploy-guide-protocol.md +0 -69
  122. package/bundled/skills/prizmkit-verify/SKILL.md +0 -281
  123. package/bundled/skills/prizmkit-verify/scripts/verify-light.py +0 -402
@@ -8,11 +8,11 @@ set -euo pipefail
8
8
  # log consolidation, and lifecycle commands.
9
9
  #
10
10
  # Usage:
11
- # ./launch-bugfix-daemon.sh start [.prizmkit/plans/bug-fix-list.json] [--env "KEY=VAL ..."]
11
+ # ./launch-bugfix-daemon.sh start [.prizmkit/plans/bug-fix-list.json] [--mode <mode>] [--critic] [--env "KEY=VAL ..."]
12
12
  # ./launch-bugfix-daemon.sh stop
13
13
  # ./launch-bugfix-daemon.sh status
14
14
  # ./launch-bugfix-daemon.sh logs [--lines N] [--follow]
15
- # ./launch-bugfix-daemon.sh restart [.prizmkit/plans/bug-fix-list.json] [--env "KEY=VAL ..."]
15
+ # ./launch-bugfix-daemon.sh restart [.prizmkit/plans/bug-fix-list.json] [--mode <mode>] [--critic] [--env "KEY=VAL ..."]
16
16
  #
17
17
  # NOTE:
18
18
  # In AI skill sessions, always use this daemon wrapper.
@@ -93,6 +93,31 @@ cmd_start() {
93
93
  while [[ $# -gt 0 ]]; do
94
94
  case "$1" in
95
95
  --env) shift; env_overrides="${1:-}"; shift ;;
96
+ --mode)
97
+ shift
98
+ if [[ $# -eq 0 ]]; then
99
+ log_error "--mode requires a value (lite|standard|full)"
100
+ exit 1
101
+ fi
102
+ case "$1" in
103
+ lite|standard|full)
104
+ PIPELINE_MODE="$1"
105
+ ;;
106
+ *)
107
+ log_error "Invalid mode: $1 (must be lite, standard, or full)"
108
+ exit 1
109
+ ;;
110
+ esac
111
+ shift
112
+ ;;
113
+ --critic)
114
+ ENABLE_CRITIC=true
115
+ shift
116
+ ;;
117
+ --no-critic)
118
+ ENABLE_CRITIC=false
119
+ shift
120
+ ;;
96
121
  *) bug_list="$1"; shift ;;
97
122
  esac
98
123
  done
@@ -166,6 +191,9 @@ cmd_start() {
166
191
  echo ""
167
192
  } >> "$LOG_FILE"
168
193
 
194
+ [[ -n "${PIPELINE_MODE:-}" ]] && export PIPELINE_MODE
195
+ [[ -n "${ENABLE_CRITIC:-}" ]] && export ENABLE_CRITIC
196
+
169
197
  if [[ -n "$env_cmd" ]]; then
170
198
  nohup $env_cmd "$RUN_SCRIPT" run "$bug_list" >> "$LOG_FILE" 2>&1 &
171
199
  else
@@ -174,11 +202,12 @@ cmd_start() {
174
202
  local pipeline_pid=$!
175
203
  disown "$pipeline_pid" 2>/dev/null || true
176
204
 
177
- echo "$pipeline_pid" > "$PID_FILE"
205
+ echo "$pipeline_pid" > "${PID_FILE}.tmp"
206
+ mv "${PID_FILE}.tmp" "$PID_FILE"
178
207
 
208
+ # Write start metadata (atomic)
179
209
  python3 -c "
180
- import json
181
- from datetime import datetime
210
+ import json, os
182
211
  data = {
183
212
  'pid': $pipeline_pid,
184
213
  'pipeline_type': 'bugfix',
@@ -187,8 +216,11 @@ data = {
187
216
  'env_overrides': '$env_overrides',
188
217
  'log_file': '$LOG_FILE'
189
218
  }
190
- with open('$STATE_DIR/.pipeline-meta.json', 'w') as f:
219
+ target = os.path.join('$STATE_DIR', '.pipeline-meta.json')
220
+ tmp = target + '.tmp'
221
+ with open(tmp, 'w') as f:
191
222
  json.dump(data, f, indent=2)
223
+ os.replace(tmp, target)
192
224
  " 2>/dev/null || true
193
225
 
194
226
  sleep 2
@@ -234,7 +266,10 @@ cmd_stop() {
234
266
  fi
235
267
 
236
268
  log_info "Stopping bugfix pipeline (PID: $pid)..."
237
- kill -TERM "$pid" 2>/dev/null || true
269
+
270
+ # Kill the entire process group to include child processes (claude-internal, etc.)
271
+ # First try SIGTERM to the process group (negative PID)
272
+ kill -TERM -- -"$pid" 2>/dev/null || kill -TERM "$pid" 2>/dev/null || true
238
273
 
239
274
  local waited=0
240
275
  while [[ $waited -lt 30 ]]; do
@@ -245,9 +280,10 @@ cmd_stop() {
245
280
  waited=$((waited + 1))
246
281
  done
247
282
 
283
+ # Force kill if still alive (process group first, then individual)
248
284
  if kill -0 "$pid" 2>/dev/null; then
249
285
  log_warn "Process did not exit after 30s, sending SIGKILL..."
250
- kill -9 "$pid" 2>/dev/null || true
286
+ kill -9 -- -"$pid" 2>/dev/null || kill -9 "$pid" 2>/dev/null || true
251
287
  sleep 1
252
288
  fi
253
289
 
@@ -342,7 +378,7 @@ import json, os
342
378
  bl = json.load(open('$bug_list_path'))
343
379
  bugs = bl.get('bugs', [])
344
380
  total = len(bugs)
345
- counts = {'completed': 0, 'in_progress': 0, 'failed': 0, 'pending': 0, 'needs_info': 0}
381
+ counts = {'completed': 0, 'in_progress': 0, 'failed': 0, 'pending': 0, 'needs_info': 0, 'skipped': 0}
346
382
  for bug in bugs:
347
383
  bid = bug.get('id', '')
348
384
  sp = os.path.join('$STATE_DIR', 'bugs', bid, 'status.json')
@@ -356,7 +392,7 @@ for bug in bugs:
356
392
  else:
357
393
  counts['pending'] += 1
358
394
  pct = round(counts['completed'] / total * 100, 1) if total > 0 else 0
359
- print(json.dumps({'total': total, 'completed': counts['completed'], 'in_progress': counts['in_progress'], 'failed': counts['failed'], 'pending': counts['pending'], 'needs_info': counts['needs_info'], 'percent': pct}))
395
+ print(json.dumps({'total': total, 'completed': counts['completed'], 'in_progress': counts['in_progress'], 'failed': counts['failed'], 'pending': counts['pending'], 'needs_info': counts['needs_info'], 'skipped': counts['skipped'], 'percent': pct}))
360
396
  " 2>/dev/null || echo "")
361
397
  fi
362
398
 
@@ -416,17 +452,26 @@ show_help() {
416
452
  Usage: launch-bugfix-daemon.sh <command> [options]
417
453
 
418
454
  Commands:
419
- start [.prizmkit/plans/bug-fix-list.json] [--env "K=V ..."] Start bugfix pipeline in background
455
+ start [.prizmkit/plans/bug-fix-list.json] [--mode <mode>] [--critic] [--env "K=V ..."] Start bugfix pipeline in background
420
456
  stop Gracefully stop pipeline
421
457
  status Check if pipeline is running
422
458
  logs [--lines N] [--follow] View pipeline logs
423
- restart [.prizmkit/plans/bug-fix-list.json] [--env "K=V ..."] Stop + start pipeline
459
+ restart [.prizmkit/plans/bug-fix-list.json] [--mode <mode>] [--critic] [--env "K=V ..."] Stop + start pipeline
424
460
  help Show this help
425
461
 
462
+ Options:
463
+ --mode <lite|standard|full> Override pipeline mode for all bugs
464
+ --critic Enable adversarial critic review for all bugs
465
+ --no-critic Disable adversarial critic review for all bugs
466
+ --env "KEY=VAL ..." Set environment variables
467
+
426
468
  Examples:
427
469
  ./launch-bugfix-daemon.sh start # Start with default .prizmkit/plans/bug-fix-list.json
428
470
  ./launch-bugfix-daemon.sh start my-bugs.json # Start with custom bug list
471
+ ./launch-bugfix-daemon.sh start --mode full # Full mode for complex bugs
472
+ ./launch-bugfix-daemon.sh start --critic # Enable adversarial critic review
429
473
  ./launch-bugfix-daemon.sh start --env "MAX_RETRIES=5"
474
+ ./launch-bugfix-daemon.sh start .prizmkit/plans/bug-fix-list.json --mode full --critic --env "VERBOSE=1"
430
475
  ./launch-bugfix-daemon.sh status # Check if running (JSON on stdout)
431
476
  ./launch-bugfix-daemon.sh logs --follow # Live log tailing
432
477
  ./launch-bugfix-daemon.sh stop # Graceful shutdown
@@ -481,7 +481,7 @@ feature_list_path, state_dir = sys.argv[1], sys.argv[2]
481
481
  fl = load_json(feature_list_path)
482
482
  features = fl.get('features', [])
483
483
  total = len(features)
484
- counts = {'completed': 0, 'in_progress': 0, 'failed': 0, 'pending': 0, 'skipped': 0}
484
+ counts = {'completed': 0, 'in_progress': 0, 'failed': 0, 'pending': 0, 'skipped': 0, 'auto_skipped': 0}
485
485
  for feat in features:
486
486
  fid = feat.get('id', '')
487
487
  sp = os.path.join(state_dir, 'features', fid, 'status.json')
@@ -502,6 +502,8 @@ print(json.dumps({
502
502
  'in_progress': counts['in_progress'],
503
503
  'failed': counts['failed'],
504
504
  'pending': counts['pending'],
505
+ 'skipped': counts['skipped'],
506
+ 'auto_skipped': counts['auto_skipped'],
505
507
  'percent': pct
506
508
  }))
507
509
  " "$feature_list_path" "$STATE_DIR" 2>/dev/null || echo "")
@@ -8,11 +8,11 @@ set -euo pipefail
8
8
  # log consolidation, and lifecycle commands.
9
9
  #
10
10
  # Usage:
11
- # ./launch-refactor-daemon.sh start [.prizmkit/plans/refactor-list.json] [--env "KEY=VAL ..."]
11
+ # ./launch-refactor-daemon.sh start [.prizmkit/plans/refactor-list.json] [--mode <mode>] [--critic] [--env "KEY=VAL ..."]
12
12
  # ./launch-refactor-daemon.sh stop
13
13
  # ./launch-refactor-daemon.sh status
14
14
  # ./launch-refactor-daemon.sh logs [--lines N] [--follow]
15
- # ./launch-refactor-daemon.sh restart [.prizmkit/plans/refactor-list.json] [--env "KEY=VAL ..."]
15
+ # ./launch-refactor-daemon.sh restart [.prizmkit/plans/refactor-list.json] [--mode <mode>] [--critic] [--env "KEY=VAL ..."]
16
16
  #
17
17
  # NOTE:
18
18
  # In AI skill sessions, always use this daemon wrapper.
@@ -93,6 +93,31 @@ cmd_start() {
93
93
  while [[ $# -gt 0 ]]; do
94
94
  case "$1" in
95
95
  --env) shift; env_overrides="${1:-}"; shift ;;
96
+ --mode)
97
+ shift
98
+ if [[ $# -eq 0 ]]; then
99
+ log_error "--mode requires a value (lite|standard|full)"
100
+ exit 1
101
+ fi
102
+ case "$1" in
103
+ lite|standard|full)
104
+ PIPELINE_MODE="$1"
105
+ ;;
106
+ *)
107
+ log_error "Invalid mode: $1 (must be lite, standard, or full)"
108
+ exit 1
109
+ ;;
110
+ esac
111
+ shift
112
+ ;;
113
+ --critic)
114
+ ENABLE_CRITIC=true
115
+ shift
116
+ ;;
117
+ --no-critic)
118
+ ENABLE_CRITIC=false
119
+ shift
120
+ ;;
96
121
  *) refactor_list="$1"; shift ;;
97
122
  esac
98
123
  done
@@ -166,6 +191,9 @@ cmd_start() {
166
191
  echo ""
167
192
  } >> "$LOG_FILE"
168
193
 
194
+ [[ -n "${PIPELINE_MODE:-}" ]] && export PIPELINE_MODE
195
+ [[ -n "${ENABLE_CRITIC:-}" ]] && export ENABLE_CRITIC
196
+
169
197
  if [[ -n "$env_cmd" ]]; then
170
198
  nohup $env_cmd "$RUN_SCRIPT" run "$refactor_list" >> "$LOG_FILE" 2>&1 &
171
199
  else
@@ -174,11 +202,12 @@ cmd_start() {
174
202
  local pipeline_pid=$!
175
203
  disown "$pipeline_pid" 2>/dev/null || true
176
204
 
177
- echo "$pipeline_pid" > "$PID_FILE"
205
+ echo "$pipeline_pid" > "${PID_FILE}.tmp"
206
+ mv "${PID_FILE}.tmp" "$PID_FILE"
178
207
 
208
+ # Write start metadata (atomic)
179
209
  python3 -c "
180
- import json
181
- from datetime import datetime
210
+ import json, os
182
211
  data = {
183
212
  'pid': $pipeline_pid,
184
213
  'pipeline_type': 'refactor',
@@ -187,8 +216,11 @@ data = {
187
216
  'env_overrides': '$env_overrides',
188
217
  'log_file': '$LOG_FILE'
189
218
  }
190
- with open('$STATE_DIR/.pipeline-meta.json', 'w') as f:
219
+ target = os.path.join('$STATE_DIR', '.pipeline-meta.json')
220
+ tmp = target + '.tmp'
221
+ with open(tmp, 'w') as f:
191
222
  json.dump(data, f, indent=2)
223
+ os.replace(tmp, target)
192
224
  " 2>/dev/null || true
193
225
 
194
226
  sleep 2
@@ -234,7 +266,10 @@ cmd_stop() {
234
266
  fi
235
267
 
236
268
  log_info "Stopping refactor pipeline (PID: $pid)..."
237
- kill -TERM "$pid" 2>/dev/null || true
269
+
270
+ # Kill the entire process group to include child processes (claude-internal, etc.)
271
+ # First try SIGTERM to the process group (negative PID)
272
+ kill -TERM -- -"$pid" 2>/dev/null || kill -TERM "$pid" 2>/dev/null || true
238
273
 
239
274
  local waited=0
240
275
  while [[ $waited -lt 30 ]]; do
@@ -245,9 +280,10 @@ cmd_stop() {
245
280
  waited=$((waited + 1))
246
281
  done
247
282
 
283
+ # Force kill if still alive (process group first, then individual)
248
284
  if kill -0 "$pid" 2>/dev/null; then
249
285
  log_warn "Process did not exit after 30s, sending SIGKILL..."
250
- kill -9 "$pid" 2>/dev/null || true
286
+ kill -9 -- -"$pid" 2>/dev/null || kill -9 "$pid" 2>/dev/null || true
251
287
  sleep 1
252
288
  fi
253
289
 
@@ -342,7 +378,7 @@ import json, os
342
378
  bl = json.load(open('$refactor_list_path'))
343
379
  items = bl.get('refactors', [])
344
380
  total = len(items)
345
- counts = {'completed': 0, 'in_progress': 0, 'failed': 0, 'pending': 0, 'needs_info': 0}
381
+ counts = {'completed': 0, 'in_progress': 0, 'failed': 0, 'pending': 0, 'skipped': 0, 'auto_skipped': 0}
346
382
  for item in items:
347
383
  rid = item.get('id', '')
348
384
  sp = os.path.join('$STATE_DIR', 'refactors', rid, 'status.json')
@@ -356,7 +392,7 @@ for item in items:
356
392
  else:
357
393
  counts['pending'] += 1
358
394
  pct = round(counts['completed'] / total * 100, 1) if total > 0 else 0
359
- print(json.dumps({'total': total, 'completed': counts['completed'], 'in_progress': counts['in_progress'], 'failed': counts['failed'], 'pending': counts['pending'], 'needs_info': counts['needs_info'], 'percent': pct}))
395
+ print(json.dumps({'total': total, 'completed': counts['completed'], 'in_progress': counts['in_progress'], 'failed': counts['failed'], 'pending': counts['pending'], 'skipped': counts['skipped'], 'auto_skipped': counts['auto_skipped'], 'percent': pct}))
360
396
  " 2>/dev/null || echo "")
361
397
  fi
362
398
 
@@ -416,18 +452,27 @@ show_help() {
416
452
  Usage: launch-refactor-daemon.sh <command> [options]
417
453
 
418
454
  Commands:
419
- start [.prizmkit/plans/refactor-list.json] [--env "K=V ..."] Start refactor pipeline in background
455
+ start [.prizmkit/plans/refactor-list.json] [--mode <mode>] [--critic] [--env "K=V ..."] Start refactor pipeline in background
420
456
  stop Gracefully stop pipeline
421
457
  status Check if pipeline is running
422
458
  logs [--lines N] [--follow] View pipeline logs
423
- restart [.prizmkit/plans/refactor-list.json] [--env "K=V ..."] Stop + start pipeline
459
+ restart [.prizmkit/plans/refactor-list.json] [--mode <mode>] [--critic] [--env "K=V ..."] Stop + start pipeline
424
460
  help Show this help
425
461
 
462
+ Options:
463
+ --mode <lite|standard|full> Override pipeline mode for all refactors
464
+ --critic Enable adversarial critic review for all refactors
465
+ --no-critic Disable adversarial critic review for all refactors
466
+ --env "KEY=VAL ..." Set environment variables
467
+
426
468
  Examples:
427
469
  ./launch-refactor-daemon.sh start # Start with default .prizmkit/plans/refactor-list.json
428
470
  ./launch-refactor-daemon.sh start my-refactors.json # Start with custom refactor list
471
+ ./launch-refactor-daemon.sh start --mode full # Full mode for complex refactors
472
+ ./launch-refactor-daemon.sh start --critic # Enable adversarial critic review
429
473
  ./launch-refactor-daemon.sh start --env "MAX_RETRIES=5"
430
474
  ./launch-refactor-daemon.sh start --env "STRICT_BEHAVIOR_CHECK=0"
475
+ ./launch-refactor-daemon.sh start .prizmkit/plans/refactor-list.json --mode full --critic --env "VERBOSE=1"
431
476
  ./launch-refactor-daemon.sh status # Check if running (JSON on stdout)
432
477
  ./launch-refactor-daemon.sh logs --follow # Live log tailing
433
478
  ./launch-refactor-daemon.sh stop # Graceful shutdown
@@ -99,7 +99,12 @@ branch_merge() {
99
99
  local remaining_dirty
100
100
  remaining_dirty=$(git -C "$project_root" status --porcelain 2>/dev/null || true)
101
101
  if [[ -n "$remaining_dirty" ]]; then
102
- git -C "$project_root" stash push --include-untracked -m "pipeline-merge-stash" 2>/dev/null && had_stash=true || true
102
+ if git -C "$project_root" stash push --include-untracked -m "pipeline-merge-stash" 2>/dev/null; then
103
+ had_stash=true
104
+ else
105
+ log_warn "git stash failed — uncommitted changes may not be preserved during merge"
106
+ had_stash=false
107
+ fi
103
108
  fi
104
109
 
105
110
  # Step 2: Rebase dev branch onto original to make it fast-forwardable.
@@ -23,6 +23,70 @@ log_warn() { echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*
23
23
  log_error() { echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
24
24
  log_success() { echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
25
25
 
26
+ # ============================================================
27
+ # .env file loading
28
+ # ============================================================
29
+
30
+ # Load .env file if it exists. Does NOT override already-set env vars.
31
+ # Supports: KEY=VALUE, KEY="VALUE", KEY='VALUE', comments (#), empty lines.
32
+ # If the file does not exist, silently continues (no error).
33
+ prizm_load_env() {
34
+ local env_file="${1:-.env}"
35
+ [[ -f "$env_file" ]] || return 0
36
+
37
+ while IFS= read -r line || [[ -n "$line" ]]; do
38
+ # Skip empty lines and comments
39
+ [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
40
+ # Remove inline comments (not inside quotes)
41
+ line="${line%%#*}"
42
+ # Trim whitespace
43
+ line="$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
44
+ [[ -z "$line" ]] && continue
45
+ # Parse KEY=VALUE
46
+ if [[ "$line" =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
47
+ local key="${BASH_REMATCH[1]}"
48
+ local val="${BASH_REMATCH[2]}"
49
+ # Strip surrounding quotes
50
+ val="${val#\"}" ; val="${val%\"}"
51
+ val="${val#\'}" ; val="${val%\'}"
52
+ # Only set if not already defined in environment
53
+ if [[ -z "${!key+x}" ]]; then
54
+ export "$key=$val"
55
+ fi
56
+ fi
57
+ done < "$env_file"
58
+ }
59
+
60
+ # ============================================================
61
+ # Test mode: bootstrap prompt logging
62
+ # ============================================================
63
+
64
+ # Log bootstrap prompt content when PRIZMKIT_ENV=test.
65
+ # Called after prompt generation, before AI CLI session spawn.
66
+ # Usage: prizm_log_bootstrap_prompt <prompt_path> <item_id>
67
+ prizm_log_bootstrap_prompt() {
68
+ local prompt_path="$1"
69
+ local item_id="$2"
70
+
71
+ [[ "${PRIZMKIT_ENV:-}" == "test" ]] || return 0
72
+ [[ -f "$prompt_path" ]] || return 0
73
+
74
+ local lines size
75
+ lines=$(wc -l < "$prompt_path" 2>/dev/null | tr -d ' ')
76
+ size=$(wc -c < "$prompt_path" 2>/dev/null | tr -d ' ')
77
+
78
+ echo ""
79
+ echo -e "${MAGENTA}[TEST]${NC} ════════════════════════════════════════════════════"
80
+ echo -e "${MAGENTA}[TEST]${NC} Bootstrap Prompt for $item_id"
81
+ echo -e "${MAGENTA}[TEST]${NC} Lines: $lines | Size: $((size / 1024))KB"
82
+ echo -e "${MAGENTA}[TEST]${NC} Path: $prompt_path"
83
+ echo -e "${MAGENTA}[TEST]${NC} ════════════════════════════════════════════════════"
84
+ cat "$prompt_path"
85
+ echo ""
86
+ echo -e "${MAGENTA}[TEST]${NC} ════════════════════════ END ═══════════════════════"
87
+ echo ""
88
+ }
89
+
26
90
  # Detect AI CLI + platform.
27
91
  # Priority:
28
92
  # AI_CLI env > .prizmkit/config.json > CODEBUDDY_CLI > auto-detect(cbc/claude) > error
@@ -32,6 +96,13 @@ log_success() { echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"
32
96
  # PLATFORM
33
97
  # PRIZMKIT_PLATFORM
34
98
  prizm_detect_cli_and_platform() {
99
+ # Load .env from project root if it exists (does not override existing env vars)
100
+ local _env_root
101
+ _env_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." 2>/dev/null && pwd)" || true
102
+ if [[ -n "$_env_root" ]]; then
103
+ prizm_load_env "$_env_root/.env"
104
+ fi
105
+
35
106
  local _raw_cli=""
36
107
 
37
108
  if [[ -n "${AI_CLI:-}" ]]; then
@@ -73,7 +73,7 @@ start_heartbeat() {
73
73
  phase=$(python3 -c "
74
74
  import json, sys
75
75
  try:
76
- with open('$progress_json') as f:
76
+ with open(sys.argv[1]) as f:
77
77
  d = json.load(f)
78
78
  parts = []
79
79
  if d.get('current_phase'):
@@ -85,7 +85,7 @@ try:
85
85
  print(' | '.join(parts))
86
86
  except Exception:
87
87
  sys.exit(1)
88
- " 2>/dev/null) && {
88
+ " "$progress_json" 2>/dev/null) && {
89
89
  echo -e " ${status_icon} ${BLUE}[HEARTBEAT]${NC} ${mins}m${secs}s | log: ${size_display} | ${phase}"
90
90
  continue
91
91
  }
@@ -127,15 +127,28 @@ ORIGINAL_BRANCH=$(git -C "$PROJECT_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null
127
127
  # Branch tracking (for cleanup on interrupt)
128
128
  _DEV_BRANCH_NAME=""
129
129
 
130
- log_info "Cleaning $BUG_ID artifacts for full restart..."
131
- python3 "$SCRIPTS_DIR/update-bug-status.py" \
132
- --bug-list "$BUG_LIST" \
133
- --state-dir "$STATE_DIR" \
134
- --bug-id "$BUG_ID" \
135
- --project-root "$PROJECT_ROOT" \
136
- --action clean >/dev/null 2>&1 || {
137
- log_warn "Failed to clean bug artifacts (continuing with fresh session only)"
138
- }
130
+ log_info "Reading retry state for $BUG_ID..."
131
+ RETRY_COUNT=$(python3 -c "
132
+ import json, os
133
+ status_path = os.path.join('$STATE_DIR', 'bugs', '$BUG_ID', 'status.json')
134
+ if os.path.isfile(status_path):
135
+ with open(status_path) as f:
136
+ d = json.load(f)
137
+ print(d.get('retry_count', 0))
138
+ else:
139
+ print(0)
140
+ " 2>/dev/null || echo "0")
141
+ RESUME_PHASE=$(python3 -c "
142
+ import json, os
143
+ status_path = os.path.join('$STATE_DIR', 'bugs', '$BUG_ID', 'status.json')
144
+ if os.path.isfile(status_path):
145
+ with open(status_path) as f:
146
+ d = json.load(f)
147
+ print(d.get('resume_from_phase') or 'null')
148
+ else:
149
+ print('null')
150
+ " 2>/dev/null || echo "null")
151
+ log_info "Retry count: $RETRY_COUNT, Resume phase: $RESUME_PHASE"
139
152
 
140
153
  # ============================================================
141
154
  # Generate bootstrap prompt
@@ -149,15 +162,34 @@ mkdir -p "$SESSION_DIR/logs"
149
162
  BOOTSTRAP_PROMPT="$SESSION_DIR/bootstrap-prompt.md"
150
163
 
151
164
  log_info "Generating bugfix bootstrap prompt..."
152
- python3 "$SCRIPTS_DIR/generate-bugfix-prompt.py" \
153
- --bug-list "$BUG_LIST" \
154
- --bug-id "$BUG_ID" \
155
- --session-id "$SESSION_ID" \
156
- --run-id "$RUN_ID" \
157
- --retry-count 0 \
158
- --resume-phase "null" \
159
- --state-dir "$STATE_DIR" \
160
- --output "$BOOTSTRAP_PROMPT" >/dev/null 2>&1
165
+ GEN_ARGS=(
166
+ --bug-list "$BUG_LIST"
167
+ --bug-id "$BUG_ID"
168
+ --session-id "$SESSION_ID"
169
+ --run-id "$RUN_ID"
170
+ --retry-count "$RETRY_COUNT"
171
+ --resume-phase "$RESUME_PHASE"
172
+ --state-dir "$STATE_DIR"
173
+ --output "$BOOTSTRAP_PROMPT"
174
+ )
175
+
176
+ # Support PIPELINE_MODE env var
177
+ if [[ -n "${PIPELINE_MODE:-}" ]]; then
178
+ GEN_ARGS+=(--mode "$PIPELINE_MODE")
179
+ fi
180
+
181
+ # Support ENABLE_CRITIC env var
182
+ if [[ "${ENABLE_CRITIC:-}" == "true" || "${ENABLE_CRITIC:-}" == "1" ]]; then
183
+ GEN_ARGS+=(--critic "true")
184
+ elif [[ "${ENABLE_CRITIC:-}" == "false" || "${ENABLE_CRITIC:-}" == "0" ]]; then
185
+ GEN_ARGS+=(--critic "false")
186
+ fi
187
+
188
+ GEN_OUTPUT=$(python3 "$SCRIPTS_DIR/generate-bugfix-prompt.py" "${GEN_ARGS[@]}" 2>/dev/null) || {
189
+ log_error "Failed to generate bootstrap prompt"
190
+ exit 1
191
+ }
192
+ BUG_MODEL=$(echo "$GEN_OUTPUT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('model',''))" 2>/dev/null || echo "")
161
193
 
162
194
  # ============================================================
163
195
  # Run single AI CLI session
@@ -178,8 +210,9 @@ echo -e "${BOLD} Retry Bug Fix: $BUG_ID — $BUG_TITLE${NC}"
178
210
  echo -e "${BOLD} Severity: $BUG_SEVERITY${NC}"
179
211
  echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
180
212
  log_info "CLI: $CLI_CMD (platform: $PLATFORM)"
181
- if [[ -n "${MODEL:-}" ]]; then
182
- log_info "Model: $MODEL"
213
+ EFFECTIVE_MODEL="${BUG_MODEL:-${MODEL:-}}"
214
+ if [[ -n "$EFFECTIVE_MODEL" ]]; then
215
+ log_info "Model: $EFFECTIVE_MODEL"
183
216
  else
184
217
  log_info "Model: (CLI default)"
185
218
  fi
@@ -208,14 +241,18 @@ if [[ "$USE_STREAM_JSON" == "true" ]]; then
208
241
  VERBOSE_FLAG="--verbose"
209
242
  fi
210
243
 
211
- # Spawn AI CLI session
244
+ # Spawn AI CLI session — model priority: bug.model > $MODEL env > none
245
+ EFFECTIVE_MODEL="${BUG_MODEL:-${MODEL:-}}"
212
246
  MODEL_FLAG=""
213
- if [[ -n "${MODEL:-}" ]]; then
214
- MODEL_FLAG="--model $MODEL"
247
+ if [[ -n "$EFFECTIVE_MODEL" ]]; then
248
+ MODEL_FLAG="--model $EFFECTIVE_MODEL"
215
249
  fi
216
250
 
217
251
  unset CLAUDECODE 2>/dev/null || true
218
252
 
253
+ # Log bootstrap prompt in test mode
254
+ prizm_log_bootstrap_prompt "$BOOTSTRAP_PROMPT" "$BUG_ID"
255
+
219
256
  case "$CLI_CMD" in
220
257
  *claude*)
221
258
  # Claude Code: prompt via -p argument, --dangerously-skip-permissions for auto-accept
@@ -119,16 +119,28 @@ title = re.sub(r'-+', '-', title).strip('-') or 'feature'
119
119
  print(f'{fid}-{title}')
120
120
  " 2>/dev/null)
121
121
 
122
- log_info "Cleaning $FEATURE_ID artifacts for full restart..."
123
- python3 "$SCRIPTS_DIR/update-feature-status.py" \
124
- --feature-list "$FEATURE_LIST" \
125
- --state-dir "$STATE_DIR" \
126
- --feature-id "$FEATURE_ID" \
127
- --feature-slug "$FEATURE_SLUG" \
128
- --project-root "$PROJECT_ROOT" \
129
- --action clean >/dev/null 2>&1 || {
130
- log_warn "Failed to clean feature artifacts (continuing with fresh session only)"
131
- }
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"
132
144
 
133
145
  # ============================================================
134
146
  # Generate bootstrap prompt
@@ -147,12 +159,17 @@ GEN_ARGS=(
147
159
  --feature-id "$FEATURE_ID"
148
160
  --session-id "$SESSION_ID"
149
161
  --run-id "$RUN_ID"
150
- --retry-count 0
151
- --resume-phase "null"
162
+ --retry-count "$RETRY_COUNT"
163
+ --resume-phase "$RESUME_PHASE"
152
164
  --state-dir "$STATE_DIR"
153
165
  --output "$BOOTSTRAP_PROMPT"
154
166
  )
155
167
 
168
+ # Support PIPELINE_MODE env var
169
+ if [[ -n "${PIPELINE_MODE:-}" ]]; then
170
+ GEN_ARGS+=(--mode "$PIPELINE_MODE")
171
+ fi
172
+
156
173
  # Support ENABLE_CRITIC env var
157
174
  if [[ "${ENABLE_CRITIC:-}" == "true" || "${ENABLE_CRITIC:-}" == "1" ]]; then
158
175
  GEN_ARGS+=(--critic "true")
@@ -233,6 +250,9 @@ fi
233
250
 
234
251
  unset CLAUDECODE 2>/dev/null || true
235
252
 
253
+ # Log bootstrap prompt in test mode
254
+ prizm_log_bootstrap_prompt "$BOOTSTRAP_PROMPT" "$FEATURE_ID"
255
+
236
256
  case "$CLI_CMD" in
237
257
  *claude*)
238
258
  # Claude Code: prompt via -p argument, --dangerously-skip-permissions for auto-accept
@@ -367,6 +387,21 @@ if [[ "$SESSION_STATUS" == "success" ]]; then
367
387
  fi
368
388
  fi
369
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
+
370
405
  # Update feature status
371
406
  python3 "$SCRIPTS_DIR/update-feature-status.py" \
372
407
  --feature-list "$FEATURE_LIST" \