@ai21/gateway 0.5.3

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 (44) hide show
  1. package/README.md +91 -0
  2. package/dist/args.d.ts +74 -0
  3. package/dist/args.js +304 -0
  4. package/dist/args.js.map +1 -0
  5. package/dist/cli.d.ts +10 -0
  6. package/dist/cli.js +140 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config.d.ts +76 -0
  9. package/dist/config.js +187 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/login/browser.d.ts +7 -0
  12. package/dist/login/browser.js +41 -0
  13. package/dist/login/browser.js.map +1 -0
  14. package/dist/login/contract.d.ts +42 -0
  15. package/dist/login/contract.js +60 -0
  16. package/dist/login/contract.js.map +1 -0
  17. package/dist/login/loopback.d.ts +42 -0
  18. package/dist/login/loopback.js +192 -0
  19. package/dist/login/loopback.js.map +1 -0
  20. package/dist/login/session.d.ts +36 -0
  21. package/dist/login/session.js +75 -0
  22. package/dist/login/session.js.map +1 -0
  23. package/dist/prompt.d.ts +32 -0
  24. package/dist/prompt.js +72 -0
  25. package/dist/prompt.js.map +1 -0
  26. package/dist/report.d.ts +50 -0
  27. package/dist/report.js +214 -0
  28. package/dist/report.js.map +1 -0
  29. package/dist/result.d.ts +26 -0
  30. package/dist/result.js +22 -0
  31. package/dist/result.js.map +1 -0
  32. package/dist/revert.d.ts +60 -0
  33. package/dist/revert.js +230 -0
  34. package/dist/revert.js.map +1 -0
  35. package/dist/router.d.ts +21 -0
  36. package/dist/router.js +271 -0
  37. package/dist/router.js.map +1 -0
  38. package/dist/snippets.d.ts +52 -0
  39. package/dist/snippets.js +71 -0
  40. package/dist/snippets.js.map +1 -0
  41. package/dist/verify.d.ts +96 -0
  42. package/dist/verify.js +309 -0
  43. package/dist/verify.js.map +1 -0
  44. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # ai21-intelligent-gateway-cli
