@dosu/cli 0.43.0-alpha.1 → 0.44.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 +3 -0
  2. package/bin/dosu.js +264 -46
  3. package/package.json +4 -1
package/README.md CHANGED
@@ -96,12 +96,15 @@ Or right-click the binary, select "Open", and click "Open" in the dialog.
96
96
  | `dosu login` | Authenticate with Dosu via browser OAuth |
97
97
  | `dosu logout` | Clear saved credentials |
98
98
  | `dosu status [--json]` | Show current authentication and MCP status |
99
+ | `dosu upgrade` | Update Dosu through the package manager that installed it |
99
100
  | `dosu mcp list` | List supported AI tools |
100
101
  | `dosu mcp add <tool>` | Add the Dosu MCP server to a specific tool |
101
102
  | `dosu logs` | View or manage debug logs (`--tail`, `--clear`) |
102
103
 
103
104
  `dosu mcp add` takes `-g, --global` to install for all projects instead of project-local, and `--show-secret` to print the full manual config.
104
105
 
106
+ `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.
107
+
105
108
  ### Platform commands
106
109
 
107
110
  Once authenticated against a deployment, you can drive the Dosu platform without leaving the terminal:
package/bin/dosu.js CHANGED
@@ -4756,10 +4756,13 @@ var init_dist4 = __esm(() => {
4756
4756
  });
4757
4757
 
4758
4758
  // src/version/version.ts
4759
+ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
4760
+ return channel === "npm" && (env.npm_lifecycle_event === "npx" || env.npm_command === "exec");
4761
+ }
4759
4762
  function getVersionString() {
4760
4763
  return `v${VERSION}`;
4761
4764
  }
4762
- var VERSION = "0.43.0-alpha.1", INSTALL_CHANNEL = "npm";
4765
+ var VERSION = "0.44.0", INSTALL_CHANNEL = "npm";
4763
4766
 
4764
4767
  // src/debug/logger.ts
4765
4768
  import {
@@ -8177,7 +8180,6 @@ var exports_prompts = {};
8177
8180
  __export(exports_prompts, {
8178
8181
  buildReadyEnvelope: () => buildReadyEnvelope,
8179
8182
  STOP_PREFIX: () => STOP_PREFIX,
8180
- SAVE_NUDGE: () => SAVE_NUDGE,
8181
8183
  LOOKUP_STARTED_NOTE: () => LOOKUP_STARTED_NOTE,
8182
8184
  LATE_RESULT_NOTE: () => LATE_RESULT_NOTE
8183
8185
  });
@@ -9059,8 +9061,7 @@ __export(exports_codex, {
9059
9061
  removeCodexHooks: () => removeCodexHooks,
9060
9062
  installCodexHooks: () => installCodexHooks,
9061
9063
  inspectCodexHooks: () => inspectCodexHooks,
9062
- codexHooksPath: () => codexHooksPath,
9063
- codexHookCommand: () => codexHookCommand
9064
+ codexHooksPath: () => codexHooksPath
9064
9065
  });
9065
9066
  import { existsSync as existsSync9, readFileSync as readFileSync9 } from "node:fs";
9066
9067
  import { join as join8 } from "node:path";
@@ -9189,8 +9190,7 @@ __export(exports_factory, {
9189
9190
  removeFactoryHooks: () => removeFactoryHooks,
9190
9191
  installFactoryHooks: () => installFactoryHooks,
9191
9192
  inspectFactoryHooks: () => inspectFactoryHooks,
9192
- factoryHooksPath: () => factoryHooksPath,
9193
- factoryHookCommand: () => factoryHookCommand
9193
+ factoryHooksPath: () => factoryHooksPath
9194
9194
  });
9195
9195
  import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
9196
9196
  import { join as join9 } from "node:path";
@@ -11428,7 +11428,7 @@ When \`write_knowledge\` is listed, use it after the task for durable, non-obvio
11428
11428
  Use \`review_knowledge\` only when the user asks to inspect or manage pending knowledge. Preview one item at a time and require explicit confirmation before making changes.
11429
11429
 
11430
11430
  When \`read_knowledge\` or \`write_knowledge\` returned a \`receipt_item_id\` this turn, call \`finalize_session_knowledge\` exactly once at the end of the turn — after completing the task, immediately before your final reply — passing all receipt_item_ids from this turn. Never call it when the current turn produced no receipt_item_id, and never call it more than once per turn.
11431
- `, RULE_TARGETS, SUPPORTED_RULE_AGENT_IDS;
11431
+ `, RULE_TARGETS;
11432
11432
  var init_installer = __esm(() => {
11433
11433
  DOSU_RULE_SECTION_START = `<!-- dosu:rules:start v${DOSU_RULE_SECTION_VERSION} -->`;
11434
11434
  DOSU_RULE_SECTION_START_RE = /<!-- dosu:rules:start(?: v\d+)? -->/;
@@ -11463,7 +11463,6 @@ var init_installer = __esm(() => {
11463
11463
  path: () => join27(homedir4(), ".gemini", "GEMINI.md")
11464
11464
  }
11465
11465
  };
11466
- SUPPORTED_RULE_AGENT_IDS = Object.keys(RULE_TARGETS);
11467
11466
  });
11468
11467
 
11469
11468
  // src/setup/agents-md-step.ts
@@ -13088,7 +13087,7 @@ __export(exports_tui, {
13088
13087
  handleLogout: () => handleLogout
13089
13088
  });
13090
13089
  async function runTUI() {
13091
- console.log(import_picocolors25.default.magenta(LOGO));
13090
+ console.log(import_picocolors26.default.magenta(LOGO));
13092
13091
  const cfg = loadConfig();
13093
13092
  while (true) {
13094
13093
  const insightsReady = Boolean(cfg.active_account?.target?.space_id && cfg.active_account?.target?.deployment_id && cfg.active_account?.target?.api_key);
@@ -13202,7 +13201,7 @@ function handleLogout(cfg) {
13202
13201
  saveConfig(cfg);
13203
13202
  log.success("Credentials cleared.");
13204
13203
  }
13205
- var import_picocolors25, LOGO = `
13204
+ var import_picocolors26, LOGO = `
13206
13205
  /$$$$$$$
13207
13206
  | $$__ $$
13208
13207
  | $$ \\ $$ /$$$$$$ /$$$$$$$ /$$ /$$
@@ -13219,7 +13218,7 @@ var init_tui = __esm(() => {
13219
13218
  init_config();
13220
13219
  init_flow2();
13221
13220
  init_styles();
13222
- import_picocolors25 = __toESM(require_picocolors(), 1);
13221
+ import_picocolors26 = __toESM(require_picocolors(), 1);
13223
13222
  });
13224
13223
 
13225
13224
  // src/auth/ticket.ts
@@ -16672,6 +16671,190 @@ function topicsCommand() {
16672
16671
  return cmd;
16673
16672
  }
16674
16673
 
16674
+ // src/commands/upgrade.ts
16675
+ init_commander();
16676
+ var import_picocolors24 = __toESM(require_picocolors(), 1);
16677
+ import { spawnSync as spawnSync3 } from "node:child_process";
16678
+ import { realpathSync } from "node:fs";
16679
+ import { homedir as homedir5 } from "node:os";
16680
+ import { posix, win32 } from "node:path";
16681
+ var PACKAGE_NAME = "@dosu/cli";
16682
+ var LATEST_PACKAGE = `${PACKAGE_NAME}@latest`;
16683
+ var BREW_MANUAL_COMMAND = "brew upgrade dosu-ai/dosu/dosu";
16684
+ var NPX_COMMAND = "npx -y @dosu/cli@latest";
16685
+ var PROBE_TIMEOUT_MS = 5000;
16686
+ var RELEASES_URL = "https://github.com/dosu-ai/dosu-cli/releases/latest";
16687
+ var PACKAGE_MANAGERS = {
16688
+ npm: {
16689
+ label: "npm",
16690
+ locateArgs: ["root", "-g"],
16691
+ installArgs: ["install", "-g", LATEST_PACKAGE]
16692
+ },
16693
+ pnpm: {
16694
+ label: "pnpm",
16695
+ locateArgs: ["list", "-g", "--depth=0", "--parseable", PACKAGE_NAME],
16696
+ installArgs: ["add", "-g", LATEST_PACKAGE]
16697
+ },
16698
+ yarn: {
16699
+ label: "Yarn Classic",
16700
+ locateArgs: ["--silent", "global", "dir"],
16701
+ installArgs: ["global", "add", LATEST_PACKAGE]
16702
+ }
16703
+ };
16704
+ function isAbsoluteCommandProcessor(value) {
16705
+ return Boolean(value && win32.isAbsolute(value) && win32.basename(value).toLowerCase() === "cmd.exe");
16706
+ }
16707
+ function windowsCommandProcessor(env = process.env) {
16708
+ if (isAbsoluteCommandProcessor(env.ComSpec))
16709
+ return env.ComSpec;
16710
+ const systemRoot = env.SystemRoot && win32.isAbsolute(env.SystemRoot) ? env.SystemRoot : "C:\\Windows";
16711
+ return win32.join(systemRoot, "System32", "cmd.exe");
16712
+ }
16713
+ function safePackageManagerEnv(env) {
16714
+ return {
16715
+ ...env,
16716
+ COREPACK_ENABLE_NETWORK: "0",
16717
+ COREPACK_ENABLE_PROJECT_SPEC: "0",
16718
+ YARN_IGNORE_PATH: "1"
16719
+ };
16720
+ }
16721
+ function buildPackageManagerInvocation(manager, action, platform4 = process.platform, comSpec, env = process.env) {
16722
+ const args = action === "locate" ? PACKAGE_MANAGERS[manager].locateArgs : PACKAGE_MANAGERS[manager].installArgs;
16723
+ const safeEnv = safePackageManagerEnv(env);
16724
+ if (platform4 === "win32") {
16725
+ return {
16726
+ command: isAbsoluteCommandProcessor(comSpec) ? comSpec : windowsCommandProcessor(env),
16727
+ args: ["/d", "/s", "/c", [manager, ...args].join(" ")],
16728
+ env: { ...safeEnv, NoDefaultCurrentDirectoryInExePath: "1" }
16729
+ };
16730
+ }
16731
+ return { command: manager, args: [...args], env: safeEnv };
16732
+ }
16733
+ function packageRoots(manager, platform4, comSpec, env, cwd) {
16734
+ const invocation = buildPackageManagerInvocation(manager, "locate", platform4, comSpec, env);
16735
+ const result = spawnSync3(invocation.command, invocation.args, {
16736
+ cwd,
16737
+ encoding: "utf8",
16738
+ env: invocation.env,
16739
+ shell: false,
16740
+ stdio: ["ignore", "pipe", "ignore"],
16741
+ timeout: PROBE_TIMEOUT_MS
16742
+ });
16743
+ if (result.status !== 0 || typeof result.stdout !== "string")
16744
+ return [];
16745
+ const path3 = platform4 === "win32" ? win32 : posix;
16746
+ const lines = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => path3.isAbsolute(line));
16747
+ if (manager === "pnpm") {
16748
+ return lines.filter((line) => path3.basename(line) === "cli" && path3.basename(path3.dirname(line)) === "@dosu" && path3.basename(path3.dirname(path3.dirname(line))) === "node_modules");
16749
+ }
16750
+ if (lines.length !== 1)
16751
+ return [];
16752
+ return [
16753
+ manager === "npm" ? path3.join(lines[0], "@dosu", "cli") : path3.join(lines[0], "node_modules", "@dosu", "cli")
16754
+ ];
16755
+ }
16756
+ function owningPackageManager(entrypoint, platform4, comSpec, env = process.env, cwd = homedir5()) {
16757
+ const path3 = platform4 === "win32" ? win32 : posix;
16758
+ if (!entrypoint || !path3.isAbsolute(entrypoint))
16759
+ return null;
16760
+ let realEntrypoint;
16761
+ try {
16762
+ realEntrypoint = realpathSync(entrypoint);
16763
+ } catch {
16764
+ return null;
16765
+ }
16766
+ const owners = Object.keys(PACKAGE_MANAGERS).filter((manager) => packageRoots(manager, platform4, comSpec, env, cwd).some((root) => {
16767
+ try {
16768
+ const relative = path3.relative(realpathSync(root), realEntrypoint);
16769
+ return relative !== ".." && !relative.startsWith(`..${path3.sep}`) && !path3.isAbsolute(relative);
16770
+ } catch {
16771
+ return false;
16772
+ }
16773
+ }));
16774
+ return owners.length === 1 ? owners[0] : null;
16775
+ }
16776
+ function upgradePlan(channel, manager, platform4, comSpec, env = process.env) {
16777
+ if (channel === "homebrew") {
16778
+ return {
16779
+ label: "Homebrew",
16780
+ command: "brew",
16781
+ args: ["upgrade", "dosu-ai/dosu/dosu"],
16782
+ manualCommand: BREW_MANUAL_COMMAND
16783
+ };
16784
+ }
16785
+ if (channel === "npm" && manager) {
16786
+ const invocation = buildPackageManagerInvocation(manager, "install", platform4, comSpec, env);
16787
+ return {
16788
+ label: PACKAGE_MANAGERS[manager].label,
16789
+ ...invocation,
16790
+ manualCommand: [manager, ...PACKAGE_MANAGERS[manager].installArgs].join(" ")
16791
+ };
16792
+ }
16793
+ return null;
16794
+ }
16795
+ function printNonGlobalPackageGuidance() {
16796
+ console.log("This Dosu copy is not a uniquely identified global package installation, so it was not changed.");
16797
+ console.log(`
16798
+ Run the latest version without installing:
16799
+ ${NPX_COMMAND}`);
16800
+ console.log(`
16801
+ Or install Dosu globally with your package manager:`);
16802
+ for (const manager of Object.keys(PACKAGE_MANAGERS)) {
16803
+ console.log(` ${manager} ${PACKAGE_MANAGERS[manager].installArgs.join(" ")}`);
16804
+ }
16805
+ }
16806
+ function runUpgrade(channel = INSTALL_CHANNEL, options = {}) {
16807
+ const platform4 = options.platform ?? process.platform;
16808
+ const env = options.env ?? process.env;
16809
+ const cwd = options.cwd ?? homedir5();
16810
+ let manager = null;
16811
+ if (channel === "npm") {
16812
+ if (isNpxInvocation(channel, env)) {
16813
+ printNonGlobalPackageGuidance();
16814
+ return 1;
16815
+ }
16816
+ manager = owningPackageManager(options.entrypoint ?? process.argv[1], platform4, options.comSpec, env, cwd);
16817
+ if (!manager) {
16818
+ printNonGlobalPackageGuidance();
16819
+ return 1;
16820
+ }
16821
+ }
16822
+ const plan = upgradePlan(channel, manager, platform4, options.comSpec, env);
16823
+ if (!plan) {
16824
+ console.log("Automatic upgrades are not available for this installation yet.");
16825
+ console.log(`Download the latest release:
16826
+ ${RELEASES_URL}`);
16827
+ return 1;
16828
+ }
16829
+ console.log(`Updating Dosu with ${plan.label}...`);
16830
+ console.log(` ${plan.manualCommand}
16831
+ `);
16832
+ const result = spawnSync3(plan.command, plan.args, {
16833
+ ...channel === "npm" ? { cwd } : {},
16834
+ ...plan.env ? { env: plan.env } : {},
16835
+ shell: false,
16836
+ stdio: "inherit"
16837
+ });
16838
+ if (result.error || result.status !== 0) {
16839
+ console.error(`
16840
+ Could not update Dosu automatically.`);
16841
+ console.error(`Run manually:
16842
+ ${plan.manualCommand}`);
16843
+ return result.status && result.status > 0 ? result.status : 1;
16844
+ }
16845
+ console.log(import_picocolors24.default.green(`
16846
+ ✓ Update command completed.`));
16847
+ console.log('Run "dosu --version" to verify.');
16848
+ return 0;
16849
+ }
16850
+ function upgradeCommand() {
16851
+ return new Command("upgrade").description("Update Dosu to the latest version").action(() => {
16852
+ const status = runUpgrade();
16853
+ if (status !== 0)
16854
+ process.exitCode = status;
16855
+ });
16856
+ }
16857
+
16675
16858
  // src/cli/cli.ts
16676
16859
  init_config();
16677
16860
  init_logger();
@@ -16682,13 +16865,17 @@ init_skill_update_check();
16682
16865
  // src/version/update-check.ts
16683
16866
  init_config();
16684
16867
  init_logger();
16685
- var import_picocolors24 = __toESM(require_picocolors(), 1);
16868
+ var import_picocolors25 = __toESM(require_picocolors(), 1);
16686
16869
  import { existsSync as existsSync19, mkdirSync as mkdirSync10, readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "node:fs";
16687
16870
  import { join as join30 } from "node:path";
16688
16871
  var CACHE_FILENAME3 = "update-check.json";
16689
- var CHECK_INTERVAL_MS3 = 24 * 60 * 60 * 1000;
16690
- var FETCH_TIMEOUT_MS3 = 5000;
16872
+ var CHECK_INTERVAL_MS3 = 6 * 60 * 60 * 1000;
16873
+ var FETCH_TIMEOUT_MS3 = 1000;
16691
16874
  var REGISTRY_URL = "https://registry.npmjs.org/-/package/@dosu/cli/dist-tags";
16875
+ var 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-]+)*)?$/;
16876
+ function isValidVersion(value) {
16877
+ return typeof value === "string" && SEMVER_PATTERN.test(value);
16878
+ }
16692
16879
  function stripPrerelease(version) {
16693
16880
  return version.replace(/[-+].*$/, "");
16694
16881
  }
@@ -16715,7 +16902,7 @@ function readCache() {
16715
16902
  if (!existsSync19(path3))
16716
16903
  return null;
16717
16904
  const data = JSON.parse(readFileSync17(path3, "utf-8"));
16718
- if (typeof data.lastCheck === "number" && typeof data.latestVersion === "string") {
16905
+ if (typeof data.lastCheck === "number" && isValidVersion(data.latestVersion)) {
16719
16906
  return data;
16720
16907
  }
16721
16908
  return null;
@@ -16741,46 +16928,71 @@ async function fetchLatestVersion() {
16741
16928
  return null;
16742
16929
  const data = await resp.json();
16743
16930
  const latest = data.latest;
16744
- return typeof latest === "string" ? latest : null;
16931
+ return isValidVersion(latest) ? latest : null;
16745
16932
  } catch {
16746
16933
  return null;
16747
16934
  } finally {
16748
16935
  clearTimeout(timeout);
16749
16936
  }
16750
16937
  }
16751
- function buildUpdateHint(channel) {
16752
- if (channel === "homebrew")
16753
- return 'Run "brew upgrade dosu"';
16754
- if (channel === "binary")
16755
- return "Download from https://github.com/dosu-ai/dosu-cli/releases";
16756
- return 'Run "npm update -g @dosu/cli"';
16938
+ function buildUpdateHint(channel, npx = false) {
16939
+ if (channel === "npm" && npx) {
16940
+ return 'Use "npx -y @dosu/cli@latest" for the next Dosu command';
16941
+ }
16942
+ return 'Run "dosu upgrade"';
16943
+ }
16944
+ function buildUpdateNotice(current, latest, channel, interactive, npx = false) {
16945
+ const hint = buildUpdateHint(channel, npx);
16946
+ if (interactive) {
16947
+ const versionMessage = `Update available: ${current} → ${latest}`;
16948
+ const contentWidth = Math.max(versionMessage.length, hint.length);
16949
+ const innerWidth = contentWidth + 4;
16950
+ const horizontal = "─".repeat(innerWidth);
16951
+ const emptyLine = `│${" ".repeat(innerWidth)}│`;
16952
+ const frameLines = [
16953
+ `┌${horizontal}┐`,
16954
+ emptyLine,
16955
+ `│ ${versionMessage}${" ".repeat(contentWidth - versionMessage.length)} │`,
16956
+ `│ ${hint}${" ".repeat(contentWidth - hint.length)} │`,
16957
+ emptyLine,
16958
+ `└${horizontal}┘`
16959
+ ];
16960
+ return `
16961
+ ${frameLines.map((line) => import_picocolors25.default.yellow(line)).join(`
16962
+ `)}
16963
+ `;
16964
+ }
16965
+ const agentAction = hint[0].toLowerCase() + hint.slice(1);
16966
+ const verifyCommand = npx ? "npx -y @dosu/cli@latest --version" : "dosu --version";
16967
+ return `
16968
+ [dosu:update] Update available: ${current} → ${latest}
16969
+ ` + `Tell the user Dosu CLI is outdated. After they approve, ${agentAction}, ` + `then verify with "${verifyCommand}".
16970
+ `;
16757
16971
  }
16758
16972
  function displayNotice2(current, latest) {
16759
- const msg = `
16760
- ${import_picocolors24.default.yellow(` Update available: ${current} → ${latest}`)}
16761
- ` + `${import_picocolors24.default.dim(` ${buildUpdateHint(INSTALL_CHANNEL)}`)}
16762
- `;
16763
- console.error(msg);
16973
+ console.error(buildUpdateNotice(current, latest, INSTALL_CHANNEL, process.stderr.isTTY === true, isNpxInvocation()));
16764
16974
  }
16765
- function checkForUpdates() {
16975
+ async function checkForUpdates() {
16766
16976
  try {
16767
16977
  const cache = readCache();
16768
- if (cache && isNewerVersion(cache.latestVersion, VERSION)) {
16769
- displayNotice2(VERSION, cache.latestVersion);
16770
- }
16771
16978
  const isStale = !cache || Date.now() - cache.lastCheck > CHECK_INTERVAL_MS3;
16772
- if (isStale) {
16773
- fetchLatestVersion().then((latest) => {
16774
- writeCache({
16775
- lastCheck: Date.now(),
16776
- latestVersion: latest ?? cache?.latestVersion ?? VERSION
16777
- });
16778
- if (latest) {
16779
- logger.debug("update-check", `Cached latest version: ${latest}`);
16780
- }
16781
- }).catch((err) => {
16782
- logger.error("update-check", `Background fetch failed: ${err}`);
16783
- });
16979
+ if (!isStale) {
16980
+ if (isNewerVersion(cache.latestVersion, VERSION)) {
16981
+ displayNotice2(VERSION, cache.latestVersion);
16982
+ }
16983
+ return;
16984
+ }
16985
+ const latest = await fetchLatestVersion();
16986
+ const latestKnownVersion = latest ?? cache?.latestVersion ?? VERSION;
16987
+ writeCache({
16988
+ lastCheck: Date.now(),
16989
+ latestVersion: latestKnownVersion
16990
+ });
16991
+ if (latest) {
16992
+ logger.debug("update-check", `Cached latest version: ${latest}`);
16993
+ }
16994
+ if (isNewerVersion(latestKnownVersion, VERSION)) {
16995
+ displayNotice2(VERSION, latestKnownVersion);
16784
16996
  }
16785
16997
  } catch (err) {
16786
16998
  logger.error("update-check", `Update check failed: ${err}`);
@@ -16793,6 +17005,9 @@ function isHookEntrypointInvocation(argv) {
16793
17005
  const i2 = argv.indexOf("hooks");
16794
17006
  return i2 >= 0 && HOOK_ENTRYPOINTS.has(argv[i2 + 1] ?? "");
16795
17007
  }
17008
+ function shouldRunBackgroundChecks(actionName, argv) {
17009
+ return actionName !== "upgrade" && !isHookEntrypointInvocation(argv);
17010
+ }
16796
17011
  function suggestClosestCommand(input, program2) {
16797
17012
  let best;
16798
17013
  let bestDistance = Infinity;
@@ -16821,11 +17036,13 @@ function editDistance2(a3, b2) {
16821
17036
  }
16822
17037
  function createProgram() {
16823
17038
  const program2 = new Command;
16824
- program2.name("dosu").description("Dosu CLI - Manage MCP servers for AI tools").version(getVersionString(), "-v, --version").helpCommand("help [command]", "Show help for a command").option("--debug", "Enable debug logging to stderr", false).hook("preAction", (thisCommand) => {
17039
+ program2.name("dosu").description("Dosu CLI - Manage MCP servers for AI tools").version(getVersionString(), "-v, --version").helpCommand("help [command]", "Show help for a command").option("--debug", "Enable debug logging to stderr", false).hook("preAction", async (thisCommand, actionCommand) => {
16825
17040
  const opts = thisCommand.optsWithGlobals();
16826
17041
  logger.init({ debug: opts.debug });
16827
- if (!isHookEntrypointInvocation(process.argv)) {
16828
- checkForUpdates();
17042
+ if (shouldRunBackgroundChecks(actionCommand.name(), process.argv)) {
17043
+ if (!process.env.CI) {
17044
+ await checkForUpdates();
17045
+ }
16829
17046
  checkForSkillUpdates();
16830
17047
  checkForReadyTasks();
16831
17048
  }
@@ -17070,6 +17287,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
17070
17287
  program2.addCommand(topicsCommand());
17071
17288
  program2.addCommand(threadsCommand());
17072
17289
  program2.addCommand(skillCommand());
17290
+ program2.addCommand(upgradeCommand());
17073
17291
  program2.command("setup").description("Set up Dosu MCP for your AI tools").option("--deployment <id>", "Skip to tool configuration for a specific MCP").option("--mode <mode>", "Force OSS or Cloud mode, skipping the interactive prompt (oss|cloud)").option("--agent", "Run non-interactive setup designed for coding agents (requires --tool)").option("--tool <id>", "Configure a single AI tool by id (claude, cursor, codex, …). Required with --agent.").option("--login-ticket <ticket>", "Resume an --agent setup by redeeming a ticket from a previous run").action(async (opts) => {
17074
17292
  if (opts.agent) {
17075
17293
  if (!opts.tool) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.43.0-alpha.1",
3
+ "version": "0.44.0",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Manage MCP servers for AI tools",
6
6
  "license": "MIT",
@@ -29,6 +29,7 @@
29
29
  "lint": "bunx biome lint .",
30
30
  "format": "bunx biome format .",
31
31
  "check": "bunx biome check .",
32
+ "deadcode": "knip --no-config-hints && knip --production --config knip.production.jsonc --no-config-hints",
32
33
  "prepack": "bun run build:npm"
33
34
  },
34
35
  "engines": {
@@ -36,6 +37,7 @@
36
37
  },
37
38
  "devDependencies": {
38
39
  "@biomejs/biome": "^2.5.0",
40
+ "@clack/core": "1.4.2",
39
41
  "@clack/prompts": "^1.6.0",
40
42
  "@semantic-release/changelog": "^6.0.3",
41
43
  "@semantic-release/exec": "^7.1.0",
@@ -45,6 +47,7 @@
45
47
  "@types/bun": "^1.3.14",
46
48
  "@vitest/coverage-v8": "^4.1.9",
47
49
  "commander": "^15.0.0",
50
+ "knip": "6.32.0",
48
51
  "open": "^11.0.0",
49
52
  "picocolors": "^1.1.1",
50
53
  "semantic-release": "^25.0.5",