@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/dist/report.js ADDED
@@ -0,0 +1,214 @@
1
+ import { DEFAULT_URLS, isInsecureGateway } from "./args.js";
2
+ import { EXIT } from "./result.js";
3
+ /**
4
+ * Outcome name → exit code. This is the map `--json` consumers branch on, so the
5
+ * numbers are a contract: they may gain entries but never change meaning.
6
+ */
7
+ export const EXIT_FOR = {
8
+ created: EXIT.OK,
9
+ updated: EXIT.OK,
10
+ unchanged: EXIT.OK,
11
+ conflict: EXIT.CONFLICT,
12
+ malformed: EXIT.MALFORMED,
13
+ failed: EXIT.INTERNAL,
14
+ };
15
+ /**
16
+ * `uninstall` outcome → exit code. Same contract as EXIT_FOR: entries may be added,
17
+ * meanings never change. Actionable refusals share CONFLICT; the two
18
+ * "not-there" cases get their own codes so a script can tell them apart.
19
+ */
20
+ export const EXIT_FOR_REVERT = {
21
+ reverted: EXIT.OK,
22
+ restored: EXIT.OK,
23
+ "not-configured": EXIT.NOT_CONFIGURED,
24
+ "agent-mismatch": EXIT.CONFLICT,
25
+ drifted: EXIT.CONFLICT,
26
+ "no-backup": EXIT.NO_BACKUP,
27
+ malformed: EXIT.MALFORMED,
28
+ failed: EXIT.INTERNAL,
29
+ };
30
+ function revertLine(outcome) {
31
+ switch (outcome.kind) {
32
+ case "reverted": {
33
+ const parts = [
34
+ outcome.restored.length > 0 ? `restored ${outcome.restored.join(", ")} to previous values` : undefined,
35
+ outcome.removed.length > 0 ? `removed ${outcome.removed.join(", ")}` : undefined,
36
+ ].filter((part) => part !== undefined);
37
+ return `Reverted ${outcome.path} — ${parts.join("; ")}`;
38
+ }
39
+ case "restored":
40
+ return `Restored ${outcome.path} from ${outcome.backup}`;
41
+ case "not-configured":
42
+ return `Nothing to revert — ${outcome.path} does not carry this tool's settings.`;
43
+ case "agent-mismatch":
44
+ return `${outcome.path} is configured for agent '${outcome.actual}', not '${outcome.expected}'.`;
45
+ case "drifted":
46
+ return `${outcome.path} has changed since it was written.`;
47
+ case "no-backup":
48
+ return `No backup to restore from: ${outcome.backup} does not exist.`;
49
+ case "malformed":
50
+ return `Refusing to edit ${outcome.path}: ${outcome.reason}.`;
51
+ case "failed":
52
+ return `Could not update ${outcome.path}: ${outcome.reason}.`;
53
+ }
54
+ }
55
+ /** Human-only detail: what the user can do about a refusal. */
56
+ function revertDetail(outcome) {
57
+ switch (outcome.kind) {
58
+ case "reverted":
59
+ // Said out loud because it is a silent partial failure otherwise: the keys
60
+ // are gone but whatever they held beforehand could not be recovered.
61
+ return outcome.backupUnreadable
62
+ ? `The backup could not be read, so any values these keys held before could not be restored.\n`
63
+ : "";
64
+ case "drifted":
65
+ return ("Restoring the backup would discard those changes. Nothing was written.\n" +
66
+ "Re-run with --yes to restore anyway, or without --from-backup to remove only this tool's keys.\n");
67
+ case "agent-mismatch":
68
+ return "Nothing was written. Re-run without --agent-id to revert whatever is there.\n";
69
+ case "no-backup":
70
+ return "Re-run without --from-backup to remove only this tool's keys.\n";
71
+ case "malformed":
72
+ return "Nothing was written. Fix or move the file, then re-run.\n";
73
+ case "failed":
74
+ return "The existing file was left unchanged.\n";
75
+ default:
76
+ return "";
77
+ }
78
+ }
79
+ export function reportRevert(outcome, json) {
80
+ const code = EXIT_FOR_REVERT[outcome.kind];
81
+ if (json) {
82
+ const { kind, path, ...rest } = outcome;
83
+ const payload = { ok: code === EXIT.OK, outcome: kind, exitCode: code, path, ...rest };
84
+ return { code, out: `${JSON.stringify(payload, null, 2)}\n`, err: "" };
85
+ }
86
+ const body = `${revertLine(outcome)}\n${revertDetail(outcome)}`;
87
+ return code === EXIT.OK ? { code, out: body, err: "" } : { code, out: "", err: body };
88
+ }
89
+ /**
90
+ * Not failures, but things that make a correct config look broken later — which is
91
+ * when a warning earns its noise.
92
+ */
93
+ export function collectWarnings(ctx) {
94
+ const warnings = [];
95
+ if (ctx.processEnv.ANTHROPIC_API_KEY !== undefined && ctx.processEnv.ANTHROPIC_API_KEY !== "") {
96
+ warnings.push({
97
+ code: "anthropic-api-key-set",
98
+ // It shadows the claude.ai login and surfaces as a 401 from the gateway,
99
+ // which reads as "the CLI wrote a bad config" rather than "unset this".
100
+ 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.",
101
+ });
102
+ }
103
+ if (isInsecureGateway(ctx.urls.gateway)) {
104
+ warnings.push({
105
+ code: "insecure-gateway",
106
+ // Not just our one verifying request: this URL is what the written config
107
+ // points every future Claude Code request at, each carrying the AI21 key.
108
+ message: `${ctx.urls.gateway} is plain http, so the AI21 key will cross the network unencrypted on every request. Use an https gateway outside local development.`,
109
+ });
110
+ }
111
+ if (ctx.urls.gateway !== DEFAULT_URLS.gateway) {
112
+ warnings.push({
113
+ code: "non-production-gateway",
114
+ message: `Configured against a custom gateway (${ctx.urls.gateway}), not production.`,
115
+ });
116
+ }
117
+ return warnings;
118
+ }
119
+ /** Human-readable line for a config outcome. Never includes the key. */
120
+ function humanLine(outcome) {
121
+ switch (outcome.kind) {
122
+ case "created":
123
+ return `Wrote ${outcome.path}`;
124
+ case "updated":
125
+ return `Updated ${outcome.path} (${outcome.changed.join(", ")})\nBacked up the previous file to ${outcome.backup}`;
126
+ case "unchanged":
127
+ return `Already configured — ${outcome.path} is up to date.`;
128
+ case "conflict":
129
+ return `${outcome.path} already sets values this command would change.`;
130
+ case "malformed":
131
+ return `Refusing to edit ${outcome.path}: ${outcome.reason}.`;
132
+ case "failed":
133
+ return `Could not write ${outcome.path}: ${outcome.reason}.`;
134
+ }
135
+ }
136
+ /** How each tier reads to a human, once it has succeeded. */
137
+ const VERIFIED_VIA = {
138
+ "claude-cli": "`claude -p`",
139
+ "direct-ping": "a direct request",
140
+ };
141
+ /**
142
+ * Verification is never a failure: the config write is the deliverable, and a
143
+ * ping that could not be made — or that the gateway refused — does not un-write
144
+ * it. So a pass narrates and everything else warns.
145
+ */
146
+ function verificationWarning(outcome) {
147
+ switch (outcome.kind) {
148
+ case "skipped":
149
+ return {
150
+ code: "verification-skipped",
151
+ message: `Skipped verification — no Anthropic credential was available. ${outcome.hint}`,
152
+ };
153
+ case "failed":
154
+ return {
155
+ code: "verification-failed",
156
+ message: `Could not verify through the gateway — ${outcome.reason}. The configuration was written and left in place.`,
157
+ };
158
+ default:
159
+ return undefined;
160
+ }
161
+ }
162
+ /** The stdout line for a successful verification; nothing for any other outcome. */
163
+ function verificationLine(outcome) {
164
+ if (outcome?.kind !== "passed")
165
+ return "";
166
+ return `Verified through the gateway with ${VERIFIED_VIA[outcome.via]}.\n`;
167
+ }
168
+ /**
169
+ * One JSON object with what happened, where, why it exited that way, and any
170
+ * warnings. Flat and stable — a consumer should not have to parse prose.
171
+ */
172
+ function jsonPayload(input, code, warnings) {
173
+ const { outcome } = input;
174
+ const payload = {
175
+ ok: code === EXIT.OK,
176
+ outcome: outcome.kind,
177
+ exitCode: code,
178
+ path: outcome.path,
179
+ gateway: input.urls.gateway,
180
+ warnings: warnings.map((w) => ({ code: w.code, message: w.message })),
181
+ };
182
+ // Structured rather than warning-only: a script should be able to tell "verified"
183
+ // from "written but unverified" without matching on prose.
184
+ if (input.verification !== undefined) {
185
+ const { kind, ...rest } = input.verification;
186
+ payload.verification = { status: kind, ...rest };
187
+ }
188
+ if (outcome.kind === "updated") {
189
+ payload.changed = outcome.changed;
190
+ payload.backup = outcome.backup;
191
+ }
192
+ if (outcome.kind === "conflict") {
193
+ payload.conflicts = outcome.conflicts.map((c) => ({ key: c.key }));
194
+ }
195
+ if (outcome.kind === "malformed" || outcome.kind === "failed") {
196
+ payload.reason = outcome.reason;
197
+ }
198
+ return `${JSON.stringify(payload, null, 2)}\n`;
199
+ }
200
+ export function report(input) {
201
+ const code = EXIT_FOR[input.outcome.kind];
202
+ const fromVerification = input.verification === undefined ? undefined : verificationWarning(input.verification);
203
+ const warnings = fromVerification === undefined ? input.warnings : [...input.warnings, fromVerification];
204
+ if (input.json) {
205
+ // Everything on stdout, nothing on stderr: a single parse of one stream.
206
+ return { code, out: jsonPayload(input, code, warnings), err: "" };
207
+ }
208
+ const warningText = warnings.map((w) => `warning: ${w.message}\n`).join("");
209
+ const body = `${humanLine(input.outcome)}\n${verificationLine(input.verification)}${input.detail ?? ""}`;
210
+ // Success narrates on stdout; a refusal belongs on stderr so `>/dev/null`
211
+ // still shows the user why nothing happened.
212
+ return code === EXIT.OK ? { code, out: body, err: warningText } : { code, out: "", err: `${body}${warningText}` };
213
+ }
214
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /** What every command hands back. Its own module so cli.ts and router.ts can share it. */
2
+ /**
3
+ * Stable contract — `--json` consumers branch on these, so values are never
4
+ * reassigned once shipped. Later phases fill in the gaps.
5
+ */
6
+ export declare const EXIT: {
7
+ readonly OK: 0;
8
+ /** Unexpected internal failure. 3+ are reserved for named outcomes. */
9
+ readonly INTERNAL: 1;
10
+ readonly USAGE: 2;
11
+ /** A managed key already holds a different value and `--yes` was not given. */
12
+ readonly CONFLICT: 3;
13
+ /** The existing settings.json could not be parsed, so it was left untouched. */
14
+ readonly MALFORMED: 4;
15
+ /** `uninstall` found none of the managed keys — there was nothing of ours to revert. */
16
+ readonly NOT_CONFIGURED: 5;
17
+ /** `uninstall --from-backup` was asked for, but no .bak exists. */
18
+ readonly NO_BACKUP: 6;
19
+ /** `login` did not complete: timed out, or the response was refused. */
20
+ readonly LOGIN_INCOMPLETE: 7;
21
+ };
22
+ export interface RunResult {
23
+ readonly code: number;
24
+ readonly out: string;
25
+ readonly err: string;
26
+ }
package/dist/result.js ADDED
@@ -0,0 +1,22 @@
1
+ /** What every command hands back. Its own module so cli.ts and router.ts can share it. */
2
+ /**
3
+ * Stable contract — `--json` consumers branch on these, so values are never
4
+ * reassigned once shipped. Later phases fill in the gaps.
5
+ */
6
+ export const EXIT = {
7
+ OK: 0,
8
+ /** Unexpected internal failure. 3+ are reserved for named outcomes. */
9
+ INTERNAL: 1,
10
+ USAGE: 2,
11
+ /** A managed key already holds a different value and `--yes` was not given. */
12
+ CONFLICT: 3,
13
+ /** The existing settings.json could not be parsed, so it was left untouched. */
14
+ MALFORMED: 4,
15
+ /** `uninstall` found none of the managed keys — there was nothing of ours to revert. */
16
+ NOT_CONFIGURED: 5,
17
+ /** `uninstall --from-backup` was asked for, but no .bak exists. */
18
+ NO_BACKUP: 6,
19
+ /** `login` did not complete: timed out, or the response was refused. */
20
+ LOGIN_INCOMPLETE: 7,
21
+ };
22
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAE1F;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,EAAE,EAAE,CAAC;IACL,uEAAuE;IACvE,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,CAAC;IACR,+EAA+E;IAC/E,QAAQ,EAAE,CAAC;IACX,gFAAgF;IAChF,SAAS,EAAE,CAAC;IACZ,wFAAwF;IACxF,cAAc,EAAE,CAAC;IACjB,mEAAmE;IACnE,SAAS,EAAE,CAAC;IACZ,wEAAwE;IACxE,gBAAgB,EAAE,CAAC;CACX,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { type ConfigPaths } from "./config.js";
2
+ export type RevertOutcome = {
3
+ readonly kind: "reverted";
4
+ readonly path: string;
5
+ /** Keys we added, so reverting means deleting them. */
6
+ readonly removed: readonly string[];
7
+ /** Keys that held a value before we wrote, now put back. */
8
+ readonly restored: readonly string[];
9
+ /** A `.bak` was there but could not be parsed, so prior values were lost. */
10
+ readonly backupUnreadable: boolean;
11
+ } | {
12
+ readonly kind: "restored";
13
+ readonly path: string;
14
+ readonly backup: string;
15
+ }
16
+ /** None of the managed keys were there — not ours to revert. */
17
+ | {
18
+ readonly kind: "not-configured";
19
+ readonly path: string;
20
+ } | {
21
+ readonly kind: "agent-mismatch";
22
+ readonly path: string;
23
+ readonly expected: string;
24
+ readonly actual: string;
25
+ }
26
+ /** `--from-backup` would discard edits made since our write. */
27
+ | {
28
+ readonly kind: "drifted";
29
+ readonly path: string;
30
+ readonly backup: string;
31
+ } | {
32
+ readonly kind: "no-backup";
33
+ readonly path: string;
34
+ readonly backup: string;
35
+ } | {
36
+ readonly kind: "malformed";
37
+ readonly path: string;
38
+ readonly reason: string;
39
+ } | {
40
+ readonly kind: "failed";
41
+ readonly path: string;
42
+ readonly reason: string;
43
+ };
44
+ export interface RevertOptions {
45
+ /** Restore the `.bak` verbatim instead of removing our keys surgically. */
46
+ readonly fromBackup: boolean;
47
+ /** Proceed with a restore that discards drift. */
48
+ readonly force: boolean;
49
+ /** When set, the stored `x-agent-id` must equal this or nothing is written. */
50
+ readonly agentIdGuard?: string | undefined;
51
+ }
52
+ type JsonObject = Record<string, unknown>;
53
+ /**
54
+ * The `x-agent-id` currently stored in the `\n`-joined header value. Returns
55
+ * undefined when the header, or the whole value, is absent or unparseable — an
56
+ * absent id can never satisfy the guard, which is the safe direction.
57
+ */
58
+ export declare function storedAgentId(env: JsonObject | undefined): string | undefined;
59
+ export declare function revertConfig(paths: ConfigPaths, options: RevertOptions): RevertOutcome;
60
+ export {};
package/dist/revert.js ADDED
@@ -0,0 +1,230 @@
1
+ /**
2
+ * `uninstall` — undoing what this tool wrote, without a blind restore.
3
+ *
4
+ * Default: per-key revert. Each managed `env` key goes back to the value it held
5
+ * before we wrote, or is removed if it had none. `--from-backup` instead restores
6
+ * the `.bak` byte for byte, which discards later edits and so needs `--yes` once
7
+ * the file has drifted. `--agent-id` is a guard, not a selector.
8
+ *
9
+ * Same constraint as the writer: every path leaves the file byte-identical or
10
+ * replaces it atomically, and every refusal touches nothing.
11
+ */
12
+ import { copyFileSync, existsSync, lstatSync, readFileSync, readlinkSync, realpathSync } from "node:fs";
13
+ import { dirname, resolve } from "node:path";
14
+ import { MANAGED_KEYS, atomicWrite, describeFsError, isOurConfig, isPlainObject, serialize, } from "./config.js";
15
+ /**
16
+ * Resolve a symlinked settings.json to what it names, so a revert writes through
17
+ * the link rather than replacing it — the same reason the writer does this.
18
+ */
19
+ function followLink(path) {
20
+ try {
21
+ if (lstatSync(path, { throwIfNoEntry: false })?.isSymbolicLink() === true) {
22
+ return resolve(dirname(path), readlinkSync(path));
23
+ }
24
+ }
25
+ catch {
26
+ return path;
27
+ }
28
+ return path;
29
+ }
30
+ /** Reads and validates a settings file, mapping every failure to an outcome. */
31
+ function load(path) {
32
+ let realPath;
33
+ let raw;
34
+ try {
35
+ realPath = realpathSync(path);
36
+ raw = readFileSync(realPath, "utf8");
37
+ }
38
+ catch (err) {
39
+ return { problem: { kind: "failed", path, reason: describeFsError(err) } };
40
+ }
41
+ let parsed;
42
+ try {
43
+ parsed = JSON.parse(raw);
44
+ }
45
+ catch {
46
+ // No parser detail: the message is user-facing and the file may hold a key.
47
+ return { problem: { kind: "malformed", path, reason: "it is not valid JSON" } };
48
+ }
49
+ if (!isPlainObject(parsed)) {
50
+ return { problem: { kind: "malformed", path, reason: "its top level is not a JSON object" } };
51
+ }
52
+ const env = parsed.env;
53
+ if (env !== undefined && !isPlainObject(env)) {
54
+ return { problem: { kind: "malformed", path, reason: 'its "env" is not a JSON object' } };
55
+ }
56
+ return { file: { realPath, raw, parsed, env } };
57
+ }
58
+ /**
59
+ * The `x-agent-id` currently stored in the `\n`-joined header value. Returns
60
+ * undefined when the header, or the whole value, is absent or unparseable — an
61
+ * absent id can never satisfy the guard, which is the safe direction.
62
+ */
63
+ export function storedAgentId(env) {
64
+ const headers = env?.ANTHROPIC_CUSTOM_HEADERS;
65
+ if (typeof headers !== "string")
66
+ return undefined;
67
+ for (const line of headers.split("\n")) {
68
+ const match = /^\s*x-agent-id\s*:\s*(.+?)\s*$/i.exec(line);
69
+ if (match?.[1] !== undefined)
70
+ return match[1];
71
+ }
72
+ return undefined;
73
+ }
74
+ /** Everything except the keys we manage — the part of the file that is not ours. */
75
+ function withoutManagedKeys(parsed, env) {
76
+ if (env === undefined)
77
+ return parsed;
78
+ const remaining = Object.fromEntries(Object.entries(env).filter(([key]) => !isManaged(key)));
79
+ const keepEnv = Object.keys(remaining).length > 0;
80
+ // Rebuilt in the file's own key order rather than spread-and-append, so a revert
81
+ // reads as a minimal diff of someone else's file. An emptied env is dropped
82
+ // instead of being left behind as `{}` — that would be our litter, not theirs.
83
+ const result = {};
84
+ for (const [key, value] of Object.entries(parsed)) {
85
+ if (key !== "env") {
86
+ result[key] = value;
87
+ continue;
88
+ }
89
+ if (keepEnv)
90
+ result.env = remaining;
91
+ }
92
+ return result;
93
+ }
94
+ function isManaged(key) {
95
+ return MANAGED_KEYS.includes(key);
96
+ }
97
+ /** Whether anything outside our keys changed. Structural: indentation is not drift. */
98
+ function hasDrifted(current, backupRaw) {
99
+ let backupParsed;
100
+ try {
101
+ backupParsed = JSON.parse(backupRaw);
102
+ }
103
+ catch {
104
+ // An unparseable backup cannot be compared, so treat it as drift and let
105
+ // --yes be the way through. Refusing by default is the safe direction.
106
+ return true;
107
+ }
108
+ if (!isPlainObject(backupParsed))
109
+ return true;
110
+ const backupEnv = isPlainObject(backupParsed.env) ? backupParsed.env : undefined;
111
+ return (JSON.stringify(withoutManagedKeys(current.parsed, current.env)) !==
112
+ JSON.stringify(withoutManagedKeys(backupParsed, backupEnv)));
113
+ }
114
+ function restoreFromBackup(paths, file, options) {
115
+ const { settings: path } = paths;
116
+ const backup = file.realPath === path ? paths.backup : `${file.realPath}.bak`;
117
+ if (!existsSync(backup)) {
118
+ return { kind: "no-backup", path, backup };
119
+ }
120
+ let backupRaw;
121
+ try {
122
+ backupRaw = readFileSync(backup, "utf8");
123
+ }
124
+ catch (err) {
125
+ return { kind: "failed", path, reason: describeFsError(err) };
126
+ }
127
+ if (!options.force && hasDrifted(file, backupRaw)) {
128
+ return { kind: "drifted", path, backup };
129
+ }
130
+ try {
131
+ // copyFileSync, not a parse-and-serialize round trip: "verbatim" has to mean
132
+ // byte for byte, including formatting and any key order the developer chose.
133
+ copyFileSync(backup, file.realPath);
134
+ }
135
+ catch (err) {
136
+ return { kind: "failed", path, reason: describeFsError(err) };
137
+ }
138
+ return { kind: "restored", path, backup };
139
+ }
140
+ /** Rebuilds the document with a new `env`, preserving the file's own key order. */
141
+ function withEnv(parsed, env) {
142
+ const keep = env !== undefined && Object.keys(env).length > 0;
143
+ const result = {};
144
+ for (const [key, value] of Object.entries(parsed)) {
145
+ if (key !== "env") {
146
+ result[key] = value;
147
+ continue;
148
+ }
149
+ if (keep)
150
+ result.env = env;
151
+ }
152
+ return result;
153
+ }
154
+ /** The `env` block as it was before we wrote, or undefined if that is unknowable. */
155
+ function previousEnv(paths, file) {
156
+ const backup = file.realPath === paths.settings ? paths.backup : `${file.realPath}.bak`;
157
+ if (!existsSync(backup)) {
158
+ // No backup means we created the file, so every managed key is one we added.
159
+ return { unreadable: false };
160
+ }
161
+ try {
162
+ const parsed = JSON.parse(readFileSync(backup, "utf8"));
163
+ if (!isPlainObject(parsed))
164
+ return { unreadable: true };
165
+ return { env: isPlainObject(parsed.env) ? parsed.env : {}, unreadable: false };
166
+ }
167
+ catch {
168
+ return { unreadable: true };
169
+ }
170
+ }
171
+ /**
172
+ * Restore each managed key to its prior value rather than deleting it: deletion
173
+ * would silently discard a developer's own `ANTHROPIC_BASE_URL` that we overwrote
174
+ * with `--yes`. A key with no prior value is one we added, so it is removed. Every
175
+ * other key is copied across untouched.
176
+ */
177
+ function revertManagedKeys(paths, file) {
178
+ const { settings: path } = paths;
179
+ const { env: before, unreadable } = previousEnv(paths, file);
180
+ const removed = [];
181
+ const restored = [];
182
+ const nextEnv = {};
183
+ for (const [key, value] of Object.entries(file.env ?? {})) {
184
+ if (!isManaged(key)) {
185
+ nextEnv[key] = value;
186
+ continue;
187
+ }
188
+ const previous = before?.[key];
189
+ if (previous === undefined) {
190
+ removed.push(key);
191
+ continue;
192
+ }
193
+ nextEnv[key] = previous;
194
+ restored.push(key);
195
+ }
196
+ try {
197
+ // No backup taken, deliberately: overwriting the .bak with the configured state
198
+ // would destroy the very snapshot this function reads prior values from.
199
+ atomicWrite(file.realPath, serialize(withEnv(file.parsed, nextEnv)));
200
+ }
201
+ catch (err) {
202
+ return { kind: "failed", path, reason: describeFsError(err) };
203
+ }
204
+ return { kind: "reverted", path, removed, restored, backupUnreadable: unreadable };
205
+ }
206
+ export function revertConfig(paths, options) {
207
+ const { settings: path } = paths;
208
+ // Nothing there at all reads the same as nothing of ours in it.
209
+ if (!existsSync(followLink(path))) {
210
+ return { kind: "not-configured", path };
211
+ }
212
+ const loaded = load(path);
213
+ if ("problem" in loaded)
214
+ return loaded.problem;
215
+ const { file } = loaded;
216
+ // Gates both behaviours: without the marker this is not a file we configured.
217
+ if (!isOurConfig(file.env)) {
218
+ return { kind: "not-configured", path };
219
+ }
220
+ // The guard applies to both behaviours — a mismatched agent must stop a
221
+ // verbatim restore just as firmly as a surgical revert.
222
+ if (options.agentIdGuard !== undefined) {
223
+ const stored = storedAgentId(file.env);
224
+ if (stored !== options.agentIdGuard) {
225
+ return { kind: "agent-mismatch", path, expected: options.agentIdGuard, actual: stored ?? "none" };
226
+ }
227
+ }
228
+ return options.fromBackup ? restoreFromBackup(paths, file, options) : revertManagedKeys(paths, file);
229
+ }
230
+ //# sourceMappingURL=revert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revert.js","sourceRoot":"","sources":["../src/revert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Verb dispatch. Handlers return streams and an exit code rather than writing or
3
+ * exiting, so a command can be asserted end to end without spawning a process.
4
+ */
5
+ import { type ParsedArgs } from "./args.js";
6
+ import { type PathContext } from "./config.js";
7
+ import { type PromptIo } from "./prompt.js";
8
+ import { type LoginDeps } from "./login/session.js";
9
+ import { type RunResult } from "./result.js";
10
+ import { type VerifyDeps } from "./verify.js";
11
+ /** Everything the dispatcher needs from the outside world, injected at the edge. */
12
+ export interface RunContext {
13
+ readonly paths: PathContext;
14
+ readonly prompt: PromptIo;
15
+ readonly processEnv: Record<string, string | undefined>;
16
+ readonly verify: VerifyDeps;
17
+ readonly login: LoginDeps;
18
+ /** Progress output while `login` waits. Streams, so it cannot go in RunResult. */
19
+ readonly notify: (message: string) => void;
20
+ }
21
+ export declare function dispatch(args: ParsedArgs, ctx: RunContext): Promise<RunResult>;