@closedrouter/cli 1.1.2 → 1.1.4
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 +3 -2
- package/dist/commands/agy-proxy.d.ts +9 -0
- package/dist/commands/agy-proxy.d.ts.map +1 -0
- package/dist/commands/start.d.ts +5 -2
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/index.js +123 -53
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ cr logout
|
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
### `cr start` / `cr launch`
|
|
128
|
-
Configure and start an installed coding CLI using models exposed to your platform key. The command discovers available models
|
|
128
|
+
Configure and start an installed coding CLI using models exposed to your platform key. The command discovers available tool-capable models and keeps keys out of arguments and generated client profiles. Starting Claude Code as a client uses the Anthropic-compatible platform endpoint; `cr gateway` separately contributes a local Claude Code subscription to the shared pool.
|
|
129
129
|
|
|
130
130
|
```bash
|
|
131
131
|
# Interactive model and tool selection
|
|
@@ -135,6 +135,7 @@ cr start
|
|
|
135
135
|
cr start claude --model claude-sonnet-4-6
|
|
136
136
|
cr start codex --model gpt-4.1
|
|
137
137
|
cr start gemini --model gemini-2.5-flash
|
|
138
|
+
cr start agy --model gpt-5-nano
|
|
138
139
|
cr start aider --model gpt-4o-mini
|
|
139
140
|
cr start opencode --model gpt-4o-mini
|
|
140
141
|
|
|
@@ -142,7 +143,7 @@ cr start opencode --model gpt-4o-mini
|
|
|
142
143
|
cr start claude --model claude-sonnet-4-6 -- --resume
|
|
143
144
|
```
|
|
144
145
|
|
|
145
|
-
Claude Code
|
|
146
|
+
Claude Code uses the Anthropic-compatible endpoint and can route through any eligible provider account. Codex gets a separate `~/.codex/closedrouter-launch.config.toml` profile using the Responses API. Gemini gets an app-owned authentication settings file under `~/.closedrouter/`, and OpenCode receives inline launch configuration. Antigravity CLI requires `modelProvider: "gemini"` in `~/.gemini/antigravity-cli/settings.json`. Its launcher starts a local adapter that maps Antigravity's built-in Gemini model name to the tool-capable pool model you select. The adapter binds only to localhost and stops when Antigravity exits. The launchers do not change the tools' main configuration files.
|
|
146
147
|
|
|
147
148
|
Cursor SDK keys can also be connected in the web account dialog or imported from `CURSOR_API_KEY`. ClosedRouter discovers models using Cursor's SDK and sends text-only, tools-disabled SDK runs through its normal gateway and telemetry path. This credential type is separate from Cursor OAuth tokens imported from the editor.
|
|
148
149
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface AgyModelProxy {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
close(): Promise<void>;
|
|
4
|
+
}
|
|
5
|
+
/** Antigravity only accepts its built-in Gemini slugs. Translate those slugs
|
|
6
|
+
* at the transport boundary so its normal Gemini requests reach the selected
|
|
7
|
+
* ClosedRouter pool model, including title and other background requests. */
|
|
8
|
+
export declare function startAgyModelProxy(gatewayUrl: string, apiKey: string, model: string): Promise<AgyModelProxy>;
|
|
9
|
+
//# sourceMappingURL=agy-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agy-proxy.d.ts","sourceRoot":"","sources":["../../src/commands/agy-proxy.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;6EAE6E;AAC7E,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,aAAa,CAAC,CA+CxB"}
|
package/dist/commands/start.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* The per-tool adapters follow the launcher pattern used by Ollama: discover a
|
|
4
4
|
* model, write only app-owned config, then start the installed client process.
|
|
5
5
|
*/
|
|
6
|
-
export type StartTool = "claude" | "codex" | "gemini" | "aider" | "opencode";
|
|
6
|
+
export type StartTool = "claude" | "codex" | "gemini" | "agy" | "aider" | "opencode";
|
|
7
7
|
type CliTool = StartTool;
|
|
8
8
|
export interface StartCommandOptions {
|
|
9
9
|
tool?: string;
|
|
@@ -25,7 +25,10 @@ export interface LaunchPlan {
|
|
|
25
25
|
configFile?: ConfigFile;
|
|
26
26
|
}
|
|
27
27
|
export declare function isGatewayModelAvailable(availableModels: string[], model: string): boolean;
|
|
28
|
-
export declare function buildLaunchPlan(tool: CliTool, serverUrl: string, apiKey: string, model: string, toolArgs?: string[], homeDir?: string, executablePath?: string
|
|
28
|
+
export declare function buildLaunchPlan(tool: CliTool, serverUrl: string, apiKey: string, model: string, toolArgs?: string[], homeDir?: string, executablePath?: string, agyRouting?: {
|
|
29
|
+
baseUrl: string;
|
|
30
|
+
recognizedModel: string;
|
|
31
|
+
}): LaunchPlan;
|
|
29
32
|
export declare function modelSupportsHarness(model: Record<string, any>, tool: StartTool): boolean;
|
|
30
33
|
export declare function startCommand(options?: StartCommandOptions): Promise<void>;
|
|
31
34
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,CAAC;AACrF,KAAK,OAAO,GAAG,SAAS,CAAC;AAEzB,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzF;AA8BD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAM,EAAO,EACvB,OAAO,SAAY,EACnB,cAAc,CAAC,EAAE,MAAM,EACvB,UAAU,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACxD,UAAU,CAiHZ;AAmBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAKzF;AAiED,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmDnF"}
|
package/dist/index.js
CHANGED
|
@@ -8607,16 +8607,74 @@ to scan and import local subscriptions!`, "Pool Empty");
|
|
|
8607
8607
|
// src/commands/start.ts
|
|
8608
8608
|
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
8609
8609
|
import { spawn as spawn3 } from "node:child_process";
|
|
8610
|
+
import { execFileSync } from "node:child_process";
|
|
8610
8611
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "node:fs";
|
|
8611
8612
|
import { homedir as homedir9 } from "node:os";
|
|
8612
|
-
import { dirname, join as join9
|
|
8613
|
+
import { dirname, join as join9 } from "node:path";
|
|
8614
|
+
|
|
8615
|
+
// src/commands/agy-proxy.ts
|
|
8616
|
+
import { createServer as createServer2 } from "node:http";
|
|
8617
|
+
import { request as httpRequest } from "node:http";
|
|
8618
|
+
import { request as httpsRequest } from "node:https";
|
|
8619
|
+
async function startAgyModelProxy(gatewayUrl, apiKey, model) {
|
|
8620
|
+
const upstream = new URL(gatewayUrl.replace(/\/+$/, "") + "/");
|
|
8621
|
+
if (!["https:", "http:"].includes(upstream.protocol)) {
|
|
8622
|
+
throw new Error("ClosedRouter server URL must use HTTP or HTTPS.");
|
|
8623
|
+
}
|
|
8624
|
+
const requestUpstream = upstream.protocol === "https:" ? httpsRequest : httpRequest;
|
|
8625
|
+
const server = createServer2((incoming, outgoing) => {
|
|
8626
|
+
if (incoming.headers["x-goog-api-key"] !== apiKey) {
|
|
8627
|
+
outgoing.writeHead(401).end();
|
|
8628
|
+
return;
|
|
8629
|
+
}
|
|
8630
|
+
const requestUrl = new URL(incoming.url || "/", "http://localhost");
|
|
8631
|
+
const match = /^\/v1beta\/models\/[^/:]+:(generateContent|streamGenerateContent)$/.exec(requestUrl.pathname);
|
|
8632
|
+
if (incoming.method !== "POST" || !match) {
|
|
8633
|
+
outgoing.writeHead(404).end();
|
|
8634
|
+
return;
|
|
8635
|
+
}
|
|
8636
|
+
const target = new URL(`v1beta/models/${encodeURIComponent(model)}:${match[1]}${requestUrl.search}`, upstream);
|
|
8637
|
+
const headers = { ...incoming.headers, host: target.host, "x-goog-api-key": apiKey };
|
|
8638
|
+
const upstreamRequest = requestUpstream(target, { method: "POST", headers }, (response) => {
|
|
8639
|
+
outgoing.writeHead(response.statusCode || 502, response.headers);
|
|
8640
|
+
response.pipe(outgoing);
|
|
8641
|
+
});
|
|
8642
|
+
upstreamRequest.on("error", () => {
|
|
8643
|
+
if (!outgoing.headersSent) {
|
|
8644
|
+
outgoing.writeHead(502, { "content-type": "application/json" });
|
|
8645
|
+
outgoing.end(JSON.stringify({ error: { message: "ClosedRouter gateway connection failed." } }));
|
|
8646
|
+
} else {
|
|
8647
|
+
outgoing.destroy();
|
|
8648
|
+
}
|
|
8649
|
+
});
|
|
8650
|
+
incoming.on("aborted", () => upstreamRequest.destroy());
|
|
8651
|
+
incoming.pipe(upstreamRequest);
|
|
8652
|
+
});
|
|
8653
|
+
await new Promise((resolve, reject) => {
|
|
8654
|
+
server.once("error", reject);
|
|
8655
|
+
server.listen(0, "127.0.0.1", () => {
|
|
8656
|
+
server.off("error", reject);
|
|
8657
|
+
resolve();
|
|
8658
|
+
});
|
|
8659
|
+
});
|
|
8660
|
+
const address = server.address();
|
|
8661
|
+
if (!address || typeof address === "string")
|
|
8662
|
+
throw new Error("Could not start the Antigravity model adapter.");
|
|
8663
|
+
return {
|
|
8664
|
+
baseUrl: `http://127.0.0.1:${address.port}`,
|
|
8665
|
+
close: () => new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()))
|
|
8666
|
+
};
|
|
8667
|
+
}
|
|
8668
|
+
|
|
8669
|
+
// src/commands/start.ts
|
|
8613
8670
|
function isGatewayModelAvailable(availableModels, model) {
|
|
8614
8671
|
return availableModels.includes(model);
|
|
8615
8672
|
}
|
|
8616
8673
|
var TOOL_OPTIONS = [
|
|
8617
|
-
{ value: "claude", label: "Claude Code", hint: "Anthropic API
|
|
8674
|
+
{ value: "claude", label: "Claude Code", hint: "Anthropic-compatible API using your ClosedRouter pool" },
|
|
8618
8675
|
{ value: "codex", label: "Codex CLI", hint: "OpenAI Responses API" },
|
|
8619
8676
|
{ value: "gemini", label: "Gemini CLI", hint: "Google Gemini API" },
|
|
8677
|
+
{ value: "agy", label: "Antigravity CLI", hint: "Google Gemini API via your ClosedRouter pool" },
|
|
8620
8678
|
{ value: "aider", label: "Aider", hint: "OpenAI-compatible API" },
|
|
8621
8679
|
{ value: "opencode", label: "OpenCode", hint: "OpenAI-compatible API" }
|
|
8622
8680
|
];
|
|
@@ -8632,7 +8690,7 @@ function assertNoManagedCodexArgs(args) {
|
|
|
8632
8690
|
throw new Error(`Remove ${conflicting}; ClosedRouter manages the Codex profile and model. Put other arguments after --.`);
|
|
8633
8691
|
}
|
|
8634
8692
|
}
|
|
8635
|
-
function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir = homedir9(), executablePath) {
|
|
8693
|
+
function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir = homedir9(), executablePath, agyRouting) {
|
|
8636
8694
|
const baseUrl = normalizeServerUrl(serverUrl);
|
|
8637
8695
|
const env = { ...process.env };
|
|
8638
8696
|
const command = executablePath || tool;
|
|
@@ -8641,11 +8699,11 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
8641
8699
|
env.ANTHROPIC_BASE_URL = baseUrl;
|
|
8642
8700
|
env.ANTHROPIC_API_KEY = apiKey;
|
|
8643
8701
|
const existingHeaders = (env.ANTHROPIC_CUSTOM_HEADERS || "").split(/\r?\n/).filter((header) => header.trim() && !/^\s*x-closedrouter-provider-only\s*:/i.test(header));
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
"X-ClosedRouter-Provider-Only: claude_oauth"
|
|
8647
|
-
].join(`
|
|
8702
|
+
if (existingHeaders.length)
|
|
8703
|
+
env.ANTHROPIC_CUSTOM_HEADERS = existingHeaders.join(`
|
|
8648
8704
|
`);
|
|
8705
|
+
else
|
|
8706
|
+
delete env.ANTHROPIC_CUSTOM_HEADERS;
|
|
8649
8707
|
return {
|
|
8650
8708
|
tool,
|
|
8651
8709
|
command,
|
|
@@ -8697,6 +8755,21 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
8697
8755
|
}
|
|
8698
8756
|
};
|
|
8699
8757
|
}
|
|
8758
|
+
if (tool === "agy") {
|
|
8759
|
+
if (!agyRouting)
|
|
8760
|
+
throw new Error("Antigravity requires a local ClosedRouter model adapter.");
|
|
8761
|
+
env.GEMINI_API_KEY = apiKey;
|
|
8762
|
+
env.GOOGLE_GEMINI_BASE_URL = agyRouting.baseUrl;
|
|
8763
|
+
const conflicting = toolArgs.find((arg) => arg === "--model" || arg.startsWith("--model=") || arg === "--effort" || arg.startsWith("--effort="));
|
|
8764
|
+
if (conflicting)
|
|
8765
|
+
throw new Error(`Remove ${conflicting}; ClosedRouter manages the Antigravity model and effort.`);
|
|
8766
|
+
return {
|
|
8767
|
+
tool,
|
|
8768
|
+
command,
|
|
8769
|
+
args: ["--model", agyRouting.recognizedModel, "--effort", "high", ...toolArgs],
|
|
8770
|
+
env
|
|
8771
|
+
};
|
|
8772
|
+
}
|
|
8700
8773
|
if (tool === "aider") {
|
|
8701
8774
|
env.OPENAI_API_BASE = `${baseUrl}/v1`;
|
|
8702
8775
|
env.OPENAI_API_KEY = apiKey;
|
|
@@ -8747,11 +8820,26 @@ function modelId(model) {
|
|
|
8747
8820
|
return String(model.id || model.name || "");
|
|
8748
8821
|
}
|
|
8749
8822
|
function modelSupportsHarness(model, tool) {
|
|
8750
|
-
if (tool === "claude")
|
|
8751
|
-
return true;
|
|
8752
8823
|
const parameters = model.supported_parameters;
|
|
8753
8824
|
return (model.status === undefined || model.status === "available") && (model.available_tool_account_count === undefined || model.available_tool_account_count > 0) && (!Array.isArray(parameters) || parameters.includes("tools"));
|
|
8754
8825
|
}
|
|
8826
|
+
function discoverAgyModels(command) {
|
|
8827
|
+
try {
|
|
8828
|
+
const output = execFileSync(command, ["models"], { encoding: "utf8", timeout: 1e4, stdio: ["ignore", "pipe", "ignore"] });
|
|
8829
|
+
return new Set(output.split(/\r?\n/).map((line) => line.split(/\s+/)[0]).filter((id) => /^gemini-[\w.-]+-(?:high|medium|low)$/.test(id)).map((id) => id.replace(/-(?:high|medium|low)$/, "")));
|
|
8830
|
+
} catch {
|
|
8831
|
+
throw new Error("Could not list Antigravity CLI models. Install or update `agy`, then try `cr start agy` again.");
|
|
8832
|
+
}
|
|
8833
|
+
}
|
|
8834
|
+
function assertAgyGeminiMode(homeDir) {
|
|
8835
|
+
const settingsPath = join9(homeDir, ".gemini", "antigravity-cli", "settings.json");
|
|
8836
|
+
try {
|
|
8837
|
+
const settings = JSON.parse(readFileSync8(settingsPath, "utf8"));
|
|
8838
|
+
if (settings?.modelProvider === "gemini")
|
|
8839
|
+
return;
|
|
8840
|
+
} catch {}
|
|
8841
|
+
throw new Error(`Set "modelProvider": "gemini" in ${settingsPath} before starting Antigravity through ClosedRouter.`);
|
|
8842
|
+
}
|
|
8755
8843
|
async function selectTool(tool) {
|
|
8756
8844
|
const cleaned = tool?.toLowerCase();
|
|
8757
8845
|
if (cleaned) {
|
|
@@ -8769,50 +8857,19 @@ async function selectTool(tool) {
|
|
|
8769
8857
|
}
|
|
8770
8858
|
async function ensurePlatformKey(tool, client, options) {
|
|
8771
8859
|
const config = loadConfig();
|
|
8772
|
-
const key = options.key?.trim() ||
|
|
8860
|
+
const key = options.key?.trim() || config.apiKey;
|
|
8773
8861
|
if (key)
|
|
8774
8862
|
return key;
|
|
8775
8863
|
if (!config.sessionToken) {
|
|
8776
8864
|
throw new Error("No platform API key is configured. Run `cr login` or pass `--key <cr-sk-...>`.");
|
|
8777
8865
|
}
|
|
8778
|
-
const
|
|
8779
|
-
const allowedModels = tool === "claude" ? await client.listClaudeBridgeModels() : undefined;
|
|
8780
|
-
if (tool === "claude" && !allowedModels?.length) {
|
|
8781
|
-
throw new Error("No Claude OAuth models are enabled for this workspace.");
|
|
8782
|
-
}
|
|
8783
|
-
const created = await client.createApiKey(label, 1e6, allowedModels, 60);
|
|
8866
|
+
const created = await client.createApiKey(`ClosedRouter ${tool} launch`, 1e6, undefined, 60);
|
|
8784
8867
|
const rawKey = String(created.key || created.api_key || "");
|
|
8785
8868
|
if (!rawKey.startsWith("cr-sk-"))
|
|
8786
8869
|
throw new Error("The server did not return a platform API key.");
|
|
8787
|
-
saveConfig(
|
|
8870
|
+
saveConfig({ apiKey: rawKey });
|
|
8788
8871
|
return rawKey;
|
|
8789
8872
|
}
|
|
8790
|
-
async function ensureClaudeBridge(client, serverUrl, key) {
|
|
8791
|
-
const hasClaudeNode = (nodes) => nodes.some((node) => node.status === "online" && Array.isArray(node.providers) && node.providers.includes("claude_oauth"));
|
|
8792
|
-
if (hasClaudeNode(await client.listBridgeNodes()))
|
|
8793
|
-
return;
|
|
8794
|
-
const script = process.argv[1];
|
|
8795
|
-
if (!script)
|
|
8796
|
-
throw new Error("No Claude subscription gateway is online. Start one with `cr gateway`.");
|
|
8797
|
-
const child = spawn3(process.execPath, [resolve(script), "gateway", "--server", serverUrl, "--key-stdin"], {
|
|
8798
|
-
detached: true,
|
|
8799
|
-
env: process.env,
|
|
8800
|
-
stdio: ["pipe", "ignore", "ignore"]
|
|
8801
|
-
});
|
|
8802
|
-
child.stdin?.end(`${key}
|
|
8803
|
-
`);
|
|
8804
|
-
child.unref();
|
|
8805
|
-
for (let attempt = 0;attempt < 30; attempt++) {
|
|
8806
|
-
if (child.exitCode !== null)
|
|
8807
|
-
break;
|
|
8808
|
-
await new Promise((resolveDelay) => setTimeout(resolveDelay, 400));
|
|
8809
|
-
if (hasClaudeNode(await client.listBridgeNodes()))
|
|
8810
|
-
return;
|
|
8811
|
-
}
|
|
8812
|
-
if (child.exitCode === null)
|
|
8813
|
-
child.kill("SIGTERM");
|
|
8814
|
-
throw new Error("Could not start the local Claude gateway. Run `cr gateway` in a terminal to see its connection status.");
|
|
8815
|
-
}
|
|
8816
8873
|
async function runTool(plan) {
|
|
8817
8874
|
return await new Promise((resolveExit, rejectExit) => {
|
|
8818
8875
|
const child = spawn3(plan.command, plan.args, { env: plan.env, stdio: "inherit" });
|
|
@@ -8848,14 +8905,24 @@ async function startCommand(options = {}) {
|
|
|
8848
8905
|
if (!isGatewayModelAvailable(availableModels, model)) {
|
|
8849
8906
|
throw new Error(`Model '${model}' is not available for ${tool} with this platform key. Agent clients require a provider that supports gateway function tools. Choose another model from ClosedRouter's model catalog.`);
|
|
8850
8907
|
}
|
|
8851
|
-
if (tool === "
|
|
8852
|
-
|
|
8853
|
-
const
|
|
8854
|
-
if (
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
const
|
|
8858
|
-
|
|
8908
|
+
if (tool === "agy")
|
|
8909
|
+
assertAgyGeminiMode(homedir9());
|
|
8910
|
+
const supportedAgyModels = tool === "agy" ? discoverAgyModels(options.executablePath || "agy") : undefined;
|
|
8911
|
+
if (supportedAgyModels && supportedAgyModels.size === 0) {
|
|
8912
|
+
throw new Error("Antigravity did not report any Gemini API models. Update `agy` and select Gemini API key mode in its settings.");
|
|
8913
|
+
}
|
|
8914
|
+
const recognizedModel = supportedAgyModels ? supportedAgyModels.has("gemini-3.8-flash") ? "gemini-3.8-flash" : [...supportedAgyModels][0] : undefined;
|
|
8915
|
+
const agyProxy = tool === "agy" ? await startAgyModelProxy(serverUrl, apiKey, model) : undefined;
|
|
8916
|
+
try {
|
|
8917
|
+
const plan = buildLaunchPlan(tool, serverUrl, apiKey, model, options.toolArgs, homedir9(), options.executablePath, agyProxy && recognizedModel ? { baseUrl: agyProxy.baseUrl, recognizedModel } : undefined);
|
|
8918
|
+
if (plan.configFile)
|
|
8919
|
+
writeOwnedConfig(plan.configFile);
|
|
8920
|
+
M2.info(`${import_picocolors12.default.green("Starting")} ${import_picocolors12.default.bold(TOOL_OPTIONS.find((option) => option.value === tool)?.label || tool)} with ${import_picocolors12.default.cyan(model)} through ${import_picocolors12.default.dim(serverUrl)}`);
|
|
8921
|
+
const exitCode = await runTool(plan);
|
|
8922
|
+
process.exitCode = exitCode;
|
|
8923
|
+
} finally {
|
|
8924
|
+
await agyProxy?.close();
|
|
8925
|
+
}
|
|
8859
8926
|
}
|
|
8860
8927
|
|
|
8861
8928
|
// src/commands/whoami.ts
|
|
@@ -8903,7 +8970,7 @@ process.on("warning", (warning) => {
|
|
|
8903
8970
|
console.warn(warning.name, warning.message);
|
|
8904
8971
|
});
|
|
8905
8972
|
var program2 = new Command;
|
|
8906
|
-
program2.name("closedrouter").description("ClosedRouter CLI: Import local AI subscriptions & API keys into your shared token pool").version("1.1.
|
|
8973
|
+
program2.name("closedrouter").description("ClosedRouter CLI: Import local AI subscriptions & API keys into your shared token pool").version("1.1.3").option("-s, --server <url>", "ClosedRouter server base URL (default: http://localhost:8000)").action(async (options) => {
|
|
8907
8974
|
await onboardCommand({ server: options.server });
|
|
8908
8975
|
});
|
|
8909
8976
|
program2.command("onboard").description("Run the full interactive onboarding wizard").option("-s, --server <url>", "ClosedRouter server base URL").option("-a, --all", "Automatically import all discovered accounts").option("--shared", "Contribute accounts to the shared team pool").action(async (options) => {
|
|
@@ -8960,4 +9027,7 @@ program2.command("start [tool] [tool-args...]").alias("launch").description("Con
|
|
|
8960
9027
|
executablePath: options.path
|
|
8961
9028
|
});
|
|
8962
9029
|
});
|
|
8963
|
-
program2.
|
|
9030
|
+
program2.parseAsync(process.argv).catch((error) => {
|
|
9031
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
9032
|
+
process.exitCode = 1;
|
|
9033
|
+
});
|
package/package.json
CHANGED