@zachjxyz/moxie 0.4.0 → 0.4.1

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/bin/moxie CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  set -euo pipefail
18
18
 
19
- MOXIE_VERSION="0.4.0"
19
+ MOXIE_VERSION="0.4.1"
20
20
  # Resolve symlinks (npm installs bin as a symlink)
21
21
  _self="$0"
22
22
  while [ -L "$_self" ]; do
package/lib/agents.sh CHANGED
@@ -344,6 +344,45 @@ _init_agent_health() {
344
344
  AGENT_FAIL_STREAK+=(0)
345
345
  AGENT_DEGRADED+=(0)
346
346
  done
347
+
348
+ # Restore persisted degradation from previous phases
349
+ local deg_file="$MOXIE_DIR/degraded.json"
350
+ if [ -f "$deg_file" ]; then
351
+ for i in "${!AGENT_NAMES[@]}"; do
352
+ local name="${AGENT_NAMES[$i]}"
353
+ local is_deg
354
+ is_deg=$(python3 -c "
355
+ import json
356
+ with open('$deg_file') as f:
357
+ d = json.load(f)
358
+ print('1' if d.get('$name', False) else '0')
359
+ " 2>/dev/null)
360
+ if [ "$is_deg" = "1" ]; then
361
+ AGENT_DEGRADED[$i]=1
362
+ echo " [DEGRADED] $name — persisted from previous phase"
363
+ fi
364
+ done
365
+ fi
366
+ }
367
+
368
+ # Persist degradation state to disk (called after degrading an agent)
369
+ _save_degraded() {
370
+ local deg_file="$MOXIE_DIR/degraded.json"
371
+ python3 -c "
372
+ import json
373
+ existing = {}
374
+ try:
375
+ with open('$deg_file') as f:
376
+ existing = json.load(f)
377
+ except: pass
378
+ names = '${AGENT_NAMES[*]}'.split()
379
+ for i, name in enumerate(names):
380
+ degraded_flags = '${AGENT_DEGRADED[*]}'.split()
381
+ if i < len(degraded_flags) and degraded_flags[i] == '1':
382
+ existing[name] = True
383
+ with open('$deg_file', 'w') as f:
384
+ json.dump(existing, f, indent=2)
385
+ " 2>/dev/null
347
386
  }
348
387
 
349
388
  # Returns 0 if the agent is degraded, 1 otherwise.
@@ -394,6 +433,7 @@ _record_turn_health() {
394
433
 
395
434
  if [ "$streak" -ge "$AGENT_DEGRADE_THRESHOLD" ]; then
396
435
  AGENT_DEGRADED[$idx]=1
436
+ _save_degraded
397
437
  echo " [DEGRADED] $name failed $streak consecutive turns — removing from rotation"
398
438
  echo " (possible quota exhaustion, auth failure, or CLI crash)"
399
439
 
@@ -404,10 +444,24 @@ _record_turn_health() {
404
444
  done
405
445
 
406
446
  if [ "$healthy" -lt 2 ]; then
447
+ echo ""
407
448
  echo ""
408
449
  echo " FATAL: Only $healthy healthy agent(s) remaining."
409
450
  echo " moxie requires at least 2 agents for cross-model verification."
410
- echo " Pipeline cannot continue. Stopping."
451
+ echo " Pipeline cannot continue."
452
+ echo ""
453
+ echo " Degraded agents:"
454
+ for j in "${!AGENT_NAMES[@]}"; do
455
+ if [ "${AGENT_DEGRADED[$j]}" = "1" ]; then
456
+ echo " - ${AGENT_NAMES[$j]}"
457
+ fi
458
+ done
459
+ echo ""
460
+ echo " To resume later (e.g., when a provider recovers):"
461
+ echo " rm .moxie/degraded.json && moxie start"
462
+ echo ""
463
+ echo " To start fresh with different agents:"
464
+ echo " rm -rf .moxie && moxie init"
411
465
  return 2
412
466
  fi
413
467
  else
@@ -419,6 +473,27 @@ _record_turn_health() {
419
473
  fi
420
474
  }
421
475
 
476
+ # Force-record a failed turn (used when ledger wasn't updated despite output)
477
+ _force_fail_health() {
478
+ local name="$1"
479
+ local idx=-1
480
+ for i in "${!AGENT_NAMES[@]}"; do
481
+ [ "${AGENT_NAMES[$i]}" = "$name" ] && idx=$i && break
482
+ done
483
+ [ "$idx" = "-1" ] && return
484
+ [ "${AGENT_DEGRADED[$idx]}" = "1" ] && return
485
+
486
+ AGENT_FAIL_STREAK[$idx]=$(( ${AGENT_FAIL_STREAK[$idx]} + 1 ))
487
+ local streak=${AGENT_FAIL_STREAK[$idx]}
488
+
489
+ if [ "$streak" -ge "$AGENT_DEGRADE_THRESHOLD" ]; then
490
+ AGENT_DEGRADED[$idx]=1
491
+ _save_degraded
492
+ echo " [DEGRADED] $name failed $streak consecutive turns — removing from rotation"
493
+ echo " (agent did not update ledger despite running)"
494
+ fi
495
+ }
496
+
422
497
  # Count healthy (non-degraded) agents.
423
498
  count_healthy_agents() {
424
499
  local healthy=0
package/lib/phases.sh CHANGED
@@ -1318,15 +1318,42 @@ with open('$prompt_file', 'w') as f:
1318
1318
  f.write(content)
1319
1319
  " 2>/dev/null
1320
1320
 
1321
+ # Snapshot ledger mtime before dispatch to detect wasted turns
1322
+ local ledger_mtime_before
1323
+ ledger_mtime_before=$(stat_mtime "$ledger")
1324
+
1321
1325
  # Run
1322
1326
  dispatch_logged "$current" "$prompt_file" "$turn_timeout" "$log_dir" "$round" "$csv" "$phase"
1323
1327
  local dispatch_rc=$?
1324
1328
  rm -f "$prompt_file"
1325
1329
 
1330
+ # Check if the agent actually updated the ledger (productive turn)
1331
+ local ledger_mtime_after
1332
+ ledger_mtime_after=$(stat_mtime "$ledger")
1333
+ if [ "$ledger_mtime_before" = "$ledger_mtime_after" ]; then
1334
+ echo " [WARN] $current did not update the ledger — wasted turn"
1335
+ # Override health check: this is a failure regardless of log size
1336
+ _force_fail_health "$current"
1337
+ fi
1338
+
1326
1339
  # If _record_turn_health returned 2 (fatal: < 2 agents remaining), stop
1327
1340
  if [ "$dispatch_rc" = "2" ] || [ "$(count_healthy_agents)" -lt 2 ]; then
1341
+ echo ""
1328
1342
  echo ""
1329
1343
  echo "FATAL: Fewer than 2 healthy agents remaining. Pipeline cannot continue."
1344
+ echo ""
1345
+ echo " Degraded agents:"
1346
+ for _j in "${!AGENT_NAMES[@]}"; do
1347
+ if [ "${AGENT_DEGRADED[$_j]}" = "1" ]; then
1348
+ echo " - ${AGENT_NAMES[$_j]}"
1349
+ fi
1350
+ done
1351
+ echo ""
1352
+ echo " To resume later (e.g., when a provider recovers):"
1353
+ echo " rm .moxie/degraded.json && moxie start"
1354
+ echo ""
1355
+ echo " To start fresh with different agents:"
1356
+ echo " rm -rf .moxie && moxie init"
1330
1357
  _show_quorum "$ledger"
1331
1358
  return 1
1332
1359
  fi
@@ -1400,7 +1427,7 @@ with open('$prompt_file', 'w') as f:
1400
1427
  _show_quorum "$ledger"
1401
1428
  echo ""
1402
1429
  show_phase_tokens "$csv"
1403
- return 1
1430
+ return 0
1404
1431
  }
1405
1432
 
1406
1433
  _show_quorum() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zachjxyz/moxie",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Run multiple AI coding agents through spec-driven phases with quorum convergence. Supports CLI agents (Claude, Codex, Qwen, Aider, Goose, Amp, Cline, Roo) and Vercel AI Gateway models.",
5
5
  "bin": {
6
6
  "moxie": "bin/moxie"