@ai21/gateway 1.3.0 → 1.4.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 (93) hide show
  1. package/README.md +26 -21
  2. package/dist/agents/claude-code/index.d.ts +7 -0
  3. package/dist/agents/claude-code/index.js +112 -0
  4. package/dist/agents/claude-code/index.js.map +1 -0
  5. package/dist/agents/claude-code/revert.d.ts +11 -0
  6. package/dist/{revert.js → agents/claude-code/revert.js} +2 -1
  7. package/dist/agents/claude-code/revert.js.map +1 -0
  8. package/dist/agents/claude-code/settings.d.ts +33 -0
  9. package/dist/{config.js → agents/claude-code/settings.js} +6 -57
  10. package/dist/agents/claude-code/settings.js.map +1 -0
  11. package/dist/{snippets.d.ts → agents/claude-code/snippets.d.ts} +1 -18
  12. package/dist/{snippets.js → agents/claude-code/snippets.js} +0 -19
  13. package/dist/agents/claude-code/snippets.js.map +1 -0
  14. package/dist/agents/claude-code/status.d.ts +12 -0
  15. package/dist/agents/claude-code/status.js +42 -0
  16. package/dist/agents/claude-code/status.js.map +1 -0
  17. package/dist/agents/claude-code/verify.d.ts +39 -0
  18. package/dist/{verify.js → agents/claude-code/verify.js} +4 -135
  19. package/dist/agents/claude-code/verify.js.map +1 -0
  20. package/dist/agents/codex/config.d.ts +20 -0
  21. package/dist/agents/codex/config.js +344 -0
  22. package/dist/agents/codex/config.js.map +1 -0
  23. package/dist/agents/codex/index.d.ts +2 -0
  24. package/dist/agents/codex/index.js +79 -0
  25. package/dist/agents/codex/index.js.map +1 -0
  26. package/dist/agents/codex/snippets.d.ts +23 -0
  27. package/dist/agents/codex/snippets.js +39 -0
  28. package/dist/agents/codex/snippets.js.map +1 -0
  29. package/dist/agents/codex/status.d.ts +8 -0
  30. package/dist/agents/codex/status.js +36 -0
  31. package/dist/agents/codex/status.js.map +1 -0
  32. package/dist/agents/codex/toml.d.ts +57 -0
  33. package/dist/agents/codex/toml.js +196 -0
  34. package/dist/agents/codex/toml.js.map +1 -0
  35. package/dist/agents/codex/verify.d.ts +2 -0
  36. package/dist/agents/codex/verify.js +43 -0
  37. package/dist/agents/codex/verify.js.map +1 -0
  38. package/dist/agents/deps.d.ts +3 -0
  39. package/dist/agents/deps.js +10 -0
  40. package/dist/agents/deps.js.map +1 -0
  41. package/dist/agents/registry.d.ts +10 -0
  42. package/dist/agents/registry.js +14 -0
  43. package/dist/agents/registry.js.map +1 -0
  44. package/dist/agents/types.d.ts +276 -0
  45. package/dist/agents/types.js +3 -0
  46. package/dist/agents/types.js.map +1 -0
  47. package/dist/args.d.ts +2 -3
  48. package/dist/args.js +7 -9
  49. package/dist/args.js.map +1 -1
  50. package/dist/cli.d.ts +1 -1
  51. package/dist/cli.js +21 -14
  52. package/dist/cli.js.map +1 -1
  53. package/dist/fs/safeFile.d.ts +20 -0
  54. package/dist/fs/safeFile.js +50 -0
  55. package/dist/fs/safeFile.js.map +1 -0
  56. package/dist/{snapshot.d.ts → fs/snapshot.d.ts} +2 -2
  57. package/dist/{snapshot.js → fs/snapshot.js} +2 -2
  58. package/dist/fs/snapshot.js.map +1 -0
  59. package/dist/login/keychain/linux.d.ts +1 -1
  60. package/dist/login/keychain/linux.js +1 -1
  61. package/dist/login/keychain/linux.js.map +1 -1
  62. package/dist/precheck.d.ts +4 -1
  63. package/dist/precheck.js +12 -9
  64. package/dist/precheck.js.map +1 -1
  65. package/dist/process.d.ts +26 -0
  66. package/dist/process.js +94 -0
  67. package/dist/process.js.map +1 -0
  68. package/dist/report.d.ts +17 -25
  69. package/dist/report.js +36 -62
  70. package/dist/report.js.map +1 -1
  71. package/dist/result.d.ts +5 -5
  72. package/dist/result.js +5 -5
  73. package/dist/result.js.map +1 -1
  74. package/dist/router.d.ts +6 -4
  75. package/dist/router.js +132 -120
  76. package/dist/router.js.map +1 -1
  77. package/dist/telemetry/amplitudeHttp.js +1 -0
  78. package/dist/telemetry/amplitudeHttp.js.map +1 -1
  79. package/dist/telemetry/events.d.ts +10 -5
  80. package/dist/telemetry/events.js +0 -6
  81. package/dist/telemetry/events.js.map +1 -1
  82. package/dist/telemetry/telemetry.d.ts +6 -2
  83. package/dist/telemetry/telemetry.js +19 -8
  84. package/dist/telemetry/telemetry.js.map +1 -1
  85. package/package.json +3 -3
  86. package/dist/config.d.ts +0 -83
  87. package/dist/config.js.map +0 -1
  88. package/dist/revert.d.ts +0 -60
  89. package/dist/revert.js.map +0 -1
  90. package/dist/snapshot.js.map +0 -1
  91. package/dist/snippets.js.map +0 -1
  92. package/dist/verify.d.ts +0 -119
  93. package/dist/verify.js.map +0 -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, without an Anthropic
