@ai21/gateway 1.3.0 → 1.3.1

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 (55) hide show
  1. package/README.md +5 -4
  2. package/dist/agents/claude-code/revert.d.ts +11 -0
  3. package/dist/{revert.js → agents/claude-code/revert.js} +2 -1
  4. package/dist/agents/claude-code/revert.js.map +1 -0
  5. package/dist/agents/claude-code/settings.d.ts +33 -0
  6. package/dist/{config.js → agents/claude-code/settings.js} +6 -57
  7. package/dist/agents/claude-code/settings.js.map +1 -0
  8. package/dist/{snippets.d.ts → agents/claude-code/snippets.d.ts} +1 -18
  9. package/dist/{snippets.js → agents/claude-code/snippets.js} +0 -19
  10. package/dist/agents/claude-code/snippets.js.map +1 -0
  11. package/dist/agents/claude-code/status.d.ts +12 -0
  12. package/dist/agents/claude-code/status.js +42 -0
  13. package/dist/agents/claude-code/status.js.map +1 -0
  14. package/dist/{verify.d.ts → agents/claude-code/verify.d.ts} +14 -54
  15. package/dist/{verify.js → agents/claude-code/verify.js} +2 -133
  16. package/dist/agents/claude-code/verify.js.map +1 -0
  17. package/dist/agents/deps.d.ts +3 -0
  18. package/dist/agents/deps.js +10 -0
  19. package/dist/agents/deps.js.map +1 -0
  20. package/dist/agents/types.d.ts +266 -0
  21. package/dist/agents/types.js +3 -0
  22. package/dist/agents/types.js.map +1 -0
  23. package/dist/cli.js +3 -2
  24. package/dist/cli.js.map +1 -1
  25. package/dist/fs/safeFile.d.ts +19 -0
  26. package/dist/fs/safeFile.js +50 -0
  27. package/dist/fs/safeFile.js.map +1 -0
  28. package/dist/{snapshot.d.ts → fs/snapshot.d.ts} +1 -1
  29. package/dist/{snapshot.js → fs/snapshot.js} +1 -1
  30. package/dist/fs/snapshot.js.map +1 -0
  31. package/dist/login/keychain/linux.d.ts +1 -1
  32. package/dist/login/keychain/linux.js +1 -1
  33. package/dist/login/keychain/linux.js.map +1 -1
  34. package/dist/process.d.ts +26 -0
  35. package/dist/process.js +94 -0
  36. package/dist/process.js.map +1 -0
  37. package/dist/report.d.ts +3 -8
  38. package/dist/report.js.map +1 -1
  39. package/dist/router.d.ts +2 -3
  40. package/dist/router.js +26 -16
  41. package/dist/router.js.map +1 -1
  42. package/dist/telemetry/amplitudeHttp.js +1 -0
  43. package/dist/telemetry/amplitudeHttp.js.map +1 -1
  44. package/dist/telemetry/events.d.ts +7 -3
  45. package/dist/telemetry/telemetry.d.ts +6 -2
  46. package/dist/telemetry/telemetry.js +19 -8
  47. package/dist/telemetry/telemetry.js.map +1 -1
  48. package/package.json +3 -3
  49. package/dist/config.d.ts +0 -83
  50. package/dist/config.js.map +0 -1
  51. package/dist/revert.d.ts +0 -60
  52. package/dist/revert.js.map +0 -1
  53. package/dist/snapshot.js.map +0 -1
  54. package/dist/snippets.js.map +0 -1
  55. package/dist/verify.js.map +0 -1
