switchman-dev 0.1.8 → 0.1.10
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/README.md +118 -303
- package/package.json +1 -1
- package/src/cli/commands/audit.js +77 -0
- package/src/cli/commands/claude.js +37 -0
- package/src/cli/commands/gate.js +278 -0
- package/src/cli/commands/lease.js +256 -0
- package/src/cli/commands/mcp.js +45 -0
- package/src/cli/commands/monitor.js +191 -0
- package/src/cli/commands/queue.js +549 -0
- package/src/cli/commands/task.js +248 -0
- package/src/cli/commands/telemetry.js +108 -0
- package/src/cli/commands/worktree.js +85 -0
- package/src/cli/index.js +780 -1697
- package/src/core/licence.js +82 -57
- package/src.zip +0 -0
- package/tests.zip +0 -0
package/src/core/licence.js
CHANGED
|
@@ -223,15 +223,7 @@ async function refreshToken(refreshToken) {
|
|
|
223
223
|
* Returns { success, email } or { success: false, error }
|
|
224
224
|
*/
|
|
225
225
|
export async function loginWithGitHub() {
|
|
226
|
-
// Use Supabase's PKCE/implicit flow by opening the browser
|
|
227
|
-
// with a special device-style URL that redirects to a local callback
|
|
228
226
|
const { default: open } = await import('open');
|
|
229
|
-
|
|
230
|
-
// We use a simple approach: direct the user to the Pro page sign-in
|
|
231
|
-
// which sets the session, then we poll Supabase for the session
|
|
232
|
-
// using a one-time code approach via the CLI callback server
|
|
233
|
-
|
|
234
|
-
// Start a tiny local HTTP server to catch the OAuth callback
|
|
235
227
|
const { createServer } = await import('http');
|
|
236
228
|
|
|
237
229
|
return new Promise((resolve) => {
|
|
@@ -239,59 +231,95 @@ export async function loginWithGitHub() {
|
|
|
239
231
|
const timeout = setTimeout(() => {
|
|
240
232
|
server?.close();
|
|
241
233
|
resolve({ success: false, error: 'timeout' });
|
|
242
|
-
}, 5 * 60 * 1000);
|
|
234
|
+
}, 5 * 60 * 1000);
|
|
243
235
|
|
|
244
236
|
server = createServer(async (req, res) => {
|
|
245
237
|
const url = new URL(req.url, 'http://localhost:7429');
|
|
246
238
|
|
|
247
239
|
if (url.pathname === '/callback') {
|
|
248
|
-
const code
|
|
249
|
-
const
|
|
240
|
+
const code = url.searchParams.get('code');
|
|
241
|
+
const accessToken = url.searchParams.get('access_token');
|
|
242
|
+
const refreshToken = url.searchParams.get('refresh_token');
|
|
243
|
+
const error = url.searchParams.get('error');
|
|
250
244
|
|
|
251
245
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
252
246
|
res.end(`
|
|
253
|
-
<!DOCTYPE html>
|
|
254
|
-
<html>
|
|
247
|
+
<!DOCTYPE html><html>
|
|
255
248
|
<head><style>
|
|
256
|
-
body { background
|
|
257
|
-
display:
|
|
258
|
-
min-height:
|
|
259
|
-
.box { text-align:
|
|
260
|
-
.ok
|
|
261
|
-
|
|
262
|
-
|
|
249
|
+
body { background:#0b1020; color:#e6eef8; font-family:monospace;
|
|
250
|
+
display:flex; align-items:center; justify-content:center;
|
|
251
|
+
min-height:100vh; margin:0; }
|
|
252
|
+
.box { text-align:center; }
|
|
253
|
+
.ok { color:#4ade80; font-size:48px; }
|
|
254
|
+
.err { color:#f87171; font-size:48px; }
|
|
255
|
+
h2 { font-size:24px; margin:16px 0 8px; }
|
|
256
|
+
p { color:#5f7189; }
|
|
263
257
|
</style></head>
|
|
264
|
-
<body>
|
|
265
|
-
<div class="
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
</div>
|
|
270
|
-
</body>
|
|
271
|
-
</html>
|
|
258
|
+
<body><div class="box">
|
|
259
|
+
<div class="${error ? 'err' : 'ok'}">${error ? '✕' : '✓'}</div>
|
|
260
|
+
<h2>${error ? 'Sign in failed' : 'Signed in successfully'}</h2>
|
|
261
|
+
<p>${error ? 'You can close this tab.' : 'You can close this tab and return to your terminal.'}</p>
|
|
262
|
+
</div></body></html>
|
|
272
263
|
`);
|
|
273
264
|
|
|
274
265
|
clearTimeout(timeout);
|
|
275
266
|
server.close();
|
|
276
267
|
|
|
277
|
-
if (error
|
|
278
|
-
resolve({ success: false, error
|
|
268
|
+
if (error) {
|
|
269
|
+
resolve({ success: false, error });
|
|
279
270
|
return;
|
|
280
271
|
}
|
|
281
272
|
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
},
|
|
290
|
-
body: JSON.stringify({ auth_code: code }),
|
|
273
|
+
// If Supabase sent the token directly as query params
|
|
274
|
+
if (accessToken) {
|
|
275
|
+
saveSession({
|
|
276
|
+
access_token: accessToken,
|
|
277
|
+
refresh_token: refreshToken ?? null,
|
|
278
|
+
expires_in: 3600,
|
|
279
|
+
user: null, // will be fetched on next checkLicence
|
|
291
280
|
});
|
|
281
|
+
// Fetch the user email from Supabase
|
|
282
|
+
try {
|
|
283
|
+
const userRes = await fetch(`${AUTH_URL}/user`, {
|
|
284
|
+
headers: {
|
|
285
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
286
|
+
'apikey': SUPABASE_ANON,
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
if (userRes.ok) {
|
|
290
|
+
const user = await userRes.json();
|
|
291
|
+
const creds = readCredentials() || {};
|
|
292
|
+
writeCredentials({ ...creds, email: user.email, user_id: user.id });
|
|
293
|
+
resolve({ success: true, email: user.email });
|
|
294
|
+
} else {
|
|
295
|
+
resolve({ success: true, email: null });
|
|
296
|
+
}
|
|
297
|
+
} catch {
|
|
298
|
+
resolve({ success: true, email: null });
|
|
299
|
+
}
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
292
302
|
|
|
293
|
-
|
|
294
|
-
|
|
303
|
+
// Exchange the code for a session
|
|
304
|
+
if (code) {
|
|
305
|
+
try {
|
|
306
|
+
const tokenRes = await fetch(`${AUTH_URL}/token?grant_type=pkce`, {
|
|
307
|
+
method: 'POST',
|
|
308
|
+
headers: {
|
|
309
|
+
'Content-Type': 'application/json',
|
|
310
|
+
'apikey': SUPABASE_ANON,
|
|
311
|
+
},
|
|
312
|
+
body: JSON.stringify({ auth_code: code }),
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
if (tokenRes.ok) {
|
|
316
|
+
const session = await tokenRes.json();
|
|
317
|
+
saveSession(session);
|
|
318
|
+
resolve({ success: true, email: session.user?.email ?? null });
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Fallback exchange
|
|
295
323
|
const exchangeRes = await fetch(`${AUTH_URL}/token?grant_type=authorization_code`, {
|
|
296
324
|
method: 'POST',
|
|
297
325
|
headers: {
|
|
@@ -301,32 +329,29 @@ export async function loginWithGitHub() {
|
|
|
301
329
|
body: JSON.stringify({ code }),
|
|
302
330
|
});
|
|
303
331
|
|
|
304
|
-
if (
|
|
305
|
-
|
|
332
|
+
if (exchangeRes.ok) {
|
|
333
|
+
const session = await exchangeRes.json();
|
|
334
|
+
saveSession(session);
|
|
335
|
+
resolve({ success: true, email: session.user?.email ?? null });
|
|
306
336
|
return;
|
|
307
337
|
}
|
|
308
338
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
resolve({ success:
|
|
312
|
-
return;
|
|
339
|
+
resolve({ success: false, error: 'token_exchange_failed' });
|
|
340
|
+
} catch (err) {
|
|
341
|
+
resolve({ success: false, error: err.message });
|
|
313
342
|
}
|
|
314
|
-
|
|
315
|
-
const session = await tokenRes.json();
|
|
316
|
-
saveSession(session);
|
|
317
|
-
resolve({ success: true, email: session.user?.email });
|
|
318
|
-
} catch (err) {
|
|
319
|
-
resolve({ success: false, error: err.message });
|
|
343
|
+
return;
|
|
320
344
|
}
|
|
345
|
+
|
|
346
|
+
resolve({ success: false, error: 'no_code' });
|
|
321
347
|
}
|
|
322
348
|
});
|
|
323
349
|
|
|
324
350
|
server.listen(7429, 'localhost', () => {
|
|
325
|
-
// Build the Supabase GitHub OAuth URL with our local callback
|
|
326
351
|
const params = new URLSearchParams({
|
|
327
|
-
provider:
|
|
352
|
+
provider: 'github',
|
|
328
353
|
redirect_to: 'http://localhost:7429/callback',
|
|
329
|
-
scopes:
|
|
354
|
+
scopes: 'read:user user:email',
|
|
330
355
|
});
|
|
331
356
|
|
|
332
357
|
const loginUrl = `${AUTH_URL}/authorize?${params}`;
|
|
@@ -336,7 +361,7 @@ export async function loginWithGitHub() {
|
|
|
336
361
|
console.log('');
|
|
337
362
|
|
|
338
363
|
open(loginUrl).catch(() => {
|
|
339
|
-
console.log(
|
|
364
|
+
console.log(' Could not open browser automatically.');
|
|
340
365
|
console.log(` Please visit: ${loginUrl}`);
|
|
341
366
|
});
|
|
342
367
|
});
|
package/src.zip
ADDED
|
Binary file
|
package/tests.zip
DELETED
|
Binary file
|