Skip to content

feat(provider): custom API provider profiles store + CLI (PR-1) - #67

Merged
xjoker merged 1 commit into
devfrom
cursor/provider-profiles-store-5a91
Aug 26, 2026
Merged

feat(provider): custom API provider profiles store + CLI (PR-1)#67
xjoker merged 1 commit into
devfrom
cursor/provider-profiles-store-5a91

Conversation

@xjoker

@xjoker xjoker commented Aug 26, 2026

Copy link
Copy Markdown
Owner

First slice of custom-provider support (方案 A). Lets codex-switch target a third-party OpenAI-compatible endpoint (OpenRouter, an LLM proxy, …) instead of only ChatGPT OAuth accounts. Storage + CLI only — launch integration is PR-2, and nothing is written to ~/.codex yet.

What's in this PR

  • src/provider.rs: ProviderProfile model + private storage under $CODEX_SWITCH_HOME/providers/<alias>/provider.toml (dir 0700, file 0600), validation, key redaction, and helpers.
    • env_key is derived from the codex-switch alias (CODEX_SWITCH_<ALIAS>_KEY) so the injected key never collides with a provider's own env var. (Per decision: inherit our internal name.)
    • provider_id is sanitized from the alias and rejected if it collides with Codex's reserved ids (openai/ollama/lmstudio).
    • validate() enforces non-empty name (Codex requires it), http(s):// base_url, valid env-var name, non-empty model/key.
  • CLI: codex-switch provider add | list | show | remove.
    • Security (per decision): the API key is read from a hidden prompt (rpassword) or --api-key-stdinnever from the command line (so it can't leak via argv/ps/shell history) — and is redacted in list/show/--json output (has_key/…1234).

Design context (verified with real Codex CLI 0.149.1)

The eventual launch path (PR-2) will translate a provider profile into codex -c … overrides + inject the key into the child's env under env_key. Verified empirically that this needs zero writes to ~/.codex, preserves base-config MCP servers, and requires a non-empty provider name. This PR is the storage/CLI foundation for that.

Out of scope here: launch integration (PR-2), TUI add flow (PR-3), docs (PR-4), provider use-mode, DeepSeek-via-OpenRouter guidance.

Tests

src/provider.rs unit tests: env_key derivation, id sanitization, validation (reserved id / empty name / bad url / empty key), key redaction, 0600 file permissions, and save/load/list/remove round-trip.

Manual CLI smoke (isolated home): provider add (key via stdin) → stored 0600, env_key = CODEX_SWITCH_OPENROUTER_KEY; list/--json and show never expose the key (redacted …1234); duplicate add errors; remove works.

Verification (Linux)

cargo fmt --check, cargo clippy --all-targets --all-features -- -D warnings, cargo test --all — all pass, 0 failed.

Adds dependency rpassword (7.x) for the hidden key prompt.

Note: CI Format and audit will be red until #63 (webbrowser RUSTSEC bump) merges to dev; that failure is pre-existing and unrelated.

Open in Web Open in Cursor 

First slice of custom-provider support (方案 A). Adds a provider-profile
type that lets codex-switch target a third-party OpenAI-compatible endpoint
(OpenRouter, an LLM proxy, ...) instead of a ChatGPT OAuth account.

- src/provider.rs: ProviderProfile model + private storage under
  $CODEX_SWITCH_HOME/providers/<alias>/provider.toml (dir 0700, file 0600),
  validation (reserved-id/name/base_url/env_key/model checks), key redaction,
  and env_key derived from the codex-switch alias (CODEX_SWITCH_<ALIAS>_KEY)
  so the injected key never collides with a provider's own variable.
- CLI: codex-switch provider add/list/show/remove. The API key is read from a
  hidden prompt (rpassword) or --api-key-stdin, never from argv, and is
  redacted in list/show/--json output.

Storage only; launch integration is PR-2. Nothing is written to ~/.codex yet.

Unit tests cover env_key derivation, id sanitization, validation, redaction,
0600 permissions, and save/load/list/remove round-trip. Adds rpassword.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
@xjoker
xjoker marked this pull request as ready for review August 26, 2026 04:57
@xjoker
xjoker merged commit 80263ef into dev Aug 26, 2026
4 checks passed
cursor Bot pushed a commit that referenced this pull request Aug 26, 2026
Brings the whole custom-API-provider stack (#67-#73) up to date with dev
(webbrowser 1.2.4, pay-per-use credits column, etc). The only conflict was
src/tui/ui.rs: kept both dev's credits_table_* helpers and the provider
tab/panel renderers, and merged the test-module imports. Full suite: 1019 passed.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Aug 26, 2026
Real dev already carries #67 (provider store) and #72 (env config). Re-merged
the true dev HEAD and resolved the add/add conflicts in provider.rs / cli.rs /
commands/provider.rs by keeping the provider-docs full-feature versions
(verified supersets of dev's #67). environment.json (#72) merged in cleanly.
This PR now cleanly adds #68-#73 (launch / TUI / docs / codex overrides) that
are not yet in dev. Full suite: 1019 passed.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
xjoker added a commit that referenced this pull request Aug 26, 2026
Completes the custom API provider feature. #67 (profiles store + CLI) and #72
(Cloud Agent environment) are already on dev; this adds the remaining pieces as
a single clean commit on top of dev so the repo's rebase-and-merge can apply it
without conflicts:

- launch <provider>: codex -c overrides + env-injected API key (never argv,
  never ~/.codex/auth.json)
- TUI Accounts/Providers tabs + add/remove provider wizard
- per-provider Codex overrides: --set KEY=VALUE, --reasoning, --no-web-search,
  and matching TUI wizard steps (values passed to Codex verbatim)
- provider documentation (docs/wiki/Providers.md, etc.)

The original per-PR history is preserved in the already-merged #68-#73.
Full suite: 1019 passed.

Co-authored-by: xJoker <xjoker@users.noreply.github.com>
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