@ai21/gateway 1.3.1 → 1.5.0

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.
Files changed (69) hide show
  1. package/README.md +52 -17
  2. package/dist/agents/claude-code/desktop.d.ts +81 -0
  3. package/dist/agents/claude-code/desktop.js +615 -0
  4. package/dist/agents/claude-code/desktop.js.map +1 -0
  5. package/dist/agents/claude-code/desktopWindows.d.ts +10 -0
  6. package/dist/agents/claude-code/desktopWindows.js +151 -0
  7. package/dist/agents/claude-code/desktopWindows.js.map +1 -0
  8. package/dist/agents/claude-code/index.d.ts +7 -0
  9. package/dist/agents/claude-code/index.js +114 -0
  10. package/dist/agents/claude-code/index.js.map +1 -0
  11. package/dist/agents/claude-code/verify.d.ts +8 -50
  12. package/dist/agents/claude-code/verify.js +22 -9
  13. package/dist/agents/claude-code/verify.js.map +1 -1
  14. package/dist/agents/codex/config.d.ts +20 -0
  15. package/dist/agents/codex/config.js +347 -0
  16. package/dist/agents/codex/config.js.map +1 -0
  17. package/dist/agents/codex/index.d.ts +2 -0
  18. package/dist/agents/codex/index.js +79 -0
  19. package/dist/agents/codex/index.js.map +1 -0
  20. package/dist/agents/codex/snippets.d.ts +23 -0
  21. package/dist/agents/codex/snippets.js +39 -0
  22. package/dist/agents/codex/snippets.js.map +1 -0
  23. package/dist/agents/codex/status.d.ts +8 -0
  24. package/dist/agents/codex/status.js +36 -0
  25. package/dist/agents/codex/status.js.map +1 -0
  26. package/dist/agents/codex/toml.d.ts +57 -0
  27. package/dist/agents/codex/toml.js +196 -0
  28. package/dist/agents/codex/toml.js.map +1 -0
  29. package/dist/agents/codex/verify.d.ts +2 -0
  30. package/dist/agents/codex/verify.js +43 -0
  31. package/dist/agents/codex/verify.js.map +1 -0
  32. package/dist/agents/registry.d.ts +10 -0
  33. package/dist/agents/registry.js +14 -0
  34. package/dist/agents/registry.js.map +1 -0
  35. package/dist/agents/types.d.ts +45 -0
  36. package/dist/agents/types.js.map +1 -1
  37. package/dist/args.d.ts +2 -3
  38. package/dist/args.js +7 -9
  39. package/dist/args.js.map +1 -1
  40. package/dist/cli.d.ts +1 -1
  41. package/dist/cli.js +19 -12
  42. package/dist/cli.js.map +1 -1
  43. package/dist/fs/safeFile.d.ts +1 -0
  44. package/dist/fs/safeFile.js.map +1 -1
  45. package/dist/fs/snapshot.d.ts +1 -1
  46. package/dist/fs/snapshot.js +1 -1
  47. package/dist/login/browser.js +2 -4
  48. package/dist/login/browser.js.map +1 -1
  49. package/dist/precheck.d.ts +4 -1
  50. package/dist/precheck.js +12 -9
  51. package/dist/precheck.js.map +1 -1
  52. package/dist/process.d.ts +2 -0
  53. package/dist/process.js +6 -4
  54. package/dist/process.js.map +1 -1
  55. package/dist/report.d.ts +16 -19
  56. package/dist/report.js +36 -62
  57. package/dist/report.js.map +1 -1
  58. package/dist/result.d.ts +7 -5
  59. package/dist/result.js +7 -5
  60. package/dist/result.js.map +1 -1
  61. package/dist/router.d.ts +7 -2
  62. package/dist/router.js +171 -114
  63. package/dist/router.js.map +1 -1
  64. package/dist/status.js +11 -3
  65. package/dist/status.js.map +1 -1
  66. package/dist/telemetry/events.d.ts +3 -2
  67. package/dist/telemetry/events.js +0 -6
  68. package/dist/telemetry/events.js.map +1 -1
  69. package/package.json +1 -1
