claude-multiacc 1.0.15 → 1.0.16
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/claude +50 -2
- package/package.json +1 -1
- package/tests/run-tests.sh +18 -0
package/bin/claude
CHANGED
|
@@ -475,6 +475,48 @@ client_limit_scan() { # $1 acct dir
|
|
|
475
475
|
return 1
|
|
476
476
|
}
|
|
477
477
|
|
|
478
|
+
# A TUI auth failure cannot use the -p retry path because the client owns the terminal.
|
|
479
|
+
# Harvest the same account-owned transcripts used for quota detection so the next launch
|
|
480
|
+
# parks a rejected setup-token instead of selecting it again.
|
|
481
|
+
client_auth_scan() { # $1 acct dir
|
|
482
|
+
local idx="$1/.sessions-index" ln id claim p line ts ck ak read_n=0 i
|
|
483
|
+
local ids=() claims=()
|
|
484
|
+
[ -f "$idx" ] || return 1
|
|
485
|
+
while IFS= read -r ln; do
|
|
486
|
+
id="${ln%% *}"; claim=""
|
|
487
|
+
case "$ln" in *' '*) claim="${ln#* }" ;; esac
|
|
488
|
+
sess_id_ok "$id" && { ids+=("$id"); claims+=("$claim"); }
|
|
489
|
+
done < "$idx"
|
|
490
|
+
i=$(( ${#ids[@]} - 1 ))
|
|
491
|
+
while [ "$i" -ge 0 ] && [ "$read_n" -lt "$QUOTA_SCAN_MAX_FILES" ]; do
|
|
492
|
+
id="${ids[$i]}"; claim="${claims[$i]}"; i=$((i - 1)); read_n=$((read_n + 1))
|
|
493
|
+
sess_transcript "$1" "$id" || continue
|
|
494
|
+
p="$SESS_TRANSCRIPT"
|
|
495
|
+
[ $((now - $(file_mtime "$p"))) -le "$QUOTA_SCAN_MAX_AGE" ] || continue
|
|
496
|
+
line="$(tail -c "$QUOTA_SCAN_BYTES" "$p" 2>/dev/null \
|
|
497
|
+
| LC_ALL=C grep -a '"error"[[:space:]]*:[[:space:]]*"authentication_failed"' | tail -1)"
|
|
498
|
+
[ -n "$line" ] || continue
|
|
499
|
+
[ -n "$claim" ] || continue
|
|
500
|
+
ts="$(printf '%s' "$line" | LC_ALL=C sed -n 's/.*"timestamp"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')"
|
|
501
|
+
ck="$(iso_key "$ts")"; ak="$(iso_key "$claim")"
|
|
502
|
+
num_ok "$ck" || continue; num_ok "$ak" || continue
|
|
503
|
+
[ "$ck" -lt "$ak" ] && continue
|
|
504
|
+
claim_conflicted "$1" "$id" "$claim" && continue
|
|
505
|
+
return 0
|
|
506
|
+
done
|
|
507
|
+
return 1
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
mark_client_auth_dead() { # $1 acct dir
|
|
511
|
+
local soft=$((now + 3600)) marked
|
|
512
|
+
marked="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
513
|
+
{ echo "$now"; echo "reason=auth-error soft_until=$soft marked_at=$marked" \
|
|
514
|
+
"detail=client session failed to authenticate"; } \
|
|
515
|
+
2>/dev/null > "$1/.expired.$$" && mv -f "$1/.expired.$$" "$1/.expired" 2>/dev/null \
|
|
516
|
+
|| rm -f "$1/.expired.$$" 2>/dev/null || true
|
|
517
|
+
sel_log "$(basename "$1") parked (auth-error until $soft) — client-reported"
|
|
518
|
+
}
|
|
519
|
+
|
|
478
520
|
mark_client_limit() { # $1 acct dir, $2 reset epoch, $3 rate limit type
|
|
479
521
|
local m="$1/.limited" cur=""
|
|
480
522
|
# Never shorten a marker that already reaches further out (a weekly park must
|
|
@@ -507,11 +549,11 @@ sel_capture_session() { # $1 acct dir
|
|
|
507
549
|
# stops the moment the run it is watching is gone.
|
|
508
550
|
trap '' INT HUP TERM QUIT
|
|
509
551
|
i=0
|
|
510
|
-
while [ "$i" -lt
|
|
552
|
+
while [ "$i" -lt 600 ]; do
|
|
511
553
|
kill -0 "$pid" 2>/dev/null || break
|
|
512
554
|
sess_index_refresh "$d"
|
|
513
555
|
[ -f "$d/sessions/$pid.json" ] && break
|
|
514
|
-
sleep
|
|
556
|
+
sleep 0.1
|
|
515
557
|
i=$((i + 1))
|
|
516
558
|
done
|
|
517
559
|
sess_index_refresh "$d"
|
|
@@ -638,6 +680,12 @@ for d in "$ACC_ROOT"/acct-*; do
|
|
|
638
680
|
fi
|
|
639
681
|
valid+=("$d")
|
|
640
682
|
sess_index_refresh "$d"
|
|
683
|
+
if client_auth_scan "$d"; then
|
|
684
|
+
mark_client_auth_dead "$d"
|
|
685
|
+
valid=("${valid[@]:0:${#valid[@]}-1}")
|
|
686
|
+
expired+=("$d")
|
|
687
|
+
continue
|
|
688
|
+
fi
|
|
641
689
|
marker_active "$d" && continue
|
|
642
690
|
# The account's own records are consulted BEFORE telemetry: what the server told a real
|
|
643
691
|
# call is first-hand and carries the real reset, while limits.json can be days stale —
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-multiacc",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"description": "Multi-account addon for Claude Code and OpenAI Codex CLI: every claude / claude -p and every codex / codex exec runs under a randomly-picked subscription account with the most usage headroom. Mirrors to a deploy server. No API keys.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/tests/run-tests.sh
CHANGED
|
@@ -383,6 +383,24 @@ grep -q "all-expired: falling back" "$ACC/selection.log" \
|
|
|
383
383
|
printf '%s' "$HEALTHY_CREDS" > "$ACC/acct-01/.credentials.json"
|
|
384
384
|
printf '%s' "$HEALTHY_CREDS" > "$ACC/acct-02/.credentials.json"
|
|
385
385
|
|
|
386
|
+
# A short interactive TUI can report auth failure and exit before the -p retry path can
|
|
387
|
+
# inspect stderr. Its account-owned transcript must park that setup-token on the next run.
|
|
388
|
+
auth_sid="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
|
389
|
+
mkdir -p "$ACC/acct-01/projects/auth-regression"
|
|
390
|
+
printf '%s %s\n' "$auth_sid" '2020-01-01T00:00:00Z' > "$ACC/acct-01/.sessions-index"
|
|
391
|
+
auth_line='{"timestamp":"2026-08-22T20:27:29.985Z","error":"authentication_failed",'
|
|
392
|
+
auth_line="$auth_line\"session_id\":\"$auth_sid\"}"
|
|
393
|
+
printf '%s\n' "$auth_line" \
|
|
394
|
+
> "$ACC/acct-01/projects/auth-regression/$auth_sid.jsonl"
|
|
395
|
+
out="$(claude 2>&1)"
|
|
396
|
+
check "TUI transcript auth failure excludes rejected account" "CFG=acct-02" "$out"
|
|
397
|
+
grep -q 'reason=auth-error' "$ACC/acct-01/.expired" 2>/dev/null \
|
|
398
|
+
&& t_ok "TUI transcript auth failure writes .expired" \
|
|
399
|
+
|| t_fail "TUI transcript auth marker" "no auth-error marker"
|
|
400
|
+
rm -f "$ACC/acct-01/.expired" "$ACC/acct-01/.sessions-index" \
|
|
401
|
+
"$ACC/acct-01/projects/auth-regression/$auth_sid.jsonl"
|
|
402
|
+
rmdir "$ACC/acct-01/projects/auth-regression" 2>/dev/null || true
|
|
403
|
+
|
|
386
404
|
# ---- 9d. the .expired marker: excludes, and self-heals on a newer credential ----
|
|
387
405
|
printf '%s\nreason=auth-error marked_at=now detail=test\n' "$now" > "$ACC/acct-01/.expired"
|
|
388
406
|
touch -t 202001010101 "$ACC/acct-01/.credentials.json" # credential OLDER than the marker
|