prizmkit 1.1.93 → 1.1.94

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.1.93",
3
- "bundledAt": "2026-07-02T17:03:22.377Z",
4
- "bundledFrom": "dc86f56"
2
+ "frameworkVersion": "1.1.94",
3
+ "bundledAt": "2026-07-02T17:32:35.248Z",
4
+ "bundledFrom": "3cd68b5"
5
5
  }
@@ -44,7 +44,6 @@ start_heartbeat() {
44
44
  local prev_max_size=0
45
45
  local prev_child_activity_signature=""
46
46
  local prev_progress_signature=""
47
- local prev_error_loop_signature=""
48
47
  local stale_seconds=0
49
48
  local stale_reason="stale_session"
50
49
  while kill -0 "$cli_pid" 2>/dev/null; do
@@ -197,64 +196,24 @@ PY
197
196
  fi
198
197
  fi
199
198
 
200
- # Check for error-loop: agent is actively producing output but results are
201
- # all read-offset errors or wasted calls. This is a stuck agent that appears
202
- # "active" by log growth but is accomplishing nothing. Only a newly advancing
203
- # error signature counts; stale historical errors must not turn later normal
204
- # output into a stale kill.
205
- local error_loop_detected=false
206
- local error_loop_signature=""
207
- if [[ $effective_stale_kill_threshold -gt 0 && $growth -gt 0 && -f "$progress_json" ]]; then
208
- local error_loop_flag
209
- error_loop_flag=$(python3 - "$progress_json" <<'PY' 2>/dev/null || true
210
- import json, sys
211
- try:
212
- with open(sys.argv[1], encoding="utf-8") as fh:
213
- progress = json.load(fh)
214
- except Exception:
215
- raise SystemExit(0)
216
- errors = progress.get("errors", [])
217
- if isinstance(errors, list) and len(errors) >= 5:
218
- recent = errors[-5:]
219
- if all(isinstance(e, dict) and e.get("type") in ("read_offset_overflow", "wasted_call") for e in recent):
220
- print(json.dumps(recent, sort_keys=True, separators=(",", ":")))
221
- PY
222
- )
223
- if [[ -n "$error_loop_flag" ]]; then
224
- error_loop_signature="$error_loop_flag"
225
- if [[ -n "$prev_error_loop_signature" && "$error_loop_signature" != "$prev_error_loop_signature" ]]; then
226
- error_loop_detected=true
227
- fi
228
- fi
229
- fi
230
- prev_error_loop_signature="$error_loop_signature"
231
-
232
199
  # Track progress staleness. Parent sessions can sit in a wait/polling
233
200
  # tool while child transcripts or structured progress counters keep
234
201
  # advancing, so both child activity and progress.json state changes
235
- # count as progress. Error loops bypass normal growth-as-progress
236
- # because the log is only growing with repeated failed reads or wasted
237
- # calls.
202
+ # count as progress.
238
203
  #
239
204
  # When the main session log has been truncated (e.g. by subagent stdout
240
205
  # redirection severing the file descriptor), use structured progress and
241
206
  # child activity as the primary progress signals — the parent process is
242
207
  # still running and children may still be producing output.
243
- if [[ "$error_loop_detected" == "true" ]]; then
244
- stale_reason="error_loop"
245
- stale_seconds=$effective_stale_kill_threshold
246
- elif [[ "$log_truncated" == "true" ]]; then
247
- stale_reason="stale_session"
208
+ if [[ "$log_truncated" == "true" ]]; then
248
209
  if [[ $progress_advanced -gt 0 || $child_growth -gt 0 ]]; then
249
210
  stale_seconds=0
250
211
  else
251
212
  stale_seconds=$((stale_seconds + heartbeat_interval))
252
213
  fi
253
214
  elif [[ $growth -le 0 && $child_growth -eq 0 && $progress_advanced -eq 0 ]]; then
254
- stale_reason="stale_session"
255
215
  stale_seconds=$((stale_seconds + heartbeat_interval))
256
216
  else
257
- stale_reason="stale_session"
258
217
  stale_seconds=0
259
218
  fi
260
219
 
@@ -338,13 +297,8 @@ PY
338
297
  # stale window to surface stuck agents promptly.
339
298
  if [[ $effective_stale_kill_threshold -gt 0 && $stale_seconds -ge $effective_stale_kill_threshold ]]; then
340
299
  local stale_mins=$((stale_seconds / 60))
341
- if [[ "$stale_reason" == "error_loop" ]]; then
342
- echo -e " ${RED}[HEARTBEAT]${NC} ${mins}m${secs}s | log: ${size_display} | ${RED}STALE-KILL: repeated read-offset/wasted-call error loop (threshold: ${effective_stale_kill_threshold}s)${NC}"
343
- echo -e " ${RED}[HEARTBEAT]${NC} Killing AI CLI process $cli_pid (error loop)..."
344
- else
345
- echo -e " ${RED}[HEARTBEAT]${NC} ${mins}m${secs}s | log: ${size_display} | ${RED}STALE-KILL: no progress for ${stale_mins}m (threshold: ${effective_stale_kill_threshold}s)${NC}"
346
- echo -e " ${RED}[HEARTBEAT]${NC} Killing AI CLI process $cli_pid (stale session)..."
347
- fi
300
+ echo -e " ${RED}[HEARTBEAT]${NC} ${mins}m${secs}s | log: ${size_display} | ${RED}STALE-KILL: no progress for ${stale_mins}m (threshold: ${effective_stale_kill_threshold}s)${NC}"
301
+ echo -e " ${RED}[HEARTBEAT]${NC} Killing AI CLI process $cli_pid (stale session)..."
348
302
  # Write the marker before killing. Some CLIs exit quickly, and the
349
303
  # parent runner may stop this heartbeat process immediately after
350
304
  # wait(1) returns.
@@ -144,11 +144,7 @@ except Exception:
144
144
  pass
145
145
  PY
146
146
  )
