@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.
- package/README.md +3 -0
- package/bin/dosu.js +264 -46
- 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.
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
16690
|
-
var FETCH_TIMEOUT_MS3 =
|
|
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" &&
|
|
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
|
|
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 === "
|
|
16753
|
-
return '
|
|
16754
|
-
|
|
16755
|
-
|
|
16756
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16774
|
-
|
|
16775
|
-
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
|
|
16780
|
-
|
|
16781
|
-
|
|
16782
|
-
|
|
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 (
|
|
16828
|
-
|
|
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.
|
|
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",
|