@zachjxyz/moxie 0.4.0 → 0.4.2
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 +1 -1
- package/lib/agents.sh +76 -1
- package/lib/phases.sh +30 -3
- package/package.json +1 -1
package/bin/moxie
CHANGED
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.
|
|
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
|
@@ -861,7 +861,7 @@ cmd_run() {
|
|
|
861
861
|
trap 'rm -f "$MOXIE_DIR/moxie.pid"' EXIT
|
|
862
862
|
|
|
863
863
|
if [ "$MOXIE_PLATFORM" = "darwin" ]; then
|
|
864
|
-
caffeinate -d -i -s bash -c "
|
|
864
|
+
caffeinate -d -i -m -s bash -c "
|
|
865
865
|
set -euo pipefail; cd '$(pwd)'
|
|
866
866
|
export DRY_RUN=0 MOXIE_ROOT='$MOXIE_ROOT' MOXIE_LIB='$MOXIE_LIB'
|
|
867
867
|
source '$MOXIE_LIB/platform.sh'; source '$MOXIE_LIB/core.sh'
|
|
@@ -949,7 +949,7 @@ cmd_start() {
|
|
|
949
949
|
"
|
|
950
950
|
|
|
951
951
|
if [ "$MOXIE_PLATFORM" = "darwin" ]; then
|
|
952
|
-
nohup caffeinate -d -i -s bash -c "$_bg_script" > "$log_file" 2>&1 &
|
|
952
|
+
nohup caffeinate -d -i -m -s bash -c "$_bg_script" > "$log_file" 2>&1 &
|
|
953
953
|
elif [ "$MOXIE_PLATFORM" = "linux" ] && command -v systemd-inhibit &>/dev/null; then
|
|
954
954
|
nohup systemd-inhibit --what=idle:sleep --who=moxie --why="moxie pipeline" \
|
|
955
955
|
bash -c "$_bg_script" > "$log_file" 2>&1 &
|
|
@@ -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
|
|
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.
|
|
3
|
+
"version": "0.4.2",
|
|
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"
|