@@ -0,0 +1,266 @@
1
+ /**
2
+ * The contract every coding agent implements. The router owns the flow that is the same
3
+ * for all of them — resolve the key, check it, gate on a subscription, snapshot, write,
4
+ * verify, undo when there is no subscription, report — and asks the agent for everything
5
+ * that differs: where its config lives, what goes in it, how to take it out again, how
6
+ * to tell whether its user is signed in, and how to prove the result works.
7
+ *
8
+ * Outcomes are agent-neutral (paths and key names are data), so `report.ts` renders any
9
+ * agent's result and reads only the agent's `text` for the words that name it.
10
+ */
11
+ import type { Client, ResolvedUrls, Target } from "../args.js";
12
+ import type { ConfigPaths } from "../fs/safeFile.js";
13
+ import type { PathLookup, RunCommand } from "../process.js";
14
+ /** What every agent's config is rendered from. */
15
+ export interface SnippetInputs {
16
+ readonly gatewayUrl: string;
17
+ readonly agentId: string;
18
+ readonly ai21Key: string;
19
+ /** Signed-in user id for per-user attribution. Absent on a normal CLI run. */
20
+ readonly userId?: string | undefined;
21
+ /**
22
+ * Marks the traffic as configured by this tool, e.g. `ai21-gateway-cli/0.4.0`.
23
+ *
24
+ * Set on what the CLI writes, and deliberately absent from the snippet builders the
25
+ * contract tests pin against the webapp: a config someone pasted by hand did not
26
+ * come from here and must not claim to have. Lets the gateway tell the two apart
27
+ * without the CLI reporting anything itself.
28
+ */
29
+ readonly client?: string | undefined;
30
+ }
31
+ /** Stand-in for the AI21 key in a preview, before one has been supplied. */
32
+ export declare const AI21_KEY_PLACEHOLDER = "<your-ai21-api-key>";
33
+ /** Injected rather than read from the process, so tests can use a temp directory. */
34
+ export interface PathContext {
35
+ readonly cwd: string;
36
+ readonly home: string;
37
+ }
38
+ /** What an agent may read to locate its config — some honour an env override. */
39
+ export interface AgentEnv extends PathContext {
40
+ readonly processEnv: Record<string, string | undefined>;
41
+ }
42
+ export interface AgentPaths extends ConfigPaths {
43
+ /**
44
+ * Where to run the agent's own CLI so that the file we wrote is the one it reads.
45
+ * Home for a user-level config, since a project-local one would outrank it.
46
+ */
47
+ readonly verifyCwd: string;
48
+ }
49
+ export interface Conflict {
50
+ readonly key: string;
51
+ readonly current: string;
52
+ readonly desired: string;
53
+ }
54
+ export type ConfigOutcome = {
55
+ readonly kind: "created";
56
+ readonly path: string;
57
+ } | {
58
+ readonly kind: "updated";
59
+ readonly path: string;
60
+ readonly backup: string;
61
+ readonly changed: readonly string[];
62
+ } | {
63
+ readonly kind: "unchanged";
64
+ readonly path: string;
65
+ } | {
66
+ readonly kind: "conflict";
67
+ readonly path: string;
68
+ readonly conflicts: readonly Conflict[];
69
+ } | {
70
+ readonly kind: "malformed";
71
+ readonly path: string;
72
+ readonly reason: string;
73
+ } | {
74
+ readonly kind: "failed";
75
+ readonly path: string;
76
+ readonly reason: string;
77
+ };
78
+ export type RevertOutcome = {
79
+ readonly kind: "reverted";
80
+ readonly path: string;
81
+ /** Keys we added, so reverting means deleting them. */
82
+ readonly removed: readonly string[];
83
+ /** Keys that held a value before we wrote, now put back. */
84
+ readonly restored: readonly string[];
85
+ /** A `.bak` was there but could not be parsed, so prior values were lost. */
86
+ readonly backupUnreadable: boolean;
87
+ } | {
88
+ readonly kind: "restored";
89
+ readonly path: string;
90
+ readonly backup: string;
91
+ }
92
+ /** None of the managed keys were there — not ours to revert. */
93
+ | {
94
+ readonly kind: "not-configured";
95
+ readonly path: string;
96
+ } | {
97
+ readonly kind: "agent-mismatch";
98
+ readonly path: string;
99
+ readonly expected: string;
100
+ readonly actual: string;
101
+ }
102
+ /** `--from-backup` would discard edits made since our write. */
103
+ | {
104
+ readonly kind: "drifted";
105
+ readonly path: string;
106
+ readonly backup: string;
107
+ } | {
108
+ readonly kind: "no-backup";
109
+ readonly path: string;
110
+ readonly backup: string;
111
+ } | {
112
+ readonly kind: "malformed";
113
+ readonly path: string;
114
+ readonly reason: string;
115
+ } | {
116
+ readonly kind: "failed";
117
+ readonly path: string;
118
+ readonly reason: string;
119
+ };
120
+ export interface RevertOptions {
121
+ /** Restore the `.bak` verbatim instead of removing our keys surgically. */
122
+ readonly fromBackup: boolean;
123
+ /** Proceed with a restore that discards drift. */
124
+ readonly force: boolean;
125
+ /** When set, the stored `x-agent-id` must equal this or nothing is written. */
126
+ readonly agentIdGuard?: string | undefined;
127
+ }
128
+ /** Whether the agent's own login can carry requests through the gateway. */
129
+ export type SubscriptionStatus = {
130
+ readonly kind: "present";
131
+ }
132
+ /** Definitely unusable; `reason` keys into `AgentText.noSubscription`. */
133
+ | {
134
+ readonly kind: "missing";
135
+ readonly reason: string;
136
+ }
137
+ /** Could not tell — never blocks an install. */
138
+ | {
139
+ readonly kind: "inconclusive";
140
+ };
141
+ /** Whether the agent can run on this machine at all, before anything else does. */
142
+ export type InstallStatus = {
143
+ readonly kind: "present";
144
+ } | {
145
+ readonly kind: "missing";
146
+ };
147
+ /** What `checkInstalled` may consult: an upstream key can stand in for a missing binary. */
148
+ export interface InstallContext {
149
+ readonly upstreamKey?: string | undefined;
150
+ readonly processEnv: Record<string, string | undefined>;
151
+ }
152
+ export interface VerifyContext {
153
+ readonly urls: ResolvedUrls;
154
+ readonly agentId: string;
155
+ readonly ai21Key: string;
156
+ readonly userId?: string | undefined;
157
+ /** The agent's own upstream credential for a direct check, when it has a flag for one. */
158
+ readonly upstreamKey?: string | undefined;
159
+ readonly processEnv: Record<string, string | undefined>;
160
+ /** `AgentPaths.verifyCwd`. */
161
+ readonly cwd: string;
162
+ }
163
+ /**
164
+ * How verification ended. Only `no-subscription` changes the exit code. `via` names the
165
+ * tier that ran and `reason` the missing credential; both key into the agent's `text`.
166
+ */
167
+ export type VerifyOutcome = {
168
+ readonly kind: "disabled";
169
+ } | {
170
+ readonly kind: "skipped";
171
+ readonly hint: string;
172
+ } | {
173
+ readonly kind: "passed";
174
+ readonly via: string;
175
+ } | {
176
+ readonly kind: "failed";
177
+ readonly via: string;
178
+ readonly reason: string;
179
+ } | {
180
+ readonly kind: "no-subscription";
181
+ readonly via: string;
182
+ readonly reason: string;
183
+ };
184
+ /** Just enough of `fetch` to send one request. `text` is optional; absent means inconclusive. */
185
+ export type FetchLike = (url: string, init: {
186
+ method: string;
187
+ headers: Record<string, string>;
188
+ body: string;
189
+ signal: AbortSignal;
190
+ }) => Promise<{
191
+ ok: boolean;
192
+ status: number;
193
+ text?: () => Promise<string>;
194
+ }>;
195
+ /** The outside world an agent touches while checking a login or verifying. */
196
+ export interface AgentDeps {
197
+ readonly lookup: PathLookup;
198
+ readonly runCommand: RunCommand;
199
+ readonly fetchImpl: FetchLike;
200
+ }
201
+ export interface Warning {
202
+ /** Stable identifier, so `--json` consumers match on this and not on prose. */
203
+ readonly code: string;
204
+ readonly message: string;
205
+ }
206
+ /** Flags that feed only a verification tier some agents have. */
207
+ export type VerifyFlag = "anthropic-key";
208
+ /** What the no-subscription refusal says for one `SubscriptionStatus`/`VerifyOutcome` reason. */
209
+ export interface NoSubscriptionText {
210
+ readonly headline: string;
211
+ readonly nextStep: string;
212
+ /** Stable `--json` reason, spelled for a funnel rather than for a person. */
213
+ readonly jsonReason: string;
214
+ }
215
+ /** What the not-installed refusal says. `jsonOutcome` and `jsonReason` are a contract: never renamed. */
216
+ export interface NotInstalledText {
217
+ readonly message: string;
218
+ readonly jsonOutcome: string;
219
+ readonly jsonReason: string;
220
+ }
221
+ /** Every user-facing phrase that names the agent or its tooling. */
222
+ export interface AgentText {
223
+ /** The `--json` `outcome` of the no-subscription refusal. A contract: never renamed. */
224
+ readonly noSubscriptionOutcome: string;
225
+ readonly noSubscription: Readonly<Record<string, NoSubscriptionText>>;
226
+ /** How each verification tier reads once it has passed, keyed by `VerifyOutcome.via`. */
227
+ readonly verifiedVia: Readonly<Record<string, string>>;
228
+ /** Why verification was skipped, before the agent's manual hint. */
229
+ readonly skippedBecause: string;
230
+ readonly notInstalled: NotInstalledText;
231
+ /** The status line while `checkSubscription` runs: "Checking your Claude login…". */
232
+ readonly checkingLogin: string;
233
+ /** The done line once `checkSubscription` found a usable login: "Claude login found". */
234
+ readonly loginFound: string;
235
+ }
236
+ export interface CodingAgent {
237
+ readonly id: Client;
238
+ /** "Claude Code", as a sentence would name it. */
239
+ readonly displayName: string;
240
+ /** The config file's name, for help and messages: "settings.json". */
241
+ readonly configLabel: string;
242
+ /** Which of `--user` / `--repo` this agent can be configured at. */
243
+ readonly targets: readonly Target[];
244
+ readonly verifyFlags: readonly VerifyFlag[];
245
+ /** Checked first by install, even under --no-verify: `missing` stops it before sign-in or any write. */
246
+ checkInstalled(ctx: InstallContext, deps: AgentDeps): InstallStatus;
247
+ resolvePaths(target: Target, env: AgentEnv): AgentPaths;
248
+ /** What `--print` shows: the file as text, and the fields `--json` adds beside target and urls. */
249
+ preview(inputs: SnippetInputs): {
250
+ readonly text: string;
251
+ readonly json: Readonly<Record<string, unknown>>;
252
+ };
253
+ /** Merge our config in. Never throws; nothing is written on `conflict` or `malformed`. */
254
+ write(paths: AgentPaths, inputs: SnippetInputs, options: {
255
+ readonly force: boolean;
256
+ }): ConfigOutcome;
257
+ revert(paths: AgentPaths, options: RevertOptions): RevertOutcome;
258
+ /** Blanks the AI21 key in a config value, so conflict output never prints it. */
259
+ redact(value: string): string;
260
+ /** Agent-specific things that make a correct config look broken later. */
261
+ warnings(paths: AgentPaths, processEnv: Record<string, string | undefined>): Warning[];
262
+ checkSubscription(paths: AgentPaths, deps: AgentDeps): Promise<SubscriptionStatus>;
263
+ /** Exactly one real request through the gateway, or none. */
264
+ verify(ctx: VerifyContext, deps: AgentDeps): Promise<VerifyOutcome>;
265
+ readonly text: AgentText;
266
+ }
@@ -0,0 +1,3 @@
1
+ /** Stand-in for the AI21 key in a preview, before one has been supplied. */
2
+ export const AI21_KEY_PLACEHOLDER = "<your-ai21-api-key>";
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAgCA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC"}
package/dist/cli.js CHANGED
@@ -7,7 +7,8 @@ import { parseCliArgs } from "./args.js";
7
7
  import { EXIT } from "./result.js";
