@koreanhole/opencodex 3.2.10 → 3.2.12
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/AGENTS_INSTALL.md +4 -2
- package/README.md +8 -5
- package/package.json +1 -1
- package/src/adapters/cli-agent/cline/adapter.ts +2 -2
- package/src/adapters/cli-agent/cline/env.ts +26 -0
- package/src/adapters/cli-agent/cline/json.ts +2 -2
- package/src/adapters/cli-agent/cline/live-models.ts +10 -117
- package/src/adapters/cli-agent/cline/login.ts +85 -0
- package/src/adapters/cli-agent/cline/stream.ts +1 -1
- package/src/cli/index.ts +8 -6
- package/src/lib/codex-catalog.ts +3 -3
- package/src/server/index.ts +1 -3
- package/src/server/responses.ts +6 -7
package/AGENTS_INSTALL.md
CHANGED
|
@@ -43,11 +43,13 @@ or through the documented default path; unrelated Codex settings are not changed
|
|
|
43
43
|
|
|
44
44
|
## Credential rules
|
|
45
45
|
|
|
46
|
-
- Use the operator's existing Cline or Gemini CLI sign-in.
|
|
46
|
+
- Use the operator's existing Cline or Gemini CLI sign-in. Cline login is
|
|
47
|
+
vendor-managed through `cline auth`; the adapter has no ACP login or discovery
|
|
48
|
+
dependency. Do not copy vendor
|
|
47
49
|
tokens into config, environment files, logs, prompts, or package content. The
|
|
48
50
|
only exception is Cline's mode-0600 request-scoped staging copy.
|
|
49
51
|
- Do not authenticate on a request path. If Cline reports `auth_required`, stop
|
|
50
|
-
and ask the operator to run `ocx login cline-cli
|
|
52
|
+
and ask the operator to run `ocx login cline-cli` or `cline auth` directly.
|
|
51
53
|
- Do not edit the operator's real Cline provider store or legacy
|
|
52
54
|
`globalState.json`/`secrets.json`. Read them only to create mode-0600
|
|
53
55
|
request-scoped copies; remove those copies after the turn.
|
package/README.md
CHANGED
|
@@ -54,9 +54,11 @@ model management, service lifecycle, and restore behavior remain available
|
|
|
54
54
|
through the same `ocx` command.
|
|
55
55
|
|
|
56
56
|
The managed provider rows appear as `gemini-cli/...` and `cline-cli/...`.
|
|
57
|
-
Cline
|
|
58
|
-
the
|
|
59
|
-
|
|
57
|
+
Cline does not require ACP: it exposes a stable `default` selector that follows
|
|
58
|
+
the model already selected in Cline, while Cline model turns use the installed
|
|
59
|
+
CLI's JSON transport across the 2.2.0 and current output contracts. Explicit
|
|
60
|
+
`ocx login cline-cli` delegates to the vendor `cline auth` command. Gemini runtime
|
|
61
|
+
model discovery uses the
|
|
60
62
|
installed CLI's ACP session, while reasoning metadata and model turns use the
|
|
61
63
|
installed CLI's headless transport. Parent-declared tools are exposed through a
|
|
62
64
|
request-scoped capture MCP server.
|
|
@@ -137,8 +139,9 @@ the blocker.
|
|
|
137
139
|
- Cline runs with request-scoped, mode-0600 settings. Its built-in tools, user
|
|
138
140
|
MCP servers, hooks, plugins, telemetry, updates, and self-approval are disabled.
|
|
139
141
|
Modern provider state and legacy global/secrets state are copied privately;
|
|
140
|
-
the originals are never modified.
|
|
141
|
-
installed binary's `--help` output advertises
|
|
142
|
+
the originals are never modified. No Cline runtime path requires ACP. Its turn
|
|
143
|
+
options are used only after the installed binary's `--help` output advertises
|
|
144
|
+
them.
|
|
142
145
|
- Gemini headless turns run in a request-scoped workspace with
|
|
143
146
|
`GEMINI_CLI_TRUST_WORKSPACE=true`, `--skip-trust`, and
|
|
144
147
|
`--approval-mode auto_edit`, but the generated isolated Gemini home settings
|
package/package.json
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
type ClineStagedTurn,
|
|
20
20
|
} from "./settings";
|
|
21
21
|
import { resolveClineBinary } from "./binary";
|
|
22
|
-
import {
|
|
22
|
+
import { buildClineProbeEnv } from "./env";
|
|
23
23
|
import {
|
|
24
24
|
buildClineJsonArgs,
|
|
25
25
|
ClineJsonError,
|
|
@@ -189,7 +189,7 @@ export async function runClineTurn(
|
|
|
189
189
|
return;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
const probeEnv =
|
|
192
|
+
const probeEnv = buildClineProbeEnv(sourceEnv);
|
|
193
193
|
let capabilities: ClineJsonCapabilities;
|
|
194
194
|
try {
|
|
195
195
|
capabilities = await (deps.probeJson ?? probeClineJsonCapabilities)(binary, probeEnv, deps);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { baseScopedEnv } from "../env";
|
|
3
|
+
|
|
4
|
+
function nonEmpty(value: unknown): string | undefined {
|
|
5
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Build a real-home environment for bounded Cline capability probes. */
|
|
9
|
+
export function buildClineProbeEnv(sourceEnv: NodeJS.ProcessEnv = process.env): Record<string, string> {
|
|
10
|
+
const env = baseScopedEnv(sourceEnv);
|
|
11
|
+
const realHome = nonEmpty(sourceEnv.HOME) ?? nonEmpty(sourceEnv.USERPROFILE) ?? homedir();
|
|
12
|
+
env.HOME = realHome;
|
|
13
|
+
env.USERPROFILE = realHome;
|
|
14
|
+
for (const key of ["XDG_CONFIG_HOME", "XDG_CACHE_HOME", "CLINE_DIR", "CLINE_DATA_DIR", "CLINE_PROVIDER_SETTINGS_PATH"]) {
|
|
15
|
+
const value = nonEmpty(sourceEnv[key]);
|
|
16
|
+
if (value) env[key] = value;
|
|
17
|
+
}
|
|
18
|
+
Object.assign(env, {
|
|
19
|
+
CLINE_NO_AUTO_UPDATE: "1",
|
|
20
|
+
CLINE_TELEMETRY_DISABLED: "1",
|
|
21
|
+
CLINE_DISABLE_CLINE_PASS_NOTICE: "1",
|
|
22
|
+
NO_UPDATE_NOTIFIER: "1",
|
|
23
|
+
NO_COLOR: "1",
|
|
24
|
+
});
|
|
25
|
+
return env;
|
|
26
|
+
}
|
|
@@ -8,7 +8,7 @@ import { redactSecretString } from "../../../lib/redact";
|
|
|
8
8
|
import { commandInvocation } from "../../../lib/win-exec";
|
|
9
9
|
import { CodingAgentProtocolError, readJsonLines } from "../protocol";
|
|
10
10
|
import type { CliAgentTurnDeps } from "../types";
|
|
11
|
-
import {
|
|
11
|
+
import { buildClineProbeEnv } from "./env";
|
|
12
12
|
import type { ClineSelection } from "./settings";
|
|
13
13
|
import {
|
|
14
14
|
classifyClineFailure,
|
|
@@ -197,7 +197,7 @@ function probeFailure(code: string, detail: string): ClineJsonError {
|
|
|
197
197
|
|
|
198
198
|
export async function probeClineJsonCapabilities(
|
|
199
199
|
binary: string,
|
|
200
|
-
env: Record<string, string> =
|
|
200
|
+
env: Record<string, string> = buildClineProbeEnv(),
|
|
201
201
|
deps: CliAgentTurnDeps = {},
|
|
202
202
|
): Promise<ClineJsonCapabilities> {
|
|
203
203
|
const path = resolve(binary);
|
|
@@ -1,128 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
clineModelSource,
|
|
5
|
-
probeClineAcpSupport,
|
|
6
|
-
stageClineAcpWorkspace,
|
|
7
|
-
type ClineAcpDeps,
|
|
8
|
-
} from "./acp";
|
|
9
|
-
import { clineBinaryFingerprintSync, resolveClineBinary } from "./binary";
|
|
10
|
-
import { AcpClient, AcpError } from "../acp-client";
|
|
11
|
-
|
|
12
|
-
export type ClineLiveModelsFailure = "not_found" | "unsupported" | "auth_required" | "backoff" | "transport";
|
|
1
|
+
import { whichFromPath, type WhichFn } from "../../coding-agent/profile";
|
|
2
|
+
import type { CliAgentTurnDeps } from "../types";
|
|
3
|
+
import { resolveClineBinary } from "./binary";
|
|
13
4
|
|
|
14
5
|
export type ClineLiveModelsResult =
|
|
15
|
-
| {
|
|
16
|
-
|
|
17
|
-
models: string[];
|
|
18
|
-
source: "models" | "configOptions" | "default";
|
|
19
|
-
fingerprint: string;
|
|
20
|
-
stale?: true;
|
|
21
|
-
}
|
|
22
|
-
| {
|
|
23
|
-
ok: false;
|
|
24
|
-
reason: ClineLiveModelsFailure;
|
|
25
|
-
detail: string;
|
|
26
|
-
fingerprint?: string;
|
|
27
|
-
};
|
|
6
|
+
| { ok: true; models: ["default"]; source: "default" }
|
|
7
|
+
| { ok: false; reason: "not_found"; detail: string };
|
|
28
8
|
|
|
29
9
|
export interface ClineLiveModelsOptions {
|
|
30
10
|
binary?: string;
|
|
31
11
|
env?: NodeJS.ProcessEnv;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
failureBackoffMs?: number;
|
|
35
|
-
now?: () => number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
interface CacheEntry {
|
|
39
|
-
models: string[];
|
|
40
|
-
source: "models" | "configOptions" | "default";
|
|
41
|
-
fetchedAt: number;
|
|
42
|
-
lastFailureAt?: number;
|
|
12
|
+
which?: WhichFn;
|
|
13
|
+
deps?: CliAgentTurnDeps;
|
|
43
14
|
}
|
|
44
15
|
|
|
45
|
-
|
|
46
|
-
const failureCache = new Map<string, number>();
|
|
47
|
-
|
|
48
|
-
export function resetClineLiveModelsCacheForTests(): void {
|
|
49
|
-
cache.clear();
|
|
50
|
-
failureCache.clear();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function staleResult(fingerprint: string, entry: CacheEntry | undefined): ClineLiveModelsResult | undefined {
|
|
54
|
-
if (!entry) return undefined;
|
|
55
|
-
return {
|
|
56
|
-
ok: true,
|
|
57
|
-
models: [...entry.models],
|
|
58
|
-
source: entry.source,
|
|
59
|
-
fingerprint,
|
|
60
|
-
stale: true,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Discover Cline's native model roster with TTL, stale fallback, and failure backoff. */
|
|
16
|
+
/** Cline has no ACP-free model enumeration; default uses its persisted selection. */
|
|
65
17
|
export async function discoverClineLiveModels(options: ClineLiveModelsOptions = {}): Promise<ClineLiveModelsResult> {
|
|
66
|
-
const
|
|
67
|
-
const now = options.now ?? Date.now;
|
|
68
|
-
const ttlMs = options.ttlMs ?? 5 * 60_000;
|
|
69
|
-
const failureBackoffMs = options.failureBackoffMs ?? 60_000;
|
|
70
|
-
if (!clineAcpEnabled(sourceEnv)) {
|
|
71
|
-
return { ok: false, reason: "unsupported", detail: "ACP is disabled by OPENCODEX_CLINE_ACP=0." };
|
|
72
|
-
}
|
|
73
|
-
const binary = options.binary ?? resolveClineBinary(undefined, sourceEnv);
|
|
18
|
+
const binary = options.binary ?? resolveClineBinary(options.which ?? whichFromPath, options.env ?? process.env);
|
|
74
19
|
if (!binary) return { ok: false, reason: "not_found", detail: "Cline CLI not found on PATH." };
|
|
75
|
-
|
|
76
|
-
const current = cache.get(fingerprint);
|
|
77
|
-
const timestamp = now();
|
|
78
|
-
if (current && timestamp - current.fetchedAt < ttlMs) {
|
|
79
|
-
return { ok: true, models: [...current.models], source: current.source, fingerprint };
|
|
80
|
-
}
|
|
81
|
-
const lastFailure = failureCache.get(fingerprint) ?? current?.lastFailureAt;
|
|
82
|
-
if (lastFailure !== undefined && timestamp - lastFailure < failureBackoffMs) {
|
|
83
|
-
return staleResult(fingerprint, current)
|
|
84
|
-
?? { ok: false, reason: "backoff", detail: "Cline model discovery is cooling down after a failure.", fingerprint };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const env = buildClineAcpEnv(sourceEnv);
|
|
88
|
-
const mode = await probeClineAcpSupport(binary, env, { ...options.deps, env: sourceEnv });
|
|
89
|
-
if (!mode.acp) {
|
|
90
|
-
failureCache.set(fingerprint, timestamp);
|
|
91
|
-
if (current) current.lastFailureAt = timestamp;
|
|
92
|
-
return staleResult(fingerprint, current)
|
|
93
|
-
?? { ok: false, reason: "unsupported", detail: "Cline --help does not advertise --acp.", fingerprint };
|
|
94
|
-
}
|
|
95
|
-
const workspace = await stageClineAcpWorkspace();
|
|
96
|
-
let client: AcpClient | undefined;
|
|
97
|
-
try {
|
|
98
|
-
client = await AcpClient.connect({
|
|
99
|
-
binary,
|
|
100
|
-
env,
|
|
101
|
-
cwd: workspace.cwd,
|
|
102
|
-
args: mode.autoApproveFlag ? ["--acp", "--auto-approve", "false"] : ["--acp"],
|
|
103
|
-
label: "Cline ACP",
|
|
104
|
-
fallbackAllowed: true,
|
|
105
|
-
}, options.deps);
|
|
106
|
-
const session = await client.newSession({ cwd: workspace.cwd, mcpServers: [] });
|
|
107
|
-
const discovered = clineModelSource(session);
|
|
108
|
-
cache.set(fingerprint, { models: discovered.ids, source: discovered.source, fetchedAt: timestamp });
|
|
109
|
-
failureCache.delete(fingerprint);
|
|
110
|
-
return { ok: true, models: discovered.ids, source: discovered.source, fingerprint };
|
|
111
|
-
} catch (error) {
|
|
112
|
-
failureCache.set(fingerprint, timestamp);
|
|
113
|
-
if (current) current.lastFailureAt = timestamp;
|
|
114
|
-
const stale = staleResult(fingerprint, current);
|
|
115
|
-
if (error instanceof AcpError && error.authRequired) {
|
|
116
|
-
return stale ?? { ok: false, reason: "auth_required", detail: error.message, fingerprint };
|
|
117
|
-
}
|
|
118
|
-
return stale ?? {
|
|
119
|
-
ok: false,
|
|
120
|
-
reason: "transport",
|
|
121
|
-
detail: error instanceof Error ? error.message : String(error),
|
|
122
|
-
fingerprint,
|
|
123
|
-
};
|
|
124
|
-
} finally {
|
|
125
|
-
await client?.terminate();
|
|
126
|
-
await workspace.cleanup();
|
|
127
|
-
}
|
|
20
|
+
return { ok: true, models: ["default"], source: "default" };
|
|
128
21
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { spawn as nodeSpawn } from "node:child_process";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { commandInvocation } from "../../../lib/win-exec";
|
|
4
|
+
import { whichFromPath, type WhichFn } from "../../coding-agent/profile";
|
|
5
|
+
import type { CliAgentSpawnFn } from "../types";
|
|
6
|
+
import { resolveClineBinary } from "./binary";
|
|
7
|
+
|
|
8
|
+
const VENDOR_LOGIN_INSTRUCTION = "Cline authentication is managed by Cline CLI. Run `cline auth` in an interactive terminal.";
|
|
9
|
+
|
|
10
|
+
export class ClineLoginError extends Error {
|
|
11
|
+
constructor(
|
|
12
|
+
message: string,
|
|
13
|
+
readonly status: number,
|
|
14
|
+
readonly code: string,
|
|
15
|
+
) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "ClineLoginError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ClineLoginOptions {
|
|
22
|
+
instructionsOnly?: boolean;
|
|
23
|
+
env?: NodeJS.ProcessEnv;
|
|
24
|
+
which?: WhichFn;
|
|
25
|
+
spawn?: CliAgentSpawnFn;
|
|
26
|
+
platform?: NodeJS.Platform;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ClineLoginResult {
|
|
30
|
+
mode: "vendor" | "instruction";
|
|
31
|
+
complete: boolean;
|
|
32
|
+
exitCode: number;
|
|
33
|
+
instructions?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Explicit login delegates to the real vendor CLI and never uses ACP. */
|
|
37
|
+
export async function loginCline(options: ClineLoginOptions = {}): Promise<ClineLoginResult> {
|
|
38
|
+
const env = options.env ?? process.env;
|
|
39
|
+
const binary = resolveClineBinary(options.which ?? whichFromPath, env);
|
|
40
|
+
if (!binary) {
|
|
41
|
+
throw new ClineLoginError(
|
|
42
|
+
"Cline CLI not found on PATH. Install it with `npm install -g cline` or set CLINE_BIN_PATH.",
|
|
43
|
+
500,
|
|
44
|
+
"cli_not_found",
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (options.instructionsOnly) {
|
|
48
|
+
return {
|
|
49
|
+
mode: "instruction",
|
|
50
|
+
complete: false,
|
|
51
|
+
exitCode: 0,
|
|
52
|
+
instructions: VENDOR_LOGIN_INSTRUCTION,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const invocation = commandInvocation(binary, ["auth"], options.platform ?? process.platform, { env });
|
|
57
|
+
const spawnFn = options.spawn ?? (nodeSpawn as unknown as CliAgentSpawnFn);
|
|
58
|
+
const cwd = env.HOME?.trim() || env.USERPROFILE?.trim() || homedir();
|
|
59
|
+
return await new Promise<ClineLoginResult>((resolvePromise, reject) => {
|
|
60
|
+
let child;
|
|
61
|
+
try {
|
|
62
|
+
child = spawnFn(invocation.file, invocation.args, {
|
|
63
|
+
...invocation.options,
|
|
64
|
+
cwd,
|
|
65
|
+
env,
|
|
66
|
+
stdio: "inherit",
|
|
67
|
+
windowsHide: true,
|
|
68
|
+
});
|
|
69
|
+
} catch (error) {
|
|
70
|
+
reject(new ClineLoginError(
|
|
71
|
+
`Cline authentication could not start: ${error instanceof Error ? error.message : String(error)}`,
|
|
72
|
+
500,
|
|
73
|
+
"cli_spawn_failed",
|
|
74
|
+
));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
child.once("error", error => {
|
|
78
|
+
reject(new ClineLoginError(`Cline authentication could not start: ${error.message}`, 500, "cli_spawn_failed"));
|
|
79
|
+
});
|
|
80
|
+
child.once("close", code => {
|
|
81
|
+
const exitCode = code ?? 1;
|
|
82
|
+
resolvePromise({ mode: "vendor", complete: exitCode === 0, exitCode });
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -30,7 +30,7 @@ export function createClineStreamState(): CliAgentStreamState {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/** Map a validated Cline
|
|
33
|
+
/** Map a validated Cline tool intent into events owned by Codex. */
|
|
34
34
|
export function mapClineToolIntent(
|
|
35
35
|
vendorName: string,
|
|
36
36
|
toolCallId: string | undefined,
|
package/src/cli/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
type ProviderId,
|
|
18
18
|
} from "../config";
|
|
19
19
|
import { startServer } from "../server";
|
|
20
|
-
import {
|
|
20
|
+
import { loginCline } from "../adapters/cli-agent/cline/login";
|
|
21
21
|
import { runCodingAgentMcpServer } from "../adapters/cli-agent/mcp-server";
|
|
22
22
|
import { syncCodexCatalog } from "../lib/codex-catalog";
|
|
23
23
|
import { injectCodexConfig, recordCodexCatalogState, restoreCodexConfig } from "../lib/codex-inject";
|
|
@@ -154,21 +154,23 @@ async function loginCommand(args: string[]): Promise<number> {
|
|
|
154
154
|
const json = takeFlag(args, "--json");
|
|
155
155
|
const noWait = takeFlag(args, "--no-wait");
|
|
156
156
|
if (args.length > 0) throw new ConfigError(`Unknown login option: ${args[0]}`);
|
|
157
|
-
const result = await
|
|
157
|
+
const result = await loginCline({ instructionsOnly: noWait || json, env: process.env });
|
|
158
158
|
if (json) {
|
|
159
159
|
console.log(JSON.stringify({
|
|
160
160
|
ok: true,
|
|
161
161
|
provider: CLINE_PROVIDER_ID,
|
|
162
|
-
|
|
163
|
-
selectedMethod: result.method.id,
|
|
162
|
+
selectedMethod: "vendor-cli",
|
|
164
163
|
complete: result.complete,
|
|
165
164
|
instructions: result.instructions,
|
|
166
165
|
}));
|
|
167
166
|
} else {
|
|
168
167
|
if (result.instructions) process.stderr.write(result.instructions);
|
|
169
|
-
|
|
168
|
+
if (result.mode === "vendor") {
|
|
169
|
+
if (result.complete) console.log("Cline login complete.");
|
|
170
|
+
else console.error("Cline authentication did not complete.");
|
|
171
|
+
}
|
|
170
172
|
}
|
|
171
|
-
return
|
|
173
|
+
return result.exitCode;
|
|
172
174
|
}
|
|
173
175
|
|
|
174
176
|
async function startCommand(args: string[]): Promise<number> {
|
package/src/lib/codex-catalog.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { discoverGeminiLiveModels } from "../adapters/cli-agent/gemini/live-mode
|
|
|
7
7
|
import type { ClineTurnDeps } from "../adapters/cli-agent/cline/adapter";
|
|
8
8
|
import type { GeminiTurnDeps } from "../adapters/cli-agent/gemini/adapter";
|
|
9
9
|
|
|
10
|
-
// Cline
|
|
10
|
+
// Cline exposes no runtime context source; this fallback is Cline-only.
|
|
11
11
|
const CATALOG_FALLBACK_CONTEXT = 128_000;
|
|
12
12
|
const BASE_INSTRUCTIONS = "You are a helpful coding assistant.";
|
|
13
13
|
const MANAGED_PREFIXES = ["cline-cli/", "gemini-cli/"] as const;
|
|
@@ -131,7 +131,7 @@ export function buildCodexCatalogModel(providerId: "cline-cli" | "gemini-cli", m
|
|
|
131
131
|
: 100;
|
|
132
132
|
return {
|
|
133
133
|
slug: `${providerId}/${encodeRoutedId(model.id)}`,
|
|
134
|
-
display_name: model.name ?? (isDefault ? `${providerLabel} default` : model.id),
|
|
134
|
+
display_name: model.name ?? (isDefault ? (providerId === "cline-cli" ? "Cline" : `${providerLabel} default`) : model.id),
|
|
135
135
|
description: model.description ?? `Routed via opencodex -> ${providerLabel}.`,
|
|
136
136
|
default_reasoning_level: levels.length > 0 ? defaultLevel : "low",
|
|
137
137
|
supported_reasoning_levels: levels,
|
|
@@ -205,7 +205,7 @@ export async function discoverCodexCatalogModels(options: CodexCatalogDiscoveryO
|
|
|
205
205
|
}),
|
|
206
206
|
]);
|
|
207
207
|
const warnings: string[] = [];
|
|
208
|
-
if (!cline.ok && cline.reason !== "not_found"
|
|
208
|
+
if (!cline.ok && cline.reason !== "not_found") warnings.push(`Cline: ${cline.detail}`);
|
|
209
209
|
if (!gemini.ok && gemini.reason !== "not_found" && env.OPENCODEX_GEMINI_ACP?.trim() !== "0") warnings.push(`Gemini: ${gemini.detail}`);
|
|
210
210
|
if (gemini.ok && gemini.metadataWarning) warnings.push(`Gemini metadata: ${gemini.metadataWarning}`);
|
|
211
211
|
const clineModels = normalizedModels(cline.ok ? cline.models.map(id => ({ id })) : []);
|
package/src/server/index.ts
CHANGED
|
@@ -106,9 +106,7 @@ async function discoverModels(
|
|
|
106
106
|
? discoverGeminiLiveModels({ env, ...(geminiDeps ? { deps: geminiDeps } : {}), ...(geminiPackageRoot ? { packageRoot: geminiPackageRoot } : {}) })
|
|
107
107
|
: undefined,
|
|
108
108
|
]);
|
|
109
|
-
if (cline && !cline.ok && cline.reason !== "not_found"
|
|
110
|
-
console.warn(`[opencodex] Cline model discovery degraded [${cline.reason}]: ${cline.detail}`);
|
|
111
|
-
}
|
|
109
|
+
if (cline && !cline.ok && cline.reason !== "not_found") console.warn(`[opencodex] Cline model discovery degraded: ${cline.detail}`);
|
|
112
110
|
if (gemini && !gemini.ok && gemini.reason !== "not_found" && env.OPENCODEX_GEMINI_ACP?.trim() !== "0") {
|
|
113
111
|
console.warn(`[opencodex] Gemini model discovery degraded [${gemini.reason}]: ${gemini.detail}`);
|
|
114
112
|
}
|
package/src/server/responses.ts
CHANGED
|
@@ -374,10 +374,9 @@ function modelIdOf(model: ProviderModelEntry): string {
|
|
|
374
374
|
return typeof model === "string" ? model : model.id;
|
|
375
375
|
}
|
|
376
376
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
};
|
|
377
|
+
function defaultModelDisplayName(providerId: ProviderId): string {
|
|
378
|
+
return providerId === CLINE_PROVIDER_ID ? "Cline" : "Gemini CLI default";
|
|
379
|
+
}
|
|
381
380
|
|
|
382
381
|
function listedProviderEntries(
|
|
383
382
|
known: ProviderModels,
|
|
@@ -400,7 +399,7 @@ export function modelList(
|
|
|
400
399
|
object: "model",
|
|
401
400
|
created: 0,
|
|
402
401
|
owned_by: CLINE_PROVIDER_ID,
|
|
403
|
-
display_name: id === "default" ? "Cline
|
|
402
|
+
display_name: id === "default" ? "Cline" : id,
|
|
404
403
|
}));
|
|
405
404
|
}
|
|
406
405
|
if (scope) {
|
|
@@ -418,7 +417,7 @@ export function modelList(
|
|
|
418
417
|
object: "model",
|
|
419
418
|
created: 0,
|
|
420
419
|
owned_by: scope,
|
|
421
|
-
display_name: info.name ?? (id === "default" ?
|
|
420
|
+
display_name: info.name ?? (id === "default" ? defaultModelDisplayName(scope) : id),
|
|
422
421
|
...(info.description ? { description: info.description } : {}),
|
|
423
422
|
...(info.contextWindowTokens !== undefined
|
|
424
423
|
? {
|
|
@@ -462,7 +461,7 @@ export function modelList(
|
|
|
462
461
|
object: "model",
|
|
463
462
|
created: 0,
|
|
464
463
|
owned_by: providerId,
|
|
465
|
-
display_name: info.name ?? (id === "default" ?
|
|
464
|
+
display_name: info.name ?? (id === "default" ? defaultModelDisplayName(providerId) : id),
|
|
466
465
|
...(info.description ? { description: info.description } : {}),
|
|
467
466
|
...(info.contextWindowTokens !== undefined
|
|
468
467
|
? {
|