@closedrouter/cli 1.1.11 → 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 +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 +4 -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 +1 -1
- 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 +242 -38
- 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. 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;
|
|
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,9 +1,12 @@
|
|
|
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;
|
|
4
|
+
export declare function patchClaudeModelIdentity(source: string, aliases: Record<string, string>): string;
|
|
2
5
|
/** Share immutable framework bytes, but detach every file codesign can write.
|
|
3
6
|
* Signing a hard-linked executable would change the user's original runtime. */
|
|
4
7
|
export declare function cloneClaudeElectronRuntime(source: string, destination: string): string[];
|
|
5
8
|
export declare function prepareClaudeElectronRuntime(runtime: string, sourceApp: string): string;
|
|
6
9
|
export declare function findClaudeSharedElectron(sourceApp: string, home?: string): string | undefined;
|
|
7
10
|
export declare function useClaudeSharedElectron(plan: DesktopLaunchPlan, runtime: string, sourceApp: string, toolArgs?: string[], launchServices?: boolean): void;
|
|
8
|
-
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;
|
|
9
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;AAI1D;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,
|
|
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"}
|
|
@@ -81,5 +81,5 @@ export declare function geminiModelCatalog(models: string[], selected: string):
|
|
|
81
81
|
};
|
|
82
82
|
};
|
|
83
83
|
};
|
|
84
|
-
export declare function addModelIdentity(payload: Record<string, unknown>, model: string, protocol: "anthropic" | "responses" | "chat" | "gemini"): void;
|
|
84
|
+
export declare function addModelIdentity(payload: Record<string, unknown>, model: string, protocol: "anthropic" | "responses" | "chat" | "gemini", aliases?: Record<string, string>): void;
|
|
85
85
|
//# sourceMappingURL=launch-catalog.d.ts.map
|
|
@@ -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-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
|
|
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,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;
|
|
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))
|
|
@@ -9500,7 +9502,28 @@ function geminiModelCatalog(models, selected) {
|
|
|
9500
9502
|
}
|
|
9501
9503
|
};
|
|
9502
9504
|
}
|
|
9503
|
-
function addModelIdentity(payload, model, protocol) {
|
|
9505
|
+
function addModelIdentity(payload, model, protocol, aliases = {}) {
|
|
9506
|
+
const rewrite = (value) => {
|
|
9507
|
+
if (typeof value === "string") {
|
|
9508
|
+
for (const [alias, actual] of Object.entries(aliases))
|
|
9509
|
+
value = value.split(alias).join(actual);
|
|
9510
|
+
return value;
|
|
9511
|
+
}
|
|
9512
|
+
if (Array.isArray(value))
|
|
9513
|
+
return value.map(rewrite);
|
|
9514
|
+
if (value && typeof value === "object")
|
|
9515
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, rewrite(item)]));
|
|
9516
|
+
return value;
|
|
9517
|
+
};
|
|
9518
|
+
for (const key of ["system", "instructions", "systemInstruction"])
|
|
9519
|
+
if (payload[key] !== undefined)
|
|
9520
|
+
payload[key] = rewrite(payload[key]);
|
|
9521
|
+
if (Array.isArray(payload.messages))
|
|
9522
|
+
payload.messages = payload.messages.map((message) => {
|
|
9523
|
+
if (message && typeof message === "object" && ["system", "developer"].includes(message.role))
|
|
9524
|
+
return { ...message, content: rewrite(message.content) };
|
|
9525
|
+
return message;
|
|
9526
|
+
});
|
|
9504
9527
|
const text = `ClosedRouter runtime model identity: this request is routed to the configured model ID ${JSON.stringify(model)} through ClosedRouter. The application's name and any vendor-shaped transport alias describe the client, not the underlying inference model. If asked which model you are using, report the configured model ID ${JSON.stringify(model)} and ClosedRouter as the provider. This runtime information supersedes conflicting model identity statements in the application's prompt; it does not change other task instructions.`;
|
|
9505
9528
|
if (protocol === "anthropic") {
|
|
9506
9529
|
const system = payload.system;
|
|
@@ -9575,12 +9598,12 @@ async function startLaunchProxy(gatewayUrl, apiKey, harness, localKey = apiKey,
|
|
|
9575
9598
|
const requested = gemini ? decodeURIComponent(gemini[1]) : typeof payload.model === "string" ? payload.model : catalog?.defaultModel || "";
|
|
9576
9599
|
const model = catalog ? resolveLaunchModel(catalog, requested) : modelOverride;
|
|
9577
9600
|
if (!model) {
|
|
9578
|
-
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.` } }));
|
|
9579
9602
|
return;
|
|
9580
9603
|
}
|
|
9581
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);
|
|
9582
9605
|
if (catalog)
|
|
9583
|
-
addModelIdentity(payload, model, gemini ? "gemini" : local.pathname.startsWith("/v1/messages") ? "anthropic" : local.pathname === "/v1/responses" ? "responses" : "chat");
|
|
9606
|
+
addModelIdentity(payload, model, gemini ? "gemini" : local.pathname.startsWith("/v1/messages") ? "anthropic" : local.pathname === "/v1/responses" ? "responses" : "chat", catalog.aliases);
|
|
9584
9607
|
if (gemini)
|
|
9585
9608
|
target.pathname = upstream.pathname.replace(/\/$/, "") + `/v1beta/models/${encodeURIComponent(model)}:${gemini[2]}`;
|
|
9586
9609
|
rewrittenBody = JSON.stringify({ ...payload, ...!gemini ? { model } : {}, ...tinyProbe ? { max_tokens: 512 } : {} });
|
|
@@ -10154,6 +10177,23 @@ import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node
|
|
|
10154
10177
|
import { homedir as homedir12 } from "node:os";
|
|
10155
10178
|
import { join as join13 } from "node:path";
|
|
10156
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
|
+
|
|
10157
10197
|
// src/commands/agy-desktop-catalog.ts
|
|
10158
10198
|
function patchAntigravityCatalog(source, catalog) {
|
|
10159
10199
|
const provider = /this\.customModelsProvider=([\w$]+)\(this\.rootProvider,([\w$]+)=>\(\{customModels:\2\.appState\?\.customModelsConfig\?\.customModels\?\?\{\}\}\)\)/;
|
|
@@ -10182,10 +10222,11 @@ function patchAntigravityCatalog(source, catalog) {
|
|
|
10182
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, "[]");
|
|
10183
10223
|
return source.slice(0, start) + body + source.slice(end);
|
|
10184
10224
|
}
|
|
10185
|
-
function antigravityCatalogHook(catalog, marker) {
|
|
10225
|
+
function antigravityCatalogHook(catalog, marker, account) {
|
|
10186
10226
|
return `
|
|
10187
10227
|
const {app} = require('electron');
|
|
10188
10228
|
const patchCatalog = ${patchAntigravityCatalog.toString()};
|
|
10229
|
+
${account ? `const patchAccount = ${patchAntigravityAccount.toString()};` : ""}
|
|
10189
10230
|
app.on('web-contents-created', (_event, contents) => {
|
|
10190
10231
|
const debuggerClient = contents.debugger;
|
|
10191
10232
|
try {
|
|
@@ -10200,7 +10241,7 @@ app.on('web-contents-created', (_event, contents) => {
|
|
|
10200
10241
|
}
|
|
10201
10242
|
const result = await debuggerClient.sendCommand('Fetch.getResponseBody', {requestId:params.requestId});
|
|
10202
10243
|
const source = result.base64Encoded ? Buffer.from(result.body,'base64').toString('utf8') : result.body;
|
|
10203
|
-
const patched = patchCatalog(source, ${JSON.stringify(catalog)});
|
|
10244
|
+
const patched = patchCatalog(${account ? `patchAccount(source, ${JSON.stringify(account)})` : "source"}, ${JSON.stringify(catalog)});
|
|
10204
10245
|
await debuggerClient.sendCommand('Fetch.fulfillRequest', {requestId:params.requestId,responseCode:200,
|
|
10205
10246
|
responseHeaders:(params.responseHeaders || []).filter(h=>!['content-length','content-encoding','transfer-encoding'].includes(h.name.toLowerCase())),
|
|
10206
10247
|
body:Buffer.from(patched).toString('base64')});
|
|
@@ -10221,12 +10262,29 @@ app.on('web-contents-created', (_event, contents) => {
|
|
|
10221
10262
|
|
|
10222
10263
|
// src/commands/model-branding.ts
|
|
10223
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>';
|
|
10224
|
-
|
|
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) {
|
|
10225
10277
|
if (document.querySelector("[data-closedrouter-branding]"))
|
|
10226
10278
|
return;
|
|
10227
10279
|
const marker = document.createElement("meta");
|
|
10228
10280
|
marker.dataset.closedrouterBranding = "true";
|
|
10229
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
|
+
});
|
|
10230
10288
|
const paint = () => {
|
|
10231
10289
|
for (const element of document.querySelectorAll('button,[role="button"],[role="option"],[role="menuitem"],[role="menuitemradio"],[data-testid="model-selector-item"]')) {
|
|
10232
10290
|
const text = element.innerText.trim().split(`
|
|
@@ -10242,12 +10300,24 @@ function installModelBranding(models, artwork) {
|
|
|
10242
10300
|
}
|
|
10243
10301
|
if (element.querySelector(":scope > [data-closedrouter-logo]"))
|
|
10244
10302
|
continue;
|
|
10245
|
-
const logo = document.createElement("
|
|
10246
|
-
|
|
10247
|
-
|
|
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";
|
|
10248
10308
|
logo.title = "Routed through ClosedRouter";
|
|
10249
10309
|
logo.dataset.closedrouterLogo = "true";
|
|
10250
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
|
+
}
|
|
10251
10321
|
element.prepend(logo);
|
|
10252
10322
|
}
|
|
10253
10323
|
};
|
|
@@ -10264,8 +10334,74 @@ function installModelBranding(models, artwork) {
|
|
|
10264
10334
|
observer.observe(document.documentElement, { childList: true, subtree: true, characterData: true });
|
|
10265
10335
|
paint();
|
|
10266
10336
|
}
|
|
10267
|
-
function
|
|
10268
|
-
const
|
|
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)})` : "");
|
|
10269
10405
|
return `
|
|
10270
10406
|
require('electron').app.on('web-contents-created', (_event, contents) => {
|
|
10271
10407
|
contents.on('did-finish-load', () => {
|
|
@@ -10312,7 +10448,7 @@ function assertAntigravityDesktopHookSupport(executable) {
|
|
|
10312
10448
|
if (index < 0 || binary[index + 32 + 5] !== 49)
|
|
10313
10449
|
throw new Error("This Antigravity build disables launch inspector hooks. Use --open-only.");
|
|
10314
10450
|
}
|
|
10315
|
-
async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_PROXY_URL, catalog) {
|
|
10451
|
+
async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_PROXY_URL, catalog, account) {
|
|
10316
10452
|
const capability = randomUUID4();
|
|
10317
10453
|
const controllers = new Set;
|
|
10318
10454
|
const server = createServer4(async (incoming, outgoing) => {
|
|
@@ -10342,6 +10478,12 @@ async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_
|
|
|
10342
10478
|
chunks.push(Buffer.from(chunk));
|
|
10343
10479
|
}
|
|
10344
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
|
+
}
|
|
10345
10487
|
const headers = {};
|
|
10346
10488
|
let target;
|
|
10347
10489
|
let payload = raw;
|
|
@@ -10440,7 +10582,7 @@ async function startAgyDesktopProxy(gatewayUrl, localKey, model, modsUrl = MODS_
|
|
|
10440
10582
|
})
|
|
10441
10583
|
};
|
|
10442
10584
|
}
|
|
10443
|
-
function addAntigravityDesktopHook(plan, endpoint, catalog) {
|
|
10585
|
+
function addAntigravityDesktopHook(plan, endpoint, catalog, account, provider) {
|
|
10444
10586
|
const path = join13(plan.profileDir, "antigravity-hook.cjs");
|
|
10445
10587
|
const marker = join13(plan.profileDir, "model-catalog-ready");
|
|
10446
10588
|
const contents = `const cp = require('node:child_process');
|
|
@@ -10459,12 +10601,21 @@ cp.spawn = function(command, args, options) {
|
|
|
10459
10601
|
const csrf = args.indexOf('--csrf_token');
|
|
10460
10602
|
if (csrf >= 0) args.splice(csrf, 2, '--csrf_token=' + args[csrf + 1]);
|
|
10461
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
|
+
` : ""}
|
|
10462
10613
|
delete options.env.NODE_OPTIONS;
|
|
10463
10614
|
}
|
|
10464
10615
|
return spawn.call(this, command, args, options);
|
|
10465
10616
|
};
|
|
10466
10617
|
require('node:fs').writeFileSync(${JSON.stringify(join13(plan.profileDir, "hook-loaded"))}, 'ready', {mode: 0o600});
|
|
10467
|
-
` + (catalog ? antigravityCatalogHook(catalog, marker) + modelBrandingHook(catalog.models) : "");
|
|
10618
|
+
` + (catalog ? antigravityCatalogHook(catalog, marker, account) + modelBrandingHook(catalog.models, account) : "");
|
|
10468
10619
|
plan.files.push({ path, contents });
|
|
10469
10620
|
const logPath = join13(plan.profileDir, "inspector.log");
|
|
10470
10621
|
plan.inspectorHook = { path, logPath, ...catalog ? { readyPath: marker } : {} };
|
|
@@ -10481,6 +10632,13 @@ import { createHash as createHash3 } from "node:crypto";
|
|
|
10481
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";
|
|
10482
10633
|
import { homedir as homedir13 } from "node:os";
|
|
10483
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
|
+
}
|
|
10639
|
+
function patchClaudeModelIdentity(source, aliases) {
|
|
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.';`);
|
|
10641
|
+
}
|
|
10484
10642
|
function cloneClaudeElectronRuntime(source, destination) {
|
|
10485
10643
|
const clone = (from, to) => {
|
|
10486
10644
|
const info = lstatSync(from);
|
|
@@ -10577,7 +10735,7 @@ function useClaudeSharedElectron(plan, runtime, sourceApp, toolArgs = [], launch
|
|
|
10577
10735
|
plan.command = launchServices ? "/usr/bin/open" : runtime;
|
|
10578
10736
|
plan.args = launchServices ? ["-W", "-n", "-a", dirname3(dirname3(dirname3(runtime))), "--args", ...args] : args;
|
|
10579
10737
|
}
|
|
10580
|
-
function addClaudeDesktopHook(plan, baseUrl, localKey, sourceApp, models) {
|
|
10738
|
+
function addClaudeDesktopHook(plan, baseUrl, localKey, sourceApp, models, account) {
|
|
10581
10739
|
const path = join14(plan.profileDir, "claude-hook.cjs");
|
|
10582
10740
|
plan.files.push({ path, contents: `${sourceApp ? `const electron = require('electron');
|
|
10583
10741
|
Object.defineProperty(process, 'resourcesPath', {value: ${JSON.stringify(join14(sourceApp, "Contents/Resources"))}});
|
|
@@ -10600,7 +10758,23 @@ if (autoUpdater) {
|
|
|
10600
10758
|
autoUpdater.quitAndInstall = () => {};
|
|
10601
10759
|
}
|
|
10602
10760
|
require('node:fs').writeFileSync(${JSON.stringify(join14(plan.profileDir, "hook-loaded"))}, 'ready', {mode: 0o600});
|
|
10603
|
-
` + (models
|
|
10761
|
+
` + (models && sourceApp ? `
|
|
10762
|
+
const moduleHooks = require('node:module');
|
|
10763
|
+
const patchIdentity = ${patchClaudeModelIdentity.toString()};
|
|
10764
|
+
${account ? `const patchAccount = ${patchClaudeAccountIdentity.toString()};` : ""}
|
|
10765
|
+
if (typeof moduleHooks.registerHooks === 'function') moduleHooks.registerHooks({load(url, context, nextLoad) {
|
|
10766
|
+
const loaded = nextLoad(url, context);
|
|
10767
|
+
if (url.startsWith('file:') && require('node:url').fileURLToPath(url).startsWith(${JSON.stringify(join14(sourceApp, "Contents/Resources/app.asar/.vite/build/"))}) && loaded.source != null) {
|
|
10768
|
+
const source = typeof loaded.source === 'string' ? loaded.source : Buffer.from(loaded.source).toString('utf8');
|
|
10769
|
+
const patched = ${account ? "patchAccount(" : ""}patchIdentity(source, ${JSON.stringify(Object.fromEntries(models.map((id) => [transportModelId(id, "claude"), id])))}${account ? `),${JSON.stringify(account)})` : ")"};
|
|
10770
|
+
if (patched !== source) {
|
|
10771
|
+
require('node:fs').writeFileSync(${JSON.stringify(join14(plan.profileDir, "model-identity-hook-ready"))}, 'ready', {mode:0o600});
|
|
10772
|
+
return {...loaded, source:patched};
|
|
10773
|
+
}
|
|
10774
|
+
}
|
|
10775
|
+
return loaded;
|
|
10776
|
+
}});
|
|
10777
|
+
` : "") + (models ? modelBrandingHook(models, account) : "") });
|
|
10604
10778
|
const logPath = join14(plan.profileDir, "inspector.log");
|
|
10605
10779
|
plan.inspectorHook = { path, logPath };
|
|
10606
10780
|
plan.args.push("--inspect-brk=127.0.0.1:0");
|
|
@@ -10711,6 +10885,33 @@ require('node:fs').writeFileSync(${JSON.stringify(join15(plan.profileDir, "hook-
|
|
|
10711
10885
|
plan.args.splice(plan.args.indexOf("--args"), 0, "--stderr", logPath);
|
|
10712
10886
|
}
|
|
10713
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
|
+
|
|
10714
10915
|
// src/commands/start.ts
|
|
10715
10916
|
function isGatewayModelAvailable(availableModels, model) {
|
|
10716
10917
|
return availableModels.includes(model);
|
|
@@ -10757,7 +10958,7 @@ function assertNoManagedCodexArgs(args) {
|
|
|
10757
10958
|
throw new Error(`Remove ${conflicting}; ClosedRouter manages the Codex profile and model. Put other arguments after --.`);
|
|
10758
10959
|
}
|
|
10759
10960
|
}
|
|
10760
|
-
function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir =
|
|
10961
|
+
function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir = homedir15(), executablePath, agyRouting, catalog) {
|
|
10761
10962
|
const baseUrl = normalizeServerUrl(serverUrl);
|
|
10762
10963
|
const env = { ...process.env };
|
|
10763
10964
|
const command = executablePath || tool;
|
|
@@ -10783,10 +10984,10 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
10783
10984
|
}
|
|
10784
10985
|
if (tool === "codex") {
|
|
10785
10986
|
assertNoManagedCodexArgs(toolArgs);
|
|
10786
|
-
const codexHome = process.env.CODEX_HOME ||
|
|
10987
|
+
const codexHome = process.env.CODEX_HOME || join17(homeDir, ".codex");
|
|
10787
10988
|
const profileName = "closedrouter-launch";
|
|
10788
|
-
const configPath =
|
|
10789
|
-
const catalogPath =
|
|
10989
|
+
const configPath = join17(codexHome, `${profileName}.config.toml`);
|
|
10990
|
+
const catalogPath = join17(codexHome, "closedrouter-models.json");
|
|
10790
10991
|
const configLines = [
|
|
10791
10992
|
`model = ${tomlString(model)}`,
|
|
10792
10993
|
`model_provider = ${tomlString(profileName)}`,
|
|
@@ -10814,7 +11015,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
10814
11015
|
env.GEMINI_API_KEY = apiKey;
|
|
10815
11016
|
env.GEMINI_MODEL = model;
|
|
10816
11017
|
env.GOOGLE_GEMINI_BASE_URL = baseUrl;
|
|
10817
|
-
const configPath =
|
|
11018
|
+
const configPath = join17(homeDir, ".closedrouter", "gemini-launch.settings.json");
|
|
10818
11019
|
env.GEMINI_CLI_SYSTEM_SETTINGS_PATH = configPath;
|
|
10819
11020
|
return {
|
|
10820
11021
|
tool,
|
|
@@ -10849,9 +11050,9 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
10849
11050
|
return {
|
|
10850
11051
|
tool,
|
|
10851
11052
|
command,
|
|
10852
|
-
args: ["--model", `openai/${catalog ? "closedrouter/" : ""}${model}`, ...catalog ? ["--model-metadata-file",
|
|
11053
|
+
args: ["--model", `openai/${catalog ? "closedrouter/" : ""}${model}`, ...catalog ? ["--model-metadata-file", join17(homeDir, ".closedrouter", "aider-models.json")] : [], ...toolArgs],
|
|
10853
11054
|
env,
|
|
10854
|
-
...catalog ? { configFile: { path:
|
|
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 }]))) } } : {}
|
|
10855
11056
|
};
|
|
10856
11057
|
}
|
|
10857
11058
|
const config = {
|
|
@@ -10880,7 +11081,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
|
|
|
10880
11081
|
function writeOwnedConfig(file) {
|
|
10881
11082
|
mkdirSync5(dirname5(file.path), { recursive: true, mode: 448 });
|
|
10882
11083
|
try {
|
|
10883
|
-
const existing =
|
|
11084
|
+
const existing = readFileSync15(file.path, "utf8");
|
|
10884
11085
|
if (file.path.endsWith(".config.toml") && !existing.includes('name = "ClosedRouter"')) {
|
|
10885
11086
|
throw new Error(`Refusing to replace an existing Codex profile at ${file.path}.`);
|
|
10886
11087
|
}
|
|
@@ -10917,9 +11118,9 @@ function assertAgyCustomModel(command, label, apiKey) {
|
|
|
10917
11118
|
throw new Error(`This version of agy did not recognize '${label}'. Update agy to use ClosedRouter's accurate model display.`);
|
|
10918
11119
|
}
|
|
10919
11120
|
function assertAgyGeminiMode(homeDir) {
|
|
10920
|
-
const settingsPath =
|
|
11121
|
+
const settingsPath = join17(homeDir, ".gemini", "antigravity-cli", "settings.json");
|
|
10921
11122
|
try {
|
|
10922
|
-
const settings = JSON.parse(
|
|
11123
|
+
const settings = JSON.parse(readFileSync15(settingsPath, "utf8"));
|
|
10923
11124
|
if (settings?.modelProvider === "gemini")
|
|
10924
11125
|
return;
|
|
10925
11126
|
} catch {}
|
|
@@ -10994,7 +11195,8 @@ async function startCommand(options = {}) {
|
|
|
10994
11195
|
}
|
|
10995
11196
|
if (desktop && tool === "agy") {
|
|
10996
11197
|
assertAntigravityDesktopHookSupport(executablePath);
|
|
10997
|
-
|
|
11198
|
+
if (antigravityNativeAccountExists())
|
|
11199
|
+
await assertAntigravityModsAvailable();
|
|
10998
11200
|
}
|
|
10999
11201
|
const config = loadConfig();
|
|
11000
11202
|
const serverUrl = normalizeServerUrl(options.server || config.serverUrl);
|
|
@@ -11028,6 +11230,7 @@ async function startCommand(options = {}) {
|
|
|
11028
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.`);
|
|
11029
11231
|
}
|
|
11030
11232
|
const catalog = createLaunchCatalog(availableModels, model);
|
|
11233
|
+
const account = desktopAccountIdentity(config, serverUrl, apiKey);
|
|
11031
11234
|
if (desktop && tool === "cursor") {
|
|
11032
11235
|
const localKey = randomUUID5();
|
|
11033
11236
|
const relay = await startLaunchProxy(serverUrl, apiKey, "cursor-desktop", localKey, catalog);
|
|
@@ -11052,11 +11255,12 @@ async function startCommand(options = {}) {
|
|
|
11052
11255
|
if (sharedClaudeElectron && tool === "claude") {
|
|
11053
11256
|
if (sharedClaudeElectron)
|
|
11054
11257
|
useClaudeSharedElectron(plan, sharedClaudeElectron, sourceApp, options.toolArgs, true);
|
|
11055
|
-
addClaudeDesktopHook(plan, relay.baseUrl, localKey, sourceApp, catalog.models);
|
|
11258
|
+
addClaudeDesktopHook(plan, relay.baseUrl, localKey, sourceApp, catalog.models, account);
|
|
11056
11259
|
}
|
|
11057
11260
|
if (tool === "agy") {
|
|
11058
|
-
|
|
11059
|
-
|
|
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 });
|
|
11060
11264
|
}
|
|
11061
11265
|
writeDesktopLaunchPlan(plan);
|
|
11062
11266
|
M2.info(`Starting ${tool} desktop with ${model} through ${serverUrl}. Profile: ${plan.profileDir}. Keep cr running until you close this app instance.`);
|
|
@@ -11068,15 +11272,15 @@ async function startCommand(options = {}) {
|
|
|
11068
11272
|
return;
|
|
11069
11273
|
}
|
|
11070
11274
|
if (tool === "agy")
|
|
11071
|
-
assertAgyGeminiMode(
|
|
11072
|
-
const recognizedModel = tool === "agy" ? registerAgyLaunchCatalog(
|
|
11275
|
+
assertAgyGeminiMode(homedir15());
|
|
11276
|
+
const recognizedModel = tool === "agy" ? registerAgyLaunchCatalog(homedir15(), catalog, discoverAgyTransportModel(options.executablePath || "agy", apiKey)) : undefined;
|
|
11073
11277
|
if (recognizedModel)
|
|
11074
11278
|
assertAgyCustomModel(options.executablePath || "agy", recognizedModel, apiKey);
|
|
11075
11279
|
const relay = await startLaunchProxy(serverUrl, apiKey, tool, apiKey, catalog);
|
|
11076
11280
|
let agyProxy;
|
|
11077
11281
|
try {
|
|
11078
11282
|
agyProxy = tool === "agy" ? await startAgyModelProxy(relay.baseUrl, apiKey, model, catalog) : undefined;
|
|
11079
|
-
const plan = buildLaunchPlan(tool, relay.baseUrl, apiKey, model, options.toolArgs,
|
|
11283
|
+
const plan = buildLaunchPlan(tool, relay.baseUrl, apiKey, model, options.toolArgs, homedir15(), executablePath, agyProxy && recognizedModel ? { baseUrl: agyProxy.baseUrl, recognizedModel } : undefined, catalog);
|
|
11080
11284
|
if (plan.configFile)
|
|
11081
11285
|
writeOwnedConfig(plan.configFile);
|
|
11082
11286
|
for (const file of plan.extraFiles || [])
|
|
@@ -11135,7 +11339,7 @@ process.on("warning", (warning) => {
|
|
|
11135
11339
|
console.warn(warning.name, warning.message);
|
|
11136
11340
|
});
|
|
11137
11341
|
var program2 = new Command2;
|
|
11138
|
-
var cliVersion = JSON.parse(
|
|
11342
|
+
var cliVersion = JSON.parse(readFileSync16(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
11139
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) => {
|
|
11140
11344
|
await onboardCommand({ server: options.server });
|
|
11141
11345
|
});
|
package/package.json
CHANGED