@wrongstack/cli 1.0.17 → 1.0.24

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 (125) hide show
  1. package/dist/{acp-INCNOH42.js → acp-AJWSKWE5.js} +18 -7
  2. package/dist/arg-parser.d.ts +1 -0
  3. package/dist/{auth-YXK3EDUL.js → auth-GRBZ7Y3D.js} +61 -15
  4. package/dist/auth-menu/direct.d.ts +1 -0
  5. package/dist/auth-menu/local.d.ts +2 -0
  6. package/dist/auth-menu/oauth-menu.d.ts +3 -1
  7. package/dist/auth-menu/panel-service.d.ts +20 -0
  8. package/dist/{bench-YBU6BVQP.js → bench-N5K7Z5O3.js} +2 -2
  9. package/dist/boot/config-backup-recovery.d.ts +2 -1
  10. package/dist/boot/dispatch-webui.d.ts +11 -0
  11. package/dist/boot/short-circuit-desktop.d.ts +1 -0
  12. package/dist/boot/tui-project-picker-callback.d.ts +1 -1
  13. package/dist/boot/tui-settings-adapter.d.ts +15 -2
  14. package/dist/{boot-auto-thin-MANHOYHE.js → boot-auto-thin-6Q56FY3F.js} +3 -2
  15. package/dist/{chunk-6WRKAACA.js → chunk-2BKFWIER.js} +4 -2
  16. package/dist/{chunk-JY52HWL6.js → chunk-2EBVTYJR.js} +2 -2
  17. package/dist/chunk-3OCUS3VN.js +46 -0
  18. package/dist/chunk-424ORSE7.js +56 -0
  19. package/dist/{chunk-KEPABQYT.js → chunk-5SEYGOCH.js} +8 -82
  20. package/dist/chunk-BBHWW6LR.js +549 -0
  21. package/dist/{chunk-CJTBLTS4.js → chunk-BLD5DSVA.js} +4 -3
  22. package/dist/{chunk-K5PAL6KR.js → chunk-DRM7PSW7.js} +75 -29
  23. package/dist/{chunk-XJ7K67PP.js → chunk-JF2MULWF.js} +17 -10
  24. package/dist/{chunk-SIS37L3W.js → chunk-L2RVEQWO.js} +211 -193
  25. package/dist/{chunk-RDHFXOJM.js → chunk-LFMVHT3R.js} +106 -57
  26. package/dist/chunk-LUMETJFO.js +171 -0
  27. package/dist/{chunk-C3Z4N6A6.js → chunk-MHEBWVXL.js} +6 -2
  28. package/dist/{chunk-VGER3HYZ.js → chunk-PGKJ2OQP.js} +5 -5
  29. package/dist/{chunk-672UXYL3.js → chunk-QBBF7GIK.js} +2 -2
  30. package/dist/{chunk-DE7BZDNK.js → chunk-QFPQXKCG.js} +11 -3
  31. package/dist/chunk-R4QGL6GB.js +10 -0
  32. package/dist/chunk-S4FFHDJG.js +93 -0
  33. package/dist/chunk-SFBFYIOW.js +271 -0
  34. package/dist/{chunk-JX6KL7OF.js → chunk-SKPDE62W.js} +4 -3
  35. package/dist/{chunk-RMQNCHGO.js → chunk-U46QR4WR.js} +5 -9
  36. package/dist/{chunk-B4JLSXZB.js → chunk-WSTVGC2C.js} +73 -45
  37. package/dist/chunk-YBUCXXYZ.js +36 -0
  38. package/dist/{chunk-2VMJ3E5Z.js → chunk-YTEOAWOJ.js} +6 -2
  39. package/dist/{chunk-GPPRNAKW.js → chunk-ZMX5HRLI.js} +2 -2
  40. package/dist/{chunk-YLQEGYV4.js → chunk-ZZRSG7VK.js} +14 -4
  41. package/dist/{cli-context-4PTWEK52.js → cli-context-34Q5IJRA.js} +121 -89
  42. package/dist/cli-entry-point.d.ts +2 -0
  43. package/dist/{cli-main-DQ2GBY7M.js → cli-main-AELJDBGU.js} +1471 -1293
  44. package/dist/config-doctor.d.ts +10 -2
  45. package/dist/{config-transfer-2YF3CRTN.js → config-transfer-RUWLDCNK.js} +34 -13
  46. package/dist/{diag-doctor-ANPRUYFM.js → diag-doctor-WIFJH3XH.js} +2 -2
  47. package/dist/execute-deps.d.ts +2 -1
  48. package/dist/{execution-A6WJLSOC.js → execution-PYC5FCS4.js} +303 -256
  49. package/dist/{hq-NU75W3SE.js → hq-JTUTFI4L.js} +274 -258
  50. package/dist/hq-command-controller.d.ts +1 -1
  51. package/dist/hq-server/project-root.d.ts +35 -1
  52. package/dist/{hq-server-M2JWVW4D.js → hq-server-PC7GZMPT.js} +2 -2
  53. package/dist/{hq-service-L5INQFM4.js → hq-service-NW56MUP2.js} +11 -4
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.js +17 -12
  56. package/dist/kanban-supervisor-67ECABTD.js +7 -0
  57. package/dist/live-settings-input.d.ts +7 -0
  58. package/dist/{mailbox-serve-3GFOK2I7.js → mailbox-serve-WDOCH6KR.js} +3 -3
  59. package/dist/{mcp-DC5WSBOO.js → mcp-LBS45HWZ.js} +4 -4
  60. package/dist/modeldiag-36OGAL5C.js +828 -0
  61. package/dist/{per-subcommand-help-DHTYU524.js → per-subcommand-help-XE77MTGJ.js} +3 -3
  62. package/dist/permission-prompt-mirror.d.ts +1 -1
  63. package/dist/permission-prompt.d.ts +2 -2
  64. package/dist/plugin-config.d.ts +12 -0
  65. package/dist/plugin-management-types.d.ts +31 -0
  66. package/dist/plugin-management.d.ts +2 -30
  67. package/dist/plugin-package-install.d.ts +3 -0
  68. package/dist/{plugin-usage-M6KET4OZ.js → plugin-usage-S5LVGMBW.js} +6 -5
  69. package/dist/{plugins-WJLW6ULV.js → plugins-RHBIVLI7.js} +4 -3
  70. package/dist/provider-config-utils.d.ts +1 -6
  71. package/dist/{providers-models-LFNZ5WI7.js → providers-models-2CFG46RD.js} +41 -31
  72. package/dist/release-asset-download.d.ts +3 -0
  73. package/dist/services/dispatch-classifier.d.ts +39 -5
  74. package/dist/{sessions-config-UL45XKX7.js → sessions-config-IQUH2GXT.js} +13 -5
  75. package/dist/settings-menu.d.ts +2 -0
  76. package/dist/short-circuit-flags-SDT53OML.js +10 -0
  77. package/dist/{simpleui-dist-CXSIDAXZ.js → simpleui-dist-7BQISSEP.js} +7 -3
  78. package/dist/skill-suggest-L2EVWB6R.js +290 -0
  79. package/dist/slash-commands/effort.d.ts +1 -1
  80. package/dist/slash-commands/fallback.d.ts +1 -1
  81. package/dist/slash-commands/gitid.d.ts +1 -1
  82. package/dist/slash-commands/jev.d.ts +4 -0
  83. package/dist/slash-commands/openai-quota.d.ts +15 -0
  84. package/dist/slash-commands/sdd-task-mutations.d.ts +4 -0
  85. package/dist/slash-commands/settings-keys.d.ts +2 -0
  86. package/dist/slash-commands/settings-reset.d.ts +6 -0
  87. package/dist/standalone-update-MW47J3AK.js +164 -0
  88. package/dist/standalone-update.d.ts +19 -0
  89. package/dist/subcommands/handlers/hq-alerts.d.ts +3 -0
  90. package/dist/subcommands/handlers/hq-audit.d.ts +46 -0
  91. package/dist/subcommands/handlers/hq-data-dir.d.ts +13 -0
  92. package/dist/subcommands/handlers/skill-suggest.d.ts +21 -0
  93. package/dist/subcommands/handlers/typesafe-brain-replay.d.ts +26 -0
  94. package/dist/subcommands/handlers/typesafe-judgment-check.d.ts +3 -0
  95. package/dist/subcommands/handlers/typesafe-topic-replay.d.ts +19 -0
  96. package/dist/subcommands/handlers/typesafe-triage-replay.d.ts +18 -0
  97. package/dist/subcommands/handlers/typesafe.d.ts +23 -0
  98. package/dist/{subcommands-ERDDIJ3L.js → subcommands-ZTSIN7LG.js} +2 -2
  99. package/dist/typesafe-HVEVPA6R.js +316 -0
  100. package/dist/typesafe-brain-replay-C5276FVR.js +222 -0
  101. package/dist/typesafe-judgment-check-GGYYV5UF.js +29 -0
  102. package/dist/typesafe-topic-replay-4W73BOLV.js +218 -0
  103. package/dist/typesafe-triage-replay-FGAW7QM7.js +215 -0
  104. package/dist/{update-5DPB4YD4.js → update-7XIOEXTD.js} +4 -3
  105. package/dist/{update-check-BS3DHTSI.js → update-check-2POMBHFB.js} +3 -2
  106. package/dist/update-check.d.ts +1 -1
  107. package/dist/version-help-WZ623NWM.js +10 -0
  108. package/dist/version.d.ts +3 -2
  109. package/dist/webui-client-observability.d.ts +7 -0
  110. package/dist/{webui-server-MRPGTTKL.js → webui-server-L2SICPTB.js} +158 -94
  111. package/dist/webui-server-options.d.ts +11 -0
  112. package/dist/webui-server.d.ts +15 -1
  113. package/dist/wiring/domain-glossary.d.ts +5 -4
  114. package/dist/wiring/plugins.d.ts +1 -1
  115. package/dist/wiring/provider-persisters.d.ts +24 -0
  116. package/dist/wiring/provider-runtime.d.ts +9 -1
  117. package/dist/wiring/runtime-dispatch-state.d.ts +3 -1
  118. package/package.json +28 -28
  119. package/dist/chunk-DR2OXU46.js +0 -174
  120. package/dist/chunk-JACOMTIH.js +0 -275
  121. package/dist/chunk-M4W3QLQW.js +0 -54
  122. package/dist/chunk-XJXDOF63.js +0 -28
  123. package/dist/modeldiag-CJSFHZ3J.js +0 -1356
  124. package/dist/short-circuit-flags-SJQBJ33I.js +0 -10
  125. package/dist/version-help-WXI42PZ3.js +0 -10
