Skip to content

Remove CRS, make CLIProxyAPI the only multi-account path (rebased, supersedes #819) - #830

Merged
Aurora Capital (auroracapital) merged 6 commits into
mainfrom
crs-rebase
Aug 17, 2026
Merged

Remove CRS, make CLIProxyAPI the only multi-account path (rebased, supersedes #819)#830
Aurora Capital (auroracapital) merged 6 commits into
mainfrom
crs-rebase

Conversation

@auroracapital

Copy link
Copy Markdown
Collaborator

Supersedes #819. Same removal, rebased onto current main (v3.4.2), plus one
regression fix and the full-suite verification #819 never completed on its final
state.

Force-pushing #819's branch was not available, so this is a fresh PR off
crs-rebase. Please close #819 as superseded.

Why this replaces #819

A ReferenceError the removal introduced. refresh-tokens.mjs had two
execSync call sites. The removal deleted one and the child_process import
along with it, but the second survived at line 85, inside readKeychain():

main:   import { execFileSync, execSync } from 'child_process';   # 2 uses
#819:   import { execFileSync } from 'child_process';             # 1 use left

Every readKeychain() call would have thrown ReferenceError: execSync is not defined — that is the keychain read at the centre of token refresh. Fixed by
restoring the import; no call sites changed.

Rebased onto current main. #819 was 7 commits behind and its mergeable
state was unknown. The rebase applied cleanly and picks up the rm -rf guard
fix from #826.

Verification

Full run-all.sh on the final rebased state:

  • 27 suites pass, 1 fails.
  • test-safety-hooks.sh49 passed, 0 failed. It was red on main; Fix the rm -rf guard, which blocked nothing on stock macOS #826
    fixed it and this branch inherits that.
  • test-no-secrets.sh — 27 passed, 0 failed.
  • The one failure is test-staged-enrollment.sh, asserting
    timed out waiting for replacement-lock fault stop.

That failure is pre-existing and unrelated, verified rather than assumed: a
pristine git archive of origin/main extracted to a clean directory fails the
same suite with the identical assertion. Being investigated separately.

What the removal does

Deletes the crs-* daemons, scripts/crsproxy-reauth/, three install-crs-*.sh,
five systemd units, three plists, the tuning runbook, and claude-harness-env.mjs.
crs-health-watch.mjs went too — it imported crs-heal-relay.mjs, which has
never existed in this repo.

account-rotation/ is not removed wholesale. Only ~14 of its 106 files were
CRS; rotate.mjs, the credit ledger, claude-p-as.mjs, seat state and the
captcha cascade all stay. Three modules were renamed rather than deleted because
surviving code imports them (crs-pool-configrotation-config,
crs-refresh-lockrefresh-lock, crs-reconciler-statereconciler-state).

The PreToolUse hook was the highest-risk edit: bedrock-fallback-guard.mjs
imports route-state.mjs at module load, so breaking it would throw on every
tool call in every session. route-state.mjs keeps two modes with the live one
renamed crs-oauthoauth, and legacy modes, config blocks, CRS_* env names
and reconciler state filenames all still resolve, so an existing install migrates
rather than breaking.

CLIProxyAPI is now the only supported path for multi-account rotation and OAuth
seat management.

🤖 Generated with Claude Code

@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 103 files, which is 3 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e461c725-7b8d-4748-8d86-a9cd021ec8dc

📥 Commits

Reviewing files that changed from the base of the PR and between 82ae165 and 1a468ed.

📒 Files selected for processing (103)
  • .cursor/approval-policies/daemon-policy.md
  • claude-ops/CHANGELOG.md
  • claude-ops/README.md
  • claude-ops/bin/ops-accounts
  • claude-ops/bin/ops-bg
  • claude-ops/docs/ops/HOST-VS-PLUGIN-ROTATE-GAP.md
  • claude-ops/docs/ops/OPS-ACCOUNTS-GATEWAY.md
  • claude-ops/docs/ops/OPS-ACCOUNTS-VISION.md
  • claude-ops/docs/safety-hooks.md
  • claude-ops/hooks/bedrock-billing-guard.mjs
  • claude-ops/hooks/bedrock-fallback-guard.mjs
  • claude-ops/plugin-dependencies.json
  • claude-ops/scripts/account-rotation/CAPTCHA-CASCADE.md
  • claude-ops/scripts/account-rotation/README.md
  • claude-ops/scripts/account-rotation/__tests__/claude-settings-mode-crs.test.mjs
  • claude-ops/scripts/account-rotation/__tests__/coordination-provisioning.test.mjs
  • claude-ops/scripts/account-rotation/__tests__/model-args.test.mjs
  • claude-ops/scripts/account-rotation/__tests__/ops-accounts-backend.test.mjs
  • claude-ops/scripts/account-rotation/__tests__/production-recovery.test.mjs
  • claude-ops/scripts/account-rotation/__tests__/reauth-env.test.mjs
  • claude-ops/scripts/account-rotation/__tests__/refresh-lock.test.mjs
  • claude-ops/scripts/account-rotation/__tests__/refresh-pacing-worker.mjs
  • claude-ops/scripts/account-rotation/__tests__/refresh-pacing.test.mjs
  • claude-ops/scripts/account-rotation/bg-respawn.mjs
  • claude-ops/scripts/account-rotation/bright-data-cascade.mjs
  • claude-ops/scripts/account-rotation/captcha-cascade.mjs
  • claude-ops/scripts/account-rotation/captcha-helper.mjs
  • claude-ops/scripts/account-rotation/claude-harness-env.mjs
  • claude-ops/scripts/account-rotation/claude-settings-mode.mjs
  • claude-ops/scripts/account-rotation/claude-stack.mjs
  • claude-ops/scripts/account-rotation/config.example.json
  • claude-ops/scripts/account-rotation/crs-401-refresher.mjs
  • claude-ops/scripts/account-rotation/crs-429-cooldown.mjs
  • claude-ops/scripts/account-rotation/crs-429-cooldown.sh
  • claude-ops/scripts/account-rotation/crs-bedrock-guard.mjs
  • claude-ops/scripts/account-rotation/crs-egress-failover.sh
  • claude-ops/scripts/account-rotation/crs-health-watch.mjs
  • claude-ops/scripts/account-rotation/crs-priority-daemon.mjs
  • claude-ops/scripts/account-rotation/crs-priority-daemon.sh
  • claude-ops/scripts/account-rotation/crs-token-feed.mjs
  • claude-ops/scripts/account-rotation/crs-token-feed.sh
  • claude-ops/scripts/account-rotation/daemon.mjs
  • claude-ops/scripts/account-rotation/grok-cli-auth-proxy.py
  • claude-ops/scripts/account-rotation/launch-claude.mjs
  • claude-ops/scripts/account-rotation/magic-link-autoloop.mjs
  • claude-ops/scripts/account-rotation/magic-link-autoloop.sh
  • claude-ops/scripts/account-rotation/oauth-keep-alive-policy.mjs
  • claude-ops/scripts/account-rotation/ops-accounts-backend.mjs
  • claude-ops/scripts/account-rotation/ops-accounts-gateway.mjs
  • claude-ops/scripts/account-rotation/provision-coordination.mjs
  • claude-ops/scripts/account-rotation/reauth-env.mjs
  • claude-ops/scripts/account-rotation/reconciler-state.mjs
  • claude-ops/scripts/account-rotation/refresh-lock.mjs
  • claude-ops/scripts/account-rotation/refresh-tokens.mjs
  • claude-ops/scripts/account-rotation/rotate.mjs
  • claude-ops/scripts/account-rotation/rotation-config.mjs
  • claude-ops/scripts/account-rotation/rotation-config.test.mjs
  • claude-ops/scripts/account-rotation/rotation-vault.mjs
  • claude-ops/scripts/account-rotation/route-state.mjs
  • claude-ops/scripts/account-rotation/seat-policy-tick.mjs
  • claude-ops/scripts/account-rotation/seat-state.mjs
  • claude-ops/scripts/account-rotation/secrets-bootstrap.mjs
  • claude-ops/scripts/account-rotation/session-router.mjs
  • claude-ops/scripts/account-rotation/use-bedrock.sh
  • claude-ops/scripts/account-rotation/use-oauth.sh
  • claude-ops/scripts/crsproxy-reauth/bu_reauth.py
  • claude-ops/scripts/crsproxy-reauth/sync-env.sh
  • claude-ops/scripts/crsproxy-reauth/test-python-suites.sh
  • claude-ops/scripts/crsproxy-reauth/test_browser_cleanup.py
  • claude-ops/scripts/crsproxy-reauth/test_candidate_validation.py
  • claude-ops/scripts/crsproxy-reauth/test_checkpoint.py
  • claude-ops/scripts/crsproxy-reauth/test_lease_cooldown.py
  • claude-ops/scripts/install-crs-fra-tunnel.sh
  • claude-ops/scripts/install-crs-priority-agent.sh
  • claude-ops/scripts/install-crs-reconcilers-agent.sh
  • claude-ops/scripts/ops-accounts/providers/claude.mjs
  • claude-ops/scripts/ops-accounts/providers/cliproxy.mjs
  • claude-ops/scripts/ops-accounts/providers/cursor.mjs
  • claude-ops/scripts/ops-accounts/providers/factory.mjs
  • claude-ops/scripts/ops-accounts/providers/grok.mjs
  • claude-ops/scripts/ops-accounts/providers/openai.mjs
  • claude-ops/scripts/ops-cron-pocket-watcher.py
  • claude-ops/scripts/ops-memory-extractor.sh
  • claude-ops/scripts/systemd/claude-account-rotation.service
  • claude-ops/scripts/systemd/crs-bedrock-guard.service
  • claude-ops/scripts/systemd/crs-bedrock-guard.timer
  • claude-ops/scripts/systemd/crs-compose.service
  • claude-ops/scripts/systemd/crs-token-feed.service
  • claude-ops/scripts/systemd/crs-token-feed.timer
  • claude-ops/skills/ops-accounts/SKILL.md
  • claude-ops/skills/ops-desk/SKILL.md
  • claude-ops/skills/ops-mac/SKILL.md
  • claude-ops/skills/ops-rotate/SKILL.md
  • claude-ops/templates/com.claude-ops.crs-429-cooldown.plist
  • claude-ops/templates/com.claude-ops.crs-fra-tunnel.plist
  • claude-ops/templates/com.claude-ops.crs-priority.plist
  • claude-ops/templates/com.claude-ops.magic-link-autoloop.plist
  • claude-ops/templates/statusline/statusline-command.sh
  • claude-ops/tests/run-all.sh
  • claude-ops/tests/test-claude-invoke.sh
  • claude-ops/tests/test-rotate-cliproxy-integration.sh
  • docs/plans/2026-08-16-crs-removal-plan.md
  • docs/runbooks/crs-full-tuning-plan.md

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CRS is being removed. This commit takes out the files that only exist to
drive a claude-relay-service pool: the priority daemon, the 429 cooldown,
the token feed, the 401 refresher, the health watch, the bedrock guard,
the egress failover, the whole crsproxy-reauth Python tree, the three
install-crs-* scripts, the five crs-* systemd units, the crs-* launchd
plists, and the host-specific tuning runbook.

Three modules in that group were never CRS-specific, only CRS-named, and
other rotation code imports them. They keep their behaviour under neutral
names: crs-pool-config.mjs is now rotation-config.mjs, crs-refresh-lock.mjs
is refresh-lock.mjs, crs-reconciler-state.mjs is reconciler-state.mjs.
rotation-config.mjs loses the pool-name mapping, the relay base URL and the
relay admin password lookup, and reads its tunables from a `rotation` block,
falling back to a legacy `crs` block so an existing config still works.

refresh-tokens.mjs no longer shells out to sync-crs-account.mjs, which was
never in this repo, and its state files migrate by reading the old name when
the new one is absent. magic-link-autoloop.mjs loses the dead candidate
picker that was the only remaining reason it imported pool config.

production-recovery.test.mjs drove three of the deleted daemons; what is
left of it is the Retry-After parsing that every backoff path still uses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The relay backend is gone, so nothing may point a Claude session at one.

route-state.mjs keeps its two modes but renames the live one from crs-oauth
to oauth; crs-oauth and proxy-oauth are read as aliases so an existing
~/.claude/claude-routing-state.json still resolves. Both modes now write the
same settings: no Bedrock keys, no base-URL override, no injected API key.
It also drops the hardcoded operator host IP that sat in the base-URL regex.
New exports detect and scrub a leftover relay pair, and settingsRouteSnapshot
reports one as legacyRelay so `claude-stack doctor` can name it.

bg-respawn.mjs loses the allowlist that routed background sessions through
the relay, along with the health gate, the relay-down marker and the
session-settings overlay that came with it. What replaces it strips any
inherited relay base or cr_ token, drops a --settings relay overlay out of
the persisted respawn flags, and respawns direct. That is the migration for
a machine that was on the relay yesterday: nothing breaks, the routing just
stops being re-applied.

session-router.mjs replaces enforceDirectOrCrsPairing with enforceDirectAuth.
claude-settings-mode.mjs no longer preserves a relay pair across a mode flip.
launch-claude.mjs launches on Claude Code's own credential, and the harness
env loader it used to validate cr_ keys with is deleted.

provision-coordination.mjs no longer generates a systemd unit for a token
feed script that no longer exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ops-accounts loses `crs` and `crs-tick` as working verbs. They stay in the
shell dispatch table only so they answer with where multi-account rotation
lives now (CLIProxyAPI) and exit 2, rather than a bare "unknown command".
The Grok thin-hop probe and the relay migration hint go with them.

ops-bg no longer injects a --settings overlay into every background session
it spawns. The claude-account-rotation systemd unit no longer orders itself
behind a relay compose unit that will never exist.

The statusline suppressed a false Bedrock badge by matching a relay base URL
and a cr_ token. It now matches any loopback base URL, so a machine on
CLIProxyAPI gets the same treatment and one still carrying relay env keeps
reading correctly instead of suddenly showing Bedrock.

ops-cron-pocket-watcher.py and ops-memory-extractor.sh looked up a CRS_KEY
keychain item and defaulted to a relay port. Both now use an explicitly
configured proxy (base URL and token together, or neither) and otherwise
fall through to the OAuth paths that were already there.

ops-accounts-backend resolves a `cliproxy` backend; the retired relay values
resolve to `local` so an install that still exports one keeps working.
Provider adapters drop the vestigial per-account `crs` field, and the Cursor
and Factory quota snapshots move out of a crs-keys directory.

CI: run-all.sh drops the crsproxy-reauth Python suite along with the scripts
it ran, and picks up test-claude-invoke.sh, which existed but was wired into
nothing — it is the only cover for the credit-pool gate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ops-accounts and ops-rotate skills advertised `crs` and `crs-tick` in
their frontmatter and router tables. Those verbs no longer work, so they are
gone from the description, the argument hint and the command tables, and the
rows that described relay pooling now point at CLIProxyAPI and /ops:ops-fleet.

The three docs under docs/ops were written as a migration story from the relay
to a future gateway. That migration is over: OPS-ACCOUNTS-VISION.md now states
what pooling looks like and why the relay was removed, OPS-ACCOUNTS-GATEWAY.md
describes the local compat shim as the smaller separate thing it is, and
HOST-VS-PLUGIN-ROTATE-GAP.md stops listing units and files that no longer
exist.

The rotator README replaces its CRS pool section with CLIProxyAPI setup and
the one command that clears leftover relay credentials from an upgraded
machine. CAPTCHA-CASCADE.md follows the env-var renames.

CHANGELOG gets an entry covering what was deleted, what was renamed, and every
compatibility shim, so an operator can tell what will keep working.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The survey opened with "nothing in this plan has been executed", which stopped
being true. It also proposed re-offering CRS as an installable companion; the
owner decided to remove it outright instead, so section 8 describes a package
that does not exist. The header now says both. The analysis below it is left
as the record of the pre-removal tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: auroracapital <201698397+auroracapital@users.noreply.github.com>
@auroracapital
Aurora Capital (auroracapital) merged commit 44cbdb8 into main Aug 17, 2026
15 checks passed
Comment on lines +270 to 272
case "${ANTHROPIC_BASE_URL:-}" in
http://127.0.0.1:*|http://localhost:*|http://[::1]:*) _is_local_proxy=1 ;;
esac

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

http://[::1]:* doesn't do what it looks like — in a case pattern the brackets are a glob bracket expression, so this matches http:// + one char from {:,1} + :. It never matches http://[::1]:8317, and it does match nonsense like http://1:8317:

$ case "http://[::1]:8317" in http://[::1]:*) echo M ;; *) echo N ;; esac
N
$ case "http://1:8317" in http://[::1]:*) echo M ;; *) echo N ;; esac
M

Needs quoting so the brackets are literal:

Suggested change
case "${ANTHROPIC_BASE_URL:-}" in
http://127.0.0.1:*|http://localhost:*|http://[::1]:*) _is_local_proxy=1 ;;
esac
case "${ANTHROPIC_BASE_URL:-}" in
http://127.0.0.1:*|http://localhost:*|'http://[::1]:'*) _is_local_proxy=1 ;;
esac

Separately, this is a lot broader than the check it replaces (which required a cr_ token and a known relay port). Any loopback base URL now forces sub_type="max" and overrides an explicit CLAUDE_CODE_USE_BEDROCK=1 — and the result gets written to $billing_cache on the line below. So a genuinely-Bedrock session that happens to have a loopback proxy configured loses its billing badge and caches the wrong value. Worth keeping the token/port shape in the condition rather than "any loopback".

const SECRET_FILES = [
process.env.CLAUDE_ROTATOR_SECRETS_FILE,
join(homedir(), '.config', 'crs-sync', 'rotator-secrets.env'),
join(homedir(), '.config', 'claude-rotation', 'rotator-secrets.env'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one moves silently. Anyone with secrets at ~/.config/crs-sync/rotator-secrets.env today gets them dropped on upgrade — nothing creates or migrates the new path, and the loader just falls through to the next candidate with no warning. That's the 2captcha/BrightData credential source, so the failure surfaces much later as a captcha cascade that can't solve.

Cheap to keep both:

Suggested change
join(homedir(), '.config', 'claude-rotation', 'rotator-secrets.env'),
join(homedir(), '.config', 'claude-rotation', 'rotator-secrets.env'),
// Legacy location — read so an existing install keeps its secrets after upgrade.
join(homedir(), '.config', 'crs-sync', 'rotator-secrets.env'),

Comment on lines +31 to +32
// Legacy env name kept last so an older install still resolves its config.
process.env.CRS_CONFIG,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment doesn't match the effect. resolveConfigPath() returns the first existing candidate, so moving CRS_CONFIG behind the five on-disk defaults means it only ever wins on a machine that has no config in any default location — i.e. effectively never for the installs this is meant to protect. An operator who points CRS_CONFIG at a custom file today silently starts reading ~/.claude/scripts/account-rotation/config.json instead.

An explicit env override should still beat implicit disk defaults; just keep it next to the current env name:

Suggested change
// Legacy env name kept last so an older install still resolves its config.
process.env.CRS_CONFIG,
process.env.CLAUDE_ROTATOR_CONFIG,
// Legacy env name, still honoured ahead of the on-disk defaults.
process.env.CRS_CONFIG,

(and drop the trailing entry)

Comment on lines +122 to 126
/** True when local EFG SOCKS (CLAUDE_ROT_EFG_SOCKS_*) accepts connections. */
export async function residentialEgressHealthy() {
const host = process.env.CRS_EFG_SOCKS_HOST || '127.0.0.1';
const port = Number(process.env.CRS_EFG_SOCKS_PORT || 1089);
const host = process.env.CLAUDE_ROT_EFG_SOCKS_HOST || '127.0.0.1';
const port = Number(process.env.CLAUDE_ROT_EFG_SOCKS_PORT || 1089);
return await new Promise((resolve) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the CRS_* names in this file get renamed with no fallback, which is inconsistent with how refresh-lock.mjs handled the same problem in this PR:

const envValue = (name) => process.env[`CLAUDE_REFRESH_${name}`] ?? process.env[`CRS_REFRESH_${name}`];

The renames here are mostly tuning knobs, so the failure mode is quiet rather than loud: an install exporting CRS_CAPTCHA_SOLVER_MODE=off silently flips back to fallback and starts paying for solves, and CRS_EFG_SOCKS_PORT reverts to 1089 so solver tokens stop matching the residential browser IP. Same helper shape would cover the whole file:

const captchaEnv = (name) => process.env[`CLAUDE_ROT_${name}`] ?? process.env[`CRS_${name}`];

reauth-env.mjs has the mirror of this — resolveReauthDisplay drops CRS_REAUTH_DISPLAY, and resolveReauthTimeoutMs keeps CRS_MAGIC_LINK_ROTATE_TIMEOUT_MS but quietly drops its CRS_MAGIC_LOOP_ROTATE_TIMEOUT_MS sibling.

// A relay reachable somewhere else (a tailnet address, say) can be named in
// OPS_RELAY_HOSTS as a comma-separated host:port list; nothing site-specific
// is hardcoded here.
const LEGACY_RELAY_PORT_RE = /:(3000|3002|3005|8091|18091)(\/|$)/;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This widened from loopback-only to any-host. main required 127.0.0.1:<port> or a :<port>/api suffix; this matches those ports on any hostname. Combined with scrubLegacyRelayEnv() now running unconditionally on every spawn in session-router.mjs and bg-respawn.mjs, a CLIProxyAPI instance published on one of these ports (3000 is a very ordinary docker mapping) gets its ANTHROPIC_BASE_URL deleted out from under it — and that's the path this PR makes the only supported one.

The comment above says a relay reachable elsewhere should be named in OPS_RELAY_HOSTS, which is exactly the escape hatch that makes anchoring safe here:

Suggested change
const LEGACY_RELAY_PORT_RE = /:(3000|3002|3005|8091|18091)(\/|$)/;
const LEGACY_RELAY_PORT_RE = /^https?:\/\/(127\.0\.0\.1|localhost|\[::1\]):(3000|3002|3005|8091|18091)(\/|$)/;


export async function listAccounts(ctx) {
const snapPath = join(ctx.home, '.claude/crs-keys/quota/cursor-latest.json');
const snapPath = join(ctx.home, '.claude/quota-snapshots/cursor-latest.json');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing in the repo writes either path — rg 'crs-keys' comes back empty after this PR — so the snapshot producer is external to the plugin. Moving the read location without a fallback means existing snapshots go invisible and utilization() quietly returns { windows: [], source: 'unavailable' } rather than erroring, so it looks like a quota-API problem instead of a path change.

Since it's just a existsSync pick, worth reading either:

const snapPath = [
  join(ctx.home, '.claude/quota-snapshots/cursor-latest.json'),
  join(ctx.home, '.claude/crs-keys/quota/cursor-latest.json'),
].find(existsSync);

Same applies to the two factory-droid.json sites in providers/factory.mjs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants