@dmrlzz/davecode 0.5.0 → 0.5.2

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 (73) hide show
  1. package/dist/{ChatApp-CJBICQGA.js → ChatApp-Z6PQIZ5J.js} +7 -6
  2. package/dist/{ChatApp-CJBICQGA.js.map → ChatApp-Z6PQIZ5J.js.map} +1 -1
  3. package/dist/{account-QWDPJWAA.js → account-RTPS2V6O.js} +4 -3
  4. package/dist/{accounts-IQMR72FC.js → accounts-IYQ4ZRL7.js} +6 -5
  5. package/dist/{budget-XANOUVWO.js → budget-N2ZB66FF.js} +5 -4
  6. package/dist/{budget-XANOUVWO.js.map → budget-N2ZB66FF.js.map} +1 -1
  7. package/dist/{chat-KDDRNC5V.js → chat-6TX6JX45.js} +9 -8
  8. package/dist/{chat-KDDRNC5V.js.map → chat-6TX6JX45.js.map} +1 -1
  9. package/dist/chunk-732GIHRQ.js +23 -0
  10. package/dist/chunk-732GIHRQ.js.map +1 -0
  11. package/dist/{chunk-AZKACMME.js → chunk-BJTXMET2.js} +2 -2
  12. package/dist/{chunk-FYPMA55O.js → chunk-KUY3QHGS.js} +239 -106
  13. package/dist/chunk-KUY3QHGS.js.map +1 -0
  14. package/dist/{chunk-JLATEHS7.js → chunk-LEU46DGH.js} +2 -2
  15. package/dist/{chunk-HSBJDV3O.js → chunk-QKY3OKVG.js} +309 -23
  16. package/dist/chunk-QKY3OKVG.js.map +1 -0
  17. package/dist/{chunk-WQ7MEWDF.js → chunk-UEV5K3DH.js} +10 -4
  18. package/dist/chunk-UEV5K3DH.js.map +1 -0
  19. package/dist/{chunk-44AFJL2X.js → chunk-UNK3EQD6.js} +6 -5
  20. package/dist/chunk-UNK3EQD6.js.map +1 -0
  21. package/dist/{chunk-W7GPBEBZ.js → chunk-WAARDGCZ.js} +5 -21
  22. package/dist/chunk-WAARDGCZ.js.map +1 -0
  23. package/dist/{chunk-PGAJIGUF.js → chunk-YNAMNQLW.js} +3 -3
  24. package/dist/{config-YTUPIYZT.js → config-YQKY2AA4.js} +4 -3
  25. package/dist/{config-YTUPIYZT.js.map → config-YQKY2AA4.js.map} +1 -1
  26. package/dist/dashboard/assets/Accounts-DXiGsutB.js +1 -0
  27. package/dist/dashboard/assets/{Badge-Z4RBdO9j.js → Badge-DUGKlx3Z.js} +1 -1
  28. package/dist/dashboard/assets/{Callout-w8BTYh4k.js → Callout-1E8Wsl9W.js} +1 -1
  29. package/dist/dashboard/assets/{Goals-Bw02to72.js → Goals-kL4VAxw3.js} +1 -1
  30. package/dist/dashboard/assets/{Library-DK7mlpRb.js → Library-DZxBVUo_.js} +1 -1
  31. package/dist/dashboard/assets/Markdown-CGgIydUh.js +71 -0
  32. package/dist/dashboard/assets/{Panes-_KTf8pbZ.js → Panes-C-TJekjs.js} +1 -1
  33. package/dist/dashboard/assets/{RoutesPage-QV0oPRW9.js → RoutesPage-DWYm9tW8.js} +1 -1
  34. package/dist/dashboard/assets/{Runner-CkHBLQl0.js → Runner-CmHBjECR.js} +1 -1
  35. package/dist/dashboard/assets/{Settings-BLz2gTBR.js → Settings-BANphxva.js} +1 -1
  36. package/dist/dashboard/assets/{Tasks-BiUQSTpt.js → Tasks-cSx1PKyQ.js} +1 -1
  37. package/dist/dashboard/assets/{Traffic-BVfBuC70.js → Traffic-DEAuM6jq.js} +1 -1
  38. package/dist/dashboard/assets/{Workspace-CJTgiiU5.js → Workspace-BQFjc1jH.js} +1 -1
  39. package/dist/dashboard/assets/index-B8kld9xo.js +104 -0
  40. package/dist/dashboard/assets/{task-errors-Daqwi0ue.js → task-errors-r-WYZ_S3.js} +1 -1
  41. package/dist/dashboard/index.html +2 -2
  42. package/dist/{dist-37VQSHHA.js → dist-PIC255RX.js} +20 -2
  43. package/dist/{doctor-PYUQRRCB.js → doctor-PQC7JQPP.js} +4 -3
  44. package/dist/{doctor-PYUQRRCB.js.map → doctor-PQC7JQPP.js.map} +1 -1
  45. package/dist/{goal-SXZUDUCL.js → goal-STLEU7C7.js} +4 -3
  46. package/dist/{goal-SXZUDUCL.js.map → goal-STLEU7C7.js.map} +1 -1
  47. package/dist/index.js +31 -31
  48. package/dist/{init-Z2AFQEEP.js → init-NHU5LJSS.js} +4 -3
  49. package/dist/{init-Z2AFQEEP.js.map → init-NHU5LJSS.js.map} +1 -1
  50. package/dist/{run-AOS7L3RT.js → run-7HWSHMRJ.js} +4 -3
  51. package/dist/{run-AOS7L3RT.js.map → run-7HWSHMRJ.js.map} +1 -1
  52. package/dist/runtime.js +3 -2
  53. package/dist/{start-CEPXKZUE.js → start-WVAEAQWL.js} +4 -3
  54. package/dist/{start-CEPXKZUE.js.map → start-WVAEAQWL.js.map} +1 -1
  55. package/dist/{status-WNJ3GGKU.js → status-ZRHPFLFT.js} +5 -4
  56. package/dist/{tasks-TFUTUMWB.js → tasks-JVWXUNXN.js} +5 -4
  57. package/dist/{tasks-TFUTUMWB.js.map → tasks-JVWXUNXN.js.map} +1 -1
  58. package/package.json +6 -6
  59. package/dist/chunk-44AFJL2X.js.map +0 -1
  60. package/dist/chunk-FYPMA55O.js.map +0 -1
  61. package/dist/chunk-HSBJDV3O.js.map +0 -1
  62. package/dist/chunk-W7GPBEBZ.js.map +0 -1
  63. package/dist/chunk-WQ7MEWDF.js.map +0 -1
  64. package/dist/dashboard/assets/Accounts-cq8RLMoI.js +0 -1
  65. package/dist/dashboard/assets/Markdown-DCZ4Awcc.js +0 -69
  66. package/dist/dashboard/assets/index-BDBa5cb0.js +0 -104
  67. /package/dist/{account-QWDPJWAA.js.map → account-RTPS2V6O.js.map} +0 -0
  68. /package/dist/{accounts-IQMR72FC.js.map → accounts-IYQ4ZRL7.js.map} +0 -0
  69. /package/dist/{chunk-AZKACMME.js.map → chunk-BJTXMET2.js.map} +0 -0
  70. /package/dist/{chunk-JLATEHS7.js.map → chunk-LEU46DGH.js.map} +0 -0
  71. /package/dist/{chunk-PGAJIGUF.js.map → chunk-YNAMNQLW.js.map} +0 -0
  72. /package/dist/{dist-37VQSHHA.js.map → dist-PIC255RX.js.map} +0 -0
  73. /package/dist/{status-WNJ3GGKU.js.map → status-ZRHPFLFT.js.map} +0 -0
