claude-multiacc 2.0.28 → 2.0.29
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-accounts +24 -2
- package/bin/codex-accounts +33 -2
- package/lib/__pycache__/audit.cpython-312.pyc +0 -0
- package/lib/__pycache__/keychain.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/package.json +1 -1
- package/tests/__pycache__/packaged_command_support.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/run-tests.sh +30 -0
package/bin/claude-accounts
CHANGED
|
@@ -2482,6 +2482,21 @@ AUTH_ERR = re.compile(
|
|
|
2482
2482
|
ORG_ERR = re.compile(
|
|
2483
2483
|
r'organization has disabled|subscription access.*disabl|disabled claude subscription'
|
|
2484
2484
|
r'|ask your admin to enable|not authorized to use claude code', re.I)
|
|
2485
|
+
# EXCULPATORY, tested FIRST — the twin of BROKEN_CLI in bin/codex-accounts, and
|
|
2486
|
+
# it matters MORE here: AUTH_ERR above matches a bare `401` or `403`, so any
|
|
2487
|
+
# machine fault whose output happens to contain those three digits parks a live
|
|
2488
|
+
# login. `mark_expired` writes no `soft_until`, so that verdict is permanent
|
|
2489
|
+
# until a person clears it. These patterns say the CLI never reached the API,
|
|
2490
|
+
# which is a fact about the machine and never about the login.
|
|
2491
|
+
# See health.log 2026-08-24: `env: node: No such file or directory` failed
|
|
2492
|
+
# every account in one pass.
|
|
2493
|
+
BROKEN_CLI = re.compile(
|
|
2494
|
+
r'missing optional dependency|unsupported (platform|target triple):'
|
|
2495
|
+
r'|cannot find module|ERR_MODULE_NOT_FOUND|ERR_DLOPEN_FAILED'
|
|
2496
|
+
r'|env: node: no such file or directory|node: command not found'
|
|
2497
|
+
r'|spawn .{0,80}(ENOENT|EACCES|EPERM)|^dyld\[[0-9]+\]:'
|
|
2498
|
+
r'|cannot execute binary file|bad CPU type in executable|exec format error',
|
|
2499
|
+
re.I | re.M)
|
|
2485
2500
|
|
|
2486
2501
|
def mark_expired(d, slug, detail=''):
|
|
2487
2502
|
"""Park an account the shim must stop selecting. Verify is the strongest signal
|
|
@@ -2607,9 +2622,16 @@ for acct in manifest.get('accounts', []):
|
|
|
2607
2622
|
pass
|
|
2608
2623
|
print(f'{aid} {acct["email"]}: PASS ({dt:.1f}s) -> {out[:60]!r}')
|
|
2609
2624
|
else:
|
|
2610
|
-
|
|
2625
|
+
raw = (r.stderr or '').strip()
|
|
2626
|
+
err = raw[:200]
|
|
2611
2627
|
hint = ''
|
|
2612
|
-
|
|
2628
|
+
# STDERR only, and the WHOLE of it: stdout is the model's own answer,
|
|
2629
|
+
# and a session that merely discusses "Cannot find module" must not be
|
|
2630
|
+
# able to excuse a real dead login.
|
|
2631
|
+
if BROKEN_CLI.search(raw):
|
|
2632
|
+
hint = (' — the Claude CLI cannot run on this machine; not a login '
|
|
2633
|
+
'problem, nothing was parked')
|
|
2634
|
+
elif ORG_ERR.search(out) or ORG_ERR.search(err):
|
|
2613
2635
|
# Not an auth problem: the account authenticates fine, its organization
|
|
2614
2636
|
# has simply turned Claude Code subscription access off. Park it — a
|
|
2615
2637
|
# re-login changes nothing — and say what actually helps.
|
package/bin/codex-accounts
CHANGED
|
@@ -1768,6 +1768,30 @@ ORG_ERR = re.compile(
|
|
|
1768
1768
|
r'disabled by (your )?(workspace )?admin|admin (has )?disabled'
|
|
1769
1769
|
r'|(workspace|organization) has disabled (codex|chatgpt)'
|
|
1770
1770
|
r'|codex.{0,20}disabled for (your|this) (workspace|organization)', re.I)
|
|
1771
|
+
# EXCULPATORY, and therefore tested FIRST. These say the CLI never reached the
|
|
1772
|
+
# API at all — a missing native package, a missing node, an unrunnable binary —
|
|
1773
|
+
# so they are facts about this MACHINE, not about the login. Parking on one
|
|
1774
|
+
# converts an indeterminate probe into "this login is dead", and that verdict
|
|
1775
|
+
# does not self-heal: `mark_expired` here writes no `soft_until`, so the shim
|
|
1776
|
+
# reads it as proven dead and keeps it, while the panel refuses to re-import
|
|
1777
|
+
# the token until its fingerprint changes.
|
|
1778
|
+
#
|
|
1779
|
+
# Not hypothetical. health.log 2026-08-24T06:37:02Z: all four accounts
|
|
1780
|
+
# `FAIL rc=127 err='env: node: No such file or directory'` — one broken PATH
|
|
1781
|
+
# reddened the entire matrix, and it escaped parking only because that exact
|
|
1782
|
+
# string happens not to match AUTH_ERR. `Missing optional dependency
|
|
1783
|
+
# @openai/codex-<platform>` (my-mini, 2026-09-10) is the same class.
|
|
1784
|
+
#
|
|
1785
|
+
# Keep it NARROW. It must never contain a word a genuine auth failure uses
|
|
1786
|
+
# ("permission denied", "forbidden", a bare "not found"), or a real dead login
|
|
1787
|
+
# would be excused as a broken machine. Widen only with a test.
|
|
1788
|
+
BROKEN_CLI = re.compile(
|
|
1789
|
+
r'missing optional dependency|unsupported (platform|target triple):'
|
|
1790
|
+
r'|cannot find module|ERR_MODULE_NOT_FOUND|ERR_DLOPEN_FAILED'
|
|
1791
|
+
r'|env: node: no such file or directory|node: command not found'
|
|
1792
|
+
r'|spawn .{0,80}(ENOENT|EACCES|EPERM)|^dyld\[[0-9]+\]:'
|
|
1793
|
+
r'|cannot execute binary file|bad CPU type in executable|exec format error',
|
|
1794
|
+
re.I | re.M)
|
|
1771
1795
|
|
|
1772
1796
|
def mark_expired(d, slug, detail=''):
|
|
1773
1797
|
"""Park an account the shim must stop selecting. Verify is the strongest signal
|
|
@@ -1845,9 +1869,16 @@ for acct in manifest.get('accounts', []):
|
|
|
1845
1869
|
pass
|
|
1846
1870
|
print(f'{aid} {acct["email"]}: PASS ({dt:.1f}s) -> {(last or out)[:60]!r}')
|
|
1847
1871
|
else:
|
|
1848
|
-
|
|
1872
|
+
raw = (r.stderr or '').strip()
|
|
1873
|
+
err = raw[:200]
|
|
1849
1874
|
hint = ''
|
|
1850
|
-
|
|
1875
|
+
# STDERR only, and the WHOLE of it: stdout is the model's own answer,
|
|
1876
|
+
# and a session that merely discusses "Cannot find module" must not be
|
|
1877
|
+
# able to excuse a real dead login.
|
|
1878
|
+
if BROKEN_CLI.search(raw):
|
|
1879
|
+
hint = (' — the Codex CLI cannot run on this machine; not a login '
|
|
1880
|
+
'problem, nothing was parked')
|
|
1881
|
+
elif ORG_ERR.search(out) or ORG_ERR.search(err):
|
|
1851
1882
|
# Not an auth problem: the account authenticates fine, a workspace admin
|
|
1852
1883
|
# has simply turned Codex access off. Park it — a re-login changes
|
|
1853
1884
|
# nothing — and say what actually helps.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/tests/run-tests.sh
CHANGED
|
@@ -136,6 +136,15 @@ case "${CLAUDE_CODE_OAUTH_TOKEN:-}" in
|
|
|
136
136
|
*) echo "Failed to authenticate. API Error: 401 OAuth access token is invalid." >&2; exit 1 ;;
|
|
137
137
|
esac ;;
|
|
138
138
|
esac
|
|
139
|
+
if [ -f "$ctl" ] && grep -qx "brokencli:$acct" "$ctl" 2>/dev/null; then
|
|
140
|
+
# An infrastructure fault, not a login verdict: the CLI never reached the API.
|
|
141
|
+
# Verbatim from my-mini, 2026-09-10. Note it carries no auth vocabulary at all
|
|
142
|
+
# — the danger is that AUTH_ERR matches a bare `401`, and a node stack frame
|
|
143
|
+
# or a version string can contain one.
|
|
144
|
+
echo "Error: Missing optional dependency @openai/codex-darwin-arm64. Reinstall Codex: npm install -g @openai/codex@latest" >&2
|
|
145
|
+
echo " at findCodexExecutable (file:///opt/homebrew/lib/node_modules/@openai/codex/bin/codex.js:107:9)" >&2
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
139
148
|
case " $* " in
|
|
140
149
|
*" -p --output-format text --max-turns 1 "*) echo "OK"; exit 0 ;;
|
|
141
150
|
esac
|
|
@@ -3898,6 +3907,27 @@ check "import rejects an API key as token" "not a subscription setup-token" "$ou
|
|
|
3898
3907
|
out="$(printf 'sk-ant-api03-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ' | claude-accounts mint acct-01 --paste 2>&1)"
|
|
3899
3908
|
check "mint --paste rejects an API key" "not a subscription setup-token" "$out"
|
|
3900
3909
|
|
|
3910
|
+
# ---- 17a2. a CLI that cannot run is not a dead login ----------------------------------
|
|
3911
|
+
# health.log 2026-08-24T06:37:02Z: all four accounts FAIL rc=127
|
|
3912
|
+
# err='env: node: No such file or directory'. One broken PATH reddened the whole
|
|
3913
|
+
# verify matrix, and it escaped parking only because that string happens not to
|
|
3914
|
+
# match AUTH_ERR — which matches a bare `401`, so a node stack frame carrying one
|
|
3915
|
+
# is enough. `mark_expired` writes no soft stamp, so such a park is permanent,
|
|
3916
|
+
# and the panel then refuses to re-import the token until its fingerprint changes.
|
|
3917
|
+
rm -f "$ACC/acct-01/.expired"
|
|
3918
|
+
printf 'brokencli:acct-01\n' > "$WORK/ctl-brokencli"
|
|
3919
|
+
out="$(FAKE_CTL="$WORK/ctl-brokencli" claude-accounts verify 2>&1)"
|
|
3920
|
+
check "a broken CLI is reported as a machine fault" "cannot run on this machine" "$out"
|
|
3921
|
+
check "a broken CLI still fails the account" "acct-01" "$out"
|
|
3922
|
+
[ ! -f "$ACC/acct-01/.expired" ] \
|
|
3923
|
+
&& t_ok "a broken CLI never parks a live login" \
|
|
3924
|
+
|| t_fail "broken CLI parking" "verify parked an account over an infrastructure fault"
|
|
3925
|
+
case "$out" in
|
|
3926
|
+
*"login is dead"*) t_fail "broken CLI wording" "verify blamed the login for a machine fault" ;;
|
|
3927
|
+
*) t_ok "a broken CLI is not called a dead login" ;;
|
|
3928
|
+
esac
|
|
3929
|
+
rm -f "$WORK/ctl-brokencli"
|
|
3930
|
+
|
|
3901
3931
|
# ---- 17b. verify authenticates the way the SHIM would ---------------------------------
|
|
3902
3932
|
# A dead credential next to a live portable token: the shim runs that account with the
|
|
3903
3933
|
# TOKEN, so verify must too — testing it with the dead credential would fail a healthy
|