@closedrouter/cli 1.1.12 → 1.1.13

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 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. The active chat-box mark has a brief electric arc 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;AAEtD;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,GAAG,MAAM,CAmCrF"}
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): void;
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;AAO1E,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;;;GA6FhJ;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAmClH"}
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;AAK1D,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,GAAG,IAAI,CA2C5I"}
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,CAShG;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
+ {"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-electric]{position:absolute;inset:-3px;width:22px;height:22px;overflow:visible;pointer-events:none;opacity:0}\n@keyframes cr-electric-arc{0%,14%,100%{opacity:0;transform:translateX(-1px)}3%{opacity:.85}8%{opacity:.45;transform:translateX(1px)}12%{opacity:0}}\n@keyframes cr-electric-hover{0%,14%,100%{opacity:0;transform:translateX(1px)}2%{opacity:.95}7%{opacity:.55;transform:translateX(-1px)}12%{opacity:0}}\n@media(prefers-reduced-motion:no-preference){\n [data-closedrouter-supercharged] [data-closedrouter-electric]{animation:cr-electric-arc 5s linear infinite}\n button:hover>[data-closedrouter-supercharged] [data-closedrouter-electric],button:focus-visible>[data-closedrouter-supercharged] [data-closedrouter-electric]{animation-name:cr-electric-hover}\n}\nhtml[data-closedrouter-page-hidden] [data-closedrouter-electric]{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 modelBrandingHook(models: string[]): string;
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;AAEpU;oEACoE;AACpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAiC5E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAS1D"}
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,q7BAUrC,CAAC;AAEF;oEACoE;AACpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAqDjG;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;AAalE,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,CA0HnF"}
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 readFileSync15 } from "node:fs";
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 readFileSync14, writeFileSync as writeFileSync5 } from "node:fs";
8663
- import { homedir as homedir14 } from "node:os";
8664
- import { dirname as dirname5, join as join16 } from "node:path";
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: "This model is not in this launch's ClosedRouter catalog. Choose a supported model from the picker." } }));
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,29 @@ 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
- function installModelBranding(models, artwork) {
10265
+ var CLOSEDROUTER_ELECTRIC_CSS = `
10266
+ [data-closedrouter-logo]{position:relative;isolation:isolate}
10267
+ [data-closedrouter-electric]{position:absolute;inset:-3px;width:22px;height:22px;overflow:visible;pointer-events:none;opacity:0}
10268
+ @keyframes cr-electric-arc{0%,14%,100%{opacity:0;transform:translateX(-1px)}3%{opacity:.85}8%{opacity:.45;transform:translateX(1px)}12%{opacity:0}}
10269
+ @keyframes cr-electric-hover{0%,14%,100%{opacity:0;transform:translateX(1px)}2%{opacity:.95}7%{opacity:.55;transform:translateX(-1px)}12%{opacity:0}}
10270
+ @media(prefers-reduced-motion:no-preference){
10271
+ [data-closedrouter-supercharged] [data-closedrouter-electric]{animation:cr-electric-arc 5s linear infinite}
10272
+ button:hover>[data-closedrouter-supercharged] [data-closedrouter-electric],button:focus-visible>[data-closedrouter-supercharged] [data-closedrouter-electric]{animation-name:cr-electric-hover}
10273
+ }
10274
+ html[data-closedrouter-page-hidden] [data-closedrouter-electric]{animation-play-state:paused}
10275
+ `;
10276
+ function installModelBranding(models, artwork, electricCss) {
10246
10277
  if (document.querySelector("[data-closedrouter-branding]"))
10247
10278
  return;
10248
10279
  const marker = document.createElement("meta");
10249
10280
  marker.dataset.closedrouterBranding = "true";
10250
10281
  document.head.append(marker);
10282
+ const style = document.createElement("style");
10283
+ style.textContent = electricCss;
10284
+ document.head.append(style);
10285
+ document.addEventListener("visibilitychange", () => {
10286
+ document.documentElement.toggleAttribute("data-closedrouter-page-hidden", document.hidden);
10287
+ });
10251
10288
  const paint = () => {
10252
10289
  for (const element of document.querySelectorAll('button,[role="button"],[role="option"],[role="menuitem"],[role="menuitemradio"],[data-testid="model-selector-item"]')) {
10253
10290
  const text = element.innerText.trim().split(`
@@ -10263,12 +10300,24 @@ function installModelBranding(models, artwork) {
10263
10300
  }
10264
10301
  if (element.querySelector(":scope > [data-closedrouter-logo]"))
10265
10302
  continue;
10266
- const logo = document.createElement("img");
10267
- logo.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(artwork)}`;
10268
- logo.alt = "ClosedRouter";
10303
+ const logo = document.createElement("span");
10304
+ const image = document.createElement("img");
10305
+ image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(artwork)}`;
10306
+ image.alt = "ClosedRouter";
10307
+ image.style.cssText = "display:block;width:16px;height:16px";
10269
10308
  logo.title = "Routed through ClosedRouter";
10270
10309
  logo.dataset.closedrouterLogo = "true";
10271
10310
  logo.style.cssText = "width:16px;height:16px;flex:0 0 16px;display:inline-block;vertical-align:middle;margin-inline-end:6px;pointer-events:none";
10311
+ logo.append(image);
10312
+ if (element.matches("button") && !element.closest('[role="menu"],[role="listbox"],[role="dialog"]') && document.querySelector('[contenteditable="true"],textarea')) {
10313
+ logo.dataset.closedrouterSupercharged = "true";
10314
+ const arc = document.createElementNS("http://www.w3.org/2000/svg", "svg");
10315
+ arc.setAttribute("viewBox", "0 0 24 24");
10316
+ arc.setAttribute("aria-hidden", "true");
10317
+ arc.setAttribute("data-closedrouter-electric", "true");
10318
+ arc.innerHTML = '<path d="M1 8 6 5 3 12 8 9 M17 1 14 7 21 4 18 11 M20 16 16 19 22 20" fill="none" stroke="#D4FE51" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>';
10319
+ logo.append(arc);
10320
+ }
10272
10321
  element.prepend(logo);
10273
10322
  }
10274
10323
  };
@@ -10285,8 +10334,74 @@ function installModelBranding(models, artwork) {
10285
10334
  observer.observe(document.documentElement, { childList: true, subtree: true, characterData: true });
10286
10335
  paint();
10287
10336
  }
10288
- function modelBrandingHook(models) {
10289
- const script = `(${installModelBranding.toString()})(${JSON.stringify(models)},${JSON.stringify(CLOSEDROUTER_LOGO)})`;
10337
+ function installProviderAccountUi(account, artwork) {
10338
+ const createCard = () => {
10339
+ const card = document.createElement("section");
10340
+ card.id = "closedrouter-provider-account";
10341
+ card.setAttribute("aria-label", "ClosedRouter account");
10342
+ 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)";
10343
+ const logo = document.createElement("img");
10344
+ logo.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(artwork)}`;
10345
+ logo.alt = "ClosedRouter";
10346
+ logo.width = 28;
10347
+ logo.height = 28;
10348
+ const details = document.createElement("div");
10349
+ for (const text of [account.name, account.email, "Connected through ClosedRouter"])
10350
+ if (text) {
10351
+ const line = document.createElement("div");
10352
+ line.textContent = text;
10353
+ details.append(line);
10354
+ }
10355
+ card.append(logo, details);
10356
+ return card;
10357
+ };
10358
+ const paint = () => {
10359
+ let providerSession = document.documentElement.dataset.closedrouterAccount === "true";
10360
+ for (const button of document.querySelectorAll("button")) {
10361
+ if (!button.innerText.includes(account.name) || !button.innerText.includes("Gateway"))
10362
+ continue;
10363
+ providerSession = true;
10364
+ document.documentElement.dataset.closedrouterAccount = "true";
10365
+ if (button.querySelector("[data-closedrouter-account-logo]"))
10366
+ continue;
10367
+ const logo = document.createElement("img");
10368
+ logo.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(artwork)}`;
10369
+ logo.alt = "ClosedRouter account";
10370
+ logo.width = 24;
10371
+ logo.height = 24;
10372
+ logo.dataset.closedrouterAccountLogo = "true";
10373
+ logo.style.cssText = "flex:0 0 24px;margin-inline-end:8px";
10374
+ button.prepend(logo);
10375
+ }
10376
+ if (!providerSession || document.getElementById("closedrouter-provider-account"))
10377
+ return;
10378
+ const menu = document.querySelector('[role="menu"]');
10379
+ if (menu && /Settings|Account|Sign out|Log out/i.test(menu.innerText)) {
10380
+ menu.prepend(createCard());
10381
+ return;
10382
+ }
10383
+ const heading = [...document.querySelectorAll("h1,h2,h3,[role=heading]")].find((node) => node.innerText.trim() === "Account");
10384
+ if (!heading)
10385
+ return;
10386
+ heading.parentElement?.insertBefore(createCard(), heading.nextSibling);
10387
+ for (const button of document.querySelectorAll("button"))
10388
+ if (["Sign Out", "Sign In"].includes(button.innerText.trim()))
10389
+ button.hidden = true;
10390
+ };
10391
+ let queued = false;
10392
+ new MutationObserver(() => {
10393
+ if (!queued) {
10394
+ queued = true;
10395
+ queueMicrotask(() => {
10396
+ queued = false;
10397
+ paint();
10398
+ });
10399
+ }
10400
+ }).observe(document.documentElement, { subtree: true, childList: true });
10401
+ paint();
10402
+ }
10403
+ function modelBrandingHook(models, account) {
10404
+ 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
10405
  return `
10291
10406
  require('electron').app.on('web-contents-created', (_event, contents) => {
10292
10407
  contents.on('did-finish-load', () => {
@@ -10333,7 +10448,7 @@ function assertAntigravityDesktopHookSupport(executable) {
10333
10448
  if (index < 0 || binary[index + 32 + 5] !== 49)
10334
10449
  throw new Error("This Antigravity build disables launch inspector hooks. Use --open-only.");
10335
10450
  }
10336
- async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_PROXY_URL, catalog) {
10451
+ async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_PROXY_URL, catalog, account) {
10337
10452
  const capability = randomUUID4();
10338
10453
  const controllers = new Set;
10339
10454
  const server = createServer4(async (incoming, outgoing) => {
@@ -10363,6 +10478,12 @@ async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_
10363
10478
  chunks.push(Buffer.from(chunk));
10364
10479
  }
10365
10480
  const raw = Buffer.concat(chunks);
10481
+ if (account && !generation) {
10482
+ const tier = { id: "closedrouter", name: "ClosedRouter", description: "ClosedRouter account" };
10483
+ const metadata = path.endsWith(":loadCodeAssist") ? { currentTier: tier, allowedTiers: [tier], cloudaicompanionProject: "closedrouter", gcpManaged: false } : path.endsWith(":fetchAvailableModels") ? { models: {}, agentModelSorts: [], defaultAgentModelId: "" } : {};
10484
+ outgoing.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(metadata));
10485
+ return;
10486
+ }
10366
10487
  const headers = {};
10367
10488
  let target;
10368
10489
  let payload = raw;
@@ -10461,7 +10582,7 @@ async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_
10461
10582
  })
10462
10583
  };
10463
10584
  }
10464
- function addAntigravityDesktopHook(plan, endpoint, catalog) {
10585
+ function addAntigravityDesktopHook(plan, endpoint, catalog, account, provider) {
10465
10586
  const path = join13(plan.profileDir, "antigravity-hook.cjs");
10466
10587
  const marker = join13(plan.profileDir, "model-catalog-ready");
10467
10588
  const contents = `const cp = require('node:child_process');
@@ -10480,12 +10601,21 @@ cp.spawn = function(command, args, options) {
10480
10601
  const csrf = args.indexOf('--csrf_token');
10481
10602
  if (csrf >= 0) args.splice(csrf, 2, '--csrf_token=' + args[csrf + 1]);
10482
10603
  options = { ...options, env: { ...options?.env } };
10604
+ ${account && provider ? `
10605
+ 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"))}]]) {
10606
+ const i=args.indexOf(flag);if(i>=0)args[i+1]=value;else args.push(flag,value);
10607
+ }
10608
+ options.env.GEMINI_API_KEY=${JSON.stringify(provider.localKey)};
10609
+ options.env.GOOGLE_GEMINI_BASE_URL=${JSON.stringify(provider.baseUrl)};
10610
+ delete options.env.GOOGLE_API_KEY;
10611
+ args.push('--disable_telemetry=true');
10612
+ ` : ""}
10483
10613
  delete options.env.NODE_OPTIONS;
10484
10614
  }
10485
10615
  return spawn.call(this, command, args, options);
10486
10616
  };
10487
10617
  require('node:fs').writeFileSync(${JSON.stringify(join13(plan.profileDir, "hook-loaded"))}, 'ready', {mode: 0o600});
10488
- ` + (catalog ? antigravityCatalogHook(catalog, marker) + modelBrandingHook(catalog.models) : "");
10618
+ ` + (catalog ? antigravityCatalogHook(catalog, marker, account) + modelBrandingHook(catalog.models, account) : "");
10489
10619
  plan.files.push({ path, contents });
10490
10620
  const logPath = join13(plan.profileDir, "inspector.log");
10491
10621
  plan.inspectorHook = { path, logPath, ...catalog ? { readyPath: marker } : {} };
@@ -10502,6 +10632,10 @@ import { createHash as createHash3 } from "node:crypto";
10502
10632
  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
10633
  import { homedir as homedir13 } from "node:os";
10504
10634
  import { dirname as dirname3, join as join14, relative as relative2 } from "node:path";
10635
+ function patchClaudeAccountIdentity(source, account) {
10636
+ const fallback = /if\(([\w$]+)\)return \1;let ([\w$]+)=([\w$]+)\(\);return \2\?\{name:\2,source:"os"\}:void 0(?=\}function)/;
10637
+ return source.replace(fallback, (_all, existing) => `if(${existing})return ${existing};return ${JSON.stringify({ name: account.name, email: account.email, source: "closedrouter" })}`);
10638
+ }
10505
10639
  function patchClaudeModelIdentity(source, aliases) {
10506
10640
  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
10641
  }
@@ -10601,7 +10735,7 @@ function useClaudeSharedElectron(plan, runtime, sourceApp, toolArgs = [], launch
10601
10735
  plan.command = launchServices ? "/usr/bin/open" : runtime;
10602
10736
  plan.args = launchServices ? ["-W", "-n", "-a", dirname3(dirname3(dirname3(runtime))), "--args", ...args] : args;
10603
10737
  }
10604
- function addClaudeDesktopHook(plan, baseUrl, localKey, sourceApp, models) {
10738
+ function addClaudeDesktopHook(plan, baseUrl, localKey, sourceApp, models, account) {
10605
10739
  const path = join14(plan.profileDir, "claude-hook.cjs");
10606
10740
  plan.files.push({ path, contents: `${sourceApp ? `const electron = require('electron');
10607
10741
  Object.defineProperty(process, 'resourcesPath', {value: ${JSON.stringify(join14(sourceApp, "Contents/Resources"))}});
@@ -10627,11 +10761,12 @@ require('node:fs').writeFileSync(${JSON.stringify(join14(plan.profileDir, "hook-
10627
10761
  ` + (models && sourceApp ? `
10628
10762
  const moduleHooks = require('node:module');
10629
10763
  const patchIdentity = ${patchClaudeModelIdentity.toString()};
10764
+ ${account ? `const patchAccount = ${patchClaudeAccountIdentity.toString()};` : ""}
10630
10765
  if (typeof moduleHooks.registerHooks === 'function') moduleHooks.registerHooks({load(url, context, nextLoad) {
10631
10766
  const loaded = nextLoad(url, context);
10632
10767
  if (url.startsWith('file:') && require('node:url').fileURLToPath(url).startsWith(${JSON.stringify(join14(sourceApp, "Contents/Resources/app.asar/.vite/build/"))}) && loaded.source != null) {
10633
10768
  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])))});
10769
+ const patched = ${account ? "patchAccount(" : ""}patchIdentity(source, ${JSON.stringify(Object.fromEntries(models.map((id) => [transportModelId(id, "claude"), id])))}${account ? `),${JSON.stringify(account)})` : ")"};
10635
10770
  if (patched !== source) {
10636
10771
  require('node:fs').writeFileSync(${JSON.stringify(join14(plan.profileDir, "model-identity-hook-ready"))}, 'ready', {mode:0o600});
10637
10772
  return {...loaded, source:patched};
@@ -10639,7 +10774,7 @@ if (typeof moduleHooks.registerHooks === 'function') moduleHooks.registerHooks({
10639
10774
  }
10640
10775
  return loaded;
10641
10776
  }});
10642
- ` : "") + (models ? modelBrandingHook(models) : "") });
10777
+ ` : "") + (models ? modelBrandingHook(models, account) : "") });
10643
10778
  const logPath = join14(plan.profileDir, "inspector.log");
10644
10779
  plan.inspectorHook = { path, logPath };
10645
10780
  plan.args.push("--inspect-brk=127.0.0.1:0");
@@ -10750,6 +10885,33 @@ require('node:fs').writeFileSync(${JSON.stringify(join15(plan.profileDir, "hook-
10750
10885
  plan.args.splice(plan.args.indexOf("--args"), 0, "--stderr", logPath);
10751
10886
  }
10752
10887
 
10888
+ // src/commands/desktop-account.ts
10889
+ import { existsSync as existsSync16, readFileSync as readFileSync14 } from "node:fs";
10890
+ import { homedir as homedir14 } from "node:os";
10891
+ import { join as join16 } from "node:path";
10892
+ function desktopAccountIdentity(config, server, key) {
10893
+ const sameAccount = config.apiKey === key && config.serverUrl.replace(/\/+$/, "") === server.replace(/\/+$/, "");
10894
+ const user = sameAccount ? config.user : undefined;
10895
+ return {
10896
+ provider: "closedrouter",
10897
+ name: user?.name?.trim() || user?.email?.trim() || "ClosedRouter API key",
10898
+ ...user?.email ? { email: user.email } : {},
10899
+ ...user?.id ? { accountId: user.id } : {},
10900
+ serverOrigin: new URL(server).origin
10901
+ };
10902
+ }
10903
+ function antigravityNativeAccountExists(geminiDir = process.env.CLOSEDROUTER_ANTIGRAVITY_NATIVE_DIR || join16(homedir14(), ".gemini")) {
10904
+ const path = join16(geminiDir, "jetski-standalone-oauth-token");
10905
+ if (!existsSync16(path))
10906
+ return false;
10907
+ try {
10908
+ const value = JSON.parse(readFileSync14(path, "utf8"));
10909
+ return Boolean(value?.token?.refresh_token || value?.token?.access_token);
10910
+ } catch {
10911
+ return false;
10912
+ }
10913
+ }
10914
+
10753
10915
  // src/commands/start.ts
10754
10916
  function isGatewayModelAvailable(availableModels, model) {
10755
10917
  return availableModels.includes(model);
@@ -10796,7 +10958,7 @@ function assertNoManagedCodexArgs(args) {
10796
10958
  throw new Error(`Remove ${conflicting}; ClosedRouter manages the Codex profile and model. Put other arguments after --.`);
10797
10959
  }
10798
10960
  }
10799
- function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir = homedir14(), executablePath, agyRouting, catalog) {
10961
+ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir = homedir15(), executablePath, agyRouting, catalog) {
10800
10962
  const baseUrl = normalizeServerUrl(serverUrl);
10801
10963
  const env = { ...process.env };
10802
10964
  const command = executablePath || tool;
@@ -10822,10 +10984,10 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
10822
10984
  }
10823
10985
  if (tool === "codex") {
10824
10986
  assertNoManagedCodexArgs(toolArgs);
10825
- const codexHome = process.env.CODEX_HOME || join16(homeDir, ".codex");
10987
+ const codexHome = process.env.CODEX_HOME || join17(homeDir, ".codex");
10826
10988
  const profileName = "closedrouter-launch";
10827
- const configPath = join16(codexHome, `${profileName}.config.toml`);
10828
- const catalogPath = join16(codexHome, "closedrouter-models.json");
10989
+ const configPath = join17(codexHome, `${profileName}.config.toml`);
10990
+ const catalogPath = join17(codexHome, "closedrouter-models.json");
10829
10991
  const configLines = [
10830
10992
  `model = ${tomlString(model)}`,
10831
10993
  `model_provider = ${tomlString(profileName)}`,
@@ -10853,7 +11015,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
10853
11015
  env.GEMINI_API_KEY = apiKey;
10854
11016
  env.GEMINI_MODEL = model;
10855
11017
  env.GOOGLE_GEMINI_BASE_URL = baseUrl;
10856
- const configPath = join16(homeDir, ".closedrouter", "gemini-launch.settings.json");
11018
+ const configPath = join17(homeDir, ".closedrouter", "gemini-launch.settings.json");
10857
11019
  env.GEMINI_CLI_SYSTEM_SETTINGS_PATH = configPath;
10858
11020
  return {
10859
11021
  tool,
@@ -10888,9 +11050,9 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
10888
11050
  return {
10889
11051
  tool,
10890
11052
  command,
10891
- args: ["--model", `openai/${catalog ? "closedrouter/" : ""}${model}`, ...catalog ? ["--model-metadata-file", join16(homeDir, ".closedrouter", "aider-models.json")] : [], ...toolArgs],
11053
+ args: ["--model", `openai/${catalog ? "closedrouter/" : ""}${model}`, ...catalog ? ["--model-metadata-file", join17(homeDir, ".closedrouter", "aider-models.json")] : [], ...toolArgs],
10892
11054
  env,
10893
- ...catalog ? { configFile: { path: join16(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 }]))) } } : {}
11055
+ ...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
11056
  };
10895
11057
  }
10896
11058
  const config = {
@@ -10919,7 +11081,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
10919
11081
  function writeOwnedConfig(file) {
10920
11082
  mkdirSync5(dirname5(file.path), { recursive: true, mode: 448 });
10921
11083
  try {
10922
- const existing = readFileSync14(file.path, "utf8");
11084
+ const existing = readFileSync15(file.path, "utf8");
10923
11085
  if (file.path.endsWith(".config.toml") && !existing.includes('name = "ClosedRouter"')) {
10924
11086
  throw new Error(`Refusing to replace an existing Codex profile at ${file.path}.`);
10925
11087
  }
@@ -10956,9 +11118,9 @@ function assertAgyCustomModel(command, label, apiKey) {
10956
11118
  throw new Error(`This version of agy did not recognize '${label}'. Update agy to use ClosedRouter's accurate model display.`);
10957
11119
  }
10958
11120
  function assertAgyGeminiMode(homeDir) {
10959
- const settingsPath = join16(homeDir, ".gemini", "antigravity-cli", "settings.json");
11121
+ const settingsPath = join17(homeDir, ".gemini", "antigravity-cli", "settings.json");
10960
11122
  try {
10961
- const settings = JSON.parse(readFileSync14(settingsPath, "utf8"));
11123
+ const settings = JSON.parse(readFileSync15(settingsPath, "utf8"));
10962
11124
  if (settings?.modelProvider === "gemini")
10963
11125
  return;
10964
11126
  } catch {}
@@ -11033,7 +11195,8 @@ async function startCommand(options = {}) {
11033
11195
  }
11034
11196
  if (desktop && tool === "agy") {
11035
11197
  assertAntigravityDesktopHookSupport(executablePath);
11036
- await assertAntigravityModsAvailable();
11198
+ if (antigravityNativeAccountExists())
11199
+ await assertAntigravityModsAvailable();
11037
11200
  }
11038
11201
  const config = loadConfig();
11039
11202
  const serverUrl = normalizeServerUrl(options.server || config.serverUrl);
@@ -11067,6 +11230,7 @@ async function startCommand(options = {}) {
11067
11230
  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
11231
  }
11069
11232
  const catalog = createLaunchCatalog(availableModels, model);
11233
+ const account = desktopAccountIdentity(config, serverUrl, apiKey);
11070
11234
  if (desktop && tool === "cursor") {
11071
11235
  const localKey = randomUUID5();
11072
11236
  const relay = await startLaunchProxy(serverUrl, apiKey, "cursor-desktop", localKey, catalog);
@@ -11091,11 +11255,12 @@ async function startCommand(options = {}) {
11091
11255
  if (sharedClaudeElectron && tool === "claude") {
11092
11256
  if (sharedClaudeElectron)
11093
11257
  useClaudeSharedElectron(plan, sharedClaudeElectron, sourceApp, options.toolArgs, true);
11094
- addClaudeDesktopHook(plan, relay.baseUrl, localKey, sourceApp, catalog.models);
11258
+ addClaudeDesktopHook(plan, relay.baseUrl, localKey, sourceApp, catalog.models, account);
11095
11259
  }
11096
11260
  if (tool === "agy") {
11097
- agyDesktopProxy = await startAgyDesktopProxy(relay.baseUrl, localKey, model, undefined, catalog);
11098
- addAntigravityDesktopHook(plan, agyDesktopProxy.baseUrl, catalog);
11261
+ const localAccount = antigravityNativeAccountExists() ? undefined : account;
11262
+ agyDesktopProxy = await startAgyDesktopProxy(relay.baseUrl, localKey, model, undefined, catalog, localAccount);
11263
+ addAntigravityDesktopHook(plan, agyDesktopProxy.baseUrl, catalog, localAccount, { baseUrl: relay.baseUrl, localKey, nativeDir: process.env.CLOSEDROUTER_ANTIGRAVITY_NATIVE_DIR });
11099
11264
  }
11100
11265
  writeDesktopLaunchPlan(plan);
11101
11266
  M2.info(`Starting ${tool} desktop with ${model} through ${serverUrl}. Profile: ${plan.profileDir}. Keep cr running until you close this app instance.`);
@@ -11107,15 +11272,15 @@ async function startCommand(options = {}) {
11107
11272
  return;
11108
11273
  }
11109
11274
  if (tool === "agy")
11110
- assertAgyGeminiMode(homedir14());
11111
- const recognizedModel = tool === "agy" ? registerAgyLaunchCatalog(homedir14(), catalog, discoverAgyTransportModel(options.executablePath || "agy", apiKey)) : undefined;
11275
+ assertAgyGeminiMode(homedir15());
11276
+ const recognizedModel = tool === "agy" ? registerAgyLaunchCatalog(homedir15(), catalog, discoverAgyTransportModel(options.executablePath || "agy", apiKey)) : undefined;
11112
11277
  if (recognizedModel)
11113
11278
  assertAgyCustomModel(options.executablePath || "agy", recognizedModel, apiKey);
11114
11279
  const relay = await startLaunchProxy(serverUrl, apiKey, tool, apiKey, catalog);
11115
11280
  let agyProxy;
11116
11281
  try {
11117
11282
  agyProxy = tool === "agy" ? await startAgyModelProxy(relay.baseUrl, apiKey, model, catalog) : undefined;
11118
- const plan = buildLaunchPlan(tool, relay.baseUrl, apiKey, model, options.toolArgs, homedir14(), executablePath, agyProxy && recognizedModel ? { baseUrl: agyProxy.baseUrl, recognizedModel } : undefined, catalog);
11283
+ const plan = buildLaunchPlan(tool, relay.baseUrl, apiKey, model, options.toolArgs, homedir15(), executablePath, agyProxy && recognizedModel ? { baseUrl: agyProxy.baseUrl, recognizedModel } : undefined, catalog);
11119
11284
  if (plan.configFile)
11120
11285
  writeOwnedConfig(plan.configFile);
11121
11286
  for (const file of plan.extraFiles || [])
@@ -11174,7 +11339,7 @@ process.on("warning", (warning) => {
11174
11339
  console.warn(warning.name, warning.message);
11175
11340
  });
11176
11341
  var program2 = new Command2;
11177
- var cliVersion = JSON.parse(readFileSync15(new URL("../package.json", import.meta.url), "utf8")).version;
11342
+ var cliVersion = JSON.parse(readFileSync16(new URL("../package.json", import.meta.url), "utf8")).version;
11178
11343
  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
11344
  await onboardCommand({ server: options.server });
11180
11345
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@closedrouter/cli",
3
- "version": "1.1.12",
3
+ "version": "1.1.13",
4
4
  "description": "ClosedRouter CLI: Onboard and import local AI subscriptions and API keys into your shared token pool",
5
5
  "author": "ClosedRouter Contributors",
6
6
  "repository": {