@bman654/clodex 2.19.0 → 2.20.0
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/README.md +7 -4
- package/dist/cli.js +108 -2
- package/dist/cli.js.map +1 -1
- package/docs/ollama-cloud.md +35 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@bman654/clodex)
|
|
4
4
|
|
|
5
|
-
**clodex** lets you use your ChatGPT/Codex plan, OpenAI API models,
|
|
5
|
+
**clodex** lets you use your ChatGPT/Codex plan, OpenAI API models, OpenCode Go or Ollama Cloud models, or models from a custom OpenAI-compatible server with Claude Code as first-class model choices.
|
|
6
6
|
You can use them anywhere you use Anthropic models like Opus and Sonnet — as the main session model, and in subagents, workflows, and agent teams. Clodex integrates them directly into Claude Code, using Claude Code's system prompt.
|
|
7
7
|
It works with your existing Claude Code plan as well as your Codex plans WITHOUT violating Anthropic's ToS.
|
|
8
8
|
No messing with CMUX or child codex processes or any of that stuff.
|
|
@@ -43,6 +43,7 @@ clodex claude # 5. launch Claude Code on an OpenAI model
|
|
|
43
43
|
| OpenAI (ChatGPT / Codex plan) | OAuth | Fully supported by the clodex maintainer |
|
|
44
44
|
| OpenCode Go | API key | Community-supported — maintained by its contributor |
|
|
45
45
|
| Custom OpenAI-compatible server (OpenRouter, vLLM, …) | API key, or none | Community-supported — maintained by its contributor |
|
|
46
|
+
| Ollama Cloud | API key | Community-supported — maintained by its contributor |
|
|
46
47
|
|
|
47
48
|
**Community-supported** means the maintainer holds no account for that service,
|
|
48
49
|
so it cannot be exercised against the live API here or debugged when the vendor
|
|
@@ -124,7 +125,7 @@ Launch Claude Code bridged to configured model providers. Unrecognized flags (an
|
|
|
124
125
|
| `--dry-run` | Run the wizard but print a launch preview instead of launching (never persists anything) |
|
|
125
126
|
| `--trace` | Write debug logs to `~/.clodex/logs/` and show errors on exit |
|
|
126
127
|
| `--fast` | Request Codex fast mode (`service_tier=priority`) for ChatGPT/Codex OAuth routes; equivalent to `CLODEX_SERVICE_TIER=fast` |
|
|
127
|
-
| `--provider <id>` | Endpoint mode only: boot provider id (`openai`, `openai-oauth`,
|
|
128
|
+
| `--provider <id>` | Endpoint mode only: boot provider id of a configured provider (e.g. `openai`, `openai-oauth`, `opencode-go`, `ollama-cloud`, or `custom-<name>`); with `--model`, skips the wizard |
|
|
128
129
|
| `--model <id>` | Endpoint mode only: boot model id; with `--provider`, skips the wizard |
|
|
129
130
|
| `--context <model=stop>` | Use a different share of a model's context window for this launch only; never saved. Reaches Claude Code through the exported catalog, so a binary patched by `clodex patch` keeps its baked window until the stop is saved and the patch re-run |
|
|
130
131
|
| `--help`, `--version` | Help / version |
|
|
@@ -304,7 +305,7 @@ Two things worth knowing about the numbers:
|
|
|
304
305
|
| Subcommand | Effect |
|
|
305
306
|
| --- | --- |
|
|
306
307
|
| *(none)* | Provider hub wizard |
|
|
307
|
-
| `add` | Add OpenAI
|
|
308
|
+
| `add` | Add OpenAI, OpenCode Go or Ollama Cloud with an API key, add a custom OpenAI-compatible server by base URL, or sign in with ChatGPT |
|
|
308
309
|
| `auth openai` | Sign in with ChatGPT/Codex-plan OAuth (device code; `--browser` for workspaces that disable device codes) |
|
|
309
310
|
| `list` | Show configured providers |
|
|
310
311
|
| `remove <id>` | Remove a provider by id |
|
|
@@ -324,7 +325,9 @@ and their seeded flags when discovery omits them. Models not using Responses-Lit
|
|
|
324
325
|
this version header and are not hidden by this check. This check does not establish your
|
|
325
326
|
account's model entitlement.
|
|
326
327
|
|
|
327
|
-
Providers supported: `openai` (API key, platform.openai.com), `openai-oauth` (ChatGPT/Codex plan),
|
|
328
|
+
Providers supported: `openai` (API key, platform.openai.com), `openai-oauth` (ChatGPT/Codex plan), `opencode-go` (OpenCode Go API key), and `ollama-cloud` (Ollama Cloud API key). OpenCode Go exposes its Anthropic Messages, Chat Completions, and Responses models; only entries whose transport has been verified, live or against OpenCode's per-model endpoint table, are included. See [OpenCode Go provider](docs/opencode-go.md).
|
|
329
|
+
|
|
330
|
+
Ollama Cloud exposes a curated set of four Chat Completions models from `https://ollama.com/v1`; other models Ollama Cloud lists are hidden. See [Ollama Cloud provider](docs/ollama-cloud.md).
|
|
328
331
|
|
|
329
332
|
A **custom OpenAI-compatible server** is any OpenAI-style API, given by its base URL (the part before `/chat/completions`), such as `https://openrouter.ai/api/v1`. `providers add` asks for a name, the base URL and an API key (leave it empty for a local server without auth), lists the server's models to check the connection, and saves the provider as `custom-<name>`. Its models then appear in `clodex models`; once saved as favorites they are addressed as `clodex:custom-<name>:<model>` and can be given a short alias with `clodex models --alias`. The base URL is checked before anything is saved and again when its models are refreshed: plain `http://` is accepted only after you confirm it, and only if every address the host resolves to is on this machine, your LAN or a private network such as Tailscale (loopback, private, unique-local IPv6 or carrier-grade-NAT `100.64.0.0/10` addresses); `https://` is accepted on any of those networks as well as the public internet; and a link-local (`169.254.0.0/16`, `fe80::/10`) or well-known cloud-metadata address is refused whether or not HTTP was approved. A server on another machine in your tailnet can be added by its `100.x` address, its MagicDNS name, or the HTTPS name `tailscale serve` gives it. A model's id and name are stored with surrounding whitespace trimmed, and a model whose trimmed id or name still contains a control character is skipped, whether the list is fetched by `providers add` or by `providers refresh-models`, and error text from the server is shown with control characters replaced by spaces. Only the OpenAI-compatible kind is offered in the menu.
|
|
330
333
|
|
package/dist/cli.js
CHANGED
|
@@ -354,7 +354,7 @@ import { join } from "path";
|
|
|
354
354
|
// package.json
|
|
355
355
|
var package_default = {
|
|
356
356
|
name: "@bman654/clodex",
|
|
357
|
-
version: "2.
|
|
357
|
+
version: "2.20.0",
|
|
358
358
|
publishConfig: {
|
|
359
359
|
access: "public"
|
|
360
360
|
},
|
|
@@ -5437,6 +5437,55 @@ function openCodeGoSessionHeaders(model, claudeSessionId) {
|
|
|
5437
5437
|
return { "x-opencode-session": claudeSessionId ?? OPENCODE_GO_FALLBACK_SESSION_ID };
|
|
5438
5438
|
}
|
|
5439
5439
|
|
|
5440
|
+
// src/data/ollama-cloud-models.ts
|
|
5441
|
+
var OLLAMA_CLOUD_PROVIDER_ID = "ollama-cloud";
|
|
5442
|
+
var OLLAMA_CLOUD_PROVIDER_NAME = "Ollama Cloud";
|
|
5443
|
+
var OLLAMA_CLOUD_COMPLETIONS_BASE_URL = "https://ollama.com/v1";
|
|
5444
|
+
var OPENAI_COMPATIBLE = "@ai-sdk/openai-compatible";
|
|
5445
|
+
var CATALOG = [
|
|
5446
|
+
{
|
|
5447
|
+
id: "kimi-k3",
|
|
5448
|
+
name: "Kimi K3",
|
|
5449
|
+
contextWindow: 1048576,
|
|
5450
|
+
family: "kimi",
|
|
5451
|
+
modalities: ["text", "image"]
|
|
5452
|
+
},
|
|
5453
|
+
{ id: "glm-5.3", name: "GLM-5.3", contextWindow: 1048576, family: "glm", modalities: ["text"] },
|
|
5454
|
+
{
|
|
5455
|
+
id: "glm-5.3-flash",
|
|
5456
|
+
name: "GLM-5.3 Flash",
|
|
5457
|
+
contextWindow: 1048576,
|
|
5458
|
+
family: "glm",
|
|
5459
|
+
modalities: ["text", "image"]
|
|
5460
|
+
},
|
|
5461
|
+
{
|
|
5462
|
+
id: "deepseek-v4.1-flash",
|
|
5463
|
+
name: "DeepSeek V4.1 Flash",
|
|
5464
|
+
contextWindow: 1048576,
|
|
5465
|
+
family: "deepseek",
|
|
5466
|
+
modalities: ["text", "image"]
|
|
5467
|
+
}
|
|
5468
|
+
].map((model) => ({
|
|
5469
|
+
...model,
|
|
5470
|
+
upstreamModelId: model.id,
|
|
5471
|
+
modelFormat: "openai",
|
|
5472
|
+
npm: OPENAI_COMPATIBLE,
|
|
5473
|
+
apiUrl: OLLAMA_CLOUD_COMPLETIONS_BASE_URL,
|
|
5474
|
+
// Ollama publishes pay-as-you-go per-token rates (https://ollama.com/pricing),
|
|
5475
|
+
// but clodex does not record them for this provider: no cost is set, and the
|
|
5476
|
+
// template's preserveModelPricing keeps the global pricing cache off it.
|
|
5477
|
+
compatibility: {
|
|
5478
|
+
supportsStore: false,
|
|
5479
|
+
supportsDeveloperRole: false,
|
|
5480
|
+
maxTokensField: "max_tokens",
|
|
5481
|
+
// Effort mapping is unverified against ollama.com; send none.
|
|
5482
|
+
supportsReasoningEffort: false
|
|
5483
|
+
}
|
|
5484
|
+
}));
|
|
5485
|
+
function buildOllamaCloudModels() {
|
|
5486
|
+
return structuredClone(CATALOG);
|
|
5487
|
+
}
|
|
5488
|
+
|
|
5440
5489
|
// src/provider-templates.ts
|
|
5441
5490
|
async function verifyOpenCodeGoCredential(apiKey) {
|
|
5442
5491
|
const model = buildOpenCodeGoModels().find((entry) => entry.modelFormat === "openai");
|
|
@@ -5482,6 +5531,40 @@ async function verifyOpenCodeGoCredential(apiKey) {
|
|
|
5482
5531
|
}
|
|
5483
5532
|
return null;
|
|
5484
5533
|
}
|
|
5534
|
+
async function verifyOllamaCloudCredential(apiKey) {
|
|
5535
|
+
const model = buildOllamaCloudModels()[0];
|
|
5536
|
+
if (!model) return null;
|
|
5537
|
+
try {
|
|
5538
|
+
const response = await fetch(`${OLLAMA_CLOUD_COMPLETIONS_BASE_URL}/chat/completions`, {
|
|
5539
|
+
method: "POST",
|
|
5540
|
+
headers: {
|
|
5541
|
+
"Content-Type": "application/json",
|
|
5542
|
+
Authorization: `Bearer ${apiKey}`
|
|
5543
|
+
},
|
|
5544
|
+
body: JSON.stringify({ model: model.upstreamModelId ?? model.id }),
|
|
5545
|
+
signal: AbortSignal.timeout(TEST_TIMEOUT_MS)
|
|
5546
|
+
});
|
|
5547
|
+
if (response.status === 401 || response.status === 403) {
|
|
5548
|
+
let entitlement = false;
|
|
5549
|
+
if (response.status === 403) {
|
|
5550
|
+
const text6 = await response.text().catch(() => "");
|
|
5551
|
+
entitlement = /\b(?:subscription|plan|upgrade|quota|model|access)\b/i.test(text6) && !/\bapi[ _-]?key\b/i.test(text6);
|
|
5552
|
+
} else {
|
|
5553
|
+
await response.body?.cancel?.().catch(() => void 0);
|
|
5554
|
+
}
|
|
5555
|
+
if (!entitlement) {
|
|
5556
|
+
return "Ollama Cloud rejected this API key (authentication failed). Check the key and try again.";
|
|
5557
|
+
}
|
|
5558
|
+
} else {
|
|
5559
|
+
try {
|
|
5560
|
+
await response.body?.cancel?.();
|
|
5561
|
+
} catch {
|
|
5562
|
+
}
|
|
5563
|
+
}
|
|
5564
|
+
} catch {
|
|
5565
|
+
}
|
|
5566
|
+
return null;
|
|
5567
|
+
}
|
|
5485
5568
|
var PROVIDER_TEMPLATES = [
|
|
5486
5569
|
{
|
|
5487
5570
|
id: "openai",
|
|
@@ -5493,6 +5576,24 @@ var PROVIDER_TEMPLATES = [
|
|
|
5493
5576
|
modelSource: "api-list",
|
|
5494
5577
|
supported: true
|
|
5495
5578
|
},
|
|
5579
|
+
{
|
|
5580
|
+
id: OLLAMA_CLOUD_PROVIDER_ID,
|
|
5581
|
+
name: OLLAMA_CLOUD_PROVIDER_NAME,
|
|
5582
|
+
authType: "api",
|
|
5583
|
+
npm: "@ai-sdk/openai-compatible",
|
|
5584
|
+
defaultBaseUrl: OLLAMA_CLOUD_COMPLETIONS_BASE_URL,
|
|
5585
|
+
modelsPath: "/models",
|
|
5586
|
+
signupUrl: "https://ollama.com",
|
|
5587
|
+
modelSource: "api-list",
|
|
5588
|
+
verifyCredential: verifyOllamaCloudCredential,
|
|
5589
|
+
// Getter for the same reason as opencode-go: no eager catalog clone at import.
|
|
5590
|
+
get staticModels() {
|
|
5591
|
+
return buildOllamaCloudModels();
|
|
5592
|
+
},
|
|
5593
|
+
staticModelPolicy: "allowlist",
|
|
5594
|
+
preserveModelPricing: true,
|
|
5595
|
+
supported: true
|
|
5596
|
+
},
|
|
5496
5597
|
{
|
|
5497
5598
|
id: OPENCODE_GO_PROVIDER_ID,
|
|
5498
5599
|
name: OPENCODE_GO_PROVIDER_NAME,
|
|
@@ -11221,6 +11322,10 @@ async function createLanguageModel(spec) {
|
|
|
11221
11322
|
...spec.authType !== "none" && apiKey.trim() ? { apiKey } : {},
|
|
11222
11323
|
...spec.authType === "none" ? { fetch: fetchWithoutCredentialHeaders } : {},
|
|
11223
11324
|
...spec.headers ? { headers: spec.headers } : {},
|
|
11325
|
+
// ollama.com sends a streamed usage chunk only when the request carries
|
|
11326
|
+
// stream_options.include_usage (observed 2026-10-13); without it every
|
|
11327
|
+
// streamed turn reports output_tokens 0. Scoped to this provider only.
|
|
11328
|
+
...spec.providerId === OLLAMA_CLOUD_PROVIDER_ID ? { includeUsage: true } : {},
|
|
11224
11329
|
...spec.compatibility ? {
|
|
11225
11330
|
transformRequestBody: (body) => transformOpenAiCompatibleRequestBody(body, spec.compatibility)
|
|
11226
11331
|
} : {}
|
|
@@ -22714,7 +22819,7 @@ function parseArgs(args) {
|
|
|
22714
22819
|
}
|
|
22715
22820
|
function rootHelpText() {
|
|
22716
22821
|
return `${pc13.bold("clodex")} v${VERSION}
|
|
22717
|
-
Bridge Claude Code to OpenAI
|
|
22822
|
+
Bridge Claude Code to OpenAI, OpenCode Go, Ollama Cloud and custom OpenAI-compatible models.
|
|
22718
22823
|
|
|
22719
22824
|
${pc13.bold("Usage:")}
|
|
22720
22825
|
clodex claude [options] [claude-flags]
|
|
@@ -22796,6 +22901,7 @@ ${pc13.bold("Providers:")}
|
|
|
22796
22901
|
openai OpenAI API key (platform.openai.com)
|
|
22797
22902
|
openai-oauth ChatGPT/Codex plan OAuth \u2014 sign in with clodex providers auth openai
|
|
22798
22903
|
opencode-go OpenCode Go API key \u2014 add with clodex providers add
|
|
22904
|
+
ollama-cloud Ollama Cloud API key \u2014 add with clodex providers add
|
|
22799
22905
|
custom-<name> Any OpenAI-compatible server (OpenRouter, LM Studio, \u2026) \u2014 add with clodex providers add
|
|
22800
22906
|
|
|
22801
22907
|
${pc13.bold("Model switching:")}
|