41
+ key). 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,17 +99,18 @@ 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.
102
106
 
103
107
  `install` reports onboarding events to AI21's product analytics (Amplitude), so we can
104
108
  see where setup fails: when it started, then whether it completed or at which step it
105
- failed, with the CLI version, OS, workspace id and a random per-run id. A failure is
106
- reported as a fixed reason, never the message you saw, so no key, email, path, agent id
107
- or argument is ever sent. Setup counts as completed only once the written config has
108
- been verified. Only the production and staging gateways report; any other `--gateway`
109
+ failed, with your AI21 user id, the CLI version, OS, workspace id and a random per-run
110
+ id. A failure is reported as a fixed reason, never the message you saw, so no key, email,
111
+ path, agent id or argument is ever sent. Setup counts as completed only once the written
112
+ config has been verified. A setup run while no one is signed in to that gateway is not
113
+ reported. Only the production and staging gateways report; any other `--gateway`
109
114
  sends nothing. Reporting never delays or fails a command (`src/telemetry/`).
110
115
 
111
116
  > **Internal only.** The package is published to AI21's Artifact Registry, not
@@ -0,0 +1,7 @@
1
+ import type { CodingAgent, Warning } from "../types.js";
2
+ /** Pure, so tests pass the shadowing file as data rather than write one. */
3
+ export declare function claudeWarnings(processEnv: Record<string, string | undefined>, localOverride: {
4
+ readonly path: string;
5
+ readonly agentId?: string;
6
+ } | undefined): Warning[];
7
+ export declare const claudeCode: CodingAgent;
@@ -0,0 +1,112 @@
1
+ /** Claude Code: `env` keys in `settings.json`, checked with `claude auth status`, verified with `claude -p`. */
2
+ import { findOnPath } from "../../process.js";
3
+ import { revertConfig } from "./revert.js";
4
+ import { resolvePaths, shadowingLocalConfig, writeConfig } from "./settings.js";
5
+ import { ccSettings, ccSettingsEnv } from "./snippets.js";
6
+ import { checkClaudeLogin } from "./status.js";
7
+ import { CLAUDE_COMMAND, resolveAnthropicKey, verify } from "./verify.js";
8
+ const text = {
9
+ // Predates the agent-neutral outcome; `--json` consumers already match on it.
10
+ noSubscriptionOutcome: "no-claude-credential",
11
+ noSubscription: {
12
+ "logged-out": {
13
+ headline: "No Claude subscription detected.",
14
+ nextStep: "If you have one, run `/login` inside `claude`, then re-run this command. Otherwise, subscribe to Claude.",
15
+ jsonReason: "no_claude_subscription",
16
+ telemetryReason: "agent not logged in",
17
+ },
18
+ "key-rejected": {
19
+ headline: "Anthropic rejected your API key.",
20
+ nextStep: "Check ANTHROPIC_API_KEY (or --anthropic-key), or unset it and run `/login` inside `claude`, then re-run this command.",
21
+ jsonReason: "anthropic_key_rejected",
22
+ telemetryReason: "upstream credential rejected",
23
+ },
24
+ },
25
+ verifiedVia: {
26
+ "claude-cli": "`claude -p`",
27
+ "direct-ping": "a direct request",
28
+ },
29
+ skippedBecause: "no Anthropic credential was available",
30
+ notInstalled: {
31
+ message: "The Claude Code CLI was not found. The AI21 gateway currently supports only the Claude Code CLI; install it to use the gateway, then re-run this command.",
32
+ jsonOutcome: "no-claude-cli",
33
+ // Kept apart from `no_claude_subscription` so a funnel can split them.
34
+ jsonReason: "claude_code_cli_not_installed",
35
+ telemetryReason: "agent cli not installed",
36
+ },
37
+ checkingLogin: "Checking your Claude login…",
38
+ loginFound: "Claude login found",
39
+ };
40
+ /** Pure, so tests pass the shadowing file as data rather than write one. */
41
+ export function claudeWarnings(processEnv, localOverride) {
42
+ const found = [];
43
+ if (processEnv.ANTHROPIC_API_KEY !== undefined && processEnv.ANTHROPIC_API_KEY !== "") {
44
+ found.push({
45
+ code: "anthropic-api-key-set",
46
+ // It shadows the claude.ai login and surfaces as a 401 from the gateway,
47
+ // which reads as "the CLI wrote a bad config" rather than "unset this".
48
+ message: "ANTHROPIC_API_KEY is set in your environment. It overrides the credential Claude Code manages and can cause 401s through the gateway — unset it if requests start failing.",
49
+ });
50
+ }
51
+ if (localOverride !== undefined) {
52
+ const { path, agentId } = localOverride;
53
+ found.push({
54
+ code: "shadowed-by-local-config",
55
+ message: `${path} also sets Claude Code's env, and it is read after this file — so it wins. ` +
56
+ (agentId === undefined
57
+ ? "Requests will not use the agent configured here."
58
+ : `Requests will report as '${agentId}', not the agent configured here.`) +
59
+ " Remove its env block, or move your override into this file.",
60
+ });
61
+ }
62
+ return found;
63
+ }
64
+ export const claudeCode = {
65
+ id: "claude-code",
66
+ kind: "claude_code",
67
+ displayName: "Claude Code",
68
+ configLabel: "settings.json",
69
+ targets: ["user", "repo"],
70
+ verifyFlags: ["anthropic-key"],
71
+ checkInstalled(ctx, deps) {
72
+ // An Anthropic key alone is enough: it serves any other client, and the direct ping verifies with it.
73
+ if (findOnPath(CLAUDE_COMMAND, deps.lookup) !== undefined)
74
+ return { kind: "present" };
75
+ return resolveAnthropicKey({ anthropicKey: ctx.upstreamKey, processEnv: ctx.processEnv }) === undefined
76
+ ? { kind: "missing" }
77
+ : { kind: "present" };
78
+ },
79
+ resolvePaths(target, env) {
80
+ // `claude` must run where the file we wrote is the one that wins: a project-local
81
+ // settings.json outranks the home one, so a `--user` config is verified from home.
82
+ return { ...resolvePaths(target, env), verifyCwd: target === "user" ? env.home : env.cwd };
83
+ },
84
+ preview(inputs) {
85
+ return { text: ccSettings(inputs), json: { settings: { env: ccSettingsEnv(inputs) } } };
86
+ },
87
+ write(paths, inputs, options) {
88
+ return writeConfig(paths, ccSettingsEnv(inputs), options);
89
+ },
90
+ revert: revertConfig,
91
+ redact(value) {
92
+ return value.replace(/(x-ai21-key:\s*)\S+/gi, "$1****");
93
+ },
94
+ warnings(paths, processEnv) {
95
+ return claudeWarnings(processEnv, shadowingLocalConfig(paths));
96
+ },
97
+ async checkSubscription(paths, deps) {
98
+ switch (await checkClaudeLogin(paths.verifyCwd, deps)) {
99
+ case "logged-in":
100
+ return { kind: "present" };
101
+ case "logged-out":
102
+ return { kind: "missing", reason: "logged-out" };
103
+ case "inconclusive":
104
+ return { kind: "inconclusive" };
105
+ }
106
+ },
107
+ verify(ctx, deps) {
108
+ return verify({ ...ctx, anthropicKey: ctx.upstreamKey }, deps);
109
+ },
110
+ text,
111
+ };
112
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/agents/claude-code/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type ConfigPaths } from "../../fs/safeFile.js";
2
+ import type { RevertOptions, RevertOutcome } from "../types.js";
3
+ type JsonObject = Record<string, unknown>;
4
+ /**
5
+ * The `x-agent-id` currently stored in the `\n`-joined header value. Returns
6
+ * undefined when the header, or the whole value, is absent or unparseable — an
7
+ * absent id can never satisfy the guard, which is the safe direction.
8
+ */
9
+ export declare function storedAgentId(env: JsonObject | undefined): string | undefined;
10
+ export declare function revertConfig(paths: ConfigPaths, options: RevertOptions): RevertOutcome;
11
+ export {};
@@ -11,7 +11,8 @@
11
11
  */
