@dosu/cli 0.49.0 → 0.49.1

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 (2) hide show
  1. package/bin/dosu.js +555 -274
  2. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -2098,6 +2098,35 @@ var init_commander = __esm(() => {
2098
2098
  program = new Command;
2099
2099
  });
2100
2100
 
2101
+ // src/auth/session-errors.ts
2102
+ var SESSION_EXPIRED_CODE = "SESSION_EXPIRED", SESSION_PERSISTENCE_ERROR_CODE = "SESSION_PERSISTENCE_ERROR", SESSION_REFRESH_ERROR_CODE = "SESSION_REFRESH_ERROR", SessionExpiredError, SessionPersistenceError, SessionRefreshError;
2103
+ var init_session_errors = __esm(() => {
2104
+ SessionExpiredError = class SessionExpiredError extends Error {
2105
+ code = SESSION_EXPIRED_CODE;
2106
+ constructor(options) {
2107
+ super("Your Dosu session has expired. Run 'dosu login' to re-authenticate.", options);
2108
+ this.name = "SessionExpiredError";
2109
+ }
2110
+ };
2111
+ SessionPersistenceError = class SessionPersistenceError extends Error {
2112
+ code = SESSION_PERSISTENCE_ERROR_CODE;
2113
+ constructor(options) {
2114
+ super("Could not safely save refreshed Dosu credentials. Ensure the Dosu config directory is writable, then retry.", options);
2115
+ this.name = "SessionPersistenceError";
2116
+ }
2117
+ };
2118
+ SessionRefreshError = class SessionRefreshError extends Error {
2119
+ code = SESSION_REFRESH_ERROR_CODE;
2120
+ status;
2121
+ constructor(options = {}) {
2122
+ const message = options.status ? `Could not refresh the Dosu session (authentication server returned status ${options.status}). Retry the command.` : "Could not reach the authentication server to refresh the Dosu session. Retry the command.";
2123
+ super(message, options);
2124
+ this.name = "SessionRefreshError";
2125
+ this.status = options.status;
2126
+ }
2127
+ };
2128
+ });
2129
+
2101
2130
  // src/config/identity.ts
