@claudexor/cli 3.0.3 → 3.1.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.
- package/LICENSE +1 -1
- package/dist/about-command.d.ts +32 -0
- package/dist/about-command.d.ts.map +1 -0
- package/dist/about-command.js +40 -0
- package/dist/about-command.js.map +1 -0
- package/dist/acp-surface-runner.d.ts +12 -0
- package/dist/acp-surface-runner.d.ts.map +1 -1
- package/dist/acp-surface-runner.js +113 -11
- package/dist/acp-surface-runner.js.map +1 -1
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +2 -1
- package/dist/capabilities.js.map +1 -1
- package/dist/claudexord.d.ts +21 -0
- package/dist/claudexord.d.ts.map +1 -1
- package/dist/claudexord.js +96 -8
- package/dist/claudexord.js.map +1 -1
- package/dist/cli-error.d.ts +97 -0
- package/dist/cli-error.d.ts.map +1 -0
- package/dist/cli-error.js +308 -0
- package/dist/cli-error.js.map +1 -0
- package/dist/cli-io.d.ts +9 -0
- package/dist/cli-io.d.ts.map +1 -1
- package/dist/cli-io.js +10 -1
- package/dist/cli-io.js.map +1 -1
- package/dist/cli.js +105 -110
- package/dist/cli.js.map +1 -1
- package/dist/codex-device-login.d.ts +117 -0
- package/dist/codex-device-login.d.ts.map +1 -0
- package/dist/codex-device-login.js +227 -0
- package/dist/codex-device-login.js.map +1 -0
- package/dist/command-flags.d.ts.map +1 -1
- package/dist/command-flags.js +4 -3
- package/dist/command-flags.js.map +1 -1
- package/dist/command-help.d.ts +46 -0
- package/dist/command-help.d.ts.map +1 -0
- package/dist/command-help.js +92 -0
- package/dist/command-help.js.map +1 -0
- package/dist/command-registry.d.ts +2 -0
- package/dist/command-registry.d.ts.map +1 -1
- package/dist/command-registry.js +11 -4
- package/dist/command-registry.js.map +1 -1
- package/dist/control-services.d.ts +45 -18
- package/dist/control-services.d.ts.map +1 -1
- package/dist/control-services.js +56 -30
- package/dist/control-services.js.map +1 -1
- package/dist/credential-commands.d.ts.map +1 -1
- package/dist/credential-commands.js +44 -1
- package/dist/credential-commands.js.map +1 -1
- package/dist/daemon-outcome.d.ts +24 -0
- package/dist/daemon-outcome.d.ts.map +1 -0
- package/dist/daemon-outcome.js +59 -0
- package/dist/daemon-outcome.js.map +1 -0
- package/dist/daemon-run.d.ts +23 -4
- package/dist/daemon-run.d.ts.map +1 -1
- package/dist/daemon-run.js +66 -27
- package/dist/daemon-run.js.map +1 -1
- package/dist/delegation-belt-descriptor.d.ts +31 -13
- package/dist/delegation-belt-descriptor.d.ts.map +1 -1
- package/dist/delegation-belt-descriptor.js +43 -15
- package/dist/delegation-belt-descriptor.js.map +1 -1
- package/dist/live.d.ts +13 -1
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +56 -7
- package/dist/live.js.map +1 -1
- package/dist/mcp-runner.d.ts.map +1 -1
- package/dist/mcp-runner.js +60 -6
- package/dist/mcp-runner.js.map +1 -1
- package/dist/native-login.d.ts +10 -1
- package/dist/native-login.d.ts.map +1 -1
- package/dist/native-login.js +32 -10
- package/dist/native-login.js.map +1 -1
- package/dist/ops-commands.d.ts.map +1 -1
- package/dist/ops-commands.js +42 -51
- package/dist/ops-commands.js.map +1 -1
- package/dist/plan-implement-readiness.d.ts +32 -0
- package/dist/plan-implement-readiness.d.ts.map +1 -0
- package/dist/plan-implement-readiness.js +51 -0
- package/dist/plan-implement-readiness.js.map +1 -0
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +73 -20
- package/dist/plugins.js.map +1 -1
- package/dist/project-command.d.ts +15 -0
- package/dist/project-command.d.ts.map +1 -1
- package/dist/project-command.js +75 -20
- package/dist/project-command.js.map +1 -1
- package/dist/quota-command.d.ts.map +1 -1
- package/dist/quota-command.js +2 -6
- package/dist/quota-command.js.map +1 -1
- package/dist/release-command.d.ts.map +1 -1
- package/dist/release-command.js +31 -6
- package/dist/release-command.js.map +1 -1
- package/dist/release.d.ts +41 -10
- package/dist/release.d.ts.map +1 -1
- package/dist/release.js +70 -48
- package/dist/release.js.map +1 -1
- package/dist/repo-asset-authority.d.ts +93 -0
- package/dist/repo-asset-authority.d.ts.map +1 -0
- package/dist/repo-asset-authority.js +178 -0
- package/dist/repo-asset-authority.js.map +1 -0
- package/dist/review-command.d.ts.map +1 -1
- package/dist/review-command.js +2 -6
- package/dist/review-command.js.map +1 -1
- package/dist/settings-command.d.ts.map +1 -1
- package/dist/settings-command.js +2 -6
- package/dist/settings-command.js.map +1 -1
- package/dist/settings-service.d.ts +51 -2
- package/dist/settings-service.d.ts.map +1 -1
- package/dist/settings-service.js +126 -2
- package/dist/settings-service.js.map +1 -1
- package/dist/setup-job-store.d.ts +14 -3
- package/dist/setup-job-store.d.ts.map +1 -1
- package/dist/setup-job-store.js +24 -4
- package/dist/setup-job-store.js.map +1 -1
- package/dist/setup-jobs.d.ts +14 -4
- package/dist/setup-jobs.d.ts.map +1 -1
- package/dist/setup-jobs.js +204 -23
- package/dist/setup-jobs.js.map +1 -1
- package/dist/setup-login-inline.d.ts +69 -0
- package/dist/setup-login-inline.d.ts.map +1 -0
- package/dist/setup-login-inline.js +206 -0
- package/dist/setup-login-inline.js.map +1 -0
- package/dist/setup-login-protocol.d.ts +3 -2
- package/dist/setup-login-protocol.d.ts.map +1 -1
- package/dist/setup-login-protocol.js +16 -1
- package/dist/setup-login-protocol.js.map +1 -1
- package/dist/setup-login-runner.d.ts +9 -0
- package/dist/setup-login-runner.d.ts.map +1 -1
- package/dist/setup-login-runner.js +212 -5
- package/dist/setup-login-runner.js.map +1 -1
- package/dist/thread-delivery.d.ts.map +1 -1
- package/dist/thread-delivery.js +3 -1
- package/dist/thread-delivery.js.map +1 -1
- package/package.json +23 -23
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D-17: inline CLI presentation of a durable codex device-code login job.
|
|
3
|
+
*
|
|
4
|
+
* Both `claudexor auth login codex` and `claudexor profiles login codex <id>`
|
|
5
|
+
* ride the SAME daemon-owned setup job; this helper polls the job snapshot,
|
|
6
|
+
* shows the one-time code + verification URL as soon as the runner discloses
|
|
7
|
+
* them (transient, from the snapshot overlay — never journaled), and follows
|
|
8
|
+
* the job to its typed terminal outcome. Ctrl-C detaches the CLI; the daemon
|
|
9
|
+
* runner keeps the login alive.
|
|
10
|
+
*/
|
|
11
|
+
import { createInterface } from "node:readline/promises";
|
|
12
|
+
import { ControlSetupJob, ControlSetupJobSnapshot, isTerminalControlSetupJobState, } from "@claudexor/schema";
|
|
13
|
+
import { print, printJson } from "./cli-io.js";
|
|
14
|
+
import { controlApiFetch } from "./live.js";
|
|
15
|
+
const POLL_MS = 1_000;
|
|
16
|
+
const NEGATIVE_TERMINAL_STATES = ["failed", "cancelled", "timed_out", "not_supported"];
|
|
17
|
+
/** The typed next action for a terminal job, or null for an ordinary outcome. */
|
|
18
|
+
export function terminalLoginFallback(job) {
|
|
19
|
+
if (job.state === "not_supported" && job.nativeCommand?.errorCode === "device_auth_unsupported") {
|
|
20
|
+
return {
|
|
21
|
+
kind: "terminal_login_fallback",
|
|
22
|
+
reason: "device_auth_unsupported",
|
|
23
|
+
loginFlow: "browser_redirect",
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* D-17 audit point 8: the terminal report for a durable codex login. The
|
|
30
|
+
* `not_supported` state is actionable, not a dead-end message: when the daemon
|
|
31
|
+
* carries the consistent typed code `device_auth_unsupported` on the
|
|
32
|
+
* native-command receipt (the SAME code the runner result, journal, control
|
|
33
|
+
* DTO, and Swift surface use), the CLI names the code AND the exact next step
|
|
34
|
+
* (the legacy Terminal sign-in), and exits non-zero. Used for the non-TTY /
|
|
35
|
+
* declined path; a TTY OFFERS the transition directly (see below).
|
|
36
|
+
*/
|
|
37
|
+
export function terminalLoginReport(job, label, target = {}) {
|
|
38
|
+
if (terminalLoginFallback(job)) {
|
|
39
|
+
return {
|
|
40
|
+
lines: [
|
|
41
|
+
`${label} login not_supported (device_auth_unsupported): this codex build has no in-app device-code sign-in.`,
|
|
42
|
+
target.profileId
|
|
43
|
+
? "Next: retry this profile with the legacy Terminal sign-in (the browser-redirect flow)."
|
|
44
|
+
: "Next: run `claudexor auth login codex --browser-redirect` for the Terminal sign-in.",
|
|
45
|
+
],
|
|
46
|
+
exitCode: 1,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
lines: [`${label} login ${job.state}: ${job.message}`],
|
|
51
|
+
exitCode: job.state === "succeeded" ? 0 : 1,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Default TTY yes/no prompt. Declines (false) when stdin is not a TTY so a
|
|
55
|
+
* non-interactive pipe never blocks waiting for an answer. */
|
|
56
|
+
async function defaultPromptYesNo(question) {
|
|
57
|
+
if (!process.stdin.isTTY)
|
|
58
|
+
return false;
|
|
59
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
60
|
+
try {
|
|
61
|
+
const answer = (await rl.question(question)).trim().toLowerCase();
|
|
62
|
+
return answer === "y" || answer === "yes";
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
rl.close();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create the legacy Terminal (browser_redirect) login for the same target. This
|
|
70
|
+
* rides the daemon's existing duplicate-create / 409 semantics: the prior
|
|
71
|
+
* device-code job is already terminal (not_supported), so no conflict blocks
|
|
72
|
+
* it, and a real conflict surfaces the daemon's reason rather than silently
|
|
73
|
+
* starting a duplicate.
|
|
74
|
+
*/
|
|
75
|
+
async function createTerminalFallbackJob(fetchImpl, target, label) {
|
|
76
|
+
const response = await fetchImpl("/setup/jobs", {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers: { "Content-Type": "application/json" },
|
|
79
|
+
body: JSON.stringify({
|
|
80
|
+
harness: target.harness,
|
|
81
|
+
action: "login",
|
|
82
|
+
authRequest: "subscription",
|
|
83
|
+
loginFlow: "browser_redirect",
|
|
84
|
+
...(target.profileId ? { profileId: target.profileId } : {}),
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
print(`could not start the Terminal ${label} sign-in (${response.status}): ${await response.text()}`);
|
|
89
|
+
return 1;
|
|
90
|
+
}
|
|
91
|
+
const job = ControlSetupJob.parse(await response.json());
|
|
92
|
+
const accepted = !NEGATIVE_TERMINAL_STATES.includes(job.state);
|
|
93
|
+
print(accepted
|
|
94
|
+
? `Opening the Terminal ${label} sign-in (managed by claudexord as ${job.jobId}). Complete it in the Terminal window that opens.`
|
|
95
|
+
: `Terminal ${label} sign-in was not started: ${job.message}`);
|
|
96
|
+
return accepted ? 0 : 1;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Poll a device-code login job. In TTY mode it prints the one-time code once
|
|
100
|
+
* and follows the job to its terminal outcome; on a device_auth_unsupported
|
|
101
|
+
* miss it OFFERS the legacy Terminal sign-in (a y/N prompt that, on yes, starts
|
|
102
|
+
* the browser_redirect job in one action). In `--json` mode it emits one JSON
|
|
103
|
+
* object: the transient disclosure (so a caller can complete the sign-in), the
|
|
104
|
+
* terminal outcome (with a typed `nextAction` on the fallback), or a
|
|
105
|
+
* detached/error envelope. Returns the process exit code (0 on success).
|
|
106
|
+
*/
|
|
107
|
+
export async function streamDurableCodexLogin(addr, jobId, opts = { label: "codex" }) {
|
|
108
|
+
const { label } = opts;
|
|
109
|
+
const json = opts.json ?? false;
|
|
110
|
+
const pollMs = opts.pollMs ?? POLL_MS;
|
|
111
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((done) => setTimeout(done, ms)));
|
|
112
|
+
const fetchImpl = opts.fetchImpl ?? ((path, init) => controlApiFetch(addr, path, init));
|
|
113
|
+
const promptYesNo = opts.promptYesNo ?? defaultPromptYesNo;
|
|
114
|
+
let disclosed = false;
|
|
115
|
+
let detached = false;
|
|
116
|
+
const onSigint = () => {
|
|
117
|
+
detached = true;
|
|
118
|
+
};
|
|
119
|
+
process.once("SIGINT", onSigint);
|
|
120
|
+
try {
|
|
121
|
+
for (;;) {
|
|
122
|
+
if (detached) {
|
|
123
|
+
if (json) {
|
|
124
|
+
printJson({ ok: true, detached: true, jobId });
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
print(`Detached. ${label} login keeps running as ${jobId}; ` +
|
|
128
|
+
`re-attach with \`claudexor auth status\` or finish it in the browser.`);
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
const response = await fetchImpl(`/setup/jobs/${encodeURIComponent(jobId)}/snapshot`);
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
if (json) {
|
|
134
|
+
printJson({ ok: false, error: "snapshot_unavailable", status: response.status, jobId });
|
|
135
|
+
return 1;
|
|
136
|
+
}
|
|
137
|
+
print(`could not read ${label} login status (${response.status}); it keeps running as ${jobId}`);
|
|
138
|
+
return 1;
|
|
139
|
+
}
|
|
140
|
+
const snapshot = ControlSetupJobSnapshot.parse(await response.json());
|
|
141
|
+
const job = snapshot.job;
|
|
142
|
+
const terminal = isTerminalControlSetupJobState(job.state);
|
|
143
|
+
if (json) {
|
|
144
|
+
// Return promptly once we know the flow's shape: a disclosure means the
|
|
145
|
+
// app-server supports device-code (hand the caller the code/URL); a
|
|
146
|
+
// terminal state (e.g. the fast device_auth_unsupported miss) carries
|
|
147
|
+
// the typed nextAction. This keeps `--json` bounded — it never blocks
|
|
148
|
+
// waiting for a human to finish the browser step.
|
|
149
|
+
if (!terminal && snapshot.deviceCode) {
|
|
150
|
+
printJson({
|
|
151
|
+
ok: true,
|
|
152
|
+
job,
|
|
153
|
+
deviceCode: {
|
|
154
|
+
flow: snapshot.deviceCode.flow,
|
|
155
|
+
verificationUrl: snapshot.deviceCode.verificationUrl,
|
|
156
|
+
userCode: snapshot.deviceCode.userCode,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
if (terminal) {
|
|
162
|
+
const nextAction = terminalLoginFallback(job);
|
|
163
|
+
printJson({ ok: job.state === "succeeded", job, ...(nextAction ? { nextAction } : {}) });
|
|
164
|
+
return job.state === "succeeded" ? 0 : 1;
|
|
165
|
+
}
|
|
166
|
+
await sleep(pollMs);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
// TTY mode.
|
|
170
|
+
if (snapshot.deviceCode && !disclosed) {
|
|
171
|
+
disclosed = true;
|
|
172
|
+
print("");
|
|
173
|
+
print(`Open: ${snapshot.deviceCode.verificationUrl}`);
|
|
174
|
+
if (snapshot.deviceCode.userCode)
|
|
175
|
+
print(`Code: ${snapshot.deviceCode.userCode}`);
|
|
176
|
+
print(`Waiting for OpenAI… (Ctrl-C detaches; the login keeps running)`);
|
|
177
|
+
print("");
|
|
178
|
+
}
|
|
179
|
+
if (terminal) {
|
|
180
|
+
// device_auth_unsupported is a real fork, not a dead end: OFFER to start
|
|
181
|
+
// the legacy Terminal sign-in in one action (explicit y/N — never a
|
|
182
|
+
// silent fallback). Declining, or a non-TTY, falls back to the typed
|
|
183
|
+
// report that names the exact next command.
|
|
184
|
+
if (opts.fallback && terminalLoginFallback(job)) {
|
|
185
|
+
print(`${label} login not_supported (device_auth_unsupported): this codex build has no in-app device-code sign-in.`);
|
|
186
|
+
const yes = await promptYesNo("Start the legacy Terminal (browser-redirect) sign-in now? [y/N] ");
|
|
187
|
+
if (yes)
|
|
188
|
+
return await createTerminalFallbackJob(fetchImpl, opts.fallback, label);
|
|
189
|
+
print(opts.fallback.profileId
|
|
190
|
+
? "You can retry this profile with the legacy Terminal (browser-redirect) sign-in later."
|
|
191
|
+
: "You can start it later with `claudexor auth login codex --browser-redirect`.");
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
const report = terminalLoginReport(job, label, { profileId: opts.fallback?.profileId });
|
|
195
|
+
for (const line of report.lines)
|
|
196
|
+
print(line);
|
|
197
|
+
return report.exitCode;
|
|
198
|
+
}
|
|
199
|
+
await sleep(pollMs);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
process.removeListener("SIGINT", onSigint);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=setup-login-inline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-login-inline.js","sourceRoot":"","sources":["../src/setup-login-inline.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type SetupLoginManifest, type SetupLoginPermit, type SetupLoginRunnerResult, type SetupLoginRunnerState, type SetupExecutableEvidence, type SetupProcessGroupHandle } from "@claudexor/schema";
|
|
2
|
-
export type { SetupLoginManifest, SetupLoginPermit, SetupLoginRunnerResult, SetupLoginRunnerState, SetupProcessGroupHandle, SetupExecutableEvidence, };
|
|
1
|
+
import { type SetupLoginDeviceCode, type SetupLoginManifest, type SetupLoginPermit, type SetupLoginRunnerResult, type SetupLoginRunnerState, type SetupExecutableEvidence, type SetupProcessGroupHandle } from "@claudexor/schema";
|
|
2
|
+
export type { SetupLoginDeviceCode, SetupLoginManifest, SetupLoginPermit, SetupLoginRunnerResult, SetupLoginRunnerState, SetupProcessGroupHandle, SetupExecutableEvidence, };
|
|
3
3
|
export declare const SETUP_LOGIN_PROTOCOL_VERSION: 2;
|
|
4
4
|
export declare function readLoginManifest(path: string): SetupLoginManifest;
|
|
5
5
|
export declare function captureExecutableEvidence(path: string): SetupExecutableEvidence;
|
|
@@ -9,5 +9,6 @@ export declare function verifyExecutableEvidence(expected: SetupExecutableEviden
|
|
|
9
9
|
export declare function readRunnerState(path: string): SetupLoginRunnerState | null;
|
|
10
10
|
export declare function readRunnerResult(path: string): SetupLoginRunnerResult | null;
|
|
11
11
|
export declare function readRunnerPermit(path: string): SetupLoginPermit | null;
|
|
12
|
+
export declare function readRunnerDeviceCode(path: string): SetupLoginDeviceCode | null;
|
|
12
13
|
export declare function atomicPrivateJson(path: string, value: unknown): void;
|
|
13
14
|
//# sourceMappingURL=setup-login-protocol.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-login-protocol.d.ts","sourceRoot":"","sources":["../src/setup-login-protocol.ts"],"names":[],"mappings":"AAiBA,OAAO,
|
|
1
|
+
{"version":3,"file":"setup-login-protocol.d.ts","sourceRoot":"","sources":["../src/setup-login-protocol.ts"],"names":[],"mappings":"AAiBA,OAAO,EAML,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC7B,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,GACxB,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAG,CAAU,CAAC;AAGvD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CA4ClE;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,CAqB/E;AAED,wBAAgB,aAAa,CAC3B,UAAU,EAAE,uBAAuB,EACnC,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,MAAM,CAIR;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,GAChD,kBAAkB,CAGpB;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,OAAO,CAQnF;AAiBD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAM1E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAM5E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAMtE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAM9E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CA+BpE"}
|
|
@@ -2,7 +2,7 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { closeSync, constants, fchmodSync, fstatSync, fsyncSync, lstatSync, openSync, readFileSync, realpathSync, renameSync, rmSync, writeSync, } from "node:fs";
|
|
3
3
|
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
4
4
|
import { withExecutableInspection, isBoundedRegularExecutable } from "@claudexor/core";
|
|
5
|
-
import { SetupLoginManifest as SetupLoginManifestSchema, SetupLoginPermit as SetupLoginPermitSchema, SetupLoginRunnerResult as SetupLoginRunnerResultSchema, SetupLoginRunnerState as SetupLoginRunnerStateSchema, } from "@claudexor/schema";
|
|
5
|
+
import { SetupLoginDeviceCode as SetupLoginDeviceCodeSchema, SetupLoginManifest as SetupLoginManifestSchema, SetupLoginPermit as SetupLoginPermitSchema, SetupLoginRunnerResult as SetupLoginRunnerResultSchema, SetupLoginRunnerState as SetupLoginRunnerStateSchema, } from "@claudexor/schema";
|
|
6
6
|
export const SETUP_LOGIN_PROTOCOL_VERSION = 2;
|
|
7
7
|
const MAX_SIDECAR_BYTES = 1024 * 1024;
|
|
8
8
|
export function readLoginManifest(path) {
|
|
@@ -32,6 +32,13 @@ export function readLoginManifest(path) {
|
|
|
32
32
|
basename(manifest.permitPath) !== "runner-permit.json") {
|
|
33
33
|
throw new Error("setup-login sidecar path escapes or relocates its daemon-owned job directory");
|
|
34
34
|
}
|
|
35
|
+
if (manifest.deviceCodePath !== undefined) {
|
|
36
|
+
const deviceCodeParent = realpathSync(dirname(resolve(manifest.deviceCodePath)));
|
|
37
|
+
if (deviceCodeParent !== jobDir ||
|
|
38
|
+
basename(manifest.deviceCodePath) !== "runner-devicecode.json") {
|
|
39
|
+
throw new Error("setup-login device-code sidecar escapes or relocates its daemon-owned job directory");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
35
42
|
const cwd = realpathSync(manifest.cwd);
|
|
36
43
|
if (cwd !== jobDir && !cwd.startsWith(jobDir + sep))
|
|
37
44
|
throw new Error("setup-login cwd escapes its job directory");
|
|
@@ -113,6 +120,14 @@ export function readRunnerPermit(path) {
|
|
|
113
120
|
return null;
|
|
114
121
|
}
|
|
115
122
|
}
|
|
123
|
+
export function readRunnerDeviceCode(path) {
|
|
124
|
+
try {
|
|
125
|
+
return SetupLoginDeviceCodeSchema.parse(readPrivateJson(path));
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
116
131
|
export function atomicPrivateJson(path, value) {
|
|
117
132
|
const absolute = resolve(path);
|
|
118
133
|
const parent = dirname(absolute);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-login-protocol.js","sourceRoot":"","sources":["../src/setup-login-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,MAAM,EACN,SAAS,GACV,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AACvF,OAAO,EACL,kBAAkB,IAAI,wBAAwB,EAC9C,gBAAgB,IAAI,sBAAsB,EAC1C,sBAAsB,IAAI,4BAA4B,EACtD,qBAAqB,IAAI,2BAA2B,
|
|
1
|
+
{"version":3,"file":"setup-login-protocol.js","sourceRoot":"","sources":["../src/setup-login-protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,4 +17,13 @@ export interface SetupLoginRunnerOptions {
|
|
|
17
17
|
export declare function runSetupLogin(manifestPath: string, options?: SetupLoginRunnerOptions): Promise<number>;
|
|
18
18
|
/** Worker entrypoint. Exported so the permit ordering can be fault-injected. */
|
|
19
19
|
export declare function runSetupLoginWorker(manifestPath: string, options?: SetupLoginRunnerOptions): Promise<number>;
|
|
20
|
+
/** Ring buffer of the last OUTPUT_TAIL_BYTES of tee'd vendor output. */
|
|
21
|
+
export declare function createTailBuffer(): {
|
|
22
|
+
push(chunk: Buffer): void;
|
|
23
|
+
text(): string;
|
|
24
|
+
};
|
|
25
|
+
/** Strip terminal escapes (CSI, OSC, bare ESC, C0 controls except newline),
|
|
26
|
+
* redact secret-like tokens, and clamp - diagnostic evidence entering a
|
|
27
|
+
* durable journal/API surface, never a raw vendor log copy (INV-062). */
|
|
28
|
+
export declare function boundedTail(text: string, truncated?: boolean): string;
|
|
20
29
|
//# sourceMappingURL=setup-login-runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-login-runner.d.ts","sourceRoot":"","sources":["../src/setup-login-runner.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"setup-login-runner.d.ts","sourceRoot":"","sources":["../src/setup-login-runner.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAwC,MAAM,oBAAoB,CAAC;AAKjF,OAAO,EACL,mBAAmB,EAGpB,MAAM,iBAAiB,CAAC;AAsBzB,MAAM,WAAW,uBAAuB;IACtC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,YAAY,CAAC,EAAE,OAAO,KAAK,CAAC;IAC5B,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED,gFAAgF;AAChF,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,MAAM,CAAC,CAiKjB;AA4KD,wEAAwE;AACxE,wBAAgB,gBAAgB,IAAI;IAAE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,IAAI,MAAM,CAAA;CAAE,CAuBhF;AAED;;yEAEyE;AACzE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,MAAM,CAiBnE"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
|
+
import { createInterface } from "node:readline";
|
|
4
5
|
import { dirname, resolve, sep } from "node:path";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
import { defaultProcessGroupService, } from "@claudexor/core";
|
|
7
8
|
import { redactSecrets } from "@claudexor/util";
|
|
9
|
+
import { startCodexDeviceLogin, } from "./codex-device-login.js";
|
|
8
10
|
import { nativeLoginEnv } from "./native-login.js";
|
|
9
11
|
import { SETUP_LOGIN_PROTOCOL_VERSION, atomicPrivateJson, readLoginManifest, readRunnerPermit, verifyExecutableEvidence, } from "./setup-login-protocol.js";
|
|
10
12
|
const PERMIT_POLL_MS = 50;
|
|
@@ -73,6 +75,13 @@ export async function runSetupLoginWorker(manifestPath, options = {}) {
|
|
|
73
75
|
return 1;
|
|
74
76
|
}
|
|
75
77
|
atomicPrivateJson(manifest.statePath, { ...awaitingPermit, stage: "running" });
|
|
78
|
+
// D-17 primary flow: host the codex app-server and drive typed device-code
|
|
79
|
+
// auth (no Terminal). The app-server child shares this detached worker's
|
|
80
|
+
// process group, so every restart/permit/termination evidence semantic is
|
|
81
|
+
// unchanged from the Terminal path.
|
|
82
|
+
if (manifest.loginMode === "device_code") {
|
|
83
|
+
return runDeviceCodeLogin(manifest, permit, { now, spawnProcess });
|
|
84
|
+
}
|
|
76
85
|
// Device-auth capability gate (v3.0.3 S6): `--device-auth` exists only
|
|
77
86
|
// since codex 0.46.0. Probe the vendor's own `login --help` BEFORE spawning
|
|
78
87
|
// so an old CLI yields a typed unsupported outcome instead of an opaque
|
|
@@ -172,16 +181,190 @@ export async function runSetupLoginWorker(manifestPath, options = {}) {
|
|
|
172
181
|
});
|
|
173
182
|
return result.code === 0 && result.signal === null ? 0 : 1;
|
|
174
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* D-17 device-code login: host `codex app-server --stdio`, drive the typed
|
|
186
|
+
* device-code handshake, and write the transient disclosure sidecar (the
|
|
187
|
+
* one-time code lives ONLY there and is never persisted to the result receipt).
|
|
188
|
+
* Completion → exit 0 (the daemon then runs the unchanged native verification);
|
|
189
|
+
* a capability probe miss → `device_auth_unsupported` (the daemon demotes to
|
|
190
|
+
* the typed Terminal fallback, no stdout regex).
|
|
191
|
+
*/
|
|
192
|
+
async function runDeviceCodeLogin(manifest, permit, deps) {
|
|
193
|
+
const { now, spawnProcess } = deps;
|
|
194
|
+
if (!manifest.deviceCodePath || !manifest.appServerFlow) {
|
|
195
|
+
persistResult(manifest, {
|
|
196
|
+
permitIssuedAt: permit.issuedAt,
|
|
197
|
+
commandStarted: false,
|
|
198
|
+
errorCode: "spawn_failed",
|
|
199
|
+
exitCode: null,
|
|
200
|
+
signal: null,
|
|
201
|
+
finishedAt: now().toISOString(),
|
|
202
|
+
});
|
|
203
|
+
return 1;
|
|
204
|
+
}
|
|
205
|
+
let child;
|
|
206
|
+
try {
|
|
207
|
+
child = spawnProcess(manifest.binary, manifest.args, {
|
|
208
|
+
cwd: manifest.cwd,
|
|
209
|
+
env: nativeLoginEnv(manifest.harness, process.env, manifest.profileConfigDir),
|
|
210
|
+
detached: false,
|
|
211
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
persistResult(manifest, {
|
|
216
|
+
permitIssuedAt: permit.issuedAt,
|
|
217
|
+
commandStarted: false,
|
|
218
|
+
errorCode: "spawn_failed",
|
|
219
|
+
exitCode: null,
|
|
220
|
+
signal: null,
|
|
221
|
+
finishedAt: now().toISOString(),
|
|
222
|
+
});
|
|
223
|
+
return 1;
|
|
224
|
+
}
|
|
225
|
+
child.stderr?.resume();
|
|
226
|
+
const connection = appServerConnection(child);
|
|
227
|
+
const abort = new AbortController();
|
|
228
|
+
const onSignal = () => abort.abort();
|
|
229
|
+
process.on("SIGTERM", onSignal);
|
|
230
|
+
process.on("SIGINT", onSignal);
|
|
231
|
+
const killChild = () => {
|
|
232
|
+
try {
|
|
233
|
+
child.kill("SIGTERM");
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
/* best-effort */
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
try {
|
|
240
|
+
const start = await startCodexDeviceLogin(connection, {
|
|
241
|
+
flow: manifest.appServerFlow,
|
|
242
|
+
signal: abort.signal,
|
|
243
|
+
});
|
|
244
|
+
if (start.kind === "not_supported") {
|
|
245
|
+
killChild();
|
|
246
|
+
// Typed capability-probe miss: reuse the existing not_supported outcome
|
|
247
|
+
// so the daemon offers the legacy Terminal fallback (no stdout regex).
|
|
248
|
+
persistResult(manifest, {
|
|
249
|
+
permitIssuedAt: permit.issuedAt,
|
|
250
|
+
commandStarted: false,
|
|
251
|
+
errorCode: "device_auth_unsupported",
|
|
252
|
+
exitCode: null,
|
|
253
|
+
signal: null,
|
|
254
|
+
finishedAt: now().toISOString(),
|
|
255
|
+
});
|
|
256
|
+
return 1;
|
|
257
|
+
}
|
|
258
|
+
// Transient disclosure sidecar. The userCode rides ONLY this file (read-time
|
|
259
|
+
// snapshot projection); it never enters the result receipt or the journal.
|
|
260
|
+
atomicPrivateJson(manifest.deviceCodePath, {
|
|
261
|
+
version: SETUP_LOGIN_PROTOCOL_VERSION,
|
|
262
|
+
jobId: manifest.jobId,
|
|
263
|
+
executionId: manifest.executionId,
|
|
264
|
+
flow: manifest.appServerFlow,
|
|
265
|
+
verificationUrl: start.disclosure.verificationUrl,
|
|
266
|
+
userCode: start.disclosure.userCode,
|
|
267
|
+
disclosedAt: now().toISOString(),
|
|
268
|
+
});
|
|
269
|
+
const outcome = await start.awaitCompletion();
|
|
270
|
+
killChild();
|
|
271
|
+
if (outcome.kind === "completed") {
|
|
272
|
+
persistResult(manifest, {
|
|
273
|
+
permitIssuedAt: permit.issuedAt,
|
|
274
|
+
commandStarted: true,
|
|
275
|
+
exitCode: 0,
|
|
276
|
+
signal: null,
|
|
277
|
+
finishedAt: now().toISOString(),
|
|
278
|
+
});
|
|
279
|
+
return 0;
|
|
280
|
+
}
|
|
281
|
+
persistResult(manifest, {
|
|
282
|
+
permitIssuedAt: permit.issuedAt,
|
|
283
|
+
commandStarted: true,
|
|
284
|
+
exitCode: 1,
|
|
285
|
+
signal: null,
|
|
286
|
+
finishedAt: now().toISOString(),
|
|
287
|
+
...(outcome.kind === "failed" ? { outputTail: boundedTail(outcome.detail) } : {}),
|
|
288
|
+
});
|
|
289
|
+
return 1;
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
killChild();
|
|
293
|
+
persistResult(manifest, {
|
|
294
|
+
permitIssuedAt: permit.issuedAt,
|
|
295
|
+
commandStarted: true,
|
|
296
|
+
exitCode: 1,
|
|
297
|
+
signal: null,
|
|
298
|
+
finishedAt: now().toISOString(),
|
|
299
|
+
outputTail: boundedTail(error instanceof Error ? error.message : String(error)),
|
|
300
|
+
});
|
|
301
|
+
return 1;
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
process.off("SIGTERM", onSignal);
|
|
305
|
+
process.off("SIGINT", onSignal);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/** Adapt a `codex app-server --stdio` child to the device-login transport seam
|
|
309
|
+
* (line-delimited JSON-RPC over the child's stdio). */
|
|
310
|
+
function appServerConnection(child) {
|
|
311
|
+
const lines = createInterface({ input: child.stdout });
|
|
312
|
+
let frameHandler = null;
|
|
313
|
+
const closeHandlers = [];
|
|
314
|
+
lines.on("line", (line) => {
|
|
315
|
+
let frame;
|
|
316
|
+
try {
|
|
317
|
+
frame = JSON.parse(line);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
return; // Vendor diagnostics are not protocol authority.
|
|
321
|
+
}
|
|
322
|
+
frameHandler?.(frame);
|
|
323
|
+
});
|
|
324
|
+
const closeWith = (error) => {
|
|
325
|
+
for (const handler of closeHandlers)
|
|
326
|
+
handler(error);
|
|
327
|
+
};
|
|
328
|
+
child.once("exit", (code, signal) => closeWith(new Error(`codex app-server exited: code=${String(code)} signal=${String(signal)}`)));
|
|
329
|
+
child.once("error", (error) => closeWith(error));
|
|
330
|
+
child.stdin?.on("error", () => undefined);
|
|
331
|
+
return {
|
|
332
|
+
send(frame) {
|
|
333
|
+
child.stdin?.write(`${JSON.stringify(frame)}\n`);
|
|
334
|
+
},
|
|
335
|
+
onFrame(handler) {
|
|
336
|
+
frameHandler = handler;
|
|
337
|
+
},
|
|
338
|
+
onClose(handler) {
|
|
339
|
+
closeHandlers.push(handler);
|
|
340
|
+
},
|
|
341
|
+
close() {
|
|
342
|
+
try {
|
|
343
|
+
child.stdin?.end();
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
/* best-effort */
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
};
|
|
350
|
+
}
|
|
175
351
|
const OUTPUT_TAIL_BYTES = 4096;
|
|
176
352
|
/** Ring buffer of the last OUTPUT_TAIL_BYTES of tee'd vendor output. */
|
|
177
|
-
function createTailBuffer() {
|
|
353
|
+
export function createTailBuffer() {
|
|
178
354
|
// Byte-accurate ring: keep the final OUTPUT_TAIL_BYTES RAW bytes and decode
|
|
179
355
|
// ONCE in text() — a per-chunk String() decode splits multibyte UTF-8 into
|
|
180
356
|
// replacement chars and a UTF-16 .slice miscounts the byte bound.
|
|
181
357
|
let tail = Buffer.alloc(0);
|
|
358
|
+
// Whether the stream ever exceeded the ring — the truncation signal cannot
|
|
359
|
+
// be recovered from the decoded string's length (already <= the byte cap),
|
|
360
|
+
// so track it HERE and hand it to boundedTail (X224 ring-path fix).
|
|
361
|
+
let overflowed = false;
|
|
182
362
|
return {
|
|
183
363
|
push(chunk) {
|
|
184
|
-
|
|
364
|
+
const combined = Buffer.concat([tail, chunk]);
|
|
365
|
+
if (combined.length > OUTPUT_TAIL_BYTES)
|
|
366
|
+
overflowed = true;
|
|
367
|
+
tail = combined.subarray(-OUTPUT_TAIL_BYTES);
|
|
185
368
|
},
|
|
186
369
|
text() {
|
|
187
370
|
// The ring can start mid-codepoint: drop leading continuation bytes
|
|
@@ -189,20 +372,31 @@ function createTailBuffer() {
|
|
|
189
372
|
let start = 0;
|
|
190
373
|
while (start < tail.length && (tail[start] & 0b1100_0000) === 0b1000_0000)
|
|
191
374
|
start += 1;
|
|
192
|
-
return boundedTail(tail.subarray(start).toString("utf8"));
|
|
375
|
+
return boundedTail(tail.subarray(start).toString("utf8"), overflowed || start > 0);
|
|
193
376
|
},
|
|
194
377
|
};
|
|
195
378
|
}
|
|
196
379
|
/** Strip terminal escapes (CSI, OSC, bare ESC, C0 controls except newline),
|
|
197
380
|
* redact secret-like tokens, and clamp - diagnostic evidence entering a
|
|
198
381
|
* durable journal/API surface, never a raw vendor log copy (INV-062). */
|
|
199
|
-
function boundedTail(text) {
|
|
382
|
+
export function boundedTail(text, truncated = false) {
|
|
200
383
|
const plain = text
|
|
201
384
|
// eslint-disable-next-line no-control-regex
|
|
202
385
|
.replace(/\u001b(?:\[[0-9;?]*[ -/]*[@-~]|\][^\u0007\u001b]*(?:\u0007|\u001b\\)?)/g, "")
|
|
203
386
|
// eslint-disable-next-line no-control-regex
|
|
204
387
|
.replace(/[\u0000-\u0009\u000b-\u001f\u007f]/g, "");
|
|
205
|
-
|
|
388
|
+
// When the source was truncated at the front (ring overflow, or a
|
|
389
|
+
// direct-string caller over the byte budget), a secret split by that
|
|
390
|
+
// boundary could leave a prefix-less fragment redactSecrets cannot anchor.
|
|
391
|
+
// Drop the leading partial token in that case; untruncated output is whole.
|
|
392
|
+
// The caller's flag is authoritative (a ring string is already <= the cap,
|
|
393
|
+
// so a length check here cannot see the cut); direct callers OR in their
|
|
394
|
+
// own over-budget check.
|
|
395
|
+
const cut = truncated || Buffer.byteLength(plain, "utf8") > OUTPUT_TAIL_BYTES;
|
|
396
|
+
let bounded = plain.slice(-OUTPUT_TAIL_BYTES);
|
|
397
|
+
if (cut)
|
|
398
|
+
bounded = bounded.replace(/^\S+/, "");
|
|
399
|
+
return redactSecrets(bounded.trim().slice(0, 4000));
|
|
206
400
|
}
|
|
207
401
|
/** Run `<binary> login --help` captured, bounded to 10s. Fails OPEN: only a
|
|
208
402
|
* COMPLETED probe whose help text lacks the flag reports unsupported. */
|
|
@@ -320,6 +514,19 @@ function runnerBootstrapEnv(source = process.env) {
|
|
|
320
514
|
"LOGNAME",
|
|
321
515
|
"CLAUDEXOR_CODEX_NATIVE_HOME",
|
|
322
516
|
"CLAUDEXOR_CLAUDE_NATIVE_DIR",
|
|
517
|
+
// Network reachability for the DETACHED worker: without the proxy/CA
|
|
518
|
+
// family a corporate-proxy machine cannot reach the vendor at all and
|
|
519
|
+
// the device-code login dies opaquely. Pass-through only — never set.
|
|
520
|
+
"HTTP_PROXY",
|
|
521
|
+
"HTTPS_PROXY",
|
|
522
|
+
"NO_PROXY",
|
|
523
|
+
"ALL_PROXY",
|
|
524
|
+
"http_proxy",
|
|
525
|
+
"https_proxy",
|
|
526
|
+
"no_proxy",
|
|
527
|
+
"SSL_CERT_FILE",
|
|
528
|
+
"SSL_CERT_DIR",
|
|
529
|
+
"NODE_EXTRA_CA_CERTS",
|
|
323
530
|
]) {
|
|
324
531
|
if (source[key] !== undefined)
|
|
325
532
|
env[key] = source[key];
|