@@ -1,12 +1,12 @@
1
- import {
2
- appendHistory,
3
- backupCurrent
4
- } from "./chunk-B4JLSXZB.js";
5
1
  import {
6
2
  hasApiKey,
7
3
  isKeylessLocalProvider,
8
4
  visibleModelIds
9
5
  } from "./chunk-3VXYY5JC.js";
6
+ import {
7
+ appendHistory,
8
+ backupCurrent
9
+ } from "./chunk-WSTVGC2C.js";
10
10
  import {
11
11
  openBrowser
12
12
  } from "./chunk-DAKVBMD4.js";
@@ -17,8 +17,9 @@ import {
17
17
  mutateConfigProviders,
18
18
  normalizeKeys,
19
19
  nowIso,
20
+ resolveActiveApiKey,
20
21
  writeKeysBack
21
- } from "./chunk-DR2OXU46.js";
22
+ } from "./chunk-LUMETJFO.js";
22
23
 
23
24
  // src/auth-menu/auth-menu-audit.ts
24
25
  import { appendFileSync } from "node:fs";
@@ -260,10 +261,12 @@ async function runProviderAuthLogin(deps, strategyId, opts = {}) {
260
261
  deps.renderer.write(color.dim(" Sign-in cancelled or timed out.\n"));
261
262
  return 1;
262
263
  }
