@closedrouter/cli 1.1.12 → 1.1.14
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 -1
- package/dist/commands/agy-desktop-account.d.ts +5 -0
- package/dist/commands/agy-desktop-account.d.ts.map +1 -0
- package/dist/commands/agy-desktop-catalog.d.ts +2 -1
- package/dist/commands/agy-desktop-catalog.d.ts.map +1 -1
- package/dist/commands/agy-desktop.d.ts +7 -2
- package/dist/commands/agy-desktop.d.ts.map +1 -1
- package/dist/commands/claude-desktop.d.ts +3 -1
- package/dist/commands/claude-desktop.d.ts.map +1 -1
- package/dist/commands/desktop-account.d.ts +13 -0
- package/dist/commands/desktop-account.d.ts.map +1 -0
- package/dist/commands/launch-catalog.d.ts.map +1 -1
- package/dist/commands/model-branding.d.ts +5 -2
- package/dist/commands/model-branding.d.ts.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/index.js +219 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -155,7 +155,7 @@ On macOS, Claude uses a compatible Electron runtime installed by Cockpit, or the
|
|
|
155
155
|
|
|
156
156
|
Antigravity uses the CCPA envelope conversion documented in `~/Projects/antigravity-mods`. The launcher briefly opens a loopback Node inspector and installs its language-server hook. A browser debugger replaces the launched renderer's model catalog with native custom-model entries, then detaches. Each entry carries a distinct routing alias and a positive context and output budget. The picker lists the supported pool models, and selecting one changes inference routing. App bundles and global hook configuration are not modified. Unsupported launcher builds fail before opening; `--open-only` remains available.
|
|
157
157
|
|
|
158
|
-
Cursor, Antigravity, and the hooked Claude view display the colored ClosedRouter logo beside model names. Codex uses its custom model catalog and provider labels. Launch requests also carry the configured model ID in system context so native client identity prompts do not misidentify the underlying model. The relay resolves the requested model on each turn and preserves tools and streamed responses. Unsupported model IDs are rejected before forwarding. Catalogs are snapshots of the models available to the platform key at launch; provider quotas can change during a session.
|
|
158
|
+
Cursor, Antigravity, and the hooked Claude view display the colored ClosedRouter logo beside model names. White-core neon-blue lightning bolts orbit the active chat model button in 3D for a brief pass every five seconds, and immediately on hover or keyboard focus. Reduced-motion preferences keep the mark static; hidden windows pause the effect. Codex uses its custom model catalog and provider labels. Launch requests also carry the configured model ID in system context so native client identity prompts do not misidentify the underlying model. The relay resolves the requested model on each turn and preserves tools and streamed responses. Unsupported model IDs are rejected before forwarding. Catalogs are snapshots of the models available to the platform key at launch; provider quotas can change during a session.
|
|
159
159
|
|
|
160
160
|
macOS app bundles are discovered in `/Applications` and `~/Applications`. Common Windows and Linux installation paths are checked, with `--path` available for other installations. Live tests verified Cursor, Claude's Code and Cowork views, and Antigravity inference through ClosedRouter. Cursor and Antigravity switched between `gpt-5-nano` and `gpt-4.1-nano` in their native pickers. Cowork could answer through the gateway, but its workspace VM reported insufficient disk space on the test Mac; workspace actions were not verified. Gemma's full agent request previously received an upstream quota error. Desktop hooks fail closed when expected controllers change. See the [Codex provider configuration](https://developers.openai.com/codex/config-advanced) and [Electron fuse documentation](https://www.electronjs.org/docs/latest/tutorial/fuses) for configuration and inspector behavior.
|
|
161
161
|
|
|
@@ -269,3 +269,9 @@ Other integrations may set the same headers directly. Known client user agents p
|
|
|
269
269
|
Request inspection also reports streaming mode, tools offered, tool-result messages supplied, and total message count. These counts describe the request, not which tools the client actually executed. Tool names, arguments, outputs, and message contents are not saved.
|
|
270
270
|
|
|
271
271
|
Antigravity launches register a credential-free custom Gemini-compatible model in `~/.gemini/antigravity-cli/settings.json` under `customModelsConfig.customModels`. Its visible label is `ClosedRouter: <selected model>`, while its internal Gemini transport ID stays compatible with agy. The local adapter continues routing every request to the actual selected pool model. This fixes the previous Gemini placeholder in agy's header. Existing preferences and custom models are preserved; request routing still uses the local model adapter and telemetry relay. Re-run `cr start agy` to choose a different pool model.
|
|
272
|
+
|
|
273
|
+
### Desktop provider accounts
|
|
274
|
+
|
|
275
|
+
Antigravity can start without a Google account. With no native OAuth token, the launcher uses an isolated provider session, authenticates Gemini-compatible requests with its local relay key, and displays the ClosedRouter identity in Account settings. It skips Google enrollment and disables native telemetry for that provider session. Existing native accounts retain their account UI and account-rotation integration. Set `CLOSEDROUTER_ANTIGRAVITY_NATIVE_DIR` to an empty directory to test the account-free path.
|
|
276
|
+
|
|
277
|
+
Claude uses its native third-party gateway mode without a Claude account. Its account menu uses the ClosedRouter name and email when no principal or SSO identity is present. Launches using another key show a generic ClosedRouter API-key identity, without reusing unrelated saved account information.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DesktopAccountIdentity } from "./desktop-account";
|
|
2
|
+
/** The provider key authenticates the managed session. No Google token is
|
|
3
|
+
* created, and the native validator still runs when an OAuth token exists. */
|
|
4
|
+
export declare function patchAntigravityAccount(source: string, account: DesktopAccountIdentity): string;
|
|
5
|
+
//# sourceMappingURL=agy-desktop-account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agy-desktop-account.d.ts","sourceRoot":"","sources":["../../src/commands/agy-desktop-account.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE;8EAC8E;AAC9E,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAa/F"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { LaunchCatalog } from "./launch-catalog";
|
|
2
|
+
import type { DesktopAccountIdentity } from "./desktop-account";
|
|
2
3
|
/** Replace only the launched renderer's custom-model provider. The native
|
|
3
4
|
* picker sends ModelInfo overrides to the language server on every turn. */
|
|
4
5
|
export declare function patchAntigravityCatalog(source: string, catalog: LaunchCatalog): string;
|
|
5
6
|
/** Browser debugger interception avoids copying the app or changing its files.
|
|
6
7
|
* The startup Node inspector closes after installation; no debug port remains. */
|
|
7
|
-
export declare function antigravityCatalogHook(catalog: LaunchCatalog, marker: string): string;
|
|
8
|
+
export declare function antigravityCatalogHook(catalog: LaunchCatalog, marker: string, account?: DesktopAccountIdentity): string;
|
|
8
9
|
//# sourceMappingURL=agy-desktop-catalog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agy-desktop-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/agy-desktop-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"agy-desktop-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/agy-desktop-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAGhE;4EAC4E;AAC5E,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CA0BtF;AAED;kFACkF;AAClF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAoCvH"}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import type { DesktopLaunchPlan } from "./desktop-launch";
|
|
2
2
|
import { type LaunchCatalog } from "./launch-catalog";
|
|
3
|
+
import type { DesktopAccountIdentity } from "./desktop-account";
|
|
3
4
|
export declare function assertAntigravityModsAvailable(): Promise<void>;
|
|
4
5
|
export declare function assertAntigravityDesktopHookSupport(executable: string): void;
|
|
5
6
|
/** The same CCPA envelope bridge used by antigravity-mods, with ClosedRouter
|
|
6
7
|
* handling model selection and credentials. Account/discovery traffic continues
|
|
7
8
|
* through the user's existing account-rotation proxy. */
|
|
8
|
-
export declare function startAgyDesktopProxy(gatewayUrl: string, localKey: string, model: string, modsUrl?: string, catalog?: LaunchCatalog): Promise<{
|
|
9
|
+
export declare function startAgyDesktopProxy(gatewayUrl: string, localKey: string, model: string, modsUrl?: string, catalog?: LaunchCatalog, account?: DesktopAccountIdentity): Promise<{
|
|
9
10
|
baseUrl: string;
|
|
10
11
|
close: () => Promise<void>;
|
|
11
12
|
}>;
|
|
12
|
-
export declare function addAntigravityDesktopHook(plan: DesktopLaunchPlan, endpoint: string, catalog?: LaunchCatalog
|
|
13
|
+
export declare function addAntigravityDesktopHook(plan: DesktopLaunchPlan, endpoint: string, catalog?: LaunchCatalog, account?: DesktopAccountIdentity, provider?: {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
localKey: string;
|
|
16
|
+
nativeDir?: string;
|
|
17
|
+
}): void;
|
|
13
18
|
//# sourceMappingURL=agy-desktop.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agy-desktop.d.ts","sourceRoot":"","sources":["../../src/commands/agy-desktop.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"agy-desktop.d.ts","sourceRoot":"","sources":["../../src/commands/agy-desktop.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAG1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAKhE,wBAAsB,8BAA8B,IAAI,OAAO,CAAC,IAAI,CAAC,CAYpE;AAED,wBAAgB,mCAAmC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAa5E;AAED;;yDAEyD;AACzD,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,SAAiB,EAAE,OAAO,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,sBAAsB;;;GAuGlL;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,sBAAsB,EAAE,QAAQ,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA4C1N"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { DesktopLaunchPlan } from "./desktop-launch";
|
|
2
|
+
import type { DesktopAccountIdentity } from "./desktop-account";
|
|
3
|
+
export declare function patchClaudeAccountIdentity(source: string, account: DesktopAccountIdentity): string;
|
|
2
4
|
export declare function patchClaudeModelIdentity(source: string, aliases: Record<string, string>): string;
|
|
3
5
|
/** Share immutable framework bytes, but detach every file codesign can write.
|
|
4
6
|
* Signing a hard-linked executable would change the user's original runtime. */
|
|
@@ -6,5 +8,5 @@ export declare function cloneClaudeElectronRuntime(source: string, destination:
|
|
|
6
8
|
export declare function prepareClaudeElectronRuntime(runtime: string, sourceApp: string): string;
|
|
7
9
|
export declare function findClaudeSharedElectron(sourceApp: string, home?: string): string | undefined;
|
|
8
10
|
export declare function useClaudeSharedElectron(plan: DesktopLaunchPlan, runtime: string, sourceApp: string, toolArgs?: string[], launchServices?: boolean): void;
|
|
9
|
-
export declare function addClaudeDesktopHook(plan: DesktopLaunchPlan, baseUrl: string, localKey: string, sourceApp?: string, models?: string[]): void;
|
|
11
|
+
export declare function addClaudeDesktopHook(plan: DesktopLaunchPlan, baseUrl: string, localKey: string, sourceApp?: string, models?: string[], account?: DesktopAccountIdentity): void;
|
|
10
12
|
//# sourceMappingURL=claude-desktop.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-desktop.d.ts","sourceRoot":"","sources":["../../src/commands/claude-desktop.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-desktop.d.ts","sourceRoot":"","sources":["../../src/commands/claude-desktop.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAGlG;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAGhG;AAED;gFACgF;AAChF,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CA6BxF;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAsCvF;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,SAAY,GAAG,MAAM,GAAG,SAAS,CAShG;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,EAAO,EAAE,cAAc,UAAQ,GAAG,IAAI,CAI1J;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,IAAI,CA4C9K"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CliConfig } from "../config";
|
|
2
|
+
export interface DesktopAccountIdentity {
|
|
3
|
+
provider: "closedrouter";
|
|
4
|
+
name: string;
|
|
5
|
+
email?: string;
|
|
6
|
+
accountId?: string;
|
|
7
|
+
serverOrigin: string;
|
|
8
|
+
}
|
|
9
|
+
/** Use the saved ClosedRouter session only when this launch uses its server
|
|
10
|
+
* and key. An explicit foreign key must not display another user's identity. */
|
|
11
|
+
export declare function desktopAccountIdentity(config: CliConfig, server: string, key: string): DesktopAccountIdentity;
|
|
12
|
+
export declare function antigravityNativeAccountExists(geminiDir?: string): boolean;
|
|
13
|
+
//# sourceMappingURL=desktop-account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-account.d.ts","sourceRoot":"","sources":["../../src/commands/desktop-account.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,cAAc,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;gFACgF;AAChF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,sBAAsB,CAQ7G;AAED,wBAAgB,8BAA8B,CAAC,SAAS,SAAgF,GAAG,OAAO,CAOjJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launch-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/launch-catalog.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,OAAQ,MAAM,WAA0B,CAAC;AAEhE;sEACsE;AACtE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAGhF;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,+DAA+D;IAC/D,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CASrF;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"launch-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/launch-catalog.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,OAAQ,MAAM,WAA0B,CAAC;AAEhE;sEACsE;AACtE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAGhF;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,+DAA+D;IAC/D,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CASrF;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUhG;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE;IACvC,qBAAqB;IAAQ,OAAO;;;;;;EAC9C;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE;IACvC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;YAUQ,IAAI;YAAY,KAAK;;;EAE7C;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM;IAEjE,YAAY;QAAI,yBAAyB;;IACzC,YAAY;QACV,gBAAgB;;;;;;;;oBAEF,QAAQ;;;;QAEtB,aAAa;;;oBAAwE,KAAK;;;;QAC1F,kBAAkB;;;;;;EAGvB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,IAAI,CAmCrL"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export declare const CLOSEDROUTER_LOGO = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><rect width=\"24\" height=\"24\" rx=\"6\" fill=\"#D4FE51\"/><path d=\"M16.68 7.82A6.5 6.5 0 1 0 16.68 16.18\" fill=\"none\" stroke=\"#04080A\" stroke-width=\"2.6\" stroke-linecap=\"round\"/><circle cx=\"18.2\" cy=\"12\" r=\"1.9\" fill=\"#04080A\"/></svg>";
|
|
2
|
+
import type { DesktopAccountIdentity } from "./desktop-account";
|
|
3
|
+
export declare const CLOSEDROUTER_ELECTRIC_CSS = "\n[data-closedrouter-logo]{position:relative;isolation:isolate}\n[data-closedrouter-charged-control]{position:relative;perspective:420px;transform-style:preserve-3d;overflow:visible!important}\n[data-closedrouter-electric]{position:absolute;inset:0;pointer-events:none;transform-style:preserve-3d;opacity:0}\n[data-cr-lightning-orbit]{position:absolute;left:50%;top:50%;width:0;height:0;transform-style:preserve-3d}\n[data-cr-lightning-bolt]{position:absolute;width:30px;height:44px;left:-15px;top:-22px;overflow:visible;filter:drop-shadow(0 0 3px #58caff) drop-shadow(0 0 7px #159aff)}\n[data-cr-lightning-bolt=\"front\"]{transform:translateX(var(--cr-lightning-radius,70px)) rotateY(30deg)}\n[data-cr-lightning-bolt=\"back\"]{transform:rotateY(180deg) translateX(var(--cr-lightning-radius,70px)) rotateZ(24deg)}\n@keyframes cr-electric-depth{0%{opacity:0;transform:rotateX(22deg) rotateY(-150deg)}2%{opacity:1}8%{opacity:1;transform:rotateX(22deg) rotateY(25deg)}16%{opacity:.85;transform:rotateX(22deg) rotateY(210deg)}20%,100%{opacity:0;transform:rotateX(22deg) rotateY(210deg)}}\n@keyframes cr-electric-hover{0%{opacity:.1;transform:rotateX(-18deg) rotateY(-150deg)}2%{opacity:1}8%{opacity:1;transform:rotateX(-18deg) rotateY(25deg)}16%{opacity:.85;transform:rotateX(-18deg) rotateY(210deg)}20%,100%{opacity:0;transform:rotateX(-18deg) rotateY(210deg)}}\n@media(prefers-reduced-motion:no-preference){\n [data-cr-lightning-orbit]{animation:cr-electric-depth 5s linear infinite}\n [data-closedrouter-electric]{opacity:1}\n button:hover>[data-closedrouter-electric] [data-cr-lightning-orbit],button:focus-visible>[data-closedrouter-electric] [data-cr-lightning-orbit]{animation-name:cr-electric-hover}\n}\nhtml[data-closedrouter-page-hidden] [data-cr-lightning-orbit]{animation-play-state:paused}\n";
|
|
2
4
|
/** Add the provider mark to native controls without changing click handlers,
|
|
3
5
|
* model IDs, keyboard behavior, or the application's typography. */
|
|
4
|
-
export declare function installModelBranding(models: string[], artwork: string): void;
|
|
5
|
-
export declare function
|
|
6
|
+
export declare function installModelBranding(models: string[], artwork: string, electricCss: string): void;
|
|
7
|
+
export declare function installProviderAccountUi(account: DesktopAccountIdentity, artwork: string): void;
|
|
8
|
+
export declare function modelBrandingHook(models: string[], account?: DesktopAccountIdentity): string;
|
|
6
9
|
//# sourceMappingURL=model-branding.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-branding.d.ts","sourceRoot":"","sources":["../../src/commands/model-branding.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,mUAAqS,CAAC;
|
|
1
|
+
{"version":3,"file":"model-branding.d.ts","sourceRoot":"","sources":["../../src/commands/model-branding.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,mUAAqS,CAAC;AACpU,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,eAAO,MAAM,yBAAyB,6wDAgBrC,CAAC;AAEF;oEACoE;AACpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CA0DjG;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAmC/F;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAS5F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAclE,OAAO,EAA6F,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjJ,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AAChG,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,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;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;IACxB,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzF;AAmBD,wBAAgB,mBAAmB,CAAC,WAAW,UAAQ;;;;IAEtD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAUxG;AAqBD,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,EACzD,OAAO,CAAC,EAAE,aAAa,GACtB,UAAU,CAyHZ;AAeD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAKlF;AAuED,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6HnF"}
|
package/dist/index.js
CHANGED
|
@@ -5204,7 +5204,7 @@ var {
|
|
|
5204
5204
|
} = exports_commander;
|
|
5205
5205
|
|
|
5206
5206
|
// src/index.ts
|
|
5207
|
-
import { readFileSync as
|
|
5207
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
5208
5208
|
|
|
5209
5209
|
// ../node_modules/.bun/@clack+prompts@0.11.0/node_modules/@clack/prompts/dist/index.mjs
|
|
5210
5210
|
import { stripVTControlCharacters as S2 } from "node:util";
|
|
@@ -8659,9 +8659,9 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
|
8659
8659
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
8660
8660
|
import { spawn as spawn5 } from "node:child_process";
|
|
8661
8661
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
8662
|
-
import { mkdirSync as mkdirSync5, readFileSync as
|
|
8663
|
-
import { homedir as
|
|
8664
|
-
import { dirname as dirname5, join as
|
|
8662
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync15, writeFileSync as writeFileSync5 } from "node:fs";
|
|
8663
|
+
import { homedir as homedir15 } from "node:os";
|
|
8664
|
+
import { dirname as dirname5, join as join17 } from "node:path";
|
|
8665
8665
|
|
|
8666
8666
|
// src/model-picker.ts
|
|
8667
8667
|
import { emitKeypressEvents as emitKeypressEvents2 } from "node:readline";
|
|
@@ -9445,6 +9445,8 @@ function resolveLaunchModel(catalog, requested) {
|
|
|
9445
9445
|
id = fireworks[1];
|
|
9446
9446
|
if (catalog.models.includes(id))
|
|
9447
9447
|
return id;
|
|
9448
|
+
if (id.startsWith("ClosedRouter: ") && catalog.models.includes(id.slice(14)))
|
|
9449
|
+
return id.slice(14);
|
|
9448
9450
|
if (id.startsWith("closedrouter/") && catalog.models.includes(id.slice(13)))
|
|
9449
9451
|
return id.slice(13);
|
|
9450
9452
|
if (Object.hasOwn(catalog.aliases, id))
|
|
@@ -9596,7 +9598,7 @@ async function startLaunchProxy(gatewayUrl, apiKey, harness, localKey = apiKey,
|
|
|
9596
9598
|
const requested = gemini ? decodeURIComponent(gemini[1]) : typeof payload.model === "string" ? payload.model : catalog?.defaultModel || "";
|
|
9597
9599
|
const model = catalog ? resolveLaunchModel(catalog, requested) : modelOverride;
|
|
9598
9600
|
if (!model) {
|
|
9599
|
-
outgoing.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: { type: "invalid_request_error", message:
|
|
9601
|
+
outgoing.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: { type: "invalid_request_error", message: `Model ${JSON.stringify(requested)} is not in this launch's ClosedRouter catalog. Choose a supported model from the picker.` } }));
|
|
9600
9602
|
return;
|
|
9601
9603
|
}
|
|
9602
9604
|
const tinyProbe = local.pathname === "/v1/messages" && !model.startsWith("claude-") && payload.model !== model && typeof payload.max_tokens === "number" && payload.max_tokens <= 16 && Array.isArray(payload.messages) && payload.messages.length === 1 && (!Array.isArray(payload.tools) || payload.tools.length === 0);
|
|
@@ -10175,6 +10177,23 @@ import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node
|
|
|
10175
10177
|
import { homedir as homedir12 } from "node:os";
|
|
10176
10178
|
import { join as join13 } from "node:path";
|
|
10177
10179
|
|
|
10180
|
+
// src/commands/agy-desktop-account.ts
|
|
10181
|
+
function patchAntigravityAccount(source, account) {
|
|
10182
|
+
const validator = /async function ([\w$]+)\(([\w$]+),([\w$]+)=0\)\{(?=var [\w$]+=d,[\w$]+=d;try\{if\(!\2\.isLoggingOut\))/;
|
|
10183
|
+
if (!validator.test(source) || !source.includes("._lsClient.hasAuthToken({})"))
|
|
10184
|
+
throw new Error("This Antigravity build has an unsupported provider authentication controller.");
|
|
10185
|
+
source = source.replace(validator, (start, _fn, service) => start + `if(!(await ${service}._lsClient.hasAuthToken({})).hasToken){${service}._closedrouterProviderSession=true;document.documentElement.dataset.closedrouterAccount='true';${service}._authStateProvider.setState({state:'signedIn',context:{...${service}._authStateProvider.getState().context,closedrouterProvider:true}});return;}`);
|
|
10186
|
+
const status = /([\w$]+)=\(\)=>\{var ([\w$]+)=([\w$]+)\(\),([\w$]+)=Bj\(\2\),([\w$]+)=zj\(\)\.get\("models"\)\?\.geminiModelsOnly===!0;return\(0,([\w$]+)\.useMemo\)\(\(\)=>([\w$]+)\(\4,\5\),\[\4,\5\]\)\}/;
|
|
10187
|
+
if (!status.test(source))
|
|
10188
|
+
throw new Error("This Antigravity build has an unsupported account metadata provider.");
|
|
10189
|
+
source = source.replace(status, (all, _fn, _provider, _getProvider, state, filter, _react, transform) => all.replace(`${transform}(${state},${filter})`, `(document.documentElement.dataset.closedrouterAccount==='true'?{...(${state}||{}),name:${JSON.stringify(account.name)},email:${JSON.stringify(account.email || "")},userTier:{description:'ClosedRouter'},cascadeModelConfigData:{clientModelConfigs:[],clientModelSorts:[]}}:${transform}(${state},${filter}))`));
|
|
10190
|
+
const onboarding = /agentOnboardingState:([\w$]+)\.agentOnboardingCompleted===2\?2:1/;
|
|
10191
|
+
if (!onboarding.test(source))
|
|
10192
|
+
throw new Error("This Antigravity build has an unsupported startup onboarding controller.");
|
|
10193
|
+
source = source.replace(onboarding, "agentOnboardingState:2");
|
|
10194
|
+
return source;
|
|
10195
|
+
}
|
|
10196
|
+
|
|
10178
10197
|
// src/commands/agy-desktop-catalog.ts
|
|
10179
10198
|
function patchAntigravityCatalog(source, catalog) {
|
|
10180
10199
|
const provider = /this\.customModelsProvider=([\w$]+)\(this\.rootProvider,([\w$]+)=>\(\{customModels:\2\.appState\?\.customModelsConfig\?\.customModels\?\?\{\}\}\)\)/;
|
|
@@ -10203,10 +10222,11 @@ function patchAntigravityCatalog(source, catalog) {
|
|
|
10203
10222
|
body = body.replace(state, (_all, value, setter, react) => `[${value},${setter}]=(0,${react}.useState)(${JSON.stringify(`ClosedRouter: ${catalog.defaultModel}`)})`).replace(/\([\w$]+\?\.cascadeModelConfigData\?\.clientModelConfigs\|\|\[\]\)/g, "([])").replace(/[\w$]+\?\.clientModelConfigs\|\|\[\]/g, "[]").replace(/[\w$]+\?\.clientModelSorts\|\|\[\]/g, "[]");
|
|
10204
10223
|
return source.slice(0, start) + body + source.slice(end);
|
|
10205
10224
|
}
|
|
10206
|
-
function antigravityCatalogHook(catalog, marker) {
|
|
10225
|
+
function antigravityCatalogHook(catalog, marker, account) {
|
|
10207
10226
|
return `
|
|
10208
10227
|
const {app} = require('electron');
|
|
10209
10228
|
const patchCatalog = ${patchAntigravityCatalog.toString()};
|
|
10229
|
+
${account ? `const patchAccount = ${patchAntigravityAccount.toString()};` : ""}
|
|
10210
10230
|
app.on('web-contents-created', (_event, contents) => {
|
|
10211
10231
|
const debuggerClient = contents.debugger;
|
|
10212
10232
|
try {
|
|
@@ -10221,7 +10241,7 @@ app.on('web-contents-created', (_event, contents) => {
|
|
|
10221
10241
|
}
|
|
10222
10242
|
const result = await debuggerClient.sendCommand('Fetch.getResponseBody', {requestId:params.requestId});
|
|
10223
10243
|
const source = result.base64Encoded ? Buffer.from(result.body,'base64').toString('utf8') : result.body;
|
|
10224
|
-
const patched = patchCatalog(source, ${JSON.stringify(catalog)});
|
|
10244
|
+
const patched = patchCatalog(${account ? `patchAccount(source, ${JSON.stringify(account)})` : "source"}, ${JSON.stringify(catalog)});
|
|
10225
10245
|
await debuggerClient.sendCommand('Fetch.fulfillRequest', {requestId:params.requestId,responseCode:200,
|
|
10226
10246
|
responseHeaders:(params.responseHeaders || []).filter(h=>!['content-length','content-encoding','transfer-encoding'].includes(h.name.toLowerCase())),
|
|
10227
10247
|
body:Buffer.from(patched).toString('base64')});
|
|
@@ -10242,12 +10262,35 @@ app.on('web-contents-created', (_event, contents) => {
|
|
|
10242
10262
|
|
|
10243
10263
|
// src/commands/model-branding.ts
|
|
10244
10264
|
var CLOSEDROUTER_LOGO = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect width="24" height="24" rx="6" fill="#D4FE51"/><path d="M16.68 7.82A6.5 6.5 0 1 0 16.68 16.18" fill="none" stroke="#04080A" stroke-width="2.6" stroke-linecap="round"/><circle cx="18.2" cy="12" r="1.9" fill="#04080A"/></svg>';
|
|
10245
|
-
|
|
10265
|
+
var CLOSEDROUTER_ELECTRIC_CSS = `
|
|
10266
|
+
[data-closedrouter-logo]{position:relative;isolation:isolate}
|
|
10267
|
+
[data-closedrouter-charged-control]{position:relative;perspective:420px;transform-style:preserve-3d;overflow:visible!important}
|
|
10268
|
+
[data-closedrouter-electric]{position:absolute;inset:0;pointer-events:none;transform-style:preserve-3d;opacity:0}
|
|
10269
|
+
[data-cr-lightning-orbit]{position:absolute;left:50%;top:50%;width:0;height:0;transform-style:preserve-3d}
|
|
10270
|
+
[data-cr-lightning-bolt]{position:absolute;width:30px;height:44px;left:-15px;top:-22px;overflow:visible;filter:drop-shadow(0 0 3px #58caff) drop-shadow(0 0 7px #159aff)}
|
|
10271
|
+
[data-cr-lightning-bolt="front"]{transform:translateX(var(--cr-lightning-radius,70px)) rotateY(30deg)}
|
|
10272
|
+
[data-cr-lightning-bolt="back"]{transform:rotateY(180deg) translateX(var(--cr-lightning-radius,70px)) rotateZ(24deg)}
|
|
10273
|
+
@keyframes cr-electric-depth{0%{opacity:0;transform:rotateX(22deg) rotateY(-150deg)}2%{opacity:1}8%{opacity:1;transform:rotateX(22deg) rotateY(25deg)}16%{opacity:.85;transform:rotateX(22deg) rotateY(210deg)}20%,100%{opacity:0;transform:rotateX(22deg) rotateY(210deg)}}
|
|
10274
|
+
@keyframes cr-electric-hover{0%{opacity:.1;transform:rotateX(-18deg) rotateY(-150deg)}2%{opacity:1}8%{opacity:1;transform:rotateX(-18deg) rotateY(25deg)}16%{opacity:.85;transform:rotateX(-18deg) rotateY(210deg)}20%,100%{opacity:0;transform:rotateX(-18deg) rotateY(210deg)}}
|
|
10275
|
+
@media(prefers-reduced-motion:no-preference){
|
|
10276
|
+
[data-cr-lightning-orbit]{animation:cr-electric-depth 5s linear infinite}
|
|
10277
|
+
[data-closedrouter-electric]{opacity:1}
|
|
10278
|
+
button:hover>[data-closedrouter-electric] [data-cr-lightning-orbit],button:focus-visible>[data-closedrouter-electric] [data-cr-lightning-orbit]{animation-name:cr-electric-hover}
|
|
10279
|
+
}
|
|
10280
|
+
html[data-closedrouter-page-hidden] [data-cr-lightning-orbit]{animation-play-state:paused}
|
|
10281
|
+
`;
|
|
10282
|
+
function installModelBranding(models, artwork, electricCss) {
|
|
10246
10283
|
if (document.querySelector("[data-closedrouter-branding]"))
|
|
10247
10284
|
return;
|
|
10248
10285
|
const marker = document.createElement("meta");
|
|
10249
10286
|
marker.dataset.closedrouterBranding = "true";
|
|
10250
10287
|
document.head.append(marker);
|
|
10288
|
+
const style = document.createElement("style");
|
|
10289
|
+
style.textContent = electricCss;
|
|
10290
|
+
document.head.append(style);
|
|
10291
|
+
document.addEventListener("visibilitychange", () => {
|
|
10292
|
+
document.documentElement.toggleAttribute("data-closedrouter-page-hidden", document.hidden);
|
|
10293
|
+
});
|
|
10251
10294
|
const paint = () => {
|
|
10252
10295
|
for (const element of document.querySelectorAll('button,[role="button"],[role="option"],[role="menuitem"],[role="menuitemradio"],[data-testid="model-selector-item"]')) {
|
|
10253
10296
|
const text = element.innerText.trim().split(`
|
|
@@ -10263,12 +10306,35 @@ function installModelBranding(models, artwork) {
|
|
|
10263
10306
|
}
|
|
10264
10307
|
if (element.querySelector(":scope > [data-closedrouter-logo]"))
|
|
10265
10308
|
continue;
|
|
10266
|
-
const logo = document.createElement("
|
|
10267
|
-
|
|
10268
|
-
|
|
10309
|
+
const logo = document.createElement("span");
|
|
10310
|
+
const image = document.createElement("img");
|
|
10311
|
+
image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(artwork)}`;
|
|
10312
|
+
image.alt = "ClosedRouter";
|
|
10313
|
+
image.style.cssText = "display:block;width:16px;height:16px";
|
|
10269
10314
|
logo.title = "Routed through ClosedRouter";
|
|
10270
10315
|
logo.dataset.closedrouterLogo = "true";
|
|
10271
10316
|
logo.style.cssText = "width:16px;height:16px;flex:0 0 16px;display:inline-block;vertical-align:middle;margin-inline-end:6px;pointer-events:none";
|
|
10317
|
+
logo.append(image);
|
|
10318
|
+
if (element.matches("button") && !element.closest('[role="menu"],[role="listbox"],[role="dialog"]') && document.querySelector('[contenteditable="true"],textarea')) {
|
|
10319
|
+
logo.dataset.closedrouterSupercharged = "true";
|
|
10320
|
+
element.dataset.closedrouterChargedControl = "true";
|
|
10321
|
+
element.style.setProperty("--cr-lightning-radius", `${Math.max(35, element.getBoundingClientRect().width / 2 + 10)}px`);
|
|
10322
|
+
const layer = document.createElement("span");
|
|
10323
|
+
layer.dataset.closedrouterElectric = "true";
|
|
10324
|
+
layer.setAttribute("aria-hidden", "true");
|
|
10325
|
+
const orbit = document.createElement("span");
|
|
10326
|
+
orbit.dataset.crLightningOrbit = "true";
|
|
10327
|
+
for (const position of ["front", "back"]) {
|
|
10328
|
+
const bolt = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
10329
|
+
bolt.setAttribute("viewBox", "0 0 30 44");
|
|
10330
|
+
bolt.setAttribute("data-cr-lightning-bolt", position);
|
|
10331
|
+
const path = "M23 2 11 13 19 15 5 30 13 29 7 42 M11 13 3 11 M19 15 27 23";
|
|
10332
|
+
bolt.innerHTML = `<path d="${path}" fill="none" stroke="#42bdff" stroke-width="4.2" stroke-linecap="round" stroke-linejoin="round"/><path d="${path}" fill="none" stroke="#f5fcff" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/>`;
|
|
10333
|
+
orbit.append(bolt);
|
|
10334
|
+
}
|
|
10335
|
+
layer.append(orbit);
|
|
10336
|
+
element.append(layer);
|
|
10337
|
+
}
|
|
10272
10338
|
element.prepend(logo);
|
|
10273
10339
|
}
|
|
10274
10340
|
};
|
|
@@ -10285,8 +10351,74 @@ function installModelBranding(models, artwork) {
|
|
|
10285
10351
|
observer.observe(document.documentElement, { childList: true, subtree: true, characterData: true });
|
|
10286
10352
|
paint();
|
|
10287
10353
|
}
|
|
10288
|
-
function
|
|
10289
|
-
const
|
|
10354
|
+
function installProviderAccountUi(account, artwork) {
|
|
10355
|
+
const createCard = () => {
|
|
10356
|
+
const card = document.createElement("section");
|
|
10357
|
+
card.id = "closedrouter-provider-account";
|
|
10358
|
+
card.setAttribute("aria-label", "ClosedRouter account");
|
|
10359
|
+
card.style.cssText = "display:flex;gap:12px;align-items:center;padding:12px 8px;margin:4px 0;border-bottom:1px solid color-mix(in srgb,currentColor 15%,transparent)";
|
|
10360
|
+
const logo = document.createElement("img");
|
|
10361
|
+
logo.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(artwork)}`;
|
|
10362
|
+
logo.alt = "ClosedRouter";
|
|
10363
|
+
logo.width = 28;
|
|
10364
|
+
logo.height = 28;
|
|
10365
|
+
const details = document.createElement("div");
|
|
10366
|
+
for (const text of [account.name, account.email, "Connected through ClosedRouter"])
|
|
10367
|
+
if (text) {
|
|
10368
|
+
const line = document.createElement("div");
|
|
10369
|
+
line.textContent = text;
|
|
10370
|
+
details.append(line);
|
|
10371
|
+
}
|
|
10372
|
+
card.append(logo, details);
|
|
10373
|
+
return card;
|
|
10374
|
+
};
|
|
10375
|
+
const paint = () => {
|
|
10376
|
+
let providerSession = document.documentElement.dataset.closedrouterAccount === "true";
|
|
10377
|
+
for (const button of document.querySelectorAll("button")) {
|
|
10378
|
+
if (!button.innerText.includes(account.name) || !button.innerText.includes("Gateway"))
|
|
10379
|
+
continue;
|
|
10380
|
+
providerSession = true;
|
|
10381
|
+
document.documentElement.dataset.closedrouterAccount = "true";
|
|
10382
|
+
if (button.querySelector("[data-closedrouter-account-logo]"))
|
|
10383
|
+
continue;
|
|
10384
|
+
const logo = document.createElement("img");
|
|
10385
|
+
logo.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(artwork)}`;
|
|
10386
|
+
logo.alt = "ClosedRouter account";
|
|
10387
|
+
logo.width = 24;
|
|
10388
|
+
logo.height = 24;
|
|
10389
|
+
logo.dataset.closedrouterAccountLogo = "true";
|
|
10390
|
+
logo.style.cssText = "flex:0 0 24px;margin-inline-end:8px";
|
|
10391
|
+
button.prepend(logo);
|
|
10392
|
+
}
|
|
10393
|
+
if (!providerSession || document.getElementById("closedrouter-provider-account"))
|
|
10394
|
+
return;
|
|
10395
|
+
const menu = document.querySelector('[role="menu"]');
|
|
10396
|
+
if (menu && /Settings|Account|Sign out|Log out/i.test(menu.innerText)) {
|
|
10397
|
+
menu.prepend(createCard());
|
|
10398
|
+
return;
|
|
10399
|
+
}
|
|
10400
|
+
const heading = [...document.querySelectorAll("h1,h2,h3,[role=heading]")].find((node) => node.innerText.trim() === "Account");
|
|
10401
|
+
if (!heading)
|
|
10402
|
+
return;
|
|
10403
|
+
heading.parentElement?.insertBefore(createCard(), heading.nextSibling);
|
|
10404
|
+
for (const button of document.querySelectorAll("button"))
|
|
10405
|
+
if (["Sign Out", "Sign In"].includes(button.innerText.trim()))
|
|
10406
|
+
button.hidden = true;
|
|
10407
|
+
};
|
|
10408
|
+
let queued = false;
|
|
10409
|
+
new MutationObserver(() => {
|
|
10410
|
+
if (!queued) {
|
|
10411
|
+
queued = true;
|
|
10412
|
+
queueMicrotask(() => {
|
|
10413
|
+
queued = false;
|
|
10414
|
+
paint();
|
|
10415
|
+
});
|
|
10416
|
+
}
|
|
10417
|
+
}).observe(document.documentElement, { subtree: true, childList: true });
|
|
10418
|
+
paint();
|
|
10419
|
+
}
|
|
10420
|
+
function modelBrandingHook(models, account) {
|
|
10421
|
+
const script = `(${installModelBranding.toString()})(${JSON.stringify(models)},${JSON.stringify(CLOSEDROUTER_LOGO)},${JSON.stringify(CLOSEDROUTER_ELECTRIC_CSS)});` + (account ? `(${installProviderAccountUi.toString()})(${JSON.stringify(account)},${JSON.stringify(CLOSEDROUTER_LOGO)})` : "");
|
|
10290
10422
|
return `
|
|
10291
10423
|
require('electron').app.on('web-contents-created', (_event, contents) => {
|
|
10292
10424
|
contents.on('did-finish-load', () => {
|
|
@@ -10333,7 +10465,7 @@ function assertAntigravityDesktopHookSupport(executable) {
|
|
|
10333
10465
|
if (index < 0 || binary[index + 32 + 5] !== 49)
|
|
10334
10466
|
throw new Error("This Antigravity build disables launch inspector hooks. Use --open-only.");
|
|
10335
10467
|
}
|
|
10336
|
-
async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_PROXY_URL, catalog) {
|
|
10468
|
+
async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_PROXY_URL, catalog, account) {
|
|
10337
10469
|
const capability = randomUUID4();
|
|
10338
10470
|
const controllers = new Set;
|
|
10339
10471
|
const server = createServer4(async (incoming, outgoing) => {
|
|
@@ -10363,6 +10495,12 @@ async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_
|
|
|
10363
10495
|
chunks.push(Buffer.from(chunk));
|
|
10364
10496
|
}
|
|
10365
10497
|
const raw = Buffer.concat(chunks);
|
|
10498
|
+
if (account && !generation) {
|
|
10499
|
+
const tier = { id: "closedrouter", name: "ClosedRouter", description: "ClosedRouter account" };
|
|
10500
|
+
const metadata = path.endsWith(":loadCodeAssist") ? { currentTier: tier, allowedTiers: [tier], cloudaicompanionProject: "closedrouter", gcpManaged: false } : path.endsWith(":fetchAvailableModels") ? { models: {}, agentModelSorts: [], defaultAgentModelId: "" } : {};
|
|
10501
|
+
outgoing.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(metadata));
|
|
10502
|
+
return;
|
|
10503
|
+
}
|
|
10366
10504
|
const headers = {};
|
|
10367
10505
|
let target;
|
|
10368
10506
|
let payload = raw;
|
|
@@ -10461,7 +10599,7 @@ async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_
|
|
|
10461
10599
|
})
|
|
10462
10600
|
};
|
|
10463
10601
|
}
|
|
10464
|
-
function addAntigravityDesktopHook(plan, endpoint, catalog) {
|
|
10602
|
+
function addAntigravityDesktopHook(plan, endpoint, catalog, account, provider) {
|
|
10465
10603
|
const path = join13(plan.profileDir, "antigravity-hook.cjs");
|
|
10466
10604
|
const marker = join13(plan.profileDir, "model-catalog-ready");
|
|
10467
10605
|
const contents = `const cp = require('node:child_process');
|
|
@@ -10480,12 +10618,21 @@ cp.spawn = function(command, args, options) {
|
|
|
10480
10618
|
const csrf = args.indexOf('--csrf_token');
|
|
10481
10619
|
if (csrf >= 0) args.splice(csrf, 2, '--csrf_token=' + args[csrf + 1]);
|
|
10482
10620
|
options = { ...options, env: { ...options?.env } };
|
|
10621
|
+
${account && provider ? `
|
|
10622
|
+
for (const [flag,value] of [['--model_api_client_type','gemini'],['--api_server_url',${JSON.stringify(provider.baseUrl)}],['--gemini_dir',${JSON.stringify(provider.nativeDir || join13(plan.profileDir, "gemini"))}]]) {
|
|
10623
|
+
const i=args.indexOf(flag);if(i>=0)args[i+1]=value;else args.push(flag,value);
|
|
10624
|
+
}
|
|
10625
|
+
options.env.GEMINI_API_KEY=${JSON.stringify(provider.localKey)};
|
|
10626
|
+
options.env.GOOGLE_GEMINI_BASE_URL=${JSON.stringify(provider.baseUrl)};
|
|
10627
|
+
delete options.env.GOOGLE_API_KEY;
|
|
10628
|
+
args.push('--disable_telemetry=true');
|
|
10629
|
+
` : ""}
|
|
10483
10630
|
delete options.env.NODE_OPTIONS;
|
|
10484
10631
|
}
|
|
10485
10632
|
return spawn.call(this, command, args, options);
|
|
10486
10633
|
};
|
|
10487
10634
|
require('node:fs').writeFileSync(${JSON.stringify(join13(plan.profileDir, "hook-loaded"))}, 'ready', {mode: 0o600});
|
|
10488
|
-
` + (catalog ? antigravityCatalogHook(catalog, marker) + modelBrandingHook(catalog.models) : "");
|
|
10635
|
+
` + (catalog ? antigravityCatalogHook(catalog, marker, account) + modelBrandingHook(catalog.models, account) : "");
|
|
10489
10636
|
plan.files.push({ path, contents });
|
|
10490
10637
|
const logPath = join13(plan.profileDir, "inspector.log");
|
|
10491
10638
|
plan.inspectorHook = { path, logPath, ...catalog ? { readyPath: marker } : {} };
|
|
@@ -10502,6 +10649,10 @@ import { createHash as createHash3 } from "node:crypto";
|
|
|
10502
10649
|
import { copyFileSync, existsSync as existsSync14, linkSync, lstatSync, mkdirSync as mkdirSync4, mkdtempSync as mkdtempSync2, readFileSync as readFileSync12, readdirSync as readdirSync2, readlinkSync, realpathSync, renameSync as renameSync2, rmSync, statSync as statSync2, symlinkSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
10503
10650
|
import { homedir as homedir13 } from "node:os";
|
|
10504
10651
|
import { dirname as dirname3, join as join14, relative as relative2 } from "node:path";
|
|
10652
|
+
function patchClaudeAccountIdentity(source, account) {
|
|
10653
|
+
const fallback = /if\(([\w$]+)\)return \1;let ([\w$]+)=([\w$]+)\(\);return \2\?\{name:\2,source:"os"\}:void 0(?=\}function)/;
|
|
10654
|
+
return source.replace(fallback, (_all, existing) => `if(${existing})return ${existing};return ${JSON.stringify({ name: account.name, email: account.email, source: "closedrouter" })}`);
|
|
10655
|
+
}
|
|
10505
10656
|
function patchClaudeModelIdentity(source, aliases) {
|
|
10506
10657
|
return source.replace(/function ([\w$]+)\(\{modelId:([\w$]+),provider:([\w$]+),labelOverride:([\w$]+)\}\)\{/, (start, _name, id) => start + `const closedrouterIdentity=${JSON.stringify(aliases)}[${id}];if(closedrouterIdentity)return 'Your configured inference model ID is '+closedrouterIdentity+'. Your inference provider is ClosedRouter. The client and its transport alias do not identify the underlying inference model.';`);
|
|
10507
10658
|
}
|
|
@@ -10601,7 +10752,7 @@ function useClaudeSharedElectron(plan, runtime, sourceApp, toolArgs = [], launch
|
|
|
10601
10752
|
plan.command = launchServices ? "/usr/bin/open" : runtime;
|
|
10602
10753
|
plan.args = launchServices ? ["-W", "-n", "-a", dirname3(dirname3(dirname3(runtime))), "--args", ...args] : args;
|
|
10603
10754
|
}
|
|
10604
|
-
function addClaudeDesktopHook(plan, baseUrl, localKey, sourceApp, models) {
|
|
10755
|
+
function addClaudeDesktopHook(plan, baseUrl, localKey, sourceApp, models, account) {
|
|
10605
10756
|
const path = join14(plan.profileDir, "claude-hook.cjs");
|
|
10606
10757
|
plan.files.push({ path, contents: `${sourceApp ? `const electron = require('electron');
|
|
10607
10758
|
Object.defineProperty(process, 'resourcesPath', {value: ${JSON.stringify(join14(sourceApp, "Contents/Resources"))}});
|
|
@@ -10627,11 +10778,12 @@ require('node:fs').writeFileSync(${JSON.stringify(join14(plan.profileDir, "hook-
|
|
|
10627
10778
|
` + (models && sourceApp ? `
|
|
10628
10779
|
const moduleHooks = require('node:module');
|
|
10629
10780
|
const patchIdentity = ${patchClaudeModelIdentity.toString()};
|
|
10781
|
+
${account ? `const patchAccount = ${patchClaudeAccountIdentity.toString()};` : ""}
|
|
10630
10782
|
if (typeof moduleHooks.registerHooks === 'function') moduleHooks.registerHooks({load(url, context, nextLoad) {
|
|
10631
10783
|
const loaded = nextLoad(url, context);
|
|
10632
10784
|
if (url.startsWith('file:') && require('node:url').fileURLToPath(url).startsWith(${JSON.stringify(join14(sourceApp, "Contents/Resources/app.asar/.vite/build/"))}) && loaded.source != null) {
|
|
10633
10785
|
const source = typeof loaded.source === 'string' ? loaded.source : Buffer.from(loaded.source).toString('utf8');
|
|
10634
|
-
const patched = patchIdentity(source, ${JSON.stringify(Object.fromEntries(models.map((id) => [transportModelId(id, "claude"), id])))});
|
|
10786
|
+
const patched = ${account ? "patchAccount(" : ""}patchIdentity(source, ${JSON.stringify(Object.fromEntries(models.map((id) => [transportModelId(id, "claude"), id])))}${account ? `),${JSON.stringify(account)})` : ")"};
|
|
10635
10787
|
if (patched !== source) {
|
|
10636
10788
|
require('node:fs').writeFileSync(${JSON.stringify(join14(plan.profileDir, "model-identity-hook-ready"))}, 'ready', {mode:0o600});
|
|
10637
10789
|
return {...loaded, source:patched};
|
|
@@ -10639,7 +10791,7 @@ if (typeof moduleHooks.registerHooks === 'function') moduleHooks.registerHooks({
|
|
|
10639
10791
|
}
|
|
10640
10792
|
return loaded;
|
|
10641
10793
|
}});
|
|
10642
|
-
` : "") + (models ? modelBrandingHook(models) : "") });
|
|
10794
|
+
` : "") + (models ? modelBrandingHook(models, account) : "") });
|
|
10643
10795
|
const logPath = join14(plan.profileDir, "inspector.log");
|
|
10644
10796
|
plan.inspectorHook = { path, logPath };
|
|
10645
10797
|
plan.args.push("--inspect-brk=127.0.0.1:0");
|
|
@@ -10750,6 +10902,33 @@ require('node:fs').writeFileSync(${JSON.stringify(join15(plan.profileDir, "hook-
|
|
|
10750
10902
|
plan.args.splice(plan.args.indexOf("--args"), 0, "--stderr", logPath);
|
|
10751
10903
|
}
|
|
10752
10904
|
|
|
10905
|
+
// src/commands/desktop-account.ts
|
|
10906
|
+
import { existsSync as existsSync16, readFileSync as readFileSync14 } from "node:fs";
|
|
10907
|
+
import { homedir as homedir14 } from "node:os";
|
|
10908
|
+
import { join as join16 } from "node:path";
|
|
10909
|
+
function desktopAccountIdentity(config, server, key) {
|
|
10910
|
+
const sameAccount = config.apiKey === key && config.serverUrl.replace(/\/+$/, "") === server.replace(/\/+$/, "");
|
|
10911
|
+
const user = sameAccount ? config.user : undefined;
|
|
10912
|
+
return {
|
|
10913
|
+
provider: "closedrouter",
|
|
10914
|
+
name: user?.name?.trim() || user?.email?.trim() || "ClosedRouter API key",
|
|
10915
|
+
...user?.email ? { email: user.email } : {},
|
|
10916
|
+
...user?.id ? { accountId: user.id } : {},
|
|
10917
|
+
serverOrigin: new URL(server).origin
|
|
10918
|
+
};
|
|
10919
|
+
}
|
|
10920
|
+
function antigravityNativeAccountExists(geminiDir = process.env.CLOSEDROUTER_ANTIGRAVITY_NATIVE_DIR || join16(homedir14(), ".gemini")) {
|
|
10921
|
+
const path = join16(geminiDir, "jetski-standalone-oauth-token");
|
|
10922
|
+
if (!existsSync16(path))
|
|
10923
|
+
return false;
|
|
10924
|
+
try {
|
|
10925
|
+
const value = JSON.parse(readFileSync14(path, "utf8"));
|
|
10926
|
+
return Boolean(value?.token?.refresh_token || value?.token?.access_token);
|
|
10927
|
+
} catch {
|
|
10928
|
+
return false;
|
|
10929
|
+
}
|
|
10930
|
+
}
|
|
10931
|
+
|
|
10753
10932
|
// src/commands/start.ts
|
|
10754
10933
|
function isGatewayModelAvailable(availableModels, model) {
|
|
10755
10934
|
return availableModels.includes(model);
|
|
@@ -10796,7 +10975,7 @@ function assertNoManagedCodexArgs(args) {
|
|
|
10796
10975
|
throw new Error(`Remove ${conflicting}; ClosedRouter manages the Codex profile and model. Put other arguments after --.`);
|
|
10797
10976
|
}
|
|
10798
10977
|
}
|
|
10799
|
-
function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir =
|
|
10978
|
+
function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir = homedir15(), executablePath, agyRouting, catalog) {
|
|
10800
10979
|
const baseUrl = normalizeServerUrl(serverUrl);
|
|
10801
10980
|
const env = { ...process.env };
|
|
10802
10981
|
const command = executablePath || tool;
|
|
@@ -10822,10 +11001,10 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
10822
11001
|
}
|
|
10823
11002
|
if (tool === "codex") {
|
|
10824
11003
|
assertNoManagedCodexArgs(toolArgs);
|
|
10825
|
-
const codexHome = process.env.CODEX_HOME ||
|
|
11004
|
+
const codexHome = process.env.CODEX_HOME || join17(homeDir, ".codex");
|
|
10826
11005
|
const profileName = "closedrouter-launch";
|
|
10827
|
-
const configPath =
|
|
10828
|
-
const catalogPath =
|
|
11006
|
+
const configPath = join17(codexHome, `${profileName}.config.toml`);
|
|
11007
|
+
const catalogPath = join17(codexHome, "closedrouter-models.json");
|
|
10829
11008
|
const configLines = [
|
|
10830
11009
|
`model = ${tomlString(model)}`,
|
|
10831
11010
|
`model_provider = ${tomlString(profileName)}`,
|
|
@@ -10853,7 +11032,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
10853
11032
|
env.GEMINI_API_KEY = apiKey;
|
|
10854
11033
|
env.GEMINI_MODEL = model;
|
|
10855
11034
|
env.GOOGLE_GEMINI_BASE_URL = baseUrl;
|
|
10856
|
-
const configPath =
|
|
11035
|
+
const configPath = join17(homeDir, ".closedrouter", "gemini-launch.settings.json");
|
|
10857
11036
|
env.GEMINI_CLI_SYSTEM_SETTINGS_PATH = configPath;
|
|
10858
11037
|
return {
|
|
10859
11038
|
tool,
|
|
@@ -10888,9 +11067,9 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
10888
11067
|
return {
|
|
10889
11068
|
tool,
|
|
10890
11069
|
command,
|
|
10891
|
-
args: ["--model", `openai/${catalog ? "closedrouter/" : ""}${model}`, ...catalog ? ["--model-metadata-file",
|
|
11070
|
+
args: ["--model", `openai/${catalog ? "closedrouter/" : ""}${model}`, ...catalog ? ["--model-metadata-file", join17(homeDir, ".closedrouter", "aider-models.json")] : [], ...toolArgs],
|
|
10892
11071
|
env,
|
|
10893
|
-
...catalog ? { configFile: { path:
|
|
11072
|
+
...catalog ? { configFile: { path: join17(homeDir, ".closedrouter", "aider-models.json"), contents: JSON.stringify(Object.fromEntries(catalog.models.map((id) => [`openai/closedrouter/${id}`, { litellm_provider: "openai", mode: "chat", max_input_tokens: 8192, max_output_tokens: 4096, supports_function_calling: true }]))) } } : {}
|
|
10894
11073
|
};
|
|
10895
11074
|
}
|
|
10896
11075
|
const config = {
|
|
@@ -10919,7 +11098,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
10919
11098
|
function writeOwnedConfig(file) {
|
|
10920
11099
|
mkdirSync5(dirname5(file.path), { recursive: true, mode: 448 });
|
|
10921
11100
|
try {
|
|
10922
|
-
const existing =
|
|
11101
|
+
const existing = readFileSync15(file.path, "utf8");
|
|
10923
11102
|
if (file.path.endsWith(".config.toml") && !existing.includes('name = "ClosedRouter"')) {
|
|
10924
11103
|
throw new Error(`Refusing to replace an existing Codex profile at ${file.path}.`);
|
|
10925
11104
|
}
|
|
@@ -10956,9 +11135,9 @@ function assertAgyCustomModel(command, label, apiKey) {
|
|
|
10956
11135
|
throw new Error(`This version of agy did not recognize '${label}'. Update agy to use ClosedRouter's accurate model display.`);
|
|
10957
11136
|
}
|
|
10958
11137
|
function assertAgyGeminiMode(homeDir) {
|
|
10959
|
-
const settingsPath =
|
|
11138
|
+
const settingsPath = join17(homeDir, ".gemini", "antigravity-cli", "settings.json");
|
|
10960
11139
|
try {
|
|
10961
|
-
const settings = JSON.parse(
|
|
11140
|
+
const settings = JSON.parse(readFileSync15(settingsPath, "utf8"));
|
|
10962
11141
|
if (settings?.modelProvider === "gemini")
|
|
10963
11142
|
return;
|
|
10964
11143
|
} catch {}
|
|
@@ -11033,7 +11212,8 @@ async function startCommand(options = {}) {
|
|
|
11033
11212
|
}
|
|
11034
11213
|
if (desktop && tool === "agy") {
|
|
11035
11214
|
assertAntigravityDesktopHookSupport(executablePath);
|
|
11036
|
-
|
|
11215
|
+
if (antigravityNativeAccountExists())
|
|
11216
|
+
await assertAntigravityModsAvailable();
|
|
11037
11217
|
}
|
|
11038
11218
|
const config = loadConfig();
|
|
11039
11219
|
const serverUrl = normalizeServerUrl(options.server || config.serverUrl);
|
|
@@ -11067,6 +11247,7 @@ async function startCommand(options = {}) {
|
|
|
11067
11247
|
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.`);
|
|
11068
11248
|
}
|
|
11069
11249
|
const catalog = createLaunchCatalog(availableModels, model);
|
|
11250
|
+
const account = desktopAccountIdentity(config, serverUrl, apiKey);
|
|
11070
11251
|
if (desktop && tool === "cursor") {
|
|
11071
11252
|
const localKey = randomUUID5();
|
|
11072
11253
|
const relay = await startLaunchProxy(serverUrl, apiKey, "cursor-desktop", localKey, catalog);
|
|
@@ -11091,11 +11272,12 @@ async function startCommand(options = {}) {
|
|
|
11091
11272
|
if (sharedClaudeElectron && tool === "claude") {
|
|
11092
11273
|
if (sharedClaudeElectron)
|
|
11093
11274
|
useClaudeSharedElectron(plan, sharedClaudeElectron, sourceApp, options.toolArgs, true);
|
|
11094
|
-
addClaudeDesktopHook(plan, relay.baseUrl, localKey, sourceApp, catalog.models);
|
|
11275
|
+
addClaudeDesktopHook(plan, relay.baseUrl, localKey, sourceApp, catalog.models, account);
|
|
11095
11276
|
}
|
|
11096
11277
|
if (tool === "agy") {
|
|
11097
|
-
|
|
11098
|
-
|
|
11278
|
+
const localAccount = antigravityNativeAccountExists() ? undefined : account;
|
|
11279
|
+
agyDesktopProxy = await startAgyDesktopProxy(relay.baseUrl, localKey, model, undefined, catalog, localAccount);
|
|
11280
|
+
addAntigravityDesktopHook(plan, agyDesktopProxy.baseUrl, catalog, localAccount, { baseUrl: relay.baseUrl, localKey, nativeDir: process.env.CLOSEDROUTER_ANTIGRAVITY_NATIVE_DIR });
|
|
11099
11281
|
}
|
|
11100
11282
|
writeDesktopLaunchPlan(plan);
|
|
11101
11283
|
M2.info(`Starting ${tool} desktop with ${model} through ${serverUrl}. Profile: ${plan.profileDir}. Keep cr running until you close this app instance.`);
|
|
@@ -11107,15 +11289,15 @@ async function startCommand(options = {}) {
|
|
|
11107
11289
|
return;
|
|
11108
11290
|
}
|
|
11109
11291
|
if (tool === "agy")
|
|
11110
|
-
assertAgyGeminiMode(
|
|
11111
|
-
const recognizedModel = tool === "agy" ? registerAgyLaunchCatalog(
|
|
11292
|
+
assertAgyGeminiMode(homedir15());
|
|
11293
|
+
const recognizedModel = tool === "agy" ? registerAgyLaunchCatalog(homedir15(), catalog, discoverAgyTransportModel(options.executablePath || "agy", apiKey)) : undefined;
|
|
11112
11294
|
if (recognizedModel)
|
|
11113
11295
|
assertAgyCustomModel(options.executablePath || "agy", recognizedModel, apiKey);
|
|
11114
11296
|
const relay = await startLaunchProxy(serverUrl, apiKey, tool, apiKey, catalog);
|
|
11115
11297
|
let agyProxy;
|
|
11116
11298
|
try {
|
|
11117
11299
|
agyProxy = tool === "agy" ? await startAgyModelProxy(relay.baseUrl, apiKey, model, catalog) : undefined;
|
|
11118
|
-
const plan = buildLaunchPlan(tool, relay.baseUrl, apiKey, model, options.toolArgs,
|
|
11300
|
+
const plan = buildLaunchPlan(tool, relay.baseUrl, apiKey, model, options.toolArgs, homedir15(), executablePath, agyProxy && recognizedModel ? { baseUrl: agyProxy.baseUrl, recognizedModel } : undefined, catalog);
|
|
11119
11301
|
if (plan.configFile)
|
|
11120
11302
|
writeOwnedConfig(plan.configFile);
|
|
11121
11303
|
for (const file of plan.extraFiles || [])
|
|
@@ -11174,7 +11356,7 @@ process.on("warning", (warning) => {
|
|
|
11174
11356
|
console.warn(warning.name, warning.message);
|
|
11175
11357
|
});
|
|
11176
11358
|
var program2 = new Command2;
|
|
11177
|
-
var cliVersion = JSON.parse(
|
|
11359
|
+
var cliVersion = JSON.parse(readFileSync16(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
11178
11360
|
program2.name("closedrouter").description("ClosedRouter CLI: Import local AI subscriptions & API keys into your shared token pool").version(cliVersion).option("-s, --server <url>", "ClosedRouter server base URL (default: http://localhost:8000)").action(async (options) => {
|
|
11179
11361
|
await onboardCommand({ server: options.server });
|
|
11180
11362
|
});
|
package/package.json
CHANGED