@wrongstack/cli 1.1.1 → 1.1.4

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 (42) hide show
  1. package/dist/{acp-HCGUTFNE.js → acp-MZ5MQBFN.js} +13 -5
  2. package/dist/acp-leader/acp-leader-confirm.d.ts +18 -0
  3. package/dist/acp-leader/acp-leader-context.d.ts +29 -0
  4. package/dist/acp-leader/acp-leader-fleet.d.ts +26 -0
  5. package/dist/acp-leader/acp-leader-host-binding.d.ts +16 -0
  6. package/dist/acp-leader/acp-leader-host.d.ts +80 -0
  7. package/dist/acp-leader/acp-leader-picker.d.ts +21 -0
  8. package/dist/acp-leader/acp-leader-provider.d.ts +85 -0
  9. package/dist/acp-leader/acp-leader-resume.d.ts +10 -0
  10. package/dist/acp-leader/acp-leader-stream.d.ts +82 -0
  11. package/dist/{auth-ANOVZVHE.js → auth-IHQS6AFW.js} +60 -64
  12. package/dist/auth-menu/index.d.ts +1 -2
  13. package/dist/boot/dispatch-webui.d.ts +16 -0
  14. package/dist/{chunk-GRAGMA4B.js → chunk-2LTHDKZX.js} +4 -4
  15. package/dist/chunk-3LEIFO5D.js +65 -0
  16. package/dist/chunk-COGI7EQU.js +1458 -0
  17. package/dist/chunk-GKGWPFW2.js +50 -0
  18. package/dist/{chunk-RAWHRRUJ.js → chunk-I5LJLKA3.js} +198 -197
  19. package/dist/{chunk-5TRZZHMN.js → chunk-JCZ2D3VV.js} +4 -65
  20. package/dist/{chunk-XT3NAHRX.js → chunk-JKTJSLUT.js} +192 -1
  21. package/dist/{chunk-NMXQFQ26.js → chunk-TAE3EGBM.js} +3 -3
  22. package/dist/{chunk-3R3OADC5.js → chunk-ZF4HRR5F.js} +7 -3
  23. package/dist/{cli-context-A6XDEXN5.js → cli-context-E44HQ4ZO.js} +17 -8
  24. package/dist/{cli-main-5UGSW4TO.js → cli-main-OT63I2FX.js} +490 -228
  25. package/dist/{execution-BAP566QC.js → execution-OK34CJKJ.js} +7 -2
  26. package/dist/fleet/acp-live-steer.d.ts +28 -0
  27. package/dist/fleet/acp-permission-bridge.d.ts +49 -0
  28. package/dist/fleet/acp-quota-hold.d.ts +3 -0
  29. package/dist/fleet/acp-quota-reading.d.ts +3 -0
  30. package/dist/fleet/acp-turn-reminders.d.ts +15 -0
  31. package/dist/fleet/acp-wrongstack-bridge.d.ts +42 -0
  32. package/dist/fleet/host-acp.d.ts +20 -2
  33. package/dist/index.js +7 -4
  34. package/dist/{mcp-2XWBJEQN.js → mcp-W7A5HUXV.js} +97 -1
  35. package/dist/mcp-serve-project.d.ts +18 -0
  36. package/dist/{per-subcommand-help-D6J4ZXW2.js → per-subcommand-help-4GYSCMLU.js} +2 -2
  37. package/dist/{short-circuit-flags-CPCT5MWB.js → short-circuit-flags-QEXUS3BY.js} +2 -2
  38. package/dist/{subcommands-VTMIZQBP.js → subcommands-YADUV7IJ.js} +2 -2
  39. package/dist/{webui-server-HIUY3RHD.js → webui-server-CB64CFDG.js} +41 -3
  40. package/package.json +34 -30
  41. package/dist/auth-menu/anthropic-oauth.d.ts +0 -43
  42. package/dist/chunk-ZNNFEKDZ.js +0 -319
@@ -0,0 +1,50 @@
1
+
2
+ // src/acp-leader/acp-leader-host.ts
3
+ var ACP_LEADER_PROVIDER_ID = "acp";
4
+ var bound;
5
+ var sessionAgents;
6
+ function setAcpLeaderSessionAgents(resolve) {
7
+ sessionAgents = resolve;
8
+ }
9
+ function acpLeaderSessionAgent(sessionId) {
10
+ return sessionAgents?.(sessionId);
11
+ }
12
+ function bindAcpLeaderHost(host) {
13
+ bound = host;
14
+ }
15
+ function acpLeaderHost() {
16
+ return bound;
17
+ }
18
+ function confirmAcpLeaderThroughEvents() {
19
+ if (bound) bound = { ...bound, confirmAwaiter: void 0, confirmThroughEvents: true };
20
+ }
21
+ var liveLeaders = /* @__PURE__ */ new Set();
22
+ function trackAcpLeader(leader) {
23
+ liveLeaders.add(leader);
24
+ }
25
+ async function closeAcpLeaderSessions(timeoutMs = 1500) {
26
+ if (liveLeaders.size === 0) return;
27
+ const all = [...liveLeaders];
28
+ liveLeaders.clear();
29
+ let timer;
30
+ await Promise.race([
31
+ Promise.all(all.map((leader) => leader.closeAll().catch(() => void 0))),
32
+ new Promise((resolve) => {
33
+ timer = setTimeout(resolve, timeoutMs);
34
+ timer.unref?.();
35
+ })
36
+ ]);
37
+ if (timer) clearTimeout(timer);
38
+ }
39
+
40
+ export {
41
+ ACP_LEADER_PROVIDER_ID,
42
+ setAcpLeaderSessionAgents,
43
+ acpLeaderSessionAgent,
44
+ bindAcpLeaderHost,
45
+ acpLeaderHost,
46
+ confirmAcpLeaderThroughEvents,
47
+ trackAcpLeader,
48
+ closeAcpLeaderSessions
49
+ };
50
+ //# sourceMappingURL=chunk-GKGWPFW2.js.map
@@ -171,12 +171,11 @@ function decideAuthLocalEvents(opts) {
171
171
  return events;
172
172
  }