package/README.md CHANGED
@@ -9,9 +9,13 @@ Ships as the `@ai21/gateway` package.
9
9
  npx @ai21/gateway install --agent-id <AGENT_ID>
10
10
  ```
11
11
 
12
- Merges `~/.claude/settings.json` so Claude Code routes through the gateway from
13
- every project on the machine (pass `--repo` to configure only the current one), then
14
- sends one request to prove it works. With no key stored it signs you in through the
12
+ Configures a coding agent — Claude Code or Codex — so it routes through the
13
+ gateway. Writes the agent's config file (`.claude/settings.json` for Claude Code,
14
+ `config.toml` for Codex), then sends one request to prove it works.
15
+
16
+ Use `--client codex` for Codex (user-level only; Codex ignores `model_provider`
17
+ and `model_providers` in a project's `.codex/config.toml`). `--client claude-code`
18
+ is the default and also accepts `--repo` for a project-local setup. With no key stored it signs you in through the
15
19
  browser first and creates an AI21 key for you, all in the one command — pass `--key`
16
20
  only for scripting, since a key in argv stays in your shell history.
17
21
 
@@ -25,17 +29,17 @@ and a warning says the key went unchecked.
25
29
  `--no-verify` turns off the _post-write_ check — the one that proves end to end that
26
30
  Claude Code reaches the gateway. It does not affect the pre-write key check.
27
31
 
28
- The gateway passes your own Claude credential through, so without a Claude login it
29
- can never answer. When `claude` reports no login — before the write, or when the
30
- post-write check proves it — the command prints `No Claude subscription detected`,
31
- leaves `settings.json` as it was before the run, and exits 9. A timeout or any other
32
- verification failure only warns and keeps the config. `--no-verify` skips this too, for
33
- machines where Claude Code is signed in later.
32
+ The gateway passes the agent's own login through. Without one it can never answer,
33
+ so `install` checks before the write (with `claude auth status` or `codex login
34
+ status`) and, when verification proves it, undoes the write and exits 9. A timeout
35
+ or any other verification failure only warns and keeps the config. The no-subscription
36
+ check and verification are skipped under `--no-verify`. For Claude Code an Anthropic
37
+ key (`--anthropic-key` or `ANTHROPIC_API_KEY`) can stand in for the login.
34
38
 
35
- The gateway currently supports only the Claude Code CLI. With no `claude` on PATH and
36
- no Anthropic key (`--anthropic-key` or `ANTHROPIC_API_KEY`), `install` stops before
37
- signing in, writes nothing, and exits 10, even under `--no-verify`. With an Anthropic
38
- key it goes ahead and verifies with a direct request instead.
39
+ Without the agent's CLI on PATH, `install` stops before signing in, writes nothing,
40
+ and exits 10, even under `--no-verify` (or, for Claude Code, with neither an Anthropic
41
+ key nor Claude Desktop). For Codex there is no stand-in: only the Codex CLI can send the ChatGPT login
42
+ the gateway forwards.
39
43
 
40
44
  The dashboard prints this command for you (Add agent, or Reconnect on an existing
41
45
  agent) and offers the key as a separate copy.
@@ -95,10 +99,41 @@ derive, so `login` asks for `--app <url>` instead of guessing.
95
99
  `--print` renders the config instead of writing it, with the key masked. `--help`
96
100
  lists the rest.
97
101
 
98
- `--client <name>` picks which agent to configure. `claude-code` is the default and
99
- the only one supported so far — an unsupported name is refused rather than
100
- defaulted, so a `--client` we do not implement never writes Claude Code's file by
101
- mistake.
102
+ `--client <name>` picks which agent to configure: `claude-code` (the default) or
103
+ `codex`. An unsupported name is refused rather than defaulted, so it never writes
104
+ the wrong agent's file by mistake. `uninstall` also takes `--client` to know whose
105
+ file to revert.
106
+
107
+ ### Claude Desktop
108
+
109
+ `claude-code` covers every Claude app on the machine: `install` configures the Claude
110
+ Code CLI and Claude Desktop, whichever are installed, in one run, and `uninstall`
111
+ reverts both. It is one setup for analytics, with `agentKind: claude_code`. Desktop
112
+ is configured only for a user-level install; `--repo` leaves it alone.
113
+
114
+ Desktop uses its own third-party inference mode rather than a patched app: a gateway
115
+ profile in `~/Library/Application Support/Claude-3p/configLibrary/`, applied through
116
+ `_meta.json`, with `deploymentMode: "3p"` in both Desktop configs. Its 1P/3P chooser
117
+ and its telemetry are turned off.
118
+
119
+ It runs on the user's own Claude subscription. The first install runs `claude
120
+ setup-token`, which opens the browser once and returns a token that lasts about a
121
+ year; if the token cannot be read off the screen, it is pasted into a hidden prompt.
122
+ The token is kept in the login keychain (`ai21-gateway-claude-desktop`), and a helper
123
+ script at `~/.config/ai21-gateway/claude-desktop-credential` hands it to Desktop, which
124
+ sends it as `Authorization: Bearer`. A re-install reuses it, and
125
+ `CLAUDE_CODE_OAUTH_TOKEN` supplies one without the browser step.
126
+
127
+ Desktop is verified through the gateway before its profile is written. It reads the
128
+ profile only at launch, so `install` quits it if it is running and opens it again;
129
+ run from inside Desktop's own Claude Code, it asks you to reopen it instead.
130
+
131
+ On Windows the profile lives under `%LOCALAPPDATA%\Claude-3p` (or `Claude Nest-3p`), and
132
+ the token in an owner-only file, `~/.config/ai21-gateway/claude-desktop-token`, which
133
+ Desktop reads by running `cmd.exe /d /c type <file>`: Electron cannot spawn a `.cmd`.
134
+ There is no `script` to record the approval screen, so you paste the token into a hidden
135
+ prompt. Closing Desktop only sends it to the tray, so `install` stops its processes before
136
+ reopening it; a Microsoft Store install is reopened by its app id.
102
137
 
103
138
  `install` reports onboarding events to AI21's product analytics (Amplitude), so we can
104
139
  see where setup fails: when it started, then whether it completed or at which step it
@@ -0,0 +1,81 @@
1
+ import type { AgentEnv, AgentSurface, SnippetInputs } from "../types.js";
2
+ /** Fixed, so a re-install replaces our profile instead of stacking a second one. */
3
+ export declare const DESKTOP_PROFILE_ID = "00000000-0000-4000-8000-00000000a121";
4
+ export declare const DESKTOP_PROFILE_NAME = "AI21 Gateway";
5
+ export declare const DESKTOP_BUNDLE_ID = "com.anthropic.claudefordesktop";
6
+ /** Where the subscription token lives. Read raw by the helper, so it is not base64 like the login secrets. */
7
+ export declare const TOKEN_SERVICE = "ai21-gateway-claude-desktop";
8
+ export declare const TOKEN_ACCOUNT = "claude-oauth-token";
9
+ /** A subscription token, or undefined: it is quoted into `security -i` and sent as a header, so nothing else may pass. */
10
+ export declare function oauthToken(value: string | undefined): string | undefined;
11
+ export type DesktopPlatform = "darwin" | "win32";
12
+ export interface DesktopPaths {
13
+ readonly platform: DesktopPlatform;
14
+ /** The regular Claude profile's config; its `deploymentMode` picks 1P or 3P at launch. */
15
+ readonly normalConfig: string;
16
+ readonly thirdPartyConfig: string;
17
+ readonly meta: string;
18
+ readonly profile: string;
19
+ /** What was applied before us, so uninstall can put it back. */
20
+ readonly restore: string;
21
+ /** macOS: the helper script over the keychain; Windows: the owner-only token file that `cmd /c type` prints. */
22
+ readonly helper: string;
23
+ readonly helperCommand: {
24
+ readonly path: string;
25
+ readonly args?: readonly string[];
26
+ };
27
+ }
28
+ export declare function desktopPaths(home: string, platform?: NodeJS.Platform, env?: Record<string, string | undefined>): DesktopPaths;
29
+ export declare function desktopHeaders({ agentId, ai21Key, userId, client }: SnippetInputs): Record<string, string>;
30
+ export declare function helperScript(): string;
31
+ export declare function desktopProfile(inputs: SnippetInputs, paths: DesktopPaths): Record<string, unknown>;
32
+ export type DesktopOutcome = {
33
+ readonly kind: "written";
34
+ readonly path: string;
35
+ } | {
36
+ readonly kind: "reverted";
37
+ readonly path: string;
38
+ } | {
39
+ readonly kind: "not-configured";
40
+ readonly path: string;
41
+ } | {
42
+ readonly kind: "malformed";
43
+ readonly path: string;
44
+ readonly reason: string;
45
+ } | {
46
+ readonly kind: "failed";
47
+ readonly path: string;
48
+ readonly reason: string;
49
+ };
50
+ /** Every file is parsed before any is written, so a malformed one leaves all untouched. */
51
+ export declare function writeDesktopConfig(paths: DesktopPaths, inputs: SnippetInputs): DesktopOutcome;
52
+ export declare function revertDesktopConfig(paths: DesktopPaths): DesktopOutcome;
53
+ /** Everything outside this process, injected so tests never touch the real app or keychain. */
54
+ export interface DesktopDeps {
55
+ readonly platform: NodeJS.Platform;
56
+ readonly installed: () => boolean;
57
+ readonly isRunning: () => Promise<boolean>;
58
+ readonly quit: () => Promise<void>;
59
+ /** For an app that closes to the tray instead of exiting; absent where quit really quits. */
60
+ readonly forceQuit?: () => Promise<void>;
61
+ readonly open: () => Promise<void>;
62
+ readonly sleep: (ms: number) => Promise<void>;
63
+ readonly readToken: () => Promise<string | undefined>;
64
+ readonly storeToken: (token: string) => Promise<void>;
65
+ readonly forgetToken: () => Promise<void>;
66
+ /** Runs `claude setup-token` in the user's terminal; the token it printed, if one could be read. */
67
+ readonly setupToken: () => Promise<string | undefined>;
68
+ readonly pasteToken: () => Promise<string | undefined>;
69
+ }
70
+ export declare function run(file: string, args: readonly string[]): Promise<string>;
71
+ export declare function macDesktopDeps(): DesktopDeps;
72
+ /** Replays a terminal transcript onto a grid: Claude Code draws with cursor moves, so the token is never in one piece. */
73
+ export declare function screenFromTranscript(transcript: string): string;
74
+ /** The token on the final screen, joined across the lines the terminal wrapped it onto. */
75
+ export declare function tokenFromTranscript(transcript: string): string | undefined;
76
+ export declare function promptToken(): Promise<string | undefined>;
77
+ export type LaunchOutcome = "opened" | "restarted" | "still-running" | "open-failed";
78
+ /** Desktop reads the profile only at launch: quit it if running, then open it either way. */
79
+ export declare function relaunchDesktop(deps: DesktopDeps): Promise<LaunchOutcome>;
80
+ /** Tests replace the app and keychain; everything else about the surface is real. */
81
+ export declare function claudeDesktopSurface(desktopDeps?: (env: AgentEnv) => DesktopDeps): AgentSurface;