@dosu/cli 0.60.2 → 0.61.0

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 (3) hide show
  1. package/README.md +2 -0
  2. package/bin/dosu.js +360 -119
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -107,6 +107,8 @@ Or right-click the binary, select "Open", and click "Open" in the dialog.
107
107
 
108
108
  `dosu upgrade` delegates to npm, pnpm, Yarn Classic, or Homebrew only after confirming which manager owns the current installation. Temporary package-runner invocations stay ephemeral, ambiguous or local installs are left unchanged, and standalone binaries receive the latest safe manual download path. After a successful update it hands off to the new version, which re-applies the bundled skills and, only if the update crossed a release that changed the agent config format, runs `dosu setup` (or the non-interactive `dosu mcp refresh` without a TTY). Upgrades done outside `dosu upgrade` (npm, brew, `npx @dosu/cli@latest`) get a safety net: when the new version changed the shape of the MCP entry, the first command on it silently rewrites configured tools' MCP entries and prompts you to run `dosu setup` for the rest; the bundled agent skills are always re-applied on the first command after any version change.
109
109
 
110
+ Dosu also updates itself automatically. When the update check (every six hours) finds a newer release, npm, pnpm, Yarn Classic, and Homebrew installs start the same package-manager update in a detached background process. The current command runs unchanged, and your next command uses the new version, whose first run applies the skill and MCP refreshes above. Hooks, rules, and the status line still need `dosu setup` when a release changes them. Background updates never run for `npx` invocations, standalone binaries, CI, or `DOSU_DEV=true`. A failed install (for example, a global npm prefix that needs `sudo`) falls back to the "Run `dosu upgrade`" notice and is retried after six hours. Turn background updates off with `dosu upgrade --auto off` (and back on with `--auto on`), or with `DOSU_DISABLE_AUTOUPDATE=1` for a single environment.
111
+
110
112
  ### Platform commands
111
113
 
112
114
  Once authenticated against a deployment, you can drive the Dosu platform without leaving the terminal:
package/bin/dosu.js CHANGED
@@ -1083,7 +1083,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
1083
1083
  function getVersionString() {
1084
1084
  return `v${VERSION}`;
1085
1085
  }
1086
- var VERSION = "0.60.2", INSTALL_CHANNEL = "npm";
1086
+ var VERSION = "0.61.0", INSTALL_CHANNEL = "npm";
1087
1087
 
1088
1088
  // src/debug/logger.ts
