voicecc 1.1.17 → 1.1.19
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/dashboard/routes/auth.ts +43 -26
- package/package.json +1 -1
package/dashboard/routes/auth.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { Hono } from "hono";
|
|
16
|
-
import { execFile } from "child_process";
|
|
16
|
+
import { execFile, execFileSync } from "child_process";
|
|
17
17
|
import pty, { type IPty } from "node-pty";
|
|
18
18
|
import { writeEnvKey } from "../../server/services/env.js";
|
|
19
19
|
|
|
@@ -80,7 +80,6 @@ async function getAuthStatus(): Promise<AuthStatus> {
|
|
|
80
80
|
*/
|
|
81
81
|
function resolveClaudePath(): string {
|
|
82
82
|
try {
|
|
83
|
-
const { execFileSync } = require("child_process");
|
|
84
83
|
return execFileSync("which", [CLAUDE_BIN]).toString().trim();
|
|
85
84
|
} catch {
|
|
86
85
|
return CLAUDE_BIN;
|
|
@@ -121,45 +120,63 @@ function spawnLoginProcess(): Promise<string> {
|
|
|
121
120
|
let resolved = false;
|
|
122
121
|
let step = 0;
|
|
123
122
|
|
|
123
|
+
let loginSent = false;
|
|
124
|
+
let enterDebounce: ReturnType<typeof setTimeout> | null = null;
|
|
125
|
+
|
|
124
126
|
child.onData((data: string) => {
|
|
125
127
|
output += data;
|
|
128
|
+
const clean = data.replace(/\x1b\[[^m]*m/g, "").replace(/\r/g, "").trim();
|
|
129
|
+
if (clean) console.debug(`[auth/login] step=${step} data: ${clean.slice(0, 200)}`);
|
|
126
130
|
|
|
127
|
-
//
|
|
128
|
-
if (
|
|
129
|
-
step = 1;
|
|
130
|
-
console.debug("[auth/login] step 1: accepting trust prompt");
|
|
131
|
-
setTimeout(() => child.write("\r"), 500);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Step 1 → 2: Wait for main prompt, send /login
|
|
135
|
-
if (step === 1 && /v\d+\.\d+\.\d+/.test(output.slice(-2000))) {
|
|
136
|
-
step = 2;
|
|
137
|
-
console.debug("[auth/login] step 2: sending /login");
|
|
138
|
-
setTimeout(() => child.write("/login\r"), 1000);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Step 2 → 3: Select Claude Pro (first option)
|
|
142
|
-
if (step === 2 && /claude.*pro|login.*method/i.test(output.slice(-500))) {
|
|
143
|
-
step = 3;
|
|
144
|
-
console.debug("[auth/login] step 3: selecting Claude Pro");
|
|
145
|
-
setTimeout(() => child.write("\r"), 1000);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Step 3 → done: Capture OAuth URL
|
|
149
|
-
if (step >= 2) {
|
|
131
|
+
// ---- Check for OAuth URL first (can appear at any point after /login) ----
|
|
132
|
+
if (loginSent) {
|
|
150
133
|
const urlMatch = output.match(/(https:\/\/claude\.ai\/oauth\/authorize\S+)/);
|
|
151
134
|
if (urlMatch && !resolved) {
|
|
152
135
|
resolved = true;
|
|
153
136
|
step = 4;
|
|
154
|
-
console.debug("[auth/login]
|
|
137
|
+
console.debug("[auth/login] URL captured");
|
|
155
138
|
pendingLogin = {
|
|
156
139
|
pty: child,
|
|
157
140
|
url: urlMatch[1],
|
|
158
141
|
createdAt: Date.now(),
|
|
159
142
|
};
|
|
160
143
|
resolve(urlMatch[1]);
|
|
144
|
+
return;
|
|
161
145
|
}
|
|
162
146
|
}
|
|
147
|
+
|
|
148
|
+
if (resolved) return;
|
|
149
|
+
|
|
150
|
+
// ---- Before /login: dismiss any setup prompt by pressing Enter ----
|
|
151
|
+
// The CLI may show trust, theme picker, or other selection prompts.
|
|
152
|
+
// They all show ❯ with numbered options. We debounce to avoid spamming.
|
|
153
|
+
if (!loginSent) {
|
|
154
|
+
// Detect the main input prompt: sparkle animation = CLI is ready
|
|
155
|
+
if (/[✻✽✶✢]/.test(data)) {
|
|
156
|
+
loginSent = true;
|
|
157
|
+
console.debug("[auth/login] main prompt ready, sending /login");
|
|
158
|
+
setTimeout(() => child.write("/login\r"), 1000);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Any selection prompt (❯ followed by numbered items): press Enter
|
|
163
|
+
if (/❯/.test(data)) {
|
|
164
|
+
if (enterDebounce) clearTimeout(enterDebounce);
|
|
165
|
+
enterDebounce = setTimeout(() => {
|
|
166
|
+
console.debug("[auth/login] dismissing selection prompt");
|
|
167
|
+
child.write("\r");
|
|
168
|
+
}, 800);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ---- After /login: dismiss the login method picker ----
|
|
173
|
+
if (loginSent && step < 4 && /❯/.test(data)) {
|
|
174
|
+
if (enterDebounce) clearTimeout(enterDebounce);
|
|
175
|
+
enterDebounce = setTimeout(() => {
|
|
176
|
+
console.debug("[auth/login] selecting first option in login picker");
|
|
177
|
+
child.write("\r");
|
|
178
|
+
}, 800);
|
|
179
|
+
}
|
|
163
180
|
});
|
|
164
181
|
|
|
165
182
|
child.onExit(({ exitCode }: { exitCode: number }) => {
|