147
- if [[ "$stale_kill_reason" == "error_loop" ]]; then
148
- log_warn "Session was killed by heartbeat monitor due to repeated read-offset/wasted-call errors"
149
- else
150
- log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
151
- fi
147
+ log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
152
148
  fi
153
149
 
154
150
  local was_infra_error=false
@@ -179,11 +175,7 @@ PY
179
175
  log_warn "Infrastructure errors are retried without consuming code retry budget"
180
176
  session_status="infra_error"
181
177
  elif [[ "$was_stale_killed" == true ]]; then
182
- if [[ "$stale_kill_reason" == "error_loop" ]]; then
183
- log_warn "Session killed due to repeated read-offset/wasted-call error loop"
184
- else
185
- log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
186
- fi
178
+ log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
187
179
  log_warn "Stale-killed sessions are treated as failed; dev branch is preserved for inspection"
188
180
  session_status="crashed"
189
181
  elif [[ $exit_code -ne 0 ]]; then
@@ -155,11 +155,7 @@ except Exception:
155
155
  pass
156
156
  PY
157
157
  )
158
- if [[ "$stale_kill_reason" == "error_loop" ]]; then
159
- log_warn "Session was killed by heartbeat monitor due to repeated read-offset/wasted-call errors"
160
- else
161
- log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
162
- fi
158
+ log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
163
159
  fi
164
160
 
165
161
  local was_infra_error=false
@@ -213,11 +209,7 @@ PY
213
209
  log_warn "Infrastructure errors are retried without consuming code retry budget"
214
210
  session_status="infra_error"
215
211
  elif [[ "$was_stale_killed" == true ]]; then
216
- if [[ "$stale_kill_reason" == "error_loop" ]]; then
217
- log_warn "Session killed due to repeated read-offset/wasted-call error loop"
218
- else
219
- log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
220
- fi
212
+ log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
221
213
  log_warn "Heartbeat-killed sessions are treated as failed; dev branch is preserved for inspection"
222
214
  session_status="crashed"
223
215
  elif [[ $exit_code -ne 0 ]]; then
@@ -145,11 +145,7 @@ except Exception:
145
145
  pass
146
146
  PY
147
147
  )
148
- if [[ "$stale_kill_reason" == "error_loop" ]]; then
149
- log_warn "Session was killed by heartbeat monitor due to repeated read-offset/wasted-call errors"
150
- else
151
- log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
152
- fi
148
+ log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
153
149
  fi
154
150
 
155
151
  local was_infra_error=false
@@ -180,11 +176,7 @@ PY
180
176
  log_warn "Infrastructure errors are retried without consuming code retry budget"
181
177
  session_status="infra_error"
182
178
  elif [[ "$was_stale_killed" == true ]]; then
183
- if [[ "$stale_kill_reason" == "error_loop" ]]; then
184
- log_warn "Session killed due to repeated read-offset/wasted-call error loop"
185
- else
186
- log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
187
- fi
179
+ log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
188
180
  log_warn "Stale-killed sessions are treated as failed; dev branch is preserved for inspection"
189
181
  session_status="crashed"
190
182
  elif [[ $exit_code -ne 0 ]]; then
@@ -291,12 +291,12 @@ function Invoke-PrizmPipeline {
291
291
  }
292
292
 