@@ -116,7 +116,7 @@ import { z as z8 } from "zod";
116
116
  import { randomBytes as randomBytes7 } from "crypto";
117
117
  import { createServer } from "http";
118
118
  import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes8 } from "crypto";
119
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync3, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
119
+ import { mkdirSync as mkdirSync7, readFileSync as readFileSync3, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync3 } from "fs";
120
120
  import { dirname as dirname6, join as join6 } from "path";
121
121
  import { z as z9 } from "zod";
122
122
  import { z as z10 } from "zod";
@@ -155,6 +155,8 @@ var ENDPOINTS = {
155
155
  }
156
156
  };
157
157
  var PENDING_MS = 10 * 6e4;
158
+ var PENDING_MAX = 1e3;
159
+ var PENDING_PER_PEER = 20;
158
160
  var SESSION_MS = 8 * 60 * 6e4;
159
161
  var random = () => randomBytes(32).toString("base64url");
160
162
  var digest = (value) => createHash("sha256").update(value).digest("base64url");
@@ -200,10 +202,29 @@ var LoginService = class {
200
202
  logout(session) {
201
203
  if (session) this.sessions.delete(digest(session));
202
204
  }
203
- begin(provider) {
205
+ /**
206
+ * Start a sign-in. `peer` is the connection's address as the HTTP server sees it (never a
207
+ * forwarded header unless the server was configured to trust its proxy). Unfinished sign-ins
208
+ * never block a new one: each peer keeps a few, and when the table is full the oldest goes.
209
+ */
210
+ begin(provider, peer = "unknown") {
204
211
  this.prune();
205
212
  const client = this.options.providers[provider];
206
- if (!client || this.pending.size >= 1e3) throw new LoginError();
213
+ if (!client) throw new LoginError();
214
+ let mine = 0;
215
+ for (const value of this.pending.values()) if (value.peer === peer) mine++;
216
+ for (const [key, value] of this.pending) {
217
+ if (mine < PENDING_PER_PEER) break;
218
+ if (value.peer === peer) {
219
+ this.pending.delete(key);
220
+ mine--;
221
+ }
222
+ }
223
+ while (this.pending.size >= PENDING_MAX) {
224
+ const oldest = this.pending.keys().next().value;
225
+ if (oldest === void 0) break;
226
+ this.pending.delete(oldest);
227
+ }
207
228
  const state = random();
208
229
  const binding = random();
209
230
  const verifier = random();
@@ -211,6 +232,7 @@ var LoginService = class {
211
232
  provider,
212
233
  binding: digest(binding),
213
234
  verifier,
235
+ peer,
214
236
  expires: this.now() + PENDING_MS
215
237
  });
216
238
  const url = new URL(ENDPOINTS[provider].authorize);
@@ -1471,6 +1493,53 @@ ${message}`, options);
1471
1493
  this.source = source;
1472
1494
  }
1473
1495
  };
1496
+ var PROJECT_SETTABLE_KEYS = {
1497
+ logLevel: true,
1498
+ routing: true,
1499
+ goal: true,
1500
+ runner: {
1501
+ maxRepairCycles: true,
1502
+ branchPrefix: true,
1503
+ baseBranch: true,
1504
+ route: true,
1505
+ executor: true,
1506
+ pullRequests: true,
1507
+ commitBrain: true,
1508
+ commandTimeoutMs: true,
1509
+ idlePollMs: true,
1510
+ maxIterations: true,
1511
+ maxTaskTokens: true,
1512
+ validate: true,
1513
+ claudeCli: { accountId: true, model: true, timeoutMs: true },
1514
+ judge: { kind: true, model: true, threshold: true }
1515
+ }
1516
+ };
1517
+ function filterProjectLayer(layer) {
1518
+ const dropped = [];
1519
+ const walk = (value, tree, prefix) => {
1520
+ const out = {};
1521
+ for (const [key, v] of Object.entries(value)) {
1522
+ const rule = Object.hasOwn(tree, key) ? tree[key] : void 0;
1523
+ const path8 = prefix ? `${prefix}.${key}` : key;
1524
+ if (rule === true) {
1525
+ out[key] = v;
1526
+ } else if (rule && isPlainObject(v)) {
1527
+ const inner = walk(v, rule, path8);
1528
+ if (Object.keys(inner).length > 0) out[key] = inner;
1529
+ } else {
1530
+ dropped.push(path8);
1531
+ }
1532
+ }
1533
+ return out;
1534
+ };
1535
+ return { allowed: walk(layer, PROJECT_SETTABLE_KEYS, ""), dropped };
1536
+ }
1537
+ var warned = /* @__PURE__ */ new Set();
1538
+ function defaultWarn(message) {
1539
+ if (warned.has(message)) return;
1540
+ warned.add(message);
1541
+ process.emitWarning(message, "DaveCodeConfigWarning");
1542
+ }
1474
1543
  function isPlainObject(value) {
1475
1544
  return typeof value === "object" && value !== null && !Array.isArray(value);
1476
1545
  }
@@ -1483,7 +1552,7 @@ function deepMerge(base, override) {
1483
1552
  }
1484
1553
  return out;
1485
1554
  }
1486
- function readLayer(path8) {
1555
+ function readLayer(path8, project) {
1487
1556
  let raw;
1488
1557
  try {
1489
1558
  raw = readFileSync(path8, "utf8");
@@ -1498,9 +1567,15 @@ function readLayer(path8) {
1498
1567
  throw new ConfigError(path8, `malformed JSON: ${err.message}`, { cause: err });
1499
1568
  }
1500
1569
  if (!isPlainObject(parsed)) throw new ConfigError(path8, "expected a JSON object");
1501
- const result = configSchema.safeParse(parsed);
1570
+ let layer = parsed;
1571
+ if (project) {
1572
+ const { allowed, dropped } = filterProjectLayer(parsed);
1573
+ if (dropped.length > 0) project(dropped);
1574
+ layer = allowed;
1575
+ }
1576
+ const result = configSchema.safeParse(layer);
1502
1577
  if (!result.success) throw new ConfigError(path8, z4.prettifyError(result.error));
1503
- return parsed;
1578
+ return layer;
1504
1579
  }
1505
1580
  var TRUE_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
1506
1581
  var FALSE_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off", ""]);
@@ -1558,7 +1633,14 @@ function loadConfig(options = {}) {
1558
1633
  const globalLayer = readLayer(globalPaths(home).config);
1559
1634
  if (globalLayer) merged = deepMerge(merged, globalLayer);
1560
1635
  if (options.projectRoot) {
1561
- const projectLayer = readLayer(projectPaths(options.projectRoot).config);
1636
+ const projectFile = projectPaths(options.projectRoot).config;
1637
+ const warn = options.onWarning ?? defaultWarn;
1638
+ const projectLayer = readLayer(
1639
+ projectFile,
1640
+ (dropped) => warn(
1641
+ `Ignored ${dropped.join(", ")} in ${projectFile}: project config cannot set these keys. Set them in your user config (~/.davecode/config.json) or with DAVECODE_* environment variables.`
1642
+ )
1643
+ );
1562
1644
  if (projectLayer) merged = deepMerge(merged, projectLayer);
1563
1645
  }
1564
1646
  merged = deepMerge(merged, envLayer(env));
@@ -3875,6 +3957,76 @@ function createProviders(options = {}) {
3875
3957
  ];
3876
3958
  return new Map(providers.map((p) => [p.kind, p]));
3877
3959
  }
3960
+ var ENDPOINT_CONFIG_KEYS = ["baseUrl"];
3961
+ var MODEL_KEYS = ["models", "defaultModel"];
3962
+ var API_CONFIG_KEYS = {
3963
+ anthropic: ["baseUrl", ...MODEL_KEYS],
3964
+ openai: ["baseUrl", "includeUsage", ...MODEL_KEYS],
3965
+ gemini: ["baseUrl", ...MODEL_KEYS],
3966
+ "openai-compatible": ["baseUrl", "includeUsage", ...MODEL_KEYS],
3967
+ "claude-cli": [...MODEL_KEYS],
3968
+ "codex-cli": [...MODEL_KEYS],
3969
+ "gemini-cli": [...MODEL_KEYS],
3970
+ "antigravity-cli": [...MODEL_KEYS],
3971
+ "gemini-web": ["models"]
3972
+ };
3973
+ function isStringList(value) {
3974
+ return Array.isArray(value) && value.every((v) => typeof v === "string" && v.length > 0);
3975
+ }
3976
+ function apiConfigIssues(provider, config, existing = {}) {
3977
+ const allowed = API_CONFIG_KEYS[provider];
3978
+ const issues = [];
3979
+ for (const [key, value] of Object.entries(config)) {
3980
+ if (!allowed.includes(key)) {
3981
+ if (key in existing && JSON.stringify(existing[key]) === JSON.stringify(value)) continue;
3982
+ issues.push(
3983
+ `config.${key} cannot be set through the API for ${provider} accounts` + (allowed.length > 0 ? ` (allowed: ${allowed.join(", ")})` : "")
3984
+ );
3985
+ continue;
3986
+ }
3987
+ if (key === "baseUrl") {
3988
+ if (typeof value !== "string" || !isHttpUrl(value)) {
3989
+ issues.push("config.baseUrl must be an http(s) URL without embedded credentials");
3990
+ }
3991
+ } else if (key === "models") {
3992
+ if (!isStringList(value)) issues.push("config.models must be a list of model ids");
3993
+ } else if (key === "defaultModel") {
3994
+ if (typeof value !== "string" || !value) issues.push("config.defaultModel must be a string");
3995
+ } else if (key === "includeUsage" && typeof value !== "boolean") {
3996
+ issues.push("config.includeUsage must be true or false");
3997
+ }
3998
+ }
3999
+ return issues;
4000
+ }
4001
+ function isHttpUrl(value) {
4002
+ try {
4003
+ const url = new URL(value);
4004
+ return (url.protocol === "http:" || url.protocol === "https:") && !url.username && !url.password;
4005
+ } catch {
4006
+ return false;
4007
+ }
4008
+ }
4009
+ function mergeApiConfig(provider, existing, incoming) {
4010
+ const allowed = API_CONFIG_KEYS[provider];
4011
+ const kept = Object.fromEntries(
4012
+ Object.entries(existing).filter(([key]) => !allowed.includes(key))
4013
+ );
4014
+ return { ...kept, ...incoming };
4015
+ }
4016
+ function endpointOf(config) {
4017
+ return ENDPOINT_CONFIG_KEYS.map((key) => {
4018
+ const value = config[key];
4019
+ return typeof value === "string" ? value.trim().replace(/\/+$/, "") : "";
4020
+ }).join("\n");
4021
+ }
4022
+ function endpointChanged(existing, next) {
4023
+ return endpointOf(existing) !== endpointOf(next);
4024
+ }
4025
+ function endpointRebindIssue(existing, nextConfig, secretSupplied) {
4026
+ if (!nextConfig || secretSupplied || !existing.hasSecret) return void 0;
4027
+ if (!endpointChanged(existing.config, nextConfig)) return void 0;
4028
+ return "Changing the endpoint of an account that has a stored secret requires sending the secret again in the same request";
4029
+ }
3878
4030
  var EXPERIMENTAL_PROVIDER_KINDS = ["gemini-web"];
3879
4031
  var SUBSCRIPTION_PROVIDER_KINDS = [
3880
4032
  "claude-cli",
@@ -3883,7 +4035,7 @@ var SUBSCRIPTION_PROVIDER_KINDS = [
3883
4035
  "antigravity-cli",
3884
4036
  "gemini-web"
3885
4037
  ];
3886
- var VERSION = "0.5.0";
4038
+ var VERSION = "0.5.2";
3887
4039
  var QUOTA_WINDOWS = ["1m", "5h", "24h"];
3888
4040
  var WINDOW_MS = {
3889
4041
  "1m": 6e4,
@@ -8070,12 +8222,14 @@ function accountService(env = process.env) {
8070
8222
  }
8071
8223
  var OAUTH_PROVIDERS = ["google", "github"];
8072
8224
  var AccountError = class extends Error {
8073
- constructor(message, status) {
8225
+ constructor(message, status, code) {
8074
8226
  super(message);
8075
8227
  this.status = status;
8228
+ this.code = code;
8076
8229
  this.name = "AccountError";
8077
8230
  }
8078
8231
  status;
8232
+ code;
8079
8233
  };
8080
8234
  var userSchema = z8.object({
8081
8235
  id: z8.string().min(1),
@@ -8211,7 +8365,8 @@ var AccountClient = class {
8211
8365
  const detail = error.success ? error.data.error_description ?? error.data.msg ?? error.data.message : void 0;
8212
8366
  throw new AccountError(
8213
8367
  detail ?? `Sign-in failed (HTTP ${response.status}).`,
8214
- response.status
8368
+ response.status,
8369
+ error.success ? error.data.error : void 0
8215
8370
  );
8216
8371
  }
8217
8372
  return raw;
@@ -8287,8 +8442,9 @@ async function startAccountLogin(options) {
8287
8442
  () => setTimeout(() => void close(), 1e3).unref(),
8288
8443
  () => setTimeout(() => void close(), 1e3).unref()
8289
8444
  );
8445
+ const redirectTo = `http://127.0.0.1:${port}${callbackPath}`;
8290
8446
  return {
8291
- url: client.loginUrl(`http://127.0.0.1:${port}${callbackPath}`, pkce.challenge),
8447
+ url: options.provider ? client.authorizeUrl(options.provider, redirectTo, pkce.challenge) : client.loginUrl(redirectTo, pkce.challenge),
8292
8448
  session,
8293
8449
  close: async () => {
8294
8450
  clearTimeout(timeout);
@@ -8299,6 +8455,16 @@ async function startAccountLogin(options) {
8299
8455
  }
8300
8456
  var AAD = Buffer.from("davecode-account", "utf8");
8301
8457
  var REFRESH_MARGIN_MS = 6e4;
8458
+ var LOCK_STALE_MS = 6e4;
8459
+ var LOCK_WAIT_MS = 3e4;
8460
+ var LOCK_POLL_MS = 50;
8461
+ var INVALID_TOKEN_CODES = /* @__PURE__ */ new Set([
8462
+ "invalid_grant",
8463
+ "refresh_token_not_found",
8464
+ "refresh_token_already_used",
8465
+ "session_not_found",
8466
+ "session_expired"
8467
+ ]);
8302
8468
  var fileSchema = z9.object({
8303
8469
  v: z9.literal(1),
8304
8470
  iv: z9.string(),
@@ -8375,22 +8541,133 @@ var AccountStore = class {
8375
8541
  * or when the service revoked the session; offline, an unexpired session is still returned.
8376
8542
  */
8377
8543
  async current(client, now = Date.now()) {
8378
- const session = this.load();
8379
- if (!session) return void 0;
8380
- if (session.expiresAt - REFRESH_MARGIN_MS > now) return session;
8544
+ const first = this.load();
8545
+ if (!first) return void 0;
8546
+ if (first.expiresAt - REFRESH_MARGIN_MS > now) return first;
8547
+ const release = await this.lock();
8381
8548
  try {
8382
- const fresh = await client.refresh(session.refreshToken);
8383
- this.save(fresh);
8384
- return fresh;
8385
- } catch (err) {
8386
- if (err instanceof AccountError && err.status !== void 0 && err.status < 500) {
8387
- this.clear();
8388
- return void 0;
8549
+ const session = this.load();
8550
+ if (!session) return void 0;
8551
+ if (session.expiresAt - REFRESH_MARGIN_MS > now) return session;
8552
+ try {
8553
+ const fresh = await client.refresh(session.refreshToken);
8554
+ this.save(fresh);
8555
+ return fresh;
8556
+ } catch (err) {
8557
+ if (isInvalidToken(err)) {
8558
+ if (this.load()?.refreshToken === session.refreshToken) this.clear();
8559
+ return this.load();
8560
+ }
8561
+ return session;
8389
8562
  }
8390
- return session;
8563
+ } finally {
8564
+ release();
8565
+ }
8566
+ }
8567
+ /**
8568
+ * A cross-process lock: a file created exclusively next to account.json. A lock older than
8569
+ * LOCK_STALE_MS belongs to a process that died, and is taken over. After LOCK_WAIT_MS the
8570
+ * refresh goes ahead without it (the service tolerates two refreshes racing).
8571
+ */
8572
+ async lock() {
8573
+ const path8 = `${this.path}.lock`;
8574
+ const owner = `${process.pid}:${randomBytes8(8).toString("hex")}`;
8575
+ mkdirSync7(dirname6(path8), { recursive: true });
8576
+ const deadline = Date.now() + LOCK_WAIT_MS;
8577
+ for (; ; ) {
8578
+ try {
8579
+ writeFileSync3(path8, owner, { flag: "wx", mode: 384 });
8580
+ return () => {
8581
+ try {
8582
+ if (readFileSync3(path8, "utf8") === owner) rmSync3(path8, { force: true });
8583
+ } catch {
8584
+ }
8585
+ };
8586
+ } catch (err) {
8587
+ if (err.code !== "EEXIST" && !isWindowsBusy(err))
8588
+ return () => void 0;
8589
+ }
8590
+ try {
8591
+ if (Date.now() - statSync2(path8).mtimeMs > LOCK_STALE_MS) rmSync3(path8, { force: true });
8592
+ } catch {
8593
+ }
8594
+ if (Date.now() >= deadline) return () => void 0;
8595
+ await new Promise((resolve5) => setTimeout(resolve5, LOCK_POLL_MS));
8391
8596
  }
8392
8597
  }
8393
8598
  };
8599
+ function isInvalidToken(err) {
8600
+ if (!(err instanceof AccountError) || err.status === void 0) return false;
8601
+ if (err.code) return INVALID_TOKEN_CODES.has(err.code);
8602
+ return err.status === 400 || err.status === 401;
8603
+ }
8604
+ var isWindowsBusy = (err) => ["EPERM", "EBUSY"].includes(err.code ?? "");
8605
+ var SIGN_IN_FAILED = "Sign-in did not finish. Please try again.";
8606
+ function createAccountControl(options) {
8607
+ const service = options.service ?? accountService(options.env);
8608
+ if (!service) return void 0;
8609
+ const client = new AccountClient(service, options.fetch ? { fetch: options.fetch } : {});
8610
+ const store = () => new AccountStore(options.home, options.env);
8611
+ let active;
8612
+ let error = null;
8613
+ async function stop() {
8614
+ const login = active;
8615
+ active = void 0;
8616
+ await login?.close();
8617
+ }
8618
+ async function finish(login) {
8619
+ try {
8620
+ const session = await login.session;
8621
+ if (active !== login) return;
8622
+ active = void 0;
8623
+ store().save(session);
8624
+ } catch {
8625
+ if (active !== login) return;
8626
+ active = void 0;
8627
+ error = SIGN_IN_FAILED;
8628
+ }
8629
+ }
8630
+ return {
8631
+ async state() {
8632
+ const session = await store().current(client);
8633
+ return {
8634
+ signedIn: Boolean(session),
8635
+ user: session?.user ?? null,
8636
+ pending: active !== void 0,
8637
+ error
8638
+ };
8639
+ },
8640
+ async login(provider) {
8641
+ await stop();
8642
+ error = null;
8643
+ const login = await startAccountLogin({
8644
+ client,
8645
+ ...provider ? { provider } : {},
8646
+ ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
8647
+ });
8648
+ active = login;
8649
+ void finish(login);
8650
+ const opened = await options.open(login.url).catch(() => false);
8651
+ return { url: login.url, opened };
8652
+ },
8653
+ async cancel() {
8654
+ error = null;
8655
+ await stop();
8656
+ },
8657
+ async logout() {
8658
+ await stop();
8659
+ error = null;
8660
+ const accounts = store();
8661
+ const session = accounts.load();
8662
+ try {
8663
+ if (session) await client.signOut(session.accessToken);
8664
+ } catch {
8665
+ }
8666
+ accounts.clear();
8667
+ },
8668
+ close: stop
8669
+ };
8670
+ }
8394
8671
  var BRAND_MARK_SVG = '<svg viewBox="0 0 1214 1214" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path fill="currentColor" fill-rule="evenodd" d="M324.3 1096.5C324.6 1095.4 326.5 1088.3 328.5 1080.8C341.4 1031.3 375.8 953.4 419.7 874.0C445.8 826.9 448.4 822.4 471.8 783.0C501.5 733.1 530.1 687.6 556.4 648.5C563.7 637.5 569.7 628.4 569.5 628.2C569.4 628.1 563.1 631.7 555.4 636.3C513.8 661.4 468.0 683.9 411.0 707.5C337.2 737.9 321.7 744.7 296.0 757.2C241.9 783.5 199.1 809.4 152.0 844.3C119.5 868.4 98.8 885.9 71.3 912.4C64.0 919.5 58.0 925.0 58.0 924.7C58.0 923.1 64.7 902.4 68.8 891.0C116.1 762.1 215.0 644.2 351.0 554.8C385.2 532.3 411.6 516.9 445.5 499.4C521.4 460.4 589.4 435.7 636.0 430.0C676.8 425.1 715.1 437.0 743.9 463.6C763.4 481.6 779.0 509.9 785.2 538.5C787.7 550.1 788.7 579.7 787.1 592.5C782.6 626.4 769.7 661.5 746.5 702.0C717.7 752.5 675.6 806.9 627.0 856.4C599.5 884.4 575.9 905.4 542.5 931.6C510.0 957.1 500.7 964.2 432.5 1015.0C409.4 1032.3 382.6 1052.5 373.0 1060.0C354.5 1074.4 327.4 1095.5 325.1 1097.4C324.0 1098.3 323.8 1098.1 324.3 1096.5ZM783.2 1017.8C797.1 999.5 820.2 966.0 831.7 947.5C868.5 888.3 888.8 840.5 903.4 778.5C917.9 716.9 921.2 643.7 912.0 591.0C904.6 549.3 889.7 511.9 866.7 477.5C856.6 462.3 853.1 457.8 837.4 439.6C817.4 416.6 806.6 402.0 800.5 389.5C793.6 375.5 791.7 368.1 791.7 356.0C791.7 335.3 799.3 319.6 819.0 299.9C849.7 269.2 900.2 247.9 956.8 241.9C963.0 241.2 967.7 240.3 967.3 239.9C966.1 238.8 948.5 236.3 933.0 234.9C913.6 233.2 875.2 234.3 859.0 237.0C839.7 240.2 827.8 242.9 813.0 247.5C753.9 265.9 700.6 300.9 659.2 348.5C648.9 360.4 636.6 376.5 632.4 383.5C630.3 387.1 629.0 388.2 624.7 389.6C603.8 396.4 554.6 417.6 513.5 437.5C447.6 469.4 395.4 496.8 341.5 528.1L337.5 530.4L339.5 527.9C340.6 526.6 346.2 520.3 352.0 514.0C374.4 489.6 390.2 470.8 411.2 443.5C429.3 419.9 444.6 398.2 488.5 333.5C510.5 301.0 529.1 278.0 550.9 256.3C593.0 214.1 640.3 183.6 691.5 165.5C727.7 152.8 756.5 147.7 792.5 147.7C854.3 147.8 906.4 164.9 954.1 200.6C967.5 210.8 974.1 214.6 981.5 217.0C991.4 220.1 1022.1 231.9 1038.5 238.8C1061.9 248.7 1099.0 267.4 1097.7 268.7C1097.4 268.9 1089.3 268.5 1079.7 267.9C1033.7 264.7 984.5 274.1 946.2 293.4C932.3 300.4 915.0 313.0 903.4 324.5C881.0 346.6 870.0 369.6 870.0 394.4C870.0 413.7 876.8 433.1 894.7 465.2C908.8 490.3 914.6 501.1 922.8 517.5C961.3 594.3 980.0 662.5 980.0 725.4C980.0 770.9 967.3 818.9 944.4 860.4C927.6 890.8 912.0 911.0 882.5 940.6C856.5 966.7 828.5 989.7 797.0 1010.7C779.6 1022.2 780.0 1022.0 783.2 1017.8Z"/></svg>';
8395
8672
  var LOGO_ART = [
8396
8673
  " \u2584\u2584\u2584\u2588\u2584\u2584\u2584",
@@ -9462,6 +9739,8 @@ export {
9462
9739
  routeSchema,
9463
9740
  configSchema,
9464
9741
  ConfigError,
9742
+ PROJECT_SETTABLE_KEYS,
9743
+ filterProjectLayer,
9465
9744
  deepMerge,
9466
9745
  envLayer,
9467
9746
  loadConfig,
@@ -9486,6 +9765,12 @@ export {
9486
9765
  OpenAIProvider,
9487
9766
  OpenAICompatibleProvider,
9488
9767
  createProviders,
9768
+ ENDPOINT_CONFIG_KEYS,
9769
+ API_CONFIG_KEYS,
9770
+ apiConfigIssues,
9771
+ mergeApiConfig,
9772
+ endpointChanged,
9773
+ endpointRebindIssue,
9489
9774
  EXPERIMENTAL_PROVIDER_KINDS,
9490
9775
  SUBSCRIPTION_PROVIDER_KINDS,
9491
9776
  VERSION,
@@ -9587,6 +9872,7 @@ export {
9587
9872
  startAccountLogin,
9588
9873
  accountFile,
9589
9874
  AccountStore,
9875
+ createAccountControl,
9590
9876
  BRAND_MARK_SVG,
9591
9877
  brandLogo,
9592
9878
  DEFAULT_ROLES,
@@ -9605,4 +9891,4 @@ export {
9605
9891
  GoalStore,
9606
9892
  createGoalService
9607
9893
  };
9608
- //# sourceMappingURL=chunk-HSBJDV3O.js.map
9894
+ //# sourceMappingURL=chunk-QKY3OKVG.js.map