173
173
 
174
- // src/auth-menu/provider-auth-login.ts
175
- import { color, toErrorMessage } from "@wrongstack/core/utils";
176
- import {
177
- applyProviderAuthOutcome,
178
- createBuiltinProviderAuthRegistry
179
- } from "@wrongstack/providers/oauth";
174
+ // src/auth-menu/local.ts
175
+ import { DefaultSecretScrubber as DefaultSecretScrubber2 } from "@wrongstack/core/security";
176
+ import { color as color2 } from "@wrongstack/core/utils";
177
+ import { authProfileAliasError } from "@wrongstack/providers";
178
+ import { probeLocalLlm } from "@wrongstack/runtime/probe";
180
179
 
181
180
  // src/auth-menu/helpers.ts
182
181
  async function loadProviders(deps) {
@@ -186,125 +185,6 @@ async function loadProviders(deps) {
186
185
  });
187
186
  }
188
187
 
189
- // src/auth-menu/provider-auth-login.ts
190
- var defaultRegistry;
191
- function providerAuthRegistryFor(deps) {
192
- if (deps.providerAuthRegistry) return deps.providerAuthRegistry;
193
- defaultRegistry ??= createBuiltinProviderAuthRegistry();
194
- return defaultRegistry;
195
- }
196
- function providerAuthStrategiesFor(deps) {
197
- return providerAuthRegistryFor(deps).list();
198
- }
199
- function hyperlink(url) {
200
- return `\x1B]8;;${url}\x1B\\${url}\x1B]8;;\x1B\\`;
201
- }
202
- async function runProviderAuthLogin(deps, strategyId, opts = {}) {
203
- const registry = providerAuthRegistryFor(deps);
204
- const strategy = registry.get(strategyId);
205
- if (!strategy) {
206
- deps.renderer.writeError(`Unknown OAuth login "${strategyId}".`);
207
- return 1;
208
- }
209
- const controller = new AbortController();
210
- let sigintCount = 0;
211
- const onSigint = () => {
212
- sigintCount += 1;
213
- if (sigintCount === 1) {
214
- deps.renderer.write(
215
- color.dim("\n Cancelling sign-in\u2026 (press Ctrl+C again to force-quit)\n")
216
- );
217
- controller.abort();
218
- } else {
219
- process.exit(130);
220
- }
221
- };
222
- const onExternalAbort = () => controller.abort();
223
- if (opts.signal) {
224
- if (opts.signal.aborted) controller.abort();
225
- else opts.signal.addEventListener("abort", onExternalAbort, { once: true });
226
- } else {
227
- process.on("SIGINT", onSigint);
228
- }
229
- let session;
230
- try {
231
- deps.renderer.write(
232
- color.bold(`
233
- Sign in with ${strategy.label}`) + color.dim(` \u2192 ${opts.providerId ?? strategy.providerId}
234
- `)
235
- );
236
- const saved = strategy.id === "chatgpt-api" ? (await loadProviders(deps))[opts.providerId ?? strategy.providerId] : void 0;
237
- const credential = saved?.apiKeys?.find((key) => key.label === saved.activeKey) ?? saved?.apiKeys?.[0];
238
- session = await registry.begin(
239
- strategy.id,
240
- { modelsRegistry: deps.modelsRegistry, ...credential ? { credential } : {} },
241
- controller.signal
242
- );
243
- let outcome;
244
- if (session.interaction.type === "device_code") {
245
- const { verificationUri, userCode } = session.interaction;
246
- deps.renderer.write(
247
- color.bold("\n Open this URL and enter the code:\n") + color.cyan(` ${hyperlink(verificationUri)}
248
- `) + color.bold(` Code: ${userCode}
249
- `) + color.dim(" Waiting for authorization\u2026\n")
250
- );
251
- openBrowser(verificationUri);
252
- outcome = await session.waitForCompletion(controller.signal);
253
- } else {
254
- const { authorizeUrl, bound } = session.interaction;
255
- deps.renderer.write(
256
- color.bold("\n Open this URL in your browser to sign in:\n") + color.cyan(` ${hyperlink(authorizeUrl)}
257
- `)
258
- );
259
- if (bound) {
260
- openBrowser(authorizeUrl);
261
- deps.renderer.write(color.dim(" Waiting for browser authorization\u2026\n"));
262
- outcome = await session.waitForCompletion(controller.signal);
263
- } else {
264
- const input = (await deps.reader.readLine(
265
- `
266
- ${color.amber("?")} Paste the redirect URL or code ${color.dim("(or q to cancel)")}: `
267
- )).trim();
268
- if (!input || input.toLowerCase() === "q") return 1;
269
- outcome = await session.completeWithCode(input, controller.signal);
270
- }
271
- }
272
- if (!outcome) {
273
- deps.renderer.write(color.dim(" Sign-in cancelled or timed out.\n"));
274
- return 1;
275
- }
276
- controller.signal.throwIfAborted();
277
- await mutateConfigProviders(
278
- deps.profileConfigPath,
279
- deps.vault,
280
- (providers) => {
281
- controller.signal.throwIfAborted();
282
- applyProviderAuthOutcome(providers, outcome, { targetProviderId: opts.providerId });
283
- },
284
- deps.profileConfigPath
285
- );
286
- const savedId = opts.providerId ?? outcome.providerId;
287
- deps.renderer.write(color.green(`
288
- \u2713 Signed in \u2014 saved as ${savedId}.
289
- `));
290
- return 0;
291
- } catch (error) {
292
- const message = error instanceof DOMException && error.name === "AbortError" ? "Login cancelled." : toErrorMessage(error);
293
- deps.renderer.writeError(` Login failed: ${message}`);
294
- return 1;
295
- } finally {
296
- session?.close();
297
- if (opts.signal) opts.signal.removeEventListener("abort", onExternalAbort);
298
- else process.off("SIGINT", onSigint);
299
- }
300
- }
301
-
302
- // src/auth-menu/local.ts
303
- import { DefaultSecretScrubber as DefaultSecretScrubber2 } from "@wrongstack/core/security";
304
- import { color as color3 } from "@wrongstack/core/utils";
305
- import { authProfileAliasError } from "@wrongstack/providers";
306
- import { probeLocalLlm } from "@wrongstack/runtime/probe";
307
-
308
188
  // src/auth-menu/local-presets.ts