8
8
  import { dispatch } from "./router.js";
9
9
  import { nodePrecheckDeps } from "./precheck.js";
10
- import { isExecutableFile, nodeVerifyDeps } from "./verify.js";
10
+ import { nodeAgentDeps } from "./agents/deps.js";
11
+ import { isExecutableFile } from "./process.js";
11
12
  import { nodeBrowserDeps, openBrowser } from "./login/browser.js";
12
13
  import { selectSecretStore } from "./login/keychain/select.js";
13
14
  import { runCredentialCommand } from "./login/keychain/runner.js";
@@ -149,7 +150,7 @@ export async function run(argv) {
149
150
  paths: { cwd: process.cwd(), home: homedir() },
150
151
  prompt: { input: process.stdin, output: process.stderr },
151
152
  processEnv: process.env,
152
- verify: nodeVerifyDeps(process.env),
153
+ verify: nodeAgentDeps(process.env),
153
154
  precheck: nodePrecheckDeps(),
154
155
  login: {
155
156
  startListener: startLoopback,
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /** A config file and the backup kept beside it. */
2
+ export interface ConfigPaths {
3
+ readonly settings: string;
4
+ readonly backup: string;
5
+ }
6
+ /** A symlinked config is backed up beside its target, not beside the link. */
7
+ export declare function backupPathFor(paths: ConfigPaths, realPath: string): string;
8
+ /**
9
+ * Turns an fs error into something safe to print. The code is translated rather
10
+ * than forwarded so no stack frame, errno struct or internal path escapes.
11
+ */
12
+ export declare function describeFsError(err: unknown): string;
13
+ /**
14
+ * Write via a sibling temp file and rename. The rename is atomic within a
15
+ * filesystem, so a reader either sees the old file or the new one — never a
16
+ * half-written config. The temp file is removed on any failure so a crashed run
17
+ * leaves no litter next to the real file.
18
+ */
19
+ export declare function atomicWrite(target: string, contents: string | Buffer): void;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Writing a file someone else owns: atomically, owner-only, with errors that are safe
3
+ * to print. Shared by every coding agent's config writer, revert and snapshot.
4
+ */
5
+ import { renameSync, rmSync, writeFileSync } from "node:fs";
6
+ /** A symlinked config is backed up beside its target, not beside the link. */
7
+ export function backupPathFor(paths, realPath) {
8
+ return realPath === paths.settings ? paths.backup : `${realPath}.bak`;
9
+ }
10
+ /**
11
+ * Turns an fs error into something safe to print. The code is translated rather
12
+ * than forwarded so no stack frame, errno struct or internal path escapes.
13
+ */
14
+ export function describeFsError(err) {
15
+ const code = err?.code;
16
+ switch (code) {
17
+ case "EACCES":
18
+ case "EPERM":
19
+ return "permission denied";
20
+ case "ENOSPC":
21
+ return "no space left on the device";
22
+ case "EROFS":
23
+ return "the filesystem is read-only";
24
+ case "EISDIR":
25
+ return "it is a directory, not a file";
26
+ default:
27
+ return "the write could not be completed";
28
+ }
29
+ }
30
+ /**
31
+ * Write via a sibling temp file and rename. The rename is atomic within a
32
+ * filesystem, so a reader either sees the old file or the new one — never a
33
+ * half-written config. The temp file is removed on any failure so a crashed run
34
+ * leaves no litter next to the real file.
35
+ */
36
+ export function atomicWrite(target, contents) {
37
+ // Same directory, so the rename cannot cross a filesystem boundary. The pid
38
+ // keeps two concurrent runs from fighting over one temp name.
39
+ const tmp = `${target}.${process.pid}.tmp`;
40
+ try {
41
+ // 0600: this file carries an API key.
42
+ writeFileSync(tmp, contents, { mode: 0o600 });
43
+ renameSync(tmp, target);
44
+ }
45
+ catch (err) {
46
+ rmSync(tmp, { force: true });
47
+ throw err;
48
+ }
49
+ }
50
+ //# sourceMappingURL=safeFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safeFile.js","sourceRoot":"","sources":["../../src/fs/safeFile.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAQ5D,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAC,KAAkB,EAAE,QAAgB;IAChE,OAAO,QAAQ,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,MAAM,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,MAAM,IAAI,GAAI,GAAyC,EAAE,IAAI,CAAC;IAC9D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO;YACV,OAAO,mBAAmB,CAAC;QAC7B,KAAK,QAAQ;YACX,OAAO,6BAA6B,CAAC;QACvC,KAAK,OAAO;YACV,OAAO,6BAA6B,CAAC;QACvC,KAAK,QAAQ;YACX,OAAO,+BAA+B,CAAC;QACzC;YACE,OAAO,kCAAkC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,QAAyB;IACnE,4EAA4E;IAC5E,8DAA8D;IAC9D,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IAC3C,IAAI,CAAC;QACH,sCAAsC;QACtC,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9C,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7B,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -1,4 +1,4 @@
1
- import { type ConfigPaths } from "./config.js";
1
+ import { type ConfigPaths } from "./safeFile.js";
2
2
  /** One file as it was: its bytes and mode, or the fact that it did not exist. */
3
3
  type FileState = {
4
4
  readonly path: string;
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { chmodSync, existsSync, lstatSync, readFileSync, readlinkSync, realpathSync, rmSync, statSync } from "node:fs";
8
8
  import { dirname, resolve } from "node:path";
9
- import { atomicWrite, backupPathFor, describeFsError } from "./config.js";
9
+ import { atomicWrite, backupPathFor, describeFsError } from "./safeFile.js";
10
10
  function capture(path) {
11
11
  if (!existsSync(path))
12
12
  return { path, present: false };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/fs/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACvH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAoB,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAe9F,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAEvD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC;AAClG,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,QAAgB;IACnC,IAAI,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;IAExD,IAAI,SAAS,CAAC,QAAQ,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC;QAC9E,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,cAAc,CAAC,KAAkB;IAC/C,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEjC,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;AACvG,CAAC;AAED,SAAS,GAAG,CAAC,KAAgB;IAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,OAAO;IACT,CAAC;IAED,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxC,wEAAwE;IACxE,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,aAAa,CAAC,QAAwB;IACpD,IAAI,CAAC;QACH,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACvB,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS;YAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1D,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC9B,CAAC"}
@@ -9,7 +9,7 @@
9
9
  * The secret goes in on stdin and comes out on stdout unchanged, so unlike macOS it needs
10
10
  * no encoding.
11
11
  */
12
- import { type PathLookup } from "../../verify.js";
12
+ import { type PathLookup } from "../../process.js";
13
13
  import type { SecretStore } from "../secretStore.js";
14
14
  import { type CommandRunner } from "./runner.js";
15
15
  export declare const SECRET_TOOL = "secret-tool";
@@ -9,7 +9,7 @@
9
9
  * The secret goes in on stdin and comes out on stdout unchanged, so unlike macOS it needs
10
10
  * no encoding.
11
11
  */
12
- import { findOnPath } from "../../verify.js";
12
+ import { findOnPath } from "../../process.js";
13
13
  import { KEYCHAIN_SERVICE, KEYCHAIN_TIMEOUT_MS, accountFor, failureReason } from "./runner.js";
14
14
  export const SECRET_TOOL = "secret-tool";
15
15
  /** How the entry is labelled in Seahorse or KWalletManager, for a human deleting it. */
@@ -1 +1 @@
1
- {"version":3,"file":"linux.js","sourceRoot":"","sources":["../../../src/login/keychain/linux.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,UAAU,EAAmB,MAAM,iBAAiB,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,UAAU,EAAE,aAAa,EAAsB,MAAM,aAAa,CAAC;AAEnH,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AAEzC,wFAAwF;AACxF,MAAM,KAAK,GAAG,kBAAkB,CAAC;AAWjC,gDAAgD;AAChD,MAAM,UAAU,KAAK,CAAC,SAA6B;IACjD,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/D,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,IAAuB;IACpD,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QAAE,OAAO,SAAS,CAAC;IAElF,OAAO,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAuB,EAAE,UAAkB;IAC5E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACjD,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,IAAgB,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IACrH,MAAM,GAAG,GAAG,CAAC,IAAuB,EAAE,KAAc,EAAE,EAAE,CACtD,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAExE,MAAM,IAAI,GAAG,KAAK,EAAE,OAAe,EAAE,IAAgB,EAA+B,EAAE;QACpF,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpE,qFAAqF;QACrF,IAAI,OAAO,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAEnF,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,EAAE;YAAE,OAAO,SAAS,CAAC;QAElE,uFAAuF;QACvF,OAAO,OAAO,CAAC,MAAM,CAAC;IACxB,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,UAAU;QAEhB,IAAI;QAEJ,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK;YAC9B,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAE5F,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9G,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI;YACxB,uFAAuF;YACvF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC3C,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YAEnD,OAAO,QAAQ,KAAK,SAAS,CAAC;QAChC,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"linux.js","sourceRoot":"","sources":["../../../src/login/keychain/linux.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,UAAU,EAAmB,MAAM,kBAAkB,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,UAAU,EAAE,aAAa,EAAsB,MAAM,aAAa,CAAC;AAEnH,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AAEzC,wFAAwF;AACxF,MAAM,KAAK,GAAG,kBAAkB,CAAC;AAWjC,gDAAgD;AAChD,MAAM,UAAU,KAAK,CAAC,SAA6B;IACjD,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/D,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,IAAuB;IACpD,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QAAE,OAAO,SAAS,CAAC;IAElF,OAAO,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAuB,EAAE,UAAkB;IAC5E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACjD,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,IAAgB,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IACrH,MAAM,GAAG,GAAG,CAAC,IAAuB,EAAE,KAAc,EAAE,EAAE,CACtD,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAExE,MAAM,IAAI,GAAG,KAAK,EAAE,OAAe,EAAE,IAAgB,EAA+B,EAAE;QACpF,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpE,qFAAqF;QACrF,IAAI,OAAO,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAEnF,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,EAAE;YAAE,OAAO,SAAS,CAAC;QAElE,uFAAuF;QACvF,OAAO,OAAO,CAAC,MAAM,CAAC;IACxB,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,UAAU;QAEhB,IAAI;QAEJ,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK;YAC9B,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAE5F,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9G,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI;YACxB,uFAAuF;YACvF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC3C,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YAEnD,OAAO,QAAQ,KAAK,SAAS,CAAC;QAChC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ export interface CommandResult {
2
+ /** `null` when the process was killed or could not be started at all. */
3
+ readonly code: number | null;
4
+ readonly timedOut: boolean;
5
+ /** Combined stdout+stderr, used only to explain a failure. */
6
+ readonly output: string;
7
+ }
8
+ /** Runs one executable with a hard time budget; never rejects. */
9
+ export type RunCommand = (executable: string, args: readonly string[], opts: {
10
+ readonly cwd: string;
11
+ readonly timeoutMs: number;
12
+ }) => Promise<CommandResult>;
13
+ export interface PathLookup {
14
+ readonly platform: string;
15
+ readonly processEnv: Record<string, string | undefined>;
16
+ /** Injected so the tier-1 tests never depend on what is installed. */
17
+ readonly isExecutableFile: (candidate: string) => boolean;
18
+ }
19
+ /**
20
+ * Hand-rolled rather than shelling out to `which`/`where`, which is slower and
21
+ * absent from stripped Windows images. `node:path`'s `join` and `delimiter` follow
22
+ * the *host* platform, so they cannot resolve a Windows PATH under test on macOS.
23
+ */
24
+ export declare function findOnPath(command: string, lookup: PathLookup): string | undefined;
25
+ export declare const runCommand: RunCommand;
26
+ export declare function isExecutableFile(candidate: string): boolean;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Finding and running local executables with a hard time budget. Shared by the coding
3
+ * agents (their own CLIs) and the Linux keychain (`secret-tool`).
4
+ */
5
+ import { spawn } from "node:child_process";
6
+ import { accessSync, constants, statSync } from "node:fs";
7
+ /** npm installs the Claude Code CLI as `claude.cmd`, so this must not be empty. */
8
+ const DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD";
9
+ /**
10
+ * Hand-rolled rather than shelling out to `which`/`where`, which is slower and
11
+ * absent from stripped Windows images. `node:path`'s `join` and `delimiter` follow
12
+ * the *host* platform, so they cannot resolve a Windows PATH under test on macOS.
13
+ */
14
+ export function findOnPath(command, lookup) {
15
+ const windows = lookup.platform === "win32";
16
+ const separator = windows ? ";" : ":";
17
+ const raw = lookup.processEnv.PATH ?? (windows ? lookup.processEnv.Path : undefined) ?? "";
18
+ const extensions = windows ? (lookup.processEnv.PATHEXT ?? DEFAULT_PATHEXT).split(";") : [""];
19
+ for (const dir of raw.split(separator)) {
20
+ if (dir === "")
21
+ continue;
22
+ for (const extension of extensions) {
23
+ const candidate = `${dir.replace(/[\\/]+$/, "")}${windows ? "\\" : "/"}${command}${extension}`;
24
+ if (lookup.isExecutableFile(candidate))
25
+ return candidate;
26
+ }
27
+ }
28
+ return undefined;
29
+ }
30
+ /** Cap on captured subprocess output — only the first line is ever quoted. */
31
+ const MAX_CAPTURED_OUTPUT = 4_096;
32
+ export const runCommand = (executable, args, opts) => {
33
+ return new Promise((resolve) => {
34
+ // A .cmd cannot be spawned without a shell since the CVE-2024-27980 fix. Safe
35
+ // here because every argument is a literal. Killing the shell may orphan the
36
+ // real `claude`, which exits on its own shortly after.
37
+ const shell = /\.(cmd|bat)$/i.test(executable);
38
+ const child = spawn(shell ? `"${executable}"` : executable, [...args], {
39
+ cwd: opts.cwd,
40
+ shell,
41
+ // stdin closed: `claude` must never sit waiting on input we will not send.
42
+ stdio: ["ignore", "pipe", "pipe"],
43
+ });
44
+ let output = "";
45
+ const capture = (chunk) => {
46
+ if (output.length < MAX_CAPTURED_OUTPUT)
47
+ output += chunk.toString("utf8");
48
+ };
49
+ child.stdout?.on("data", capture);
50
+ child.stderr?.on("data", capture);
51
+ let done = false;
52
+ const settle = (result) => {
53
+ if (done)
54
+ return;
55
+ done = true;
56
+ clearTimeout(timer);
57
+ resolve(result);
58
+ };
59
+ /**
60
+ * Our own timer, not spawn's `timeout`: Windows reports a killed process as an
61
+ * ordinary non-zero exit, so an inferred timeout would be wrong there.
62
+ *
63
+ * It resolves the promise itself rather than killing and waiting for `close`.
64
+ * `close` fires when the *stdio* closes, and anything `claude` spawned inherits
65
+ * those pipes — an MCP server or a hook outliving its parent holds them open, so
66
+ * the kill lands and `close` never comes. That hung the CLI indefinitely after a
67
+ * write it had already completed. The budget is now a guarantee, not a hope.
68
+ */
69
+ let timedOut = false;
70
+ const timer = setTimeout(() => {
71
+ timedOut = true;
72
+ child.kill("SIGKILL");
73
+ settle({ code: null, timedOut, output: output.trim() });
74
+ }, opts.timeoutMs);
75
+ // A spawn error may never emit `close`, so both paths settle. Only the errno is
76
+ // kept — the message carries an absolute path.
77
+ child.once("error", (err) => settle({ code: null, timedOut, output: err.code ?? "" }));
78
+ child.once("close", (code) => settle({ code, timedOut, output: output.trim() }));
79
+ });
80
+ };
81
+ export function isExecutableFile(candidate) {
82
+ try {
83
+ if (!statSync(candidate).isFile())
84
+ return false;
85
+ // The execute bit is meaningless on Windows, where the extension decides.
86
+ if (process.platform !== "win32")
87
+ accessSync(candidate, constants.X_OK);
88
+ return true;
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../src/process.ts"],"names":[],"mappings":"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"}
package/dist/report.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import type { ResolvedUrls } from "./args.js";
2
- import type { ConfigOutcome } from "./config.js";
2
+ import type { ConfigOutcome, RevertOutcome, Warning } from "./agents/types.js";
3
3
  import type { PrecheckOutcome } from "./precheck.js";
4
- import type { RevertOutcome } from "./revert.js";
5
- import type { MissingCredential, VerifyOutcome } from "./verify.js";
4
+ import type { MissingCredential, VerifyOutcome } from "./agents/claude-code/verify.js";
6
5
  import { type RunResult } from "./result.js";
7
6
  /**
8
7
  * Outcome name → exit code. This is the map `--json` consumers branch on, so the
@@ -27,11 +26,7 @@ export interface ColorTargets {
27
26
  /** `NOTHING_WRITTEN`, painted for stderr — the stream every refusal that says it lands on. */
28
27
  export declare function nothingWasWritten(streams?: ColorTargets): string;
29
28
  export declare function reportRevert(outcome: RevertOutcome, json: boolean, streams?: ColorTargets): RunResult;
30
- export interface Warning {
31
- /** Stable identifier, so `--json` consumers match on this and not on prose. */
32
- readonly code: "anthropic-api-key-set" | "shadowed-by-local-config" | "non-production-gateway" | "insecure-gateway" | "verification-skipped" | "verification-failed" | "key-check-inconclusive";
33
- readonly message: string;
34
- }
29
+ export type { Warning } from "./agents/types.js";
35
30
  export interface WarningContext {
36
31
  readonly urls: ResolvedUrls;
37
32
  /** The process environment, injected so tests need not mutate the real one. */