2
+
3
+ One command to point a local coding agent at the AI21 Intelligent Gateway.
4
+ Ships as the `@ai21/gateway` package.
5
+
6
+ ## Usage
7
+
8
+ ```bash
9
+ npx @ai21/gateway install --agent-id <AGENT_ID>
10
+ ```
11
+
12
+ Merges `.claude/settings.json` so Claude Code routes through the gateway, then
13
+ sends one request to prove it works. The AI21 key is prompted for without echo —
14
+ pass `--key` only for scripting, since a key in argv stays in your shell history.
15
+
16
+ The dashboard prints this command for you (Add agent, or Reconnect on an existing
17
+ agent) and offers the key as a separate copy.
18
+
19
+ | Command | Does |
20
+ | ----------- | ------------------------------------------------ |
21
+ | `install` | write the config and verify it (default command) |
22
+ | `uninstall` | revert what this tool wrote |
23
+
24
+ `configure` is accepted as an alias for `install`: it was the verb's name through
25
+ 0.3.x, so commands copied from an older dashboard keep working.
26
+
27
+ There is a third verb, `login`, which signs in through the browser and then
28
+ installs. It parses and runs but is **left out of `--help`**: it calls back to a
29
+ loopback listener, which only works from a locally served dashboard — Chrome's
30
+ Local Network Access gate makes a public page's request to `127.0.0.1` hang. Until
31
+ that has a real answer it is a local-dev path, and advertising it would send
32
+ readers into a dead end. `--app <url>` points it at a local webapp.
33
+
34
+ The gateway defaults to `https://api.ai21.com/gateway`. `--gateway <url>` points
35
+ somewhere else — staging is `https://api.ai21-stg.com/gateway`, and the dashboard
36
+ puts it in the command it prints for you.
37
+
38
+ `--print` renders the config instead of writing it, with the key masked. `--help`
39
+ lists the rest.
40
+
41
+ `--client <name>` picks which agent to configure. `claude-code` is the default and
42
+ the only one supported so far — an unsupported name is refused rather than
43
+ defaulted, so a `--client` we do not implement never writes Claude Code's file by
44
+ mistake.
45
+
46
+ > **Internal only.** The package is published to AI21's Artifact Registry, not
47
+ > public npm, so a bare `npx` cannot reach it yet — see below.
48
+
49
+ ## Installing
50
+
51
+ `@ai21/gateway` is published to public npm, so nothing needs configuring:
52
+
53
+ ```bash
54
+ npx @ai21/gateway --version
55
+ ```
56
+
57
+ Run it from any directory other than this repo — inside the repo, `npx` finds the
58
+ local package and `ai21-gateway` is not on PATH.
59
+
60
+ Releases go out from the **Release and Publish** workflow (Actions tab), which runs
61
+ semantic-release: the version comes from the conventional-commit history since the
62
+ last tag. `package.json` stays at `0.0.0`; the git tag is the record.
63
+
64
+ `403` misleads: it reads as though the AI21 gateway rejected you, but it is npm
65
+ failing to reach the registry — before the CLI has run at all.
66
+
67
+ The last one catches people out: this project _is_ `@ai21/gateway`, so npx
68
+ resolves the name to the working directory instead of the registry, finds no
69
+ linked binary, and fails. The published artifact can never be exercised from its
70
+ own source tree — use a scratch directory.
71
+
72
+ ## Development
73
+
74
+ Requires Node 20+ (`engines`); `.nvmrc` pins 22, which is what CI builds and
75
+ tests on. No runtime dependencies; TypeScript and `@types/node` are the only dev
76
+ dependencies.
77
+
78
+ ```bash
79
+ ./scripts/init.sh # pre-commit, nvm, registry auth, dependencies
80
+ ```
81
+
82
+ Then day to day:
83
+
84
+ ```bash
85
+ npm run lint # eslint (--max-warnings 0); `lint:fix` to autofix
86
+ npm run typecheck # tsc --noEmit
87
+ npm run format # prettier --write (@ai21/prettier-config)
88
+ npm run quality # audit + lint + typecheck + format:check — what CI runs
89
+ npm test # build, then node --test
90
+ npm run precommit # what the pre-commit hook runs
91
+ ```
package/dist/args.d.ts ADDED
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Baked-in endpoints. Shipping these means the happy path needs no URL, and the
3
+ * snippets we tell people to copy carry no hostname that can go stale.
4
+ */
5
+ /** Production, and the only baked-in set. `--gateway` points elsewhere. */
6
+ export declare const DEFAULT_URLS: {
7
+ readonly app: "https://app.ai21.com";
8
+ readonly gateway: "https://api.ai21.com/gateway";
9
+ readonly identity: "https://api.ai21.com";
10
+ };
11
+ export interface ResolvedUrls {
12
+ readonly app: string;
13
+ readonly gateway: string;
14
+ readonly identity: string;
15
+ readonly agents: string;
16
+ }
17
+ /**
18
+ * `--gateway` overrides only the gateway itself — the escape hatch for a local
19
+ * or dev backend. `agents` is always derived from whichever gateway won, so an
20
+ * override stays internally consistent.
21
+ */
22
+ export declare function resolveUrls(gatewayOverride?: string, appOverride?: string): ResolvedUrls;
23
+ /** The workspace dashboard, built from the baked-in origin rather than a given URL. */
24
+ export declare function dashboardUrl(urls: ResolvedUrls, workspaceId: string): string;
25
+ /** Which coding agent's config to write. Only Claude Code is implemented; the flag
26
+ * exists so the choice is explicit at the boundary rather than assumed throughout. */
27
+ export declare const CLIENTS: readonly ["claude-code"];
28
+ export type Client = (typeof CLIENTS)[number];
29
+ export declare const DEFAULT_CLIENT: Client;
30
+ export declare const VERBS: readonly ["install", "login", "uninstall"];
31
+ export type Verb = (typeof VERBS)[number];
32
+ export declare const DOCUMENTED_VERBS: readonly Verb[];
33
+ export type Target = "repo" | "user";
34
+ export interface ParsedArgs {
35
+ readonly verb: Verb;
36
+ readonly urls: ResolvedUrls;
37
+ readonly target: Target;
38
+ /** Whose config gets written. Defaults to Claude Code. */
39
+ readonly client: Client;
40
+ readonly agentId?: string | undefined;
41
+ readonly key?: string | undefined;
42
+ readonly userId?: string | undefined;
43
+ readonly agentIdGuard?: string | undefined;
44
+ /** Anthropic credential for the direct verifying ping. Never written to disk. */
45
+ readonly anthropicKey?: string | undefined;
46
+ readonly noVerify: boolean;
47
+ readonly print: boolean;
48
+ readonly json: boolean;
49
+ readonly yes: boolean;
50
+ readonly fromBackup: boolean;
51
+ }
52
+ export type ParseOutcome = {
53
+ readonly kind: "args";
54
+ readonly args: ParsedArgs;
55
+ } | {
56
+ readonly kind: "help";
57
+ } | {
58
+ readonly kind: "version";
59
+ } | {
60
+ readonly kind: "error";
61
+ readonly message: string;
62
+ };
63
+ /**
64
+ * Shared with the interactive prompt, which is a second way these values enter
65
+ * the program and must not be a second way the rule is skipped.
66
+ */
67
+ export declare function containsControlCharacters(value: string): boolean;
68
+ /**
69
+ * A plain-http gateway that is not on this machine. `--gateway` allows http for
70
+ * local dev, but every request through it carries the AI21 key, so off-box http
71
+ * means credentials on the wire in the clear.
72
+ */
73
+ export declare function isInsecureGateway(gateway: string): boolean;
74
+ export declare function parseCliArgs(argv: readonly string[]): ParseOutcome;
package/dist/args.js ADDED
@@ -0,0 +1,304 @@
1
+ /**
2
+ * Argument parsing and per-verb validation.
3
+ *
4
+ * Everything here is pure: argv in, a resolved plan or an error message out. No
5
+ * I/O, no process access — that keeps the whole surface assertable without
6
+ * spawning anything.
7
+ */
8
+ import { parseArgs } from "node:util";
9
+ /**
10
+ * Baked-in endpoints. Shipping these means the happy path needs no URL, and the
11
+ * snippets we tell people to copy carry no hostname that can go stale.
12
+ */
13
+ /** Production, and the only baked-in set. `--gateway` points elsewhere. */
14
+ export const DEFAULT_URLS = {
15
+ app: "https://app.ai21.com",
16
+ gateway: "https://api.ai21.com/gateway",
17
+ identity: "https://api.ai21.com",
18
+ };
19
+ /**
20
+ * `--gateway` overrides only the gateway itself — the escape hatch for a local
21
+ * or dev backend. `agents` is always derived from whichever gateway won, so an
22
+ * override stays internally consistent.
23
+ */
24
+ export function resolveUrls(gatewayOverride, appOverride) {
25
+ const base = DEFAULT_URLS;
26
+ // Trailing slashes are stripped so appending a path can't produce `//`, which
27
+ // some gateways treat as a different route than the one intended.
28
+ const gateway = (gatewayOverride ?? base.gateway).replace(/\/+$/, "");
29
+ return {
30
+ app: (appOverride ?? base.app).replace(/\/+$/, ""),
31
+ gateway,
32
+ identity: base.identity,
33
+ agents: `${gateway}/settings/agents`,
34
+ };
35
+ }
36
+ /** The workspace dashboard, built from the baked-in origin rather than a given URL. */
37
+ export function dashboardUrl(urls, workspaceId) {
38
+ return `${urls.app}/w/${encodeURIComponent(workspaceId)}`;
39
+ }
40
+ /** Which coding agent's config to write. Only Claude Code is implemented; the flag
41
+ * exists so the choice is explicit at the boundary rather than assumed throughout. */
42
+ export const CLIENTS = ["claude-code"];
43
+ export const DEFAULT_CLIENT = "claude-code";
44
+ export const VERBS = ["install", "login", "uninstall"];
45
+ /* What --help and the usage errors name. `login` is accepted but not advertised: it
46
+ * needs a webapp that answers its loopback callback, which is a local-dev-only setup
47
+ * today, so offering it to everyone reading --help only invites a dead end. */
48
+ export const DOCUMENTED_VERBS = ["install", "uninstall"];
49
+ /** `configure` was this verb's name through 0.3.x, and the dashboard printed it. Still
50
+ * accepted so a copied command keeps working; deliberately absent from help. (`setup`
51
+ * was never released, so it needs no alias.) */
52
+ const VERB_ALIASES = { configure: "install" };
53
+ /** Flags each verb accepts, beyond the global `--help` / `--version`. */
54
+ const ALLOWED_FLAGS = {
55
+ install: [
56
+ "app",
57
+ "agent-id",
58
+ "client",
59
+ "key",
60
+ "user-id",
61
+ "gateway",
62
+ "repo",
63
+ "user",
64
+ "print",
65
+ "json",
66
+ "yes",
67
+ "anthropic-key",
68
+ "no-verify",
69
+ ],
70
+ // `login` ends in the same write-then-verify as `install`, so it takes the
71
+ // same verification flags.
72
+ // `--app` is the webapp counterpart of `--gateway`: the escape hatch for running
73
+ // `login` against a locally served webapp, which is the only way to develop the
74
+ // cross-repo handshake end to end.
75
+ login: ["gateway", "app", "client", "repo", "user", "print", "json", "anthropic-key", "no-verify"],
76
+ // `uninstall` needs --repo/--user for the same reason `install` does: it has to
77
+ // revert whichever settings.json was written, and a --user config would
78
+ // otherwise be unrevertable. It takes no --env/--gateway, though — it reads an
79
+ // existing file rather than resolving an endpoint. It will need `--client` the
80
+ // moment there is a second one, for the same unrevertable reason.
81
+ uninstall: ["agent-id", "from-backup", "yes", "json", "repo", "user"],
82
+ };
83
+ const OPTION_SPEC = {
84
+ help: { type: "boolean", short: "h" },
85
+ version: { type: "boolean", short: "v" },
86
+ key: { type: "string" },
87
+ "user-id": { type: "string" },
88
+ client: { type: "string" },
89
+ gateway: { type: "string" },
90
+ repo: { type: "boolean" },
91
+ user: { type: "boolean" },
92
+ print: { type: "boolean" },
93
+ json: { type: "boolean" },
94
+ yes: { type: "boolean" },
95
+ "from-backup": { type: "boolean" },
96
+ "agent-id": { type: "string" },
97
+ "anthropic-key": { type: "string" },
98
+ app: { type: "string" },
99
+ "no-verify": { type: "boolean" },
100
+ };
101
+ function fail(message) {
102
+ return { kind: "error", message };
103
+ }
104
+ function quoted(values) {
105
+ return values.map((value) => `'${value}'`).join(", ");
106
+ }
107
+ function asClient(value) {
108
+ return CLIENTS.includes(value) ? value : undefined;
109
+ }
110
+ /**
111
+ * Flags whose values end up inside `ANTHROPIC_CUSTOM_HEADERS`, which is a
112
+ * `\n`-joined string. A newline in any of them forges an extra header that
113
+ * Claude Code would then send on every gateway request, so they are validated
114
+ * here at the boundary rather than in the snippet builders — those stay a
115
+ * faithful copy of the webapp's.
116
+ *
117
+ * This matters more than it looks: `login` will populate `key` and `agent-id`
118
+ * from a loopback HTTP callback, so these values stop being purely local input.
119
+ */
120
+ const HEADER_VALUE_FLAGS = ["agent-id", "key", "user-id"];
121
+ /**
122
+ * Same rule, different reason: `--anthropic-key` is never written to disk, but it
123
+ * becomes the `x-api-key` header, where a bad value surfaces as a confusing 401.
124
+ */
125
+ const REQUEST_HEADER_VALUE_FLAGS = ["anthropic-key"];
126
+ /** Flags that only mean something on a run that actually verifies. */
127
+ const VERIFY_FLAGS = ["anthropic-key", "no-verify"];
128
+ // C0 controls plus DEL — covers \n and \r, and leaves no exotic gaps.
129
+ // eslint-disable-next-line no-control-regex
130
+ const CONTROL_CHARS = /[\u0000-\u001F\u007F]/;
131
+ /**
132
+ * Shared with the interactive prompt, which is a second way these values enter
133
+ * the program and must not be a second way the rule is skipped.
134
+ */
135
+ export function containsControlCharacters(value) {
136
+ return CONTROL_CHARS.test(value);
137
+ }
138
+ function validateHeaderValue(flag, value) {
139
+ if (value.trim() === "") {
140
+ return `--${flag} must not be empty.`;
141
+ }
142
+ if (CONTROL_CHARS.test(value)) {
143
+ return `--${flag} must not contain control characters — they would forge an extra request header.`;
144
+ }
145
+ return undefined;
146
+ }
147
+ /** Loopback never leaves the machine, so plain http there carries no exposure. */
148
+ function isLoopbackHost(hostname) {
149
+ return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "::1" || hostname === "[::1]";
150
+ }
151
+ /**
152
+ * A plain-http gateway that is not on this machine. `--gateway` allows http for
153
+ * local dev, but every request through it carries the AI21 key, so off-box http
154
+ * means credentials on the wire in the clear.
155
+ */
156
+ export function isInsecureGateway(gateway) {
157
+ try {
158
+ const { protocol, hostname } = new URL(gateway);
159
+ return protocol === "http:" && !isLoopbackHost(hostname);
160
+ }
161
+ catch {
162
+ return false;
163
+ }
164
+ }
165
+ /** Rejects anything that isn't an absolute http(s) URL. */
166
+ function validateUrlFlag(flag, value) {
167
+ let parsed;
168
+ try {
169
+ parsed = new URL(value);
170
+ }
171
+ catch {
172
+ return `--${flag} must be an absolute URL, got '${value}'`;
173
+ }
174
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
175
+ return `--${flag} must be http(s), got '${parsed.protocol}//'`;
176
+ }
177
+ return undefined;
178
+ }
179
+ const validateGateway = (value) => validateUrlFlag("gateway", value);
180
+ /**
181
+ * `--app` replaces an origin, so a path in it would be applied inconsistently: the
182
+ * sign-in URL is resolved against the origin and would drop it, while the dashboard
183
+ * link concatenates and would keep it.
184
+ */
185
+ function validateOrigin(flag, value) {
186
+ const { pathname, search, hash } = new URL(value);
187
+ return pathname === "/" && search === "" && hash === ""
188
+ ? undefined
189
+ : `--${flag} must be an origin with no path, got '${value}'`;
190
+ }
191
+ export function parseCliArgs(argv) {
192
+ let values;
193
+ let positionals;
194
+ try {
195
+ ({ values, positionals } = parseArgs({
196
+ args: [...argv],
197
+ options: OPTION_SPEC,
198
+ strict: true,
199
+ allowPositionals: true,
200
+ }));
201
+ }
202
+ catch (err) {
203
+ return fail(err instanceof Error ? err.message : String(err));
204
+ }
205
+ // --help / --version win over everything, including an invalid verb.
206
+ if (values.help === true)
207
+ return { kind: "help" };
208
+ if (values.version === true)
209
+ return { kind: "version" };
210
+ const [first, ...restPositionals] = positionals;
211
+ let verb = "install";
212
+ if (first !== undefined) {
213
+ const resolved = VERB_ALIASES[first] ?? first;
214
+ if (!VERBS.includes(resolved)) {
215
+ return fail(`Unknown command '${first}'. Valid commands are ${quoted(DOCUMENTED_VERBS)}.`);
216
+ }
217
+ verb = resolved;
218
+ }
219
+ if (restPositionals.length > 0) {
220
+ return fail(`'${verb}' takes no positional arguments, got ${quoted(restPositionals)}.`);
221
+ }
222
+ const supplied = Object.keys(values).filter((flag) => values[flag] !== undefined);
223
+ const allowed = ALLOWED_FLAGS[verb];
224
+ const rejected = supplied.filter((flag) => flag !== "help" && flag !== "version" && !allowed.includes(flag));
225
+ if (rejected.length > 0) {
226
+ // Explicit rejection rather than silent ignore. `--key` on `uninstall`, say,
227
+ // reads as though it selects which config to revert; quietly dropping it
228
+ // would revert something the user did not name.
229
+ return fail(`${rejected.map((flag) => `--${flag}`).join(", ")} ${rejected.length === 1 ? "is" : "are"} not valid for '${verb}'. ` +
230
+ `Valid flags for '${verb}': ${allowed.map((flag) => `--${flag}`).join(", ")}.`);
231
+ }
232
+ for (const flag of [...HEADER_VALUE_FLAGS, ...REQUEST_HEADER_VALUE_FLAGS]) {
233
+ const value = values[flag];
234
+ if (typeof value !== "string")
235
+ continue;
236
+ const problem = validateHeaderValue(flag, value);
237
+ if (problem !== undefined)
238
+ return fail(problem);
239
+ }
240
+ const clientRaw = typeof values.client === "string" ? values.client : undefined;
241
+ let client = DEFAULT_CLIENT;
242
+ if (clientRaw !== undefined) {
243
+ const resolved = asClient(clientRaw);
244
+ if (resolved === undefined) {
245
+ // Named rather than silently defaulted: `--client codex` writing Claude Code's
246
+ // settings.json would configure a client the user did not ask for.
247
+ return fail(`Unsupported client '${clientRaw}'. Supported clients are ${quoted(CLIENTS)}.`);
248
+ }
249
+ client = resolved;
250
+ }
251
+ const gateway = typeof values.gateway === "string" ? values.gateway : undefined;
252
+ if (gateway !== undefined) {
253
+ const problem = validateGateway(gateway);
254
+ if (problem !== undefined)
255
+ return fail(problem);
256
+ }
257
+ const app = typeof values.app === "string" ? values.app : undefined;
258
+ if (app !== undefined) {
259
+ const problem = validateUrlFlag("app", app) ?? validateOrigin("app", app);
260
+ if (problem !== undefined)
261
+ return fail(problem);
262
+ }
263
+ if (values.repo === true && values.user === true) {
264
+ return fail("--repo and --user are mutually exclusive; pass at most one.");
265
+ }
266
+ // --print neither writes nor verifies. Rejected rather than ignored, per the rule
267
+ // the per-verb check above applies — and --anthropic-key carries a credential.
268
+ // `--app` sets the origin the loopback listener accepts, so it only means something
269
+ // for `login`, the one flow a browser takes part in.
270
+ if (values.app !== undefined && verb !== "login") {
271
+ return fail("--app only applies to 'login', the flow a browser takes part in.");
272
+ }
273
+ const strandedVerifyFlags = VERIFY_FLAGS.filter((flag) => values.print === true && values[flag] !== undefined);
274
+ if (strandedVerifyFlags.length > 0) {
275
+ return fail(`${strandedVerifyFlags.map((flag) => `--${flag}`).join(", ")} ` +
276
+ `${strandedVerifyFlags.length === 1 ? "has" : "have"} no effect with --print, which neither writes nor verifies.`);
277
+ }
278
+ /* The dashboard hands over by printing a command carrying the agent id, and the key
279
+ * is prompted for rather than pasted into a shell — so both arrive the ordinary way,
280
+ * and there is nothing for this to special-case. */
281
+ if (verb === "install" && typeof values["agent-id"] !== "string") {
282
+ return fail("--agent-id is required to install. Pass --agent-id <id>.");
283
+ }
284
+ return {
285
+ kind: "args",
286
+ args: {
287
+ verb,
288
+ urls: resolveUrls(gateway, app),
289
+ target: values.user === true ? "user" : "repo",
290
+ client,
291
+ agentId: verb === "install" && typeof values["agent-id"] === "string" ? values["agent-id"] : undefined,
292
+ key: typeof values.key === "string" ? values.key : undefined,
293
+ userId: typeof values["user-id"] === "string" ? values["user-id"] : undefined,
294
+ agentIdGuard: verb === "uninstall" && typeof values["agent-id"] === "string" ? values["agent-id"] : undefined,
295
+ anthropicKey: typeof values["anthropic-key"] === "string" ? values["anthropic-key"] : undefined,
296
+ noVerify: values["no-verify"] === true,
297
+ print: values.print === true,
298
+ json: values.json === true,
299
+ yes: values.yes === true,
300
+ fromBackup: values["from-backup"] === true,
301
+ },
302
+ };
303
+ }
304
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import { type RunResult } from "./result.js";
3
+ export { EXIT, type RunResult } from "./result.js";
4
+ export declare const USAGE = "ai21-gateway \u2014 point a local coding agent at the AI21 Intelligent Gateway\n\nUsage:\n ai21-gateway install --agent-id <id> configure a repo (default command)\n ai21-gateway uninstall revert what this tool wrote\n ai21-gateway --help\n ai21-gateway --version\n\nInstall flags:\n --agent-id <id> agent to attribute requests to (required)\n --key <key> AI21 key; prompted for without echo when omitted. Prefer the\n prompt: a key passed here is kept in your shell history\n --user-id <id> adds the x-ai21-user-id attribution header\n --client <name> which agent to configure; 'claude-code' (default) is the only\n one supported so far\n --gateway <url> override the gateway URL outright\n --repo | --user write repo-local (default) or to the home directory\n --yes overwrite an existing conflicting value\n --print render the resolved configuration instead of writing it\n (the key is always masked)\n --json machine-readable output\n\nUninstall flags:\n --agent-id <id> guard: refuse unless the stored agent matches\n --from-backup restore settings.json.bak verbatim instead of removing\n only this tool's keys \u2014 discards later edits\n --yes proceed with a --from-backup restore that discards changes\n --repo | --user which settings.json to revert\n\nBy default 'uninstall' removes only the keys this tool wrote, leaving unrelated\nsettings and any later edits of your own intact.\n\nVerification flags:\n --anthropic-key <key> Anthropic credential for the verifying request; used\n only when 'claude' is not on PATH, never written to disk\n --no-verify write the configuration without verifying it\n\nAfter a successful write the CLI sends one request through the gateway to confirm\nthe configuration works: 'claude -p' when it is on PATH, otherwise a direct\nrequest if an Anthropic credential is available. With neither, verification is\nskipped with a warning \u2014 it never changes the exit code.\n\nRe-running the same command is a no-op. An existing settings.json is backed up\nto settings.json.bak before it is changed, and is left untouched if the CLI\nrefuses.";
5
+ export declare function readVersion(): string;
6
+ /**
7
+ * Pure entry point: argv in, streams-and-exit-code out. Keeping I/O at the edge
8
+ * is what lets the whole CLI be asserted without spawning a process.
9
+ */
10
+ export declare function run(argv: readonly string[]): Promise<RunResult>;
package/dist/cli.js ADDED
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, realpathSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { parseCliArgs } from "./args.js";
7
+ import { EXIT } from "./result.js";
8
+ import { dispatch } from "./router.js";
9
+ import { nodeVerifyDeps } from "./verify.js";
10
+ import { nodeBrowserDeps, openBrowser } from "./login/browser.js";
11
+ import { startLoopback } from "./login/loopback.js";
12
+ export { EXIT } from "./result.js";
13
+ export const USAGE = `ai21-gateway — point a local coding agent at the AI21 Intelligent Gateway
14
+
15
+ Usage:
16
+ ai21-gateway install --agent-id <id> configure a repo (default command)
17
+ ai21-gateway uninstall revert what this tool wrote
18
+ ai21-gateway --help
19
+ ai21-gateway --version
20
+
21
+ Install flags:
22
+ --agent-id <id> agent to attribute requests to (required)
23
+ --key <key> AI21 key; prompted for without echo when omitted. Prefer the
24
+ prompt: a key passed here is kept in your shell history
25
+ --user-id <id> adds the x-ai21-user-id attribution header
26
+ --client <name> which agent to configure; 'claude-code' (default) is the only
27
+ one supported so far
28
+ --gateway <url> override the gateway URL outright
29
+ --repo | --user write repo-local (default) or to the home directory
30
+ --yes overwrite an existing conflicting value
31
+ --print render the resolved configuration instead of writing it
32
+ (the key is always masked)
33
+ --json machine-readable output
34
+
35
+ Uninstall flags:
36
+ --agent-id <id> guard: refuse unless the stored agent matches
37
+ --from-backup restore settings.json.bak verbatim instead of removing
38
+ only this tool's keys — discards later edits
39
+ --yes proceed with a --from-backup restore that discards changes
40
+ --repo | --user which settings.json to revert
41
+
42
+ By default 'uninstall' removes only the keys this tool wrote, leaving unrelated
43
+ settings and any later edits of your own intact.
44
+
45
+ Verification flags:
46
+ --anthropic-key <key> Anthropic credential for the verifying request; used
47
+ only when 'claude' is not on PATH, never written to disk
48
+ --no-verify write the configuration without verifying it
49
+
50
+ After a successful write the CLI sends one request through the gateway to confirm
51
+ the configuration works: 'claude -p' when it is on PATH, otherwise a direct
52
+ request if an Anthropic credential is available. With neither, verification is
53
+ skipped with a warning — it never changes the exit code.
54
+
55
+ Re-running the same command is a no-op. An existing settings.json is backed up
56
+ to settings.json.bak before it is changed, and is left untouched if the CLI
57
+ refuses.`;
58
+ /** Absolute path to the package root, resolved from this module's location. */
59
+ function packageRoot() {
60
+ return join(dirname(fileURLToPath(import.meta.url)), "..");
61
+ }
62
+ export function readVersion() {
63
+ const raw = readFileSync(join(packageRoot(), "package.json"), "utf8");
64
+ const { version } = JSON.parse(raw);
65
+ if (typeof version !== "string") {
66
+ throw new Error('package.json is missing a string "version"');
67
+ }
68
+ return version;
69
+ }
70
+ function versionResult() {
71
+ try {
72
+ return { code: EXIT.OK, out: `${readVersion()}\n`, err: "" };
73
+ }
74
+ catch {
75
+ // Deliberately no error detail: the underlying failure is an fs error
76
+ // carrying an absolute install path, and user-facing errors must not leak
77
+ // internal paths or stack traces.
78
+ return {
79
+ code: EXIT.INTERNAL,
80
+ out: "",
81
+ err: "ai21-gateway: could not read its own package metadata — the installation looks corrupt. Try reinstalling.\n",
82
+ };
83
+ }
84
+ }
85
+ /**
86
+ * Pure entry point: argv in, streams-and-exit-code out. Keeping I/O at the edge
87
+ * is what lets the whole CLI be asserted without spawning a process.
88
+ */
89
+ export async function run(argv) {
90
+ // Bare invocation is a request for orientation, not a failed `install`.
91
+ if (argv.length === 0)
92
+ return { code: EXIT.OK, out: `${USAGE}\n`, err: "" };
93
+ const outcome = parseCliArgs(argv);
94
+ switch (outcome.kind) {
95
+ case "help":
96
+ return { code: EXIT.OK, out: `${USAGE}\n`, err: "" };
97
+ case "version":
98
+ return versionResult();
99
+ case "error":
100
+ return { code: EXIT.USAGE, out: "", err: `${outcome.message}\n\n${USAGE}\n` };
101
+ case "args":
102
+ // Everything the CLI needs from the outside world is gathered here, at the
103
+ // edge, so every layer below stays pure and testable against a temp
104
+ // directory and a pair of fake streams.
105
+ return dispatch(outcome.args, {
106
+ paths: { cwd: process.cwd(), home: homedir() },
107
+ prompt: { input: process.stdin, output: process.stderr },
108
+ processEnv: process.env,
109
+ verify: nodeVerifyDeps(process.env),
110
+ login: {
111
+ startListener: startLoopback,
112
+ openBrowser: (url) => openBrowser(url, nodeBrowserDeps()),
113
+ },
114
+ // stderr, so `--json` on stdout stays a single parseable object even while
115
+ // login narrates its progress.
116
+ notify: (message) => process.stderr.write(`${message}\n`),
117
+ });
118
+ }
119
+ }
120
+ function isMain() {
121
+ const invoked = process.argv[1];
122
+ if (invoked === undefined)
123
+ return false;
124
+ try {
125
+ // realpath both sides: npm installs `bin` as a symlink into node_modules/.bin
126
+ return realpathSync(invoked) === realpathSync(fileURLToPath(import.meta.url));
127
+ }
128
+ catch {
129
+ return false;
130
+ }
131
+ }
132
+ if (isMain()) {
133
+ const { code, out, err } = await run(process.argv.slice(2));
134
+ if (out !== "")
135
+ process.stdout.write(out);
136
+ if (err !== "")
137
+ process.stderr.write(err);
138
+ process.exit(code);
139
+ }
140
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}