309
189
  import { projectLocalProviderPresets } from "@wrongstack/providers/definitions";
310
190
  var LOCAL_LLM_PRESETS = projectLocalProviderPresets();
@@ -318,24 +198,24 @@ function parseAuthMenuIndex(raw) {
318
198
  }
319
199
 
320
200
  // src/auth-menu/shared.ts
321
- import { color as color2 } from "@wrongstack/core/utils";
201
+ import { color } from "@wrongstack/core/utils";
322
202
  function renderProviderLine(renderer, id, cfg, idx) {
323
203
  const keys = normalizeKeys(cfg);
324
204
  const active = activeLabel(cfg, keys);
325
205
  const firstKey = keys[0];
326
206
  let summary;
327
207
  if (keys.length === 0) {
328
- summary = color2.dim("(no keys)");
208
+ summary = color.dim("(no keys)");
329
209
  } else if (keys.length === 1) {
330
210
  summary = maskedKey(firstKey?.apiKey ?? "");
331
211
  } else {
332
212
  const activeKeyObj = active != null ? keys.find((k) => k.label === active) : void 0;
333
- summary = `${color2.dim(`${keys.length} keys`)} ${color2.dim("active:")} ${color2.bold(active ?? "?")} ` + maskedKey(activeKeyObj?.apiKey ?? firstKey?.apiKey ?? "");
213
+ summary = `${color.dim(`${keys.length} keys`)} ${color.dim("active:")} ${color.bold(active ?? "?")} ` + maskedKey(activeKeyObj?.apiKey ?? firstKey?.apiKey ?? "");
334
214
  }
335
- const fam = cfg.family ? color2.dim(`[${cfg.family}]`) : "";
336
- const aliasHint = cfg.type && cfg.type !== id ? color2.dim(`\u2192 ${cfg.type}`) : "";
215
+ const fam = cfg.family ? color.dim(`[${cfg.family}]`) : "";
216
+ const aliasHint = cfg.type && cfg.type !== id ? color.dim(`\u2192 ${cfg.type}`) : "";
337
217
  renderer.write(
338
- ` ${color2.dim(`${idx}.`.padStart(4))} ${id.padEnd(22)} ${fam} ${aliasHint} ${summary}
218
+ ` ${color.dim(`${idx}.`.padStart(4))} ${id.padEnd(22)} ${fam} ${aliasHint} ${summary}
339
219
  `
340
220
  );
341
221
  }
@@ -344,23 +224,23 @@ function renderProviderHeader(renderer, providerId, cfg) {
344
224
  const active = activeLabel(cfg, keys);
345
225
  renderer.write(
346
226
  `
347
- ${color2.bold(providerId)} ${cfg.family ? color2.dim(`[${cfg.family}]`) : color2.amber("[no family]")}
227
+ ${color.bold(providerId)} ${cfg.family ? color.dim(`[${cfg.family}]`) : color.amber("[no family]")}
348
228
  `
349
229
  );
350
230
  const details = [
351
- color2.dim(` type: ${cfg.type ?? providerId}`),
352
- color2.dim(` family: ${cfg.family ?? "(unset \u2192 resolved from models.dev when type matches)"}`),
353
- color2.dim(` baseUrl: ${cfg.baseUrl ?? "(unset \u2192 catalog default)"}`)
231
+ color.dim(` type: ${cfg.type ?? providerId}`),
232
+ color.dim(` family: ${cfg.family ?? "(unset \u2192 resolved from models.dev when type matches)"}`),
233
+ color.dim(` baseUrl: ${cfg.baseUrl ?? "(unset \u2192 catalog default)"}`)
354
234
  ];
355
235
  if (cfg.envVars && cfg.envVars.length > 0) {
356
- details.push(color2.dim(` envVars: ${cfg.envVars.join(", ")}`));
236
+ details.push(color.dim(` envVars: ${cfg.envVars.join(", ")}`));
357
237
  }
358
238
  if (cfg.models && cfg.models.length > 0) {
359
- details.push(color2.dim(` models: ${cfg.models.join(", ")}`));
239
+ details.push(color.dim(` models: ${cfg.models.join(", ")}`));
360
240
  }
361
241
  renderer.write(details.join("\n") + "\n");
362
242
  if (keys.length === 0) {
363
- renderer.write(color2.dim(" (no keys saved)\n"));
243
+ renderer.write(color.dim(" (no keys saved)\n"));
364
244
  } else {
365
245
  for (let i = 0; i < keys.length; i++) {
366
246
  const key = keys[i];
@@ -369,56 +249,56 @@ ${color2.bold(providerId)} ${cfg.family ? color2.dim(`[${cfg.family}]`) : color2
369
249
  }
370
250
  }
371
251
  function renderKeyLine(renderer, key, idx, active) {
372
- const marker = key.label === active ? color2.green("\u25CF") : color2.dim("\u25CB");
252
+ const marker = key.label === active ? color.green("\u25CF") : color.dim("\u25CB");
373
253
  renderer.write(
374
- ` ${color2.dim(`${idx}.`.padStart(4))} ${marker} ${key.label.padEnd(20)} ${maskedKey(key.apiKey)} ${color2.dim(key.createdAt)}
254
+ ` ${color.dim(`${idx}.`.padStart(4))} ${marker} ${key.label.padEnd(20)} ${maskedKey(key.apiKey)} ${color.dim(key.createdAt)}
375
255
  `
376
256
  );
377
257
  }
