myshell-tools 2.15.0 → 3.2.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/CHANGELOG.md +83 -1
- package/README.md +39 -44
- package/dist/cli.js +33 -22
- package/dist/cli.js.map +1 -1
- package/dist/commands/cost.js +44 -21
- package/dist/commands/cost.js.map +1 -1
- package/dist/commands/doctor.d.ts +17 -4
- package/dist/commands/doctor.js +62 -35
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/login.d.ts +18 -10
- package/dist/commands/login.js +81 -109
- package/dist/commands/login.js.map +1 -1
- package/dist/core/json-envelope.js +31 -3
- package/dist/core/json-envelope.js.map +1 -1
- package/dist/core/native-session.d.ts +57 -0
- package/dist/core/native-session.js +68 -0
- package/dist/core/native-session.js.map +1 -0
- package/dist/core/orchestrate.js +106 -43
- package/dist/core/orchestrate.js.map +1 -1
- package/dist/core/types.d.ts +26 -0
- package/dist/infra/atomic.d.ts +9 -1
- package/dist/infra/atomic.js +12 -2
- package/dist/infra/atomic.js.map +1 -1
- package/dist/infra/config.d.ts +8 -0
- package/dist/infra/config.js.map +1 -1
- package/dist/infra/credentials.d.ts +69 -3
- package/dist/infra/credentials.js +118 -9
- package/dist/infra/credentials.js.map +1 -1
- package/dist/infra/health.d.ts +57 -0
- package/dist/infra/health.js +96 -0
- package/dist/infra/health.js.map +1 -0
- package/dist/infra/insights.d.ts +14 -0
- package/dist/infra/insights.js +31 -0
- package/dist/infra/insights.js.map +1 -1
- package/dist/interface/menu.d.ts +70 -5
- package/dist/interface/menu.js +292 -88
- package/dist/interface/menu.js.map +1 -1
- package/dist/interface/render.js +20 -13
- package/dist/interface/render.js.map +1 -1
- package/dist/providers/claude.d.ts +24 -8
- package/dist/providers/claude.js +77 -15
- package/dist/providers/claude.js.map +1 -1
- package/dist/providers/codex-parse.js +14 -2
- package/dist/providers/codex-parse.js.map +1 -1
- package/dist/providers/codex.d.ts +13 -1
- package/dist/providers/codex.js +19 -8
- package/dist/providers/codex.js.map +1 -1
- package/dist/providers/detect.js +22 -1
- package/dist/providers/detect.js.map +1 -1
- package/dist/providers/port.d.ts +15 -0
- package/dist/providers/registry.d.ts +8 -4
- package/dist/providers/registry.js +7 -6
- package/dist/providers/registry.js.map +1 -1
- package/dist/ui/help.d.ts +17 -0
- package/dist/ui/help.js +106 -0
- package/dist/ui/help.js.map +1 -0
- package/package.json +1 -1
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { OutputSink } from '../interface/render.js';
|
|
18
18
|
import type { EnvironmentStatus } from '../providers/detect.js';
|
|
19
|
+
import type { ClaudeTokenStatus } from '../infra/credentials.js';
|
|
19
20
|
export interface DoctorExtras {
|
|
20
21
|
readonly nodeVersion: string;
|
|
21
22
|
readonly stateWritable: boolean;
|
|
@@ -28,11 +29,12 @@ export interface DoctorExtras {
|
|
|
28
29
|
* Used by runDoctor after it collects the real data, and by unit tests with
|
|
29
30
|
* hand-built inputs.
|
|
30
31
|
*
|
|
31
|
-
* @param env
|
|
32
|
-
* @param extras
|
|
33
|
-
* @param color
|
|
32
|
+
* @param env - Full environment status (from detectEnvironment or a fake).
|
|
33
|
+
* @param extras - Supplemental runtime info (node version, write probe, etc.).
|
|
34
|
+
* @param color - Whether to emit ANSI colour codes.
|
|
35
|
+
* @param claudeTokenInfo - Optional pre-computed token lifetime status (from claudeTokenStatus()).
|
|
34
36
|
*/
|
|
35
|
-
export declare function buildDoctorReport(env: EnvironmentStatus, extras: DoctorExtras, color: boolean): string[];
|
|
37
|
+
export declare function buildDoctorReport(env: EnvironmentStatus, extras: DoctorExtras, color: boolean, claudeTokenInfo?: ClaudeTokenStatus | null): string[];
|
|
36
38
|
export interface DoctorFixOpts {
|
|
37
39
|
/** When true, run an interactive fix pass after the report. */
|
|
38
40
|
readonly fix?: boolean;
|
|
@@ -56,6 +58,17 @@ export interface DoctorFixOpts {
|
|
|
56
58
|
* Defaults to the real detectEnvironment from providers/detect.ts.
|
|
57
59
|
*/
|
|
58
60
|
readonly detectEnvironment?: () => Promise<EnvironmentStatus>;
|
|
61
|
+
/**
|
|
62
|
+
* Load the Claude token capture timestamp (ISO 8601). Injected in tests to
|
|
63
|
+
* drive the token-expiry refresh prompt hermetically (no disk read).
|
|
64
|
+
* Defaults to the real loadClaudeTokenCapturedAt from infra/credentials.ts.
|
|
65
|
+
*/
|
|
66
|
+
readonly loadClaudeTokenCapturedAt?: () => Promise<string | undefined>;
|
|
67
|
+
/**
|
|
68
|
+
* Current epoch-ms, used for deterministic token-expiry computation in tests.
|
|
69
|
+
* Defaults to Date.now().
|
|
70
|
+
*/
|
|
71
|
+
readonly now?: () => number;
|
|
59
72
|
}
|
|
60
73
|
/**
|
|
61
74
|
* Detect the environment, probe I/O, build the report, and write it to `out`.
|
package/dist/commands/doctor.js
CHANGED
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
* remain hermetic — no real npm/login/detect spawned in tests.
|
|
16
16
|
*/
|
|
17
17
|
import readline from 'node:readline';
|
|
18
|
-
import { access, mkdir, writeFile, rm } from 'node:fs/promises';
|
|
19
|
-
import { join } from 'node:path';
|
|
20
18
|
import { detectEnvironment, getInstallCommand } from '../providers/detect.js';
|
|
21
19
|
import { installProvider } from '../providers/install.js';
|
|
22
20
|
import { runLogin } from './login.js';
|
|
23
21
|
import { isPricingStale } from '../infra/pricing.js';
|
|
22
|
+
import { probeStateWritable } from '../infra/health.js';
|
|
23
|
+
import { loadClaudeTokenCapturedAt, claudeTokenStatus } from '../infra/credentials.js';
|
|
24
24
|
import { parseYesNo } from '../interface/menu.js';
|
|
25
25
|
import { bold, green, red, yellow, dim, divider, label } from '../ui/theme.js';
|
|
26
26
|
/**
|
|
@@ -30,13 +30,14 @@ import { bold, green, red, yellow, dim, divider, label } from '../ui/theme.js';
|
|
|
30
30
|
* Used by runDoctor after it collects the real data, and by unit tests with
|
|
31
31
|
* hand-built inputs.
|
|
32
32
|
*
|
|
33
|
-
* @param env
|
|
34
|
-
* @param extras
|
|
35
|
-
* @param color
|
|
33
|
+
* @param env - Full environment status (from detectEnvironment or a fake).
|
|
34
|
+
* @param extras - Supplemental runtime info (node version, write probe, etc.).
|
|
35
|
+
* @param color - Whether to emit ANSI colour codes.
|
|
36
|
+
* @param claudeTokenInfo - Optional pre-computed token lifetime status (from claudeTokenStatus()).
|
|
36
37
|
*/
|
|
37
|
-
export function buildDoctorReport(env, extras, color) {
|
|
38
|
+
export function buildDoctorReport(env, extras, color, claudeTokenInfo) {
|
|
38
39
|
const lines = [];
|
|
39
|
-
lines.push(bold('myshell-tools
|
|
40
|
+
lines.push(bold('myshell-tools — environment health', color));
|
|
40
41
|
lines.push(divider(color));
|
|
41
42
|
// ---- Platform & Node -------------------------------------------------------
|
|
42
43
|
lines.push(`${label('Platform', color)}: ${env.platform}`);
|
|
@@ -58,9 +59,29 @@ export function buildDoctorReport(env, extras, color) {
|
|
|
58
59
|
if (ps.installed) {
|
|
59
60
|
const versionStr = ps.version !== null ? ps.version : 'unknown';
|
|
60
61
|
lines.push(` ${green('✓', color)} ${bold(ps.id, color)} — installed, version: ${versionStr}`);
|
|
61
|
-
if (ps.
|
|
62
|
+
if (ps.id === 'opencode') {
|
|
63
|
+
// opencode auth was never probed — it is usable via free models without
|
|
64
|
+
// sign-in. Saying "signed in" would be dishonest.
|
|
65
|
+
lines.push(` ${label('auth', color)}: ${green('free models (no sign-in needed)', color)}`);
|
|
66
|
+
}
|
|
67
|
+
else if (ps.authenticated) {
|
|
62
68
|
const planLabel = ps.plan !== null ? ` (${ps.plan})` : '';
|
|
63
69
|
lines.push(` ${label('auth', color)}: ${green('signed in', color)}${planLabel}`);
|
|
70
|
+
// Token lifetime line — only for claude, only when we have a captured-at date.
|
|
71
|
+
if (ps.id === 'claude' && claudeTokenInfo != null) {
|
|
72
|
+
const info = claudeTokenInfo;
|
|
73
|
+
if (info.expired) {
|
|
74
|
+
lines.push(` ${label('token', color)}: ${red('EXPIRED — run: myshell-tools login claude --code', color)}`);
|
|
75
|
+
}
|
|
76
|
+
else if (info.nearExpiry) {
|
|
77
|
+
const expiryDate = info.expiresAt.slice(0, 10);
|
|
78
|
+
lines.push(` ${label('token', color)}: ${yellow(`expires soon (${info.daysLeft} days, ~${expiryDate}) — re-run login when convenient`, color)}`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const expiryDate = info.expiresAt.slice(0, 10);
|
|
82
|
+
lines.push(` ${label('token', color)}: expires ~${expiryDate} (${info.daysLeft} days left)`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
64
85
|
}
|
|
65
86
|
else {
|
|
66
87
|
lines.push(` ${label('auth', color)}: ${yellow('not signed in', color)} — run: myshell-tools login`);
|
|
@@ -85,29 +106,6 @@ export function buildDoctorReport(env, extras, color) {
|
|
|
85
106
|
// ---------------------------------------------------------------------------
|
|
86
107
|
// I/O runner — called by cli.ts
|
|
87
108
|
// ---------------------------------------------------------------------------
|
|
88
|
-
/**
|
|
89
|
-
* Probe the .myshell-tools directory for writability.
|
|
90
|
-
*
|
|
91
|
-
* Creates .myshell-tools/ if needed, writes a temp file, then removes it.
|
|
92
|
-
* Returns true when successful, false on any I/O error.
|
|
93
|
-
*/
|
|
94
|
-
async function probestateWritable(cwd) {
|
|
95
|
-
const stateDir = join(cwd, '.myshell-tools');
|
|
96
|
-
const probe = join(stateDir, '.doctor-probe');
|
|
97
|
-
try {
|
|
98
|
-
await mkdir(stateDir, { recursive: true });
|
|
99
|
-
await writeFile(probe, '');
|
|
100
|
-
await rm(probe, { force: true });
|
|
101
|
-
await access(stateDir);
|
|
102
|
-
return true;
|
|
103
|
-
}
|
|
104
|
-
catch {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// ---------------------------------------------------------------------------
|
|
109
|
-
// I/O runner — called by cli.ts
|
|
110
|
-
// ---------------------------------------------------------------------------
|
|
111
109
|
/**
|
|
112
110
|
* Detect the environment, probe I/O, build the report, and write it to `out`.
|
|
113
111
|
*
|
|
@@ -125,13 +123,19 @@ export async function runDoctor(out, opts) {
|
|
|
125
123
|
const installProviderFn = opts?.installProvider ?? installProvider;
|
|
126
124
|
const loginFn = opts?.login ?? ((o, id) => runLogin(o, id));
|
|
127
125
|
const env = await detectEnvironmentFn();
|
|
128
|
-
const stateWritable = await
|
|
126
|
+
const stateWritable = await probeStateWritable(process.cwd());
|
|
129
127
|
const extras = {
|
|
130
128
|
nodeVersion: process.version,
|
|
131
129
|
stateWritable,
|
|
132
130
|
pricingStale: isPricingStale(),
|
|
133
131
|
};
|
|
134
|
-
|
|
132
|
+
// Compute token lifetime info when claude is signed in and a capture date is stored.
|
|
133
|
+
let claudeTokenInfo;
|
|
134
|
+
if (env.claude.installed && env.claude.authenticated) {
|
|
135
|
+
const capturedAt = await loadClaudeTokenCapturedAt();
|
|
136
|
+
claudeTokenInfo = claudeTokenStatus(capturedAt, Date.now());
|
|
137
|
+
}
|
|
138
|
+
const lines = buildDoctorReport(env, extras, out.color, claudeTokenInfo);
|
|
135
139
|
for (const line of lines) {
|
|
136
140
|
out.write(line + '\n');
|
|
137
141
|
}
|
|
@@ -154,8 +158,10 @@ export async function runDoctor(out, opts) {
|
|
|
154
158
|
});
|
|
155
159
|
rlClose = () => rl.close();
|
|
156
160
|
}
|
|
161
|
+
const loadCapturedAtFn = opts.loadClaudeTokenCapturedAt ?? loadClaudeTokenCapturedAt;
|
|
162
|
+
const nowFn = opts.now ?? (() => Date.now());
|
|
157
163
|
try {
|
|
158
|
-
await runFixPass(out, env, readLineFn, installProviderFn, loginFn, detectEnvironmentFn);
|
|
164
|
+
await runFixPass(out, env, readLineFn, installProviderFn, loginFn, detectEnvironmentFn, loadCapturedAtFn, nowFn);
|
|
159
165
|
}
|
|
160
166
|
finally {
|
|
161
167
|
rlClose?.();
|
|
@@ -176,7 +182,7 @@ export async function runDoctor(out, opts) {
|
|
|
176
182
|
*
|
|
177
183
|
* Never throws — any step failure is caught and reported via `out`.
|
|
178
184
|
*/
|
|
179
|
-
async function runFixPass(out, initialEnv, readLine, installProviderFn, loginFn, detectEnvironmentFn) {
|
|
185
|
+
async function runFixPass(out, initialEnv, readLine, installProviderFn, loginFn, detectEnvironmentFn, loadCapturedAtFn, nowFn) {
|
|
180
186
|
const providers = ['claude', 'codex', 'opencode'];
|
|
181
187
|
// ---- Step 1: offer installs for missing providers -------------------------
|
|
182
188
|
const missingIds = providers.filter((id) => !initialEnv[id].installed);
|
|
@@ -221,6 +227,27 @@ async function runFixPass(out, initialEnv, readLine, installProviderFn, loginFn,
|
|
|
221
227
|
}
|
|
222
228
|
}
|
|
223
229
|
}
|
|
230
|
+
// ---- Step 3b: offer a Claude token refresh when it is expiring -------------
|
|
231
|
+
// The sk-ant-oat… token from `claude setup-token` is ~1-year-lived. Proactively
|
|
232
|
+
// offer to refresh it when expired or inside the warning window so users aren't
|
|
233
|
+
// surprised by a mid-session auth failure (a real reported confusion).
|
|
234
|
+
if (env.claude.installed && env.claude.authenticated) {
|
|
235
|
+
const capturedAt = await loadCapturedAtFn().catch(() => undefined);
|
|
236
|
+
const tokenInfo = claudeTokenStatus(capturedAt, nowFn());
|
|
237
|
+
if (tokenInfo !== null && (tokenInfo.expired || tokenInfo.nearExpiry)) {
|
|
238
|
+
const when = tokenInfo.expired ? 'has expired' : `expires in ${tokenInfo.daysLeft} days`;
|
|
239
|
+
out.write(`\nYour Claude token ${when}. Refresh it now? (Y/n) `);
|
|
240
|
+
const ans = await readLine();
|
|
241
|
+
if (parseYesNo(ans, true)) {
|
|
242
|
+
try {
|
|
243
|
+
await loginFn(out, 'claude');
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
out.write(red(`✗ Claude re-login did not complete.\n`, out.color));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
224
251
|
// ---- Step 4: final re-detect and brief summary ----------------------------
|
|
225
252
|
let finalEnv = env;
|
|
226
253
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,QAAQ,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/login.d.ts
CHANGED
|
@@ -11,13 +11,11 @@
|
|
|
11
11
|
* containers / over SSH (Replit, Codespaces, etc.) where localhost can't be
|
|
12
12
|
* reached from the user's browser.
|
|
13
13
|
* - 'code': a no-localhost flow that works anywhere.
|
|
14
|
-
* · claude → `claude setup-token`:
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* (
|
|
18
|
-
*
|
|
19
|
-
* back to prompting the user to paste it (up to 3 retries, with helpful
|
|
20
|
-
* warnings for blank or wrong-type inputs).
|
|
14
|
+
* · claude → `claude setup-token`: spawned with fully inherited stdio so
|
|
15
|
+
* the native spinner/animation renders cleanly. After the process exits
|
|
16
|
+
* successfully, the user is prompted to paste the token (sk-ant-oat…)
|
|
17
|
+
* back here (up to 3 retries, with helpful warnings for blank or
|
|
18
|
+
* wrong-type inputs).
|
|
21
19
|
* · codex → `codex login --device-auth`: prints a URL + one-time code;
|
|
22
20
|
* the user authorizes their ChatGPT account on any device.
|
|
23
21
|
*
|
|
@@ -25,9 +23,8 @@
|
|
|
25
23
|
* to 'code' (so the localhost trap is avoided), everything else to 'browser'.
|
|
26
24
|
*
|
|
27
25
|
* Security: myshell-tools never stores raw API keys or passwords. The Claude
|
|
28
|
-
* OAuth token (sk-ant-oat…) is
|
|
29
|
-
*
|
|
30
|
-
* ~/.myshell-tools/credentials.json (mode 0o600).
|
|
26
|
+
* OAuth token (sk-ant-oat…) is captured after the user explicitly pastes it,
|
|
27
|
+
* and is stored in ~/.myshell-tools/credentials.json (mode 0o600).
|
|
31
28
|
*/
|
|
32
29
|
import type { OutputSink } from '../interface/render.js';
|
|
33
30
|
import type { ProviderId } from '../providers/port.js';
|
|
@@ -52,6 +49,17 @@ export declare function isHeadlessEnv(env: NodeJS.ProcessEnv, platform: NodeJS.P
|
|
|
52
49
|
* Pure / testable.
|
|
53
50
|
*/
|
|
54
51
|
export declare function resolveLoginMethod(explicit: LoginMethod | undefined, env: NodeJS.ProcessEnv, platform: NodeJS.Platform): LoginMethod;
|
|
52
|
+
/**
|
|
53
|
+
* Decide whether to retry a failed browser sign-in using the code method,
|
|
54
|
+
* based on the user's answer to the interactive prompt.
|
|
55
|
+
*
|
|
56
|
+
* Wraps {@link parseYesNo} with `defaultYes=true` (pressing Enter accepts the
|
|
57
|
+
* retry). Pure / hermetically testable.
|
|
58
|
+
*
|
|
59
|
+
* @param answer - Raw line from readLine(), or null on EOF.
|
|
60
|
+
* @returns True if the code method should be retried; false if not.
|
|
61
|
+
*/
|
|
62
|
+
export declare function shouldRetryWithCode(answer: string | null): boolean;
|
|
55
63
|
/**
|
|
56
64
|
* Run the interactive sign-in flow for one provider (or all installed providers
|
|
57
65
|
* when no argument is given). Returns 0 on success, 1 only for an invalid
|
package/dist/commands/login.js
CHANGED
|
@@ -11,13 +11,11 @@
|
|
|
11
11
|
* containers / over SSH (Replit, Codespaces, etc.) where localhost can't be
|
|
12
12
|
* reached from the user's browser.
|
|
13
13
|
* - 'code': a no-localhost flow that works anywhere.
|
|
14
|
-
* · claude → `claude setup-token`:
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* (
|
|
18
|
-
*
|
|
19
|
-
* back to prompting the user to paste it (up to 3 retries, with helpful
|
|
20
|
-
* warnings for blank or wrong-type inputs).
|
|
14
|
+
* · claude → `claude setup-token`: spawned with fully inherited stdio so
|
|
15
|
+
* the native spinner/animation renders cleanly. After the process exits
|
|
16
|
+
* successfully, the user is prompted to paste the token (sk-ant-oat…)
|
|
17
|
+
* back here (up to 3 retries, with helpful warnings for blank or
|
|
18
|
+
* wrong-type inputs).
|
|
21
19
|
* · codex → `codex login --device-auth`: prints a URL + one-time code;
|
|
22
20
|
* the user authorizes their ChatGPT account on any device.
|
|
23
21
|
*
|
|
@@ -25,14 +23,14 @@
|
|
|
25
23
|
* to 'code' (so the localhost trap is avoided), everything else to 'browser'.
|
|
26
24
|
*
|
|
27
25
|
* Security: myshell-tools never stores raw API keys or passwords. The Claude
|
|
28
|
-
* OAuth token (sk-ant-oat…) is
|
|
29
|
-
*
|
|
30
|
-
* ~/.myshell-tools/credentials.json (mode 0o600).
|
|
26
|
+
* OAuth token (sk-ant-oat…) is captured after the user explicitly pastes it,
|
|
27
|
+
* and is stored in ~/.myshell-tools/credentials.json (mode 0o600).
|
|
31
28
|
*/
|
|
32
29
|
import readline from 'node:readline';
|
|
33
30
|
import { execa } from 'execa';
|
|
34
31
|
import { detectProvider, getInstallCommand } from '../providers/detect.js';
|
|
35
32
|
import { bold, dim, green, red, yellow } from '../ui/theme.js';
|
|
33
|
+
import { parseYesNo } from '../interface/menu.js';
|
|
36
34
|
import { classifyPastedSecret, extractClaudeToken, saveClaudeToken, stripPastedSecretWrapper, } from '../infra/credentials.js';
|
|
37
35
|
/** Each provider's default (browser/localhost) sign-in command. */
|
|
38
36
|
const LOGIN_COMMAND = {
|
|
@@ -52,9 +50,8 @@ const LOGIN_CODE_COMMAND = {
|
|
|
52
50
|
args: ['setup-token'],
|
|
53
51
|
guidance: 'A sign-in link will appear below.\n' +
|
|
54
52
|
' 1. Open it in any browser and sign in at claude.ai.\n' +
|
|
55
|
-
' 2. Copy the
|
|
56
|
-
' 3.
|
|
57
|
-
' We will capture the token automatically when possible.',
|
|
53
|
+
' 2. Copy the token it shows you (starts with sk-ant-oat).\n' +
|
|
54
|
+
' 3. When prompted below, paste it here and press Enter.',
|
|
58
55
|
},
|
|
59
56
|
codex: {
|
|
60
57
|
bin: 'codex',
|
|
@@ -114,6 +111,51 @@ export function resolveLoginMethod(explicit, env, platform) {
|
|
|
114
111
|
return explicit;
|
|
115
112
|
return isHeadlessEnv(env, platform) ? 'code' : 'browser';
|
|
116
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Decide whether to retry a failed browser sign-in using the code method,
|
|
116
|
+
* based on the user's answer to the interactive prompt.
|
|
117
|
+
*
|
|
118
|
+
* Wraps {@link parseYesNo} with `defaultYes=true` (pressing Enter accepts the
|
|
119
|
+
* retry). Pure / hermetically testable.
|
|
120
|
+
*
|
|
121
|
+
* @param answer - Raw line from readLine(), or null on EOF.
|
|
122
|
+
* @returns True if the code method should be retried; false if not.
|
|
123
|
+
*/
|
|
124
|
+
export function shouldRetryWithCode(answer) {
|
|
125
|
+
return parseYesNo(answer, true);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Run the code sign-in method for a single provider.
|
|
129
|
+
*
|
|
130
|
+
* Factored out so both the initial `--code` path and the browser-fail retry
|
|
131
|
+
* path can invoke it without duplicating the spawn + paste-capture logic.
|
|
132
|
+
* Never throws.
|
|
133
|
+
*/
|
|
134
|
+
async function runCodeMethodForProvider(out, id, readLine) {
|
|
135
|
+
const { bin, args, guidance } = LOGIN_CODE_COMMAND[id];
|
|
136
|
+
out.write(bold(`\nSigning in to ${id} — code method (no localhost needed).\n`, out.color));
|
|
137
|
+
out.write(dim(guidance + '\n', out.color));
|
|
138
|
+
const result = await execa(bin, [...args], { stdin: 'inherit', stdout: 'inherit', stderr: 'inherit', reject: false });
|
|
139
|
+
if (result.exitCode === 0) {
|
|
140
|
+
if (id === 'claude') {
|
|
141
|
+
// `claude setup-token` ran with inherited stdio (so the native animation
|
|
142
|
+
// rendered cleanly). Now prompt the user to paste the token it printed.
|
|
143
|
+
// captureClaudeTokenWithPaste reports its own success/failure messages.
|
|
144
|
+
await captureClaudeTokenWithPaste(out, readLine);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
out.write(green(`✓ ${id} sign-in complete.\n`, out.color));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
if (id === 'claude') {
|
|
152
|
+
out.write(red(`✗ claude setup-token did not complete (exit ${result.exitCode ?? 'unknown'}). Run it manually: claude setup-token\n`, out.color));
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
out.write(red(`✗ ${id} sign-in did not complete (exit ${result.exitCode ?? 'unknown'}).\n`, out.color));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
117
159
|
/**
|
|
118
160
|
* Run the interactive sign-in flow for one provider (or all installed providers
|
|
119
161
|
* when no argument is given). Returns 0 on success, 1 only for an invalid
|
|
@@ -144,117 +186,47 @@ export async function runLogin(out, providerArg, opts) {
|
|
|
144
186
|
out.write(dim(`${id}: not installed — skipping. Install with: ${getInstallCommand(id)}\n`, out.color));
|
|
145
187
|
continue;
|
|
146
188
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// and stderr are piped so we can scan for the token, but each line is also
|
|
152
|
-
// written verbatim to the real terminal so the user sees the flow live.
|
|
153
|
-
// stdin is still inherited so the user can interact (paste the auth code).
|
|
154
|
-
let result;
|
|
155
|
-
let capturedOutput = '';
|
|
156
|
-
if (method === 'code' && id === 'claude') {
|
|
157
|
-
const { bin, args, guidance } = LOGIN_CODE_COMMAND[id];
|
|
158
|
-
out.write(bold(`\nSigning in to ${id} — code method (no localhost needed).\n`, out.color));
|
|
159
|
-
out.write(dim(guidance + '\n', out.color));
|
|
160
|
-
capturedOutput = await runWithTeeCapture(bin, [...args]);
|
|
161
|
-
// We use a synthetic exit-code-0 result — tee-capture never throws, and
|
|
162
|
-
// we treat the flow as complete regardless of the subprocess exit code
|
|
163
|
-
// (the token presence is the real signal).
|
|
164
|
-
result = { exitCode: 0 };
|
|
165
|
-
}
|
|
166
|
-
else if (method === 'code') {
|
|
167
|
-
const { bin, args, guidance } = LOGIN_CODE_COMMAND[id];
|
|
168
|
-
out.write(bold(`\nSigning in to ${id} — code method (no localhost needed).\n`, out.color));
|
|
169
|
-
out.write(dim(guidance + '\n', out.color));
|
|
170
|
-
result = await execa(bin, [...args], { stdin: 'inherit', stdout: 'inherit', stderr: 'inherit', reject: false });
|
|
189
|
+
if (method === 'code') {
|
|
190
|
+
// stdio:'inherit' hands the terminal to the provider CLI so its OAuth /
|
|
191
|
+
// device / paste flow runs in place.
|
|
192
|
+
await runCodeMethodForProvider(out, id, opts?.readLine);
|
|
171
193
|
}
|
|
172
194
|
else {
|
|
195
|
+
// Browser method
|
|
173
196
|
const { bin, args } = LOGIN_COMMAND[id];
|
|
174
197
|
out.write(bold(`\nSigning in to ${id} — a browser window may open…\n`, out.color));
|
|
175
|
-
result = await execa(bin, [...args], { stdin: 'inherit', stdout: 'inherit', stderr: 'inherit', reject: false });
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
out.write(green('✓ Claude token captured and saved — claude is now ready.\n', out.color));
|
|
198
|
+
const result = await execa(bin, [...args], { stdin: 'inherit', stdout: 'inherit', stderr: 'inherit', reject: false });
|
|
199
|
+
if (result.exitCode === 0) {
|
|
200
|
+
out.write(green(`✓ ${id} sign-in complete.\n`, out.color));
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
out.write(red(`✗ ${id} sign-in did not complete (exit ${result.exitCode ?? 'unknown'}).\n`, out.color));
|
|
204
|
+
// The classic container failure mode is a dead localhost callback.
|
|
205
|
+
// When an interactive readline is available, offer to immediately retry
|
|
206
|
+
// using the no-localhost code method. Otherwise print the manual hint.
|
|
207
|
+
if (opts?.readLine !== undefined) {
|
|
208
|
+
out.write(`Browser sign-in failed. Try the no-localhost code method now? (Y/n) `);
|
|
209
|
+
const ans = await opts.readLine();
|
|
210
|
+
if (shouldRetryWithCode(ans)) {
|
|
211
|
+
await runCodeMethodForProvider(out, id, opts.readLine);
|
|
190
212
|
}
|
|
191
|
-
|
|
192
|
-
out.write(dim(
|
|
213
|
+
else {
|
|
214
|
+
out.write(dim(`If the browser/localhost step failed, try the code method instead:\n` +
|
|
215
|
+
` myshell-tools login ${id} --code\n`, out.color));
|
|
193
216
|
}
|
|
194
217
|
}
|
|
195
218
|
else {
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
await captureClaudeTokenWithPaste(out, opts?.readLine);
|
|
219
|
+
// Non-interactive path: print the hint as before.
|
|
220
|
+
out.write(dim(`If the browser/localhost step failed, try the code method instead:\n` +
|
|
221
|
+
` myshell-tools login ${id} --code\n`, out.color));
|
|
200
222
|
}
|
|
201
223
|
}
|
|
202
|
-
else {
|
|
203
|
-
out.write(green(`✓ ${id} sign-in complete.\n`, out.color));
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
out.write(red(`✗ ${id} sign-in did not complete (exit ${result.exitCode ?? 'unknown'}).\n`, out.color));
|
|
208
|
-
// The classic container failure mode is a dead localhost callback. Point
|
|
209
|
-
// the user at the code method, which sidesteps localhost entirely.
|
|
210
|
-
if (method === 'browser') {
|
|
211
|
-
out.write(dim(`If the browser/localhost step failed, try the code method instead:\n` +
|
|
212
|
-
` myshell-tools login ${id} --code\n`, out.color));
|
|
213
|
-
}
|
|
214
224
|
}
|
|
215
225
|
}
|
|
216
226
|
return 0;
|
|
217
227
|
}
|
|
218
228
|
// ---------------------------------------------------------------------------
|
|
219
|
-
//
|
|
220
|
-
// ---------------------------------------------------------------------------
|
|
221
|
-
/**
|
|
222
|
-
* Run a command with stdout and stderr piped (tee'd to the real terminal) and
|
|
223
|
-
* stdin inherited. Returns the accumulated stdout+stderr text, or an empty
|
|
224
|
-
* string on spawn failure. Never throws.
|
|
225
|
-
*
|
|
226
|
-
* Uses execa v9's `all: true` option to merge stdout+stderr into one stream,
|
|
227
|
-
* then iterates it via `subprocess.iterable({ from: 'all', preserveNewlines: true })`
|
|
228
|
-
* while mirroring each chunk to `process.stdout` so the user sees the output
|
|
229
|
-
* live. stdin is inherited so the user can interact (e.g. paste an auth code).
|
|
230
|
-
*/
|
|
231
|
-
async function runWithTeeCapture(bin, args) {
|
|
232
|
-
try {
|
|
233
|
-
const subprocess = execa(bin, [...args], {
|
|
234
|
-
stdin: 'inherit',
|
|
235
|
-
stdout: 'pipe',
|
|
236
|
-
stderr: 'pipe',
|
|
237
|
-
all: true,
|
|
238
|
-
reject: false,
|
|
239
|
-
timeout: 300_000,
|
|
240
|
-
});
|
|
241
|
-
const chunks = [];
|
|
242
|
-
for await (const line of subprocess.iterable({ from: 'all', preserveNewlines: true })) {
|
|
243
|
-
const text = typeof line === 'string' ? line : String(line);
|
|
244
|
-
process.stdout.write(text);
|
|
245
|
-
chunks.push(text);
|
|
246
|
-
}
|
|
247
|
-
await subprocess; // wait for exit (already resolved by the iteration above)
|
|
248
|
-
return chunks.join('');
|
|
249
|
-
}
|
|
250
|
-
catch {
|
|
251
|
-
// Spawn error or unexpected failure — return empty so the caller falls back
|
|
252
|
-
// to the paste prompt.
|
|
253
|
-
return '';
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
// ---------------------------------------------------------------------------
|
|
257
|
-
// Paste-fallback token capture helper (internal)
|
|
229
|
+
// Paste token capture helper (internal)
|
|
258
230
|
// ---------------------------------------------------------------------------
|
|
259
231
|
/**
|
|
260
232
|
* Prompt the user to paste the token shown by `claude setup-token`, extract
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|