2102
2131
  function getAccessTokenClaim(accessToken, claim) {
2103
2132
  try {
@@ -2330,6 +2359,160 @@ var init_config = __esm(() => {
2330
2359
  init_config_v1_migration();
2331
2360
  });
2332
2361
 
2362
+ // src/config/config-lock.ts
2363
+ import { randomUUID } from "node:crypto";
2364
+ import {
2365
+ closeSync,
2366
+ existsSync as existsSync2,
2367
+ linkSync,
2368
+ mkdirSync as mkdirSync2,
2369
+ openSync,
2370
+ readFileSync as readFileSync2,
2371
+ statSync,
2372
+ unlinkSync,
2373
+ writeFileSync as writeFileSync2
2374
+ } from "node:fs";
2375
+ import { join as join2 } from "node:path";
2376
+ async function withConfigRefreshLock(task, options = {}) {
2377
+ const release = await acquireConfigRefreshLock(options);
2378
+ try {
2379
+ return await task();
2380
+ } finally {
2381
+ release();
2382
+ }
2383
+ }
2384
+ async function acquireConfigRefreshLock(options) {
2385
+ const now = options.now ?? Date.now;
2386
+ const sleep = options.sleep ?? defaultSleep;
2387
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
2388
+ const retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
2389
+ const staleAgeMs = options.staleAgeMs ?? DEFAULT_STALE_AGE_MS;
2390
+ const isProcessAlive = options.isProcessAlive ?? defaultIsProcessAlive;
2391
+ const ownerId = options.ownerId ?? randomUUID();
2392
+ const configDir = getConfigDir();
2393
+ const lockPath = join2(configDir, CONFIG_REFRESH_LOCK_FILENAME);
2394
+ try {
2395
+ if (!existsSync2(configDir))
2396
+ mkdirSync2(configDir, { recursive: true, mode: 448 });
2397
+ } catch (cause) {
2398
+ throw new SessionPersistenceError({ cause });
2399
+ }
2400
+ const deadline = now() + Math.max(0, timeoutMs);
2401
+ while (true) {
2402
+ try {
2403
+ createLockFile(lockPath, { owner_id: ownerId, pid: process.pid, created_at: now() });
2404
+ return () => releaseOwnedLock(lockPath, ownerId);
2405
+ } catch (cause) {
2406
+ if (!hasErrorCode(cause, "EEXIST")) {
2407
+ throw new SessionPersistenceError({ cause });
2408
+ }
2409
+ }
2410
+ if (claimAndRemoveStaleLock(lockPath, staleAgeMs, now(), isProcessAlive, ownerId)) {
2411
+ continue;
2412
+ }
2413
+ if (now() >= deadline) {
2414
+ throw new SessionPersistenceError({
2415
+ cause: new Error("Timed out waiting for another Dosu session refresh.")
2416
+ });
2417
+ }
2418
+ await sleep(Math.max(1, retryDelayMs));
2419
+ }
2420
+ }
2421
+ function createLockFile(lockPath, metadata) {
2422
+ const fd = openSync(lockPath, "wx", 384);
2423
+ try {
2424
+ writeFileSync2(fd, JSON.stringify(metadata));
2425
+ } catch (cause) {
2426
+ try {
2427
+ closeSync(fd);
2428
+ } catch {}
2429
+ try {
2430
+ unlinkSync(lockPath);
2431
+ } catch {}
2432
+ throw cause;
2433
+ }
2434
+ try {
2435
+ closeSync(fd);
2436
+ } catch (cause) {
2437
+ try {
2438
+ unlinkSync(lockPath);
2439
+ } catch {}
2440
+ throw cause;
2441
+ }
2442
+ }
2443
+ function releaseOwnedLock(lockPath, ownerId) {
2444
+ try {
2445
+ if (readLockMetadata(lockPath)?.owner_id === ownerId)
2446
+ unlinkSync(lockPath);
2447
+ } catch {}
2448
+ }
2449
+ function claimAndRemoveStaleLock(lockPath, staleAgeMs, now, isProcessAlive, ownerId) {
2450
+ const claimPath = `${lockPath}.stale.${process.pid}.${ownerId}`;
2451
+ try {
2452
+ linkSync(lockPath, claimPath);
2453
+ const metadata = readLockMetadata(claimPath);
2454
+ let stale = false;
2455
+ if (metadata && Number.isInteger(metadata.pid) && metadata.pid > 0) {
2456
+ stale = !isProcessAlive(metadata.pid);
2457
+ } else {
2458
+ stale = now - statSync(claimPath).mtimeMs >= staleAgeMs;
2459
+ }
2460
+ if (!stale)
2461
+ return false;
2462
+ const current = statSync(lockPath);
2463
+ const claimed = statSync(claimPath);
2464
+ if (current.dev !== claimed.dev || current.ino !== claimed.ino)
2465
+ return false;
2466
+ unlinkSync(lockPath);
2467
+ return true;
2468
+ } catch (cause) {
2469
+ return hasErrorCode(cause, "ENOENT");
2470
+ } finally {
2471
+ try {
2472
+ unlinkSync(claimPath);
2473
+ } catch {}
2474
+ }
2475
+ }
2476
+ function readLockMetadata(lockPath) {
2477
+ try {
2478
+ const parsed = JSON.parse(readFileSync2(lockPath, "utf8"));
2479
+ if (!isRecord3(parsed))
2480
+ return;
2481
+ if (typeof parsed.owner_id !== "string" || typeof parsed.pid !== "number" || typeof parsed.created_at !== "number") {
2482
+ return;
2483
+ }
2484
+ return {
2485
+ owner_id: parsed.owner_id,
2486
+ pid: parsed.pid,
2487
+ created_at: parsed.created_at
2488
+ };
2489
+ } catch {
2490
+ return;
2491
+ }
2492
+ }
2493
+ function defaultIsProcessAlive(pid) {
2494
+ try {
2495
+ process.kill(pid, 0);
2496
+ return true;
2497
+ } catch (cause) {
2498
+ return !hasErrorCode(cause, "ESRCH");
2499
+ }
2500
+ }
2501
+ function defaultSleep(delayMs) {
2502
+ return new Promise((resolve) => setTimeout(resolve, delayMs));
2503
+ }
2504
+ function hasErrorCode(value, code) {
2505
+ return isRecord3(value) && value.code === code;
2506
+ }
2507
+ function isRecord3(value) {
2508
+ return typeof value === "object" && value !== null;
2509
+ }
2510
+ var CONFIG_REFRESH_LOCK_FILENAME = "session-refresh.lock", DEFAULT_TIMEOUT_MS = 5000, DEFAULT_RETRY_DELAY_MS = 25, DEFAULT_STALE_AGE_MS = 30000;
2511
+ var init_config_lock = __esm(() => {
2512
+ init_session_errors();
2513
+ init_config();
2514
+ });
2515
+
2333
2516
  // src/config/constants.ts
2334
2517
  function getWebAppURL() {
2335
2518
  return process.env.DOSU_WEB_APP_URL_OVERRIDE ?? "https://app.dosu.dev" ?? "";
@@ -2359,12 +2542,12 @@ class Client {
2359
2542
  if (isTokenExpired(this.config)) {
2360
2543
  await this.refreshToken();
2361
2544
  }
2545
+ const requestAccessToken = this.config.active_account?.session.access_token;
2362
2546
  let resp = await this.doRequestOnce(method, path2, body);
2363
2547
  if (resp.status === 401 || resp.status === 403) {
2364
- try {
2548
+ const currentAccessToken = this.config.active_account?.session.access_token;
2549
+ if (!currentAccessToken || currentAccessToken === requestAccessToken) {
2365
2550
  await this.refreshToken();
2366
- } catch {
2367
- throw new SessionExpiredError;
2368
2551
  }
2369
2552
  resp = await this.doRequestOnce(method, path2, body);
2370
2553
  }
@@ -2405,36 +2588,34 @@ class Client {
2405
2588
  return this.doRequest("DELETE", path2);
2406
2589
  }
2407
2590
  async refreshToken() {
2408
- this.adoptNewerDiskTokens();
2409
- if (!this.config.active_account?.session.refresh_token) {
2410
- throw new Error("no refresh token available");
2411
- }
2412
- try {
2413
- await this.refreshTokenOnce();
2414
- } catch (err) {
2415
- if (!this.adoptNewerDiskTokens()) {
2416
- throw err;
2591
+ const refreshTokenAtStart = this.config.active_account?.session.refresh_token;
2592
+ if (!refreshTokenAtStart) {
2593
+ throw new SessionExpiredError;
2594
+ }
2595
+ await withConfigRefreshLock(async () => {
2596
+ const disk = loadConfig();
2597
+ this.assertSameActiveAccount(disk);
2598
+ const diskRefreshToken = disk.active_account?.session.refresh_token;
2599
+ if (!diskRefreshToken)
2600
+ throw new SessionExpiredError;
2601
+ const diskHasNewerSession = diskRefreshToken !== refreshTokenAtStart;
2602
+ if (diskHasNewerSession && !isTokenExpired(disk)) {
2603
+ this.adoptConfig(disk);
2604
+ return;
2417
2605
  }
2418
- await this.refreshTokenOnce();
2419
- }
2420
- }
2421
- adoptNewerDiskTokens() {
2422
- const disk = loadConfig();
2423
- this.assertSameActiveAccount(disk);
2424
- const diskSession = disk.active_account?.session;
2425
- const memorySession = this.config.active_account?.session;
2426
- if (!diskSession?.refresh_token || !memorySession || diskSession.refresh_token === memorySession.refresh_token) {
2427
- return false;
2428
- }
2429
- memorySession.access_token = diskSession.access_token;
2430
- memorySession.refresh_token = diskSession.refresh_token;
2431
- memorySession.expires_at = diskSession.expires_at;
2432
- return true;
2606
+ const candidate = await this.refreshTokenOnce(disk);
2607
+ try {
2608
+ saveConfig(candidate);
2609
+ } catch (cause) {
2610
+ throw new SessionPersistenceError({ cause });
2611
+ }
2612
+ this.adoptConfig(candidate);
2613
+ });
2433
2614
  }
2434
- async refreshTokenOnce() {
2435
- const session = this.config.active_account?.session;
2615
+ async refreshTokenOnce(source) {
2616
+ const session = source.active_account?.session;
2436
2617
  if (!session?.refresh_token)
2437
- throw new Error("no refresh token available");
2618
+ throw new SessionExpiredError;
2438
2619
  const supabaseURL = getSupabaseURL();
2439
2620
  const oauthClientID = getAccessTokenOAuthClientID(session.access_token);
2440
2621
  const endpoint = oauthClientID ? `${supabaseURL}/auth/v1/oauth/token` : `${supabaseURL}/auth/v1/token?grant_type=refresh_token`;
@@ -2444,20 +2625,54 @@ class Client {
2444
2625
  refresh_token: session.refresh_token,
2445
2626
  client_id: oauthClientID
2446
2627
  }).toString() : JSON.stringify({ refresh_token: session.refresh_token });
2447
- const resp = await fetch(endpoint, {
2448
- method: "POST",
2449
- headers,
2450
- body
2451
- });
2452
- if (resp.status !== 200) {
2453
- throw new Error(`refresh failed with status ${resp.status}`);
2628
+ const controller = new AbortController;
2629
+ const timeout = setTimeout(() => controller.abort(), REFRESH_REQUEST_TIMEOUT_MS);
2630
+ let resp;
2631
+ try {
2632
+ resp = await fetch(endpoint, {
2633
+ method: "POST",
2634
+ headers,
2635
+ body,
2636
+ signal: controller.signal
2637
+ });
2638
+ } catch (cause) {
2639
+ clearTimeout(timeout);
2640
+ throw new SessionRefreshError({ cause });
2454
2641
  }
2455
- const data = await resp.json();
2456
- this.assertSameActiveAccount(loadConfig());
2457
- session.access_token = data.access_token;
2458
- session.refresh_token = data.refresh_token;
2459
- session.expires_at = Math.floor(Date.now() / 1000) + data.expires_in;
2460
- saveConfig(this.config);
2642
+ let data;
2643
+ try {
2644
+ if (resp.status !== 200) {
2645
+ const errorCode = await readAuthErrorCode(resp);
2646
+ if (REAUTHENTICATION_ERROR_CODES.has(errorCode ?? "") || !oauthClientID && errorCode === "validation_failed") {
2647
+ throw new SessionExpiredError;
2648
+ }
2649
+ throw new SessionRefreshError({ status: resp.status });
2650
+ }
2651
+ data = await readRefreshResponse(resp);
2652
+ } finally {
2653
+ clearTimeout(timeout);
2654
+ }
2655
+ const latest = loadConfig();
2656
+ this.assertSameActiveAccount(latest);
2657
+ const latestSession = latest.active_account?.session;
2658
+ if (!latestSession?.refresh_token)
2659
+ throw new SessionExpiredError;
2660
+ if (latestSession.refresh_token !== session.refresh_token) {
2661
+ return latest;
2662
+ }
2663
+ return configWithSession(latest, {
2664
+ access_token: data.access_token,
2665
+ refresh_token: data.refresh_token,
2666
+ expires_at: Math.floor(Date.now() / 1000) + data.expires_in
2667
+ });
2668
+ }
2669
+ adoptConfig(source) {
2670
+ this.config.mode = source.mode;
2671
+ this.config.active_account = source.active_account ? {
2672
+ ...source.active_account,
2673
+ session: { ...source.active_account.session },
2674
+ target: source.active_account.target ? { ...source.active_account.target } : undefined
2675
+ } : undefined;
2461
2676
  }
2462
2677
  assertSameActiveAccount(disk) {
2463
2678
  const memoryUserID = getConfigUserID(this.config);
@@ -2514,6 +2729,49 @@ class Client {
2514
2729
  return resp.json();
2515
2730
  }
2516
2731
  }
2732
+ async function readAuthErrorCode(resp) {
2733
+ try {
2734
+ const data = await resp.json();
2735
+ if (!isRecord4(data))
2736
+ return;
2737
+ const code = typeof data.error_code === "string" ? data.error_code : data.error;
2738
+ return typeof code === "string" ? code : undefined;
2739
+ } catch {
2740
+ return;
2741
+ }
2742
+ }
2743
+ async function readRefreshResponse(resp) {
2744
+ let data;
2745
+ try {
2746
+ data = await resp.json();
2747
+ } catch (cause) {
2748
+ throw new SessionRefreshError({ cause, status: resp.status });
2749
+ }
2750
+ if (!isRecord4(data) || typeof data.access_token !== "string" || typeof data.refresh_token !== "string" || typeof data.expires_in !== "number" || !Number.isFinite(data.expires_in)) {
2751
+ throw new SessionRefreshError({ status: resp.status });
2752
+ }
2753
+ return {
2754
+ access_token: data.access_token,
2755
+ refresh_token: data.refresh_token,
2756
+ expires_in: data.expires_in
2757
+ };
2758
+ }
2759
+ function configWithSession(source, session) {
2760
+ const account = source.active_account;
2761
+ if (!account)
2762
+ throw new SessionExpiredError;
2763
+ return {
2764
+ ...source,
2765
+ active_account: {
2766
+ ...account,
2767
+ session,
2768
+ target: account.target ? { ...account.target } : undefined
2769
+ }
2770
+ };
2771
+ }
2772
+ function isRecord4(value) {
2773
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2774
+ }
2517
2775
  async function readErrorBody(resp) {
2518
2776
  try {
2519
2777
  const text = await resp.text();
@@ -2522,15 +2780,18 @@ async function readErrorBody(resp) {
2522
2780
  return "";
2523
2781
  }
2524
2782
  }
2525
- var SessionExpiredError;
2783
+ var REFRESH_REQUEST_TIMEOUT_MS = 1e4, REAUTHENTICATION_ERROR_CODES;
2526
2784
  var init_client = __esm(() => {
2785
+ init_session_errors();
2527
2786
  init_config();
2528
- SessionExpiredError = class SessionExpiredError extends Error {
2529
- constructor() {
2530
- super("session expired");
2531
- this.name = "SessionExpiredError";
2532
- }
2533
- };
2787
+ init_config_lock();
2788
+ REAUTHENTICATION_ERROR_CODES = new Set([
2789
+ "invalid_grant",
2790
+ "refresh_token_already_used",
2791
+ "refresh_token_not_found",
2792
+ "session_expired",
2793
+ "session_not_found"
2794
+ ]);
2534
2795
  });
2535
2796
 
2536
2797
  // node_modules/picocolors/picocolors.js
@@ -4739,18 +5000,18 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
4739
5000
  function getVersionString() {
4740
5001
  return `v${VERSION}`;
4741
5002
  }
4742
- var VERSION = "0.49.0", INSTALL_CHANNEL = "npm";
5003
+ var VERSION = "0.49.1", INSTALL_CHANNEL = "npm";
4743
5004
 
4744
5005
  // src/debug/logger.ts
4745
5006
  import {
4746
5007
  appendFileSync,
4747
- existsSync as existsSync2,
4748
- mkdirSync as mkdirSync2,
4749
- readFileSync as readFileSync2,
4750
- statSync,
4751
- writeFileSync as writeFileSync2
5008
+ existsSync as existsSync3,
5009
+ mkdirSync as mkdirSync3,
5010
+ readFileSync as readFileSync3,
5011
+ statSync as statSync2,
5012
+ writeFileSync as writeFileSync3
4752
5013
  } from "node:fs";
4753
- import { join as join2 } from "node:path";
5014
+ import { join as join3 } from "node:path";
4754
5015
  function redactSecrets(message) {
4755
5016
  let redacted = message;
4756
5017
  for (const key of SECRET_QUERY_KEYS) {
@@ -4770,29 +5031,29 @@ function ensureInit() {
4770
5031
  function resolveLogPath() {
4771
5032
  if (!logFilePath) {
4772
5033
  const dir = getConfigDir();
4773
- if (!existsSync2(dir)) {
4774
- mkdirSync2(dir, { recursive: true, mode: 448 });
5034
+ if (!existsSync3(dir)) {
5035
+ mkdirSync3(dir, { recursive: true, mode: 448 });
4775
5036
  }
4776
- logFilePath = join2(dir, LOG_FILENAME);
5037
+ logFilePath = join3(dir, LOG_FILENAME);
4777
5038
  }
4778
5039
  return logFilePath;
4779
5040
  }
4780
5041
  function truncateIfNeeded() {
4781
5042
  try {
4782
5043
  const path2 = resolveLogPath();
4783
- if (!existsSync2(path2))
5044
+ if (!existsSync3(path2))
4784
5045
  return;
4785
- const stat = statSync(path2);
5046
+ const stat = statSync2(path2);
4786
5047
  if (stat.size <= MAX_LOG_SIZE)
4787
5048
  return;
4788
- const content = readFileSync2(path2);
5049
+ const content = readFileSync3(path2);
4789
5050
  const start = content.length - TRUNCATE_KEEP;
4790
5051
  let lineStart = start;
4791
5052
  while (lineStart < content.length && content[lineStart] !== 10) {
4792
5053
  lineStart++;
4793
5054
  }
4794
5055
  lineStart = Math.min(lineStart + 1, content.length);
4795
- writeFileSync2(path2, content.subarray(lineStart), { mode: 384 });
5056
+ writeFileSync3(path2, content.subarray(lineStart), { mode: 384 });
4796
5057
  } catch {}
4797
5058
  }
4798
5059
  function writeSessionHeader() {
@@ -4897,11 +5158,7 @@ function createTypedClient(config) {
4897
5158
  async headers() {
4898
5159
  if (isTokenExpired(config)) {
4899
5160
  logger.debug("trpc", "token expired, refreshing before request");
4900
- try {
4901
- await httpClient.refreshToken();
4902
- } catch {
4903
- throw new Error("session expired. Run 'dosu login' to re-authenticate");
4904
- }
5161
+ await httpClient.refreshToken();
4905
5162
  }
4906
5163
  return {
4907
5164
  "Supabase-Access-Token": config.active_account?.session.access_token ?? "",
@@ -4909,13 +5166,13 @@ function createTypedClient(config) {
4909
5166
  };
4910
5167
  },
4911
5168
  async fetch(url, options) {
5169
+ const requestAccessToken = new Headers(options?.headers).get("Supabase-Access-Token");
4912
5170
  const res = await globalThis.fetch(url, options);
4913
5171
  if (res.status === 401 || res.status === 403) {
4914
5172
  logger.debug("trpc", "got 401/403, attempting token refresh and retry");
4915
- try {
5173
+ const currentAccessToken = config.active_account?.session.access_token;
5174
+ if (!currentAccessToken || requestAccessToken === null || currentAccessToken === requestAccessToken) {
4916
5175
  await httpClient.refreshToken();
4917
- } catch {
4918
- return res;
4919
5176
  }
4920
5177
  return globalThis.fetch(url, {
4921
5178
  ...options,
@@ -8401,17 +8658,17 @@ var init_errors = __esm(() => {
8401
8658
  });
8402
8659
 
8403
8660
  // src/version/skill-update-check.ts
8404
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
8405
- import { join as join5 } from "node:path";
8661
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
8662
+ import { join as join6 } from "node:path";
8406
8663
  function getCachePath2() {
8407
- return join5(getConfigDir(), CACHE_FILENAME2);
8664
+ return join6(getConfigDir(), CACHE_FILENAME2);
8408
8665
  }
8409
8666
  function readSkillCache() {
8410
8667
  try {
8411
8668
  const path3 = getCachePath2();
8412
- if (!existsSync5(path3))
8669
+ if (!existsSync6(path3))
8413
8670
  return null;
8414
- const data = JSON.parse(readFileSync6(path3, "utf-8"));
8671
+ const data = JSON.parse(readFileSync7(path3, "utf-8"));
8415
8672
  if (typeof data.lastCheck === "number" && typeof data.latestSha === "string" && typeof data.installedSha === "string") {
8416
8673
  return data;
8417
8674
  }
@@ -8423,10 +8680,10 @@ function readSkillCache() {
8423
8680
  function writeSkillCache(cache) {
8424
8681
  try {
8425
8682
  const dir = getConfigDir();
8426
- if (!existsSync5(dir)) {
8427
- mkdirSync4(dir, { recursive: true, mode: 448 });
8683
+ if (!existsSync6(dir)) {
8684
+ mkdirSync5(dir, { recursive: true, mode: 448 });
8428
8685
  }
8429
- writeFileSync5(getCachePath2(), JSON.stringify(cache), { mode: 384 });
8686
+ writeFileSync6(getCachePath2(), JSON.stringify(cache), { mode: 384 });
8430
8687
  } catch {}
8431
8688
  }
8432
8689
  function clearInstalledSha() {
@@ -8500,7 +8757,7 @@ var init_skill_update_check = __esm(() => {
8500
8757
  // src/commands/skill.ts
8501
8758
  import { exec as exec2, execSync as execSync2 } from "node:child_process";
8502
8759
  import { homedir } from "node:os";
8503
- import { join as join6 } from "node:path";
8760
+ import { join as join7 } from "node:path";
8504
8761
  function skillAgentIDsForProviders(providerIDs) {
8505
8762
  return [
8506
8763
  ...new Set(providerIDs.map((providerID) => SKILL_AGENT_BY_PROVIDER[providerID]).filter((agent) => Boolean(agent)))
@@ -8511,17 +8768,17 @@ function skillInstallTargetForProvider(providerID) {
8511
8768
  if (!agentID)
8512
8769
  return null;
8513
8770
  if (agentID === "claude-code") {
8514
- const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join6(homedir(), ".claude");
8515
- return { path: join6(claudeConfigDir, "skills", SKILL_NAME), symlink: true };
8771
+ const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join7(homedir(), ".claude");
8772
+ return { path: join7(claudeConfigDir, "skills", SKILL_NAME), symlink: true };
8516
8773
  }
8517
8774
  if (agentID === "windsurf") {
8518
8775
  return {
8519
- path: join6(homedir(), ".codeium", "windsurf", "skills", SKILL_NAME),
8776
+ path: join7(homedir(), ".codeium", "windsurf", "skills", SKILL_NAME),
8520
8777
  symlink: true
8521
8778
  };
8522
8779
  }
8523
8780
  return {
8524
- path: join6(homedir(), ".agents", "skills", SKILL_NAME),
8781
+ path: join7(homedir(), ".agents", "skills", SKILL_NAME),
8525
8782
  symlink: false
8526
8783
  };
8527
8784
  }
@@ -8901,7 +9158,7 @@ var require_cjs = __commonJS((exports) => {
8901
9158
  var require_lib = __commonJS((exports, module) => {
8902
9159
  var __filename = "/home/runner/work/dosu-cli/dosu-cli/node_modules/write-file-atomic/lib/index.js";
8903
9160
  module.exports = writeFile;
8904
- module.exports.sync = writeFileSync6;
9161
+ module.exports.sync = writeFileSync7;
8905
9162
  module.exports._getTmpname = getTmpname;
8906
9163
  module.exports._cleanupOnExit = cleanupOnExit;
8907
9164
  var fs7 = __require("fs");
@@ -9034,7 +9291,7 @@ var require_lib = __commonJS((exports, module) => {
9034
9291
  }
9035
9292
  return promise;
9036
9293
  }
9037
- function writeFileSync6(filename, data, options) {
9294
+ function writeFileSync7(filename, data, options) {
9038
9295
  if (typeof options === "string") {
9039
9296
  options = { encoding: options };
9040
9297
  } else if (!options) {
@@ -9110,7 +9367,7 @@ var require_lib = __commonJS((exports, module) => {
9110
9367
  });
9111
9368
 
9112
9369
  // src/mcp/config-helpers.ts
9113
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync7 } from "node:fs";
9370
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "node:fs";
9114
9371
  import { dirname as dirname2 } from "node:path";
9115
9372
  function mcpURL(deploymentID) {
9116
9373
  return `${getBackendURL()}/v1/mcp/deployments/${deploymentID}`;
@@ -9144,9 +9401,9 @@ function mcpRemoteServer(url, apiKey) {
9144
9401
  };
9145
9402
  }
9146
9403
  function loadJSONConfig(path3) {
9147
- if (!existsSync6(path3))
9404
+ if (!existsSync7(path3))
9148
9405
  return {};
9149
- let data = readFileSync7(path3, "utf-8").trim();
9406
+ let data = readFileSync8(path3, "utf-8").trim();
9150
9407
  if (!data)
9151
9408
  return {};
9152
9409
  if (path3.endsWith(".jsonc")) {
@@ -9209,8 +9466,8 @@ function saveJSONConfig(path3, cfg) {
9209
9466
  }
9210
9467
  function writeSecureFile(path3, content) {
9211
9468
  const dir = dirname2(path3);
9212
- if (!existsSync6(dir)) {
9213
- mkdirSync5(dir, { recursive: true, mode: 448 });
9469
+ if (!existsSync7(dir)) {
9470
+ mkdirSync6(dir, { recursive: true, mode: 448 });
9214
9471
  }
9215
9472
  writeFileAtomic.sync(path3, content, { mode: 384, chown: false });
9216
9473
  }
@@ -9251,21 +9508,21 @@ var init_config_helpers = __esm(() => {
9251
9508
  });
9252
9509
 
9253
9510
  // src/mcp/detect.ts
9254
- import { existsSync as existsSync7 } from "node:fs";
9511
+ import { existsSync as existsSync8 } from "node:fs";
9255
9512
  import { homedir as homedir2, platform as platform2 } from "node:os";
9256
- import { delimiter, dirname as dirname3, join as join7 } from "node:path";
9513
+ import { delimiter, dirname as dirname3, join as join8 } from "node:path";
9257
9514
  function isInstalled(paths) {
9258
- return paths.some((p2) => existsSync7(expandHome(p2)));
9515
+ return paths.some((p2) => existsSync8(expandHome(p2)));
9259
9516
  }
9260
9517
  function expandHome(path3) {
9261
9518
  if (!path3.startsWith("~"))
9262
9519
  return path3;
9263
- return join7(homedir2(), path3.slice(1));
9520
+ return join8(homedir2(), path3.slice(1));
9264
9521
  }
9265
9522
  function appSupportDir() {
9266
9523
  switch (platform2()) {
9267
9524
  case "darwin": {
9268
- return join7(homedir2(), "Library", "Application Support");
9525
+ return join8(homedir2(), "Library", "Application Support");
9269
9526
  }
9270
9527
  case "win32": {
9271
9528
  return process.env.APPDATA ?? "";
@@ -9274,7 +9531,7 @@ function appSupportDir() {
9274
9531
  const xdg = process.env.XDG_CONFIG_HOME;
9275
9532
  if (xdg)
9276
9533
  return xdg;
9277
- return join7(homedir2(), ".config");
9534
+ return join8(homedir2(), ".config");
9278
9535
  }
9279
9536
  }
9280
9537
  }
@@ -9283,8 +9540,8 @@ function findNpx() {
9283
9540
  for (const dir of (process.env.PATH ?? "").split(delimiter)) {
9284
9541
  if (!dir)
9285
9542
  continue;
9286
- const candidate = join7(dir, bin);
9287
- if (existsSync7(candidate))
9543
+ const candidate = join8(dir, bin);
9544
+ if (existsSync8(candidate))
9288
9545
  return candidate;
9289
9546
  }
9290
9547
  throw new Error("npx not found on PATH — Node.js is required (the MCP entry runs `npx mcp-remote`).");
@@ -9369,7 +9626,7 @@ var init_antigravity = __esm(() => {
9369
9626
  });
9370
9627
 
9371
9628
  // src/mcp/providers/claude.ts
9372
- import { join as join8 } from "node:path";
9629
+ import { join as join9 } from "node:path";
9373
9630
  var ClaudeProvider = () => createJSONProvider({
9374
9631
  providerName: "Claude Code",
9375
9632
  providerID: "claude",
@@ -9378,24 +9635,24 @@ var ClaudeProvider = () => createJSONProvider({
9378
9635
  paths: ["~/.claude"],
9379
9636
  globalPath: "~/.claude.json",
9380
9637
  topKey: "mcpServers",
9381
- localConfigPath: (cwd) => join8(cwd, ".mcp.json")
9638
+ localConfigPath: (cwd) => join9(cwd, ".mcp.json")
9382
9639
  });
9383
9640
  var init_claude = __esm(() => {
9384
9641
  init_base();
9385
9642
  });
9386
9643
 
9387
9644
  // src/mcp/providers/claude-desktop.ts
9388
- import { join as join9 } from "node:path";
9645
+ import { join as join10 } from "node:path";
9389
9646
  function configPath() {
9390
- return join9(appSupportDir(), "Claude", "claude_desktop_config.json");
9647
+ return join10(appSupportDir(), "Claude", "claude_desktop_config.json");
9391
9648
  }
9392
9649
  var ClaudeDesktopProvider = () => ({
9393
9650
  name: () => "Claude Desktop",
9394
9651
  id: () => "claude-desktop",
9395
9652
  supportsLocal: () => false,
9396
9653
  priority: () => 2,
9397
- detectPaths: () => [join9(appSupportDir(), "Claude")],
9398
- isInstalled: () => isInstalled([join9(appSupportDir(), "Claude")]),
9654
+ detectPaths: () => [join10(appSupportDir(), "Claude")],
9655
+ isInstalled: () => isInstalled([join10(appSupportDir(), "Claude")]),
9399
9656
  globalConfigPath: () => configPath(),
9400
9657
  isConfigured: () => isJSONKeyConfigured(configPath(), "mcpServers"),
9401
9658
  install(cfg, global) {
@@ -9425,14 +9682,14 @@ var init_claude_desktop = __esm(() => {
9425
9682
  });
9426
9683
 
9427
9684
  // src/mcp/providers/cline.ts
9428
- import { join as join10 } from "node:path";
9429
- var extensionDir = () => join10(appSupportDir(), "Code", "User", "globalStorage", "saoudrizwan.claude-dev"), ClineProvider = () => createJSONProvider({
9685
+ import { join as join11 } from "node:path";
9686
+ var extensionDir = () => join11(appSupportDir(), "Code", "User", "globalStorage", "saoudrizwan.claude-dev"), ClineProvider = () => createJSONProvider({
9430
9687
  providerName: "Cline",
9431
9688
  providerID: "cline",
9432
9689
  local: false,
9433
9690
  priorityValue: 11,
9434
9691
  paths: [extensionDir()],
9435
- globalPath: join10(extensionDir(), "settings", "cline_mcp_settings.json"),
9692
+ globalPath: join11(extensionDir(), "settings", "cline_mcp_settings.json"),
9436
9693
  topKey: "mcpServers",
9437
9694
  buildServer: (cfg) => ({
9438
9695
  url: mcpURL(cfg.active_account.target.deployment_id),
@@ -9448,7 +9705,7 @@ var init_cline = __esm(() => {
9448
9705
  });
9449
9706
 
9450
9707
  // src/mcp/providers/cline-cli.ts
9451
- import { join as join11 } from "node:path";
9708
+ import { join as join12 } from "node:path";
9452
9709
  function clineDir() {
9453
9710
  return process.env.CLINE_DIR ?? expandHome("~/.cline");
9454
9711
  }
@@ -9458,7 +9715,7 @@ var ClineCliProvider = () => createJSONProvider({
9458
9715
  local: false,
9459
9716
  priorityValue: 12,
9460
9717
  paths: [clineDir()],
9461
- globalPath: join11(clineDir(), "data", "settings", "cline_mcp_settings.json"),
9718
+ globalPath: join12(clineDir(), "data", "settings", "cline_mcp_settings.json"),
9462
9719
  topKey: "mcpServers",
9463
9720
  buildServer: (cfg) => ({
9464
9721
  url: mcpURL(cfg.active_account.target.deployment_id),
@@ -9474,20 +9731,20 @@ var init_cline_cli = __esm(() => {
9474
9731
  });
9475
9732
 
9476
9733
  // src/mcp/providers/codex.ts
9477
- import { existsSync as existsSync8, readFileSync as readFileSync8 } from "node:fs";
9478
- import { join as join12 } from "node:path";
9734
+ import { existsSync as existsSync9, readFileSync as readFileSync9 } from "node:fs";
9735
+ import { join as join13 } from "node:path";
9479
9736
  function codexHome() {
9480
9737
  return process.env.CODEX_HOME ?? expandHome("~/.codex");
9481
9738
  }
9482
9739
  function getConfigPath2(global) {
9483
9740
  if (global)
9484
- return join12(codexHome(), "config.toml");
9485
- return join12(process.cwd(), ".codex", "config.toml");
9741
+ return join13(codexHome(), "config.toml");
9742
+ return join13(process.cwd(), ".codex", "config.toml");
9486
9743
  }
9487
9744
  function readTOML(path3) {
9488
- if (!existsSync8(path3))
9745
+ if (!existsSync9(path3))
9489
9746
  return "";
9490
- return readFileSync8(path3, "utf-8");
9747
+ return readFileSync9(path3, "utf-8");
9491
9748
  }
9492
9749
  function writeTOML(path3, content) {
9493
9750
  writeSecureFile(path3, content);
@@ -9550,9 +9807,9 @@ var CodexProvider = () => ({
9550
9807
  priority: () => 8,
9551
9808
  detectPaths: () => ["~/.codex"],
9552
9809
  isInstalled: () => isInstalled(["~/.codex"]),
9553
- globalConfigPath: () => join12(codexHome(), "config.toml"),
9810
+ globalConfigPath: () => join13(codexHome(), "config.toml"),
9554
9811
  isConfigured: () => {
9555
- const content = readTOML(join12(codexHome(), "config.toml"));
9812
+ const content = readTOML(join13(codexHome(), "config.toml"));
9556
9813
  return content.includes("[mcp_servers.dosu]");
9557
9814
  },
9558
9815
  install(cfg, global) {
@@ -9574,10 +9831,10 @@ var init_codex = __esm(() => {
9574
9831
  });
9575
9832
 
9576
9833
  // src/mcp/providers/copilot.ts
9577
- import { join as join13 } from "node:path";
9834
+ import { join as join14 } from "node:path";
9578
9835
  function globalPath() {
9579
9836
  if (process.env.XDG_CONFIG_HOME) {
9580
- return join13(process.env.XDG_CONFIG_HOME, "mcp-config.json");
9837
+ return join14(process.env.XDG_CONFIG_HOME, "mcp-config.json");
9581
9838
  }
9582
9839
  return expandHome("~/.copilot/mcp-config.json");
9583
9840
  }
@@ -9608,7 +9865,7 @@ var CopilotProvider = () => ({
9608
9865
  };
9609
9866
  installJSONServer(globalPath(), "mcpServers", server);
9610
9867
  } else {
9611
- const configPath2 = join13(process.cwd(), ".vscode", "mcp.json");
9868
+ const configPath2 = join14(process.cwd(), ".vscode", "mcp.json");
9612
9869
  const server = {
9613
9870
  type: "http",
9614
9871
  url,
@@ -9621,7 +9878,7 @@ var CopilotProvider = () => ({
9621
9878
  if (global) {
9622
9879
  removeJSONServer(globalPath(), "mcpServers");
9623
9880
  } else {
9624
- const configPath2 = join13(process.cwd(), ".vscode", "mcp.json");
9881
+ const configPath2 = join14(process.cwd(), ".vscode", "mcp.json");
9625
9882
  removeJSONServer(configPath2, "servers");
9626
9883
  }
9627
9884
  }
@@ -9633,7 +9890,7 @@ var init_copilot = __esm(() => {
9633
9890
  });
9634
9891
 
9635
9892
  // src/mcp/providers/cursor.ts
9636
- import { join as join14 } from "node:path";
9893
+ import { join as join15 } from "node:path";
9637
9894
  var CursorProvider = () => createJSONProvider({
9638
9895
  providerName: "Cursor",
9639
9896
  providerID: "cursor",
@@ -9646,7 +9903,7 @@ var CursorProvider = () => createJSONProvider({
9646
9903
  url: mcpURL(cfg.active_account.target.deployment_id),
9647
9904
  headers: mcpHeaders(cfg.active_account.target.api_key)
9648
9905
  }),
9649
- localConfigPath: (cwd) => join14(cwd, ".cursor", "mcp.json")
9906
+ localConfigPath: (cwd) => join15(cwd, ".cursor", "mcp.json")
9650
9907
  });
9651
9908
  var init_cursor = __esm(() => {
9652
9909
  init_config_helpers();
@@ -9654,7 +9911,7 @@ var init_cursor = __esm(() => {
9654
9911
  });
9655
9912
 
9656
9913
  // src/mcp/providers/factory.ts
9657
- import { join as join15 } from "node:path";
9914
+ import { join as join16 } from "node:path";
9658
9915
  var FactoryProvider = () => createJSONProvider({
9659
9916
  providerName: "Factory",
9660
9917
  providerID: "factory",
@@ -9663,14 +9920,14 @@ var FactoryProvider = () => createJSONProvider({
9663
9920
  paths: ["~/.factory"],
9664
9921
  globalPath: "~/.factory/mcp.json",
9665
9922
  topKey: "mcpServers",
9666
- localConfigPath: (cwd) => join15(cwd, ".factory", "mcp.json")
9923
+ localConfigPath: (cwd) => join16(cwd, ".factory", "mcp.json")
9667
9924
  });
9668
9925
  var init_factory = __esm(() => {
9669
9926
  init_base();
9670
9927
  });
9671
9928
 
9672
9929
  // src/mcp/providers/gemini.ts
9673
- import { join as join16 } from "node:path";
9930
+ import { join as join17 } from "node:path";
9674
9931
  var GeminiProvider = () => createJSONProvider({
9675
9932
  providerName: "Gemini CLI",
9676
9933
  providerID: "gemini",
@@ -9679,7 +9936,7 @@ var GeminiProvider = () => createJSONProvider({
9679
9936
  paths: ["~/.gemini"],
9680
9937
  globalPath: "~/.gemini/settings.json",
9681
9938
  topKey: "mcpServers",
9682
- localConfigPath: (cwd) => join16(cwd, ".gemini", "settings.json")
9939
+ localConfigPath: (cwd) => join17(cwd, ".gemini", "settings.json")
9683
9940
  });
9684
9941
  var init_gemini = __esm(() => {
9685
9942
  init_base();
@@ -9729,14 +9986,14 @@ var init_manual = __esm(() => {
9729
9986
  });
9730
9987
 
9731
9988
  // src/mcp/providers/mcporter.ts
9732
- import { existsSync as existsSync9 } from "node:fs";
9733
- import { join as join17 } from "node:path";
9989
+ import { existsSync as existsSync10 } from "node:fs";
9990
+ import { join as join18 } from "node:path";
9734
9991
  function resolveGlobalConfigPath() {
9735
9992
  const jsonPath = expandHome("~/.mcporter/mcporter.json");
9736
- if (existsSync9(jsonPath))
9993
+ if (existsSync10(jsonPath))
9737
9994
  return jsonPath;
9738
9995
  const jsoncPath = expandHome("~/.mcporter/mcporter.jsonc");
9739
- if (existsSync9(jsoncPath))
9996
+ if (existsSync10(jsoncPath))
9740
9997
  return jsoncPath;
9741
9998
  return jsonPath;
9742
9999
  }
@@ -9757,7 +10014,7 @@ var MCPorterProvider = () => ({
9757
10014
  globalConfigPath: () => resolveGlobalConfigPath(),
9758
10015
  isConfigured: () => isJSONKeyConfigured(resolveGlobalConfigPath(), "mcpServers"),
9759
10016
  install(cfg, global) {
9760
- const configPath2 = global ? resolveGlobalConfigPath() : join17(process.cwd(), "config", "mcporter.json");
10017
+ const configPath2 = global ? resolveGlobalConfigPath() : join18(process.cwd(), "config", "mcporter.json");
9761
10018
  const server = {
9762
10019
  type: "http",
9763
10020
  url: mcpEndpoint4(cfg),
@@ -9766,7 +10023,7 @@ var MCPorterProvider = () => ({
9766
10023
  installJSONServer(configPath2, "mcpServers", server);
9767
10024
  },
9768
10025
  remove(global) {
9769
- const configPath2 = global ? resolveGlobalConfigPath() : join17(process.cwd(), "config", "mcporter.json");
10026
+ const configPath2 = global ? resolveGlobalConfigPath() : join18(process.cwd(), "config", "mcporter.json");
9770
10027
  removeJSONServer(configPath2, "mcpServers");
9771
10028
  }
9772
10029
  });
@@ -9777,7 +10034,7 @@ var init_mcporter = __esm(() => {
9777
10034
  });
9778
10035
 
9779
10036
  // src/mcp/providers/opencode.ts
9780
- import { join as join18 } from "node:path";
10037
+ import { join as join19 } from "node:path";
9781
10038
  var OpenCodeProvider = () => createJSONProvider({
9782
10039
  providerName: "OpenCode",
9783
10040
  providerID: "opencode",
@@ -9792,7 +10049,7 @@ var OpenCodeProvider = () => createJSONProvider({
9792
10049
  enabled: true,
9793
10050
  headers: mcpHeaders(cfg.active_account.target.api_key)
9794
10051
  }),
9795
- localConfigPath: (cwd) => join18(cwd, "opencode.json")
10052
+ localConfigPath: (cwd) => join19(cwd, "opencode.json")
9796
10053
  });
9797
10054
  var init_opencode = __esm(() => {
9798
10055
  init_config_helpers();
@@ -9800,16 +10057,16 @@ var init_opencode = __esm(() => {
9800
10057
  });
9801
10058
 
9802
10059
  // src/mcp/providers/vscode.ts
9803
- import { join as join19 } from "node:path";
10060
+ import { join as join20 } from "node:path";
9804
10061
  var VSCodeProvider = () => createJSONProvider({
9805
10062
  providerName: "VS Code",
9806
10063
  providerID: "vscode",
9807
10064
  local: true,
9808
10065
  priorityValue: 6,
9809
- paths: [join19(appSupportDir(), "Code")],
9810
- globalPath: join19(appSupportDir(), "Code", "User", "mcp.json"),
10066
+ paths: [join20(appSupportDir(), "Code")],
10067
+ globalPath: join20(appSupportDir(), "Code", "User", "mcp.json"),
9811
10068
  topKey: "servers",
9812
- localConfigPath: (cwd) => join19(cwd, ".vscode", "mcp.json")
10069
+ localConfigPath: (cwd) => join20(cwd, ".vscode", "mcp.json")
9813
10070
  });
9814
10071
  var init_vscode = __esm(() => {
9815
10072
  init_detect();
@@ -9818,14 +10075,14 @@ var init_vscode = __esm(() => {
9818
10075
 
9819
10076
  // src/mcp/providers/windsurf.ts
9820
10077
  import { homedir as homedir3 } from "node:os";
9821
- import { join as join20 } from "node:path";
10078
+ import { join as join21 } from "node:path";
9822
10079
  var WindsurfProvider = () => createJSONProvider({
9823
10080
  providerName: "Windsurf",
9824
10081
  providerID: "windsurf",
9825
10082
  local: false,
9826
10083
  priorityValue: 9,
9827
- paths: [join20(homedir3(), ".codeium", "windsurf")],
9828
- globalPath: join20(homedir3(), ".codeium", "windsurf", "mcp_config.json"),
10084
+ paths: [join21(homedir3(), ".codeium", "windsurf")],
10085
+ globalPath: join21(homedir3(), ".codeium", "windsurf", "mcp_config.json"),
9829
10086
  topKey: "mcpServers"
9830
10087
  });
9831
10088
  var init_windsurf = __esm(() => {
@@ -9834,12 +10091,12 @@ var init_windsurf = __esm(() => {
9834
10091
 
9835
10092
  // src/mcp/providers/zed.ts
9836
10093
  import { platform as platform3 } from "node:os";
9837
- import { join as join21 } from "node:path";
10094
+ import { join as join22 } from "node:path";
9838
10095
  function zedConfigDir() {
9839
10096
  const os2 = platform3();
9840
10097
  if (os2 === "darwin" || os2 === "win32")
9841
- return join21(appSupportDir(), "Zed");
9842
- return join21(appSupportDir(), "zed");
10098
+ return join22(appSupportDir(), "Zed");
10099
+ return join22(appSupportDir(), "zed");
9843
10100
  }
9844
10101
  var ZedProvider = () => createJSONProvider({
9845
10102
  providerName: "Zed",
@@ -9847,7 +10104,7 @@ var ZedProvider = () => createJSONProvider({
9847
10104
  local: true,
9848
10105
  priorityValue: 10,
9849
10106
  paths: [zedConfigDir()],
9850
- globalPath: join21(zedConfigDir(), "settings.json"),
10107
+ globalPath: join22(zedConfigDir(), "settings.json"),
9851
10108
  topKey: "context_servers",
9852
10109
  buildServer: (cfg) => ({
9853
10110
  source: "custom",
@@ -9855,7 +10112,7 @@ var ZedProvider = () => createJSONProvider({
9855
10112
  url: mcpURL(cfg.active_account.target.deployment_id),
9856
10113
  headers: mcpHeaders(cfg.active_account.target.api_key)
9857
10114
  }),
9858
- localConfigPath: (cwd) => join21(cwd, ".zed", "settings.json")
10115
+ localConfigPath: (cwd) => join22(cwd, ".zed", "settings.json")
9859
10116
  });
9860
10117
  var init_zed = __esm(() => {
9861
10118
  init_config_helpers();
@@ -9914,14 +10171,14 @@ var init_providers = __esm(() => {
9914
10171
  });
9915
10172
 
9916
10173
  // src/rules/installer.ts
9917
- import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync9, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
10174
+ import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync7 } from "node:fs";
9918
10175
  import { homedir as homedir4 } from "node:os";
9919
- import { dirname as dirname4, join as join22 } from "node:path";
10176
+ import { dirname as dirname4, join as join23 } from "node:path";
9920
10177
  function claudeConfigDir() {
9921
- return process.env.CLAUDE_CONFIG_DIR || join22(homedir4(), ".claude");
10178
+ return process.env.CLAUDE_CONFIG_DIR || join23(homedir4(), ".claude");
9922
10179
  }
9923
10180
  function codexHome2() {
9924
- return process.env.CODEX_HOME || join22(homedir4(), ".codex");
10181
+ return process.env.CODEX_HOME || join23(homedir4(), ".codex");
9925
10182
  }
9926
10183
  function isRuleAgent(agent) {
9927
10184
  return Object.hasOwn(RULE_TARGETS, agent);
@@ -9947,17 +10204,17 @@ async function fetchDosuRule(fetchImpl = globalThis.fetch) {
9947
10204
  return normalizeRule(FALLBACK_DOSU_RULE);
9948
10205
  }
9949
10206
  function ensureParent(path3) {
9950
- mkdirSync6(dirname4(path3), { recursive: true });
10207
+ mkdirSync7(dirname4(path3), { recursive: true });
9951
10208
  }
9952
10209
  function writeIfChanged(path3, content) {
9953
- if (!existsSync10(path3)) {
10210
+ if (!existsSync11(path3)) {
9954
10211
  ensureParent(path3);
9955
- writeFileSync6(path3, content, "utf-8");
10212
+ writeFileSync7(path3, content, "utf-8");
9956
10213
  return "created";
9957
10214
  }
9958
- if (readFileSync9(path3, "utf-8") === content)
10215
+ if (readFileSync10(path3, "utf-8") === content)
9959
10216
  return "unchanged";
9960
- writeFileSync6(path3, content, "utf-8");
10217
+ writeFileSync7(path3, content, "utf-8");
9961
10218
  return "updated";
9962
10219
  }
9963
10220
  function findSection(content) {
@@ -9983,14 +10240,14 @@ function buildSection(content, lineEnding = `
9983
10240
  return `${DOSU_RULE_SECTION_START}${lineEnding}${body}${lineEnding}${DOSU_RULE_SECTION_END}`;
9984
10241
  }
9985
10242
  function upsertSection(path3, content) {
9986
- if (!existsSync10(path3)) {
10243
+ if (!existsSync11(path3)) {
9987
10244
  const section2 = buildSection(content);
9988
10245
  ensureParent(path3);
9989
- writeFileSync6(path3, `${section2}
10246
+ writeFileSync7(path3, `${section2}
9990
10247
  `, "utf-8");
9991
10248
  return "created";
9992
10249
  }
9993
- const existing = readFileSync9(path3, "utf-8");
10250
+ const existing = readFileSync10(path3, "utf-8");
9994
10251
  const lineEnding = lineEndingFor(existing);
9995
10252
  const section = buildSection(content, lineEnding);
9996
10253
  const location = findSection(existing);
@@ -10003,7 +10260,7 @@ function upsertSection(path3, content) {
10003
10260
  }
10004
10261
  if (next === existing)
10005
10262
  return "unchanged";
10006
- writeFileSync6(path3, next, "utf-8");
10263
+ writeFileSync7(path3, next, "utf-8");
10007
10264
  return "updated";
10008
10265
  }
10009
10266
  function installRuleForAgent(agent, content) {
@@ -10020,22 +10277,22 @@ function removeRuleForAgent(agent) {
10020
10277
  return null;
10021
10278
  const target = RULE_TARGETS[agent];
10022
10279
  const path3 = target.path();
10023
- if (!existsSync10(path3))
10280
+ if (!existsSync11(path3))
10024
10281
  return { agent, path: path3, action: "not_found" };
10025
10282
  if (target.kind === "file") {
10026
- unlinkSync(path3);
10283
+ unlinkSync2(path3);
10027
10284
  return { agent, path: path3, action: "removed" };
10028
10285
  }
10029
- const existing = readFileSync9(path3, "utf-8");
10286
+ const existing = readFileSync10(path3, "utf-8");
10030
10287
  const lineEnding = lineEndingFor(existing);
10031
10288
  const location = findSection(existing);
10032
10289
  if (!location)
10033
10290
  return { agent, path: path3, action: "not_found" };
10034
10291
  const next = (existing.slice(0, location.start) + existing.slice(location.end + DOSU_RULE_SECTION_END.length)).replace(/(?:\r?\n){3,}/g, `${lineEnding}${lineEnding}`).replace(/^(?:\r?\n)+/, "").trimEnd();
10035
10292
  if (!next) {
10036
- unlinkSync(path3);
10293
+ unlinkSync2(path3);
10037
10294
  } else {
10038
- writeFileSync6(path3, `${next}${lineEnding}`, "utf-8");
10295
+ writeFileSync7(path3, `${next}${lineEnding}`, "utf-8");
10039
10296
  }
10040
10297
  return { agent, path: path3, action: "removed" };
10041
10298
  }
@@ -10063,36 +10320,36 @@ var init_installer = __esm(() => {
10063
10320
  RULE_TARGETS = {
10064
10321
  claude: {
10065
10322
  kind: "file",
10066
- path: () => join22(claudeConfigDir(), "rules", "dosu.md")
10323
+ path: () => join23(claudeConfigDir(), "rules", "dosu.md")
10067
10324
  },
10068
10325
  cursor: {
10069
10326
  kind: "file",
10070
- path: () => join22(homedir4(), ".cursor", "rules", "dosu.mdc"),
10327
+ path: () => join23(homedir4(), ".cursor", "rules", "dosu.mdc"),
10071
10328
  cursorFrontmatter: true
10072
10329
  },
10073
10330
  codex: {
10074
10331
  kind: "section",
10075
- path: () => join22(codexHome2(), "AGENTS.md")
10332
+ path: () => join23(codexHome2(), "AGENTS.md")
10076
10333
  },
10077
10334
  opencode: {
10078
10335
  kind: "section",
10079
- path: () => join22(homedir4(), ".config", "opencode", "AGENTS.md")
10336
+ path: () => join23(homedir4(), ".config", "opencode", "AGENTS.md")
10080
10337
  },
10081
10338
  gemini: {
10082
10339
  kind: "section",
10083
- path: () => join22(homedir4(), ".gemini", "GEMINI.md")
10340
+ path: () => join23(homedir4(), ".gemini", "GEMINI.md")
10084
10341
  },
10085
10342
  antigravity: {
10086
10343
  kind: "section",
10087
- path: () => join22(homedir4(), ".gemini", "GEMINI.md")
10344
+ path: () => join23(homedir4(), ".gemini", "GEMINI.md")
10088
10345
  }
10089
10346
  };
10090
10347
  });
10091
10348
 
10092
10349
  // src/setup/agents-md-step.ts
10093
10350
  import { execSync as execSync3 } from "node:child_process";
10094
- import { existsSync as existsSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
10095
- import { join as join23 } from "node:path";
10351
+ import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "node:fs";
10352
+ import { join as join24 } from "node:path";
10096
10353
  function inGitWorkTree(cwd = process.cwd()) {
10097
10354
  try {
10098
10355
  const stdout2 = execSync3("git rev-parse --is-inside-work-tree", {
@@ -10130,14 +10387,14 @@ function findSection2(content) {
10130
10387
  return { start, end };
10131
10388
  }
10132
10389
  function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RULE) {
10133
- const path3 = join23(cwd, "AGENTS.md");
10134
- if (!existsSync11(path3)) {
10390
+ const path3 = join24(cwd, "AGENTS.md");
10391
+ if (!existsSync12(path3)) {
10135
10392
  const section2 = buildDosuAgentsSection(content);
10136
- writeFileSync7(path3, `${section2}
10393
+ writeFileSync8(path3, `${section2}
10137
10394
  `);
10138
10395
  return { path: path3, action: "created" };
10139
10396
  }
10140
- const existing = readFileSync10(path3, "utf-8");
10397
+ const existing = readFileSync11(path3, "utf-8");
10141
10398
  const lineEnding = lineEndingFor2(existing);
10142
10399
  const section = renderDosuAgentsSection(content, lineEnding);
10143
10400
  const location = findSection2(existing);
@@ -10149,7 +10406,7 @@ function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RU
10149
10406
  }
10150
10407
  if (next === existing)
10151
10408
  return { path: path3, action: "unchanged" };
10152
- writeFileSync7(path3, next);
10409
+ writeFileSync8(path3, next);
10153
10410
  return { path: path3, action: "updated" };
10154
10411
  }
10155
10412
  async function stepUpdateAgentsMd(cwd = process.cwd(), content) {
@@ -10178,19 +10435,19 @@ var init_agents_md_step = __esm(() => {
10178
10435
  });
10179
10436
 
10180
10437
  // src/telemetry/settings.ts
10181
- import { randomUUID } from "node:crypto";
10438
+ import { randomUUID as randomUUID2 } from "node:crypto";
10182
10439
  import {
10183
- existsSync as existsSync12,
10440
+ existsSync as existsSync13,
10184
10441
  lstatSync,
10185
- mkdirSync as mkdirSync7,
10186
- readFileSync as readFileSync11,
10442
+ mkdirSync as mkdirSync8,
10443
+ readFileSync as readFileSync12,
10187
10444
  renameSync as renameSync2,
10188
- unlinkSync as unlinkSync2,
10189
- writeFileSync as writeFileSync8
10445
+ unlinkSync as unlinkSync3,
10446
+ writeFileSync as writeFileSync9
10190
10447
  } from "node:fs";
10191
- import { join as join24 } from "node:path";
10448
+ import { join as join25 } from "node:path";
10192
10449
  function getTelemetrySettingsPath() {
10193
- return join24(getConfigDir(), TELEMETRY_SETTINGS_FILENAME);
10450
+ return join25(getConfigDir(), TELEMETRY_SETTINGS_FILENAME);
10194
10451
  }
10195
10452
  function loadTelemetrySettings() {
10196
10453
  return readTelemetrySettings().settings;
@@ -10228,7 +10485,7 @@ function getOrCreateInstallID() {
10228
10485
  }
10229
10486
  if (current.status !== "current" && current.status !== "missing")
10230
10487
  return;
10231
- const installID = randomUUID();
10488
+ const installID = randomUUID2();
10232
10489
  const settings2 = current.status === "current" ? current.settings : emptyTelemetrySettings();
10233
10490
  settings2.install_id = installID;
10234
10491
  return writeTelemetrySettings(settings2) ? installID : undefined;
@@ -10238,7 +10495,7 @@ function resetInstallID() {
10238
10495
  if (current.status !== "current" && current.status !== "missing")
10239
10496
  return;
10240
10497
  const settings2 = current.status === "current" ? current.settings : emptyTelemetrySettings();
10241
- const installID = randomUUID();
10498
+ const installID = randomUUID2();
10242
10499
  settings2.install_id = installID;
10243
10500
  return writeTelemetrySettings(settings2) ? installID : undefined;
10244
10501
  }
@@ -10258,7 +10515,7 @@ function readTelemetrySettings() {
10258
10515
  }
10259
10516
  let content;
10260
10517
  try {
10261
- content = readFileSync11(path3, "utf-8");
10518
+ content = readFileSync12(path3, "utf-8");
10262
10519
  } catch {
10263
10520
  return { status: "error", settings: disabledTelemetrySettings() };
10264
10521
  }
@@ -10268,7 +10525,7 @@ function readTelemetrySettings() {
10268
10525
  } catch {
10269
10526
  return { status: "invalid", settings: disabledTelemetrySettings() };
10270
10527
  }
10271
- if (!isRecord3(raw))
10528
+ if (!isRecord5(raw))
10272
10529
  return { status: "invalid", settings: disabledTelemetrySettings() };
10273
10530
  if (raw.schema_version !== TELEMETRY_SCHEMA_VERSION) {
10274
10531
  const status = "schema_version" in raw ? "unsupported" : "invalid";
@@ -10288,11 +10545,11 @@ function readTelemetrySettings() {
10288
10545
  function writeTelemetrySettings(settings2) {
10289
10546
  const path3 = getTelemetrySettingsPath();
10290
10547
  const dir = getConfigDir();
10291
- const temporaryPath = `${path3}.${process.pid}.${randomUUID()}.tmp`;
10548
+ const temporaryPath = `${path3}.${process.pid}.${randomUUID2()}.tmp`;
10292
10549
  try {
10293
- if (!existsSync12(dir))
10294
- mkdirSync7(dir, { recursive: true, mode: 448 });
10295
- writeFileSync8(temporaryPath, `${JSON.stringify(settings2, null, 2)}
10550
+ if (!existsSync13(dir))
10551
+ mkdirSync8(dir, { recursive: true, mode: 448 });
10552
+ writeFileSync9(temporaryPath, `${JSON.stringify(settings2, null, 2)}
10296
10553
  `, {
10297
10554
  flag: "wx",
10298
10555
  mode: 384
@@ -10301,7 +10558,7 @@ function writeTelemetrySettings(settings2) {
10301
10558
  return true;
10302
10559
  } catch {
10303
10560
  try {
10304
- unlinkSync2(temporaryPath);
10561
+ unlinkSync3(temporaryPath);
10305
10562
  } catch {}
10306
10563
  return false;
10307
10564
  }
@@ -10323,7 +10580,7 @@ function isEnabledEnvironmentFlag(value) {
10323
10580
  function isUUID(value) {
10324
10581
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
10325
10582
  }
10326
- function isRecord3(value) {
10583
+ function isRecord5(value) {
10327
10584
  return typeof value === "object" && value !== null && !Array.isArray(value);
10328
10585
  }
10329
10586
  function isErrorCode(error, code) {
@@ -10336,11 +10593,11 @@ var init_settings = __esm(() => {
10336
10593
  });
10337
10594
 
10338
10595
  // src/telemetry/debug-id.ts
10339
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "3772d842-939e-9b04-6475-6e2164756e21";
10596
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "636daf7a-af53-b408-6475-6e2164756e21";
10340
10597
 
10341
10598
  // src/telemetry/telemetry.ts
10342
- import { randomUUID as randomUUID2 } from "node:crypto";
10343
- import { existsSync as existsSync13 } from "node:fs";
10599
+ import { randomUUID as randomUUID3 } from "node:crypto";
10600
+ import { existsSync as existsSync14 } from "node:fs";
10344
10601
  import { request as httpRequest2 } from "node:http";
10345
10602
  import { request as httpsRequest } from "node:https";
10346
10603
  import { isAbsolute, relative, resolve, sep } from "node:path";
@@ -10479,7 +10736,7 @@ function parseOwnedStackLine(originalLine, packageRoot) {
10479
10736
  return;
10480
10737
  }
10481
10738
  try {
10482
- if (!existsSync13(resolvedPath))
10739
+ if (!existsSync14(resolvedPath))
10483
10740
  return;
10484
10741
  } catch {
10485
10742
  return;
@@ -10487,15 +10744,16 @@ function parseOwnedStackLine(originalLine, packageRoot) {
10487
10744
  return { filename, lineno: Number(match[2]), colno: Number(match[3]) };
10488
10745
  }
10489
10746
  function sanitizeError(error) {
10490
- const data = safeRead(error, "data");
10491
- const typeCandidate = safeRead(error, "name");
10492
- const codeCandidates = [safeRead(data, "code"), safeRead(error, "code")];
10747
+ const normalizedError = domainErrorFromCauseChain(error) ?? error;
10748
+ const data = safeRead(normalizedError, "data");
10749
+ const typeCandidate = safeRead(normalizedError, "name");
10750
+ const codeCandidates = [safeRead(data, "code"), safeRead(normalizedError, "code")];
10493
10751
  const statusCandidates = [
10494
10752
  safeRead(data, "httpStatus"),
10495
- safeRead(error, "status"),
10496
- safeRead(error, "statusCode")
10753
+ safeRead(normalizedError, "status"),
10754
+ safeRead(normalizedError, "statusCode")
10497
10755
  ];
10498
- const exitCodeCandidate = safeRead(error, "exitCode");
10756
+ const exitCodeCandidate = safeRead(normalizedError, "exitCode");
10499
10757
  const code = codeCandidates.find(validErrorCode);
10500
10758
  const status = statusCandidates.find(validStatus);
10501
10759
  const exitCode = typeof exitCodeCandidate === "number" && Number.isFinite(exitCodeCandidate) ? normalizeExitCode(exitCodeCandidate) : undefined;
@@ -10503,10 +10761,25 @@ function sanitizeError(error) {
10503
10761
  type: validErrorType(typeCandidate) ? typeCandidate : "Error",
10504
10762
  ...code ? { code } : {},
10505
10763
  ...status ? { status } : {},
10506
- frames: parseStack(safeRead(error, "stack")),
10764
+ frames: parseStack(safeRead(normalizedError, "stack")),
10507
10765
  ...exitCode === undefined ? {} : { exitCode }
10508
10766
  };
10509
10767
  }
10768
+ function domainErrorFromCauseChain(error) {
10769
+ const seen = new Set;
10770
+ let current = error;
10771
+ for (let depth = 0;depth < 5 && objectLike(current); depth += 1) {
10772
+ if (seen.has(current))
10773
+ return;
10774
+ seen.add(current);
10775
+ const code = safeRead(current, "code");
10776
+ if (code === "SESSION_EXPIRED" || code === "SESSION_PERSISTENCE_ERROR" || code === "SESSION_REFRESH_ERROR") {
10777
+ return current;
10778
+ }
10779
+ current = safeRead(current, "cause");
10780
+ }
10781
+ return;
10782
+ }
10510
10783
  function durationBucket(durationMs) {
10511
10784
  const duration = Number.isFinite(durationMs) ? Math.max(0, durationMs) : 0;
10512
10785
  if (duration < 100)
@@ -10867,7 +11140,7 @@ function createCommandTelemetry(settings2, dependencies = {}) {
10867
11140
  const env = dependencies.env ?? process.env;
10868
11141
  const fetcher = dependencies.fetch;
10869
11142
  const now = dependencies.now ?? Date.now;
10870
- const generateUuid = dependencies.randomUUID ?? randomUUID2;
11143
+ const generateUuid = dependencies.randomUUID ?? randomUUID3;
10871
11144
  const writeStderr = dependencies.stderr ?? ((payload) => process.stderr.write(`${payload}
10872
11145
  `));
10873
11146
  const webAppURL = dependencies.webAppURL ?? getWebAppURL;
@@ -10935,7 +11208,7 @@ function createCommandTelemetry(settings2, dependencies = {}) {
10935
11208
  }
10936
11209
  }
10937
11210
  }
10938
- if (!disabled && result === "failure" && error && sentryDsn) {
11211
+ if (!disabled && result === "failure" && error && shouldSendToSentry(error) && sentryDsn) {
10939
11212
  const id = eventId(generateUuid);
10940
11213
  const envelope = id ? buildSentryEnvelope({
10941
11214
  dsn: sentryDsn,
@@ -10991,6 +11264,9 @@ function createCommandTelemetry(settings2, dependencies = {}) {
10991
11264
  }
10992
11265
  };
10993
11266
  }
11267
+ function shouldSendToSentry(error) {
11268
+ return !["SESSION_EXPIRED", "SESSION_PERSISTENCE_ERROR"].includes(error.code ?? "");
11269
+ }
10994
11270
  var REQUEST_TIMEOUT_MS = 500, MAX_RESPONSE_BYTES, MAX_STACK_FRAMES = 20, UNKNOWN_COMMAND = "unknown", FALLBACK_INSTALL_ID = "00000000-0000-4000-8000-000000000000", BUNDLE_CODE_FILE = "app:///bin/dosu.js", CLI_PACKAGE_ROOT, SAFE_ERROR_TYPES, SAFE_ERROR_CODES;
10995
11271
  var init_telemetry = __esm(() => {
10996
11272
  MAX_RESPONSE_BYTES = 1024 * 1024;
@@ -11006,6 +11282,8 @@ var init_telemetry = __esm(() => {
11006
11282
  "RangeError",
11007
11283
  "ReferenceError",
11008
11284
  "SessionExpiredError",
11285
+ "SessionPersistenceError",
11286
+ "SessionRefreshError",
11009
11287
  "SyntaxError",
11010
11288
  "TRPCClientError",
11011
11289
  "TypeError"
@@ -11052,6 +11330,9 @@ var init_telemetry = __esm(() => {
11052
11330
  "PAYMENT_REQUIRED",
11053
11331
  "PRECONDITION_FAILED",
11054
11332
  "SERVICE_UNAVAILABLE",
11333
+ "SESSION_EXPIRED",
11334
+ "SESSION_PERSISTENCE_ERROR",
11335
+ "SESSION_REFRESH_ERROR",
11055
11336
  "TIMEOUT",
11056
11337
  "TOO_MANY_REQUESTS",
11057
11338
  "UNAUTHORIZED",
@@ -11363,11 +11644,11 @@ var init_agent_kickoff = __esm(() => {
11363
11644
  });
11364
11645
 
11365
11646
  // src/setup/logs-handoff.ts
11366
- import { existsSync as existsSync14, readdirSync, statSync as statSync2 } from "node:fs";
11647
+ import { existsSync as existsSync15, readdirSync, statSync as statSync3 } from "node:fs";
11367
11648
  import { homedir as homedir5 } from "node:os";
11368
- import { join as join25 } from "node:path";
11649
+ import { join as join26 } from "node:path";
11369
11650
  function countJsonlFiles(root, cap = COUNT_CAP) {
11370
- if (!existsSync14(root))
11651
+ if (!existsSync15(root))
11371
11652
  return { count: 0, capped: false };
11372
11653
  let count = 0;
11373
11654
  const stack = [root];
@@ -11382,7 +11663,7 @@ function countJsonlFiles(root, cap = COUNT_CAP) {
11382
11663
  continue;
11383
11664
  }
11384
11665
  for (const entry of entries) {
11385
- const path3 = join25(dir, entry.name);
11666
+ const path3 = join26(dir, entry.name);
11386
11667
  if (entry.isDirectory()) {
11387
11668
  stack.push(path3);
11388
11669
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
@@ -11396,23 +11677,23 @@ function countJsonlFiles(root, cap = COUNT_CAP) {
11396
11677
  }
11397
11678
  function detectLogSources(home = process.env.HOME || homedir5()) {
11398
11679
  const roots = {
11399
- cursor: join25(home, ".cursor", "projects"),
11400
- claude: join25(home, ".claude", "projects"),
11401
- codex: join25(home, ".codex", "sessions")
11680
+ cursor: join26(home, ".cursor", "projects"),
11681
+ claude: join26(home, ".claude", "projects"),
11682
+ codex: join26(home, ".codex", "sessions")
11402
11683
  };
11403
11684
  const hits = [];
11404
11685
  for (const source of LOG_SOURCES) {
11405
11686
  const root = roots[source];
11406
11687
  if (source === "cursor") {
11407
- if (!existsSync14(root))
11688
+ if (!existsSync15(root))
11408
11689
  continue;
11409
11690
  let count = 0;
11410
11691
  let capped = false;
11411
11692
  try {
11412
11693
  for (const proj of readdirSync(root)) {
11413
- const transcripts = join25(root, proj, "agent-transcripts");
11694
+ const transcripts = join26(root, proj, "agent-transcripts");
11414
11695
  try {
11415
- if (!statSync2(transcripts).isDirectory())
11696
+ if (!statSync3(transcripts).isDirectory())
11416
11697
  continue;
11417
11698
  } catch {
11418
11699
  continue;
@@ -11941,7 +12222,7 @@ async function startOAuthFlow(signal, path3 = "/cli/auth", params = {}, onAuthUR
11941
12222
  logger.debug("auth.flow", "Browser unavailable — returning to caller for fallback");
11942
12223
  return { browserOpened: false };
11943
12224
  }
11944
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
12225
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
11945
12226
  const timeoutMinutes = Math.round(timeoutMs / 60000);
11946
12227
  const timeout = new Promise((_2, reject) => {
11947
12228
  timeoutId = setTimeout(() => {
@@ -11969,11 +12250,11 @@ function buildAuthURL(callbackURL, path3, extraParams) {
11969
12250
  const params = new URLSearchParams({ callback: callbackURL, ...extraParams });
11970
12251
  return `${webAppURL}${path3}?${params}`;
11971
12252
  }
11972
- var DEFAULT_TIMEOUT_MS;
12253
+ var DEFAULT_TIMEOUT_MS2;
11973
12254
  var init_flow = __esm(() => {
11974
12255
  init_logger();
11975
12256
  init_server();
11976
- DEFAULT_TIMEOUT_MS = 8 * 60 * 1000;
12257
+ DEFAULT_TIMEOUT_MS2 = 8 * 60 * 1000;
11977
12258
  });
11978
12259
 
11979
12260
  // src/setup/flow.ts
@@ -11986,12 +12267,12 @@ __export(exports_flow2, {
11986
12267
  runInstallSkill: () => runInstallSkill,
11987
12268
  cliAuthFailureReason: () => cliAuthFailureReason
11988
12269
  });
11989
- import { randomUUID as randomUUID3 } from "node:crypto";
12270
+ import { randomUUID as randomUUID4 } from "node:crypto";
11990
12271
  function trackInBackground(tracking) {
11991
12272
  tracking.catch(() => {});
11992
12273
  }
11993
12274
  async function runSetup(opts = {}) {
11994
- const onboardingRunID = randomUUID3();
12275
+ const onboardingRunID = randomUUID4();
11995
12276
  logger.info("setup", `Setup flow started${opts.deploymentID ? ` deployment=${opts.deploymentID}` : ""}${opts.mode ? ` mode=${opts.mode}` : ""}`);
11996
12277
  intro("Dosu CLI Setup");
11997
12278
  trackInBackground(trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_launch_attempted", {
@@ -12611,8 +12892,8 @@ var init_flow2 = __esm(() => {
12611
12892
  });
12612
12893
 
12613
12894
  // src/commands/insights.ts
12614
- import { existsSync as existsSync15, mkdirSync as mkdirSync8, readdirSync as readdirSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "node:fs";
12615
- import { dirname as dirname5, join as join26 } from "node:path";
12895
+ import { existsSync as existsSync16, mkdirSync as mkdirSync9, readdirSync as readdirSync2, unlinkSync as unlinkSync4, writeFileSync as writeFileSync10 } from "node:fs";
12896
+ import { dirname as dirname5, join as join27 } from "node:path";
12616
12897
  function shuffled(arr) {
12617
12898
  const copy2 = [...arr];
12618
12899
  for (let i2 = copy2.length - 1;i2 > 0; i2--) {
@@ -12716,17 +12997,17 @@ function makeAskFn(cfg) {
12716
12997
  };
12717
12998
  }
12718
12999
  function insightsDir() {
12719
- return join26(getConfigDir(), "insights");
13000
+ return join27(getConfigDir(), "insights");
12720
13001
  }
12721
13002
  function reportPath(timestamp) {
12722
13003
  const dir = insightsDir();
12723
13004
  if (!timestamp)
12724
- return join26(dir, "latest.html");
13005
+ return join27(dir, "latest.html");
12725
13006
  const iso = timestamp.toISOString().slice(0, 19).replace(/:/g, "-");
12726
- return join26(dir, `report-${iso}Z.html`);
13007
+ return join27(dir, `report-${iso}Z.html`);
12727
13008
  }
12728
13009
  function pruneOldReports(dir, keepN) {
12729
- if (!existsSync15(dir))
13010
+ if (!existsSync16(dir))
12730
13011
  return;
12731
13012
  let entries;
12732
13013
  try {
@@ -12738,7 +13019,7 @@ function pruneOldReports(dir, keepN) {
12738
13019
  const reports = entries.filter((f2) => REPORT_FILE_PATTERN.test(f2)).sort().reverse();
12739
13020
  for (const f2 of reports.slice(keepN)) {
12740
13021
  try {
12741
- unlinkSync3(join26(dir, f2));
13022
+ unlinkSync4(join27(dir, f2));
12742
13023
  } catch (err) {
12743
13024
  logger.debug("insights", `failed to prune ${f2}: ${err instanceof Error ? err.message : err}`);
12744
13025
  }
@@ -12811,9 +13092,9 @@ function defaultRunner(cfg) {
12811
13092
  render: renderHTML,
12812
13093
  writeFile: (path3, content) => {
12813
13094
  const dir = dirname5(path3);
12814
- if (!existsSync15(dir))
12815
- mkdirSync8(dir, { recursive: true, mode: 448 });
12816
- writeFileSync9(path3, content, { mode: 384 });
13095
+ if (!existsSync16(dir))
13096
+ mkdirSync9(dir, { recursive: true, mode: 448 });
13097
+ writeFileSync10(path3, content, { mode: 384 });
12817
13098
  },
12818
13099
  prune: pruneOldReports,
12819
13100
  openInBrowser: async (path3) => {
@@ -13644,13 +13925,13 @@ var init_flow3 = __esm(() => {
13644
13925
  init_commander();
13645
13926
  init_client();
13646
13927
  import {
13647
- closeSync,
13928
+ closeSync as closeSync2,
13648
13929
  constants,
13649
13930
  fstatSync,
13650
- openSync,
13651
- readFileSync as readFileSync14,
13931
+ openSync as openSync2,
13932
+ readFileSync as readFileSync15,
13652
13933
  readSync,
13653
- unlinkSync as unlinkSync4
13934
+ unlinkSync as unlinkSync5
13654
13935
  } from "node:fs";
13655
13936
 
13656
13937
  // src/commands/analytics.ts
@@ -13874,8 +14155,8 @@ init_commander();
13874
14155
  init_trpc();
13875
14156
  init_logger();
13876
14157
  var import_picocolors9 = __toESM(require_picocolors(), 1);
13877
- import { existsSync as existsSync4, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync4 } from "node:fs";
13878
- import { dirname, join as join4 } from "node:path";
14158
+ import { existsSync as existsSync5, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync5 } from "node:fs";
14159
+ import { dirname, join as join5 } from "node:path";
13879
14160
 
13880
14161
  // src/setup/github-step.ts
13881
14162
  init_dist8();
@@ -14743,20 +15024,20 @@ ${dim(`deployment ${deployment_id}`)}`);
14743
15024
  init_config();
14744
15025
  init_logger();
14745
15026
  var import_picocolors8 = __toESM(require_picocolors(), 1);
14746
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
14747
- import { join as join3 } from "node:path";
15027
+ import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
15028
+ import { join as join4 } from "node:path";
14748
15029
  var CACHE_FILENAME = "pending-tasks.json";
14749
15030
  var CHECK_INTERVAL_MS = 60000;
14750
15031
  var FETCH_TIMEOUT_MS = 5000;
14751
15032
  function getCachePath() {
14752
- return join3(getConfigDir(), CACHE_FILENAME);
15033
+ return join4(getConfigDir(), CACHE_FILENAME);
14753
15034
  }
14754
15035
  function readPendingTasks() {
14755
15036
  try {
14756
15037
  const path3 = getCachePath();
14757
- if (!existsSync3(path3))
15038
+ if (!existsSync4(path3))
14758
15039
  return { tasks: [] };
14759
- const data = JSON.parse(readFileSync3(path3, "utf-8"));
15040
+ const data = JSON.parse(readFileSync4(path3, "utf-8"));
14760
15041
  if (Array.isArray(data?.tasks)) {
14761
15042
  return { tasks: data.tasks };
14762
15043
  }
@@ -14768,10 +15049,10 @@ function readPendingTasks() {
14768
15049
  function writePendingTasks(cache) {
14769
15050
  try {
14770
15051
  const dir = getConfigDir();
14771
- if (!existsSync3(dir)) {
14772
- mkdirSync3(dir, { recursive: true, mode: 448 });
15052
+ if (!existsSync4(dir)) {
15053
+ mkdirSync4(dir, { recursive: true, mode: 448 });
14773
15054
  }
14774
- writeFileSync3(getCachePath(), JSON.stringify(cache), { mode: 384 });
15055
+ writeFileSync4(getCachePath(), JSON.stringify(cache), { mode: 384 });
14775
15056
  } catch {}
14776
15057
  }
14777
15058
  function addPendingTask(task) {
@@ -15010,12 +15291,12 @@ function loadFindings(findingsPath) {
15010
15291
  console.error(import_picocolors9.default.red("Run the Dosu audit in your coding agent first (it writes .dosu/audit.json)."));
15011
15292
  process.exit(1);
15012
15293
  };
15013
- if (!existsSync4(findingsPath)) {
15294
+ if (!existsSync5(findingsPath)) {
15014
15295
  fail();
15015
15296
  }
15016
15297
  let parsed;
15017
15298
  try {
15018
- parsed = JSON.parse(readFileSync4(findingsPath, "utf-8"));
15299
+ parsed = JSON.parse(readFileSync5(findingsPath, "utf-8"));
15019
15300
  } catch {
15020
15301
  fail();
15021
15302
  }
@@ -15025,21 +15306,21 @@ function loadFindings(findingsPath) {
15025
15306
  return parsed;
15026
15307
  }
15027
15308
  function cleanupFindings(findingsPath, cwd = process.cwd()) {
15028
- const gitignorePath = join4(cwd, ".gitignore");
15309
+ const gitignorePath = join5(cwd, ".gitignore");
15029
15310
  try {
15030
- const content = existsSync4(gitignorePath) ? readFileSync4(gitignorePath, "utf-8") : "";
15311
+ const content = existsSync5(gitignorePath) ? readFileSync5(gitignorePath, "utf-8") : "";
15031
15312
  const hasEntry = content.split(/\r?\n/).some((line) => /^\.dosu\/?$/.test(line.trim()));
15032
15313
  if (!hasEntry) {
15033
15314
  const sep = content === "" || content.endsWith(`
15034
15315
  `) ? "" : `
15035
15316
  `;
15036
- writeFileSync4(gitignorePath, `${content}${sep}.dosu/
15317
+ writeFileSync5(gitignorePath, `${content}${sep}.dosu/
15037
15318
  `);
15038
15319
  }
15039
15320
  } catch (err) {
15040
15321
  logger.warn("audit", `could not update .gitignore: ${errText(err)}`);
15041
15322
  }
15042
- const defaultDir = join4(cwd, ".dosu");
15323
+ const defaultDir = join5(cwd, ".dosu");
15043
15324
  if (dirname(findingsPath) !== defaultDir)
15044
15325
  return;
15045
15326
  try {
@@ -15082,7 +15363,7 @@ function auditCommand() {
15082
15363
  const nonInteractive = Boolean(opts.tasks);
15083
15364
  const client = createTypedClient(cfg);
15084
15365
  const dataSourceId = await ensureSyncedRepo(cfg, client, detected, opts.dataSourceId, nonInteractive);
15085
- const findingsPath = opts.findings ?? join4(process.cwd(), ".dosu", "audit.json");
15366
+ const findingsPath = opts.findings ?? join5(process.cwd(), ".dosu", "audit.json");
15086
15367
  const findings = loadFindings(findingsPath);
15087
15368
  if (!opts.dataSourceId && findings.repo?.slug && findings.repo.slug !== detected.slug) {
15088
15369
  console.error(import_picocolors9.default.red(`Audit was run on ${findings.repo.slug}, but the current repo is ${detected.slug}. ` + `Run 'dosu audit' from ${findings.repo.slug} so the PR targets the audited repo.`));
@@ -15257,7 +15538,7 @@ init_commander();
15257
15538
  init_trpc();
15258
15539
  init_logger();
15259
15540
  var import_picocolors11 = __toESM(require_picocolors(), 1);
15260
- import { readFileSync as readFileSync5 } from "node:fs";
15541
+ import { readFileSync as readFileSync6 } from "node:fs";
15261
15542
  function requireConfig5() {
15262
15543
  const cfg = requireLoginConfig();
15263
15544
  if (!cfg.active_account?.target?.space_id) {
@@ -15278,7 +15559,7 @@ async function getKnowledgeStoreId(client, spaceId) {
15278
15559
  }
15279
15560
  function readBody(opts) {
15280
15561
  if (opts.bodyFile)
15281
- return readFileSync5(opts.bodyFile, "utf-8");
15562
+ return readFileSync6(opts.bodyFile, "utf-8");
15282
15563
  return opts.body;
15283
15564
  }
15284
15565
  var IMPORT_ALREADY_IN_PROGRESS_CODE = "IMPORT_ALREADY_IN_PROGRESS";
@@ -16012,7 +16293,7 @@ init_dist();
16012
16293
  init_commander();
16013
16294
  init_trpc();
16014
16295
  var import_picocolors19 = __toESM(require_picocolors(), 1);
16015
- import { readFileSync as readFileSync12 } from "node:fs";
16296
+ import { readFileSync as readFileSync13 } from "node:fs";
16016
16297
  function requireConfig10() {
16017
16298
  return requireLoginConfig();
16018
16299
  }
@@ -16188,7 +16469,7 @@ function reviewCommand() {
16188
16469
  let body = opts.body;
16189
16470
  if (opts.bodyFile) {
16190
16471
  try {
16191
- body = readFileSync12(opts.bodyFile, "utf-8");
16472
+ body = readFileSync13(opts.bodyFile, "utf-8");
16192
16473
  } catch (err) {
16193
16474
  console.error(import_picocolors19.default.red(`Failed to read --body-file: ${err.message}`));
16194
16475
  process.exit(1);
@@ -16977,8 +17258,8 @@ init_skill_update_check();
16977
17258
  init_config();
16978
17259
  init_logger();
16979
17260
  var import_picocolors25 = __toESM(require_picocolors(), 1);
16980
- import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "node:fs";
16981
- import { join as join27 } from "node:path";
17261
+ import { existsSync as existsSync17, mkdirSync as mkdirSync10, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "node:fs";
17262
+ import { join as join28 } from "node:path";
16982
17263
  var CACHE_FILENAME3 = "update-check.json";
16983
17264
  var CHECK_INTERVAL_MS3 = 6 * 60 * 60 * 1000;
16984
17265
  var FETCH_TIMEOUT_MS3 = 1000;
@@ -17005,14 +17286,14 @@ function isNewerVersion(latest, current) {
17005
17286
  return false;
17006
17287
  }
17007
17288
  function getCachePath3() {
17008
- return join27(getConfigDir(), CACHE_FILENAME3);
17289
+ return join28(getConfigDir(), CACHE_FILENAME3);
17009
17290
  }
17010
17291
  function readCache() {
17011
17292
  try {
17012
17293
  const path3 = getCachePath3();
17013
- if (!existsSync16(path3))
17294
+ if (!existsSync17(path3))
17014
17295
  return null;
17015
- const data = JSON.parse(readFileSync13(path3, "utf-8"));
17296
+ const data = JSON.parse(readFileSync14(path3, "utf-8"));
17016
17297
  if (typeof data.lastCheck === "number" && isValidVersion(data.latestVersion)) {
17017
17298
  return data;
17018
17299
  }
@@ -17024,10 +17305,10 @@ function readCache() {
17024
17305
  function writeCache(cache) {
17025
17306
  try {
17026
17307
  const dir = getConfigDir();
17027
- if (!existsSync16(dir)) {
17028
- mkdirSync9(dir, { recursive: true, mode: 448 });
17308
+ if (!existsSync17(dir)) {
17309
+ mkdirSync10(dir, { recursive: true, mode: 448 });
17029
17310
  }
17030
- writeFileSync10(getCachePath3(), JSON.stringify(cache), { mode: 384 });
17311
+ writeFileSync11(getCachePath3(), JSON.stringify(cache), { mode: 384 });
17031
17312
  } catch {}
17032
17313
  }
17033
17314
  async function fetchLatestVersion() {
@@ -17162,7 +17443,7 @@ function loadConfigForTelemetry() {
17162
17443
  let fd;
17163
17444
  try {
17164
17445
  const nonblocking = typeof constants.O_NONBLOCK === "number" ? constants.O_NONBLOCK : 0;
17165
- fd = openSync(getConfigPath(), constants.O_RDONLY | nonblocking);
17446
+ fd = openSync2(getConfigPath(), constants.O_RDONLY | nonblocking);
17166
17447
  const file = fstatSync(fd);
17167
17448
  if (!file.isFile() || file.size > MAX_TELEMETRY_CONFIG_BYTES)
17168
17449
  return;
@@ -17176,7 +17457,7 @@ function loadConfigForTelemetry() {
17176
17457
  } finally {
17177
17458
  if (fd !== undefined) {
17178
17459
  try {
17179
- closeSync(fd);
17460
+ closeSync2(fd);
17180
17461
  } catch {}
17181
17462
  }
17182
17463
  }
@@ -17541,7 +17822,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
17541
17822
  const logPath = logger.getLogPath();
17542
17823
  if (opts.clear) {
17543
17824
  try {
17544
- unlinkSync4(logPath);
17825
+ unlinkSync5(logPath);
17545
17826
  console.log("Log file deleted.");
17546
17827
  } catch {
17547
17828
  console.log("No log file to delete.");
@@ -17551,7 +17832,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
17551
17832
  if (opts.tail !== undefined) {
17552
17833
  const n2 = typeof opts.tail === "string" ? parseInt(opts.tail, 10) || 50 : 50;
17553
17834
  try {
17554
- const content = readFileSync14(logPath, "utf-8");
17835
+ const content = readFileSync15(logPath, "utf-8");
17555
17836
  const lines = content.split(`
17556
17837
  `);
17557
17838
  console.log(lines.slice(-n2).join(`
@@ -17617,4 +17898,4 @@ execute().catch((err) => {
17617
17898
  process.exit(1);
17618
17899
  });
17619
17900
 
17620
- //# debugId=3772d842-939e-9b04-6475-6e2164756e21
17901
+ //# debugId=636daf7a-af53-b408-6475-6e2164756e21