378
258
  function renderActions(renderer, keysLength) {
379
259
  renderer.write(`
380
- ${color2.dim("Actions:")}
260
+ ${color.dim("Actions:")}
381
261
  `);
382
- renderer.write(` ${color2.bold("a")} Add another key
262
+ renderer.write(` ${color.bold("a")} Add another key
383
263
  `);
384
264
  if (keysLength > 0) {
385
- renderer.write(` ${color2.bold("u")} <n> Update key <n>
265
+ renderer.write(` ${color.bold("u")} <n> Update key <n>
386
266
  `);
387
- renderer.write(` ${color2.bold("d")} <n> Delete key <n>
267
+ renderer.write(` ${color.bold("d")} <n> Delete key <n>
388
268
  `);
389
- renderer.write(` ${color2.bold("s")} <n> Set key <n> as active
269
+ renderer.write(` ${color.bold("s")} <n> Set key <n> as active
390
270
  `);
391
271
  }
392
- renderer.write(` ${color2.bold("f")} Edit family
272
+ renderer.write(` ${color.bold("f")} Edit family
393
273
  `);
394
274
  renderer.write(
395
- ` ${color2.bold("B")} Edit baseUrl ${color2.dim("(capital B \u2014 b is Back)")}
275
+ ` ${color.bold("B")} Edit baseUrl ${color.dim("(capital B \u2014 b is Back)")}
396
276
  `
397
277
  );
398
- renderer.write(` ${color2.bold("m")} Edit visible model list
278
+ renderer.write(` ${color.bold("m")} Edit visible model list
399
279
  `);
400
- renderer.write(` ${color2.bold("x")} Remove this provider entirely
280
+ renderer.write(` ${color.bold("x")} Remove this provider entirely
401
281
  `);
402
- renderer.write(` ${color2.bold("b")} Back
282
+ renderer.write(` ${color.bold("b")} Back
403
283
  `);
404
- renderer.write(` ${color2.bold("q")} Quit
284
+ renderer.write(` ${color.bold("q")} Quit
405
285
  `);
406
286
  }
407
287
  function renderTopMenu(renderer, providers) {
408
288
  renderer.write(`
409
- ${color2.bold("WrongStack")} ${color2.dim("\u2014 API key manager")}
289
+ ${color.bold("WrongStack")} ${color.dim("\u2014 API key manager")}
410
290
 
411
291
  `);
412
292
  const ids = Object.keys(providers).sort();
413
293
  if (ids.length === 0) {
414
- renderer.write(color2.dim(" No providers configured yet.\n"));
294
+ renderer.write(color.dim(" No providers configured yet.\n"));
415
295
  renderer.write(
416
- color2.dim(
296
+ color.dim(
417
297
  " Use (a) to add one from the models.dev catalog, (l) for a local server, or (c) for a custom provider.\n"
418
298
  )
419
299
  );
420
300
  } else {
421
- renderer.write(` ${color2.dim("Saved providers:")}
301
+ renderer.write(` ${color.dim("Saved providers:")}
422
302
  `);
423
303
  let idx = 1;
424
304
  for (const id of ids) {
@@ -429,30 +309,30 @@ ${color2.bold("WrongStack")} ${color2.dim("\u2014 API key manager")}
429
309
  }
430
310
  }
431
311
  renderer.write(`
432
- ${color2.dim("Actions:")}
312
+ ${color.dim("Actions:")}
433
313
  `);
434
- renderer.write(` ${color2.bold("a")} Add a provider (from catalog)
314
+ renderer.write(` ${color.bold("a")} Add a provider (from catalog)
435
315
  `);
436
316
  renderer.write(
437
- ` ${color2.bold("l")} Add a local server ${color2.dim("(OmniRoute / Ollama / vLLM / LM Studio)")}
317
+ ` ${color.bold("l")} Add a local server ${color.dim("(OmniRoute / Ollama / vLLM / LM Studio)")}
438
318
  `
439
319
  );
440
- renderer.write(` ${color2.bold("c")} Add a custom provider
320
+ renderer.write(` ${color.bold("c")} Add a custom provider
441
321
  `);
442
- renderer.write(` ${color2.bold("s")} Login with provider OAuth
322
+ renderer.write(` ${color.bold("s")} Login with provider OAuth
443
323
  `);
444
324
  if (ids.length > 0) {
445
325
  renderer.write(
446
- ` ${color2.dim("1-")}${color2.dim(String(ids.length))} ${color2.bold("Manage a provider")}
326
+ ` ${color.dim("1-")}${color.dim(String(ids.length))} ${color.bold("Manage a provider")}
447
327
  `
448
328
  );
449
329
  }
450
- renderer.write(` ${color2.bold("q")} Quit
330
+ renderer.write(` ${color.bold("q")} Quit
451
331
  `);
452
332
  }
453
333
  async function readKeyInput(deps, intent) {
454
334
  const key = (await deps.reader.readSecret(
455
- ` ${color2.amber("?")} ${intent} ${color2.dim("(hidden, paste OK)")}: `
335
+ ` ${color.amber("?")} ${intent} ${color.dim("(hidden, paste OK)")}: `
456
336
  )).trim();
457
337
  if (!key) {
458
338
  deps.renderer.writeError("No key entered.");
@@ -461,7 +341,7 @@ async function readKeyInput(deps, intent) {
461
341
  return key;
462
342
  }
463
343
  async function confirm(deps, question) {
464
- const answer = (await deps.reader.readLine(` ${color2.amber("?")} ${question} ${color2.dim("[y/N/q]")} `)).trim().toLowerCase();
344
+ const answer = (await deps.reader.readLine(` ${color.amber("?")} ${question} ${color.dim("[y/N/q]")} `)).trim().toLowerCase();
465
345
  if (answer === "q" || answer === "quit") return null;
466
346
  return answer === "y" || answer === "yes";
467
347
  }
@@ -540,7 +420,7 @@ async function runAuthLocal(deps, opts = {}) {
540
420
  if (!probe.ok) {
541
421
  if (chosen.noAuth) {
542
422
  deps.renderer.write(
543
- color3.dim(
423
+ color2.dim(
544
424
  ` Saving ${chosen.label} anyway \u2014 keyless local gateway needs no key and discovers models when it comes up.
545
425
  `
546
426
  )
@@ -549,7 +429,7 @@ async function runAuthLocal(deps, opts = {}) {
549
429
  } else {
550
430
  const saveAnyway = await promptSaveAnyway(deps);
551
431
  if (!saveAnyway) {
552
- deps.renderer.write(color3.dim(" Cancelled. Nothing saved.\n"));
432
+ deps.renderer.write(color2.dim(" Cancelled. Nothing saved.\n"));
553
433
  return 0;
554
434
  }
555
435
  probeFailedAndSaved = true;
@@ -614,19 +494,19 @@ async function runAuthLocal(deps, opts = {}) {
614
494
  }
615
495
  if (apiKey) {
616
496
  deps.renderer.write(
617
- ` ${color3.green("\u2713")} Saved ${color3.bold(profileId)}/${color3.bold(finalLabel)} \u2192 ${color3.cyan(baseUrl)}
497
+ ` ${color2.green("\u2713")} Saved ${color2.bold(profileId)}/${color2.bold(finalLabel)} \u2192 ${color2.cyan(baseUrl)}
618
498
  `
619
499
  );
620
500
  } else {
621
501
  deps.renderer.write(
622
- ` ${color3.green("\u2713")} Saved ${color3.bold(profileId)} (no key) \u2192 ${color3.cyan(baseUrl)}
502
+ ` ${color2.green("\u2713")} Saved ${color2.bold(profileId)} (no key) \u2192 ${color2.cyan(baseUrl)}
623
503
  `
624
504
  );
625
505
  }
626
506
  const firstModel = resolvedModels && resolvedModels.length > 0 ? resolvedModels[0] : null;
627
- const modelHint = firstModel ? color3.cyan(firstModel) : color3.dim("<model-id>");
507
+ const modelHint = firstModel ? color2.cyan(firstModel) : color2.dim("<model-id>");
628
508
  deps.renderer.write(
629
- color3.dim(` Launch: wstack --provider ${profileId} --model ${modelHint} "<task>"
509
+ color2.dim(` Launch: wstack --provider ${profileId} --model ${modelHint} "<task>"
630
510
  `)
631
511
  );
632
512
  return 0;
@@ -658,47 +538,47 @@ function resolveModelList(models, probe, scrubber) {
658
538
  return out;
659
539
  }
660
540
  function renderProbeResult(deps, probe, opts = {}) {
661
- const label = opts.presetLabel ? ` ${color3.bold(opts.presetLabel)}` : "";
662
- const elapsed = probe.elapsedMs !== void 0 ? ` ${color3.dim(`(${probe.elapsedMs}ms)`)}` : "";
541
+ const label = opts.presetLabel ? ` ${color2.bold(opts.presetLabel)}` : "";
542
+ const elapsed = probe.elapsedMs !== void 0 ? ` ${color2.dim(`(${probe.elapsedMs}ms)`)}` : "";
663
543
  switch (probe.status) {
664
544
  case "ok": {
665
- const models = probe.modelCount !== void 0 ? color3.dim(`, ${probe.modelCount} model${probe.modelCount === 1 ? "" : "s"}`) : "";
666
- deps.renderer.write(` ${color3.green("\u25CF")} ${label} health probe ok${models}${elapsed}
545
+ const models = probe.modelCount !== void 0 ? color2.dim(`, ${probe.modelCount} model${probe.modelCount === 1 ? "" : "s"}`) : "";
546
+ deps.renderer.write(` ${color2.green("\u25CF")} ${label} health probe ok${models}${elapsed}
667
547
  `);
668
548
  break;
669
549
  }
670
550
  case "timeout": {
671
551
  deps.renderer.write(
672
- ` ${color3.red("\u25CF")} ${label} health probe timed out${elapsed}
673
- ${color3.dim("The server did not respond within the timeout.")}
674
- ${color3.dim("Is the local server running? Check the port and try again.")}
552
+ ` ${color2.red("\u25CF")} ${label} health probe timed out${elapsed}
553
+ ${color2.dim("The server did not respond within the timeout.")}
554
+ ${color2.dim("Is the local server running? Check the port and try again.")}
675
555
  `
676
556
  );
677
557
  break;
678
558
  }
679
559
  case "unreachable": {
680
- const detail = probe.detail ? ` ${color3.dim(`(${probe.detail})`)}` : "";
560
+ const detail = probe.detail ? ` ${color2.dim(`(${probe.detail})`)}` : "";
681
561
  deps.renderer.write(
682
- ` ${color3.red("\u25CF")} ${label} server unreachable${detail}
683
- ${color3.dim("Could not connect. Common causes:")}
684
- ${color3.dim(" - The local server is not running")}
685
- ${color3.dim(" - The port is blocked by a firewall")}
686
- ${color3.dim(" - The base URL is wrong")}
562
+ ` ${color2.red("\u25CF")} ${label} server unreachable${detail}
563
+ ${color2.dim("Could not connect. Common causes:")}
564
+ ${color2.dim(" - The local server is not running")}
565
+ ${color2.dim(" - The port is blocked by a firewall")}
566
+ ${color2.dim(" - The base URL is wrong")}
687
567
  `
688
568
  );
689
569
  break;
690
570
  }
691
571
  case "http_error": {
692
572
  const status = probe.httpStatus !== void 0 ? ` HTTP ${probe.httpStatus}` : "";
693
- const detail = probe.detail ? ` ${color3.dim(`\u2014 ${probe.detail}`)}` : "";
694
- deps.renderer.write(` ${color3.yellow("\u25CF")} ${label} health probe got${status}${detail}
573
+ const detail = probe.detail ? ` ${color2.dim(`\u2014 ${probe.detail}`)}` : "";
574
+ deps.renderer.write(` ${color2.yellow("\u25CF")} ${label} health probe got${status}${detail}
695
575
  `);
696
576
  break;
697
577
  }
698
578
  case "invalid_response": {
699
579
  deps.renderer.write(
700
- ` ${color3.yellow("\u25CF")} ${label} health probe returned an unexpected shape
701
- ` + (probe.detail ? ` ${color3.dim(probe.detail)}
580
+ ` ${color2.yellow("\u25CF")} ${label} health probe returned an unexpected shape
581
+ ` + (probe.detail ? ` ${color2.dim(probe.detail)}
702
582
  ` : "")
703
583
  );
704
584
  break;
@@ -711,31 +591,31 @@ function renderProbeResult(deps, probe, opts = {}) {
711
591
  async function promptSaveAnyway(deps) {
712
592
  const answer = (await deps.reader.readLine(
713
593
  `
714
- ${color3.amber("?")} ${color3.bold("Save anyway?")} ${color3.dim("[y/N]")}: `
594
+ ${color2.amber("?")} ${color2.bold("Save anyway?")} ${color2.dim("[y/N]")}: `
715
595
  )).trim().toLowerCase();
716
596
  return answer === "y" || answer === "yes";
717
597
  }
718
598
  async function pickLocalPreset(deps) {
719
599
  deps.renderer.write(
720
600
  `
721
- ${color3.bold("Local LLM servers")} ${color3.dim("\u2014 pick one to pre-fill the base URL")}
601
+ ${color2.bold("Local LLM servers")} ${color2.dim("\u2014 pick one to pre-fill the base URL")}
722
602
 
723
603
  `
724
604
  );
725
605
  let idx = 1;
726
606
  for (const entry of LOCAL_LLM_PRESETS) {
727
- const auth = entry.noAuth ? color3.dim("(no auth)") : color3.dim("(optional auth)");
607
+ const auth = entry.noAuth ? color2.dim("(no auth)") : color2.dim("(optional auth)");
728
608
  deps.renderer.write(
729
- ` ${color3.dim(`${idx}.`.padStart(4))} ${color3.bold(entry.label.padEnd(12))} ${color3.cyan(entry.defaultBaseUrl.padEnd(34))} ${auth}
609
+ ` ${color2.dim(`${idx}.`.padStart(4))} ${color2.bold(entry.label.padEnd(12))} ${color2.cyan(entry.defaultBaseUrl.padEnd(34))} ${auth}
730
610
  `
731
611
  );
732
- deps.renderer.write(` ${color3.dim(entry.hint)}
612
+ deps.renderer.write(` ${color2.dim(entry.hint)}
733
613
  `);
734
614
  idx++;
735
615
  }
736
616
  const answer = (await deps.reader.readLine(
737
617
  `
738
- ${color3.amber("?")} Pick ${color3.dim(`(1-${LOCAL_LLM_PRESETS.length}, q to quit)`)}: `
618
+ ${color2.amber("?")} Pick ${color2.dim(`(1-${LOCAL_LLM_PRESETS.length}, q to quit)`)}: `
739
619
  )).trim().toLowerCase();
740
620
  if (!answer || answer === "q" || answer === "quit") return void 0;
741
621
  const num = parseAuthMenuIndex(answer);
@@ -749,12 +629,133 @@ ${color3.amber("?")} Pick ${color3.dim(`(1-${LOCAL_LLM_PRESETS.length}, q to qui
749
629
  }
750
630
  async function promptOptionalKey(deps, preset) {
751
631
  const answer = (await deps.reader.readSecret(
752
- ` ${color3.amber("?")} ${color3.bold(preset.label)} API key ${color3.dim("(hidden \u2014 Enter to skip if auth is disabled on the server)")}: `
632
+ ` ${color2.amber("?")} ${color2.bold(preset.label)} API key ${color2.dim("(hidden \u2014 Enter to skip if auth is disabled on the server)")}: `
753
633
  )).trim();
754
634
  if (!answer) return void 0;
755
635
  return answer;
756
636
  }
757
637
 
638
+ // src/auth-menu/provider-auth-login.ts
639
+ import { color as color3, toErrorMessage } from "@wrongstack/core/utils";
640
+ import {
641
+ applyProviderAuthOutcome,
642
+ createBuiltinProviderAuthRegistry,
643
+ retiredProviderAuthLoginHint
644
+ } from "@wrongstack/providers/oauth";
645
+ var defaultRegistry;
646
+ function providerAuthRegistryFor(deps) {
647
+ if (deps.providerAuthRegistry) return deps.providerAuthRegistry;
648
+ defaultRegistry ??= createBuiltinProviderAuthRegistry();
649
+ return defaultRegistry;
650
+ }
651
+ function providerAuthStrategiesFor(deps) {
652
+ return providerAuthRegistryFor(deps).list();
653
+ }
654
+ function hyperlink(url) {
655
+ return `\x1B]8;;${url}\x1B\\${url}\x1B]8;;\x1B\\`;
656
+ }
657
+ async function runProviderAuthLogin(deps, strategyId, opts = {}) {
658
+ const registry = providerAuthRegistryFor(deps);
659
+ const strategy = registry.get(strategyId);
660
+ if (!strategy) {
661
+ deps.renderer.writeError(
662
+ retiredProviderAuthLoginHint(strategyId) ?? `Unknown OAuth login "${strategyId}".`
663
+ );
664
+ return 1;
665
+ }
666
+ const controller = new AbortController();
667
+ let sigintCount = 0;
668
+ const onSigint = () => {
669
+ sigintCount += 1;
670
+ if (sigintCount === 1) {
671
+ deps.renderer.write(
672
+ color3.dim("\n Cancelling sign-in\u2026 (press Ctrl+C again to force-quit)\n")
673
+ );
674
+ controller.abort();
675
+ } else {
676
+ process.exit(130);
677
+ }
678
+ };
679
+ const onExternalAbort = () => controller.abort();
680
+ if (opts.signal) {
681
+ if (opts.signal.aborted) controller.abort();
682
+ else opts.signal.addEventListener("abort", onExternalAbort, { once: true });
683
+ } else {
684
+ process.on("SIGINT", onSigint);
685
+ }
686
+ let session;
687
+ try {
688
+ deps.renderer.write(
689
+ color3.bold(`
690
+ Sign in with ${strategy.label}`) + color3.dim(` \u2192 ${opts.providerId ?? strategy.providerId}
691
+ `)
692
+ );
693
+ const saved = strategy.id === "chatgpt-api" ? (await loadProviders(deps))[opts.providerId ?? strategy.providerId] : void 0;
694
+ const credential = saved?.apiKeys?.find((key) => key.label === saved.activeKey) ?? saved?.apiKeys?.[0];
695
+ session = await registry.begin(
696
+ strategy.id,
697
+ { modelsRegistry: deps.modelsRegistry, ...credential ? { credential } : {} },
698
+ controller.signal
699
+ );
700
+ let outcome;
701
+ if (session.interaction.type === "device_code") {
702
+ const { verificationUri, userCode } = session.interaction;
703
+ deps.renderer.write(
704
+ color3.bold("\n Open this URL and enter the code:\n") + color3.cyan(` ${hyperlink(verificationUri)}
705
+ `) + color3.bold(` Code: ${userCode}
706
+ `) + color3.dim(" Waiting for authorization\u2026\n")
707
+ );
708
+ openBrowser(verificationUri);
709
+ outcome = await session.waitForCompletion(controller.signal);
710
+ } else {
711
+ const { authorizeUrl, bound } = session.interaction;
712
+ deps.renderer.write(
713
+ color3.bold("\n Open this URL in your browser to sign in:\n") + color3.cyan(` ${hyperlink(authorizeUrl)}
714
+ `)
715
+ );
716
+ if (bound) {
717
+ openBrowser(authorizeUrl);
718
+ deps.renderer.write(color3.dim(" Waiting for browser authorization\u2026\n"));
719
+ outcome = await session.waitForCompletion(controller.signal);
720
+ } else {
721
+ const input = (await deps.reader.readLine(
722
+ `
723
+ ${color3.amber("?")} Paste the redirect URL or code ${color3.dim("(or q to cancel)")}: `
724
+ )).trim();
725
+ if (!input || input.toLowerCase() === "q") return 1;
726
+ outcome = await session.completeWithCode(input, controller.signal);
727
+ }
728
+ }
729
+ if (!outcome) {
730
+ deps.renderer.write(color3.dim(" Sign-in cancelled or timed out.\n"));
731
+ return 1;
732
+ }
733
+ controller.signal.throwIfAborted();
734
+ await mutateConfigProviders(
735
+ deps.profileConfigPath,
736
+ deps.vault,
737
+ (providers) => {
738
+ controller.signal.throwIfAborted();
739
+ applyProviderAuthOutcome(providers, outcome, { targetProviderId: opts.providerId });
740
+ },
741
+ deps.profileConfigPath
742
+ );
743
+ const savedId = opts.providerId ?? outcome.providerId;
744
+ deps.renderer.write(color3.green(`
745
+ \u2713 Signed in \u2014 saved as ${savedId}.
746
+ `));
747
+ return 0;
748
+ } catch (error) {
749
+ const message = error instanceof DOMException && error.name === "AbortError" ? "Login cancelled." : toErrorMessage(error);
750
+ deps.renderer.writeError(` Login failed: ${message}`);
751
+ return 1;
752
+ } finally {
753
+ session?.close();
754
+ if (opts.signal) opts.signal.removeEventListener("abort", onExternalAbort);
755
+ else process.off("SIGINT", onSigint);
756
+ }
757
+ }
758
+
758
759
  // src/auth-menu/oauth-menu.ts
759
760
  import { color as color4 } from "@wrongstack/core/utils";
760
761
  function renderOAuthLoginOptions(deps, indent = " ") {
@@ -2001,11 +2002,11 @@ export {
2001
2002
  readKeyInput,
2002
2003
  confirm,
2003
2004
  validateFamily,
2004
- providerAuthStrategiesFor,
2005
- runProviderAuthLogin,
2006
2005
  LOCAL_LLM_PRESETS,
2007
2006
  parseAuthMenuIndex,
2008
2007
  runAuthLocal,
2008
+ providerAuthStrategiesFor,
2009
+ runProviderAuthLogin,
2009
2010
  resolveOAuthKind,
2010
2011
  runOAuthLoginKind,
2011
2012
  runOAuthLoginMenu,
@@ -2024,4 +2025,4 @@ export {
2024
2025
  addCustomProvider,
2025
2026
  addKeyForProvider
2026
2027
  };
2027
- //# sourceMappingURL=chunk-RAWHRRUJ.js.map
2028
+ //# sourceMappingURL=chunk-I5LJLKA3.js.map