@lasso-ai/cli 1.5.0 → 2.0.1
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/dist/cli/agent.d.ts +1 -0
- package/dist/cli/backends.d.ts +53 -0
- package/dist/cli/backends.js +267 -0
- package/dist/cli/bridge.d.ts +8 -5
- package/dist/cli/bridge.js +357 -151
- package/dist/cli/host/install.js +12 -1
- package/dist/cli/local-runtime.d.ts +28 -0
- package/dist/cli/local-runtime.js +294 -0
- package/dist/cli/oneshot.js +28 -10
- package/dist/cli/runtime-client.d.ts +91 -10
- package/dist/cli/runtime-client.js +38 -3
- package/dist/overlay.js +44 -28
- package/dist/runtime/__tests__/adapter-normalization.test.d.ts +1 -0
- package/dist/runtime/__tests__/adapter-normalization.test.js +392 -0
- package/dist/runtime/__tests__/state-machine.test.d.ts +1 -0
- package/dist/runtime/__tests__/state-machine.test.js +107 -0
- package/dist/runtime/__tests__/verification-engine.test.d.ts +1 -0
- package/dist/runtime/__tests__/verification-engine.test.js +91 -0
- package/dist/runtime/__tests__/workspace-guard.test.d.ts +1 -0
- package/dist/runtime/__tests__/workspace-guard.test.js +104 -0
- package/dist/runtime/adapters/claude-code-adapter.d.ts +46 -0
- package/dist/runtime/adapters/claude-code-adapter.js +230 -0
- package/dist/runtime/adapters/codex-cli-adapter.d.ts +44 -0
- package/dist/runtime/adapters/codex-cli-adapter.js +202 -0
- package/dist/runtime/adapters/cursor-adapter.d.ts +47 -0
- package/dist/runtime/adapters/cursor-adapter.js +214 -0
- package/dist/runtime/adapters/factory.d.ts +19 -0
- package/dist/runtime/adapters/factory.js +48 -0
- package/dist/runtime/adapters/local-agent-adapter.d.ts +143 -0
- package/dist/runtime/adapters/local-agent-adapter.js +408 -0
- package/dist/runtime/adapters/opencode-adapter.d.ts +43 -0
- package/dist/runtime/adapters/opencode-adapter.js +210 -0
- package/dist/runtime/agent-runtime.d.ts +286 -0
- package/dist/runtime/agent-runtime.js +8 -0
- package/dist/runtime/agent-state-machine.d.ts +67 -0
- package/dist/runtime/agent-state-machine.js +234 -0
- package/dist/runtime/backend-interface.d.ts +272 -0
- package/dist/runtime/backend-interface.js +38 -0
- package/dist/runtime/event-mapper.d.ts +11 -0
- package/dist/runtime/event-mapper.js +40 -0
- package/dist/runtime/index.d.ts +20 -0
- package/dist/runtime/index.js +43 -0
- package/dist/runtime/local-session-runner.d.ts +60 -0
- package/dist/runtime/local-session-runner.js +185 -0
- package/dist/runtime/review.d.ts +24 -0
- package/dist/runtime/review.js +30 -0
- package/dist/runtime/verification-engine.d.ts +71 -0
- package/dist/runtime/verification-engine.js +374 -0
- package/dist/runtime/workspace-guard.d.ts +70 -0
- package/dist/runtime/workspace-guard.js +321 -0
- package/docs/local-coding-agents.md +183 -0
- package/package.json +22 -3
package/dist/cli/agent.d.ts
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local coding agent discovery for the Lasso CLI.
|
|
3
|
+
*
|
|
4
|
+
* Detects which agent CLIs are installed on THIS machine and whether they are
|
|
5
|
+
* authenticated, using each agent's own structured status command (never
|
|
6
|
+
* human-readable output scraping):
|
|
7
|
+
*
|
|
8
|
+
* claude → claude --version / claude auth status (JSON: loggedIn)
|
|
9
|
+
* codex → codex --version / codex login status (exit code)
|
|
10
|
+
* opencode → opencode --version / opencode providers list / opencode models
|
|
11
|
+
* cursor-agent→ cursor-agent -v / cursor-agent status --format json (JSON: isAuthenticated)
|
|
12
|
+
*
|
|
13
|
+
* Auth failures do not mark a backend as missing — it is reported with
|
|
14
|
+
* fix instructions so the overlay can show why it is locked.
|
|
15
|
+
*/
|
|
16
|
+
export type LocalAgentProvider = "claude_code" | "opencode" | "codex_cli" | "cursor";
|
|
17
|
+
export interface DetectedBackendModel {
|
|
18
|
+
/** Model option id sent by the overlay (e.g. "opencode:big-pickle") */
|
|
19
|
+
id: string;
|
|
20
|
+
label: string;
|
|
21
|
+
/**
|
|
22
|
+
* Value for backendConfig.modelId — already normalized for the agent's CLI
|
|
23
|
+
* ("" means the agent's configured default).
|
|
24
|
+
*/
|
|
25
|
+
modelId: string;
|
|
26
|
+
}
|
|
27
|
+
export interface DetectedBackend {
|
|
28
|
+
provider: LocalAgentProvider;
|
|
29
|
+
installed: boolean;
|
|
30
|
+
authenticated: boolean;
|
|
31
|
+
version?: string;
|
|
32
|
+
models: DetectedBackendModel[];
|
|
33
|
+
error?: string;
|
|
34
|
+
fixInstructions?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Probe all supported local agents in parallel.
|
|
38
|
+
* Fault-tolerant: a missing or broken CLI never rejects the whole list.
|
|
39
|
+
*/
|
|
40
|
+
export declare function detectBackends(): Promise<DetectedBackend[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Whether a model option id belongs to a local agent (provider prefix match).
|
|
43
|
+
*/
|
|
44
|
+
export declare const LOCAL_MODEL_PREFIXES: string[];
|
|
45
|
+
/**
|
|
46
|
+
* Extract the modelId for backendConfig from an overlay model option id.
|
|
47
|
+
* Examples:
|
|
48
|
+
* "claude_code:sonnet" → "sonnet"
|
|
49
|
+
* "opencode:big-pickle" → "opencode/big-pickle"
|
|
50
|
+
* "codex_cli:default" → "" (agent's configured default)
|
|
51
|
+
* "claude-3-5-sonnet" → "claude-3-5-sonnet" (hosted ids pass through)
|
|
52
|
+
*/
|
|
53
|
+
export declare function modelIdForBackend(optionId: string, provider: string): string;
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Local coding agent discovery for the Lasso CLI.
|
|
4
|
+
*
|
|
5
|
+
* Detects which agent CLIs are installed on THIS machine and whether they are
|
|
6
|
+
* authenticated, using each agent's own structured status command (never
|
|
7
|
+
* human-readable output scraping):
|
|
8
|
+
*
|
|
9
|
+
* claude → claude --version / claude auth status (JSON: loggedIn)
|
|
10
|
+
* codex → codex --version / codex login status (exit code)
|
|
11
|
+
* opencode → opencode --version / opencode providers list / opencode models
|
|
12
|
+
* cursor-agent→ cursor-agent -v / cursor-agent status --format json (JSON: isAuthenticated)
|
|
13
|
+
*
|
|
14
|
+
* Auth failures do not mark a backend as missing — it is reported with
|
|
15
|
+
* fix instructions so the overlay can show why it is locked.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.LOCAL_MODEL_PREFIXES = void 0;
|
|
19
|
+
exports.detectBackends = detectBackends;
|
|
20
|
+
exports.modelIdForBackend = modelIdForBackend;
|
|
21
|
+
const node_child_process_1 = require("node:child_process");
|
|
22
|
+
const node_util_1 = require("node:util");
|
|
23
|
+
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
24
|
+
async function probe(bin, args, timeout = 10000) {
|
|
25
|
+
try {
|
|
26
|
+
const { stdout, stderr } = await execFileAsync(bin, args, { timeout, windowsHide: true });
|
|
27
|
+
return { ok: true, stdout, stderr, code: 0, failed: false };
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const e = error;
|
|
31
|
+
if (e.killed) {
|
|
32
|
+
return { ok: false, stdout: e.stdout || "", stderr: "timeout", code: undefined, failed: true };
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
stdout: e.stdout || "",
|
|
37
|
+
stderr: e.stderr || String(error),
|
|
38
|
+
code: typeof e.code === "number" ? e.code : undefined,
|
|
39
|
+
failed: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function stripAnsi(text) {
|
|
44
|
+
return text.replace(/\u001b\[[0-9;]*m/g, "").replace(/\u001b\][^\u0007]*\u0007/g, "");
|
|
45
|
+
}
|
|
46
|
+
function parseJson(stdout) {
|
|
47
|
+
const start = stdout.indexOf("{");
|
|
48
|
+
if (start < 0)
|
|
49
|
+
return null;
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(stdout.slice(start));
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function detectClaudeCode() {
|
|
58
|
+
const base = {
|
|
59
|
+
provider: "claude_code",
|
|
60
|
+
installed: false,
|
|
61
|
+
authenticated: false,
|
|
62
|
+
models: [
|
|
63
|
+
{ id: "claude_code:sonnet", label: "Sonnet", modelId: "sonnet" },
|
|
64
|
+
{ id: "claude_code:opus", label: "Opus", modelId: "opus" },
|
|
65
|
+
{ id: "claude_code:haiku", label: "Haiku", modelId: "haiku" },
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
const version = await probe("claude", ["--version"]);
|
|
69
|
+
if (version.failed) {
|
|
70
|
+
return {
|
|
71
|
+
...base,
|
|
72
|
+
error: "Claude Code CLI not found.",
|
|
73
|
+
fixInstructions: "Install: npm install -g @anthropic-ai/claude-code",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
base.installed = true;
|
|
77
|
+
base.version = version.stdout.trim().split("\n")[0];
|
|
78
|
+
const auth = await probe("claude", ["auth", "status"], 15000);
|
|
79
|
+
const parsed = parseJson(auth.stdout);
|
|
80
|
+
if (parsed && typeof parsed.loggedIn === "boolean") {
|
|
81
|
+
base.authenticated = parsed.loggedIn;
|
|
82
|
+
if (!parsed.loggedIn) {
|
|
83
|
+
base.error = "Claude Code is not logged in.";
|
|
84
|
+
base.fixInstructions = "Run 'claude' once and complete the login flow.";
|
|
85
|
+
}
|
|
86
|
+
return base;
|
|
87
|
+
}
|
|
88
|
+
// Fallback: exit code decides
|
|
89
|
+
base.authenticated = auth.ok;
|
|
90
|
+
if (!auth.ok) {
|
|
91
|
+
base.error = "Claude Code authentication could not be verified.";
|
|
92
|
+
base.fixInstructions = "Run 'claude' once and complete the login flow.";
|
|
93
|
+
}
|
|
94
|
+
return base;
|
|
95
|
+
}
|
|
96
|
+
async function detectOpenCode() {
|
|
97
|
+
const base = {
|
|
98
|
+
provider: "opencode",
|
|
99
|
+
installed: false,
|
|
100
|
+
authenticated: false,
|
|
101
|
+
models: [],
|
|
102
|
+
};
|
|
103
|
+
const version = await probe("opencode", ["--version"]);
|
|
104
|
+
if (version.failed) {
|
|
105
|
+
return {
|
|
106
|
+
...base,
|
|
107
|
+
error: "OpenCode CLI not found.",
|
|
108
|
+
fixInstructions: "Install: npm install -g opencode-ai",
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
base.installed = true;
|
|
112
|
+
base.version = version.stdout.trim().split("\n")[0];
|
|
113
|
+
const providers = await probe("opencode", ["providers", "list"], 15000);
|
|
114
|
+
if (providers.failed) {
|
|
115
|
+
base.error = "OpenCode authentication could not be verified.";
|
|
116
|
+
base.fixInstructions = "Run 'opencode providers list' and configure credentials with 'opencode auth login'.";
|
|
117
|
+
return base;
|
|
118
|
+
}
|
|
119
|
+
const text = stripAnsi(`${providers.stdout}\n${providers.stderr}`);
|
|
120
|
+
const credStart = text.indexOf("Credentials");
|
|
121
|
+
const envStart = text.indexOf("Environment");
|
|
122
|
+
if (credStart >= 0) {
|
|
123
|
+
const section = text.slice(credStart, envStart > credStart ? envStart : undefined);
|
|
124
|
+
if (!section.includes("●")) {
|
|
125
|
+
base.error = "OpenCode has no stored credentials.";
|
|
126
|
+
base.fixInstructions = "Run 'opencode auth login' or set a provider API key.";
|
|
127
|
+
return base;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
base.authenticated = true;
|
|
131
|
+
// Model list (may fail without breaking detection)
|
|
132
|
+
const models = await probe("opencode", ["models"], 15000);
|
|
133
|
+
if (models.ok) {
|
|
134
|
+
const ids = models.stdout
|
|
135
|
+
.split("\n")
|
|
136
|
+
.map((line) => line.trim())
|
|
137
|
+
.filter((line) => /^[a-z0-9-]+\/[a-z0-9._-]+$/i.test(line))
|
|
138
|
+
.slice(0, 30);
|
|
139
|
+
base.models = ids.map((full) => {
|
|
140
|
+
const name = full.split("/")[1];
|
|
141
|
+
return {
|
|
142
|
+
id: `opencode:${name}`,
|
|
143
|
+
label: name,
|
|
144
|
+
modelId: full,
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (base.models.length === 0) {
|
|
149
|
+
base.models = [
|
|
150
|
+
{ id: "opencode:big-pickle", label: "Big Pickle", modelId: "opencode/big-pickle" },
|
|
151
|
+
{ id: "opencode:deepseek-v4-flash", label: "DeepSeek V4 Flash", modelId: "opencode/deepseek-v4-flash" },
|
|
152
|
+
];
|
|
153
|
+
}
|
|
154
|
+
return base;
|
|
155
|
+
}
|
|
156
|
+
async function detectCodex() {
|
|
157
|
+
const base = {
|
|
158
|
+
provider: "codex_cli",
|
|
159
|
+
installed: false,
|
|
160
|
+
authenticated: false,
|
|
161
|
+
models: [{ id: "codex_cli:default", label: "Default model (codex config)", modelId: "" }],
|
|
162
|
+
};
|
|
163
|
+
const version = await probe("codex", ["--version"]);
|
|
164
|
+
if (version.failed) {
|
|
165
|
+
return {
|
|
166
|
+
...base,
|
|
167
|
+
error: "Codex CLI not found.",
|
|
168
|
+
fixInstructions: "Install: npm install -g @openai/codex",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
base.installed = true;
|
|
172
|
+
base.version = version.stdout.trim().split("\n")[0];
|
|
173
|
+
const auth = await probe("codex", ["login", "status"], 15000);
|
|
174
|
+
if (!auth.ok) {
|
|
175
|
+
base.error = "Codex CLI is not logged in.";
|
|
176
|
+
base.fixInstructions = "Run 'codex login' and sign in with ChatGPT or an API key.";
|
|
177
|
+
return base;
|
|
178
|
+
}
|
|
179
|
+
base.authenticated = true;
|
|
180
|
+
return base;
|
|
181
|
+
}
|
|
182
|
+
async function detectCursor() {
|
|
183
|
+
const base = {
|
|
184
|
+
provider: "cursor",
|
|
185
|
+
installed: false,
|
|
186
|
+
authenticated: false,
|
|
187
|
+
models: [
|
|
188
|
+
{ id: "cursor:sonnet-4", label: "Sonnet 4", modelId: "sonnet-4" },
|
|
189
|
+
{ id: "cursor:gpt-5", label: "GPT-5", modelId: "gpt-5" },
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
const version = await probe("cursor-agent", ["-v"]);
|
|
193
|
+
if (version.failed) {
|
|
194
|
+
return {
|
|
195
|
+
...base,
|
|
196
|
+
error: "Cursor Agent CLI not found.",
|
|
197
|
+
fixInstructions: "Install: curl https://cursor.com/install -fsS | bash",
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
base.installed = true;
|
|
201
|
+
base.version = version.stdout.trim().split("\n")[0];
|
|
202
|
+
const auth = await probe("cursor-agent", ["status", "--format", "json"], 15000);
|
|
203
|
+
const parsed = parseJson(auth.stdout);
|
|
204
|
+
if (parsed && typeof parsed.isAuthenticated === "boolean") {
|
|
205
|
+
base.authenticated = parsed.isAuthenticated;
|
|
206
|
+
if (!parsed.isAuthenticated) {
|
|
207
|
+
base.error = "Cursor Agent is not authenticated.";
|
|
208
|
+
base.fixInstructions = "Run 'cursor-agent login'.";
|
|
209
|
+
return base;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (auth.failed) {
|
|
213
|
+
base.error = "Cursor Agent is not authenticated.";
|
|
214
|
+
base.fixInstructions = "Run 'cursor-agent login'.";
|
|
215
|
+
return base;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
base.authenticated = true;
|
|
219
|
+
}
|
|
220
|
+
const models = await probe("cursor-agent", ["models"], 15000);
|
|
221
|
+
if (models.ok) {
|
|
222
|
+
const ids = models.stdout
|
|
223
|
+
.split("\n")
|
|
224
|
+
.map((line) => line.trim())
|
|
225
|
+
.filter((line) => /^[a-z0-9][a-z0-9.-]*$/i.test(line))
|
|
226
|
+
.slice(0, 20);
|
|
227
|
+
if (ids.length > 0) {
|
|
228
|
+
base.models = ids.map((id) => ({ id: `cursor:${id}`, label: id, modelId: id }));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return base;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Probe all supported local agents in parallel.
|
|
235
|
+
* Fault-tolerant: a missing or broken CLI never rejects the whole list.
|
|
236
|
+
*/
|
|
237
|
+
async function detectBackends() {
|
|
238
|
+
return Promise.all([detectClaudeCode(), detectOpenCode(), detectCodex(), detectCursor()]);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Whether a model option id belongs to a local agent (provider prefix match).
|
|
242
|
+
*/
|
|
243
|
+
exports.LOCAL_MODEL_PREFIXES = ["claude_code:", "claude-code:", "opencode:", "codex:", "codex_cli:", "cursor:"];
|
|
244
|
+
/**
|
|
245
|
+
* Extract the modelId for backendConfig from an overlay model option id.
|
|
246
|
+
* Examples:
|
|
247
|
+
* "claude_code:sonnet" → "sonnet"
|
|
248
|
+
* "opencode:big-pickle" → "opencode/big-pickle"
|
|
249
|
+
* "codex_cli:default" → "" (agent's configured default)
|
|
250
|
+
* "claude-3-5-sonnet" → "claude-3-5-sonnet" (hosted ids pass through)
|
|
251
|
+
*/
|
|
252
|
+
function modelIdForBackend(optionId, provider) {
|
|
253
|
+
if (!exports.LOCAL_MODEL_PREFIXES.some((p) => optionId.startsWith(p)) && !["claude_code", "opencode", "codex_cli", "cursor"].includes(provider)) {
|
|
254
|
+
return optionId;
|
|
255
|
+
}
|
|
256
|
+
const colon = optionId.indexOf(":");
|
|
257
|
+
const raw = colon >= 0 ? optionId.slice(colon + 1) : optionId;
|
|
258
|
+
if (provider === "opencode") {
|
|
259
|
+
if (raw === "default")
|
|
260
|
+
return "";
|
|
261
|
+
return raw.includes("/") ? raw : `opencode/${raw}`;
|
|
262
|
+
}
|
|
263
|
+
if (provider === "codex_cli") {
|
|
264
|
+
return raw === "default" ? "" : raw;
|
|
265
|
+
}
|
|
266
|
+
return raw;
|
|
267
|
+
}
|
package/dist/cli/bridge.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ type GitState = {
|
|
|
9
9
|
hasRemote?: boolean;
|
|
10
10
|
remote?: string;
|
|
11
11
|
};
|
|
12
|
+
type Provider = "anthropic" | "openai" | "google" | "nvidia" | "ollama" | "claude_code" | "opencode" | "codex_cli" | "cursor";
|
|
12
13
|
export type BridgeMessage = {
|
|
13
14
|
type: "hello";
|
|
14
15
|
from: "overlay" | "cli";
|
|
@@ -17,7 +18,7 @@ export type BridgeMessage = {
|
|
|
17
18
|
taskId: string;
|
|
18
19
|
instruction: string;
|
|
19
20
|
model: string;
|
|
20
|
-
provider?: "anthropic" | "openai" | "google" | "nvidia" | "ollama";
|
|
21
|
+
provider?: "anthropic" | "openai" | "google" | "nvidia" | "ollama" | "claude_code" | "opencode" | "codex_cli" | "cursor";
|
|
21
22
|
messages?: Array<{
|
|
22
23
|
role: string;
|
|
23
24
|
content: string;
|
|
@@ -52,7 +53,7 @@ export type BridgeMessage = {
|
|
|
52
53
|
taskId: string;
|
|
53
54
|
question: string;
|
|
54
55
|
model: string;
|
|
55
|
-
provider?: "anthropic" | "openai" | "google" | "nvidia" | "ollama";
|
|
56
|
+
provider?: "anthropic" | "openai" | "google" | "nvidia" | "ollama" | "claude_code" | "opencode" | "codex_cli" | "cursor";
|
|
56
57
|
messages?: Array<{
|
|
57
58
|
role: string;
|
|
58
59
|
content: string;
|
|
@@ -112,7 +113,9 @@ export type BridgeMessage = {
|
|
|
112
113
|
} | {
|
|
113
114
|
type: "git_generate_message";
|
|
114
115
|
model: string;
|
|
115
|
-
provider?: "anthropic" | "openai" | "google" | "nvidia" | "ollama";
|
|
116
|
+
provider?: "anthropic" | "openai" | "google" | "nvidia" | "ollama" | "claude_code" | "opencode" | "codex_cli" | "cursor";
|
|
117
|
+
taskId?: string;
|
|
118
|
+
pageContext?: any;
|
|
116
119
|
} | {
|
|
117
120
|
type: "git_init";
|
|
118
121
|
} | {
|
|
@@ -136,7 +139,7 @@ export type BridgeMessage = {
|
|
|
136
139
|
prompt: string;
|
|
137
140
|
scope?: "project" | "component";
|
|
138
141
|
model?: string;
|
|
139
|
-
provider?: "anthropic" | "openai" | "google" | "nvidia" | "ollama";
|
|
142
|
+
provider?: "anthropic" | "openai" | "google" | "nvidia" | "ollama" | "claude_code" | "opencode" | "codex_cli" | "cursor";
|
|
140
143
|
messages?: Array<{
|
|
141
144
|
role: "user" | "assistant";
|
|
142
145
|
content: string;
|
|
@@ -160,7 +163,7 @@ export type BridgeMessage = {
|
|
|
160
163
|
type ModelOption = {
|
|
161
164
|
id: string;
|
|
162
165
|
label: string;
|
|
163
|
-
provider:
|
|
166
|
+
provider: Provider;
|
|
164
167
|
locked?: boolean;
|
|
165
168
|
lockedReason?: string;
|
|
166
169
|
};
|