1089
1089
  import {
@@ -13800,7 +13800,7 @@ var init_conflicts = __esm(() => {
13800
13800
  });
13801
13801
 
13802
13802
  // src/telemetry/debug-id.ts
13803
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "49fa5d82-a4a1-8b36-6475-6e2164756e21";
13803
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "41cac967-78f1-f75a-6475-6e2164756e21";
13804
13804
 
13805
13805
  // src/telemetry/telemetry.ts
13806
13806
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -60326,11 +60326,11 @@ dosu skill install | remove | update
60326
60326
  dosu telemetry status [--json]
60327
60327
  dosu telemetry enable | disable | reset
60328
60328
  dosu insights
60329
- dosu upgrade
60329
+ dosu upgrade [--auto on|off]
60330
60330
  dosu logs [--tail [n]] [--clear]
60331
60331
  \`\`\`
60332
60332
 
60333
- \`deployments\` selects the MCP deployment stored in local config; it is distinct from \`agents\`. \`insights\` opens an interactive visual report. \`logs --clear\` deletes the CLI log file.
60333
+ \`deployments\` selects the MCP deployment stored in local config; it is distinct from \`agents\`. \`insights\` opens an interactive visual report. \`logs --clear\` deletes the CLI log file. The CLI updates itself in the background by default; a \`[dosu:update] Installing ...\` notice on stderr needs no action. \`upgrade --auto off\` turns that off.
60334
60334
 
60335
60335
  ## Codebase audit
60336
60336
 
@@ -62341,10 +62341,204 @@ var init_refresh = __esm(() => {
62341
62341
  init_providers();
62342
62342
  });
62343
62343
 
62344
- // src/version/update-check.ts
62345
- import { existsSync as existsSync23, mkdirSync as mkdirSync13, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "node:fs";
62344
+ // src/version/auto-update.ts
62345
+ import { spawn as spawn3 } from "node:child_process";
62346
+ import {
62347
+ closeSync as closeSync6,
62348
+ existsSync as existsSync23,
62349
+ mkdirSync as mkdirSync13,
62350
+ openSync as openSync6,
62351
+ readFileSync as readFileSync22,
62352
+ rmSync as rmSync7,
62353
+ statSync as statSync8,
62354
+ writeFileSync as writeFileSync14,
62355
+ writeSync
62356
+ } from "node:fs";
62357
+ import { homedir as homedir11 } from "node:os";
62346
62358
  import { join as join38 } from "node:path";
62359
+ function statePath() {
62360
+ return join38(getConfigDir(), STATE_FILENAME2);
62361
+ }
62362
+ function lockPath2() {
62363
+ return join38(getConfigDir(), LOCK_FILENAME2);
62364
+ }
62347
62365
  function isValidVersion(value) {
62366
+ return typeof value === "string" && VERSION_PATTERN.test(value);
62367
+ }
62368
+ function readState() {
62369
+ try {
62370
+ const raw = JSON.parse(readFileSync22(statePath(), "utf-8"));
62371
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw))
62372
+ return {};
62373
+ const data = raw;
62374
+ const state = {};
62375
+ if (data.disabled === true)
62376
+ state.disabled = true;
62377
+ const last = data.lastAttempt;
62378
+ if (last && isValidVersion(last.version) && typeof last.ok === "boolean" && typeof last.finishedAt === "number") {
62379
+ state.lastAttempt = { version: last.version, ok: last.ok, finishedAt: last.finishedAt };
62380
+ }
62381
+ return state;
62382
+ } catch {
62383
+ return {};
62384
+ }
62385
+ }
62386
+ function writeState(state) {
62387
+ try {
62388
+ const dir = getConfigDir();
62389
+ if (!existsSync23(dir))
62390
+ mkdirSync13(dir, { recursive: true, mode: 448 });
62391
+ writeFileSync14(statePath(), `${JSON.stringify(state, null, 2)}
62392
+ `, { mode: 384 });
62393
+ return true;
62394
+ } catch {
62395
+ return false;
62396
+ }
62397
+ }
62398
+ function isEnabledFlag(value) {
62399
+ if (value === undefined)
62400
+ return false;
62401
+ const normalized = value.trim().toLowerCase();
62402
+ return normalized !== "" && !["0", "false", "no", "off"].includes(normalized);
62403
+ }
62404
+ function autoUpdateDisabledReason(env = process.env) {
62405
+ if (isEnabledFlag(env[AUTO_UPDATE_ENV]))
62406
+ return "env";
62407
+ if (readState().disabled)
62408
+ return "settings";
62409
+ return;
62410
+ }
62411
+ function setAutoUpdateEnabled(enabled) {
62412
+ const state = readState();
62413
+ if (enabled)
62414
+ delete state.disabled;
62415
+ else
62416
+ state.disabled = true;
62417
+ return writeState(state);
62418
+ }
62419
+ function canAutoUpdate(channel, env) {
62420
+ if (env.NODE_ENV === "test" || env.CI || env.DOSU_DEV === "true")
62421
+ return false;
62422
+ if (!SUPPORTED_CHANNELS.has(channel) || isNpxInvocation(channel, env))
62423
+ return false;
62424
+ return autoUpdateDisabledReason(env) === undefined;
62425
+ }
62426
+ function backgroundInvocation(channel, entrypoint = process.argv[1], execPath = process.execPath) {
62427
+ const args = ["upgrade", "--background"];
62428
+ if (channel === "npm") {
62429
+ return entrypoint ? { command: execPath, args: [entrypoint, ...args] } : null;
62430
+ }
62431
+ if (channel === "homebrew")
62432
+ return { command: execPath, args };
62433
+ return null;
62434
+ }
62435
+ function lockIsFresh(now) {
62436
+ try {
62437
+ return now - statSync8(lockPath2()).mtimeMs < LOCK_STALE_MS;
62438
+ } catch {
62439
+ return false;
62440
+ }
62441
+ }
62442
+ function claimLock(version, now) {
62443
+ try {
62444
+ mkdirSync13(getConfigDir(), { recursive: true, mode: 448 });
62445
+ if (!lockIsFresh(now))
62446
+ rmSync7(lockPath2(), { force: true });
62447
+ const fd = openSync6(lockPath2(), "wx", 384);
62448
+ try {
62449
+ writeSync(fd, version);
62450
+ } finally {
62451
+ closeSync6(fd);
62452
+ }
62453
+ return "claimed";
62454
+ } catch (err) {
62455
+ return err.code === "EEXIST" ? "held" : "failed";
62456
+ }
62457
+ }
62458
+ function releaseLock() {
62459
+ try {
62460
+ rmSync7(lockPath2(), { force: true });
62461
+ } catch {}
62462
+ }
62463
+ function readLockVersion() {
62464
+ try {
62465
+ const version = readFileSync22(lockPath2(), "utf-8").trim();
62466
+ return isValidVersion(version) ? version : undefined;
62467
+ } catch {
62468
+ return;
62469
+ }
62470
+ }
62471
+ function startAutoUpdate(version, options = {}) {
62472
+ const channel = options.channel ?? INSTALL_CHANNEL;
62473
+ const env = options.env ?? process.env;
62474
+ const now = options.now ?? Date.now();
62475
+ try {
62476
+ if (!isValidVersion(version) || !canAutoUpdate(channel, env))
62477
+ return "unavailable";
62478
+ if (lockIsFresh(now))
62479
+ return "in_progress";
62480
+ const last = readState().lastAttempt;
62481
+ if (last?.version === version && now - last.finishedAt < RETRY_INTERVAL_MS) {
62482
+ return "unavailable";
62483
+ }
62484
+ const invocation = backgroundInvocation(channel, options.entrypoint, options.execPath);
62485
+ if (!invocation)
62486
+ return "unavailable";
62487
+ const claim = claimLock(version, now);
62488
+ if (claim !== "claimed")
62489
+ return claim === "held" ? "in_progress" : "unavailable";
62490
+ try {
62491
+ const child = spawn3(invocation.command, invocation.args, {
62492
+ cwd: homedir11(),
62493
+ detached: true,
62494
+ stdio: "ignore",
62495
+ windowsHide: true,
62496
+ env: { ...env, DOSU_TELEMETRY_DISABLED: "1" }
62497
+ });
62498
+ child.on("error", releaseLock);
62499
+ child.unref();
62500
+ } catch (err) {
62501
+ releaseLock();
62502
+ throw err;
62503
+ }
62504
+ logger.info("auto-update", `Started background update to ${version}`);
62505
+ return "started";
62506
+ } catch (err) {
62507
+ logger.error("auto-update", `Could not start background update: ${err}`);
62508
+ return "unavailable";
62509
+ }
62510
+ }
62511
+ function runBackgroundUpgrade(upgrade, now = Date.now) {
62512
+ const version = readLockVersion();
62513
+ let status = 1;
62514
+ try {
62515
+ status = upgrade();
62516
+ } catch (err) {
62517
+ logger.error("auto-update", `Background update threw: ${err}`);
62518
+ }
62519
+ if (version) {
62520
+ const state = readState();
62521
+ state.lastAttempt = { version, ok: status === 0, finishedAt: now() };
62522
+ writeState(state);
62523
+ }
62524
+ logger.info("auto-update", `Background update ${status === 0 ? "finished" : "failed"}`);
62525
+ releaseLock();
62526
+ return status;
62527
+ }
62528
+ var STATE_FILENAME2 = "auto-update.json", LOCK_FILENAME2 = "auto-update.lock", LOCK_STALE_MS, RETRY_INTERVAL_MS, SUPPORTED_CHANNELS, VERSION_PATTERN, AUTO_UPDATE_ENV = "DOSU_DISABLE_AUTOUPDATE";
62529
+ var init_auto_update = __esm(() => {
62530
+ init_config();
62531
+ init_logger();
62532
+ LOCK_STALE_MS = 15 * 60 * 1000;
62533
+ RETRY_INTERVAL_MS = 6 * 60 * 60 * 1000;
62534
+ SUPPORTED_CHANNELS = new Set(["npm", "homebrew"]);
62535
+ VERSION_PATTERN = /^[0-9A-Za-z.+-]{1,64}$/;
62536
+ });
62537
+
62538
+ // src/version/update-check.ts
62539
+ import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync15 } from "node:fs";
62540
+ import { join as join39 } from "node:path";
62541
+ function isValidVersion2(value) {
62348
62542
  return typeof value === "string" && SEMVER_PATTERN.test(value);
62349
62543
  }
62350
62544
  function stripPrerelease(version) {
@@ -62365,15 +62559,15 @@ function isNewerVersion(latest, current) {
62365
62559
  return false;
62366
62560
  }
62367
62561
  function getCachePath2() {
62368
- return join38(getConfigDir(), CACHE_FILENAME3);
62562
+ return join39(getConfigDir(), CACHE_FILENAME3);
62369
62563
  }
62370
62564
  function readCache() {
62371
62565
  try {
62372
62566
  const path = getCachePath2();
62373
- if (!existsSync23(path))
62567
+ if (!existsSync24(path))
62374
62568
  return null;
62375
- const data = JSON.parse(readFileSync22(path, "utf-8"));
62376
- if (typeof data.lastCheck === "number" && isValidVersion(data.latestVersion)) {
62569
+ const data = JSON.parse(readFileSync23(path, "utf-8"));
62570
+ if (typeof data.lastCheck === "number" && isValidVersion2(data.latestVersion)) {
62377
62571
  return data;
62378
62572
  }
62379
62573
  return null;
@@ -62384,10 +62578,10 @@ function readCache() {
62384
62578
  function writeCache(cache) {
62385
62579
  try {
62386
62580
  const dir = getConfigDir();
62387
- if (!existsSync23(dir)) {
62388
- mkdirSync13(dir, { recursive: true, mode: 448 });
62581
+ if (!existsSync24(dir)) {
62582
+ mkdirSync14(dir, { recursive: true, mode: 448 });
62389
62583
  }
62390
- writeFileSync14(getCachePath2(), JSON.stringify(cache), { mode: 384 });
62584
+ writeFileSync15(getCachePath2(), JSON.stringify(cache), { mode: 384 });
62391
62585
  } catch {}
62392
62586
  }
62393
62587
  async function fetchLatestVersion() {
@@ -62399,7 +62593,7 @@ async function fetchLatestVersion() {
62399
62593
  return null;
62400
62594
  const data = await resp.json();
62401
62595
  const latest = data.latest;
62402
- return isValidVersion(latest) ? latest : null;
62596
+ return isValidVersion2(latest) ? latest : null;
62403
62597
  } catch {
62404
62598
  return null;
62405
62599
  } finally {
@@ -62419,30 +62613,43 @@ function styleHint(hint) {
62419
62613
  const [, before, command, after] = match;
62420
62614
  return [before && import_picocolors30.default.dim(before), import_picocolors30.default.cyan(command), after && import_picocolors30.default.dim(after)].filter(Boolean).join("");
62421
62615
  }
62422
- function buildUpdateNotice(current, latest, channel, interactive, npx = false, width = process.stderr.columns ?? 80) {
62423
- const hint = buildUpdateHint(channel, npx);
62424
- if (interactive) {
62425
- const content = [
62426
- `Update available: ${import_picocolors30.default.dim(current)} ${import_picocolors30.default.dim("→")} ${import_picocolors30.default.bold(brand(latest))}`,
62427
- styleHint(hint)
62428
- ];
62429
- const innerWidth = Math.max(...content.map(visibleWidth2)) + BOX_PADDING * 2;
62430
- const framed = (line) => {
62431
- const pad = innerWidth - visibleWidth2(line);
62432
- const left = Math.floor(pad / 2);
62433
- return `${import_picocolors30.default.yellow("│")}${" ".repeat(left)}${line}${" ".repeat(pad - left)}${import_picocolors30.default.yellow("│")}`;
62434
- };
62435
- const box = [
62436
- import_picocolors30.default.yellow(`╭${"─".repeat(innerWidth)}╮`),
62437
- framed(""),
62438
- ...content.map(framed),
62439
- framed(""),
62440
- import_picocolors30.default.yellow(`╰${"─".repeat(innerWidth)}╯`)
62441
- ];
62442
- return `
62616
+ function framedNotice(content, width) {
62617
+ const innerWidth = Math.max(...content.map(visibleWidth2)) + BOX_PADDING * 2;
62618
+ const framed = (line) => {
62619
+ const pad = innerWidth - visibleWidth2(line);
62620
+ const left = Math.floor(pad / 2);
62621
+ return `${import_picocolors30.default.yellow("│")}${" ".repeat(left)}${line}${" ".repeat(pad - left)}${import_picocolors30.default.yellow("│")}`;
62622
+ };
62623
+ const box = [
62624
+ import_picocolors30.default.yellow(`╭${"─".repeat(innerWidth)}╮`),
62625
+ framed(""),
62626
+ ...content.map(framed),
62627
+ framed(""),
62628
+ import_picocolors30.default.yellow(`╰${"─".repeat(innerWidth)}╯`)
62629
+ ];
62630
+ return `
62443
62631
  ${centerBlock(box, width).join(`
62444
62632
  `)}
62445
62633
  `;
62634
+ }
62635
+ function versionArrow(current, latest) {
62636
+ return `${import_picocolors30.default.dim(current)} ${import_picocolors30.default.dim("→")} ${import_picocolors30.default.bold(brand(latest))}`;
62637
+ }
62638
+ function buildAutoUpdateNotice(current, latest, interactive, width = process.stderr.columns ?? 80) {
62639
+ if (interactive) {
62640
+ return framedNotice([
62641
+ `Updating Dosu: ${versionArrow(current, latest)}`,
62642
+ import_picocolors30.default.dim("Installing in the background; your next command uses it")
62643
+ ], width);
62644
+ }
62645
+ return `
62646
+ [dosu:update] Installing Dosu ${latest} in the background (running ${current}). ` + `The next Dosu command uses it; no action needed.
62647
+ `;
62648
+ }
62649
+ function buildUpdateNotice(current, latest, channel, interactive, npx = false, width = process.stderr.columns ?? 80) {
62650
+ const hint = buildUpdateHint(channel, npx);
62651
+ if (interactive) {
62652
+ return framedNotice([`Update available: ${versionArrow(current, latest)}`, styleHint(hint)], width);
62446
62653
  }
62447
62654
  const agentAction = hint[0].toLowerCase() + hint.slice(1);
62448
62655
  const verifyCommand = npx ? "npx -y @dosu/cli@latest --version" : "dosu --version";
@@ -62455,8 +62662,12 @@ function getAvailableUpdate() {
62455
62662
  const cache = readCache();
62456
62663
  return cache && isNewerVersion(cache.latestVersion, VERSION) ? cache.latestVersion : null;
62457
62664
  }
62458
- function displayNotice(current, latest) {
62459
- console.error(buildUpdateNotice(current, latest, INSTALL_CHANNEL, process.stderr.isTTY === true, isNpxInvocation()));
62665
+ function handleNewerVersion(latest, notify) {
62666
+ const autoUpdate = startAutoUpdate(latest);
62667
+ if (!notify)
62668
+ return;
62669
+ const interactive = process.stderr.isTTY === true;
62670
+ console.error(autoUpdate === "unavailable" ? buildUpdateNotice(VERSION, latest, INSTALL_CHANNEL, interactive, isNpxInvocation()) : buildAutoUpdateNotice(VERSION, latest, interactive));
62460
62671
  }
62461
62672
  async function checkForUpdates(options = {}) {
62462
62673
  const notify = options.notify ?? true;
@@ -62464,8 +62675,8 @@ async function checkForUpdates(options = {}) {
62464
62675
  const cache = readCache();
62465
62676
  const isStale = !cache || Date.now() - cache.lastCheck > CHECK_INTERVAL_MS2;
62466
62677
  if (!isStale) {
62467
- if (notify && isNewerVersion(cache.latestVersion, VERSION)) {
62468
- displayNotice(VERSION, cache.latestVersion);
62678
+ if (isNewerVersion(cache.latestVersion, VERSION)) {
62679
+ handleNewerVersion(cache.latestVersion, notify);
62469
62680
  }
62470
62681
  return;
62471
62682
  }
@@ -62478,8 +62689,8 @@ async function checkForUpdates(options = {}) {
62478
62689
  if (latest) {
62479
62690
  logger.debug("update-check", `Cached latest version: ${latest}`);
62480
62691
  }
62481
- if (notify && isNewerVersion(latestKnownVersion, VERSION)) {
62482
- displayNotice(VERSION, latestKnownVersion);
62692
+ if (isNewerVersion(latestKnownVersion, VERSION)) {
62693
+ handleNewerVersion(latestKnownVersion, notify);
62483
62694
  }
62484
62695
  } catch (err) {
62485
62696
  logger.error("update-check", `Update check failed: ${err}`);
@@ -62491,14 +62702,15 @@ var init_update_check = __esm(() => {
62491
62702
  init_logger();
62492
62703
  init_styles();
62493
62704
  init_layout();
62705
+ init_auto_update();
62494
62706
  import_picocolors30 = __toESM(require_picocolors(), 1);
62495
62707
  CHECK_INTERVAL_MS2 = 6 * 60 * 60 * 1000;
62496
62708
  SEMVER_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
62497
62709
  });
62498
62710
 
62499
62711
  // src/version/mcp-refresh-check.ts
62500
- import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync15 } from "node:fs";
62501
- import { join as join39 } from "node:path";
62712
+ import { existsSync as existsSync25, mkdirSync as mkdirSync15, readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "node:fs";
62713
+ import { join as join40 } from "node:path";
62502
62714
  function needsMcpRefresh(previous, current) {
62503
62715
  if (previous === null)
62504
62716
  return true;
@@ -62508,14 +62720,14 @@ function needsMcpRefresh(previous, current) {
62508
62720
  return MCP_FORMAT_CHANGES.some((change) => isNewerVersion(change, older) && !isNewerVersion(change, newer));
62509
62721
  }
62510
62722
  function getCachePath3() {
62511
- return join39(getConfigDir(), CACHE_FILENAME4);
62723
+ return join40(getConfigDir(), CACHE_FILENAME4);
62512
62724
  }
62513
62725
  function readMcpRefreshCache() {
62514
62726
  try {
62515
62727
  const path = getCachePath3();
62516
- if (!existsSync24(path))
62728
+ if (!existsSync25(path))
62517
62729
  return null;
62518
- const data = JSON.parse(readFileSync23(path, "utf-8"));
62730
+ const data = JSON.parse(readFileSync24(path, "utf-8"));
62519
62731
  if (typeof data?.version === "string")
62520
62732
  return { version: data.version };
62521
62733
  return null;
@@ -62526,10 +62738,10 @@ function readMcpRefreshCache() {
62526
62738
  function writeMcpRefreshCache(cache) {
62527
62739
  try {
62528
62740
  const dir = getConfigDir();
62529
- if (!existsSync24(dir)) {
62530
- mkdirSync14(dir, { recursive: true, mode: 448 });
62741
+ if (!existsSync25(dir)) {
62742
+ mkdirSync15(dir, { recursive: true, mode: 448 });
62531
62743
  }
62532
- writeFileSync15(getCachePath3(), JSON.stringify(cache), { mode: 384 });
62744
+ writeFileSync16(getCachePath3(), JSON.stringify(cache), { mode: 384 });
62533
62745
  } catch {}
62534
62746
  }
62535
62747
  function canRefreshMcp(cfg) {
@@ -62538,7 +62750,7 @@ function canRefreshMcp(cfg) {
62538
62750
  return false;
62539
62751
  return cfg.mode === MODE_OSS || Boolean(target.deployment_id);
62540
62752
  }
62541
- function displayNotice2(names) {
62753
+ function displayNotice(names) {
62542
62754
  console.error(`
62543
62755
  ${import_picocolors31.default.green(`✓ Dosu ${VERSION}: refreshed MCP config for ${names.join(", ")}`)}
62544
62756
  ` + `${import_picocolors31.default.dim(` Run ${import_picocolors31.default.cyan('"dosu setup"')} to also update hooks and rules, then restart your AI agents.`)}
@@ -62563,7 +62775,7 @@ function checkForMcpRefresh(options = {}) {
62563
62775
  writeMcpRefreshCache({ version: VERSION });
62564
62776
  logger.info("mcp-refresh", `Version ${VERSION}: refreshed ${result.updated.length}, failed ${result.failed.length}`);
62565
62777
  if (notify && result.updated.length > 0) {
62566
- displayNotice2(result.updated.map((provider) => provider.name()));
62778
+ displayNotice(result.updated.map((provider) => provider.name()));
62567
62779
  }
62568
62780
  } catch (err) {
62569
62781
  logger.error("mcp-refresh", `MCP refresh check failed: ${err}`);
@@ -62580,7 +62792,7 @@ var init_mcp_refresh_check = __esm(() => {
62580
62792
  });
62581
62793
 
62582
62794
  // src/version/skill-update-check.ts
62583
- function displayNotice3() {
62795
+ function displayNotice2() {
62584
62796
  console.error(`
62585
62797
  ${import_picocolors32.default.green(`✓ Dosu ${VERSION}: refreshed the bundled agent skills`)}
62586
62798
  ` + `${import_picocolors32.default.dim(" Restart your AI agents to pick up the new skill content.")}
@@ -62599,7 +62811,7 @@ function checkForSkillUpdates(options = {}) {
62599
62811
  }
62600
62812
  logger.info("skill-update-check", `Refreshed skills from ${state.version} to ${VERSION}`);
62601
62813
  if (notify && result.version)
62602
- displayNotice3();
62814
+ displayNotice2();
62603
62815
  } catch (err) {
62604
62816
  logger.error("skill-update-check", `Skill update check failed: ${err}`);
62605
62817
  }
@@ -62639,11 +62851,11 @@ var init_errors3 = __esm(() => {
62639
62851
  var MCP_PROVIDER_SLUG2 = "dosu_mcp";
62640
62852
 
62641
62853
  // src/debug/follow.ts
62642
- import { closeSync as closeSync6, openSync as openSync6, readSync as readSync5, statSync as statSync8 } from "node:fs";
62854
+ import { closeSync as closeSync7, openSync as openSync7, readSync as readSync5, statSync as statSync9 } from "node:fs";
62643
62855
  function createLogFollower(path, emit) {
62644
62856
  const sizeOf = () => {
62645
62857
  try {
62646
- return statSync8(path).size;
62858
+ return statSync9(path).size;
62647
62859
  } catch {
62648
62860
  return 0;
62649
62861
  }
@@ -62657,7 +62869,7 @@ function createLogFollower(path, emit) {
62657
62869
  if (size === offset)
62658
62870
  return;
62659
62871
  try {
62660
- const fd = openSync6(path, "r");
62872
+ const fd = openSync7(path, "r");
62661
62873
  try {
62662
62874
  const buf = Buffer.alloc(size - offset);
62663
62875
  const read = readSync5(fd, buf, 0, buf.length, offset);
@@ -62665,7 +62877,7 @@ function createLogFollower(path, emit) {
62665
62877
  if (read > 0)
62666
62878
  emit(buf.toString("utf-8", 0, read));
62667
62879
  } finally {
62668
- closeSync6(fd);
62880
+ closeSync7(fd);
62669
62881
  }
62670
62882
  } catch {}
62671
62883
  }
@@ -62674,15 +62886,15 @@ function createLogFollower(path, emit) {
62674
62886
  var init_follow = () => {};
62675
62887
 
62676
62888
  // src/sessions/session-title.ts
62677
- import { existsSync as existsSync25, mkdirSync as mkdirSync15, readFileSync as readFileSync24, renameSync as renameSync6, statSync as statSync9, writeFileSync as writeFileSync16 } from "node:fs";
62678
- import { homedir as homedir11 } from "node:os";
62679
- import { join as join40 } from "node:path";
62889
+ import { existsSync as existsSync26, mkdirSync as mkdirSync16, readFileSync as readFileSync25, renameSync as renameSync6, statSync as statSync10, writeFileSync as writeFileSync17 } from "node:fs";
62890
+ import { homedir as homedir12 } from "node:os";
62891
+ import { join as join41 } from "node:path";
62680
62892
  function cachePath2(configDir) {
62681
- return join40(configDir, CACHE_FILENAME5);
62893
+ return join41(configDir, CACHE_FILENAME5);
62682
62894
  }
62683
62895
  function loadCacheFile2(configDir) {
62684
62896
  try {
62685
- const raw = JSON.parse(readFileSync24(cachePath2(configDir), "utf-8"));
62897
+ const raw = JSON.parse(readFileSync25(cachePath2(configDir), "utf-8"));
62686
62898
  if (raw.schema_version !== CACHE_SCHEMA_VERSION2 || typeof raw.entries !== "object")
62687
62899
  return {};
62688
62900
  return raw.entries;
@@ -62692,12 +62904,12 @@ function loadCacheFile2(configDir) {
62692
62904
  }
62693
62905
  function saveCacheFile2(configDir, entries) {
62694
62906
  try {
62695
- if (!existsSync25(configDir))
62696
- mkdirSync15(configDir, { recursive: true, mode: 448 });
62907
+ if (!existsSync26(configDir))
62908
+ mkdirSync16(configDir, { recursive: true, mode: 448 });
62697
62909
  const path = cachePath2(configDir);
62698
62910
  const tmp = `${path}.${process.pid}.tmp`;
62699
62911
  const file = { schema_version: CACHE_SCHEMA_VERSION2, entries };
62700
- writeFileSync16(tmp, JSON.stringify(file), { mode: 384 });
62912
+ writeFileSync17(tmp, JSON.stringify(file), { mode: 384 });
62701
62913
  renameSync6(tmp, path);
62702
62914
  } catch {}
62703
62915
  }
@@ -62730,15 +62942,15 @@ function claudeSummaryFromHead(text) {
62730
62942
  }
62731
62943
  return null;
62732
62944
  }
62733
- function reconstructSession(harness, id, slug, home = homedir11(), exists = existsSync25) {
62945
+ function reconstructSession(harness, id, slug, home = homedir12(), exists = existsSync26) {
62734
62946
  if (!slug)
62735
62947
  return null;
62736
62948
  const candidates = [];
62737
62949
  if (harness === "claude") {
62738
- candidates.push(join40(home, ".claude", "projects", slug, `${id}.jsonl`));
62950
+ candidates.push(join41(home, ".claude", "projects", slug, `${id}.jsonl`));
62739
62951
  } else if (harness === "cursor") {
62740
- const project = join40(home, ".cursor", "projects", slug);
62741
- candidates.push(join40(project, "agent-transcripts", id, `${id}.jsonl`), join40(project, "agent-transcripts", `${id}.jsonl`));
62952
+ const project = join41(home, ".cursor", "projects", slug);
62953
+ candidates.push(join41(project, "agent-transcripts", id, `${id}.jsonl`), join41(project, "agent-transcripts", `${id}.jsonl`));
62742
62954
  } else {
62743
62955
  return null;
62744
62956
  }
@@ -62750,14 +62962,14 @@ function reconstructSession(harness, id, slug, home = homedir11(), exists = exis
62750
62962
  }
62751
62963
  function readHead2(path) {
62752
62964
  try {
62753
- return readFileSync24(path, "utf-8").slice(0, 128 * 1024);
62965
+ return readFileSync25(path, "utf-8").slice(0, 128 * 1024);
62754
62966
  } catch {
62755
62967
  return null;
62756
62968
  }
62757
62969
  }
62758
62970
  function fileMtime2(path) {
62759
62971
  try {
62760
- return statSync9(path).mtime.toISOString();
62972
+ return statSync10(path).mtime.toISOString();
62761
62973
  } catch {
62762
62974
  return "";
62763
62975
  }
@@ -62830,7 +63042,7 @@ var init_alt_screen = __esm(() => {
62830
63042
  });
62831
63043
 
62832
63044
  // src/tui/activity-view.ts
62833
- import { existsSync as existsSync26, readFileSync as readFileSync25 } from "node:fs";
63045
+ import { existsSync as existsSync27, readFileSync as readFileSync26 } from "node:fs";
62834
63046
  import { basename as basename5 } from "node:path";
62835
63047
  function reduceActivityViewKey(key) {
62836
63048
  if (key === "q" || key === ESC7 || key === CTRL_C4)
@@ -63151,7 +63363,7 @@ function createRowNamer() {
63151
63363
  names.titles[key] = t;
63152
63364
  };
63153
63365
  for (const s of [...backlog.queued, ...backlog.open]) {
63154
- if (!existsSync26(s.path))
63366
+ if (!existsSync27(s.path))
63155
63367
  continue;
63156
63368
  const key = `${s.harness}/${s.id}`;
63157
63369
  const dir = dirs.resolve(s);
@@ -63188,7 +63400,7 @@ function createRowNamer() {
63188
63400
  }
63189
63401
  function defaultReadLog2() {
63190
63402
  try {
63191
- return readFileSync25(logger.getLogPath(), "utf-8");
63403
+ return readFileSync26(logger.getLogPath(), "utf-8");
63192
63404
  } catch {
63193
63405
  return "";
63194
63406
  }
@@ -63405,14 +63617,14 @@ var init_activity_view = __esm(() => {
63405
63617
  });
63406
63618
 
63407
63619
  // src/rules/installer.ts
63408
- import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync26, unlinkSync as unlinkSync5, writeFileSync as writeFileSync17 } from "node:fs";
63409
- import { homedir as homedir12 } from "node:os";
63410
- import { dirname as dirname12, join as join41 } from "node:path";
63620
+ import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync27, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "node:fs";
63621
+ import { homedir as homedir13 } from "node:os";
63622
+ import { dirname as dirname12, join as join42 } from "node:path";
63411
63623
  function claudeConfigDir4() {
63412
- return process.env.CLAUDE_CONFIG_DIR || join41(homedir12(), ".claude");
63624
+ return process.env.CLAUDE_CONFIG_DIR || join42(homedir13(), ".claude");
63413
63625
  }
63414
63626
  function codexHome4() {
63415
- return process.env.CODEX_HOME || join41(homedir12(), ".codex");
63627
+ return process.env.CODEX_HOME || join42(homedir13(), ".codex");
63416
63628
  }
63417
63629
  function isRuleAgent(agent) {
63418
63630
  return Object.hasOwn(RULE_TARGETS, agent);
@@ -63438,17 +63650,17 @@ async function fetchDosuRule(fetchImpl = globalThis.fetch) {
63438
63650
  return normalizeRule(FALLBACK_DOSU_RULE);
63439
63651
  }
63440
63652
  function ensureParent(path) {
63441
- mkdirSync16(dirname12(path), { recursive: true });
63653
+ mkdirSync17(dirname12(path), { recursive: true });
63442
63654
  }
63443
63655
  function writeIfChanged(path, content) {
63444
- if (!existsSync27(path)) {
63656
+ if (!existsSync28(path)) {
63445
63657
  ensureParent(path);
63446
- writeFileSync17(path, content, "utf-8");
63658
+ writeFileSync18(path, content, "utf-8");
63447
63659
  return "created";
63448
63660
  }
63449
- if (readFileSync26(path, "utf-8") === content)
63661
+ if (readFileSync27(path, "utf-8") === content)
63450
63662
  return "unchanged";
63451
- writeFileSync17(path, content, "utf-8");
63663
+ writeFileSync18(path, content, "utf-8");
63452
63664
  return "updated";
63453
63665
  }
63454
63666
  function findSection(content) {
@@ -63474,14 +63686,14 @@ function buildSection(content, lineEnding = `
63474
63686
  return `${DOSU_RULE_SECTION_START}${lineEnding}${body}${lineEnding}${DOSU_RULE_SECTION_END}`;
63475
63687
  }
63476
63688
  function upsertSection(path, content) {
63477
- if (!existsSync27(path)) {
63689
+ if (!existsSync28(path)) {
63478
63690
  const section = buildSection(content);
63479
63691
  ensureParent(path);
63480
- writeFileSync17(path, `${section}
63692
+ writeFileSync18(path, `${section}
63481
63693
  `, "utf-8");
63482
63694
  return "created";
63483
63695
  }
63484
- const existing = readFileSync26(path, "utf-8");
63696
+ const existing = readFileSync27(path, "utf-8");
63485
63697
  const lineEnding = lineEndingFor(existing);
63486
63698
  const section = buildSection(content, lineEnding);
63487
63699
  const location = findSection(existing);
@@ -63494,7 +63706,7 @@ function upsertSection(path, content) {
63494
63706
  }
63495
63707
  if (next === existing)
63496
63708
  return "unchanged";
63497
- writeFileSync17(path, next, "utf-8");
63709
+ writeFileSync18(path, next, "utf-8");
63498
63710
  return "updated";
63499
63711
  }
63500
63712
  function installRuleForAgent(agent, content) {
@@ -63511,13 +63723,13 @@ function removeRuleForAgent(agent) {
63511
63723
  return null;
63512
63724
  const target = RULE_TARGETS[agent];
63513
63725
  const path = target.path();
63514
- if (!existsSync27(path))
63726
+ if (!existsSync28(path))
63515
63727
  return { agent, path, action: "not_found" };
63516
63728
  if (target.kind === "file") {
63517
63729
  unlinkSync5(path);
63518
63730
  return { agent, path, action: "removed" };
63519
63731
  }
63520
- const existing = readFileSync26(path, "utf-8");
63732
+ const existing = readFileSync27(path, "utf-8");
63521
63733
  const lineEnding = lineEndingFor(existing);
63522
63734
  const location = findSection(existing);
63523
63735
  if (!location)
@@ -63526,7 +63738,7 @@ function removeRuleForAgent(agent) {
63526
63738
  if (!next) {
63527
63739
  unlinkSync5(path);
63528
63740
  } else {
63529
- writeFileSync17(path, `${next}${lineEnding}`, "utf-8");
63741
+ writeFileSync18(path, `${next}${lineEnding}`, "utf-8");
63530
63742
  }
63531
63743
  return { agent, path, action: "removed" };
63532
63744
  }
@@ -63554,36 +63766,36 @@ var init_installer = __esm(() => {
63554
63766
  RULE_TARGETS = {
63555
63767
  claude: {
63556
63768
  kind: "file",
63557
- path: () => join41(claudeConfigDir4(), "rules", "dosu.md")
63769
+ path: () => join42(claudeConfigDir4(), "rules", "dosu.md")
63558
63770
  },
63559
63771
  cursor: {
63560
63772
  kind: "file",
63561
- path: () => join41(homedir12(), ".cursor", "rules", "dosu.mdc"),
63773
+ path: () => join42(homedir13(), ".cursor", "rules", "dosu.mdc"),
63562
63774
  cursorFrontmatter: true
63563
63775
  },
63564
63776
  codex: {
63565
63777
  kind: "section",
63566
- path: () => join41(codexHome4(), "AGENTS.md")
63778
+ path: () => join42(codexHome4(), "AGENTS.md")
63567
63779
  },
63568
63780
  opencode: {
63569
63781
  kind: "section",
63570
- path: () => join41(homedir12(), ".config", "opencode", "AGENTS.md")
63782
+ path: () => join42(homedir13(), ".config", "opencode", "AGENTS.md")
63571
63783
  },
63572
63784
  gemini: {
63573
63785
  kind: "section",
63574
- path: () => join41(homedir12(), ".gemini", "GEMINI.md")
63786
+ path: () => join42(homedir13(), ".gemini", "GEMINI.md")
63575
63787
  },
63576
63788
  antigravity: {
63577
63789
  kind: "section",
63578
- path: () => join41(homedir12(), ".gemini", "GEMINI.md")
63790
+ path: () => join42(homedir13(), ".gemini", "GEMINI.md")
63579
63791
  }
63580
63792
  };
63581
63793
  });
63582
63794
 
63583
63795
  // src/setup/agents-md-step.ts
63584
63796
  import { execSync as execSync2 } from "node:child_process";
63585
- import { existsSync as existsSync28, readFileSync as readFileSync27, writeFileSync as writeFileSync18 } from "node:fs";
63586
- import { join as join42 } from "node:path";
63797
+ import { existsSync as existsSync29, readFileSync as readFileSync28, writeFileSync as writeFileSync19 } from "node:fs";
63798
+ import { join as join43 } from "node:path";
63587
63799
  function inGitWorkTree(cwd = process.cwd()) {
63588
63800
  try {
63589
63801
  const stdout = execSync2("git rev-parse --is-inside-work-tree", {
@@ -63597,10 +63809,10 @@ function inGitWorkTree(cwd = process.cwd()) {
63597
63809
  }
63598
63810
  function dosuAgentsSectionState(cwd = process.cwd()) {
63599
63811
  try {
63600
- const path = join42(cwd, "AGENTS.md");
63601
- if (!existsSync28(path))
63812
+ const path = join43(cwd, "AGENTS.md");
63813
+ if (!existsSync29(path))
63602
63814
  return "missing";
63603
- const content = readFileSync27(path, "utf-8");
63815
+ const content = readFileSync28(path, "utf-8");
63604
63816
  const startMatch = content.match(SECTION_START_RE);
63605
63817
  if (!startMatch || !content.includes(DOSU_SECTION_END))
63606
63818
  return "missing";
@@ -63635,14 +63847,14 @@ function findSection2(content) {
63635
63847
  return { start, end };
63636
63848
  }
63637
63849
  function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RULE) {
63638
- const path = join42(cwd, "AGENTS.md");
63639
- if (!existsSync28(path)) {
63850
+ const path = join43(cwd, "AGENTS.md");
63851
+ if (!existsSync29(path)) {
63640
63852
  const section = buildDosuAgentsSection(content);
63641
- writeFileSync18(path, `${section}
63853
+ writeFileSync19(path, `${section}
63642
63854
  `);
63643
63855
  return { path, action: "created" };
63644
63856
  }
63645
- const existing = readFileSync27(path, "utf-8");
63857
+ const existing = readFileSync28(path, "utf-8");
63646
63858
  const lineEnding = lineEndingFor2(existing);
63647
63859
  const section = renderDosuAgentsSection(content, lineEnding);
63648
63860
  const location = findSection2(existing);
@@ -63654,7 +63866,7 @@ function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RU
63654
63866
  }
63655
63867
  if (next === existing)
63656
63868
  return { path, action: "unchanged" };
63657
- writeFileSync18(path, next);
63869
+ writeFileSync19(path, next);
63658
63870
  return { path, action: "updated" };
63659
63871
  }
63660
63872
  async function stepUpdateAgentsMd(cwd = process.cwd(), content) {
@@ -65366,7 +65578,7 @@ var init_flow2 = __esm(() => {
65366
65578
  // src/commands/upgrade.ts
65367
65579
  import { spawnSync } from "node:child_process";
65368
65580
  import { realpathSync as realpathSync2 } from "node:fs";
65369
- import { homedir as homedir13 } from "node:os";
65581
+ import { homedir as homedir14 } from "node:os";
65370
65582
  import { posix, win32 as win322 } from "node:path";
65371
65583
  function isAbsoluteCommandProcessor(value) {
65372
65584
  return Boolean(value && win322.isAbsolute(value) && win322.basename(value).toLowerCase() === "cmd.exe");
@@ -65420,7 +65632,7 @@ function packageRoots(manager, platform, comSpec, env, cwd) {
65420
65632
  manager === "npm" ? path.join(lines[0], "@dosu", "cli") : path.join(lines[0], "node_modules", "@dosu", "cli")
65421
65633
  ];
65422
65634
  }
65423
- function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd = homedir13()) {
65635
+ function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd = homedir14()) {
65424
65636
  const path = platform === "win32" ? win322 : posix;
65425
65637
  if (!entrypoint || !path.isAbsolute(entrypoint))
65426
65638
  return null;
@@ -65473,7 +65685,7 @@ Or install Dosu globally with your package manager:`);
65473
65685
  function runUpgrade(channel = INSTALL_CHANNEL, options = {}) {
65474
65686
  const platform = options.platform ?? process.platform;
65475
65687
  const env = options.env ?? process.env;
65476
- const cwd = options.cwd ?? homedir13();
65688
+ const cwd = options.cwd ?? homedir14();
65477
65689
  let manager = null;
65478
65690
  if (channel === "npm") {
65479
65691
  if (isNpxInvocation(channel, env)) {
@@ -65540,7 +65752,7 @@ function finishWithNewBinary(channel, options) {
65540
65752
  return;
65541
65753
  }
65542
65754
  const result = spawnSync(invocation.command, invocation.args, {
65543
- cwd: options.cwd ?? homedir13(),
65755
+ cwd: options.cwd ?? homedir14(),
65544
65756
  shell: false,
65545
65757
  stdio: "inherit"
65546
65758
  });
@@ -65590,9 +65802,37 @@ Refreshing agent MCP configs with the new version...`);
65590
65802
  console.error(SETUP_FALLBACK);
65591
65803
  return 0;
65592
65804
  }
65805
+ function setAutoUpdate(value) {
65806
+ const normalized = value.trim().toLowerCase();
65807
+ if (normalized !== "on" && normalized !== "off") {
65808
+ console.error(`Invalid --auto value '${value}' (expected 'on' or 'off').`);
65809
+ return 2;
65810
+ }
65811
+ if (!setAutoUpdateEnabled(normalized === "on")) {
65812
+ console.error("Could not save the auto-update setting.");
65813
+ return 1;
65814
+ }
65815
+ if (normalized === "off") {
65816
+ console.log('Automatic updates are off. Run "dosu upgrade" to update by hand.');
65817
+ } else if (autoUpdateDisabledReason() === "env") {
65818
+ console.log(`Automatic updates are on, but ${AUTO_UPDATE_ENV} still disables them here.`);
65819
+ } else {
65820
+ console.log("Automatic updates are on.");
65821
+ }
65822
+ return 0;
65823
+ }
65593
65824
  function upgradeCommand() {
65594
- return new Command("upgrade").description("Update Dosu to the latest version, re-running setup when the update changes agent config").addOption(new Option("--finish <from>").hideHelp()).action(async (opts) => {
65595
- const status = opts.finish !== undefined ? await finishUpgrade(opts.finish) : await completeUpgrade();
65825
+ return new Command("upgrade").description("Update Dosu to the latest version, re-running setup when the update changes agent config").option("--auto <on|off>", "Turn automatic background updates on or off").addOption(new Option("--background").hideHelp()).addOption(new Option("--finish <from>").hideHelp()).action(async (opts) => {
65826
+ let status;
65827
+ if (opts.auto !== undefined) {
65828
+ status = setAutoUpdate(opts.auto);
65829
+ } else if (opts.background) {
65830
+ status = runBackgroundUpgrade(() => runUpgrade());
65831
+ } else if (opts.finish !== undefined) {
65832
+ status = await finishUpgrade(opts.finish);
65833
+ } else {
65834
+ status = await completeUpgrade();
65835
+ }
65596
65836
  if (status !== 0)
65597
65837
  process.exitCode = status;
65598
65838
  });
@@ -65602,6 +65842,7 @@ var init_upgrade = __esm(() => {
65602
65842
  init_commander();
65603
65843
  init_config();
65604
65844
  init_refresh();
65845
+ init_auto_update();
65605
65846
  init_mcp_refresh_check();
65606
65847
  init_skill_update_check();
65607
65848
  import_picocolors35 = __toESM(require_picocolors(), 1);
@@ -66309,7 +66550,7 @@ var init_pages_view = __esm(() => {
66309
66550
  });
66310
66551
 
66311
66552
  // src/tui/tui.ts
66312
- import { homedir as homedir14 } from "node:os";
66553
+ import { homedir as homedir15 } from "node:os";
66313
66554
  import { basename as basename6 } from "node:path";
66314
66555
  async function probeSession(cfg) {
66315
66556
  if (!isAuthenticated(cfg) || !isTokenExpired(cfg))
@@ -66574,7 +66815,7 @@ async function runSettings(cfg) {
66574
66815
  }
66575
66816
  }
66576
66817
  function displayDir(dir) {
66577
- const home = homedir14();
66818
+ const home = homedir15();
66578
66819
  return dir === home ? "~" : dir.startsWith(`${home}/`) ? `~${dir.slice(home.length)}` : dir;
66579
66820
  }
66580
66821
  function discoverProjectDirs() {
@@ -67284,7 +67525,7 @@ var init_flow3 = __esm(() => {
67284
67525
  });
67285
67526
 
67286
67527
  // src/cli/cli.ts
67287
- import { readFileSync as readFileSync28, unlinkSync as unlinkSync6 } from "node:fs";
67528
+ import { readFileSync as readFileSync29, unlinkSync as unlinkSync6 } from "node:fs";
67288
67529
  function shouldRunBackgroundChecks(actionName) {
67289
67530
  return actionName !== "upgrade";
67290
67531
  }
@@ -67730,7 +67971,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
67730
67971
  }
67731
67972
  if (opts.follow) {
67732
67973
  try {
67733
- const lines = readFileSync28(logPath, "utf-8").split(`
67974
+ const lines = readFileSync29(logPath, "utf-8").split(`
67734
67975
  `);
67735
67976
  if (lines.at(-1) === "")
67736
67977
  lines.pop();
@@ -67746,7 +67987,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
67746
67987
  if (opts.tail !== undefined) {
67747
67988
  const n = typeof opts.tail === "string" ? parseInt(opts.tail, 10) || 50 : 50;
67748
67989
  try {
67749
- const content = readFileSync28(logPath, "utf-8");
67990
+ const content = readFileSync29(logPath, "utf-8");
67750
67991
  const lines = content.split(`
67751
67992
  `);
67752
67993
  console.log(lines.slice(-n).join(`
@@ -67872,4 +68113,4 @@ main().catch((err) => {
67872
68113
  process.exit(1);
67873
68114
  });
67874
68115
 
67875
- //# debugId=49fa5d82-a4a1-8b36-6475-6e2164756e21
68116
+ //# debugId=41cac967-78f1-f75a-6475-6e2164756e21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.60.2",
3
+ "version": "0.61.0",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Manage MCP servers for AI tools",
6
6
  "license": "MIT",