264
+ controller.signal.throwIfAborted();
263
265
  await mutateConfigProviders(
264
266
  deps.profileConfigPath,
265
267
  deps.vault,
266
268
  (providers) => {
269
+ controller.signal.throwIfAborted();
267
270
  applyProviderAuthOutcome(providers, outcome, { targetProviderId: opts.providerId });
268
271
  },
269
272
  deps.profileConfigPath
@@ -287,6 +290,7 @@ async function runProviderAuthLogin(deps, strategyId, opts = {}) {
287
290
  // src/auth-menu/local.ts
288
291
  import { DefaultSecretScrubber as DefaultSecretScrubber2 } from "@wrongstack/core/security";
289
292
  import { color as color3 } from "@wrongstack/core/utils";
293
+ import { authProfileAliasError } from "@wrongstack/providers";
290
294
  import { probeLocalLlm } from "@wrongstack/runtime/probe";
291
295
 
292
296
  // src/auth-menu/helpers.ts
@@ -479,10 +483,27 @@ async function runAuthLocal(deps, opts = {}) {
479
483
  if (!chosen) {
480
484
  return 0;
481
485
  }
482
- const baseUrl = opts.baseUrl?.trim() || chosen.defaultBaseUrl;
486
+ const profileId = opts.alias?.trim() || chosen.id;
487
+ const aliasError = authProfileAliasError(
488
+ opts.alias !== void 0 ? opts.alias.trim() : profileId
489
+ );
490
+ if (aliasError) {
491
+ deps.renderer.writeError(aliasError);
492
+ return 1;
493
+ }
494
+ const aliasedProfile = opts.alias !== void 0 ? (await loadProviders(deps))[profileId] : void 0;
495
+ if (aliasedProfile && !opts.probeOnly) {
496
+ deps.renderer.writeError(
497
+ `Auth profile "${profileId}" already exists. Choose another alias or manage its keys explicitly.`
498
+ );
499
+ return 1;
500
+ }
501
+ const baseUrl = opts.baseUrl?.trim() || (opts.probeOnly ? aliasedProfile?.baseUrl : void 0) || chosen.defaultBaseUrl;
483
502
  let apiKey;
484
503
  if (opts.apiKey !== void 0) {
485
504
  apiKey = opts.apiKey.trim() || void 0;
505
+ } else if (opts.probeOnly && aliasedProfile) {
506
+ apiKey = resolveActiveApiKey(aliasedProfile);
486
507
  } else if (chosen.noAuth) {
487
508
  apiKey = void 0;
488
509
  } else if (opts.skipKey) {
@@ -528,7 +549,7 @@ async function runAuthLocal(deps, opts = {}) {
528
549
  const resolvedModels = resolveModelList(opts.models, probe, scrubber);
529
550
  const label = opts.label?.trim() || "default";
530
551
  const providers = await loadProviders(deps);
531
- const existing = providers[chosen.id];
552
+ const existing = providers[profileId];
532
553
  const previousModels = existing?.models ? [...existing.models] : existing?.models === void 0 ? void 0 : [...existing.models];
533
554
  const usedLabels = new Set(existing ? normalizeKeys(existing).map((k) => k.label) : []);
534
555
  let finalLabel = label;
@@ -543,7 +564,9 @@ async function runAuthLocal(deps, opts = {}) {
543
564
  deps.profileConfigPath,
544
565
  deps.vault,
545
566
  (all) => {
546
- const p = all[chosen.id] ?? { type: chosen.id };
567
+ if (opts.alias !== void 0 && all[profileId])
568
+ throw new Error(`Auth profile "${profileId}" already exists.`);
569
+ const p = all[profileId] ?? { type: chosen.id };
547
570
  if (!p.type) p.type = chosen.id;
548
571
  if (!p.family) p.family = "openai-compatible";
549
572
  if (!p.baseUrl) p.baseUrl = baseUrl;
@@ -557,16 +580,16 @@ async function runAuthLocal(deps, opts = {}) {
557
580
  writeKeysBack(p, list);
558
581
  if (!p.activeKey) p.activeKey = finalLabel;
559
582
  }
560
- all[chosen.id] = p;
583
+ all[profileId] = p;
561
584
  },
562
585
  deps.profileConfigPath
563
586
  );
564
587
  } catch (err) {
565
- deps.renderer.writeError(`Failed to save ${chosen.id}: ${err.message}`);
588
+ deps.renderer.writeError(`Failed to save ${profileId}: ${err.message}`);
566
589
  return 1;
567
590
  }
568
591
  const events = decideAuthLocalEvents({
569
- providerId: chosen.id,
592
+ providerId: profileId,
570
593
  baseUrl,
571
594
  previousModels,
572
595
  newModels: resolvedModels,
@@ -581,19 +604,19 @@ async function runAuthLocal(deps, opts = {}) {
581
604
  }
582
605
  if (apiKey) {
583
606
  deps.renderer.write(
584
- ` ${color3.green("\u2713")} Saved ${color3.bold(chosen.id)}/${color3.bold(finalLabel)} \u2192 ${color3.cyan(baseUrl)}
607
+ ` ${color3.green("\u2713")} Saved ${color3.bold(profileId)}/${color3.bold(finalLabel)} \u2192 ${color3.cyan(baseUrl)}
585
608
  `
586
609
  );
587
610
  } else {
588
611
  deps.renderer.write(
589
- ` ${color3.green("\u2713")} Saved ${color3.bold(chosen.id)} (no key) \u2192 ${color3.cyan(baseUrl)}
612
+ ` ${color3.green("\u2713")} Saved ${color3.bold(profileId)} (no key) \u2192 ${color3.cyan(baseUrl)}
590
613
  `
591
614
  );
592
615
  }
593
616
  const firstModel = resolvedModels && resolvedModels.length > 0 ? resolvedModels[0] : null;
594
617
  const modelHint = firstModel ? color3.cyan(firstModel) : color3.dim("<model-id>");
595
618
  deps.renderer.write(
596
- color3.dim(` Launch: wstack --provider ${chosen.id} --model ${modelHint} "<task>"
619
+ color3.dim(` Launch: wstack --provider ${profileId} --model ${modelHint} "<task>"
597
620
  `)
598
621
  );
599
622
  return 0;
@@ -746,11 +769,19 @@ function resolveOAuthKind(choice, opts = {}) {
746
769
  async function runOAuthLoginChoice(deps, choice, opts = {}) {
747
770
  const kind = resolveOAuthKind(choice, { ...opts, deps });
748
771
  if (!kind) return false;
749
- await runOAuthLoginKind(deps, kind);
772
+ const sourceId = providerAuthRegistryFor(deps).get(kind)?.providerId ?? kind;
773
+ const profiles = await loadProviders(deps);
774
+ let suggestedAlias = sourceId;
775
+ for (let n = 2; profiles[suggestedAlias]; n++) suggestedAlias = `${sourceId}-${n}`;
776
+ const alias = (await deps.reader.readLine(
777
+ ` Auth profile alias [${suggestedAlias}] (existing alias re-authenticates; q cancels): `
778
+ )).trim();
779
+ if (alias.toLowerCase() !== "q")
780
+ await runOAuthLoginKind(deps, kind, { providerId: alias || suggestedAlias });
750
781
  return true;
751
782
  }
752
- async function runOAuthLoginKind(deps, kind) {
753
- return runProviderAuthLogin(deps, kind);
783
+ async function runOAuthLoginKind(deps, kind, opts) {
784
+ return opts ? runProviderAuthLogin(deps, kind, opts) : runProviderAuthLogin(deps, kind);
754
785
  }
755
786
  async function runOAuthLoginMenu(deps) {
756
787
  const entries = providerAuthRegistryFor(deps).list();
@@ -777,6 +808,7 @@ import {
777
808
  setRawMode as setRawMode2,
778
809
  stripAnsi as stripAnsi2,
779
810
  toErrorMessage,
811
+ withFileLock,
780
812
  writeOut as writeOut2
781
813
  } from "@wrongstack/core/utils";
782
814
 
@@ -1053,6 +1085,7 @@ var PROVIDER_FAMILY_PREFERRED_ORDER = [
1053
1085
  "openai-codex",
1054
1086
  "github-copilot",
1055
1087
  "google",
1088
+ "google-antigravity",
1056
1089
  "openai-compatible"
1057
1090
  ];
1058
1091
  function orderProvidersForDisplay(filtered) {
@@ -1129,41 +1162,44 @@ function renderLiveProviderList(query, filtered, selectedIdx, savedSet) {
1129
1162
  }
1130
1163
  async function saveToGlobalConfig(configPath, provider, model, homeFn = () => process.env.HOME ?? os.homedir()) {
1131
1164
  try {
1132
- const { atomicWrite } = await import("@wrongstack/core/utils");
1133
- const fs = await import("node:fs/promises");
1134
- let existing = {};
1135
- try {
1136
- const raw = await fs.readFile(configPath, "utf8");
1137
- existing = JSON.parse(raw);
1138
- } catch {
1139
- }
1140
- const oldCfg = { ...existing };
1141
- existing.provider = provider;
1142
- existing.model = model;
1143
- try {
1144
- await backupCurrent(homeFn, configPath);
1145
- } catch (err) {
1146
- console.warn(
1147
- JSON.stringify({
1148
- level: "warn",
1149
- event: "picker.backup_failed",
1150
- message: toErrorMessage(err),
1151
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1152
- })
1153
- );
1154
- }
1155
- await atomicWrite(configPath, JSON.stringify(existing, null, 2), { mode: 384 });
1156
- try {
1157
- await appendHistory(
1158
- oldCfg,
1159
- existing,
1160
- `Provider/model changed: ${oldCfg.provider ?? "(none)"} \u2192 ${provider}, ${oldCfg.model ?? "(none)"} \u2192 ${model}`,
1161
- homeFn,
1162
- configPath
1163
- );
1164
- } catch {
1165
- }
1166
- return true;
1165
+ return await withFileLock(configPath, async () => {
1166
+ const { atomicWrite } = await import("@wrongstack/core/utils");
1167
+ const fs = await import("node:fs/promises");
1168
+ let existing = {};
1169
+ try {
1170
+ const raw = await fs.readFile(configPath, "utf8");
1171
+ existing = JSON.parse(raw);
1172
+ } catch (err) {
1173
+ if (err.code !== "ENOENT") throw err;
1174
+ }
1175
+ const oldCfg = { ...existing };
1176
+ existing.provider = provider;
1177
+ existing.model = model;
1178
+ try {
1179
+ await backupCurrent(homeFn, configPath);
1180
+ } catch (err) {
1181
+ console.warn(
1182
+ JSON.stringify({
1183
+ level: "warn",
1184
+ event: "picker.backup_failed",
1185
+ message: toErrorMessage(err),
1186
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1187
+ })
1188
+ );
1189
+ }
1190
+ await atomicWrite(configPath, JSON.stringify(existing, null, 2), { mode: 384 });
1191
+ try {
1192
+ await appendHistory(
1193
+ oldCfg,
1194
+ existing,
1195
+ `Provider/model changed: ${oldCfg.provider ?? "(none)"} \u2192 ${provider}, ${oldCfg.model ?? "(none)"} \u2192 ${model}`,
1196
+ homeFn,
1197
+ configPath
1198
+ );
1199
+ } catch {
1200
+ }
1201
+ return true;
1202
+ });
1167
1203
  } catch (err) {
1168
1204
  console.warn(
1169
1205
  JSON.stringify({
@@ -1357,6 +1393,7 @@ ${theme.accent(color7.bold("\u258C WrongStack"))} ${color7.dim("Provider & Mode
1357
1393
  "openai-codex",
1358
1394
  "github-copilot",
1359
1395
  "google",
1396
+ "google-antigravity",
1360
1397
  "openai-compatible"
1361
1398
  ];
1362
1399
  const familyOrder = [
@@ -1585,7 +1622,11 @@ async function resolveModelSelection(answer, models, provider, _registry, render
1585
1622
 
1586
1623
  // src/auth-menu/add-provider.ts
1587
1624
  import { color as color8 } from "@wrongstack/core/utils";
1588
- import { catalogProviderIdFor, PROVIDER_DEFINITIONS } from "@wrongstack/providers";
1625
+ import {
1626
+ authProfileAliasError as authProfileAliasError2,
1627
+ catalogProviderIdFor,
1628
+ PROVIDER_DEFINITIONS
1629
+ } from "@wrongstack/providers";
1589
1630
 
1590
1631
  // src/provider-id.ts
1591
1632
  function nextCustomProviderId(existing) {
@@ -1640,9 +1681,7 @@ async function addFromCatalog(deps) {
1640
1681
  ${color8.dim("OAuth login options: enter a registered strategy name, or q to quit.")}
1641
1682
  `
1642
1683
  );
1643
- const answer = (await deps.reader.readLine(
1644
- ` ${color8.amber("?")} OAuth strategy ${color8.dim("(or q)")}: `
1645
- )).trim();
1684
+ const answer = (await deps.reader.readLine(` ${color8.amber("?")} OAuth strategy ${color8.dim("(or q)")}: `)).trim();
1646
1685
  if (answer && await runOAuthLoginChoice(deps, answer, { allowNumeric: false })) {
1647
1686
  return true;
1648
1687
  }
@@ -1678,6 +1717,7 @@ async function addKeyForCatalogProvider(deps, chosen) {
1678
1717
  const baseUrl = baseRaw || chosen.apiBase;
1679
1718
  const providersNow = await loadProviders(deps);
1680
1719
  let suggestedAlias = chosen.id;
1720
+ for (let n = 2; providersNow[suggestedAlias]; n++) suggestedAlias = `${chosen.id}-${n}`;
1681
1721
  if (family !== chosen.family) {
1682
1722
  let candidate = `${chosen.id}-${family}`;
1683
1723
  let n = 2;
@@ -1691,6 +1731,11 @@ async function addKeyForCatalogProvider(deps, chosen) {
1691
1731
  ` ${color8.amber("?")} Save as alias ${color8.dim(`[${suggestedAlias}]`)} ${color8.dim("(used with --provider <alias>)")}: `
1692
1732
  )).trim();
1693
1733
  const alias = aliasRaw || suggestedAlias;
1734
+ const aliasError = authProfileAliasError2(alias);
1735
+ if (aliasError) {
1736
+ deps.renderer.writeError(aliasError);
1737
+ return false;
1738
+ }
1694
1739
  const existing = providersNow[alias];
1695
1740
  if (existing) {
1696
1741
  const sameFamily = (existing.family ?? chosen.family) === family;
@@ -1704,6 +1749,10 @@ async function addKeyForCatalogProvider(deps, chosen) {
1704
1749
  );
1705
1750
  return false;
1706
1751
  }
1752
+ deps.renderer.writeError(
1753
+ `Auth profile "${alias}" already exists. Choose another alias or manage its keys explicitly.`
1754
+ );
1755
+ return false;
1707
1756
  }
1708
1757
  return addKeyForProvider(alias, deps, {
1709
1758
  type: chosen.id,
@@ -1897,4 +1946,4 @@ export {
1897
1946
  addCustomProvider,
1898
1947
  addKeyForProvider
1899
1948
  };
1900
- //# sourceMappingURL=chunk-RDHFXOJM.js.map
1949
+ //# sourceMappingURL=chunk-LFMVHT3R.js.map
@@ -0,0 +1,171 @@
1
+
2
+ // src/provider-config-utils.ts
3
+ import { FsError } from "@wrongstack/core/types";
4
+ import { expectDefined } from "@wrongstack/core/utils";
5
+ import * as fs from "node:fs/promises";
6
+ import * as path from "node:path";
7
+ import {
8
+ decryptConfigSecrets,
9
+ decryptConfigSecretsForRewrite,
10
+ encryptConfigSecrets
11
+ } from "@wrongstack/core/security";
12
+ import { atomicWrite, backupConfigFile, color, withFileLock } from "@wrongstack/core/utils";
13
+ import {
14
+ clearStaleProviderDefaults,
15
+ removeProviderFallbackReferences,
16
+ validateProviderConfigShape
17
+ } from "@wrongstack/providers";
18
+ import { clearStaleProviderDefaults as clearStaleProviderDefaults2 } from "@wrongstack/providers";
19
+ import { nowIso } from "@wrongstack/primitives";
20
+ function normalizeKeys(cfg) {
21
+ if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {
22
+ return cfg.apiKeys.map((k) => ({ ...k }));
23
+ }
24
+ if (typeof cfg.apiKey === "string" && cfg.apiKey.length > 0) {
25
+ return [{ label: "default", apiKey: cfg.apiKey, createdAt: "" }];
26
+ }
27
+ return [];
28
+ }
29
+ function writeKeysBack(cfg, keys) {
30
+ if (keys.length === 0) {
31
+ delete cfg.apiKeys;
32
+ delete cfg.apiKey;
33
+ delete cfg.activeKey;
34
+ return;
35
+ }
36
+ cfg.apiKeys = keys;
37
+ const active = keys.find((k) => k.label === cfg.activeKey) ?? expectDefined(keys[0]);
38
+ delete cfg.apiKey;
39
+ if (!cfg.activeKey || !keys.some((k) => k.label === cfg.activeKey)) {
40
+ cfg.activeKey = active.label;
41
+ }
42
+ }
43
+ function resolveActiveApiKey(cfg) {
44
+ if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {
45
+ const active = cfg.activeKey ? cfg.apiKeys.find((k) => k.label === cfg.activeKey) : void 0;
46
+ return (active ?? cfg.apiKeys[0])?.apiKey;
47
+ }
48
+ return cfg.apiKey && cfg.apiKey.length > 0 ? cfg.apiKey : void 0;
49
+ }
50
+ function activeLabel(cfg, keys) {
51
+ if (cfg.activeKey && keys.some((k) => k.label === cfg.activeKey)) return cfg.activeKey;
52
+ return keys[0]?.label;
53
+ }
54
+ function maskedKey(key) {
55
+ if (!key) return color.dim("\u2014");
56
+ if (key.length <= 8) return color.dim("\u2022".repeat(key.length));
57
+ const head = key.slice(0, 4);
58
+ const tail = key.slice(-4);
59
+ return `${color.dim(head + "\u2026")}${tail}`;
60
+ }
61
+ async function loadConfigProviders(configPath, vault, opts) {
62
+ const warn = opts?.warn;
63
+ const targetPath = opts?.profileConfigPath ?? configPath;
64
+ let raw;
65
+ try {
66
+ raw = await fs.readFile(targetPath, "utf8");
67
+ } catch (err) {
68
+ if (err.code !== "ENOENT") {
69
+ warn?.(`Could not read ${targetPath}: ${err.message}. Treating as empty.`);
70
+ }
71
+ return {};
72
+ }
73
+ let parsed;
74
+ try {
75
+ parsed = JSON.parse(raw);
76
+ validateProviderConfigShape(parsed);
77
+ } catch (err) {
78
+ warn?.(`Config at ${targetPath} is not valid JSON: ${err.message}`);
79
+ return {};
80
+ }
81
+ const decrypted = decryptConfigSecrets(parsed, vault);
82
+ return decrypted.providers ?? {};
83
+ }
84
+ var configMutationChain = Promise.resolve();
85
+ function globalRootForConfigPath(configPath) {
86
+ const configDir = path.dirname(configPath);
87
+ const profilesDir = path.dirname(configDir);
88
+ return path.basename(profilesDir) === "profiles" ? path.dirname(profilesDir) : configDir;
89
+ }
90
+ function queueConfigMutation(mutate) {
91
+ const run = configMutationChain.then(mutate, mutate);
92
+ configMutationChain = run.then(
93
+ () => void 0,
94
+ () => void 0
95
+ );
96
+ return run;
97
+ }
98
+ async function mutateConfigProviders(configPath, vault, mutator, profileConfigPath) {
99
+ await queueConfigMutation(
100
+ () => withFileLock(profileConfigPath ?? configPath, async () => {
101
+ const targetPath = profileConfigPath ?? configPath;
102
+ let raw;
103
+ let fileExists = true;
104
+ try {
105
+ raw = await fs.readFile(targetPath, "utf8");
106
+ } catch (err) {
107
+ if (err.code !== "ENOENT") {
108
+ throw new FsError({
109
+ message: `Refusing to mutate ${configPath}: ${err.message}`,
110
+ code: "FS_READ_FAILED",
111
+ path: targetPath,
112
+ context: { operation: "mutateConfigProviders", phase: "read" },
113
+ cause: err
114
+ });
115
+ }
116
+ fileExists = false;
117
+ raw = "{}";
118
+ }
119
+ let parsed;
120
+ try {
121
+ parsed = JSON.parse(raw);
122
+ validateProviderConfigShape(parsed);
123
+ } catch (err) {
124
+ if (fileExists) {
125
+ throw new FsError({
126
+ message: `Refusing to overwrite corrupt config at ${targetPath} (${err.message}). Fix or move the file aside before retrying.`,
127
+ code: "FS_READ_FAILED",
128
+ path: targetPath,
129
+ context: { operation: "mutateConfigProviders", phase: "parse" },
130
+ cause: err
131
+ });
132
+ }
133
+ parsed = {};
134
+ }
135
+ const decrypted = decryptConfigSecretsForRewrite(parsed, vault);
136
+ const providers = decrypted.providers ?? {};
137
+ const previousProviderIds = Object.keys(providers);
138
+ const primaryBefore = JSON.stringify([
139
+ decrypted["provider"],
140
+ decrypted["model"],
141
+ typeof decrypted["provider"] === "string" ? providers[decrypted["provider"]] : void 0
142
+ ]);
143
+ mutator(providers, decrypted);
144
+ for (const id of previousProviderIds) {
145
+ if (!Object.hasOwn(providers, id)) removeProviderFallbackReferences(decrypted, id);
146
+ }
147
+ decrypted.providers = providers;
148
+ const primaryAfter = JSON.stringify([
149
+ decrypted["provider"],
150
+ decrypted["model"],
151
+ typeof decrypted["provider"] === "string" ? providers[decrypted["provider"]] : void 0
152
+ ]);
153
+ clearStaleProviderDefaults(decrypted, { preservePrimary: primaryBefore === primaryAfter });
154
+ const encrypted = encryptConfigSecrets(decrypted, vault);
155
+ await backupConfigFile(targetPath, { globalRoot: globalRootForConfigPath(targetPath) });
156
+ await atomicWrite(targetPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
157
+ })
158
+ );
159
+ }
160
+
161
+ export {
162
+ normalizeKeys,
163
+ writeKeysBack,
164
+ resolveActiveApiKey,
165
+ activeLabel,
166
+ maskedKey,
167
+ loadConfigProviders,
168
+ mutateConfigProviders,
169
+ nowIso
170
+ };
171
+ //# sourceMappingURL=chunk-LUMETJFO.js.map
@@ -185,7 +185,11 @@ function parseAuthFlags(args) {
185
185
  key = a.slice(0, eq);
186
186
  inlineVal = a.slice(eq + 1);
187
187
  }
188
- if (key === "--label") {
188
+ if (key === "--alias") {
189
+ const next = args[i + 1];
190
+ const v = inlineVal !== void 0 ? inlineVal : next !== void 0 && !next.startsWith("-") ? args[++i] : "";
191
+ out.alias = v ?? "";
192
+ } else if (key === "--label") {
189
193
  const v = inlineVal !== void 0 ? inlineVal : args[++i];
190
194
  if (v) out.label = v;
191
195
  } else if (key === "--family") {
@@ -258,4 +262,4 @@ export {
258
262
  parseAuthFlags,
259
263
  parseSpawnFlags
260
264
  };
261
- //# sourceMappingURL=chunk-C3Z4N6A6.js.map
265
+ //# sourceMappingURL=chunk-MHEBWVXL.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  helpCmd,
3
3
  versionCmd
4
- } from "./chunk-6WRKAACA.js";
4
+ } from "./chunk-2BKFWIER.js";
5
5
  import {
6
6
  parseArgs
7
- } from "./chunk-C3Z4N6A6.js";
7
+ } from "./chunk-MHEBWVXL.js";
8
8
 
9
9
  // src/boot/short-circuit-flags.ts
10
10
  async function handleHelpVersionShortCircuit(argv) {
@@ -22,11 +22,11 @@ async function handleHelpVersionShortCircuit(argv) {
22
22
  }
23
23
  if (earlyFlags["help"] === true) {
24
24
  if (positional.length > 0) {
25
- const { subcommandNames } = await import("./subcommands-ERDDIJ3L.js");
25
+ const { subcommandNames } = await import("./subcommands-ZTSIN7LG.js");
26
26
  if (subcommandNames.includes(positional[0])) {
27
27
  const first = positional[0];
28
28
  const deep = positional[1];
29
- const { renderDeepHelp, renderFocusedHelp } = await import("./per-subcommand-help-DHTYU524.js");
29
+ const { renderDeepHelp, renderFocusedHelp } = await import("./per-subcommand-help-XE77MTGJ.js");
30
30
  if (deep && renderDeepHelp(`${first}:${deep}`, stubRenderer)) {
31
31
  return 0;
32
32
  }
@@ -43,4 +43,4 @@ async function handleHelpVersionShortCircuit(argv) {
43
43
  export {
44
44
  handleHelpVersionShortCircuit
45
45
  };
46
- //# sourceMappingURL=chunk-VGER3HYZ.js.map
46
+ //# sourceMappingURL=chunk-PGKJ2OQP.js.map
@@ -14,7 +14,7 @@ async function printUpdateNotice(initialUpdateInfo) {
14
14
  const ac = new AbortController();
15
15
  const timer = setTimeout(() => ac.abort(), 2e3);
16
16
  try {
17
- const { checkForUpdate } = await import("./update-check-BS3DHTSI.js");
17
+ const { checkForUpdate } = await import("./update-check-2POMBHFB.js");
18
18
  info = await checkForUpdate(ac.signal);
19
19
  } catch {
20
20
  } finally {
@@ -62,4 +62,4 @@ export {
62
62
  applySessionShellDefault,
63
63
  runPreflight
64
64
  };
65
- //# sourceMappingURL=chunk-672UXYL3.js.map
65
+ //# sourceMappingURL=chunk-QBBF7GIK.js.map
@@ -3,12 +3,13 @@ import {
3
3
  } from "./chunk-U3SS4NRH.js";
4
4
  import {
5
5
  checkForUpdate
6
- } from "./chunk-YLQEGYV4.js";
6
+ } from "./chunk-ZZRSG7VK.js";
7
7
 
8
8
  // src/subcommands/handlers/update.ts
9
9
  import { spawn } from "node:child_process";
10
10
  import { existsSync, realpathSync } from "node:fs";
11
11
  import * as path from "node:path";
12
+ import { isStandaloneBinary } from "@wrongstack/core/utils";
12
13
  var MAX_UPDATE_OUTPUT_CHARS = 256 * 1024;
13
14
  async function runUpdateCommand(args, deps) {
14
15
  const cwd = deps.cwd;
@@ -55,7 +56,7 @@ async function runUpdateCommand(args, deps) {
55
56
  });
56
57
  if (info.checkFailed) {
57
58
  deps.renderer.write(
58
- `Update check failed for ${packageName}. Check your internet connection and try again.
59
+ `Update check failed for ${isStandaloneBinary() ? "the GitHub releases" : packageName}. Check your internet connection and try again.
59
60
  `
60
61
  );
61
62
  return 1;
@@ -75,6 +76,13 @@ async function runUpdateCommand(args, deps) {
75
76
  `);
76
77
  return 0;
77
78
  }
79
+ if (isStandaloneBinary()) {
80
+ const { updateStandaloneBinary } = await import("./standalone-update-MW47J3AK.js");
81
+ return updateStandaloneBinary({
82
+ current: info.current,
83
+ renderer: deps.renderer
84
+ });
85
+ }
78
86
  const packageManager = parsed.packageManager ?? detectUpdatePackageManager();
79
87
  let updateCommand;
80
88
  try {
@@ -383,4 +391,4 @@ export {
383
391
  detectUpdatePackageManager,
384
392
  detectUpdatePackageName
385
393
  };
386
- //# sourceMappingURL=chunk-DE7BZDNK.js.map
394
+ //# sourceMappingURL=chunk-QFPQXKCG.js.map
@@ -0,0 +1,10 @@
1
+
2
+ // src/webui-server/kanban-supervisor.ts
3
+ import {
4
+ createKanbanSupervisor
5
+ } from "@wrongstack/webui-server";
6
+
7
+ export {
8
+ createKanbanSupervisor
9
+ };
10
+ //# sourceMappingURL=chunk-R4QGL6GB.js.map