12
12
  import { copyFileSync, existsSync, lstatSync, readFileSync, readlinkSync, realpathSync } from "node:fs";
13
13
  import { dirname, resolve } from "node:path";
14
- import { MANAGED_KEYS, atomicWrite, describeFsError, isOurConfig, isPlainObject, serialize, } from "./config.js";
14
+ import { atomicWrite, describeFsError } from "../../fs/safeFile.js";
15
+ import { MANAGED_KEYS, isOurConfig, isPlainObject, serialize } from "./settings.js";
15
16
  /**
16
17
  * Resolve a symlinked settings.json to what it names, so a revert writes through
17
18
  * the link rather than replacing it — the same reason the writer does this.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revert.js","sourceRoot":"","sources":["../../../src/agents/claude-code/revert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { Target } from "../../args.js";
2
+ import { type ConfigPaths } from "../../fs/safeFile.js";
3
+ import type { ConfigOutcome, PathContext } from "../types.js";
4
+ /** The `env` keys this tool owns. Anything else in the file is not ours. */
5
+ export declare const MANAGED_KEYS: readonly ["ANTHROPIC_BASE_URL", "ANTHROPIC_CUSTOM_HEADERS", "ENABLE_TOOL_SEARCH"];
6
+ /**
7
+ * Whether this file is *ours*, judged by a marker rather than by key names. Key names
8
+ * cannot tell our `ENABLE_TOOL_SEARCH` from one the developer set, so a hand-added key
9
+ * would be deleted by the next `uninstall`. Only this tool writes an `x-ai21-key`.
10
+ */
11
+ export declare function isOurConfig(env: Record<string, unknown> | undefined): boolean;
12
+ /** Claude Code reads `settings.local.json` after ours, so its env wins. */
13
+ export declare function shadowingLocalConfig(paths: ConfigPaths): {
14
+ path: string;
15
+ agentId?: string;
16
+ } | undefined;
17
+ /**
18
+ * `--user` (the default) targets the home directory, `--repo` the project. A
19
+ * literal `~` is never expanded, so a directory named `~` is treated as one.
20
+ */
21
+ export declare function resolvePaths(target: Target, ctx: PathContext): ConfigPaths;
22
+ type JsonObject = Record<string, unknown>;
23
+ export declare function isPlainObject(value: unknown): value is JsonObject;
24
+ export declare function serialize(settings: JsonObject): string;
25
+ /**
26
+ * Merge `desiredEnv` into `paths.settings`. Returns what happened rather than
27
+ * throwing, so the caller owns reporting and the exit code. Nothing is written on
28
+ * the `conflict` or `malformed` outcomes.
29
+ */
30
+ export declare function writeConfig(paths: ConfigPaths, desiredEnv: Record<string, string>, options?: {
31
+ readonly force: boolean;
32
+ }): ConfigOutcome;
33
+ export {};
@@ -5,20 +5,14 @@
5
5
  * for us. Every path leaves it byte-identical or replaces it atomically with a
6
6
  * backup alongside, and no refusal path touches it at all.
7
7
  *
8
- * Helpers are exported for `revert.ts` and `snapshot.ts`, which uphold the same
8
+ * Helpers are exported for `revert.ts` and `fs/snapshot.ts`, which uphold the same
9
9
  * guarantees on the way back out — a second atomic write is a second chance to get it wrong.
10
10
  */
11
- import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, renameSync, rmSync, writeFileSync, } from "node:fs";
11
+ import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, } from "node:fs";
12
12
  import { dirname, join, resolve } from "node:path";
13
- import { DEFAULT_CLIENT } from "./args.js";
13
+ import { atomicWrite, backupPathFor, describeFsError } from "../../fs/safeFile.js";
14
14
  /** The `env` keys this tool owns. Anything else in the file is not ours. */
15
15
  export const MANAGED_KEYS = ["ANTHROPIC_BASE_URL", "ANTHROPIC_CUSTOM_HEADERS", "ENABLE_TOOL_SEARCH"];
16
- /* Where each client's config lives, relative to whichever root the target selects.
17
- * A second client needs more than a row here — MANAGED_KEYS and the snippet builders
18
- * are Claude Code's env shape — but this is the fork the rest of the code reads. */
19
- const CLIENT_CONFIG = {
20
- "claude-code": { dir: ".claude", file: "settings.json" },
21
- };
22
16
  /**
23
17
  * Whether this file is *ours*, judged by a marker rather than by key names. Key names
24
18
  * cannot tell our `ENABLE_TOOL_SEARCH` from one the developer set, so a hand-added key
@@ -50,61 +44,16 @@ export function shadowingLocalConfig(paths) {
50
44
  * `--user` (the default) targets the home directory, `--repo` the project. A
51
45
  * literal `~` is never expanded, so a directory named `~` is treated as one.
52
46
  */
53
- export function resolvePaths(target, ctx, client = DEFAULT_CLIENT) {
54
- const { dir, file } = CLIENT_CONFIG[client];
55
- const settings = join(target === "user" ? ctx.home : ctx.cwd, dir, file);
47
+ export function resolvePaths(target, ctx) {
48
+ const settings = join(target === "user" ? ctx.home : ctx.cwd, ".claude", "settings.json");
56
49
  return { settings, backup: `${settings}.bak` };
57
50
  }
58
- /**
59
- * Turns an fs error into something safe to print. The code is translated rather
60
- * than forwarded so no stack frame, errno struct or internal path escapes.
61
- */
62
- export function describeFsError(err) {
63
- const code = err?.code;
64
- switch (code) {
65
- case "EACCES":
66
- case "EPERM":
67
- return "permission denied";
68
- case "ENOSPC":
69
- return "no space left on the device";
70
- case "EROFS":
71
- return "the filesystem is read-only";
72
- case "EISDIR":
73
- return "it is a directory, not a file";
74
- default:
75
- return "the write could not be completed";
76
- }
77
- }
78
51
  export function isPlainObject(value) {
79
52
  return typeof value === "object" && value !== null && !Array.isArray(value);
80
53
  }
81
- /**
82
- * Write via a sibling temp file and rename. The rename is atomic within a
83
- * filesystem, so a reader either sees the old file or the new one — never a
84
- * half-written config. The temp file is removed on any failure so a crashed run
85
- * leaves no litter next to the real file.
86
- */
87
- export function atomicWrite(target, contents) {
88
- // Same directory, so the rename cannot cross a filesystem boundary. The pid
89
- // keeps two concurrent runs from fighting over one temp name.
90
- const tmp = `${target}.${process.pid}.tmp`;
91
- try {
92
- // 0600: this file carries an API key.
93
- writeFileSync(tmp, contents, { mode: 0o600 });
94
- renameSync(tmp, target);
95
- }
96
- catch (err) {
97
- rmSync(tmp, { force: true });
98
- throw err;
99
- }
100
- }
101
54
  export function serialize(settings) {
102
55
  return `${JSON.stringify(settings, null, 2)}\n`;
103
56
  }
104
- /** A symlinked settings.json is backed up beside its target, not beside the link. */
105
- export function backupPathFor(paths, realPath) {
106
- return realPath === paths.settings ? paths.backup : `${realPath}.bak`;
107
- }
108
57
  /**
109
58
  * Merge `desiredEnv` into `paths.settings`. Returns what happened rather than
110
59
  * throwing, so the caller owns reporting and the exit code. Nothing is written on
@@ -206,4 +155,4 @@ export function writeConfig(paths, desiredEnv, options = { force: false }) {
206
155
  }
207
156
  return { kind: "updated", path, backup: backupPath, changed };
208
157
  }
209
- //# sourceMappingURL=config.js.map
158
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/agents/claude-code/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EACT,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGnD,OAAO,EAAoB,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGrG,4EAA4E;AAC5E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,oBAAoB,EAAE,0BAA0B,EAAE,oBAAoB,CAAU,CAAC;AAE9G;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,GAAwC;IAClE,MAAM,OAAO,GAAG,GAAG,EAAE,wBAAwB,CAAC;IAE9C,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAClF,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,oBAAoB,CAAC,KAAkB;IACrD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAE9D,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,GAAG,GAAI,MAAmD,EAAE,GAAG,CAAC;IACtE,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,0BAA0B,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,oBAAoB,CAAC,CAAC;IACzC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAE9E,MAAM,OAAO,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,8BAA8B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE5G,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC9D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,GAAgB;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IAE1F,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,QAAQ,MAAM,EAAE,CAAC;AACjD,CAAC;AAID,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAoB;IAC5C,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,KAAkB,EAClB,UAAkC,EAClC,UAAuC,EAAE,KAAK,EAAE,KAAK,EAAE;IAEvD,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAEjC,6EAA6E;IAC7E,2EAA2E;IAC3E,uEAAuE;IACvE,IAAI,UAAU,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,IAAI,SAAS,CAAC,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC;YAC1E,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,UAAU,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,WAAW,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,uEAAuE;YACvE,0EAA0E;YAC1E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;QAChE,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,IAAI,QAAgB,CAAC;IACrB,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAC9B,2EAA2E;QAC3E,oEAAoE;QACpE,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;IAChE,CAAC;IAED,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAClD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,6EAA6E;QAC7E,4DAA4D;QAC5D,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACrE,CAAC;IAED,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAC;IACnF,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC;IAC/B,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7D,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,gCAAgC,EAAE,CAAC;IAC/E,CAAC;IAED,MAAM,UAAU,GAAe,WAAW,IAAI,EAAE,CAAC;IAEjD,MAAM,SAAS,GAAe,EAAE,CAAC;IACjC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACxD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,OAAO,KAAK,OAAO;YAAE,SAAS;QAElC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,6EAA6E;QAC7E,6BAA6B;QAC7B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7G,CAAC;IACH,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC3C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC/C,CAAC;IAED,4DAA4D;IAC5D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IACrC,CAAC;IAED,6EAA6E;IAC7E,2DAA2D;IAC3D,IAAI,CAAC;QACH;;;8EAGsE;QACtE,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7B,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YACnC,+EAA+E;YAC/E,gFAAgF;YAChF,iDAAiD;YACjD,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;QAED,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,EAAE,GAAG,UAAU,EAAE,GAAG,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC;IACzF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;IAChE,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AAChE,CAAC"}
@@ -15,26 +15,9 @@
15
15
  * signed-in user. The CLI is unauthenticated, so that line is absent entirely
16
16
  * unless `--user-id` supplies one — not blank, and no trailing newline.
17
17
  */
18
+ import type { SnippetInputs } from "../types.js";
18
19
  /** Stand-in for the caller's own Anthropic key, which the CLI never holds. */
19
20
  export declare const ANTHROPIC_KEY_PLACEHOLDER = "<your-anthropic-api-key>";
20
- /** Stand-in for the AI21 key in a preview, before one has been supplied. */
21
- export declare const AI21_KEY_PLACEHOLDER = "<your-ai21-api-key>";
22
- export interface SnippetInputs {
23
- readonly gatewayUrl: string;
24
- readonly agentId: string;
25
- readonly ai21Key: string;
26
- /** Signed-in user id for per-user attribution. Absent on a normal CLI run. */
27
- readonly userId?: string | undefined;
28
- /**
29
- * Marks the traffic as configured by this tool, e.g. `ai21-gateway-cli/0.4.0`.
30
- *
31
- * Set on what the CLI writes, and deliberately absent from the snippet builders the
32
- * contract test pins against the webapp: a config someone pasted by hand did not
33
- * come from here and must not claim to have. Lets the gateway tell the two apart
34
- * without the CLI reporting anything itself.
35
- */
36
- readonly client?: string | undefined;
37
- }
38
21
  /** Claude Code's `ANTHROPIC_CUSTOM_HEADERS` value. Header order is contractual. */
39
22
  export declare function ccCustomHeaders({ agentId, ai21Key, userId, client }: SnippetInputs): string;
40
23
  /**
@@ -1,24 +1,5 @@
1
- /**
2
- * Snippet builders duplicated from the gateway webapp, so what the CLI writes is
3
- * byte-identical to what the UI tells people to copy.
4
- *
5
- * Copied from AI21Labs/ai21-intelligent-gateway-webapp:
6
- * src/pages/docs/integrations.tsx — the builders
7
- * src/pages/docs/snippetContext.tsx — the placeholder constants
8
- *
9
- * A webapp edit cannot fail our CI, so this drifts silently — re-copy when the
10
- * gateway's snippets change. `test/fixtures/webapp-snippets.json` is what catches
11
- * a divergence. Only the Claude Code path is mirrored; the LangChain snippets are
12
- * now a four-way client matrix whose port is a design question, not a copy job.
13
- *
14
- * One deliberate divergence: the webapp always emits `x-ai21-user-id`, having a
15
- * signed-in user. The CLI is unauthenticated, so that line is absent entirely
16
- * unless `--user-id` supplies one — not blank, and no trailing newline.
17
- */
18
1
  /** Stand-in for the caller's own Anthropic key, which the CLI never holds. */
19
2
  export const ANTHROPIC_KEY_PLACEHOLDER = "<your-anthropic-api-key>";
20
- /** Stand-in for the AI21 key in a preview, before one has been supplied. */
21
- export const AI21_KEY_PLACEHOLDER = "<your-ai21-api-key>";
22
3
  /** Drops the lines that only exist when a user id was supplied. */
23
4
  function joinLines(lines) {
24
5
  return lines.filter((line) => line !== undefined).join("\n");
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snippets.js","sourceRoot":"","sources":["../../../src/agents/claude-code/snippets.ts"],"names":[],"mappings":"AAmBA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,yBAAyB,GAAG,0BAA0B,CAAC;AAEpE,mEAAmE;AACnE,SAAS,SAAS,CAAC,KAAsC;IACvD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/E,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAiB;IACjF,OAAO,SAAS,CAAC;QACf,eAAe,OAAO,EAAE;QACxB,eAAe,OAAO,EAAE;QACxB,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,mBAAmB,MAAM,EAAE;QAC9D,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,MAAM,EAAE;KAC9D,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,OAAO;QACL,kBAAkB,EAAE,MAAM,CAAC,UAAU;QACrC,wBAAwB,EAAE,eAAe,CAAC,MAAM,CAAC;QACjD,gFAAgF;QAChF,kFAAkF;QAClF,iFAAiF;QACjF,kBAAkB,EAAE,MAAM;KAC3B,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,UAAU,CAAC,MAAqB;IAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAiB;IACjF,OAAO,SAAS,CAAC;QACf,QAAQ,UAAU,iBAAiB;QACnC,qBAAqB,OAAO,MAAM;QAClC,oBAAoB,yBAAyB,MAAM;QACnD,yCAAyC;QACzC,qBAAqB,OAAO,MAAM;QAClC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,yBAAyB,MAAM,MAAM;QACxE,0CAA0C;QAC1C,wDAAwD;QACxD,iFAAiF;KAClF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { AgentDeps } from "../types.js";
2
+ /** `claude auth status` is local and answers in about a second. */
3
+ export declare const AUTH_STATUS_TIMEOUT_MS = 5000;
4
+ export type ClaudeLogin = "logged-in" | "logged-out" | "inconclusive";
5
+ /**
6
+ * Asks `claude auth status`, which reads local state only, whether Claude Code has any
7
+ * credential — so a missing one is caught before anything is written. Only an explicit
8
+ * `"loggedIn": false` with no auth method counts as logged out, and only for Anthropic's
9
+ * own API: an older `claude` without the subcommand, unparseable output, or a Bedrock or
10
+ * Vertex setup are all inconclusive and leave the decision to verification.
11
+ */
12
+ export declare function checkClaudeLogin(cwd: string, deps: AgentDeps): Promise<ClaudeLogin>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Whether Claude Code has a login the gateway can forward, asked before anything is
3
+ * written so a missing one never leaves a config behind.
4
+ */
5
+ import { findOnPath } from "../../process.js";
6
+ import { CLAUDE_COMMAND } from "./verify.js";
7
+ /** `claude auth status` is local and answers in about a second. */
8
+ export const AUTH_STATUS_TIMEOUT_MS = 5_000;
9
+ /**
10
+ * Asks `claude auth status`, which reads local state only, whether Claude Code has any
11
+ * credential — so a missing one is caught before anything is written. Only an explicit
12
+ * `"loggedIn": false` with no auth method counts as logged out, and only for Anthropic's
13
+ * own API: an older `claude` without the subcommand, unparseable output, or a Bedrock or
14
+ * Vertex setup are all inconclusive and leave the decision to verification.
15
+ */
16
+ export async function checkClaudeLogin(cwd, deps) {
17
+ const executable = findOnPath(CLAUDE_COMMAND, deps.lookup);
18
+ if (executable === undefined)
19
+ return "inconclusive";
20
+ const result = await deps.runCommand(executable, ["auth", "status"], { cwd, timeoutMs: AUTH_STATUS_TIMEOUT_MS });
21
+ if (result.timedOut || result.code === null)
22
+ return "inconclusive";
23
+ const start = result.output.indexOf("{");
24
+ const end = result.output.lastIndexOf("}");
25
+ if (start === -1 || end < start)
26
+ return "inconclusive";
27
+ let status;
28
+ try {
29
+ status = JSON.parse(result.output.slice(start, end + 1));
30
+ }
31
+ catch {
32
+ return "inconclusive";
33
+ }
34
+ if (typeof status !== "object" || status === null)
35
+ return "inconclusive";
36
+ const { loggedIn, authMethod, apiProvider } = status;
37
+ if (loggedIn === true)
38
+ return "logged-in";
39
+ const firstParty = apiProvider === undefined || apiProvider === "firstParty";
40
+ return loggedIn === false && authMethod === "none" && firstParty ? "logged-out" : "inconclusive";
41
+ }
42
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/agents/claude-code/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,mEAAmE;AACnE,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAI5C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,IAAe;IACjE,MAAM,UAAU,GAAG,UAAU,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3D,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,cAAc,CAAC;IAEpD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,sBAAsB,EAAE,CAAC,CAAC;IACjH,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,cAAc,CAAC;IAEnE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK;QAAE,OAAO,cAAc,CAAC;IAEvD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,cAAc,CAAC;IAEzE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,MAI7C,CAAC;IACF,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,WAAW,CAAC;IAE1C,MAAM,UAAU,GAAG,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,YAAY,CAAC;IAE7E,OAAO,QAAQ,KAAK,KAAK,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC;AACnG,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { AgentDeps, VerifyContext as AgentVerifyContext, VerifyOutcome } from "../types.js";
2
+ export declare const CLAUDE_COMMAND = "claude";
3
+ export declare const CLAUDE_PROMPT = "ai21-gateway CLI connectivity check \u2014 reply with OK and nothing else.";
4
+ export declare const PING_PATH = "/v1/messages";
5
+ /**
6
+ * Both tiers are bounded; the spawn gets longer because it waits on a full model
7
+ * round trip. 20s is measured, not guessed: a working `claude -p` returns in ~5s,
8
+ * and a rejected one hangs rather than failing, so this budget is what turns that
9
+ * hang into a message.
10
+ */
11
+ export declare const PING_TIMEOUT_MS = 10000;
12
+ export declare const CLAUDE_TIMEOUT_MS = 20000;
13
+ /** Mirrors the `genericCurl` snippet; a contract test holds the two together. */
14
+ export declare const PING_BODY: {
15
+ readonly model: "claude-sonnet-4-5";
16
+ readonly max_tokens: 64;
17
+ readonly messages: readonly [{
18
+ readonly role: "user";
19
+ readonly content: "Hello through the gateway";
20
+ }];
21
+ };
22
+ /**
23
+ * `via` is `claude-cli` or `direct-ping`. A `no-subscription` reason is `logged-out`
24
+ * (`claude` has no login at all) or `key-rejected` (Anthropic itself refused the key
25
+ * the direct ping sent).
26
+ */
27
+ /** Claude Code's verification also takes `--anthropic-key`, for the direct-ping tier. */
28
+ export interface VerifyContext extends AgentVerifyContext {
29
+ /** `--anthropic-key`, which outranks the environment. */
30
+ readonly anthropicKey?: string | undefined;
31
+ }
32
+ /** What the direct ping would send: `--anthropic-key`, else a non-empty ANTHROPIC_API_KEY. */
33
+ export declare function resolveAnthropicKey(ctx: Pick<VerifyContext, "anthropicKey" | "processEnv">): string | undefined;
34
+ /**
35
+ * Which side rejected us, without needing an Anthropic key: a deliberately invalid
36
+ * `x-api-key` cannot succeed, so whichever layer answers is the answer.
37
+ */
38
+ export type CredentialVerdict = "ai21-rejected" | "ai21-accepted" | "inconclusive";
39
+ export declare function verify(ctx: VerifyContext, deps: AgentDeps): Promise<VerifyOutcome>;