claude-multiacc 2.0.45 → 2.0.46
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/codex +14 -1
- package/docs/AUTORESUME.md +6 -0
- package/lib/__pycache__/audit.cpython-312.pyc +0 -0
- package/lib/__pycache__/autoresume.cpython-312.pyc +0 -0
- package/lib/__pycache__/claude_reset.cpython-312.pyc +0 -0
- package/lib/__pycache__/claude_token_identity.cpython-312.pyc +0 -0
- package/lib/__pycache__/codex_config_edit.cpython-312.pyc +0 -0
- package/lib/__pycache__/codex_python.cpython-312.pyc +0 -0
- package/lib/__pycache__/keychain.cpython-312.pyc +0 -0
- package/lib/__pycache__/mcp_registry.cpython-312.pyc +0 -0
- package/lib/__pycache__/selector_policy.cpython-312.pyc +0 -0
- package/lib/__pycache__/selector_primitives.cpython-312.pyc +0 -0
- package/lib/__pycache__/shim_path.cpython-312.pyc +0 -0
- package/lib/autoresume.py +5 -2
- package/package.json +1 -1
- package/tests/__pycache__/packaged_command_support.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_autoresume.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_claude_reset.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_claude_token_identity.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_codex_reset.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_codex_reset_polling.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_codex_reset_reporting.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_codex_reset_windows.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_token_identity_ceremony.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_token_identity_integration.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_token_identity_retry.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_token_identity_sync.cpython-312.pyc +0 -0
- package/tests/run-tests.sh +10 -0
- package/tests/test_autoresume.py +7 -1
package/bin/codex
CHANGED
|
@@ -1363,8 +1363,21 @@ fi
|
|
|
1363
1363
|
pick="$PICK_DIR"
|
|
1364
1364
|
# A probe answers here, before anything that would count as a launch: no rotation
|
|
1365
1365
|
# memory, no limits kick, no pick line in selection.log — and never an exec.
|
|
1366
|
+
# A limited tier also names when it lifts (resets_at=<epoch>, only when known): hard is
|
|
1367
|
+
# the soonest reset among the exhausted accounts, soft the picked account's own marker.
|
|
1368
|
+
# This is the machine twin of the tty-only notice above — callers read stdout, and a
|
|
1369
|
+
# service's stderr stays byte-clean.
|
|
1366
1370
|
if [ "$AR_PROBE" = "1" ]; then
|
|
1367
|
-
|
|
1371
|
+
ar_reset=0
|
|
1372
|
+
case "$AR_TIER" in
|
|
1373
|
+
hard) ar_reset="$best_reset" ;;
|
|
1374
|
+
soft) ar_reset="$(limited_reset_of "$pick")" ;;
|
|
1375
|
+
esac
|
|
1376
|
+
if [ "$ar_reset" -gt 0 ] 2>/dev/null; then
|
|
1377
|
+
printf 'pick=%s tier=%s resets_at=%s\n' "${pick##*/}" "$AR_TIER" "$ar_reset"
|
|
1378
|
+
else
|
|
1379
|
+
printf 'pick=%s tier=%s\n' "${pick##*/}" "$AR_TIER"
|
|
1380
|
+
fi
|
|
1368
1381
|
exit 0
|
|
1369
1382
|
fi
|
|
1370
1383
|
# Remember the pick so the NEXT run does not hand back the same account. An explicit
|
package/docs/AUTORESUME.md
CHANGED
|
@@ -293,6 +293,12 @@ CLAUDE_MULTIACC_AR_PROBE=1 CLAUDE_MULTIACC_AR_AVOID=acct-07:1790000000 claude
|
|
|
293
293
|
- `soft`: only the all-limited fallback;
|
|
294
294
|
- `hard`: only exhausted accounts are left;
|
|
295
295
|
- `none`: nothing is usable; exit 3.
|
|
296
|
+
- **`resets_at`** (codex only): a `soft` or `hard` answer may end with
|
|
297
|
+
` resets_at=<epoch>`, when that tier's reset is known. For `hard` it is the soonest
|
|
298
|
+
reset among the exhausted accounts. For `soft` it is the picked account's own reset.
|
|
299
|
+
An `eligible` answer never carries it. This is the machine-readable form of the
|
|
300
|
+
terminal-only "every usable account is at a limit" notice; stderr stays empty.
|
|
301
|
+
Parsers must accept trailing `key=value` fields.
|
|
296
302
|
- **What the probe runs:** the same candidate loop as a launch, including marker upkeep
|
|
297
303
|
and its log lines, stopping before exec.
|
|
298
304
|
- **Environment:** run it with no `CLAUDE_CONFIG_DIR`, `CLAUDE_ACCOUNT` or
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/autoresume.py
CHANGED
|
@@ -1118,10 +1118,13 @@ def probe_env(environ, provider, avoid):
|
|
|
1118
1118
|
|
|
1119
1119
|
|
|
1120
1120
|
def parse_probe(out):
|
|
1121
|
-
"""The probe's ``pick=<acct> tier=<eligible|soft|hard|none>`` -> (pick, tier).
|
|
1121
|
+
"""The probe's ``pick=<acct> tier=<eligible|soft|hard|none>`` -> (pick, tier).
|
|
1122
|
+
|
|
1123
|
+
Trailing ``key=value`` fields (the codex shim's ``resets_at=<epoch>``) are accepted
|
|
1124
|
+
and ignored here."""
|
|
1122
1125
|
pick, tier = "", ""
|
|
1123
1126
|
for line in (out or "").split("\n"):
|
|
1124
|
-
m = re.match(r"^pick=(\S*) tier=(\S+)
|
|
1127
|
+
m = re.match(r"^pick=(\S*) tier=(\S+)(?:\s+\w+=\S*)*\s*$", line.strip())
|
|
1125
1128
|
if m:
|
|
1126
1129
|
pick, tier = m.group(1), m.group(2)
|
|
1127
1130
|
if pick and not ACCT_RE.match(pick):
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/tests/run-tests.sh
CHANGED
|
@@ -5695,6 +5695,10 @@ cxlj 99 10 99 > "$CX/acct-01/limits.json"
|
|
|
5695
5695
|
cxlj 7 100 100 > "$CX/acct-02/limits.json"
|
|
5696
5696
|
out="$(codex 2>&1)"
|
|
5697
5697
|
check "codex: a still-serving limited account beats an exhausted one with more headroom" "CFG=acct-01" "$out"
|
|
5698
|
+
out="$(CODEX_MULTIACC_AR_PROBE=1 codex 2>&1)"; rc=$?
|
|
5699
|
+
[ "$rc:$out" = "0:pick=acct-01 tier=soft resets_at=$((now+3600))" ] \
|
|
5700
|
+
&& t_ok "codex probe: a soft pick carries its own marker's resets_at" \
|
|
5701
|
+
|| t_fail "codex probe soft resets_at" "rc=$rc out=$out"
|
|
5698
5702
|
# The codex-review case (2026-09-04): the exhausted account is the only one INSIDE the
|
|
5699
5703
|
# session gate; the gate must not resurrect it over a still-serving account outside it.
|
|
5700
5704
|
printf '%s\nbucket=7d percent=100 marked_at=x reason=limits\n' "$((now+3600))" > "$CX/acct-01/.limited"
|
|
@@ -5713,6 +5717,12 @@ printf '%s\nbucket=5h percent=100 marked_at=x reason=limits\n' "$((now+7200))" >
|
|
|
5713
5717
|
printf '%s\nbucket=5h percent=100 marked_at=x reason=limits\n' "$((now+600))" > "$CX/acct-02/.limited"
|
|
5714
5718
|
out="$(codex 2>&1)"
|
|
5715
5719
|
check "codex: all exhausted: the soonest reset is handed out" "CFG=acct-02" "$out"
|
|
5720
|
+
# The probe is the machine channel for the tty-only notice: it names the soonest reset,
|
|
5721
|
+
# and its stderr stays empty.
|
|
5722
|
+
out="$(CODEX_MULTIACC_AR_PROBE=1 codex 2>"$WORK/cx-probe.err")"; rc=$?
|
|
5723
|
+
[ "$rc:$out" = "0:pick=acct-02 tier=hard resets_at=$((now+600))" ] && [ ! -s "$WORK/cx-probe.err" ] \
|
|
5724
|
+
&& t_ok "codex probe: all exhausted answers tier=hard resets_at=<soonest reset>, stderr clean" \
|
|
5725
|
+
|| t_fail "codex probe hard resets_at" "rc=$rc out=$out err=$(cat "$WORK/cx-probe.err")"
|
|
5716
5726
|
grep -q "all-exhausted resets_in=" "$CX/selection.log" \
|
|
5717
5727
|
&& t_ok "codex: the all-exhausted pick is logged with its reset" || t_fail "codex all-exhausted log" "no line"
|
|
5718
5728
|
rm -f "$CX"/acct-*/.limited "$CX"/acct-*/limits.json
|
package/tests/test_autoresume.py
CHANGED
|
@@ -697,7 +697,13 @@ class StateTests(unittest.TestCase):
|
|
|
697
697
|
self.assertEqual(ar.parse_probe("noise\npick=acct-02 tier=eligible\n"),
|
|
698
698
|
("acct-02", "eligible"))
|
|
699
699
|
self.assertEqual(ar.parse_probe("pick= tier=none\n"), ("", "none"))
|
|
700
|
-
|
|
700
|
+
# The codex shim appends resets_at=<epoch> to a limited tier; old lines still parse.
|
|
701
|
+
self.assertEqual(ar.parse_probe("pick=acct-03 tier=hard resets_at=1790000000\n"),
|
|
702
|
+
("acct-03", "hard"))
|
|
703
|
+
self.assertEqual(ar.parse_probe("pick=acct-03 tier=soft resets_at=1790000000"),
|
|
704
|
+
("acct-03", "soft"))
|
|
705
|
+
for bad in ("", "pick=acct-02", "pick=../x tier=eligible", "pick=acct-02 tier=great",
|
|
706
|
+
"pick=acct-02 tier=hard resets_at", "pick=acct-02 tier=hard x y"):
|
|
701
707
|
self.assertEqual(ar.parse_probe(bad), ("", ""), bad)
|
|
702
708
|
self.assertTrue(ar.probe_allows("quota", "acct-02", "eligible", "acct-01"))
|
|
703
709
|
self.assertFalse(ar.probe_allows("quota", "acct-01", "eligible", "acct-01"))
|