293
293
  function Write-PrizmStaleKillMarker {
294
- param([string]$MarkerPath, [int]$StaleSeconds, [int]$Threshold, [string]$Reason = 'stale_session')
294
+ param([string]$MarkerPath, [int]$StaleSeconds, [int]$Threshold)
295
295
  $markerDir = Split-Path $MarkerPath -Parent
296
296
  if ($markerDir) { New-Item -ItemType Directory -Force -Path $markerDir | Out-Null }
297
297
  [ordered]@{
298
298
  killed_at = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
299
- reason = $Reason
299
+ reason = 'stale_session'
300
300
  stale_seconds = $StaleSeconds
301
301
  threshold = $Threshold
302
302
  } | ConvertTo-Json -Compress | Set-Content -Path $MarkerPath -Encoding UTF8
@@ -726,11 +726,9 @@ function Invoke-PrizmPipeline {
726
726
 
727
727
  $elapsedSeconds = 0
728
728
  $staleSeconds = 0
729
- $staleReason = 'stale_session'
730
729
  $previousLogSize = 0
731
730
  $previousProgressSignature = ''
732
731
  $previousChildActivitySignature = ''
733
- $previousErrorLoopSignature = ''
734
732
  $staleKillMarker = Join-Path $logsDir 'stale-kill.json'
735
733
  $wasStaleKilled = $false
736
734
  while ($true) {
@@ -755,42 +753,9 @@ function Invoke-PrizmPipeline {
755
753
 
756
754
  $effectiveStaleKillThreshold = Get-PrizmEffectiveStaleKillThreshold -ProgressFile $progressJson -BaseThreshold $staleKillThreshold
757
755
 
758
- # Check for error-loop: agent is actively producing output but results are
759
- # all read-offset errors or wasted calls. Only a newly advancing error
760
- # signature counts; stale historical errors must not turn later normal output
761
- # into a stale kill.
762
- $errorLoopDetected = $false
763
- $errorLoopSignature = ''
764
- if ($effectiveStaleKillThreshold -gt 0 -and $growth -gt 0 -and (Test-Path $progressJson)) {
765
- try {
766
- $progress = Get-Content $progressJson -Raw | ConvertFrom-Json
767
- $errors = $progress.errors
768
- if ($errors -is [array] -and $errors.Count -ge 5) {
769
- $recent = $errors[-5..-1]
770
- $allBad = ($recent | Where-Object {
771
- $_.type -in @("read_offset_overflow", "wasted_call")
772
- }).Count -eq 5
773
- if ($allBad) {
774
- $errorLoopSignature = ($recent | ConvertTo-Json -Compress)
775
- if ($previousErrorLoopSignature -and $errorLoopSignature -ne $previousErrorLoopSignature) {
776
- $errorLoopDetected = $true
777
- }
778
- }
779
- }
780
- } catch {
781
- # Ignore JSON parse errors — progress file may be incomplete or malformed
782
- }
783
- }
784
- $previousErrorLoopSignature = $errorLoopSignature
785
-
786
- if ($errorLoopDetected) {
787
- $staleReason = 'error_loop'
788
- $staleSeconds = $effectiveStaleKillThreshold
789
- } elseif ($growth -gt 0 -or $childAdvanced -or $progressAdvanced) {
790
- $staleReason = 'stale_session'
756
+ if ($growth -gt 0 -or $childAdvanced -or $progressAdvanced) {
791
757
  $staleSeconds = 0
792
758
  } else {
793
- $staleReason = 'stale_session'
794
759
  $staleSeconds += $heartbeatInterval
795
760
  }
796
761
 
@@ -807,12 +772,8 @@ function Invoke-PrizmPipeline {
807
772
  }
808
773
  if ($effectiveStaleKillThreshold -gt 0 -and $staleSeconds -ge $effectiveStaleKillThreshold) {
809
774
  $wasStaleKilled = $true
810
- if ($staleReason -eq 'error_loop') {
811
- Write-PrizmWarn "Session stale-killed due to repeated read-offset/wasted-call error loop"
812
- } else {
813
- Write-PrizmWarn "Session stale-killed (no progress for ${effectiveStaleKillThreshold}s)"
814
- }
815
- Write-PrizmStaleKillMarker $staleKillMarker $staleSeconds $effectiveStaleKillThreshold $staleReason
775
+ Write-PrizmWarn "Session stale-killed (no progress for ${effectiveStaleKillThreshold}s)"
776
+ Write-PrizmStaleKillMarker $staleKillMarker $staleSeconds $effectiveStaleKillThreshold
816
777
  Stop-PrizmSessionProcess $pidPath
817
778
  if ($staleKillGraceSeconds -gt 0) { Start-Sleep -Seconds $staleKillGraceSeconds }
818
779
  break
@@ -866,11 +827,7 @@ function Invoke-PrizmPipeline {
866
827
  Write-PrizmWarn "AI session failed due to AI CLI/provider infrastructure error"
867
828
  Write-PrizmWarn "Infrastructure errors are retried without consuming code retry budget"
868
829
  } elseif ($wasStaleKilled -or (Test-Path $staleKillMarker)) {
869
- if ($staleKillReason -eq 'error_loop') {
870
- Write-PrizmWarn "Session was killed by heartbeat monitor due to repeated read-offset/wasted-call errors"
871
- } else {
872
- Write-PrizmWarn "Session was stale-killed by heartbeat monitor (no progress for too long)"
873
- }
830
+ Write-PrizmWarn "Session was stale-killed by heartbeat monitor (no progress for too long)"
874
831
  Write-PrizmWarn "Heartbeat-killed sessions are treated as failed; dev branch is preserved for inspection"
875
832
  } elseif ($exitCode -ne 0) {
876
833
  Write-PrizmWarn "AI session exited with code $exitCode"
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.93",
2
+ "version": "1.1.94",
3
3
  "skills": {
4
4
  "prizm-kit": {
5
5
  "description": "Full-lifecycle dev toolkit. Covers spec-driven development, Prizm context docs, code quality, debugging, deployment, and knowledge management.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.1.93",
3
+ "version": "1.1.94",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {