@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
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Codex: a provider block in `~/.codex/config.toml`, checked with `codex login status`,
3
+ * verified with `codex exec`. User-level only: Codex ignores `model_provider` and
4
+ * `model_providers` in a project's `.codex/config.toml`.
5
+ */
6
+ import { findOnPath } from "../../process.js";
7
+ import { codexHome, resolveCodexPaths, revertCodexConfig, writeCodexConfig } from "./config.js";
8
+ import { codexPlacementExample, codexTables, ROOT_LINE } from "./snippets.js";
9
+ import { CODEX_COMMAND, checkCodexLogin } from "./status.js";
10
+ import { verifyCodex } from "./verify.js";
11
+ const text = {
12
+ noSubscriptionOutcome: "no-codex-login",
13
+ noSubscription: {
14
+ "logged-out": {
15
+ headline: "No ChatGPT login detected for Codex.",
16
+ nextStep: "Run `codex login` and sign in with ChatGPT, then re-run this command.",
17
+ jsonReason: "no_chatgpt_login",
18
+ telemetryReason: "agent not logged in",
19
+ },
20
+ "api-key-login": {
21
+ headline: "Codex is signed in with an API key, not a ChatGPT login.",
22
+ nextStep: "The gateway forwards your ChatGPT login. Run `codex logout`, then `codex login` with ChatGPT, then re-run this command.",
23
+ jsonReason: "chatgpt_login_required",
24
+ telemetryReason: "agent logged in with an api key",
25
+ },
26
+ },
27
+ verifiedVia: { "codex-exec": "`codex exec`" },
28
+ skippedBecause: "the Codex CLI was not found to verify with",
29
+ notInstalled: {
30
+ message: "The Codex CLI was not found. Install it, sign in with `codex login`, then re-run this command.",
31
+ jsonOutcome: "no-codex-cli",
32
+ jsonReason: "codex_cli_not_installed",
33
+ telemetryReason: "agent cli not installed",
34
+ },
35
+ checkingLogin: "Checking your Codex login…",
36
+ loginFound: "Codex login found",
37
+ };
38
+ export const codex = {
39
+ id: "codex",
40
+ kind: "codex",
41
+ displayName: "Codex",
42
+ configLabel: "config.toml",
43
+ targets: ["user"],
44
+ verifyFlags: [],
45
+ checkInstalled(_ctx, deps) {
46
+ // No stand-in: only the Codex CLI can send the ChatGPT login the gateway forwards.
47
+ return findOnPath(CODEX_COMMAND, deps.lookup) === undefined ? { kind: "missing" } : { kind: "present" };
48
+ },
49
+ resolvePaths(_target, env) {
50
+ return { ...resolveCodexPaths(codexHome(env)), verifyCwd: env.home };
51
+ },
52
+ preview(inputs) {
53
+ return {
54
+ text: codexPlacementExample(inputs),
55
+ json: { config: [ROOT_LINE, "", ...codexTables(inputs)].join("\n") },
56
+ };
57
+ },
58
+ write: writeCodexConfig,
59
+ revert: revertCodexConfig,
60
+ // The writer already masks the key in each conflict (see `want` in config.ts); a
61
+ // conflict value here is one key's value, with no header syntax left to match on.
62
+ redact: (value) => value,
63
+ warnings(_paths, processEnv) {
64
+ const found = [];
65
+ if (processEnv.OPENAI_BASE_URL !== undefined && processEnv.OPENAI_BASE_URL !== "") {
66
+ found.push({
67
+ code: "openai-base-url-set",
68
+ message: "OPENAI_BASE_URL is set in your environment. Codex has deprecated it, and it can send requests past the gateway — unset it if they do not show up.",
69
+ });
70
+ }
71
+ return found;
72
+ },
73
+ checkSubscription(paths, deps) {
74
+ return checkCodexLogin(paths.verifyCwd, deps);
75
+ },
76
+ verify: verifyCodex,
77
+ text,
78
+ };
79
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/agents/codex/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * What `install --client codex` writes into `~/.codex/config.toml`, built to match the
3
+ * webapp snippet byte for byte (AI21Labs/ai21-intelligent-gateway-webapp,
4
+ * `src/pages/docs/integrations.tsx:codexPlacementExample`). `test/fixtures` pins the
5
+ * two together; re-capture it when the webapp's snippet changes.
6
+ *
7
+ * Two parts, because they go to different places: the root `model_provider` line must
8
+ * sit above every `[table]` (TOML would otherwise read it as a key of the table before
9
+ * it), while the provider tables can go anywhere.
10
+ *
11
+ * One deliberate divergence, as for Claude Code: the webapp always emits
12
+ * `x-ai21-user-id`, having a signed-in user; here that line is absent unless
13
+ * `--user-id` supplies one. `x-ai21-client` is added on what the CLI writes only.
14
+ */
15
+ import { type SnippetInputs } from "../types.js";
16
+ /** The root key that selects our provider. */
17
+ export declare const ROOT_LINE: string;
18
+ /** The header lines in contract order, as `[key, value]`. */
19
+ export declare function codexHeaders({ agentId, ai21Key, userId, client }: SnippetInputs): [string, string][];
20
+ /** The two provider tables, as lines. */
21
+ export declare function codexTables(inputs: SnippetInputs): string[];
22
+ /** The webapp's paste-in example, comments included. Also what `--print` shows. */
23
+ export declare function codexPlacementExample(inputs: SnippetInputs): string;
@@ -0,0 +1,39 @@
1
+ import { HEADERS_TABLE, PROVIDER_ID, PROVIDER_TABLE, tomlKey, tomlString } from "./toml.js";
2
+ /** The root key that selects our provider. */
3
+ export const ROOT_LINE = `model_provider = ${tomlString(PROVIDER_ID)}`;
4
+ /** The header lines in contract order, as `[key, value]`. */
5
+ export function codexHeaders({ agentId, ai21Key, userId, client }) {
6
+ const headers = [
7
+ ["x-upstream", "openai-codex"],
8
+ ["x-ai21-key", ai21Key],
9
+ ["x-agent-id", agentId],
10
+ ];
11
+ if (userId !== undefined)
12
+ headers.push(["x-ai21-user-id", userId]);
13
+ if (client !== undefined)
14
+ headers.push(["x-ai21-client", client]);
15
+ return headers;
16
+ }
17
+ /** The two provider tables, as lines. */
18
+ export function codexTables(inputs) {
19
+ return [
20
+ `[${PROVIDER_TABLE}]`,
21
+ `name = ${tomlString("AI21 Gateway")}`,
22
+ `base_url = ${tomlString(`${inputs.gatewayUrl}/v1`)}`,
23
+ `wire_api = "responses"`,
24
+ `requires_openai_auth = true`,
25
+ `[${HEADERS_TABLE}]`,
26
+ ...codexHeaders(inputs).map(([key, value]) => `${tomlKey(key)} = ${tomlString(value)}`),
27
+ ];
28
+ }
29
+ /** The webapp's paste-in example, comments included. Also what `--print` shows. */
30
+ export function codexPlacementExample(inputs) {
31
+ return [
32
+ "# Adds to your existing ~/.codex/config.toml — nothing else changes.",
33
+ "# Keep model_provider above every [section]: it is a root key.",
34
+ ROOT_LINE,
35
+ "",
36
+ ...codexTables(inputs),
37
+ ].join("\n");
38
+ }
39
+ //# sourceMappingURL=snippets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snippets.js","sourceRoot":"","sources":["../../../src/agents/codex/snippets.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5F,8CAA8C;AAC9C,MAAM,CAAC,MAAM,SAAS,GAAG,oBAAoB,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;AAEvE,6DAA6D;AAC7D,MAAM,UAAU,YAAY,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAiB;IAC9E,MAAM,OAAO,GAAuB;QAClC,CAAC,YAAY,EAAE,cAAc,CAAC;QAC9B,CAAC,YAAY,EAAE,OAAO,CAAC;QACvB,CAAC,YAAY,EAAE,OAAO,CAAC;KACxB,CAAC;IACF,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;IAEnE,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;IAElE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,WAAW,CAAC,MAAqB;IAC/C,OAAO;QACL,IAAI,cAAc,GAAG;QACrB,UAAU,UAAU,CAAC,cAAc,CAAC,EAAE;QACtC,cAAc,UAAU,CAAC,GAAG,MAAM,CAAC,UAAU,KAAK,CAAC,EAAE;QACrD,wBAAwB;QACxB,6BAA6B;QAC7B,IAAI,aAAa,GAAG;QACpB,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;KACxF,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,qBAAqB,CAAC,MAAqB;IACzD,OAAO;QACL,sEAAsE;QACtE,gEAAgE;QAChE,SAAS;QACT,EAAE;QACF,GAAG,WAAW,CAAC,MAAM,CAAC;KACvB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { AgentDeps, SubscriptionStatus } from "../types.js";
2
+ export declare const CODEX_COMMAND = "codex";
3
+ /**
4
+ * Runs `codex login status` and reads stderr. Only "Logged in using ChatGPT" counts
5
+ * as present; "Logged in using an API key" or "Not logged in" count as missing.
6
+ * An unrecognisable output, a missing binary or a timeout are all inconclusive.
7
+ */
8
+ export declare function checkCodexLogin(cwd: string, deps: AgentDeps): Promise<SubscriptionStatus>;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Codex login check with `codex login status`.
3
+ */
4
+ import { findOnPath } from "../../process.js";
5
+ export const CODEX_COMMAND = "codex";
6
+ const STATUS_TIMEOUT_MS = 5_000;
7
+ /**
8
+ * Runs `codex login status` and reads stderr. Only "Logged in using ChatGPT" counts
9
+ * as present; "Logged in using an API key" or "Not logged in" count as missing.
10
+ * An unrecognisable output, a missing binary or a timeout are all inconclusive.
11
+ */
12
+ export async function checkCodexLogin(cwd, deps) {
13
+ const executable = findOnPath(CODEX_COMMAND, deps.lookup);
14
+ if (executable === undefined)
15
+ return { kind: "inconclusive" };
16
+ const result = await deps.runCommand(executable, ["login", "status"], { cwd, timeoutMs: STATUS_TIMEOUT_MS });
17
+ if (result.timedOut || result.code === null)
18
+ return { kind: "inconclusive" };
19
+ // A broken config or missing CODEX_HOME makes the CLI exit 1 and print an error.
20
+ // That is not "definitely signed out"; it is "could not tell".
21
+ if (result.code === 1 && !/^(Not logged in|Logged in using an API key)/.test(result.output.trim())) {
22
+ return { kind: "inconclusive" };
23
+ }
24
+ if (result.code === 0 && /^Logged in using ChatGPT/.test(result.output.trim())) {
25
+ return { kind: "present" };
26
+ }
27
+ // "Logged in using an API key" without ChatGPT → not usable through the gateway.
28
+ if (result.code === 0 && /^Logged in using an API key/.test(result.output.trim())) {
29
+ return { kind: "missing", reason: "api-key-login" };
30
+ }
31
+ if (result.output.trim() === "Not logged in") {
32
+ return { kind: "missing", reason: "logged-out" };
33
+ }
34
+ return { kind: "inconclusive" };
35
+ }
36
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/agents/codex/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC;AAErC,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAEhC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,IAAe;IAChE,MAAM,UAAU,GAAG,UAAU,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1D,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAE9D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC7G,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAE7E,iFAAiF;IACjF,+DAA+D;IAC/D,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,6CAA6C,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACnG,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAClC,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QAC/E,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,iFAAiF;IACjF,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,6BAA6B,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QAClF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACtD,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,eAAe,EAAE,CAAC;QAC7C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IACnD,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * A targeted edit of `~/.codex/config.toml`: find the few things this tool owns, and
3
+ * replace or remove exactly those lines. Everything else — comments, ordering, blank
4
+ * lines, CRLF endings, tables we have never heard of — is carried through byte for byte.
5
+ *
6
+ * Not a TOML parser. It reads lines, and understands only what it must to stay safe:
7
+ * where a table starts, which root key a line assigns, and whether a line is inside a
8
+ * multi-line string (where a `[` is text, not a header). Anything it owns but cannot
9
+ * edit safely — our provider as dotted keys or an inline table — is reported as
10
+ * `unsupported`, and the caller refuses rather than guess.
11
+ */
12
+ /** The provider id this tool writes. The webapp snippet uses the same one. */
13
+ export declare const PROVIDER_ID = "ai21";
14
+ /** The tables we own, in the order we write them. */
15
+ export declare const PROVIDER_TABLE = "model_providers.ai21";
16
+ export declare const HEADERS_TABLE = "model_providers.ai21.http_headers";
17
+ export interface Line {
18
+ /** Without its line ending. */
19
+ readonly text: string;
20
+ /** "\n", "\r\n", or "" for a last line with no newline. */
21
+ readonly eol: string;
22
+ }
23
+ export declare function splitLines(raw: string): Line[];
24
+ export declare function joinLines(lines: readonly Line[]): string;
25
+ /** The file's own newline, so lines we add match the ones around them. */
26
+ export declare function newlineOf(lines: readonly Line[]): string;
27
+ export interface Region {
28
+ /** Index of the header line. */
29
+ readonly start: number;
30
+ /** One past the last line that belongs to the table (its header and its keys). */
31
+ readonly end: number;
32
+ }
33
+ export interface Scan {
34
+ readonly lines: Line[];
35
+ /** The root `model_provider = …` line, if any. */
36
+ readonly rootModelProvider?: number | undefined;
37
+ /** Index of the first table header; root keys live before it. */
38
+ readonly firstHeader: number;
39
+ readonly provider?: Region | undefined;
40
+ readonly headers?: Region | undefined;
41
+ /** Why we refuse to edit, when our provider is present in a form we do not handle. */
42
+ readonly unsupported?: string | undefined;
43
+ }
44
+ export declare function scan(raw: string): Scan;
45
+ /** A basic-string value's contents, or undefined when the line holds anything else. */
46
+ export declare function stringValue(text: string): string | undefined;
47
+ /** The `key = value` lines of a region, keyed by their normalised key. */
48
+ export declare function entries(scanned: Scan, region: Region | undefined): Map<string, string>;
49
+ /** Escapes a value for a TOML basic string. Control characters never reach here: args refuses them. */
50
+ export declare function tomlString(value: string): string;
51
+ /**
52
+ * Header keys need quoting in TOML only if they are not bare keys. Ours are all bare
53
+ * (`x-ai21-key`), but the rule is written down once rather than assumed at each site.
54
+ */
55
+ export declare function tomlKey(key: string): string;
56
+ /** Drops the lines at `[start, end)` and any blank lines left directly above them. */
57
+ export declare function removeRange(lines: Line[], start: number, end: number): Line[];
@@ -0,0 +1,196 @@
1
+ /**
2
+ * A targeted edit of `~/.codex/config.toml`: find the few things this tool owns, and
3
+ * replace or remove exactly those lines. Everything else — comments, ordering, blank
4
+ * lines, CRLF endings, tables we have never heard of — is carried through byte for byte.
5
+ *
6
+ * Not a TOML parser. It reads lines, and understands only what it must to stay safe:
7
+ * where a table starts, which root key a line assigns, and whether a line is inside a
8
+ * multi-line string (where a `[` is text, not a header). Anything it owns but cannot
9
+ * edit safely — our provider as dotted keys or an inline table — is reported as
10
+ * `unsupported`, and the caller refuses rather than guess.
11
+ */
12
+ /** The provider id this tool writes. The webapp snippet uses the same one. */
13
+ export const PROVIDER_ID = "ai21";
14
+ /** The tables we own, in the order we write them. */
15
+ export const PROVIDER_TABLE = `model_providers.${PROVIDER_ID}`;
16
+ export const HEADERS_TABLE = `model_providers.${PROVIDER_ID}.http_headers`;
17
+ export function splitLines(raw) {
18
+ const lines = [];
19
+ const pattern = /([^\r\n]*)(\r\n|\n|$)/g;
20
+ let match;
21
+ while ((match = pattern.exec(raw)) !== null) {
22
+ const [, text = "", eol = ""] = match;
23
+ if (text === "" && eol === "")
24
+ break;
25
+ lines.push({ text, eol });
26
+ }
27
+ return lines;
28
+ }
29
+ export function joinLines(lines) {
30
+ return lines.map((line) => line.text + line.eol).join("");
31
+ }
32
+ /** The file's own newline, so lines we add match the ones around them. */
33
+ export function newlineOf(lines) {
34
+ return lines.find((line) => line.eol !== "")?.eol ?? "\n";
35
+ }
36
+ /** A table header's dotted name with quoting and spaces normalised: `[ a . "b" ]` → `a.b`. */
37
+ function headerName(text) {
38
+ const match = /^\s*\[\s*([^[\]]+?)\s*\]\s*(#.*)?$/.exec(text);
39
+ if (match === null)
40
+ return undefined;
41
+ return match[1]
42
+ .split(".")
43
+ .map((part) => part
44
+ .trim()
45
+ .replace(/^"(.*)"$/, "$1")
46
+ .replace(/^'(.*)'$/, "$1"))
47
+ .join(".");
48
+ }
49
+ /** `[[array.of.tables]]` headers also end the table before them. */
50
+ function isArrayHeader(text) {
51
+ return /^\s*\[\[/.test(text);
52
+ }
53
+ /** The key a `key = value` line assigns, normalised like a header name. */
54
+ function assignedKey(text) {
55
+ const match = /^\s*((?:"[^"]*"|'[^']*'|[A-Za-z0-9_-]+)(?:\s*\.\s*(?:"[^"]*"|'[^']*'|[A-Za-z0-9_-]+))*)\s*=/.exec(text);
56
+ if (match === null)
57
+ return undefined;
58
+ return match[1]
59
+ .split(/\s*\.\s*/)
60
+ .map((part) => part.replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1"))
61
+ .join(".");
62
+ }
63
+ /**
64
+ * Tracks whether a line leaves us inside a multi-line string, so a `[` or `key =` in
65
+ * the middle of one is not mistaken for structure.
66
+ */
67
+ function multilineStateAfter(text, open) {
68
+ let state = open;
69
+ let rest = text;
70
+ for (;;) {
71
+ if (state !== undefined) {
72
+ const close = rest.indexOf(state);
73
+ if (close === -1)
74
+ return state;
75
+ rest = rest.slice(close + 3);
76
+ state = undefined;
77
+ continue;
78
+ }
79
+ const basic = rest.indexOf('"""');
80
+ const literal = rest.indexOf("'''");
81
+ const hash = rest.indexOf("#");
82
+ const candidates = [basic, literal].filter((index) => index !== -1);
83
+ if (candidates.length === 0)
84
+ return undefined;
85
+ const first = Math.min(...candidates);
86
+ if (hash !== -1 && hash < first)
87
+ return undefined;
88
+ state = first === basic ? '"""' : "'''";
89
+ rest = rest.slice(first + 3);
90
+ }
91
+ }
92
+ export function scan(raw) {
93
+ const lines = splitLines(raw);
94
+ let table; // undefined = root
95
+ let multiline;
96
+ let rootModelProvider;
97
+ let firstHeader = lines.length;
98
+ let unsupported;
99
+ const regions = {};
100
+ let current;
101
+ const close = (at) => {
102
+ if (current !== undefined && (current.name === PROVIDER_TABLE || current.name === HEADERS_TABLE)) {
103
+ regions[current.name] = { start: current.start, end: at };
104
+ }
105
+ current = undefined;
106
+ };
107
+ lines.forEach((line, index) => {
108
+ const inString = multiline !== undefined;
109
+ multiline = multilineStateAfter(line.text, multiline);
110
+ if (inString)
111
+ return;
112
+ const name = isArrayHeader(line.text) ? "[[array]]" : headerName(line.text);
113
+ if (name !== undefined) {
114
+ close(index);
115
+ if (firstHeader === lines.length)
116
+ firstHeader = index;
117
+ table = name;
118
+ if (name === PROVIDER_TABLE || name === HEADERS_TABLE) {
119
+ if (regions[name] !== undefined)
120
+ unsupported = `it defines [${name}] twice`;
121
+ current = { name, start: index };
122
+ }
123
+ else if (name.startsWith(`${PROVIDER_TABLE}.`)) {
124
+ unsupported = `it has a [${name}] table this tool does not manage`;
125
+ }
126
+ return;
127
+ }
128
+ const key = assignedKey(line.text);
129
+ if (key === undefined)
130
+ return;
131
+ // A dotted or inline form of our provider, from any table that could reach it. A
132
+ // child table of ours (`[model_providers.ai21.x]`) was already refused at its header.
133
+ const full = table === undefined ? key : `${table}.${key}`;
134
+ const inOurs = table === PROVIDER_TABLE || table === HEADERS_TABLE || table?.startsWith(`${PROVIDER_TABLE}.`);
135
+ if ((full === PROVIDER_TABLE || full.startsWith(`${PROVIDER_TABLE}.`)) && inOurs !== true) {
136
+ unsupported = `it sets ${full} outside a [${PROVIDER_TABLE}] table`;
137
+ }
138
+ if (table === PROVIDER_TABLE && key.startsWith("http_headers")) {
139
+ unsupported = `it sets ${PROVIDER_TABLE}.${key} as a dotted key`;
140
+ }
141
+ if (table === undefined && key === "model_provider")
142
+ rootModelProvider = index;
143
+ });
144
+ close(lines.length);
145
+ return {
146
+ lines,
147
+ rootModelProvider,
148
+ firstHeader,
149
+ provider: regions[PROVIDER_TABLE],
150
+ headers: regions[HEADERS_TABLE],
151
+ unsupported,
152
+ };
153
+ }
154
+ /** A basic-string value's contents, or undefined when the line holds anything else. */
155
+ export function stringValue(text) {
156
+ const match = /=\s*"((?:[^"\\]|\\.)*)"\s*(#.*)?$/.exec(text);
157
+ if (match === null)
158
+ return undefined;
159
+ return match[1].replace(/\\(["\\nt])/g, (_, c) => (c === "n" ? "\n" : c === "t" ? "\t" : c));
160
+ }
161
+ /** The `key = value` lines of a region, keyed by their normalised key. */
162
+ export function entries(scanned, region) {
163
+ const found = new Map();
164
+ if (region === undefined)
165
+ return found;
166
+ for (let index = region.start + 1; index < region.end; index += 1) {
167
+ const text = scanned.lines[index].text;
168
+ const key = assignedKey(text);
169
+ if (key === undefined)
170
+ continue;
171
+ found.set(key, text.slice(text.indexOf("=") + 1).trim());
172
+ }
173
+ return found;
174
+ }
175
+ /** Escapes a value for a TOML basic string. Control characters never reach here: args refuses them. */
176
+ export function tomlString(value) {
177
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
178
+ }
179
+ /**
180
+ * Header keys need quoting in TOML only if they are not bare keys. Ours are all bare
181
+ * (`x-ai21-key`), but the rule is written down once rather than assumed at each site.
182
+ */
183
+ export function tomlKey(key) {
184
+ return /^[A-Za-z0-9_-]+$/.test(key) ? key : tomlString(key);
185
+ }
186
+ /** Drops the lines at `[start, end)` and any blank lines left directly above them. */
187
+ export function removeRange(lines, start, end) {
188
+ let from = start;
189
+ while (from > 0 && lines[from - 1].text.trim() === "")
190
+ from -= 1;
191
+ // Keep one blank line between what remains above and below, if both exist.
192
+ const keepBlank = from > 0 && end < lines.length && from < start;
193
+ const result = [...lines.slice(0, from), ...(keepBlank ? [lines[from]] : []), ...lines.slice(end)];
194
+ return result;
195
+ }
196
+ //# sourceMappingURL=toml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toml.js","sourceRoot":"","sources":["../../../src/agents/codex/toml.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { AgentDeps, VerifyContext, VerifyOutcome } from "../types.js";
2
+ export declare function verifyCodex(ctx: VerifyContext, deps: AgentDeps): Promise<VerifyOutcome>;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Verification for Codex: `codex exec --skip-git-repo-check --ephemeral --sandbox read-only`
3
+ * with retries disabled on the command line. No direct-ping tier: only the Codex CLI can
4
+ * send the ChatGPT credential, and there is no way to make a stand-alone request.
5
+ */
6
+ import { findOnPath } from "../../process.js";
7
+ import { CODEX_COMMAND } from "./status.js";
8
+ const VERIFY_TIMEOUT_MS = 30_000;
9
+ const PROMPT = "ai21-gateway CLI connectivity check — reply with OK and nothing else.";
10
+ /** `codex exec` with retries off so a bad call fails fast. */
11
+ const EXEC_ARGS = [
12
+ "exec",
13
+ "--skip-git-repo-check",
14
+ "--ephemeral",
15
+ "--sandbox",
16
+ "read-only",
17
+ "-c",
18
+ "model_providers.ai21.request_max_retries=0",
19
+ "-c",
20
+ "model_providers.ai21.stream_max_retries=0",
21
+ PROMPT,
22
+ ];
23
+ function manualHint(cwd) {
24
+ return `Run \`${CODEX_COMMAND} exec --skip-git-repo-check --ephemeral "${PROMPT}"\` in ${cwd} to verify by hand`;
25
+ }
26
+ export async function verifyCodex(ctx, deps) {
27
+ const executable = findOnPath(CODEX_COMMAND, deps.lookup);
28
+ if (executable === undefined) {
29
+ return { kind: "skipped", hint: `${manualHint(ctx.cwd)}.` };
30
+ }
31
+ const result = await deps.runCommand(executable, EXEC_ARGS, { cwd: ctx.cwd, timeoutMs: VERIFY_TIMEOUT_MS });
32
+ if (result.timedOut) {
33
+ return {
34
+ kind: "failed",
35
+ via: "codex-exec",
36
+ reason: `\`${CODEX_COMMAND} exec\` did not answer within ${VERIFY_TIMEOUT_MS / 1_000}s`,
37
+ };
38
+ }
39
+ if (result.code === 0)
40
+ return { kind: "passed", via: "codex-exec" };
41
+ return { kind: "failed", via: "codex-exec", reason: `\`${CODEX_COMMAND} exec\` exited ${result.code}` };
42
+ }
43
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/agents/codex/verify.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEjC,MAAM,MAAM,GAAG,uEAAuE,CAAC;AAEvF,8DAA8D;AAC9D,MAAM,SAAS,GAAG;IAChB,MAAM;IACN,uBAAuB;IACvB,aAAa;IACb,WAAW;IACX,WAAW;IACX,IAAI;IACJ,4CAA4C;IAC5C,IAAI;IACJ,2CAA2C;IAC3C,MAAM;CACP,CAAC;AAEF,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,SAAS,aAAa,4CAA4C,MAAM,UAAU,GAAG,oBAAoB,CAAC;AACnH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAkB,EAAE,IAAe;IACnE,MAAM,UAAU,GAAG,UAAU,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1D,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IAC9D,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAE5G,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,GAAG,EAAE,YAAY;YACjB,MAAM,EAAE,KAAK,aAAa,iCAAiC,iBAAiB,GAAG,KAAK,GAAG;SACxF,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC;IAEpE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,aAAa,kBAAkB,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;AAC1G,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AgentDeps } from "./types.js";
2
+ /** The real-world adapters, kept here so `cli.ts` stays a thin edge. */
3
+ export declare function nodeAgentDeps(processEnv: Record<string, string | undefined>): AgentDeps;
@@ -0,0 +1,10 @@
1
+ import { isExecutableFile, runCommand } from "../process.js";
2
+ /** The real-world adapters, kept here so `cli.ts` stays a thin edge. */
3
+ export function nodeAgentDeps(processEnv) {
4
+ return {
5
+ lookup: { platform: process.platform, processEnv, isExecutableFile },
6
+ runCommand,
7
+ fetchImpl: fetch,
8
+ };
9
+ }
10
+ //# sourceMappingURL=deps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/agents/deps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG7D,wEAAwE;AACxE,MAAM,UAAU,aAAa,CAAC,UAA8C;IAC1E,OAAO;QACL,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE;QACpE,UAAU;QACV,SAAS,EAAE,KAA6B;KACzC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Every coding agent the CLI can configure, keyed by its `--client` value. Typed as a
3
+ * full `Record<Client, …>`, so adding an id to `CLIENTS` without an agent here does
4
+ * not compile.
5
+ */
6
+ import type { Client } from "../args.js";
7
+ import type { CodingAgent } from "./types.js";
8
+ export declare function agentFor(client: Client): CodingAgent;
9
+ /** The agent the gateway's `kind` belongs to, if the CLI can configure that kind at all. */
10
+ export declare function agentOfKind(kind: string): CodingAgent | undefined;
@@ -0,0 +1,14 @@
1
+ import { claudeCode } from "./claude-code/index.js";
2
+ import { codex } from "./codex/index.js";
3
+ const AGENTS = {
4
+ "claude-code": claudeCode,
5
+ codex,
6
+ };
7
+ export function agentFor(client) {
8
+ return AGENTS[client];
9
+ }
10
+ /** The agent the gateway's `kind` belongs to, if the CLI can configure that kind at all. */
11
+ export function agentOfKind(kind) {
12
+ return Object.values(AGENTS).find((agent) => agent.kind === kind);
13
+ }
14
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/agents/registry.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAGzC,MAAM,MAAM,GAA0C;IACpD,aAAa,EAAE,UAAU;IACzB,KAAK;CACN,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACpE,CAAC"}