@dosu/cli 0.60.1 → 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.
- package/README.md +4 -2
- package/bin/dosu.js +932 -670
- package/package.json +1 -1
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.
|
|
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 = "
|
|
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
|
|
|
@@ -61641,283 +61641,6 @@ var init_topics = __esm(() => {
|
|
|
61641
61641
|
import_picocolors29 = __toESM(require_picocolors(), 1);
|
|
61642
61642
|
});
|
|
61643
61643
|
|
|
61644
|
-
// src/commands/upgrade.ts
|
|
61645
|
-
import { spawnSync } from "node:child_process";
|
|
61646
|
-
import { realpathSync as realpathSync2 } from "node:fs";
|
|
61647
|
-
import { homedir as homedir9 } from "node:os";
|
|
61648
|
-
import { posix, win32 as win322 } from "node:path";
|
|
61649
|
-
function isAbsoluteCommandProcessor(value) {
|
|
61650
|
-
return Boolean(value && win322.isAbsolute(value) && win322.basename(value).toLowerCase() === "cmd.exe");
|
|
61651
|
-
}
|
|
61652
|
-
function windowsCommandProcessor(env = process.env) {
|
|
61653
|
-
if (isAbsoluteCommandProcessor(env.ComSpec))
|
|
61654
|
-
return env.ComSpec;
|
|
61655
|
-
const systemRoot = env.SystemRoot && win322.isAbsolute(env.SystemRoot) ? env.SystemRoot : "C:\\Windows";
|
|
61656
|
-
return win322.join(systemRoot, "System32", "cmd.exe");
|
|
61657
|
-
}
|
|
61658
|
-
function safePackageManagerEnv(env) {
|
|
61659
|
-
return {
|
|
61660
|
-
...env,
|
|
61661
|
-
COREPACK_ENABLE_NETWORK: "0",
|
|
61662
|
-
COREPACK_ENABLE_PROJECT_SPEC: "0",
|
|
61663
|
-
YARN_IGNORE_PATH: "1"
|
|
61664
|
-
};
|
|
61665
|
-
}
|
|
61666
|
-
function buildPackageManagerInvocation(manager, action, platform = process.platform, comSpec, env = process.env) {
|
|
61667
|
-
const args = action === "locate" ? PACKAGE_MANAGERS[manager].locateArgs : PACKAGE_MANAGERS[manager].installArgs;
|
|
61668
|
-
const safeEnv = safePackageManagerEnv(env);
|
|
61669
|
-
if (platform === "win32") {
|
|
61670
|
-
return {
|
|
61671
|
-
command: isAbsoluteCommandProcessor(comSpec) ? comSpec : windowsCommandProcessor(env),
|
|
61672
|
-
args: ["/d", "/s", "/c", [manager, ...args].join(" ")],
|
|
61673
|
-
env: { ...safeEnv, NoDefaultCurrentDirectoryInExePath: "1" }
|
|
61674
|
-
};
|
|
61675
|
-
}
|
|
61676
|
-
return { command: manager, args: [...args], env: safeEnv };
|
|
61677
|
-
}
|
|
61678
|
-
function packageRoots(manager, platform, comSpec, env, cwd) {
|
|
61679
|
-
const invocation = buildPackageManagerInvocation(manager, "locate", platform, comSpec, env);
|
|
61680
|
-
const result = spawnSync(invocation.command, invocation.args, {
|
|
61681
|
-
cwd,
|
|
61682
|
-
encoding: "utf8",
|
|
61683
|
-
env: invocation.env,
|
|
61684
|
-
shell: false,
|
|
61685
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
61686
|
-
timeout: PROBE_TIMEOUT_MS
|
|
61687
|
-
});
|
|
61688
|
-
if (result.status !== 0 || typeof result.stdout !== "string")
|
|
61689
|
-
return [];
|
|
61690
|
-
const path = platform === "win32" ? win322 : posix;
|
|
61691
|
-
const lines = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => path.isAbsolute(line));
|
|
61692
|
-
if (manager === "pnpm") {
|
|
61693
|
-
return lines.filter((line) => path.basename(line) === "cli" && path.basename(path.dirname(line)) === "@dosu" && path.basename(path.dirname(path.dirname(line))) === "node_modules");
|
|
61694
|
-
}
|
|
61695
|
-
if (lines.length !== 1)
|
|
61696
|
-
return [];
|
|
61697
|
-
return [
|
|
61698
|
-
manager === "npm" ? path.join(lines[0], "@dosu", "cli") : path.join(lines[0], "node_modules", "@dosu", "cli")
|
|
61699
|
-
];
|
|
61700
|
-
}
|
|
61701
|
-
function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd = homedir9()) {
|
|
61702
|
-
const path = platform === "win32" ? win322 : posix;
|
|
61703
|
-
if (!entrypoint || !path.isAbsolute(entrypoint))
|
|
61704
|
-
return null;
|
|
61705
|
-
let realEntrypoint;
|
|
61706
|
-
try {
|
|
61707
|
-
realEntrypoint = realpathSync2(entrypoint);
|
|
61708
|
-
} catch {
|
|
61709
|
-
return null;
|
|
61710
|
-
}
|
|
61711
|
-
const owners = Object.keys(PACKAGE_MANAGERS).filter((manager) => packageRoots(manager, platform, comSpec, env, cwd).some((root) => {
|
|
61712
|
-
try {
|
|
61713
|
-
const relative = path.relative(realpathSync2(root), realEntrypoint);
|
|
61714
|
-
return relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
61715
|
-
} catch {
|
|
61716
|
-
return false;
|
|
61717
|
-
}
|
|
61718
|
-
}));
|
|
61719
|
-
return owners.length === 1 ? owners[0] : null;
|
|
61720
|
-
}
|
|
61721
|
-
function upgradePlan(channel, manager, platform, comSpec, env = process.env) {
|
|
61722
|
-
if (channel === "homebrew") {
|
|
61723
|
-
return {
|
|
61724
|
-
label: "Homebrew",
|
|
61725
|
-
command: "brew",
|
|
61726
|
-
args: ["upgrade", "dosu-ai/dosu/dosu"],
|
|
61727
|
-
manualCommand: BREW_MANUAL_COMMAND
|
|
61728
|
-
};
|
|
61729
|
-
}
|
|
61730
|
-
if (channel === "npm" && manager) {
|
|
61731
|
-
const invocation = buildPackageManagerInvocation(manager, "install", platform, comSpec, env);
|
|
61732
|
-
return {
|
|
61733
|
-
label: PACKAGE_MANAGERS[manager].label,
|
|
61734
|
-
...invocation,
|
|
61735
|
-
manualCommand: [manager, ...PACKAGE_MANAGERS[manager].installArgs].join(" ")
|
|
61736
|
-
};
|
|
61737
|
-
}
|
|
61738
|
-
return null;
|
|
61739
|
-
}
|
|
61740
|
-
function printNonGlobalPackageGuidance() {
|
|
61741
|
-
console.log("This Dosu copy is not a uniquely identified global package installation, so it was not changed.");
|
|
61742
|
-
console.log(`
|
|
61743
|
-
Run the latest version without installing:
|
|
61744
|
-
${NPX_COMMAND}`);
|
|
61745
|
-
console.log(`
|
|
61746
|
-
Or install Dosu globally with your package manager:`);
|
|
61747
|
-
for (const manager of Object.keys(PACKAGE_MANAGERS)) {
|
|
61748
|
-
console.log(` ${manager} ${PACKAGE_MANAGERS[manager].installArgs.join(" ")}`);
|
|
61749
|
-
}
|
|
61750
|
-
}
|
|
61751
|
-
function runUpgrade(channel = INSTALL_CHANNEL, options = {}) {
|
|
61752
|
-
const platform = options.platform ?? process.platform;
|
|
61753
|
-
const env = options.env ?? process.env;
|
|
61754
|
-
const cwd = options.cwd ?? homedir9();
|
|
61755
|
-
let manager = null;
|
|
61756
|
-
if (channel === "npm") {
|
|
61757
|
-
if (isNpxInvocation(channel, env)) {
|
|
61758
|
-
printNonGlobalPackageGuidance();
|
|
61759
|
-
return 1;
|
|
61760
|
-
}
|
|
61761
|
-
manager = owningPackageManager(options.entrypoint ?? process.argv[1], platform, options.comSpec, env, cwd);
|
|
61762
|
-
if (!manager) {
|
|
61763
|
-
if (env.DOSU_DEV === "true") {
|
|
61764
|
-
console.log("DOSU_DEV=true and this copy is not a global package: skipping the package install.");
|
|
61765
|
-
return 0;
|
|
61766
|
-
}
|
|
61767
|
-
printNonGlobalPackageGuidance();
|
|
61768
|
-
return 1;
|
|
61769
|
-
}
|
|
61770
|
-
}
|
|
61771
|
-
const plan = upgradePlan(channel, manager, platform, options.comSpec, env);
|
|
61772
|
-
if (!plan) {
|
|
61773
|
-
console.log("Automatic upgrades are not available for this installation yet.");
|
|
61774
|
-
console.log(`Download the latest release:
|
|
61775
|
-
${RELEASES_URL}`);
|
|
61776
|
-
return 1;
|
|
61777
|
-
}
|
|
61778
|
-
console.log(`Updating Dosu with ${plan.label}...`);
|
|
61779
|
-
console.log(` ${plan.manualCommand}
|
|
61780
|
-
`);
|
|
61781
|
-
const result = spawnSync(plan.command, plan.args, {
|
|
61782
|
-
...channel === "npm" ? { cwd } : {},
|
|
61783
|
-
...plan.env ? { env: plan.env } : {},
|
|
61784
|
-
shell: false,
|
|
61785
|
-
stdio: "inherit"
|
|
61786
|
-
});
|
|
61787
|
-
if (result.error || result.status !== 0) {
|
|
61788
|
-
console.error(`
|
|
61789
|
-
Could not update Dosu automatically.`);
|
|
61790
|
-
console.error(`Run manually:
|
|
61791
|
-
${plan.manualCommand}`);
|
|
61792
|
-
return result.status && result.status > 0 ? result.status : 1;
|
|
61793
|
-
}
|
|
61794
|
-
console.log(import_picocolors30.default.green(`
|
|
61795
|
-
✓ Update command completed.`));
|
|
61796
|
-
console.log('Run "dosu --version" to verify.');
|
|
61797
|
-
return 0;
|
|
61798
|
-
}
|
|
61799
|
-
function postUpgradeArgs(interactive) {
|
|
61800
|
-
return interactive ? ["setup"] : ["mcp", "refresh"];
|
|
61801
|
-
}
|
|
61802
|
-
function newBinaryInvocation(channel, args, entrypoint = process.argv[1], execPath = process.execPath) {
|
|
61803
|
-
if (channel === "npm") {
|
|
61804
|
-
return entrypoint ? { command: execPath, args: [entrypoint, ...args] } : null;
|
|
61805
|
-
}
|
|
61806
|
-
if (channel === "homebrew") {
|
|
61807
|
-
return { command: "dosu", args };
|
|
61808
|
-
}
|
|
61809
|
-
return null;
|
|
61810
|
-
}
|
|
61811
|
-
function isInteractiveTerminal() {
|
|
61812
|
-
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
61813
|
-
}
|
|
61814
|
-
function setupAgentsWithNewBinary(channel, interactive, options) {
|
|
61815
|
-
const invocation = newBinaryInvocation(channel, postUpgradeArgs(interactive), options.entrypoint ?? process.argv[1]);
|
|
61816
|
-
if (!invocation) {
|
|
61817
|
-
console.error(SETUP_FALLBACK);
|
|
61818
|
-
return;
|
|
61819
|
-
}
|
|
61820
|
-
console.log(interactive ? `
|
|
61821
|
-
Running setup with the new version to update your AI agents...
|
|
61822
|
-
` : `
|
|
61823
|
-
Refreshing agent MCP configs with the new version...`);
|
|
61824
|
-
const result = spawnSync(invocation.command, invocation.args, {
|
|
61825
|
-
cwd: options.cwd ?? homedir9(),
|
|
61826
|
-
shell: false,
|
|
61827
|
-
stdio: "inherit"
|
|
61828
|
-
});
|
|
61829
|
-
if (result.error || result.status !== 0) {
|
|
61830
|
-
console.error(SETUP_FALLBACK);
|
|
61831
|
-
}
|
|
61832
|
-
}
|
|
61833
|
-
async function completeUpgrade(channel = INSTALL_CHANNEL, options = {}) {
|
|
61834
|
-
const status = runUpgrade(channel, options);
|
|
61835
|
-
if (status !== 0)
|
|
61836
|
-
return status;
|
|
61837
|
-
const interactive = options.interactive ?? isInteractiveTerminal();
|
|
61838
|
-
if (!interactive) {
|
|
61839
|
-
console.log("Updating Dosu skills...");
|
|
61840
|
-
try {
|
|
61841
|
-
const result = await installSkill();
|
|
61842
|
-
if (result.success) {
|
|
61843
|
-
console.log(import_picocolors30.default.green("✓ Skills updated."));
|
|
61844
|
-
} else {
|
|
61845
|
-
console.error('Skills could not be refreshed. Run "dosu skill update" to retry.');
|
|
61846
|
-
}
|
|
61847
|
-
} catch {
|
|
61848
|
-
console.error('Skills could not be refreshed. Run "dosu skill update" to retry.');
|
|
61849
|
-
}
|
|
61850
|
-
}
|
|
61851
|
-
setupAgentsWithNewBinary(channel, interactive, options);
|
|
61852
|
-
return 0;
|
|
61853
|
-
}
|
|
61854
|
-
function upgradeCommand() {
|
|
61855
|
-
return new Command("upgrade").description("Update Dosu to the latest version, then re-run setup to update your AI agents").action(async () => {
|
|
61856
|
-
const status = await completeUpgrade();
|
|
61857
|
-
if (status !== 0)
|
|
61858
|
-
process.exitCode = status;
|
|
61859
|
-
});
|
|
61860
|
-
}
|
|
61861
|
-
var import_picocolors30, PACKAGE_NAME = "@dosu/cli", LATEST_PACKAGE, BREW_MANUAL_COMMAND = "brew upgrade dosu-ai/dosu/dosu", NPX_COMMAND = "npx -y @dosu/cli@latest", PROBE_TIMEOUT_MS = 5000, RELEASES_URL = "https://github.com/dosu-ai/dosu-cli/releases/latest", PACKAGE_MANAGERS, SETUP_FALLBACK = 'Run "dosu setup" to finish updating your AI agents.';
|
|
61862
|
-
var init_upgrade = __esm(() => {
|
|
61863
|
-
init_commander();
|
|
61864
|
-
init_skill();
|
|
61865
|
-
import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
61866
|
-
LATEST_PACKAGE = `${PACKAGE_NAME}@latest`;
|
|
61867
|
-
PACKAGE_MANAGERS = {
|
|
61868
|
-
npm: {
|
|
61869
|
-
label: "npm",
|
|
61870
|
-
locateArgs: ["root", "-g"],
|
|
61871
|
-
installArgs: ["install", "-g", LATEST_PACKAGE]
|
|
61872
|
-
},
|
|
61873
|
-
pnpm: {
|
|
61874
|
-
label: "pnpm",
|
|
61875
|
-
locateArgs: ["list", "-g", "--depth=0", "--parseable", PACKAGE_NAME],
|
|
61876
|
-
installArgs: ["add", "-g", LATEST_PACKAGE]
|
|
61877
|
-
},
|
|
61878
|
-
yarn: {
|
|
61879
|
-
label: "Yarn Classic",
|
|
61880
|
-
locateArgs: ["--silent", "global", "dir"],
|
|
61881
|
-
installArgs: ["global", "add", LATEST_PACKAGE]
|
|
61882
|
-
}
|
|
61883
|
-
};
|
|
61884
|
-
});
|
|
61885
|
-
|
|
61886
|
-
// src/debug/follow.ts
|
|
61887
|
-
import { closeSync as closeSync6, openSync as openSync6, readSync as readSync5, statSync as statSync8 } from "node:fs";
|
|
61888
|
-
function createLogFollower(path, emit) {
|
|
61889
|
-
const sizeOf = () => {
|
|
61890
|
-
try {
|
|
61891
|
-
return statSync8(path).size;
|
|
61892
|
-
} catch {
|
|
61893
|
-
return 0;
|
|
61894
|
-
}
|
|
61895
|
-
};
|
|
61896
|
-
let offset = sizeOf();
|
|
61897
|
-
return {
|
|
61898
|
-
poll() {
|
|
61899
|
-
const size = sizeOf();
|
|
61900
|
-
if (size < offset)
|
|
61901
|
-
offset = 0;
|
|
61902
|
-
if (size === offset)
|
|
61903
|
-
return;
|
|
61904
|
-
try {
|
|
61905
|
-
const fd = openSync6(path, "r");
|
|
61906
|
-
try {
|
|
61907
|
-
const buf = Buffer.alloc(size - offset);
|
|
61908
|
-
const read = readSync5(fd, buf, 0, buf.length, offset);
|
|
61909
|
-
offset += read;
|
|
61910
|
-
if (read > 0)
|
|
61911
|
-
emit(buf.toString("utf-8", 0, read));
|
|
61912
|
-
} finally {
|
|
61913
|
-
closeSync6(fd);
|
|
61914
|
-
}
|
|
61915
|
-
} catch {}
|
|
61916
|
-
}
|
|
61917
|
-
};
|
|
61918
|
-
}
|
|
61919
|
-
var init_follow = () => {};
|
|
61920
|
-
|
|
61921
61644
|
// src/mcp/providers/base.ts
|
|
61922
61645
|
function createJSONProvider(opts) {
|
|
61923
61646
|
const buildServer = opts.buildServer ?? defaultBuildServer;
|
|
@@ -62449,15 +62172,15 @@ var init_vscode = __esm(() => {
|
|
|
62449
62172
|
});
|
|
62450
62173
|
|
|
62451
62174
|
// src/mcp/providers/windsurf.ts
|
|
62452
|
-
import { homedir as
|
|
62175
|
+
import { homedir as homedir9 } from "node:os";
|
|
62453
62176
|
import { join as join36 } from "node:path";
|
|
62454
62177
|
var WindsurfProvider = () => createJSONProvider({
|
|
62455
62178
|
providerName: "Windsurf",
|
|
62456
62179
|
providerID: "windsurf",
|
|
62457
62180
|
local: false,
|
|
62458
62181
|
priorityValue: 9,
|
|
62459
|
-
paths: [join36(
|
|
62460
|
-
globalPath: join36(
|
|
62182
|
+
paths: [join36(homedir9(), ".codeium", "windsurf")],
|
|
62183
|
+
globalPath: join36(homedir9(), ".codeium", "windsurf", "mcp_config.json"),
|
|
62461
62184
|
topKey: "mcpServers"
|
|
62462
62185
|
});
|
|
62463
62186
|
var init_windsurf = __esm(() => {
|
|
@@ -62466,14 +62189,14 @@ var init_windsurf = __esm(() => {
|
|
|
62466
62189
|
|
|
62467
62190
|
// src/mcp/providers/zed.ts
|
|
62468
62191
|
import { rmSync as rmSync6 } from "node:fs";
|
|
62469
|
-
import { homedir as
|
|
62192
|
+
import { homedir as homedir10, platform as platform3 } from "node:os";
|
|
62470
62193
|
import { join as join37 } from "node:path";
|
|
62471
62194
|
function zedConfigDir() {
|
|
62472
62195
|
const os = platform3();
|
|
62473
62196
|
if (os === "win32")
|
|
62474
62197
|
return join37(appSupportDir(), "Zed");
|
|
62475
62198
|
if (os === "darwin")
|
|
62476
|
-
return join37(
|
|
62199
|
+
return join37(homedir10(), ".config", "zed");
|
|
62477
62200
|
return join37(appSupportDir(), "zed");
|
|
62478
62201
|
}
|
|
62479
62202
|
function zedDataDir() {
|
|
@@ -62482,7 +62205,7 @@ function zedDataDir() {
|
|
|
62482
62205
|
return join37(appSupportDir(), "Zed");
|
|
62483
62206
|
if (os === "win32")
|
|
62484
62207
|
return join37(process.env.LOCALAPPDATA ?? "", "Zed");
|
|
62485
|
-
return join37(process.env.XDG_DATA_HOME ?? join37(
|
|
62208
|
+
return join37(process.env.XDG_DATA_HOME ?? join37(homedir10(), ".local", "share"), "zed");
|
|
62486
62209
|
}
|
|
62487
62210
|
function legacyDarwinSettingsPath() {
|
|
62488
62211
|
return platform3() === "darwin" ? join37(appSupportDir(), "Zed", "settings.json") : null;
|
|
@@ -62618,10 +62341,204 @@ var init_refresh = __esm(() => {
|
|
|
62618
62341
|
init_providers();
|
|
62619
62342
|
});
|
|
62620
62343
|
|
|
62621
|
-
// src/version/update
|
|
62622
|
-
import {
|
|
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";
|
|
62623
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
|
+
}
|
|
62624
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) {
|
|
62625
62542
|
return typeof value === "string" && SEMVER_PATTERN.test(value);
|
|
62626
62543
|
}
|
|
62627
62544
|
function stripPrerelease(version) {
|
|
@@ -62642,15 +62559,15 @@ function isNewerVersion(latest, current) {
|
|
|
62642
62559
|
return false;
|
|
62643
62560
|
}
|
|
62644
62561
|
function getCachePath2() {
|
|
62645
|
-
return
|
|
62562
|
+
return join39(getConfigDir(), CACHE_FILENAME3);
|
|
62646
62563
|
}
|
|
62647
62564
|
function readCache() {
|
|
62648
62565
|
try {
|
|
62649
62566
|
const path = getCachePath2();
|
|
62650
|
-
if (!
|
|
62567
|
+
if (!existsSync24(path))
|
|
62651
62568
|
return null;
|
|
62652
|
-
const data = JSON.parse(
|
|
62653
|
-
if (typeof data.lastCheck === "number" &&
|
|
62569
|
+
const data = JSON.parse(readFileSync23(path, "utf-8"));
|
|
62570
|
+
if (typeof data.lastCheck === "number" && isValidVersion2(data.latestVersion)) {
|
|
62654
62571
|
return data;
|
|
62655
62572
|
}
|
|
62656
62573
|
return null;
|
|
@@ -62661,10 +62578,10 @@ function readCache() {
|
|
|
62661
62578
|
function writeCache(cache) {
|
|
62662
62579
|
try {
|
|
62663
62580
|
const dir = getConfigDir();
|
|
62664
|
-
if (!
|
|
62665
|
-
|
|
62581
|
+
if (!existsSync24(dir)) {
|
|
62582
|
+
mkdirSync14(dir, { recursive: true, mode: 448 });
|
|
62666
62583
|
}
|
|
62667
|
-
|
|
62584
|
+
writeFileSync15(getCachePath2(), JSON.stringify(cache), { mode: 384 });
|
|
62668
62585
|
} catch {}
|
|
62669
62586
|
}
|
|
62670
62587
|
async function fetchLatestVersion() {
|
|
@@ -62676,7 +62593,7 @@ async function fetchLatestVersion() {
|
|
|
62676
62593
|
return null;
|
|
62677
62594
|
const data = await resp.json();
|
|
62678
62595
|
const latest = data.latest;
|
|
62679
|
-
return
|
|
62596
|
+
return isValidVersion2(latest) ? latest : null;
|
|
62680
62597
|
} catch {
|
|
62681
62598
|
return null;
|
|
62682
62599
|
} finally {
|
|
@@ -62692,34 +62609,47 @@ function buildUpdateHint(channel, npx = false) {
|
|
|
62692
62609
|
function styleHint(hint) {
|
|
62693
62610
|
const match = hint.match(/^(.*)("[^"]+")(.*)$/);
|
|
62694
62611
|
if (!match)
|
|
62695
|
-
return
|
|
62612
|
+
return import_picocolors30.default.dim(hint);
|
|
62696
62613
|
const [, before, command, after] = match;
|
|
62697
|
-
return [before &&
|
|
62614
|
+
return [before && import_picocolors30.default.dim(before), import_picocolors30.default.cyan(command), after && import_picocolors30.default.dim(after)].filter(Boolean).join("");
|
|
62615
|
+
}
|
|
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 `
|
|
62631
|
+
${centerBlock(box, width).join(`
|
|
62632
|
+
`)}
|
|
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
|
+
`;
|
|
62698
62648
|
}
|
|
62699
62649
|
function buildUpdateNotice(current, latest, channel, interactive, npx = false, width = process.stderr.columns ?? 80) {
|
|
62700
62650
|
const hint = buildUpdateHint(channel, npx);
|
|
62701
62651
|
if (interactive) {
|
|
62702
|
-
|
|
62703
|
-
`Update available: ${import_picocolors31.default.dim(current)} ${import_picocolors31.default.dim("→")} ${import_picocolors31.default.bold(brand(latest))}`,
|
|
62704
|
-
styleHint(hint)
|
|
62705
|
-
];
|
|
62706
|
-
const innerWidth = Math.max(...content.map(visibleWidth2)) + BOX_PADDING * 2;
|
|
62707
|
-
const framed = (line) => {
|
|
62708
|
-
const pad = innerWidth - visibleWidth2(line);
|
|
62709
|
-
const left = Math.floor(pad / 2);
|
|
62710
|
-
return `${import_picocolors31.default.yellow("│")}${" ".repeat(left)}${line}${" ".repeat(pad - left)}${import_picocolors31.default.yellow("│")}`;
|
|
62711
|
-
};
|
|
62712
|
-
const box = [
|
|
62713
|
-
import_picocolors31.default.yellow(`╭${"─".repeat(innerWidth)}╮`),
|
|
62714
|
-
framed(""),
|
|
62715
|
-
...content.map(framed),
|
|
62716
|
-
framed(""),
|
|
62717
|
-
import_picocolors31.default.yellow(`╰${"─".repeat(innerWidth)}╯`)
|
|
62718
|
-
];
|
|
62719
|
-
return `
|
|
62720
|
-
${centerBlock(box, width).join(`
|
|
62721
|
-
`)}
|
|
62722
|
-
`;
|
|
62652
|
+
return framedNotice([`Update available: ${versionArrow(current, latest)}`, styleHint(hint)], width);
|
|
62723
62653
|
}
|
|
62724
62654
|
const agentAction = hint[0].toLowerCase() + hint.slice(1);
|
|
62725
62655
|
const verifyCommand = npx ? "npx -y @dosu/cli@latest --version" : "dosu --version";
|
|
@@ -62732,8 +62662,12 @@ function getAvailableUpdate() {
|
|
|
62732
62662
|
const cache = readCache();
|
|
62733
62663
|
return cache && isNewerVersion(cache.latestVersion, VERSION) ? cache.latestVersion : null;
|
|
62734
62664
|
}
|
|
62735
|
-
function
|
|
62736
|
-
|
|
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));
|
|
62737
62671
|
}
|
|
62738
62672
|
async function checkForUpdates(options = {}) {
|
|
62739
62673
|
const notify = options.notify ?? true;
|
|
@@ -62741,8 +62675,8 @@ async function checkForUpdates(options = {}) {
|
|
|
62741
62675
|
const cache = readCache();
|
|
62742
62676
|
const isStale = !cache || Date.now() - cache.lastCheck > CHECK_INTERVAL_MS2;
|
|
62743
62677
|
if (!isStale) {
|
|
62744
|
-
if (
|
|
62745
|
-
|
|
62678
|
+
if (isNewerVersion(cache.latestVersion, VERSION)) {
|
|
62679
|
+
handleNewerVersion(cache.latestVersion, notify);
|
|
62746
62680
|
}
|
|
62747
62681
|
return;
|
|
62748
62682
|
}
|
|
@@ -62755,27 +62689,28 @@ async function checkForUpdates(options = {}) {
|
|
|
62755
62689
|
if (latest) {
|
|
62756
62690
|
logger.debug("update-check", `Cached latest version: ${latest}`);
|
|
62757
62691
|
}
|
|
62758
|
-
if (
|
|
62759
|
-
|
|
62692
|
+
if (isNewerVersion(latestKnownVersion, VERSION)) {
|
|
62693
|
+
handleNewerVersion(latestKnownVersion, notify);
|
|
62760
62694
|
}
|
|
62761
62695
|
} catch (err) {
|
|
62762
62696
|
logger.error("update-check", `Update check failed: ${err}`);
|
|
62763
62697
|
}
|
|
62764
62698
|
}
|
|
62765
|
-
var
|
|
62699
|
+
var import_picocolors30, CACHE_FILENAME3 = "update-check.json", CHECK_INTERVAL_MS2, FETCH_TIMEOUT_MS2 = 1000, REGISTRY_URL = "https://registry.npmjs.org/-/package/@dosu/cli/dist-tags", SEMVER_PATTERN, BOX_PADDING = 3;
|
|
62766
62700
|
var init_update_check = __esm(() => {
|
|
62767
62701
|
init_config();
|
|
62768
62702
|
init_logger();
|
|
62769
62703
|
init_styles();
|
|
62770
62704
|
init_layout();
|
|
62771
|
-
|
|
62705
|
+
init_auto_update();
|
|
62706
|
+
import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
62772
62707
|
CHECK_INTERVAL_MS2 = 6 * 60 * 60 * 1000;
|
|
62773
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-]+)*)?$/;
|
|
62774
62709
|
});
|
|
62775
62710
|
|
|
62776
62711
|
// src/version/mcp-refresh-check.ts
|
|
62777
|
-
import { existsSync as
|
|
62778
|
-
import { join as
|
|
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";
|
|
62779
62714
|
function needsMcpRefresh(previous, current) {
|
|
62780
62715
|
if (previous === null)
|
|
62781
62716
|
return true;
|
|
@@ -62785,14 +62720,14 @@ function needsMcpRefresh(previous, current) {
|
|
|
62785
62720
|
return MCP_FORMAT_CHANGES.some((change) => isNewerVersion(change, older) && !isNewerVersion(change, newer));
|
|
62786
62721
|
}
|
|
62787
62722
|
function getCachePath3() {
|
|
62788
|
-
return
|
|
62723
|
+
return join40(getConfigDir(), CACHE_FILENAME4);
|
|
62789
62724
|
}
|
|
62790
62725
|
function readMcpRefreshCache() {
|
|
62791
62726
|
try {
|
|
62792
62727
|
const path = getCachePath3();
|
|
62793
|
-
if (!
|
|
62728
|
+
if (!existsSync25(path))
|
|
62794
62729
|
return null;
|
|
62795
|
-
const data = JSON.parse(
|
|
62730
|
+
const data = JSON.parse(readFileSync24(path, "utf-8"));
|
|
62796
62731
|
if (typeof data?.version === "string")
|
|
62797
62732
|
return { version: data.version };
|
|
62798
62733
|
return null;
|
|
@@ -62803,10 +62738,10 @@ function readMcpRefreshCache() {
|
|
|
62803
62738
|
function writeMcpRefreshCache(cache) {
|
|
62804
62739
|
try {
|
|
62805
62740
|
const dir = getConfigDir();
|
|
62806
|
-
if (!
|
|
62807
|
-
|
|
62741
|
+
if (!existsSync25(dir)) {
|
|
62742
|
+
mkdirSync15(dir, { recursive: true, mode: 448 });
|
|
62808
62743
|
}
|
|
62809
|
-
|
|
62744
|
+
writeFileSync16(getCachePath3(), JSON.stringify(cache), { mode: 384 });
|
|
62810
62745
|
} catch {}
|
|
62811
62746
|
}
|
|
62812
62747
|
function canRefreshMcp(cfg) {
|
|
@@ -62815,10 +62750,10 @@ function canRefreshMcp(cfg) {
|
|
|
62815
62750
|
return false;
|
|
62816
62751
|
return cfg.mode === MODE_OSS || Boolean(target.deployment_id);
|
|
62817
62752
|
}
|
|
62818
|
-
function
|
|
62753
|
+
function displayNotice(names) {
|
|
62819
62754
|
console.error(`
|
|
62820
|
-
${
|
|
62821
|
-
` + `${
|
|
62755
|
+
${import_picocolors31.default.green(`✓ Dosu ${VERSION}: refreshed MCP config for ${names.join(", ")}`)}
|
|
62756
|
+
` + `${import_picocolors31.default.dim(` Run ${import_picocolors31.default.cyan('"dosu setup"')} to also update hooks and rules, then restart your AI agents.`)}
|
|
62822
62757
|
`);
|
|
62823
62758
|
}
|
|
62824
62759
|
function checkForMcpRefresh(options = {}) {
|
|
@@ -62840,27 +62775,27 @@ function checkForMcpRefresh(options = {}) {
|
|
|
62840
62775
|
writeMcpRefreshCache({ version: VERSION });
|
|
62841
62776
|
logger.info("mcp-refresh", `Version ${VERSION}: refreshed ${result.updated.length}, failed ${result.failed.length}`);
|
|
62842
62777
|
if (notify && result.updated.length > 0) {
|
|
62843
|
-
|
|
62778
|
+
displayNotice(result.updated.map((provider) => provider.name()));
|
|
62844
62779
|
}
|
|
62845
62780
|
} catch (err) {
|
|
62846
62781
|
logger.error("mcp-refresh", `MCP refresh check failed: ${err}`);
|
|
62847
62782
|
}
|
|
62848
62783
|
}
|
|
62849
|
-
var
|
|
62784
|
+
var import_picocolors31, CACHE_FILENAME4 = "mcp-refresh.json", MCP_FORMAT_CHANGES;
|
|
62850
62785
|
var init_mcp_refresh_check = __esm(() => {
|
|
62851
62786
|
init_config();
|
|
62852
62787
|
init_logger();
|
|
62853
62788
|
init_refresh();
|
|
62854
62789
|
init_update_check();
|
|
62855
|
-
|
|
62790
|
+
import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
62856
62791
|
MCP_FORMAT_CHANGES = ["0.53.0"];
|
|
62857
62792
|
});
|
|
62858
62793
|
|
|
62859
62794
|
// src/version/skill-update-check.ts
|
|
62860
|
-
function
|
|
62795
|
+
function displayNotice2() {
|
|
62861
62796
|
console.error(`
|
|
62862
|
-
${
|
|
62863
|
-
` + `${
|
|
62797
|
+
${import_picocolors32.default.green(`✓ Dosu ${VERSION}: refreshed the bundled agent skills`)}
|
|
62798
|
+
` + `${import_picocolors32.default.dim(" Restart your AI agents to pick up the new skill content.")}
|
|
62864
62799
|
`);
|
|
62865
62800
|
}
|
|
62866
62801
|
function checkForSkillUpdates(options = {}) {
|
|
@@ -62876,294 +62811,16 @@ function checkForSkillUpdates(options = {}) {
|
|
|
62876
62811
|
}
|
|
62877
62812
|
logger.info("skill-update-check", `Refreshed skills from ${state.version} to ${VERSION}`);
|
|
62878
62813
|
if (notify && result.version)
|
|
62879
|
-
|
|
62814
|
+
displayNotice2();
|
|
62880
62815
|
} catch (err) {
|
|
62881
62816
|
logger.error("skill-update-check", `Skill update check failed: ${err}`);
|
|
62882
62817
|
}
|
|
62883
62818
|
}
|
|
62884
|
-
var
|
|
62819
|
+
var import_picocolors32;
|
|
62885
62820
|
var init_skill_update_check = __esm(() => {
|
|
62886
62821
|
init_skill();
|
|
62887
62822
|
init_logger();
|
|
62888
|
-
|
|
62889
|
-
});
|
|
62890
|
-
|
|
62891
|
-
// src/rules/installer.ts
|
|
62892
|
-
import { existsSync as existsSync25, mkdirSync as mkdirSync15, readFileSync as readFileSync24, unlinkSync as unlinkSync5, writeFileSync as writeFileSync16 } from "node:fs";
|
|
62893
|
-
import { homedir as homedir12 } from "node:os";
|
|
62894
|
-
import { dirname as dirname12, join as join40 } from "node:path";
|
|
62895
|
-
function claudeConfigDir4() {
|
|
62896
|
-
return process.env.CLAUDE_CONFIG_DIR || join40(homedir12(), ".claude");
|
|
62897
|
-
}
|
|
62898
|
-
function codexHome4() {
|
|
62899
|
-
return process.env.CODEX_HOME || join40(homedir12(), ".codex");
|
|
62900
|
-
}
|
|
62901
|
-
function isRuleAgent(agent) {
|
|
62902
|
-
return Object.hasOwn(RULE_TARGETS, agent);
|
|
62903
|
-
}
|
|
62904
|
-
function rulePathForAgent(agent) {
|
|
62905
|
-
return isRuleAgent(agent) ? RULE_TARGETS[agent].path() : null;
|
|
62906
|
-
}
|
|
62907
|
-
function normalizeRule(content) {
|
|
62908
|
-
return `${content.trim()}
|
|
62909
|
-
`;
|
|
62910
|
-
}
|
|
62911
|
-
async function fetchDosuRule(fetchImpl = globalThis.fetch) {
|
|
62912
|
-
for (const url of DOSU_RULE_URLS) {
|
|
62913
|
-
try {
|
|
62914
|
-
const response = await fetchImpl(url);
|
|
62915
|
-
if (!response.ok)
|
|
62916
|
-
continue;
|
|
62917
|
-
const content = await response.text();
|
|
62918
|
-
if (content.trim())
|
|
62919
|
-
return normalizeRule(content);
|
|
62920
|
-
} catch {}
|
|
62921
|
-
}
|
|
62922
|
-
return normalizeRule(FALLBACK_DOSU_RULE);
|
|
62923
|
-
}
|
|
62924
|
-
function ensureParent(path) {
|
|
62925
|
-
mkdirSync15(dirname12(path), { recursive: true });
|
|
62926
|
-
}
|
|
62927
|
-
function writeIfChanged(path, content) {
|
|
62928
|
-
if (!existsSync25(path)) {
|
|
62929
|
-
ensureParent(path);
|
|
62930
|
-
writeFileSync16(path, content, "utf-8");
|
|
62931
|
-
return "created";
|
|
62932
|
-
}
|
|
62933
|
-
if (readFileSync24(path, "utf-8") === content)
|
|
62934
|
-
return "unchanged";
|
|
62935
|
-
writeFileSync16(path, content, "utf-8");
|
|
62936
|
-
return "updated";
|
|
62937
|
-
}
|
|
62938
|
-
function findSection(content) {
|
|
62939
|
-
const startMatch = content.match(DOSU_RULE_SECTION_START_RE);
|
|
62940
|
-
const start = startMatch?.index ?? -1;
|
|
62941
|
-
const end = content.indexOf(DOSU_RULE_SECTION_END, Math.max(start, 0));
|
|
62942
|
-
if (start === -1 && end === -1)
|
|
62943
|
-
return null;
|
|
62944
|
-
if (start === -1 || end < start) {
|
|
62945
|
-
throw new Error("Dosu rule markers are incomplete; refusing to overwrite the instruction file");
|
|
62946
|
-
}
|
|
62947
|
-
return { start, end };
|
|
62948
|
-
}
|
|
62949
|
-
function lineEndingFor(content) {
|
|
62950
|
-
return content.includes(`\r
|
|
62951
|
-
`) ? `\r
|
|
62952
|
-
` : `
|
|
62953
|
-
`;
|
|
62954
|
-
}
|
|
62955
|
-
function buildSection(content, lineEnding = `
|
|
62956
|
-
`) {
|
|
62957
|
-
const body = content.trimEnd().replace(/\r?\n/g, lineEnding);
|
|
62958
|
-
return `${DOSU_RULE_SECTION_START}${lineEnding}${body}${lineEnding}${DOSU_RULE_SECTION_END}`;
|
|
62959
|
-
}
|
|
62960
|
-
function upsertSection(path, content) {
|
|
62961
|
-
if (!existsSync25(path)) {
|
|
62962
|
-
const section = buildSection(content);
|
|
62963
|
-
ensureParent(path);
|
|
62964
|
-
writeFileSync16(path, `${section}
|
|
62965
|
-
`, "utf-8");
|
|
62966
|
-
return "created";
|
|
62967
|
-
}
|
|
62968
|
-
const existing = readFileSync24(path, "utf-8");
|
|
62969
|
-
const lineEnding = lineEndingFor(existing);
|
|
62970
|
-
const section = buildSection(content, lineEnding);
|
|
62971
|
-
const location = findSection(existing);
|
|
62972
|
-
let next;
|
|
62973
|
-
if (location) {
|
|
62974
|
-
next = existing.slice(0, location.start) + section + existing.slice(location.end + DOSU_RULE_SECTION_END.length);
|
|
62975
|
-
} else {
|
|
62976
|
-
const separator = existing.length > 0 && !existing.endsWith(lineEnding) ? `${lineEnding}${lineEnding}` : existing.length > 0 ? lineEnding : "";
|
|
62977
|
-
next = `${existing}${separator}${section}${lineEnding}`;
|
|
62978
|
-
}
|
|
62979
|
-
if (next === existing)
|
|
62980
|
-
return "unchanged";
|
|
62981
|
-
writeFileSync16(path, next, "utf-8");
|
|
62982
|
-
return "updated";
|
|
62983
|
-
}
|
|
62984
|
-
function installRuleForAgent(agent, content) {
|
|
62985
|
-
if (!isRuleAgent(agent))
|
|
62986
|
-
return null;
|
|
62987
|
-
const target = RULE_TARGETS[agent];
|
|
62988
|
-
const path = target.path();
|
|
62989
|
-
const normalized = normalizeRule(content);
|
|
62990
|
-
const action = target.kind === "file" ? writeIfChanged(path, target.cursorFrontmatter ? `${CURSOR_FRONTMATTER}${normalized}` : normalized) : upsertSection(path, normalized);
|
|
62991
|
-
return { agent, path, action };
|
|
62992
|
-
}
|
|
62993
|
-
function removeRuleForAgent(agent) {
|
|
62994
|
-
if (!isRuleAgent(agent))
|
|
62995
|
-
return null;
|
|
62996
|
-
const target = RULE_TARGETS[agent];
|
|
62997
|
-
const path = target.path();
|
|
62998
|
-
if (!existsSync25(path))
|
|
62999
|
-
return { agent, path, action: "not_found" };
|
|
63000
|
-
if (target.kind === "file") {
|
|
63001
|
-
unlinkSync5(path);
|
|
63002
|
-
return { agent, path, action: "removed" };
|
|
63003
|
-
}
|
|
63004
|
-
const existing = readFileSync24(path, "utf-8");
|
|
63005
|
-
const lineEnding = lineEndingFor(existing);
|
|
63006
|
-
const location = findSection(existing);
|
|
63007
|
-
if (!location)
|
|
63008
|
-
return { agent, path, action: "not_found" };
|
|
63009
|
-
const next = (existing.slice(0, location.start) + existing.slice(location.end + DOSU_RULE_SECTION_END.length)).replace(/(?:\r?\n){3,}/g, `${lineEnding}${lineEnding}`).replace(/^(?:\r?\n)+/, "").trimEnd();
|
|
63010
|
-
if (!next) {
|
|
63011
|
-
unlinkSync5(path);
|
|
63012
|
-
} else {
|
|
63013
|
-
writeFileSync16(path, `${next}${lineEnding}`, "utf-8");
|
|
63014
|
-
}
|
|
63015
|
-
return { agent, path, action: "removed" };
|
|
63016
|
-
}
|
|
63017
|
-
var DOSU_RULE_SECTION_VERSION = 1, DOSU_RULE_SECTION_START, DOSU_RULE_SECTION_END = "<!-- dosu:rules:end -->", DOSU_RULE_SECTION_START_RE, CURSOR_FRONTMATTER = `---
|
|
63018
|
-
alwaysApply: true
|
|
63019
|
-
---
|
|
63020
|
-
|
|
63021
|
-
`, DOSU_RULE_URLS, FALLBACK_DOSU_RULE = `The team you are assisting maintains shared knowledge in Dosu: consult it to build on prior work, and contribute durable knowledge so future teammates and agents do not have to rediscover it. Always use only tools currently listed by the server.
|
|
63022
|
-
|
|
63023
|
-
When \`read_knowledge\` is listed, call it before non-trivial code or documentation work involving architecture, conventions, prior decisions, gotchas, incidents, ownership, or branch history. **If unsure whether relevant context exists, read first.** Pass \`repo\` and \`branch\` when available. Skip generic questions, trivial or self-contained edits, and context already injected by Dosu.
|
|
63024
|
-
|
|
63025
|
-
When \`write_knowledge\` is listed, use it after the task for durable, non-obvious knowledge that future work would otherwise have to rediscover. Do not save task or PR summaries, progress, test results, obvious facts, speculation, duplicates, or sensitive data. **If nothing durable was learned, do not write.**
|
|
63026
|
-
|
|
63027
|
-
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.
|
|
63028
|
-
|
|
63029
|
-
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.
|
|
63030
|
-
`, RULE_TARGETS;
|
|
63031
|
-
var init_installer = __esm(() => {
|
|
63032
|
-
DOSU_RULE_SECTION_START = `<!-- dosu:rules:start v${DOSU_RULE_SECTION_VERSION} -->`;
|
|
63033
|
-
DOSU_RULE_SECTION_START_RE = /<!-- dosu:rules:start(?: v\d+)? -->/;
|
|
63034
|
-
DOSU_RULE_URLS = [
|
|
63035
|
-
"https://raw.githubusercontent.com/dosu-ai/dosu-cli/main/rules/dosu.md",
|
|
63036
|
-
"https://raw.githubusercontent.com/dosu-ai/dosu-cli/master/rules/dosu.md"
|
|
63037
|
-
];
|
|
63038
|
-
RULE_TARGETS = {
|
|
63039
|
-
claude: {
|
|
63040
|
-
kind: "file",
|
|
63041
|
-
path: () => join40(claudeConfigDir4(), "rules", "dosu.md")
|
|
63042
|
-
},
|
|
63043
|
-
cursor: {
|
|
63044
|
-
kind: "file",
|
|
63045
|
-
path: () => join40(homedir12(), ".cursor", "rules", "dosu.mdc"),
|
|
63046
|
-
cursorFrontmatter: true
|
|
63047
|
-
},
|
|
63048
|
-
codex: {
|
|
63049
|
-
kind: "section",
|
|
63050
|
-
path: () => join40(codexHome4(), "AGENTS.md")
|
|
63051
|
-
},
|
|
63052
|
-
opencode: {
|
|
63053
|
-
kind: "section",
|
|
63054
|
-
path: () => join40(homedir12(), ".config", "opencode", "AGENTS.md")
|
|
63055
|
-
},
|
|
63056
|
-
gemini: {
|
|
63057
|
-
kind: "section",
|
|
63058
|
-
path: () => join40(homedir12(), ".gemini", "GEMINI.md")
|
|
63059
|
-
},
|
|
63060
|
-
antigravity: {
|
|
63061
|
-
kind: "section",
|
|
63062
|
-
path: () => join40(homedir12(), ".gemini", "GEMINI.md")
|
|
63063
|
-
}
|
|
63064
|
-
};
|
|
63065
|
-
});
|
|
63066
|
-
|
|
63067
|
-
// src/setup/agents-md-step.ts
|
|
63068
|
-
import { execSync as execSync2 } from "node:child_process";
|
|
63069
|
-
import { existsSync as existsSync26, readFileSync as readFileSync25, writeFileSync as writeFileSync17 } from "node:fs";
|
|
63070
|
-
import { join as join41 } from "node:path";
|
|
63071
|
-
function inGitWorkTree(cwd = process.cwd()) {
|
|
63072
|
-
try {
|
|
63073
|
-
const stdout = execSync2("git rev-parse --is-inside-work-tree", {
|
|
63074
|
-
cwd,
|
|
63075
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
63076
|
-
});
|
|
63077
|
-
return stdout.toString().trim() === "true";
|
|
63078
|
-
} catch {
|
|
63079
|
-
return false;
|
|
63080
|
-
}
|
|
63081
|
-
}
|
|
63082
|
-
function dosuAgentsSectionState(cwd = process.cwd()) {
|
|
63083
|
-
try {
|
|
63084
|
-
const path = join41(cwd, "AGENTS.md");
|
|
63085
|
-
if (!existsSync26(path))
|
|
63086
|
-
return "missing";
|
|
63087
|
-
const content = readFileSync25(path, "utf-8");
|
|
63088
|
-
const startMatch = content.match(SECTION_START_RE);
|
|
63089
|
-
if (!startMatch || !content.includes(DOSU_SECTION_END))
|
|
63090
|
-
return "missing";
|
|
63091
|
-
return Number(startMatch[1] ?? 0) >= DOSU_SECTION_VERSION ? "current" : "outdated";
|
|
63092
|
-
} catch {
|
|
63093
|
-
return "missing";
|
|
63094
|
-
}
|
|
63095
|
-
}
|
|
63096
|
-
function lineEndingFor2(content) {
|
|
63097
|
-
return content.includes(`\r
|
|
63098
|
-
`) ? `\r
|
|
63099
|
-
` : `
|
|
63100
|
-
`;
|
|
63101
|
-
}
|
|
63102
|
-
function renderDosuAgentsSection(content, lineEnding) {
|
|
63103
|
-
const body = content.trim().replace(/\r?\n/g, lineEnding);
|
|
63104
|
-
return `${DOSU_SECTION_START}${lineEnding}${body}${lineEnding}${DOSU_SECTION_END}`;
|
|
63105
|
-
}
|
|
63106
|
-
function buildDosuAgentsSection(content = FALLBACK_DOSU_RULE) {
|
|
63107
|
-
return renderDosuAgentsSection(content, `
|
|
63108
|
-
`);
|
|
63109
|
-
}
|
|
63110
|
-
function findSection2(content) {
|
|
63111
|
-
const startMatch = content.match(SECTION_START_RE);
|
|
63112
|
-
const start = startMatch?.index ?? -1;
|
|
63113
|
-
const end = content.indexOf(DOSU_SECTION_END, Math.max(start, 0));
|
|
63114
|
-
if (start === -1 && end === -1)
|
|
63115
|
-
return null;
|
|
63116
|
-
if (start === -1 || end < start) {
|
|
63117
|
-
throw new Error("Dosu AGENTS.md markers are incomplete; refusing to overwrite the file");
|
|
63118
|
-
}
|
|
63119
|
-
return { start, end };
|
|
63120
|
-
}
|
|
63121
|
-
function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RULE) {
|
|
63122
|
-
const path = join41(cwd, "AGENTS.md");
|
|
63123
|
-
if (!existsSync26(path)) {
|
|
63124
|
-
const section = buildDosuAgentsSection(content);
|
|
63125
|
-
writeFileSync17(path, `${section}
|
|
63126
|
-
`);
|
|
63127
|
-
return { path, action: "created" };
|
|
63128
|
-
}
|
|
63129
|
-
const existing = readFileSync25(path, "utf-8");
|
|
63130
|
-
const lineEnding = lineEndingFor2(existing);
|
|
63131
|
-
const section = renderDosuAgentsSection(content, lineEnding);
|
|
63132
|
-
const location = findSection2(existing);
|
|
63133
|
-
let next;
|
|
63134
|
-
if (location) {
|
|
63135
|
-
next = existing.slice(0, location.start) + section + existing.slice(location.end + DOSU_SECTION_END.length);
|
|
63136
|
-
} else {
|
|
63137
|
-
next = `${existing.trimEnd()}${lineEnding}${lineEnding}${section}${lineEnding}`;
|
|
63138
|
-
}
|
|
63139
|
-
if (next === existing)
|
|
63140
|
-
return { path, action: "unchanged" };
|
|
63141
|
-
writeFileSync17(path, next);
|
|
63142
|
-
return { path, action: "updated" };
|
|
63143
|
-
}
|
|
63144
|
-
async function stepUpdateAgentsMd(cwd = process.cwd(), content) {
|
|
63145
|
-
logger.info("setup", "Step: update AGENTS.md");
|
|
63146
|
-
try {
|
|
63147
|
-
const result = upsertDosuAgentsSection(cwd, content ?? await fetchDosuRule());
|
|
63148
|
-
logger.info("setup", `AGENTS.md ${result.action} at ${result.path}`);
|
|
63149
|
-
const status = result.action === "unchanged" ? "already up to date" : result.action;
|
|
63150
|
-
log2.success(formatSetupSummary("AGENTS.md", [{ path: result.path, status }]));
|
|
63151
|
-
return true;
|
|
63152
|
-
} catch (err) {
|
|
63153
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
63154
|
-
logger.error("setup", `AGENTS.md update failed: ${msg}`);
|
|
63155
|
-
log2.error(`Could not update AGENTS.md: ${msg}`);
|
|
63156
|
-
return false;
|
|
63157
|
-
}
|
|
63158
|
-
}
|
|
63159
|
-
var DOSU_SECTION_VERSION = 2, DOSU_SECTION_START, DOSU_SECTION_END = "<!-- dosu:mcp:end -->", SECTION_START_RE;
|
|
63160
|
-
var init_agents_md_step = __esm(() => {
|
|
63161
|
-
init_logger();
|
|
63162
|
-
init_installer();
|
|
63163
|
-
init_prompts();
|
|
63164
|
-
init_styles();
|
|
63165
|
-
DOSU_SECTION_START = `<!-- dosu:mcp:start v${DOSU_SECTION_VERSION} -->`;
|
|
63166
|
-
SECTION_START_RE = /<!-- dosu:mcp:start(?: v(\d+))? -->/;
|
|
62823
|
+
import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
63167
62824
|
});
|
|
63168
62825
|
|
|
63169
62826
|
// src/auth/errors.ts
|
|
@@ -63193,16 +62850,51 @@ var init_errors3 = __esm(() => {
|
|
|
63193
62850
|
// src/mcp/constants.ts
|
|
63194
62851
|
var MCP_PROVIDER_SLUG2 = "dosu_mcp";
|
|
63195
62852
|
|
|
62853
|
+
// src/debug/follow.ts
|
|
62854
|
+
import { closeSync as closeSync7, openSync as openSync7, readSync as readSync5, statSync as statSync9 } from "node:fs";
|
|
62855
|
+
function createLogFollower(path, emit) {
|
|
62856
|
+
const sizeOf = () => {
|
|
62857
|
+
try {
|
|
62858
|
+
return statSync9(path).size;
|
|
62859
|
+
} catch {
|
|
62860
|
+
return 0;
|
|
62861
|
+
}
|
|
62862
|
+
};
|
|
62863
|
+
let offset = sizeOf();
|
|
62864
|
+
return {
|
|
62865
|
+
poll() {
|
|
62866
|
+
const size = sizeOf();
|
|
62867
|
+
if (size < offset)
|
|
62868
|
+
offset = 0;
|
|
62869
|
+
if (size === offset)
|
|
62870
|
+
return;
|
|
62871
|
+
try {
|
|
62872
|
+
const fd = openSync7(path, "r");
|
|
62873
|
+
try {
|
|
62874
|
+
const buf = Buffer.alloc(size - offset);
|
|
62875
|
+
const read = readSync5(fd, buf, 0, buf.length, offset);
|
|
62876
|
+
offset += read;
|
|
62877
|
+
if (read > 0)
|
|
62878
|
+
emit(buf.toString("utf-8", 0, read));
|
|
62879
|
+
} finally {
|
|
62880
|
+
closeSync7(fd);
|
|
62881
|
+
}
|
|
62882
|
+
} catch {}
|
|
62883
|
+
}
|
|
62884
|
+
};
|
|
62885
|
+
}
|
|
62886
|
+
var init_follow = () => {};
|
|
62887
|
+
|
|
63196
62888
|
// src/sessions/session-title.ts
|
|
63197
|
-
import { existsSync as
|
|
63198
|
-
import { homedir as
|
|
63199
|
-
import { join as
|
|
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";
|
|
63200
62892
|
function cachePath2(configDir) {
|
|
63201
|
-
return
|
|
62893
|
+
return join41(configDir, CACHE_FILENAME5);
|
|
63202
62894
|
}
|
|
63203
62895
|
function loadCacheFile2(configDir) {
|
|
63204
62896
|
try {
|
|
63205
|
-
const raw = JSON.parse(
|
|
62897
|
+
const raw = JSON.parse(readFileSync25(cachePath2(configDir), "utf-8"));
|
|
63206
62898
|
if (raw.schema_version !== CACHE_SCHEMA_VERSION2 || typeof raw.entries !== "object")
|
|
63207
62899
|
return {};
|
|
63208
62900
|
return raw.entries;
|
|
@@ -63212,12 +62904,12 @@ function loadCacheFile2(configDir) {
|
|
|
63212
62904
|
}
|
|
63213
62905
|
function saveCacheFile2(configDir, entries) {
|
|
63214
62906
|
try {
|
|
63215
|
-
if (!
|
|
62907
|
+
if (!existsSync26(configDir))
|
|
63216
62908
|
mkdirSync16(configDir, { recursive: true, mode: 448 });
|
|
63217
62909
|
const path = cachePath2(configDir);
|
|
63218
62910
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
63219
62911
|
const file = { schema_version: CACHE_SCHEMA_VERSION2, entries };
|
|
63220
|
-
|
|
62912
|
+
writeFileSync17(tmp, JSON.stringify(file), { mode: 384 });
|
|
63221
62913
|
renameSync6(tmp, path);
|
|
63222
62914
|
} catch {}
|
|
63223
62915
|
}
|
|
@@ -63250,15 +62942,15 @@ function claudeSummaryFromHead(text) {
|
|
|
63250
62942
|
}
|
|
63251
62943
|
return null;
|
|
63252
62944
|
}
|
|
63253
|
-
function reconstructSession(harness, id, slug, home =
|
|
62945
|
+
function reconstructSession(harness, id, slug, home = homedir12(), exists = existsSync26) {
|
|
63254
62946
|
if (!slug)
|
|
63255
62947
|
return null;
|
|
63256
62948
|
const candidates = [];
|
|
63257
62949
|
if (harness === "claude") {
|
|
63258
|
-
candidates.push(
|
|
62950
|
+
candidates.push(join41(home, ".claude", "projects", slug, `${id}.jsonl`));
|
|
63259
62951
|
} else if (harness === "cursor") {
|
|
63260
|
-
const project =
|
|
63261
|
-
candidates.push(
|
|
62952
|
+
const project = join41(home, ".cursor", "projects", slug);
|
|
62953
|
+
candidates.push(join41(project, "agent-transcripts", id, `${id}.jsonl`), join41(project, "agent-transcripts", `${id}.jsonl`));
|
|
63262
62954
|
} else {
|
|
63263
62955
|
return null;
|
|
63264
62956
|
}
|
|
@@ -63270,14 +62962,14 @@ function reconstructSession(harness, id, slug, home = homedir13(), exists = exis
|
|
|
63270
62962
|
}
|
|
63271
62963
|
function readHead2(path) {
|
|
63272
62964
|
try {
|
|
63273
|
-
return
|
|
62965
|
+
return readFileSync25(path, "utf-8").slice(0, 128 * 1024);
|
|
63274
62966
|
} catch {
|
|
63275
62967
|
return null;
|
|
63276
62968
|
}
|
|
63277
62969
|
}
|
|
63278
62970
|
function fileMtime2(path) {
|
|
63279
62971
|
try {
|
|
63280
|
-
return
|
|
62972
|
+
return statSync10(path).mtime.toISOString();
|
|
63281
62973
|
} catch {
|
|
63282
62974
|
return "";
|
|
63283
62975
|
}
|
|
@@ -63350,7 +63042,7 @@ var init_alt_screen = __esm(() => {
|
|
|
63350
63042
|
});
|
|
63351
63043
|
|
|
63352
63044
|
// src/tui/activity-view.ts
|
|
63353
|
-
import { existsSync as
|
|
63045
|
+
import { existsSync as existsSync27, readFileSync as readFileSync26 } from "node:fs";
|
|
63354
63046
|
import { basename as basename5 } from "node:path";
|
|
63355
63047
|
function reduceActivityViewKey(key) {
|
|
63356
63048
|
if (key === "q" || key === ESC7 || key === CTRL_C4)
|
|
@@ -63491,15 +63183,15 @@ function statusLine(status) {
|
|
|
63491
63183
|
if (status.running) {
|
|
63492
63184
|
const since = status.startedAt ? ` · since ${localTime(status.startedAt)}` : "";
|
|
63493
63185
|
const pid = status.pid !== undefined ? ` (pid ${status.pid})` : "";
|
|
63494
|
-
return `\uD83D\uDCDA ${
|
|
63186
|
+
return `\uD83D\uDCDA ${import_picocolors33.default.bold(brand("Studying sessions..."))}${import_picocolors33.default.dim(`${pid}${since}`)}`;
|
|
63495
63187
|
}
|
|
63496
63188
|
if (status.state.paused) {
|
|
63497
|
-
return `${
|
|
63189
|
+
return `${import_picocolors33.default.yellow("○")} ${import_picocolors33.default.bold("Paused")} ${import_picocolors33.default.dim("· studying stays off until you resume")}`;
|
|
63498
63190
|
}
|
|
63499
63191
|
if (status.staleLock) {
|
|
63500
|
-
return `${
|
|
63192
|
+
return `${import_picocolors33.default.yellow("○")} ${import_picocolors33.default.bold("Not running")} ${import_picocolors33.default.dim("· a previous run exited without cleaning up")}`;
|
|
63501
63193
|
}
|
|
63502
|
-
return `${
|
|
63194
|
+
return `${import_picocolors33.default.dim("○")} ${import_picocolors33.default.bold("Idle")} ${import_picocolors33.default.dim("· hooks study new sessions automatically")}`;
|
|
63503
63195
|
}
|
|
63504
63196
|
function progressLine(done, ready, width, notes = 0) {
|
|
63505
63197
|
const total = done + ready;
|
|
@@ -63508,7 +63200,7 @@ function progressLine(done, ready, width, notes = 0) {
|
|
|
63508
63200
|
const cells = Math.max(10, Math.min(30, width - 44));
|
|
63509
63201
|
const ratio = Math.max(0, Math.min(1, done / total));
|
|
63510
63202
|
const filled = Math.min(cells, Math.round(ratio * cells));
|
|
63511
|
-
const bar = brand("█".repeat(filled)) +
|
|
63203
|
+
const bar = brand("█".repeat(filled)) + import_picocolors33.default.dim("░".repeat(cells - filled));
|
|
63512
63204
|
const pct = Math.floor(ratio * 100);
|
|
63513
63205
|
const suffix = notes > 0 ? ` · ${notes} suggested page${notes === 1 ? "" : "s"}` : "";
|
|
63514
63206
|
return `${bar} ${done}/${total} studied · ${pct}%${suffix}`;
|
|
@@ -63547,17 +63239,17 @@ function confirmBox(queuedCount, backlog, width, mode = "start") {
|
|
|
63547
63239
|
const verb = mode === "clear" ? "clear" : mode === "stop" ? "stop" : mode === "resume" ? "resume" : "start";
|
|
63548
63240
|
const maxInner = Math.max(20, Math.min(width, contentWidth()) - 4);
|
|
63549
63241
|
const rows = [
|
|
63550
|
-
|
|
63551
|
-
...wrapLine(scope, maxInner, "").map((line) =>
|
|
63242
|
+
import_picocolors33.default.bold(brand(title)),
|
|
63243
|
+
...wrapLine(scope, maxInner, "").map((line) => import_picocolors33.default.dim(line)),
|
|
63552
63244
|
"",
|
|
63553
|
-
`${
|
|
63245
|
+
`${import_picocolors33.default.bold("enter")} ${verb} · ${import_picocolors33.default.bold("esc")} cancel`
|
|
63554
63246
|
];
|
|
63555
63247
|
const inner = Math.min(maxInner, Math.max(...rows.map(visibleWidth2)));
|
|
63556
63248
|
const pad = (row) => row + " ".repeat(Math.max(0, inner - visibleWidth2(row)));
|
|
63557
63249
|
return [
|
|
63558
|
-
|
|
63559
|
-
...rows.map((row) => `${
|
|
63560
|
-
|
|
63250
|
+
import_picocolors33.default.dim(`╭${"─".repeat(inner + 2)}╮`),
|
|
63251
|
+
...rows.map((row) => `${import_picocolors33.default.dim("│")} ${pad(row)} ${import_picocolors33.default.dim("│")}`),
|
|
63252
|
+
import_picocolors33.default.dim(`╰${"─".repeat(inner + 2)}╯`)
|
|
63561
63253
|
];
|
|
63562
63254
|
}
|
|
63563
63255
|
function buildActivityFrame(status, activity, width, backlog = null, pane = DEFAULT_PANE, queued = [], studiedBeforeRun = 0, open = [], runProgress = null, projectNames = {}, sessionNames = {}, frameLines) {
|
|
@@ -63573,7 +63265,7 @@ function buildActivityFrame(status, activity, width, backlog = null, pane = DEFA
|
|
|
63573
63265
|
progress = progressLine(studiedDelta + stepDone, Math.max(0, backlog.ready - stepDone), width, runProgress?.notes ?? 0);
|
|
63574
63266
|
}
|
|
63575
63267
|
const refusal = !status.running && status.state.last_refusal;
|
|
63576
|
-
const refusalLines = refusal ? wrapLine(`! Studying paused: ${refusal.message} (${localTime(refusal.at)})`, width).map((line) =>
|
|
63268
|
+
const refusalLines = refusal ? wrapLine(`! Studying paused: ${refusal.message} (${localTime(refusal.at)})`, width).map((line) => import_picocolors33.default.yellow(line)) : [];
|
|
63577
63269
|
const fullRows = Boolean(pane.fullRows);
|
|
63578
63270
|
const withName = (item, key) => projectNames[key] ? { ...item, project: projectNames[key] } : item;
|
|
63579
63271
|
const latestPass = new Map;
|
|
@@ -63599,8 +63291,8 @@ function buildActivityFrame(status, activity, width, backlog = null, pane = DEFA
|
|
|
63599
63291
|
breadcrumb(["home", "activity"], width),
|
|
63600
63292
|
"",
|
|
63601
63293
|
statusLine(status),
|
|
63602
|
-
|
|
63603
|
-
...queueDetail.length > 0 ? wrapLine(queueDetail.join(" · "), width).map((line) =>
|
|
63294
|
+
import_picocolors33.default.dim(studied),
|
|
63295
|
+
...queueDetail.length > 0 ? wrapLine(queueDetail.join(" · "), width).map((line) => import_picocolors33.default.dim(line)) : [],
|
|
63604
63296
|
...progress ? [progress] : [],
|
|
63605
63297
|
...refusalLines,
|
|
63606
63298
|
"",
|
|
@@ -63616,7 +63308,7 @@ function buildActivityFrame(status, activity, width, backlog = null, pane = DEFA
|
|
|
63616
63308
|
status.running ? "s stop" : status.state.paused ? "s resume" : "s sync now",
|
|
63617
63309
|
...!status.running && status.state.watermark ? ["c clear"] : [],
|
|
63618
63310
|
"esc back"
|
|
63619
|
-
].join(" · "), width, "").map((line) =>
|
|
63311
|
+
].join(" · "), width, "").map((line) => import_picocolors33.default.dim(line))
|
|
63620
63312
|
]
|
|
63621
63313
|
];
|
|
63622
63314
|
const defaultHeight = fullRows ? ACTIVITY_VIEW_FULL_LIST_ROWS : ACTIVITY_VIEW_LIST_LINES;
|
|
@@ -63629,7 +63321,7 @@ function buildActivityFrame(status, activity, width, backlog = null, pane = DEFA
|
|
|
63629
63321
|
({ visible, above, below } = windowList(source, pane.scroll, height));
|
|
63630
63322
|
display = visible.flatMap((row) => wrapRow(row, width));
|
|
63631
63323
|
}
|
|
63632
|
-
const listRows = display.length > 0 ? display.map((row) =>
|
|
63324
|
+
const listRows = display.length > 0 ? display.map((row) => import_picocolors33.default.dim(row)) : [import_picocolors33.default.dim(empty)];
|
|
63633
63325
|
const scrollParts = [];
|
|
63634
63326
|
if (above > 0)
|
|
63635
63327
|
scrollParts.push(`↑ ${above} earlier`);
|
|
@@ -63638,7 +63330,7 @@ function buildActivityFrame(status, activity, width, backlog = null, pane = DEFA
|
|
|
63638
63330
|
const lines = [
|
|
63639
63331
|
...header,
|
|
63640
63332
|
...listRows,
|
|
63641
|
-
...scrollParts.length > 0 ? [
|
|
63333
|
+
...scrollParts.length > 0 ? [import_picocolors33.default.dim(clip(scrollParts.join(" · "), width))] : [],
|
|
63642
63334
|
...footer
|
|
63643
63335
|
];
|
|
63644
63336
|
return { lines, listHeight: height };
|
|
@@ -63671,7 +63363,7 @@ function createRowNamer() {
|
|
|
63671
63363
|
names.titles[key] = t;
|
|
63672
63364
|
};
|
|
63673
63365
|
for (const s of [...backlog.queued, ...backlog.open]) {
|
|
63674
|
-
if (!
|
|
63366
|
+
if (!existsSync27(s.path))
|
|
63675
63367
|
continue;
|
|
63676
63368
|
const key = `${s.harness}/${s.id}`;
|
|
63677
63369
|
const dir = dirs.resolve(s);
|
|
@@ -63708,7 +63400,7 @@ function createRowNamer() {
|
|
|
63708
63400
|
}
|
|
63709
63401
|
function defaultReadLog2() {
|
|
63710
63402
|
try {
|
|
63711
|
-
return
|
|
63403
|
+
return readFileSync26(logger.getLogPath(), "utf-8");
|
|
63712
63404
|
} catch {
|
|
63713
63405
|
return "";
|
|
63714
63406
|
}
|
|
@@ -63893,7 +63585,7 @@ ${CLEAR_BELOW}`);
|
|
|
63893
63585
|
input.on("data", onData);
|
|
63894
63586
|
});
|
|
63895
63587
|
}
|
|
63896
|
-
var
|
|
63588
|
+
var import_picocolors33, ESC7, HIDE_CURSOR3, SHOW_CURSOR3, CTRL_C4, KEY_UP4, KEY_DOWN4, KEY_RIGHT3, KEY_LEFT3, CURSOR_HOME, CLEAR_BELOW, CLEAR_EOL, ACTIVITY_VIEW_POLL_MS = 500, ACTIVITY_VIEW_LIST_LINES = 10, ACTIVITY_VIEW_FULL_LIST_ROWS = 5, ACTIVITY_VIEW_BUFFER_LINES = 200, ACTIVITY_VIEW_TABS, DEFAULT_PANE, TITLE_READS_PER_DRAW = 25;
|
|
63897
63589
|
var init_activity_view = __esm(() => {
|
|
63898
63590
|
init_follow();
|
|
63899
63591
|
init_logger();
|
|
@@ -63908,7 +63600,7 @@ var init_activity_view = __esm(() => {
|
|
|
63908
63600
|
init_alt_screen();
|
|
63909
63601
|
init_layout();
|
|
63910
63602
|
init_menu();
|
|
63911
|
-
|
|
63603
|
+
import_picocolors33 = __toESM(require_picocolors(), 1);
|
|
63912
63604
|
ESC7 = String.fromCharCode(27);
|
|
63913
63605
|
HIDE_CURSOR3 = `${ESC7}[?25l`;
|
|
63914
63606
|
SHOW_CURSOR3 = `${ESC7}[?25h`;
|
|
@@ -63924,6 +63616,284 @@ var init_activity_view = __esm(() => {
|
|
|
63924
63616
|
DEFAULT_PANE = { tab: "activity", scroll: 0 };
|
|
63925
63617
|
});
|
|
63926
63618
|
|
|
63619
|
+
// src/rules/installer.ts
|
|
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";
|
|
63623
|
+
function claudeConfigDir4() {
|
|
63624
|
+
return process.env.CLAUDE_CONFIG_DIR || join42(homedir13(), ".claude");
|
|
63625
|
+
}
|
|
63626
|
+
function codexHome4() {
|
|
63627
|
+
return process.env.CODEX_HOME || join42(homedir13(), ".codex");
|
|
63628
|
+
}
|
|
63629
|
+
function isRuleAgent(agent) {
|
|
63630
|
+
return Object.hasOwn(RULE_TARGETS, agent);
|
|
63631
|
+
}
|
|
63632
|
+
function rulePathForAgent(agent) {
|
|
63633
|
+
return isRuleAgent(agent) ? RULE_TARGETS[agent].path() : null;
|
|
63634
|
+
}
|
|
63635
|
+
function normalizeRule(content) {
|
|
63636
|
+
return `${content.trim()}
|
|
63637
|
+
`;
|
|
63638
|
+
}
|
|
63639
|
+
async function fetchDosuRule(fetchImpl = globalThis.fetch) {
|
|
63640
|
+
for (const url of DOSU_RULE_URLS) {
|
|
63641
|
+
try {
|
|
63642
|
+
const response = await fetchImpl(url);
|
|
63643
|
+
if (!response.ok)
|
|
63644
|
+
continue;
|
|
63645
|
+
const content = await response.text();
|
|
63646
|
+
if (content.trim())
|
|
63647
|
+
return normalizeRule(content);
|
|
63648
|
+
} catch {}
|
|
63649
|
+
}
|
|
63650
|
+
return normalizeRule(FALLBACK_DOSU_RULE);
|
|
63651
|
+
}
|
|
63652
|
+
function ensureParent(path) {
|
|
63653
|
+
mkdirSync17(dirname12(path), { recursive: true });
|
|
63654
|
+
}
|
|
63655
|
+
function writeIfChanged(path, content) {
|
|
63656
|
+
if (!existsSync28(path)) {
|
|
63657
|
+
ensureParent(path);
|
|
63658
|
+
writeFileSync18(path, content, "utf-8");
|
|
63659
|
+
return "created";
|
|
63660
|
+
}
|
|
63661
|
+
if (readFileSync27(path, "utf-8") === content)
|
|
63662
|
+
return "unchanged";
|
|
63663
|
+
writeFileSync18(path, content, "utf-8");
|
|
63664
|
+
return "updated";
|
|
63665
|
+
}
|
|
63666
|
+
function findSection(content) {
|
|
63667
|
+
const startMatch = content.match(DOSU_RULE_SECTION_START_RE);
|
|
63668
|
+
const start = startMatch?.index ?? -1;
|
|
63669
|
+
const end = content.indexOf(DOSU_RULE_SECTION_END, Math.max(start, 0));
|
|
63670
|
+
if (start === -1 && end === -1)
|
|
63671
|
+
return null;
|
|
63672
|
+
if (start === -1 || end < start) {
|
|
63673
|
+
throw new Error("Dosu rule markers are incomplete; refusing to overwrite the instruction file");
|
|
63674
|
+
}
|
|
63675
|
+
return { start, end };
|
|
63676
|
+
}
|
|
63677
|
+
function lineEndingFor(content) {
|
|
63678
|
+
return content.includes(`\r
|
|
63679
|
+
`) ? `\r
|
|
63680
|
+
` : `
|
|
63681
|
+
`;
|
|
63682
|
+
}
|
|
63683
|
+
function buildSection(content, lineEnding = `
|
|
63684
|
+
`) {
|
|
63685
|
+
const body = content.trimEnd().replace(/\r?\n/g, lineEnding);
|
|
63686
|
+
return `${DOSU_RULE_SECTION_START}${lineEnding}${body}${lineEnding}${DOSU_RULE_SECTION_END}`;
|
|
63687
|
+
}
|
|
63688
|
+
function upsertSection(path, content) {
|
|
63689
|
+
if (!existsSync28(path)) {
|
|
63690
|
+
const section = buildSection(content);
|
|
63691
|
+
ensureParent(path);
|
|
63692
|
+
writeFileSync18(path, `${section}
|
|
63693
|
+
`, "utf-8");
|
|
63694
|
+
return "created";
|
|
63695
|
+
}
|
|
63696
|
+
const existing = readFileSync27(path, "utf-8");
|
|
63697
|
+
const lineEnding = lineEndingFor(existing);
|
|
63698
|
+
const section = buildSection(content, lineEnding);
|
|
63699
|
+
const location = findSection(existing);
|
|
63700
|
+
let next;
|
|
63701
|
+
if (location) {
|
|
63702
|
+
next = existing.slice(0, location.start) + section + existing.slice(location.end + DOSU_RULE_SECTION_END.length);
|
|
63703
|
+
} else {
|
|
63704
|
+
const separator = existing.length > 0 && !existing.endsWith(lineEnding) ? `${lineEnding}${lineEnding}` : existing.length > 0 ? lineEnding : "";
|
|
63705
|
+
next = `${existing}${separator}${section}${lineEnding}`;
|
|
63706
|
+
}
|
|
63707
|
+
if (next === existing)
|
|
63708
|
+
return "unchanged";
|
|
63709
|
+
writeFileSync18(path, next, "utf-8");
|
|
63710
|
+
return "updated";
|
|
63711
|
+
}
|
|
63712
|
+
function installRuleForAgent(agent, content) {
|
|
63713
|
+
if (!isRuleAgent(agent))
|
|
63714
|
+
return null;
|
|
63715
|
+
const target = RULE_TARGETS[agent];
|
|
63716
|
+
const path = target.path();
|
|
63717
|
+
const normalized = normalizeRule(content);
|
|
63718
|
+
const action = target.kind === "file" ? writeIfChanged(path, target.cursorFrontmatter ? `${CURSOR_FRONTMATTER}${normalized}` : normalized) : upsertSection(path, normalized);
|
|
63719
|
+
return { agent, path, action };
|
|
63720
|
+
}
|
|
63721
|
+
function removeRuleForAgent(agent) {
|
|
63722
|
+
if (!isRuleAgent(agent))
|
|
63723
|
+
return null;
|
|
63724
|
+
const target = RULE_TARGETS[agent];
|
|
63725
|
+
const path = target.path();
|
|
63726
|
+
if (!existsSync28(path))
|
|
63727
|
+
return { agent, path, action: "not_found" };
|
|
63728
|
+
if (target.kind === "file") {
|
|
63729
|
+
unlinkSync5(path);
|
|
63730
|
+
return { agent, path, action: "removed" };
|
|
63731
|
+
}
|
|
63732
|
+
const existing = readFileSync27(path, "utf-8");
|
|
63733
|
+
const lineEnding = lineEndingFor(existing);
|
|
63734
|
+
const location = findSection(existing);
|
|
63735
|
+
if (!location)
|
|
63736
|
+
return { agent, path, action: "not_found" };
|
|
63737
|
+
const next = (existing.slice(0, location.start) + existing.slice(location.end + DOSU_RULE_SECTION_END.length)).replace(/(?:\r?\n){3,}/g, `${lineEnding}${lineEnding}`).replace(/^(?:\r?\n)+/, "").trimEnd();
|
|
63738
|
+
if (!next) {
|
|
63739
|
+
unlinkSync5(path);
|
|
63740
|
+
} else {
|
|
63741
|
+
writeFileSync18(path, `${next}${lineEnding}`, "utf-8");
|
|
63742
|
+
}
|
|
63743
|
+
return { agent, path, action: "removed" };
|
|
63744
|
+
}
|
|
63745
|
+
var DOSU_RULE_SECTION_VERSION = 1, DOSU_RULE_SECTION_START, DOSU_RULE_SECTION_END = "<!-- dosu:rules:end -->", DOSU_RULE_SECTION_START_RE, CURSOR_FRONTMATTER = `---
|
|
63746
|
+
alwaysApply: true
|
|
63747
|
+
---
|
|
63748
|
+
|
|
63749
|
+
`, DOSU_RULE_URLS, FALLBACK_DOSU_RULE = `The team you are assisting maintains shared knowledge in Dosu: consult it to build on prior work, and contribute durable knowledge so future teammates and agents do not have to rediscover it. Always use only tools currently listed by the server.
|
|
63750
|
+
|
|
63751
|
+
When \`read_knowledge\` is listed, call it before non-trivial code or documentation work involving architecture, conventions, prior decisions, gotchas, incidents, ownership, or branch history. **If unsure whether relevant context exists, read first.** Pass \`repo\` and \`branch\` when available. Skip generic questions, trivial or self-contained edits, and context already injected by Dosu.
|
|
63752
|
+
|
|
63753
|
+
When \`write_knowledge\` is listed, use it after the task for durable, non-obvious knowledge that future work would otherwise have to rediscover. Do not save task or PR summaries, progress, test results, obvious facts, speculation, duplicates, or sensitive data. **If nothing durable was learned, do not write.**
|
|
63754
|
+
|
|
63755
|
+
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.
|
|
63756
|
+
|
|
63757
|
+
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.
|
|
63758
|
+
`, RULE_TARGETS;
|
|
63759
|
+
var init_installer = __esm(() => {
|
|
63760
|
+
DOSU_RULE_SECTION_START = `<!-- dosu:rules:start v${DOSU_RULE_SECTION_VERSION} -->`;
|
|
63761
|
+
DOSU_RULE_SECTION_START_RE = /<!-- dosu:rules:start(?: v\d+)? -->/;
|
|
63762
|
+
DOSU_RULE_URLS = [
|
|
63763
|
+
"https://raw.githubusercontent.com/dosu-ai/dosu-cli/main/rules/dosu.md",
|
|
63764
|
+
"https://raw.githubusercontent.com/dosu-ai/dosu-cli/master/rules/dosu.md"
|
|
63765
|
+
];
|
|
63766
|
+
RULE_TARGETS = {
|
|
63767
|
+
claude: {
|
|
63768
|
+
kind: "file",
|
|
63769
|
+
path: () => join42(claudeConfigDir4(), "rules", "dosu.md")
|
|
63770
|
+
},
|
|
63771
|
+
cursor: {
|
|
63772
|
+
kind: "file",
|
|
63773
|
+
path: () => join42(homedir13(), ".cursor", "rules", "dosu.mdc"),
|
|
63774
|
+
cursorFrontmatter: true
|
|
63775
|
+
},
|
|
63776
|
+
codex: {
|
|
63777
|
+
kind: "section",
|
|
63778
|
+
path: () => join42(codexHome4(), "AGENTS.md")
|
|
63779
|
+
},
|
|
63780
|
+
opencode: {
|
|
63781
|
+
kind: "section",
|
|
63782
|
+
path: () => join42(homedir13(), ".config", "opencode", "AGENTS.md")
|
|
63783
|
+
},
|
|
63784
|
+
gemini: {
|
|
63785
|
+
kind: "section",
|
|
63786
|
+
path: () => join42(homedir13(), ".gemini", "GEMINI.md")
|
|
63787
|
+
},
|
|
63788
|
+
antigravity: {
|
|
63789
|
+
kind: "section",
|
|
63790
|
+
path: () => join42(homedir13(), ".gemini", "GEMINI.md")
|
|
63791
|
+
}
|
|
63792
|
+
};
|
|
63793
|
+
});
|
|
63794
|
+
|
|
63795
|
+
// src/setup/agents-md-step.ts
|
|
63796
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
63797
|
+
import { existsSync as existsSync29, readFileSync as readFileSync28, writeFileSync as writeFileSync19 } from "node:fs";
|
|
63798
|
+
import { join as join43 } from "node:path";
|
|
63799
|
+
function inGitWorkTree(cwd = process.cwd()) {
|
|
63800
|
+
try {
|
|
63801
|
+
const stdout = execSync2("git rev-parse --is-inside-work-tree", {
|
|
63802
|
+
cwd,
|
|
63803
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
63804
|
+
});
|
|
63805
|
+
return stdout.toString().trim() === "true";
|
|
63806
|
+
} catch {
|
|
63807
|
+
return false;
|
|
63808
|
+
}
|
|
63809
|
+
}
|
|
63810
|
+
function dosuAgentsSectionState(cwd = process.cwd()) {
|
|
63811
|
+
try {
|
|
63812
|
+
const path = join43(cwd, "AGENTS.md");
|
|
63813
|
+
if (!existsSync29(path))
|
|
63814
|
+
return "missing";
|
|
63815
|
+
const content = readFileSync28(path, "utf-8");
|
|
63816
|
+
const startMatch = content.match(SECTION_START_RE);
|
|
63817
|
+
if (!startMatch || !content.includes(DOSU_SECTION_END))
|
|
63818
|
+
return "missing";
|
|
63819
|
+
return Number(startMatch[1] ?? 0) >= DOSU_SECTION_VERSION ? "current" : "outdated";
|
|
63820
|
+
} catch {
|
|
63821
|
+
return "missing";
|
|
63822
|
+
}
|
|
63823
|
+
}
|
|
63824
|
+
function lineEndingFor2(content) {
|
|
63825
|
+
return content.includes(`\r
|
|
63826
|
+
`) ? `\r
|
|
63827
|
+
` : `
|
|
63828
|
+
`;
|
|
63829
|
+
}
|
|
63830
|
+
function renderDosuAgentsSection(content, lineEnding) {
|
|
63831
|
+
const body = content.trim().replace(/\r?\n/g, lineEnding);
|
|
63832
|
+
return `${DOSU_SECTION_START}${lineEnding}${body}${lineEnding}${DOSU_SECTION_END}`;
|
|
63833
|
+
}
|
|
63834
|
+
function buildDosuAgentsSection(content = FALLBACK_DOSU_RULE) {
|
|
63835
|
+
return renderDosuAgentsSection(content, `
|
|
63836
|
+
`);
|
|
63837
|
+
}
|
|
63838
|
+
function findSection2(content) {
|
|
63839
|
+
const startMatch = content.match(SECTION_START_RE);
|
|
63840
|
+
const start = startMatch?.index ?? -1;
|
|
63841
|
+
const end = content.indexOf(DOSU_SECTION_END, Math.max(start, 0));
|
|
63842
|
+
if (start === -1 && end === -1)
|
|
63843
|
+
return null;
|
|
63844
|
+
if (start === -1 || end < start) {
|
|
63845
|
+
throw new Error("Dosu AGENTS.md markers are incomplete; refusing to overwrite the file");
|
|
63846
|
+
}
|
|
63847
|
+
return { start, end };
|
|
63848
|
+
}
|
|
63849
|
+
function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RULE) {
|
|
63850
|
+
const path = join43(cwd, "AGENTS.md");
|
|
63851
|
+
if (!existsSync29(path)) {
|
|
63852
|
+
const section = buildDosuAgentsSection(content);
|
|
63853
|
+
writeFileSync19(path, `${section}
|
|
63854
|
+
`);
|
|
63855
|
+
return { path, action: "created" };
|
|
63856
|
+
}
|
|
63857
|
+
const existing = readFileSync28(path, "utf-8");
|
|
63858
|
+
const lineEnding = lineEndingFor2(existing);
|
|
63859
|
+
const section = renderDosuAgentsSection(content, lineEnding);
|
|
63860
|
+
const location = findSection2(existing);
|
|
63861
|
+
let next;
|
|
63862
|
+
if (location) {
|
|
63863
|
+
next = existing.slice(0, location.start) + section + existing.slice(location.end + DOSU_SECTION_END.length);
|
|
63864
|
+
} else {
|
|
63865
|
+
next = `${existing.trimEnd()}${lineEnding}${lineEnding}${section}${lineEnding}`;
|
|
63866
|
+
}
|
|
63867
|
+
if (next === existing)
|
|
63868
|
+
return { path, action: "unchanged" };
|
|
63869
|
+
writeFileSync19(path, next);
|
|
63870
|
+
return { path, action: "updated" };
|
|
63871
|
+
}
|
|
63872
|
+
async function stepUpdateAgentsMd(cwd = process.cwd(), content) {
|
|
63873
|
+
logger.info("setup", "Step: update AGENTS.md");
|
|
63874
|
+
try {
|
|
63875
|
+
const result = upsertDosuAgentsSection(cwd, content ?? await fetchDosuRule());
|
|
63876
|
+
logger.info("setup", `AGENTS.md ${result.action} at ${result.path}`);
|
|
63877
|
+
const status = result.action === "unchanged" ? "already up to date" : result.action;
|
|
63878
|
+
log2.success(formatSetupSummary("AGENTS.md", [{ path: result.path, status }]));
|
|
63879
|
+
return true;
|
|
63880
|
+
} catch (err) {
|
|
63881
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
63882
|
+
logger.error("setup", `AGENTS.md update failed: ${msg}`);
|
|
63883
|
+
log2.error(`Could not update AGENTS.md: ${msg}`);
|
|
63884
|
+
return false;
|
|
63885
|
+
}
|
|
63886
|
+
}
|
|
63887
|
+
var DOSU_SECTION_VERSION = 2, DOSU_SECTION_START, DOSU_SECTION_END = "<!-- dosu:mcp:end -->", SECTION_START_RE;
|
|
63888
|
+
var init_agents_md_step = __esm(() => {
|
|
63889
|
+
init_logger();
|
|
63890
|
+
init_installer();
|
|
63891
|
+
init_prompts();
|
|
63892
|
+
init_styles();
|
|
63893
|
+
DOSU_SECTION_START = `<!-- dosu:mcp:start v${DOSU_SECTION_VERSION} -->`;
|
|
63894
|
+
SECTION_START_RE = /<!-- dosu:mcp:start(?: v(\d+))? -->/;
|
|
63895
|
+
});
|
|
63896
|
+
|
|
63927
63897
|
// src/setup/analytics.ts
|
|
63928
63898
|
async function trackCliOnboardingEvent(cfg, onboardingRunID, event, properties = {}) {
|
|
63929
63899
|
try {
|
|
@@ -65391,7 +65361,7 @@ async function stepSelectTools(detected) {
|
|
|
65391
65361
|
initialValues: preselected,
|
|
65392
65362
|
statusFor: (id, picked) => {
|
|
65393
65363
|
if (configuredMap.get(id))
|
|
65394
|
-
return picked ? dim("configured") :
|
|
65364
|
+
return picked ? dim("configured") : import_picocolors34.default.yellow("will remove");
|
|
65395
65365
|
return picked ? brand("will configure") : undefined;
|
|
65396
65366
|
},
|
|
65397
65367
|
summary: (picked) => {
|
|
@@ -65566,7 +65536,7 @@ ${dim(wrapLog("Run it inside a session to keep that session out of studying. Rem
|
|
|
65566
65536
|
log2.success("All agents already configured. No changes needed.");
|
|
65567
65537
|
}
|
|
65568
65538
|
}
|
|
65569
|
-
var
|
|
65539
|
+
var import_picocolors34, OAUTH_ANALYTICS_REASONS, SETUP_HANDSHAKE_TIMEOUT_MS = 1800000, LIBRARY_SELECT_CANCELLED;
|
|
65570
65540
|
var init_flow2 = __esm(() => {
|
|
65571
65541
|
init_dist();
|
|
65572
65542
|
init_errors3();
|
|
@@ -65591,7 +65561,7 @@ var init_flow2 = __esm(() => {
|
|
|
65591
65561
|
init_github_step();
|
|
65592
65562
|
init_rules_step();
|
|
65593
65563
|
init_styles();
|
|
65594
|
-
|
|
65564
|
+
import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
65595
65565
|
OAUTH_ANALYTICS_REASONS = new Set([
|
|
65596
65566
|
"access_denied",
|
|
65597
65567
|
"bad_oauth_state",
|
|
@@ -65605,6 +65575,298 @@ var init_flow2 = __esm(() => {
|
|
|
65605
65575
|
LIBRARY_SELECT_CANCELLED = Symbol("library-select-cancelled");
|
|
65606
65576
|
});
|
|
65607
65577
|
|
|
65578
|
+
// src/commands/upgrade.ts
|
|
65579
|
+
import { spawnSync } from "node:child_process";
|
|
65580
|
+
import { realpathSync as realpathSync2 } from "node:fs";
|
|
65581
|
+
import { homedir as homedir14 } from "node:os";
|
|
65582
|
+
import { posix, win32 as win322 } from "node:path";
|
|
65583
|
+
function isAbsoluteCommandProcessor(value) {
|
|
65584
|
+
return Boolean(value && win322.isAbsolute(value) && win322.basename(value).toLowerCase() === "cmd.exe");
|
|
65585
|
+
}
|
|
65586
|
+
function windowsCommandProcessor(env = process.env) {
|
|
65587
|
+
if (isAbsoluteCommandProcessor(env.ComSpec))
|
|
65588
|
+
return env.ComSpec;
|
|
65589
|
+
const systemRoot = env.SystemRoot && win322.isAbsolute(env.SystemRoot) ? env.SystemRoot : "C:\\Windows";
|
|
65590
|
+
return win322.join(systemRoot, "System32", "cmd.exe");
|
|
65591
|
+
}
|
|
65592
|
+
function safePackageManagerEnv(env) {
|
|
65593
|
+
return {
|
|
65594
|
+
...env,
|
|
65595
|
+
COREPACK_ENABLE_NETWORK: "0",
|
|
65596
|
+
COREPACK_ENABLE_PROJECT_SPEC: "0",
|
|
65597
|
+
YARN_IGNORE_PATH: "1"
|
|
65598
|
+
};
|
|
65599
|
+
}
|
|
65600
|
+
function buildPackageManagerInvocation(manager, action, platform = process.platform, comSpec, env = process.env) {
|
|
65601
|
+
const args = action === "locate" ? PACKAGE_MANAGERS[manager].locateArgs : PACKAGE_MANAGERS[manager].installArgs;
|
|
65602
|
+
const safeEnv = safePackageManagerEnv(env);
|
|
65603
|
+
if (platform === "win32") {
|
|
65604
|
+
return {
|
|
65605
|
+
command: isAbsoluteCommandProcessor(comSpec) ? comSpec : windowsCommandProcessor(env),
|
|
65606
|
+
args: ["/d", "/s", "/c", [manager, ...args].join(" ")],
|
|
65607
|
+
env: { ...safeEnv, NoDefaultCurrentDirectoryInExePath: "1" }
|
|
65608
|
+
};
|
|
65609
|
+
}
|
|
65610
|
+
return { command: manager, args: [...args], env: safeEnv };
|
|
65611
|
+
}
|
|
65612
|
+
function packageRoots(manager, platform, comSpec, env, cwd) {
|
|
65613
|
+
const invocation = buildPackageManagerInvocation(manager, "locate", platform, comSpec, env);
|
|
65614
|
+
const result = spawnSync(invocation.command, invocation.args, {
|
|
65615
|
+
cwd,
|
|
65616
|
+
encoding: "utf8",
|
|
65617
|
+
env: invocation.env,
|
|
65618
|
+
shell: false,
|
|
65619
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
65620
|
+
timeout: PROBE_TIMEOUT_MS
|
|
65621
|
+
});
|
|
65622
|
+
if (result.status !== 0 || typeof result.stdout !== "string")
|
|
65623
|
+
return [];
|
|
65624
|
+
const path = platform === "win32" ? win322 : posix;
|
|
65625
|
+
const lines = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => path.isAbsolute(line));
|
|
65626
|
+
if (manager === "pnpm") {
|
|
65627
|
+
return lines.filter((line) => path.basename(line) === "cli" && path.basename(path.dirname(line)) === "@dosu" && path.basename(path.dirname(path.dirname(line))) === "node_modules");
|
|
65628
|
+
}
|
|
65629
|
+
if (lines.length !== 1)
|
|
65630
|
+
return [];
|
|
65631
|
+
return [
|
|
65632
|
+
manager === "npm" ? path.join(lines[0], "@dosu", "cli") : path.join(lines[0], "node_modules", "@dosu", "cli")
|
|
65633
|
+
];
|
|
65634
|
+
}
|
|
65635
|
+
function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd = homedir14()) {
|
|
65636
|
+
const path = platform === "win32" ? win322 : posix;
|
|
65637
|
+
if (!entrypoint || !path.isAbsolute(entrypoint))
|
|
65638
|
+
return null;
|
|
65639
|
+
let realEntrypoint;
|
|
65640
|
+
try {
|
|
65641
|
+
realEntrypoint = realpathSync2(entrypoint);
|
|
65642
|
+
} catch {
|
|
65643
|
+
return null;
|
|
65644
|
+
}
|
|
65645
|
+
const owners = Object.keys(PACKAGE_MANAGERS).filter((manager) => packageRoots(manager, platform, comSpec, env, cwd).some((root) => {
|
|
65646
|
+
try {
|
|
65647
|
+
const relative = path.relative(realpathSync2(root), realEntrypoint);
|
|
65648
|
+
return relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
65649
|
+
} catch {
|
|
65650
|
+
return false;
|
|
65651
|
+
}
|
|
65652
|
+
}));
|
|
65653
|
+
return owners.length === 1 ? owners[0] : null;
|
|
65654
|
+
}
|
|
65655
|
+
function upgradePlan(channel, manager, platform, comSpec, env = process.env) {
|
|
65656
|
+
if (channel === "homebrew") {
|
|
65657
|
+
return {
|
|
65658
|
+
label: "Homebrew",
|
|
65659
|
+
command: "brew",
|
|
65660
|
+
args: ["upgrade", "dosu-ai/dosu/dosu"],
|
|
65661
|
+
manualCommand: BREW_MANUAL_COMMAND
|
|
65662
|
+
};
|
|
65663
|
+
}
|
|
65664
|
+
if (channel === "npm" && manager) {
|
|
65665
|
+
const invocation = buildPackageManagerInvocation(manager, "install", platform, comSpec, env);
|
|
65666
|
+
return {
|
|
65667
|
+
label: PACKAGE_MANAGERS[manager].label,
|
|
65668
|
+
...invocation,
|
|
65669
|
+
manualCommand: [manager, ...PACKAGE_MANAGERS[manager].installArgs].join(" ")
|
|
65670
|
+
};
|
|
65671
|
+
}
|
|
65672
|
+
return null;
|
|
65673
|
+
}
|
|
65674
|
+
function printNonGlobalPackageGuidance() {
|
|
65675
|
+
console.log("This Dosu copy is not a uniquely identified global package installation, so it was not changed.");
|
|
65676
|
+
console.log(`
|
|
65677
|
+
Run the latest version without installing:
|
|
65678
|
+
${NPX_COMMAND}`);
|
|
65679
|
+
console.log(`
|
|
65680
|
+
Or install Dosu globally with your package manager:`);
|
|
65681
|
+
for (const manager of Object.keys(PACKAGE_MANAGERS)) {
|
|
65682
|
+
console.log(` ${manager} ${PACKAGE_MANAGERS[manager].installArgs.join(" ")}`);
|
|
65683
|
+
}
|
|
65684
|
+
}
|
|
65685
|
+
function runUpgrade(channel = INSTALL_CHANNEL, options = {}) {
|
|
65686
|
+
const platform = options.platform ?? process.platform;
|
|
65687
|
+
const env = options.env ?? process.env;
|
|
65688
|
+
const cwd = options.cwd ?? homedir14();
|
|
65689
|
+
let manager = null;
|
|
65690
|
+
if (channel === "npm") {
|
|
65691
|
+
if (isNpxInvocation(channel, env)) {
|
|
65692
|
+
printNonGlobalPackageGuidance();
|
|
65693
|
+
return 1;
|
|
65694
|
+
}
|
|
65695
|
+
manager = owningPackageManager(options.entrypoint ?? process.argv[1], platform, options.comSpec, env, cwd);
|
|
65696
|
+
if (!manager) {
|
|
65697
|
+
if (env.DOSU_DEV === "true") {
|
|
65698
|
+
console.log("DOSU_DEV=true and this copy is not a global package: skipping the package install.");
|
|
65699
|
+
return 0;
|
|
65700
|
+
}
|
|
65701
|
+
printNonGlobalPackageGuidance();
|
|
65702
|
+
return 1;
|
|
65703
|
+
}
|
|
65704
|
+
}
|
|
65705
|
+
const plan = upgradePlan(channel, manager, platform, options.comSpec, env);
|
|
65706
|
+
if (!plan) {
|
|
65707
|
+
console.log("Automatic upgrades are not available for this installation yet.");
|
|
65708
|
+
console.log(`Download the latest release:
|
|
65709
|
+
${RELEASES_URL}`);
|
|
65710
|
+
return 1;
|
|
65711
|
+
}
|
|
65712
|
+
console.log(`Updating Dosu with ${plan.label}...`);
|
|
65713
|
+
console.log(` ${plan.manualCommand}
|
|
65714
|
+
`);
|
|
65715
|
+
const result = spawnSync(plan.command, plan.args, {
|
|
65716
|
+
...channel === "npm" ? { cwd } : {},
|
|
65717
|
+
...plan.env ? { env: plan.env } : {},
|
|
65718
|
+
shell: false,
|
|
65719
|
+
stdio: "inherit"
|
|
65720
|
+
});
|
|
65721
|
+
if (result.error || result.status !== 0) {
|
|
65722
|
+
console.error(`
|
|
65723
|
+
Could not update Dosu automatically.`);
|
|
65724
|
+
console.error(`Run manually:
|
|
65725
|
+
${plan.manualCommand}`);
|
|
65726
|
+
return result.status && result.status > 0 ? result.status : 1;
|
|
65727
|
+
}
|
|
65728
|
+
console.log(import_picocolors35.default.green(`
|
|
65729
|
+
✓ Update command completed.`));
|
|
65730
|
+
console.log('Run "dosu --version" to verify.');
|
|
65731
|
+
return 0;
|
|
65732
|
+
}
|
|
65733
|
+
function postUpgradeArgs(fromVersion = VERSION) {
|
|
65734
|
+
return ["upgrade", "--finish", fromVersion];
|
|
65735
|
+
}
|
|
65736
|
+
function newBinaryInvocation(channel, args, entrypoint = process.argv[1], execPath = process.execPath) {
|
|
65737
|
+
if (channel === "npm") {
|
|
65738
|
+
return entrypoint ? { command: execPath, args: [entrypoint, ...args] } : null;
|
|
65739
|
+
}
|
|
65740
|
+
if (channel === "homebrew") {
|
|
65741
|
+
return { command: "dosu", args };
|
|
65742
|
+
}
|
|
65743
|
+
return null;
|
|
65744
|
+
}
|
|
65745
|
+
function isInteractiveTerminal() {
|
|
65746
|
+
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
65747
|
+
}
|
|
65748
|
+
function finishWithNewBinary(channel, options) {
|
|
65749
|
+
const invocation = newBinaryInvocation(channel, postUpgradeArgs(), options.entrypoint ?? process.argv[1]);
|
|
65750
|
+
if (!invocation) {
|
|
65751
|
+
console.error(SETUP_FALLBACK);
|
|
65752
|
+
return;
|
|
65753
|
+
}
|
|
65754
|
+
const result = spawnSync(invocation.command, invocation.args, {
|
|
65755
|
+
cwd: options.cwd ?? homedir14(),
|
|
65756
|
+
shell: false,
|
|
65757
|
+
stdio: "inherit"
|
|
65758
|
+
});
|
|
65759
|
+
if (result.error || result.status !== 0) {
|
|
65760
|
+
console.error(SETUP_FALLBACK);
|
|
65761
|
+
}
|
|
65762
|
+
}
|
|
65763
|
+
async function completeUpgrade(channel = INSTALL_CHANNEL, options = {}) {
|
|
65764
|
+
const status = runUpgrade(channel, options);
|
|
65765
|
+
if (status !== 0)
|
|
65766
|
+
return status;
|
|
65767
|
+
finishWithNewBinary(channel, options);
|
|
65768
|
+
return 0;
|
|
65769
|
+
}
|
|
65770
|
+
async function finishUpgrade(from, options = {}) {
|
|
65771
|
+
const previous = SEMVER.test(from) ? from : null;
|
|
65772
|
+
if (!needsMcpRefresh(previous, VERSION)) {
|
|
65773
|
+
checkForSkillUpdates();
|
|
65774
|
+
writeMcpRefreshCache({ version: VERSION });
|
|
65775
|
+
console.log(import_picocolors35.default.green(`✓ Dosu ${VERSION} is ready. Your AI agents need no changes.`));
|
|
65776
|
+
return 0;
|
|
65777
|
+
}
|
|
65778
|
+
if (options.interactive ?? isInteractiveTerminal()) {
|
|
65779
|
+
console.log(`
|
|
65780
|
+
This update changes how agents connect to Dosu. Running setup...
|
|
65781
|
+
`);
|
|
65782
|
+
await Promise.resolve().then(() => init_flow2());
|
|
65783
|
+
await runSetup();
|
|
65784
|
+
return 0;
|
|
65785
|
+
}
|
|
65786
|
+
checkForSkillUpdates();
|
|
65787
|
+
const cfg = loadConfigNonBlocking();
|
|
65788
|
+
if (!cfg || !canRefreshMcp(cfg)) {
|
|
65789
|
+
console.error(SETUP_FALLBACK);
|
|
65790
|
+
return 0;
|
|
65791
|
+
}
|
|
65792
|
+
console.log(`
|
|
65793
|
+
Refreshing agent MCP configs with the new version...`);
|
|
65794
|
+
const result = refreshConfiguredProviders(cfg);
|
|
65795
|
+
writeMcpRefreshCache({ version: VERSION });
|
|
65796
|
+
for (const provider of result.updated)
|
|
65797
|
+
console.log(` ✓ ${provider.name()}`);
|
|
65798
|
+
for (const { provider, error } of result.failed) {
|
|
65799
|
+
console.log(` ✗ ${provider.name()}: ${error.message}`);
|
|
65800
|
+
}
|
|
65801
|
+
if (result.failed.length > 0)
|
|
65802
|
+
console.error(SETUP_FALLBACK);
|
|
65803
|
+
return 0;
|
|
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
|
+
}
|
|
65824
|
+
function upgradeCommand() {
|
|
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
|
+
}
|
|
65836
|
+
if (status !== 0)
|
|
65837
|
+
process.exitCode = status;
|
|
65838
|
+
});
|
|
65839
|
+
}
|
|
65840
|
+
var import_picocolors35, PACKAGE_NAME = "@dosu/cli", LATEST_PACKAGE, BREW_MANUAL_COMMAND = "brew upgrade dosu-ai/dosu/dosu", NPX_COMMAND = "npx -y @dosu/cli@latest", PROBE_TIMEOUT_MS = 5000, RELEASES_URL = "https://github.com/dosu-ai/dosu-cli/releases/latest", PACKAGE_MANAGERS, SETUP_FALLBACK = 'Run "dosu setup" to finish updating your AI agents.', SEMVER;
|
|
65841
|
+
var init_upgrade = __esm(() => {
|
|
65842
|
+
init_commander();
|
|
65843
|
+
init_config();
|
|
65844
|
+
init_refresh();
|
|
65845
|
+
init_auto_update();
|
|
65846
|
+
init_mcp_refresh_check();
|
|
65847
|
+
init_skill_update_check();
|
|
65848
|
+
import_picocolors35 = __toESM(require_picocolors(), 1);
|
|
65849
|
+
LATEST_PACKAGE = `${PACKAGE_NAME}@latest`;
|
|
65850
|
+
PACKAGE_MANAGERS = {
|
|
65851
|
+
npm: {
|
|
65852
|
+
label: "npm",
|
|
65853
|
+
locateArgs: ["root", "-g"],
|
|
65854
|
+
installArgs: ["install", "-g", LATEST_PACKAGE]
|
|
65855
|
+
},
|
|
65856
|
+
pnpm: {
|
|
65857
|
+
label: "pnpm",
|
|
65858
|
+
locateArgs: ["list", "-g", "--depth=0", "--parseable", PACKAGE_NAME],
|
|
65859
|
+
installArgs: ["add", "-g", LATEST_PACKAGE]
|
|
65860
|
+
},
|
|
65861
|
+
yarn: {
|
|
65862
|
+
label: "Yarn Classic",
|
|
65863
|
+
locateArgs: ["--silent", "global", "dir"],
|
|
65864
|
+
installArgs: ["global", "add", LATEST_PACKAGE]
|
|
65865
|
+
}
|
|
65866
|
+
};
|
|
65867
|
+
SEMVER = /^\d+\.\d+\.\d+/;
|
|
65868
|
+
});
|
|
65869
|
+
|
|
65608
65870
|
// src/tui/analytics-view.ts
|
|
65609
65871
|
function analyticsListHeight(rows) {
|
|
65610
65872
|
const room = frameMaxLines(rows) - ANALYTICS_VIEW_CHROME_LINES;
|
|
@@ -66288,7 +66550,7 @@ var init_pages_view = __esm(() => {
|
|
|
66288
66550
|
});
|
|
66289
66551
|
|
|
66290
66552
|
// src/tui/tui.ts
|
|
66291
|
-
import { homedir as
|
|
66553
|
+
import { homedir as homedir15 } from "node:os";
|
|
66292
66554
|
import { basename as basename6 } from "node:path";
|
|
66293
66555
|
async function probeSession(cfg) {
|
|
66294
66556
|
if (!isAuthenticated(cfg) || !isTokenExpired(cfg))
|
|
@@ -66553,7 +66815,7 @@ async function runSettings(cfg) {
|
|
|
66553
66815
|
}
|
|
66554
66816
|
}
|
|
66555
66817
|
function displayDir(dir) {
|
|
66556
|
-
const home =
|
|
66818
|
+
const home = homedir15();
|
|
66557
66819
|
return dir === home ? "~" : dir.startsWith(`${home}/`) ? `~${dir.slice(home.length)}` : dir;
|
|
66558
66820
|
}
|
|
66559
66821
|
function discoverProjectDirs() {
|
|
@@ -67263,7 +67525,7 @@ var init_flow3 = __esm(() => {
|
|
|
67263
67525
|
});
|
|
67264
67526
|
|
|
67265
67527
|
// src/cli/cli.ts
|
|
67266
|
-
import { readFileSync as
|
|
67528
|
+
import { readFileSync as readFileSync29, unlinkSync as unlinkSync6 } from "node:fs";
|
|
67267
67529
|
function shouldRunBackgroundChecks(actionName) {
|
|
67268
67530
|
return actionName !== "upgrade";
|
|
67269
67531
|
}
|
|
@@ -67709,7 +67971,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
|
|
|
67709
67971
|
}
|
|
67710
67972
|
if (opts.follow) {
|
|
67711
67973
|
try {
|
|
67712
|
-
const lines =
|
|
67974
|
+
const lines = readFileSync29(logPath, "utf-8").split(`
|
|
67713
67975
|
`);
|
|
67714
67976
|
if (lines.at(-1) === "")
|
|
67715
67977
|
lines.pop();
|
|
@@ -67725,7 +67987,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
|
|
|
67725
67987
|
if (opts.tail !== undefined) {
|
|
67726
67988
|
const n = typeof opts.tail === "string" ? parseInt(opts.tail, 10) || 50 : 50;
|
|
67727
67989
|
try {
|
|
67728
|
-
const content =
|
|
67990
|
+
const content = readFileSync29(logPath, "utf-8");
|
|
67729
67991
|
const lines = content.split(`
|
|
67730
67992
|
`);
|
|
67731
67993
|
console.log(lines.slice(-n).join(`
|
|
@@ -67851,4 +68113,4 @@ main().catch((err) => {
|
|
|
67851
68113
|
process.exit(1);
|
|
67852
68114
|
});
|
|
67853
68115
|
|
|
67854
|
-
//# debugId=
|
|
68116
|
+
//# debugId=41cac967-78f1-f75a-6475-6e2164756e21
|