Skip to content

Port upstream 0.67.0: Raycast provider - #668

Open
Finesssee wants to merge 3 commits into
port/upstream-0.67.0from
port/micro-0.67.0-raycast
Open

Finesssee wants to merge 3 commits into
port/upstream-0.67.0from
port/micro-0.67.0-raycast

Conversation

@Finesssee

Copy link
Copy Markdown
Collaborator

Summary

Adds the Raycast AI credits provider (upstream CodexBar 0.67.0). It reads monthly credits from the signed-in www.raycast.com session and shows credits left, plan, and renewal date.

Upstream reference

  • Upstream release tag v0.67.0 (read-only, tag-pinned GET): Raycast provider, frontend_api/current_user/ai_credits.
  • Provider icon copied from the upstream v0.67.0 tag.

Ported

  • New ProviderId::Raycast (raycast, alias raycast-ai, cookie domain www.raycast.com, brand #FF6363), factory arm, no-token-account entry.
  • rust/src/providers/raycast/: request (Cookie, Accept, Origin, Referer, Chrome User-Agent), parse rules (numeric or numeric-string amounts; negative/invalid amounts, bad dates, non-object funding_subscription are parse failures), cookie filtering (only __raycast_session and csrf_token, exact host first), classified errors (missing/expired session, 403, 429, 5xx).
  • Auto imports from Chrome; a Manual header is pinned and never falls back to a browser; Off makes no request. 401 advances to the next candidate within one refresh; other failures stop retries.
  • Shell cookie-source options (auto/manual/off), tray dashboard link, settings source hint, frontend and dashboard icons, provider catalog fixture, docs, README row, changelog.

Deferred / caveats

  • Chrome Windows App-Bound Encryption may block automatic import; Manual is the fallback.
  • Chrome channels/Chromium profiles (upstream feat(browser): support Chrome channels and Chromium profiles #614) are not in this base; Auto reads all Chrome profiles merged.
  • Top-up packages and credits/details are not fetched.
  • The global default cookie source is Manual, so users choose Auto.
  • The shell maps Off to the CLI source mode, so the message says cookies are disabled.
  • Amount formatting rounds ties per Rust, which may differ marginally from JS toFixed.

Validation

  • cargo fmt --all: clean.
  • cargo clippy --workspace --all-targets -- -D warnings: pass.
  • cargo test -p codexbar raycast: 29 passed.
  • cargo test -p codexbar (full): 2189 passed, 0 failed, 1 ignored.
  • cargo test -p codexbar-desktop-tauri: 464 passed, 1 failed (commands::tests::bootstrap_payload_exposes_every_provider_variant: catalog 80 vs 79 active). That test calls get_bootstrap_state(), which loads this machine's real settings, so a deprecated provider that is enabled locally adds one catalog entry. It is environment-dependent and unrelated to the Raycast change; the three new Raycast shell tests pass.
  • pnpm test (vitest): 67 files, 402 tests passed.
  • pnpm run build: pass.

Affected areas

Shared: ProviderId, provider factory, token accounts, providers/mod.rs (new browser_cookies_from_browser helper). Shell: cookie-source options. Frontend: icon registry, tray dashboard set, settings source hint.

UI proof

Pending: coordinator will capture CUA proof on a fresh build. This PR is a draft for that reason.

Adds the Raycast AI credits provider (cookie-backed frontend_api/current_user/ai_credits), its cookie-source options, icons, catalog registration, and docs.
@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 40ee856f-b9ef-4556-bc49-f6e60244743b

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

Thermo-nuclear review

Scope: head 4c68ec9 against the raycast entry in the 0.67.0 audit and AGENTS.md / PORTING.md section 5. The provider is well factored (cookies.rs / parse.rs / mod.rs / tests.rs), no file crosses 1000 lines because of this PR, registration matches the Replicate template file-for-file, and the spec matrix (invalid amounts, exact-host precedence, Manual pinned, Off makes no request, 401 advance) is covered by tests. Findings are small.

Fix in this review:

  1. parse.rs: amount + non_negative_amount were a two-layer wrapper whose only caller was the second layer. Folded the sign check into amount (one function, one error path, same messages).
  2. mod.rs::check_status: an if/else chain with an early return inside a let initializer. Rewritten as a match on StatusCode, same messages and mapping.

Left as-is, with reasons:

  1. error_state_kind compares error text to the MISSING_SESSION / SESSION_EXPIRED constants. It is a magic-string identity, but the trait doc explicitly allows a message guard, both strings are consts used at the raise site, and a typed alternative (NoCookies, OAuthExpired) would either change user-facing copy or need a new ProviderError variant in shared code. Tests pin the classification.
  2. Chrome cookies from all profiles are merged with no profile identity, so the optional csrf_token can come from a different profile than the session. The spec says CSRF is not required for this GET and to forward it when present; fixing this needs profile data on Cookie (shared browser layer), out of scope for a micro port.
  3. Request timeout: spec default is 15 s but the shell always passes web_timeout (60), so the clamp yields 30 s. Changing that means a per-provider default in shared fetch-context plumbing; not worth it here.
  4. Hardcoded English in cookie_source_options_for("raycast") follows the existing Replicate / Helmcode pattern in that function; locale keys for that catalog are a separate cleanup.
  5. TrayPanel.tsx HAS_DASHBOARD is a hand-maintained id set (pre-existing design); the one-word addition is consistent.

No UI-visible change comes from the fixes.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

Thermo-nuclear review follow-up

Reviewed by Codex gpt-6-luna (xhigh); verified and validated by Claude. Fixes landed at d16c04d.

Fixed:

  • parse.rs: folded amount and non_negative_amount into one function; object helper removed (root uses as_object, funding_subscription matched inline; null and absent both read as no subscription).
  • mod.rs::check_status: rewritten as a match on StatusCode, same messages.
  • provider_settings.rs: Raycast cookie-source help text moved to locale keys (ProviderRaycast*), translated in all eight catalogs (English text unchanged).

Left out:

  • Codex also proposed making funding_subscription: null a parse failure. Not applied: the spec only lists {} as the empty-subscription fixture, and upstream decodes the field as optional, so null stays valid.
  • Earlier items 3 to 5 and 7 remain as explained in the first review.

Commands run: cargo +1.98.0 fmt --all, cargo +1.98.0 clippy --workspace --all-targets -- -D warnings (clean), cargo +1.98.0 test -p codexbar raycast (29 passed), -p codexbar locale (16 passed), -p codexbar-desktop-tauri cookie_source (7 passed). No desktop app run; UI change is limited to localized help text.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

CUA proof

Build commit: d16c04d889369068261734445358adafcee7a162 (PR head). Debug desktop build, driven with cua-driver CLI in the background on a second monitor (no focus, keyboard or mouse taken). Fully isolated profile (CODEXBAR_PROOF_HOME) and a local mock; no real account data on screen.

Blocker found while building (PR code, not proof-only): unpatched head fails pnpm run tauri:build:debug because beforeBuildCommand runs pnpm run build -> check-locale: DRIFT DETECTED rust=882 ts=879; only in Rust: ProviderRaycastAutoImportHelp, ProviderRaycastManualCookieHelp, ProviderRaycastCookiesDisabled. The PR adds the keys to rust/src/locale.rs and the .ftl files but not to apps/desktop-tauri/src/i18n/keys.ts (ALL_LOCALE_KEYS). Any hosted gate that runs pnpm run build will fail until they are added.

Proof-only patches (uncommitted, restored afterwards):

  • Root Cargo.toml [patch.crates-io] dirs shim redirecting home/config/data dirs under CODEXBAR_PROOF_HOME (plus Cargo.lock).
  • rust/src/providers/raycast/mod.rs RaycastProvider::new(): env CODEXBAR_PROOF_RAYCAST_ORIGIN overrides the https origin, client .no_proxy(). Real fetch path runs against a local python mock; TLS/URL validation otherwise untouched.
  • apps/desktop-tauri/src/i18n/keys.ts: the 3 missing Raycast keys added so the build could pass (works around the blocker above).

Commands: bash launch.sh trayPanel | popOut | settings:providers, MOCK_VARIANT=nototal|expired bash launch.sh trayPanel; cua-driver call get_window_state ... --screenshot-out-file.

# Assertion Result
0 No real email/account from the machine visible; only Raycast provider present PASS
1 Dark theme under auto in tray, pop-out and settings PASS
2 Tray/pop-out: Raycast only, no error, "Credits" meter 25% used, plan Pro+ PASS
2b Reset 2026-12-01 PASS in Settings > Providers ("Resets in 61d 11h"); not shown in the compact tray card
2c Text "750 / 1000 credits left" NOT VISIBLE for the metered case (set as reset_description, but the UI shows the reset text instead); minor
3 Mock saw only __raycast_session and csrf_token; unrelated cookies stripped, no 401 PASS
4 nototal: no meter/percentage, Left 12.5 and Total 0 rows PASS. Note the summary reads "12.5 / 0 credits left" (Some(total=0) formatted as a pair), not "12.5 credits left"; cosmetic
5 expired: "Raycast website session expired. Sign in at www.raycast.com/settings or paste a fresh Cookie header." PASS
6 Settings: Raycast row enabled, cookie source Automatic / Manual / Disabled with Manual selected and helper "Paste a Cookie header from www.raycast.com/settings." PASS (Automatic helper text not checked: selecting Auto would read Chrome)
7 Logs under proof home; real %APPDATA%\CodexBar untouched PASS

Screenshots (local, not committed), C:\Users\FSOS\AppData\Local\Win-CodexBar\port-audit\proof\668\shots\: 01-tray-meter.png, 02-popout-meter.png, 03-settings-providers.png, 04-settings-cookie-source.png, 05-tray-nototal.png, 06-tray-expired.png.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

CUA regression follow-up

Fixes landed at current head b88abef

Findings from the CUA proof, all three fixed:

  1. Build break (check-locale rust=882 vs ts=879). Added ProviderRaycastAutoImportHelp, ProviderRaycastManualCookieHelp, ProviderRaycastCookiesDisabled to apps/desktop-tauri/src/i18n/keys.ts after CookieSourceManual, in the same order as rust/src/locale.rs. check-locale now reports 882 = 882. The keys are consumed by the backend (provider_settings.rs cookie-source help), not by the frontend directly.
  2. "750 / 1000 credits left" not visible for the metered case. Upstream 0.67.0 shows the balance as the metric's detail line under the bar (detailText), with the reset line separate (RaycastMenuCardModelTests; upstream enables it per provider via the descriptor flag showsPrimaryBalanceDescription). The port has no such descriptor flag, so the Raycast provider now marks the window explicitly:
    • RateWindow gains a crate-private detail_description (#[serde(skip)], so the CLI JSON shape is unchanged) with with_detail_description() / detail_description(). Only raycast/parse.rs sets it (metered case).
    • The bridge RateWindowSnapshot carries it as an optional detailDescription (omitted when absent). types/bridge.ts is updated to match.
    • Menu card (MenuCardDetails.tsx): when detailDescription is set, it renders as .menu-metric__detail under the bar and is not reused as the reset fallback. Settings > Providers usage bar and the float-bar tooltip follow the same rule. The compact tray status label no longer treats the balance as a reset phrase.
    • Other providers never set the field, so what they show does not change.
  3. "12.5 / 0 credits left". Credits::summary pairs remaining and total only when the total is positive. A zero or missing total now reads "12.5 credits left". The Left/Total detail rows are unchanged.

Tests added:

  • raycast/tests.rs: the metered window carries the detail line; the zero-allowance case has none. New a_zero_or_missing_total_does_not_appear_in_the_balance_summary checks both cases, and no test expects "/ 0".
  • bridge.rs: detail_description_crosses_the_bridge_and_is_not_a_reset_phrase (camelCase serialization, omitted when absent, tray label stays 25%).
  • MenuCard.test.tsx: a metered window with resetsAt shows "750 / 1000 credits left" as a detail line next to "Resets in ..."; a reset-phrase description ("Resets in 3h") adds no extra detail line and is not shown twice.

Commands run (Rust 1.98.0, E-core wrappers):

  • node apps/desktop-tauri/scripts/check-locale-drift.mjs: OK, 882 keys.
  • cargo +1.98.0 fmt --all --check: clean.
  • cargo +1.98.0 clippy --workspace --all-targets -- -D warnings: clean.
  • cargo +1.98.0 test -p codexbar -- --test-threads=4: 2190 passed, 1 ignored.
  • cargo +1.98.0 test -p codexbar-desktop-tauri -- --test-threads=4: 465 passed, 1 failed. The failure is bootstrap_payload_exposes_every_provider_variant (catalog 80 vs 79). That test builds the catalog from the installed settings on the host, which keeps a deprecated provider in the catalog if it is already enabled. It does not touch code in this diff.
  • pnpm --dir apps/desktop-tauri install --frozen-lockfile, pnpm test (404 passed), pnpm run lint (no errors, only warnings that already existed), pnpm run build (includes check-locale): all pass.

This is a visible UI change: the metered Raycast card gets a new balance line. It needs fresh UI proof on this head.

@Finesssee

Finesssee commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator Author

UI proof (browser-use)

Result: PASS on build b88abef30cc746a34ec4c3e337e41f0e75cdca01, the current PR head "Show Raycast credit balance and fix locale key drift". The three findings from the earlier proof are fixed: the balance detail line shows, the reset text isn't duplicated, and a zero total gives no / 0 summary.

At the maintainer's direction, this proof drove the app's WebView2 over CDP with the browser-use CLI (0.1.13) instead of CUA. It used no keyboard, mouse or focus. The proof windows stayed on the second display, and the kit settings turned the global shortcut off so the proof build didn't take Ctrl+Shift+U.

Setup

  • Build: pnpm run tauri:build:debug at b88abef3 in the worker worktree. The exe was copied to the proof kit.
  • Proof-only patch: never committed, and reverted after the build.
    • A workspace Cargo.toml [patch.crates-io] dirs shim for an isolated home, plus the resulting Cargo.lock change.
    • A CODEXBAR_PROOF_RAYCAST_FIXTURE hook in providers/raycast/mod.rs. It passes a fixture body to the real parse::parse_credits and the real status mapping. CODEXBAR_PROOF_RAYCAST_STATUS=401 exercises the rejected-session path. The provider is https-only, so TLS and URL validation are unchanged. The hook logs the forwarded cookie names (never values).
  • Data: isolated USERPROFILE, HOME, APPDATA, LOCALAPPDATA and provider homes under the kit. Only Raycast is enabled, the cookie source is manual and the theme is auto. The dummy manual cookie header holds unrelated_tracker, __raycast_session, csrf_token and other_cookie.
  • Fixtures: both are copied from this PR's translated upstream tests (rust/src/providers/raycast/tests.rs).
    • meter: the CREDITS constant, 125 of 500 credits, tier pro, renews 2026-10-18.
    • nototal: {"remaining_balance_credits":"12.5","total_balance_credits":"0"}.
  • Commands: VARIANT=meter|nototal|expired bash launch.sh trayPanel exports WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=9335 .... Each run was driven with BU_CDP_URL=http://127.0.0.1:9335 BU_NAME=worker-668 BH_TAB_MARKER=0 browser-use <<'PY' ... PY. curl /json/version first confirmed that port 9335 was this kit's exe (Edg/154 WebView2), the only CodexBar process running.

Results

# Assertion Result
A0 No real email or account from the host is visible. DOM scans of the tray panel (all three variants) and settings found no @ addresses and no host user name. PASS
A1 Dark under theme auto: matchMedia('(prefers-color-scheme: dark)') is true, data-theme=dark, body rgb(28, 28, 30) with text rgb(245, 245, 247), on the tray panel and in settings. PASS
A2 Tray, meter: the Raycast card shows plan Pro, the Credits meter at 75% used, the reset Resets in 17d 2h, and the detail line 125 / 500 credits left (.menu-metric__detail). PASS
A3 Tray, meter: the reset and balance text are not duplicated. There is exactly one .menu-metric__reset and one .menu-metric__detail. PASS
A4 Tray, nototal: the summary reads 12.5 credits left, and no / 0 total appears anywhere in the panel. The bridge has primary.isInformational=true and resetDescription="12.5 credits left". The Left 12.5 / Total 0 rows match upstream v0.67.0 raycast.ts, which keeps both rows when there is no positive-total meter (upstream test zero allowance does not invent a quota window). PASS
A5 Tray, expired (fixture status 401): errorState=expiredSession with "Raycast website session expired. Sign in at www.raycast.com/settings or paste a fresh Cookie header." No stale percentage or credit numbers are shown. PASS
A6 Settings → Providers: Raycast is listed with its icon, manual and 75%. The detail pane shows plan Pro, data source manual, the Usage bar at 75%, "Resets in 17d 2h" and 125 / 500 credits left. PASS
A7 Forwarded cookies: the fixture hook logged ["__raycast_session", "csrf_token"]. unrelated_tracker and other_cookie were not forwarded. PASS
— Tray icon pixels and float bar z-order. Not covered (native, browser-use per maintainer). See the unit tests in rust/src/providers/raycast/tests.rs and apps/desktop-tauri/src-tauri/src/commands/tests.rs.

Validation at b88abef3

Run in the worker worktree on Rust 1.98.0 and Node 24 before the proof build:

Command Result
cargo +1.98.0 fmt --all --check pass
cargo +1.98.0 clippy --workspace --all-targets -- -D warnings pass
cargo +1.98.0 test -p codexbar 2190 passed, 0 failed, 1 ignored
cargo +1.98.0 test -p codexbar-desktop-tauri 465 passed, 1 failed: bootstrap_payload_exposes_every_provider_variant, the non-hermetic #684 test that reads the real %APPDATA%\CodexBar\settings.json. #711 fixes it; it is not caused by this PR.
pnpm install --frozen-lockfile pass
pnpm run check-locale 882 keys match between Rust and TS
pnpm test 67 files, 404 tests passed
pnpm run lint 0 errors (unused-import warnings only, the same as on the base)
pnpm run build pass

Screenshots

All paths are under C:\Users\FSOS\AppData\Local\Win-CodexBar\port-audit\proof\668\shots\:

  • bu-01-tray-meter-overview.png: the compact overview, Credits 75% used.
  • bu-02-tray-meter-selected.png: the Raycast card with Pro, 75% used, Resets in 17d 2h and 125 / 500 credits left.
  • bu-03-settings-providers.png: Settings → Providers → Raycast, dark theme.
  • bu-04-tray-nototal-selected.png: 12.5 credits left, with no / 0.
  • bu-05-tray-expired-selected.png: the session-expired error state.

Not blocking (found on main, not caused by this PR)

  1. Detail rows render twice in the expanded tray card. MenuCardDetails.tsx on main has two identical menu-card__provider-details sections: one guarded by !compactOverview and one unguarded, which a merge resolution in [0.61.0] Expose Antigravity terminal strategy outcomes #574 re-added. So displayDetails rows show twice in the expanded card (the Left / Total rows in nototal here). The fix is tracked with the 0.62.0 Compact Overview parity port (upstream Add compact Overview layouts steipete/CodexBar#2616, branch port/micro-0.62.0-compact-overview-parity), so this PR leaves it alone.
  2. "1 minutes ago". The MinutesAgo / UpdatedMinutesAgo strings in en-US.ftl have no singular form. This is the same on main.
  3. The Settings usage bar is labelled "Session". The settings UsageSection always uses ProviderSessionLabel for the primary window and ignores primaryLabel ("Credits" in the tray). This is generic behavior on main for every provider.

@Finesssee
Finesssee marked this pull request as ready for review September 30, 2026 21:19
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.

1 participant