@dosu/cli 0.13.1 → 0.13.3
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/bin/dosu.js +75 -30
- package/package.json +3 -2
package/bin/dosu.js
CHANGED
|
@@ -4341,7 +4341,7 @@ function getSupabaseAnonKey() {
|
|
|
4341
4341
|
function getVersionString() {
|
|
4342
4342
|
return `v${VERSION}`;
|
|
4343
4343
|
}
|
|
4344
|
-
var VERSION = "0.13.
|
|
4344
|
+
var VERSION = "0.13.3";
|
|
4345
4345
|
|
|
4346
4346
|
// src/debug/logger.ts
|
|
4347
4347
|
import {
|
|
@@ -4353,6 +4353,17 @@ import {
|
|
|
4353
4353
|
writeFileSync as writeFileSync2
|
|
4354
4354
|
} from "node:fs";
|
|
4355
4355
|
import { join as join2 } from "node:path";
|
|
4356
|
+
function redactSecrets(message) {
|
|
4357
|
+
let redacted = message;
|
|
4358
|
+
for (const key of SECRET_QUERY_KEYS) {
|
|
4359
|
+
const queryPattern = new RegExp(`([?&]${key}=)[^\\s&#]+`, "gi");
|
|
4360
|
+
redacted = redacted.replace(queryPattern, `$1${REDACTED}`);
|
|
4361
|
+
}
|
|
4362
|
+
redacted = redacted.replace(/(\b(?:access_token|refresh_token|api_key|apikey|id_token|token)\b\s*[:=]\s*)("[^"]+"|'[^']+'|[^\s,]+)/gi, `$1${REDACTED}`);
|
|
4363
|
+
redacted = redacted.replace(/(X-Dosu-API-Key:\s*)[^\s,]+/gi, `$1${REDACTED}`);
|
|
4364
|
+
redacted = redacted.replace(/(Authorization:\s*Bearer\s+)[^\s,]+/gi, `$1${REDACTED}`);
|
|
4365
|
+
return redacted;
|
|
4366
|
+
}
|
|
4356
4367
|
function ensureInit() {
|
|
4357
4368
|
if (!initialized) {
|
|
4358
4369
|
initLogger({});
|
|
@@ -4409,7 +4420,8 @@ function initLogger(opts) {
|
|
|
4409
4420
|
function writeEntry(level, mod, message) {
|
|
4410
4421
|
ensureInit();
|
|
4411
4422
|
const timestamp = new Date().toISOString();
|
|
4412
|
-
const
|
|
4423
|
+
const safeMessage = redactSecrets(message);
|
|
4424
|
+
const line = `[${timestamp}] [${level}] [${mod}] ${safeMessage}
|
|
4413
4425
|
`;
|
|
4414
4426
|
try {
|
|
4415
4427
|
appendFileSync(resolveLogPath(), line, { mode: 384 });
|
|
@@ -4424,10 +4436,19 @@ function writeEntry(level, mod, message) {
|
|
|
4424
4436
|
console.error(colorize(line.trimEnd()));
|
|
4425
4437
|
}
|
|
4426
4438
|
}
|
|
4427
|
-
var import_picocolors, MAX_LOG_SIZE = 1048576, TRUNCATE_KEEP = 524288, LOG_FILENAME = "debug.log", initialized = false, debugToConsole = false, logFilePath = null, logger;
|
|
4439
|
+
var import_picocolors, MAX_LOG_SIZE = 1048576, TRUNCATE_KEEP = 524288, LOG_FILENAME = "debug.log", REDACTED = "[REDACTED]", SECRET_QUERY_KEYS, initialized = false, debugToConsole = false, logFilePath = null, logger;
|
|
4428
4440
|
var init_logger = __esm(() => {
|
|
4429
4441
|
init_config();
|
|
4430
4442
|
import_picocolors = __toESM(require_picocolors(), 1);
|
|
4443
|
+
SECRET_QUERY_KEYS = [
|
|
4444
|
+
"access_token",
|
|
4445
|
+
"refresh_token",
|
|
4446
|
+
"api_key",
|
|
4447
|
+
"apikey",
|
|
4448
|
+
"token",
|
|
4449
|
+
"id_token",
|
|
4450
|
+
"code"
|
|
4451
|
+
];
|
|
4431
4452
|
logger = {
|
|
4432
4453
|
init: initLogger,
|
|
4433
4454
|
getLogPath() {
|
|
@@ -6635,7 +6656,8 @@ var init_skill = __esm(() => {
|
|
|
6635
6656
|
});
|
|
6636
6657
|
|
|
6637
6658
|
// src/mcp/config-helpers.ts
|
|
6638
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5
|
|
6659
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
6660
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
6639
6661
|
import { dirname } from "node:path";
|
|
6640
6662
|
function mcpURL(deploymentID) {
|
|
6641
6663
|
return `${getBackendURL()}/v1/mcp/deployments/${deploymentID}`;
|
|
@@ -6644,6 +6666,9 @@ function mcpBaseURL() {
|
|
|
6644
6666
|
return `${getBackendURL()}/v1/mcp`;
|
|
6645
6667
|
}
|
|
6646
6668
|
function mcpHeaders(apiKey) {
|
|
6669
|
+
if (!apiKey) {
|
|
6670
|
+
throw new Error("API key is required. Run 'dosu setup' to create one.");
|
|
6671
|
+
}
|
|
6647
6672
|
return { "X-Dosu-API-Key": apiKey };
|
|
6648
6673
|
}
|
|
6649
6674
|
function loadJSONConfig(path) {
|
|
@@ -6708,11 +6733,14 @@ function stripJSONComments(data) {
|
|
|
6708
6733
|
return result.join("");
|
|
6709
6734
|
}
|
|
6710
6735
|
function saveJSONConfig(path, cfg) {
|
|
6736
|
+
writeSecureFile(path, JSON.stringify(cfg, null, 2));
|
|
6737
|
+
}
|
|
6738
|
+
function writeSecureFile(path, content) {
|
|
6711
6739
|
const dir = dirname(path);
|
|
6712
6740
|
if (!existsSync4(dir)) {
|
|
6713
|
-
mkdirSync4(dir, { recursive: true });
|
|
6741
|
+
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
6714
6742
|
}
|
|
6715
|
-
|
|
6743
|
+
writeFileAtomic.sync(path, content, { mode: 384, chown: false });
|
|
6716
6744
|
}
|
|
6717
6745
|
function isJSONKeyConfigured(configPath, topLevelKey) {
|
|
6718
6746
|
const cfg = loadJSONConfig(configPath);
|
|
@@ -6744,7 +6772,11 @@ function removeJSONServer(configPath, topKey) {
|
|
|
6744
6772
|
}
|
|
6745
6773
|
saveJSONConfig(configPath, jsonCfg);
|
|
6746
6774
|
}
|
|
6747
|
-
var
|
|
6775
|
+
var require2, writeFileAtomic;
|
|
6776
|
+
var init_config_helpers = __esm(() => {
|
|
6777
|
+
require2 = createRequire2(import.meta.url);
|
|
6778
|
+
writeFileAtomic = require2("write-file-atomic");
|
|
6779
|
+
});
|
|
6748
6780
|
|
|
6749
6781
|
// src/mcp/detect.ts
|
|
6750
6782
|
import { existsSync as existsSync5 } from "node:fs";
|
|
@@ -6938,8 +6970,8 @@ var init_cline_cli = __esm(() => {
|
|
|
6938
6970
|
});
|
|
6939
6971
|
|
|
6940
6972
|
// src/mcp/providers/codex.ts
|
|
6941
|
-
import { existsSync as existsSync6,
|
|
6942
|
-
import {
|
|
6973
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
|
|
6974
|
+
import { join as join9 } from "node:path";
|
|
6943
6975
|
function codexHome() {
|
|
6944
6976
|
return process.env.CODEX_HOME ?? expandHome("~/.codex");
|
|
6945
6977
|
}
|
|
@@ -6954,10 +6986,7 @@ function readTOML(path) {
|
|
|
6954
6986
|
return readFileSync6(path, "utf-8");
|
|
6955
6987
|
}
|
|
6956
6988
|
function writeTOML(path, content) {
|
|
6957
|
-
|
|
6958
|
-
if (!existsSync6(dir))
|
|
6959
|
-
mkdirSync5(dir, { recursive: true });
|
|
6960
|
-
writeFileSync5(path, content);
|
|
6989
|
+
writeSecureFile(path, content);
|
|
6961
6990
|
}
|
|
6962
6991
|
function mcpEndpoint(cfg) {
|
|
6963
6992
|
if (cfg.mode === MODE_OSS)
|
|
@@ -7139,17 +7168,29 @@ function mcpEndpoint3(cfg) {
|
|
|
7139
7168
|
throw new Error("deployment ID is required");
|
|
7140
7169
|
return mcpURL(cfg.deployment_id);
|
|
7141
7170
|
}
|
|
7171
|
+
function maskSecret(secret) {
|
|
7172
|
+
if (secret.length <= 8)
|
|
7173
|
+
return "[hidden]";
|
|
7174
|
+
const visibleChars = Math.min(4, Math.floor(secret.length / 4));
|
|
7175
|
+
return `${secret.slice(0, visibleChars)}...${secret.slice(-visibleChars)}`;
|
|
7176
|
+
}
|
|
7142
7177
|
var ManualProvider = () => ({
|
|
7143
7178
|
name: () => "Manual Configuration",
|
|
7144
7179
|
id: () => "manual",
|
|
7145
7180
|
supportsLocal: () => false,
|
|
7146
|
-
install(cfg) {
|
|
7181
|
+
install(cfg, _global, opts = {}) {
|
|
7147
7182
|
const url = mcpEndpoint3(cfg);
|
|
7183
|
+
const apiKey = mcpHeaders(cfg.api_key)["X-Dosu-API-Key"];
|
|
7184
|
+
const headerValue = opts.showSecret ? apiKey : maskSecret(apiKey);
|
|
7148
7185
|
console.log("Use these details to configure the Dosu MCP server in your client:");
|
|
7149
7186
|
console.log();
|
|
7150
7187
|
console.log(` Transport: HTTP`);
|
|
7151
7188
|
console.log(` Endpoint: ${url}`);
|
|
7152
|
-
console.log(` Header: X-Dosu-API-Key: ${
|
|
7189
|
+
console.log(` Header: X-Dosu-API-Key: ${headerValue}`);
|
|
7190
|
+
if (!opts.showSecret) {
|
|
7191
|
+
console.log();
|
|
7192
|
+
console.log(" Secret hidden. Re-run with --show-secret to print the full API key.");
|
|
7193
|
+
}
|
|
7153
7194
|
console.log();
|
|
7154
7195
|
},
|
|
7155
7196
|
remove() {
|
|
@@ -8659,15 +8700,16 @@ async function createDeploymentForRepo(trpc, orgID, spaceID, repo) {
|
|
|
8659
8700
|
await deleteOrphanDeployment(trpc, deployment.deployment_id, repo.slug);
|
|
8660
8701
|
return null;
|
|
8661
8702
|
}
|
|
8662
|
-
|
|
8703
|
+
const dataSourceID = dataSource.data_source_id;
|
|
8704
|
+
await trpc.dataSource.syncDataSource.mutate(dataSourceID);
|
|
8663
8705
|
const spaceDeployments = await trpc.workspaces.listForSpace.query(spaceID);
|
|
8664
8706
|
await Promise.all(spaceDeployments.map((d3) => trpc.deploymentDataSource.create.mutate({
|
|
8665
8707
|
deployment_id: d3.deployment_id,
|
|
8666
|
-
data_source_id:
|
|
8708
|
+
data_source_id: dataSourceID
|
|
8667
8709
|
})));
|
|
8668
8710
|
return {
|
|
8669
8711
|
deployment_id: deployment.deployment_id,
|
|
8670
|
-
data_source_id:
|
|
8712
|
+
data_source_id: dataSourceID
|
|
8671
8713
|
};
|
|
8672
8714
|
} catch (err) {
|
|
8673
8715
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -9685,7 +9727,7 @@ async function startCallbackServer() {
|
|
|
9685
9727
|
const url = new URL(req.url ?? "/", `http://localhost`);
|
|
9686
9728
|
const cookieLen = (req.headers.cookie ?? "").length;
|
|
9687
9729
|
const ua = req.headers["user-agent"] ?? "none";
|
|
9688
|
-
logger.debug("auth.server", `Request: ${req.method} ${
|
|
9730
|
+
logger.debug("auth.server", `Request: ${req.method} ${url.pathname} cookie-len=${cookieLen} ua=${ua} has-token=${url.searchParams.has("access_token")}`);
|
|
9689
9731
|
if (url.pathname !== "/callback") {
|
|
9690
9732
|
logger.debug("auth.server", `404: ${url.pathname}`);
|
|
9691
9733
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
@@ -10544,8 +10586,8 @@ var init_flow2 = __esm(() => {
|
|
|
10544
10586
|
});
|
|
10545
10587
|
|
|
10546
10588
|
// src/commands/insights.ts
|
|
10547
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
10548
|
-
import { dirname as
|
|
10589
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync, unlinkSync, writeFileSync as writeFileSync4 } from "node:fs";
|
|
10590
|
+
import { dirname as dirname2, join as join19 } from "node:path";
|
|
10549
10591
|
function shuffled(arr) {
|
|
10550
10592
|
const copy2 = [...arr];
|
|
10551
10593
|
for (let i = copy2.length - 1;i > 0; i--) {
|
|
@@ -10743,10 +10785,10 @@ function defaultRunner(cfg) {
|
|
|
10743
10785
|
build: buildInsights,
|
|
10744
10786
|
render: renderHTML,
|
|
10745
10787
|
writeFile: (path2, content) => {
|
|
10746
|
-
const dir =
|
|
10788
|
+
const dir = dirname2(path2);
|
|
10747
10789
|
if (!existsSync9(dir))
|
|
10748
|
-
|
|
10749
|
-
|
|
10790
|
+
mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
10791
|
+
writeFileSync4(path2, content, { mode: 384 });
|
|
10750
10792
|
},
|
|
10751
10793
|
prune: pruneOldReports,
|
|
10752
10794
|
openInBrowser: async (path2) => {
|
|
@@ -12377,7 +12419,7 @@ init_skill_update_check();
|
|
|
12377
12419
|
init_config();
|
|
12378
12420
|
init_logger();
|
|
12379
12421
|
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
12380
|
-
import { existsSync as existsSync10, mkdirSync as
|
|
12422
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
|
|
12381
12423
|
import { join as join20 } from "node:path";
|
|
12382
12424
|
var CACHE_FILENAME2 = "update-check.json";
|
|
12383
12425
|
var CHECK_INTERVAL_MS2 = 24 * 60 * 60 * 1000;
|
|
@@ -12421,9 +12463,9 @@ function writeCache(cache) {
|
|
|
12421
12463
|
try {
|
|
12422
12464
|
const dir = getConfigDir();
|
|
12423
12465
|
if (!existsSync10(dir)) {
|
|
12424
|
-
|
|
12466
|
+
mkdirSync6(dir, { recursive: true, mode: 448 });
|
|
12425
12467
|
}
|
|
12426
|
-
|
|
12468
|
+
writeFileSync5(getCachePath2(), JSON.stringify(cache), { mode: 384 });
|
|
12427
12469
|
} catch {}
|
|
12428
12470
|
}
|
|
12429
12471
|
async function fetchLatestVersion() {
|
|
@@ -12556,7 +12598,7 @@ function createProgram() {
|
|
|
12556
12598
|
}
|
|
12557
12599
|
});
|
|
12558
12600
|
const mcp = program2.command("mcp").description("Manage MCP server integrations");
|
|
12559
|
-
mcp.command("add <agent>").description("Add Dosu MCP to an AI tool").option("-g, --global", "Add globally (all projects) instead of project-local", false).action((toolId, opts) => {
|
|
12601
|
+
mcp.command("add <agent>").description("Add Dosu MCP to an AI tool").option("-g, --global", "Add globally (all projects) instead of project-local", false).option("--show-secret", "Print full manual configuration secrets", false).action((toolId, opts) => {
|
|
12560
12602
|
let provider;
|
|
12561
12603
|
try {
|
|
12562
12604
|
provider = getProvider(toolId.toLowerCase());
|
|
@@ -12573,8 +12615,11 @@ function createProgram() {
|
|
|
12573
12615
|
if (cfg.mode !== MODE_OSS && !cfg.deployment_id) {
|
|
12574
12616
|
throw new Error("no MCP selected. Run 'dosu' to open the TUI and select an MCP");
|
|
12575
12617
|
}
|
|
12618
|
+
if (!cfg.api_key) {
|
|
12619
|
+
throw new Error("no API key available. Run 'dosu setup' to create one");
|
|
12620
|
+
}
|
|
12576
12621
|
if (provider.id() === "manual") {
|
|
12577
|
-
provider.install(cfg, false);
|
|
12622
|
+
provider.install(cfg, false, { showSecret: opts.showSecret });
|
|
12578
12623
|
return;
|
|
12579
12624
|
}
|
|
12580
12625
|
let global = opts.global;
|
|
@@ -12585,7 +12630,7 @@ function createProgram() {
|
|
|
12585
12630
|
}
|
|
12586
12631
|
const scope = global ? "global (all projects)" : "project-local";
|
|
12587
12632
|
console.log(`Adding Dosu MCP to ${provider.name()} (${scope})...`);
|
|
12588
|
-
provider.install(cfg, global);
|
|
12633
|
+
provider.install(cfg, global, { showSecret: opts.showSecret });
|
|
12589
12634
|
console.log(`
|
|
12590
12635
|
✓ Successfully added Dosu MCP to ${provider.name()}!`);
|
|
12591
12636
|
if (global) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dosu/cli",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dosu CLI - Manage MCP servers for AI tools",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"commander": "^13.1.0",
|
|
53
53
|
"open": "^10.1.0",
|
|
54
54
|
"picocolors": "^1.1.1",
|
|
55
|
-
"superjson": "^2.2.6"
|
|
55
|
+
"superjson": "^2.2.6",
|
|
56
|
+
"write-file-atomic": "^5.0.1"
|
|
56
57
|
}
|
|
57
58
|
}
|