@dosu/cli 0.44.0 → 0.46.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 +35 -0
- package/bin/dosu.js +1377 -145
- package/package.json +3 -1
package/bin/dosu.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
var __create = Object.create;
|
|
4
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
@@ -2113,6 +2114,9 @@ function getAccessTokenClaim(accessToken, claim) {
|
|
|
2113
2114
|
function getAccessTokenUserID(accessToken) {
|
|
2114
2115
|
return getAccessTokenClaim(accessToken, "sub");
|
|
2115
2116
|
}
|
|
2117
|
+
function getAccessTokenEmail(accessToken) {
|
|
2118
|
+
return getAccessTokenClaim(accessToken, "email");
|
|
2119
|
+
}
|
|
2116
2120
|
function getAccessTokenOAuthClientID(accessToken) {
|
|
2117
2121
|
return getAccessTokenClaim(accessToken, "client_id");
|
|
2118
2122
|
}
|
|
@@ -2219,15 +2223,22 @@ function loadConfig() {
|
|
|
2219
2223
|
} catch {
|
|
2220
2224
|
return emptyConfig();
|
|
2221
2225
|
}
|
|
2226
|
+
const parsed = parseConfig(raw);
|
|
2222
2227
|
if (isConfigV2(raw))
|
|
2223
|
-
return
|
|
2228
|
+
return parsed;
|
|
2224
2229
|
if (isRecord2(raw) && "schema_version" in raw)
|
|
2225
|
-
return
|
|
2226
|
-
const migrated = migrateLegacyConfig(raw);
|
|
2230
|
+
return parsed;
|
|
2227
2231
|
try {
|
|
2228
|
-
writeConfig(path2,
|
|
2232
|
+
writeConfig(path2, parsed);
|
|
2229
2233
|
} catch {}
|
|
2230
|
-
return
|
|
2234
|
+
return parsed;
|
|
2235
|
+
}
|
|
2236
|
+
function parseConfig(raw) {
|
|
2237
|
+
if (isConfigV2(raw))
|
|
2238
|
+
return normalizeV2(raw);
|
|
2239
|
+
if (isRecord2(raw) && "schema_version" in raw)
|
|
2240
|
+
return emptyConfig();
|
|
2241
|
+
return migrateLegacyConfig(raw);
|
|
2231
2242
|
}
|
|
2232
2243
|
function saveConfig(cfg) {
|
|
2233
2244
|
writeConfig(getConfigPath(), cfg);
|
|
@@ -4762,7 +4773,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
|
|
|
4762
4773
|
function getVersionString() {
|
|
4763
4774
|
return `v${VERSION}`;
|
|
4764
4775
|
}
|
|
4765
|
-
var VERSION = "0.
|
|
4776
|
+
var VERSION = "0.46.0", INSTALL_CHANNEL = "npm";
|
|
4766
4777
|
|
|
4767
4778
|
// src/debug/logger.ts
|
|
4768
4779
|
import {
|
|
@@ -10386,6 +10397,34 @@ var init_insights2 = __esm(() => {
|
|
|
10386
10397
|
init_insights();
|
|
10387
10398
|
});
|
|
10388
10399
|
|
|
10400
|
+
// src/auth/errors.ts
|
|
10401
|
+
var exports_errors = {};
|
|
10402
|
+
__export(exports_errors, {
|
|
10403
|
+
OAuthCallbackError: () => OAuthCallbackError
|
|
10404
|
+
});
|
|
10405
|
+
var OAuthCallbackError;
|
|
10406
|
+
var init_errors = __esm(() => {
|
|
10407
|
+
OAuthCallbackError = class OAuthCallbackError extends Error {
|
|
10408
|
+
error;
|
|
10409
|
+
errorCode;
|
|
10410
|
+
errorDescription;
|
|
10411
|
+
constructor(message, details = {}) {
|
|
10412
|
+
super(message);
|
|
10413
|
+
this.name = "OAuthCallbackError";
|
|
10414
|
+
this.error = details.error;
|
|
10415
|
+
this.errorCode = details.errorCode;
|
|
10416
|
+
this.errorDescription = details.errorDescription;
|
|
10417
|
+
}
|
|
10418
|
+
get userMessage() {
|
|
10419
|
+
const desc = this.errorDescription ?? this.message;
|
|
10420
|
+
if (this.errorCode === "bad_oauth_state" || /state/i.test(desc)) {
|
|
10421
|
+
return `Authentication failed: ${desc}. Run \`dosu login\` again.`;
|
|
10422
|
+
}
|
|
10423
|
+
return `Authentication failed: ${desc}`;
|
|
10424
|
+
}
|
|
10425
|
+
};
|
|
10426
|
+
});
|
|
10427
|
+
|
|
10389
10428
|
// src/version/skill-update-check.ts
|
|
10390
10429
|
import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "node:fs";
|
|
10391
10430
|
import { join as join10 } from "node:path";
|
|
@@ -10527,7 +10566,7 @@ async function installSkill(providerIDs, options = {}) {
|
|
|
10527
10566
|
return { success: true };
|
|
10528
10567
|
}
|
|
10529
10568
|
try {
|
|
10530
|
-
const command = `npx skills add ${SKILL_REPO} -g ${agentArgs} -s
|
|
10569
|
+
const command = `npx skills add ${SKILL_REPO} -g ${agentArgs} -s "*" -y`;
|
|
10531
10570
|
if (options.quiet)
|
|
10532
10571
|
await execQuiet(command);
|
|
10533
10572
|
else
|
|
@@ -10551,11 +10590,11 @@ async function installSkill(providerIDs, options = {}) {
|
|
|
10551
10590
|
function skillCommand() {
|
|
10552
10591
|
const cmd = new Command("skill").description("Manage the Dosu agent skill");
|
|
10553
10592
|
cmd.command("install").description("Install the Dosu skill for AI coding agents").action(async () => {
|
|
10554
|
-
console.log(`Installing
|
|
10593
|
+
console.log(`Installing skills from ${SKILL_REPO}...`);
|
|
10555
10594
|
const result = await installSkill();
|
|
10556
10595
|
if (result.success) {
|
|
10557
10596
|
console.log(import_picocolors13.default.green(`
|
|
10558
|
-
✓
|
|
10597
|
+
✓ Skills installed successfully.`));
|
|
10559
10598
|
} else {
|
|
10560
10599
|
console.error(import_picocolors13.default.red(`
|
|
10561
10600
|
Failed to install skill. Make sure npx is available.`));
|
|
@@ -10577,7 +10616,7 @@ Failed to remove skill.`));
|
|
|
10577
10616
|
}
|
|
10578
10617
|
});
|
|
10579
10618
|
cmd.command("update").description("Update the Dosu skill to the latest version").action(async () => {
|
|
10580
|
-
console.log(`Updating ${
|
|
10619
|
+
console.log(`Updating skills from ${SKILL_REPO}...`);
|
|
10581
10620
|
const result = await installSkill();
|
|
10582
10621
|
if (!result.success) {
|
|
10583
10622
|
console.error(import_picocolors13.default.red(`
|
|
@@ -10585,7 +10624,7 @@ Failed to update skill.`));
|
|
|
10585
10624
|
process.exit(1);
|
|
10586
10625
|
}
|
|
10587
10626
|
console.log(import_picocolors13.default.green(`
|
|
10588
|
-
✓
|
|
10627
|
+
✓ Skills updated.`));
|
|
10589
10628
|
});
|
|
10590
10629
|
return cmd;
|
|
10591
10630
|
}
|
|
@@ -11553,56 +11592,1013 @@ var init_agents_md_step = __esm(() => {
|
|
|
11553
11592
|
SECTION_START_RE = /<!-- dosu:mcp:start(?: v(\d+))? -->/;
|
|
11554
11593
|
});
|
|
11555
11594
|
|
|
11595
|
+
// src/telemetry/settings.ts
|
|
11596
|
+
import { randomUUID } from "node:crypto";
|
|
11597
|
+
import {
|
|
11598
|
+
existsSync as existsSync18,
|
|
11599
|
+
lstatSync,
|
|
11600
|
+
mkdirSync as mkdirSync9,
|
|
11601
|
+
readFileSync as readFileSync16,
|
|
11602
|
+
renameSync as renameSync3,
|
|
11603
|
+
unlinkSync as unlinkSync2,
|
|
11604
|
+
writeFileSync as writeFileSync9
|
|
11605
|
+
} from "node:fs";
|
|
11606
|
+
import { join as join29 } from "node:path";
|
|
11607
|
+
function getTelemetrySettingsPath() {
|
|
11608
|
+
return join29(getConfigDir(), TELEMETRY_SETTINGS_FILENAME);
|
|
11609
|
+
}
|
|
11610
|
+
function loadTelemetrySettings() {
|
|
11611
|
+
return readTelemetrySettings().settings;
|
|
11612
|
+
}
|
|
11613
|
+
function setTelemetryEnabled(enabled) {
|
|
11614
|
+
if (typeof enabled !== "boolean")
|
|
11615
|
+
return false;
|
|
11616
|
+
const current = readTelemetrySettings();
|
|
11617
|
+
if (current.status === "unsupported" || current.status === "error")
|
|
11618
|
+
return false;
|
|
11619
|
+
const settings2 = current.status === "current" ? current.settings : emptyTelemetrySettings();
|
|
11620
|
+
if (enabled)
|
|
11621
|
+
delete settings2.disabled;
|
|
11622
|
+
else
|
|
11623
|
+
settings2.disabled = true;
|
|
11624
|
+
return writeTelemetrySettings(settings2);
|
|
11625
|
+
}
|
|
11626
|
+
function telemetryDisabledByEnvironment() {
|
|
11627
|
+
if (isEnabledEnvironmentFlag(process.env.DO_NOT_TRACK))
|
|
11628
|
+
return "DO_NOT_TRACK";
|
|
11629
|
+
if (isEnabledEnvironmentFlag(process.env.DOSU_TELEMETRY_DISABLED)) {
|
|
11630
|
+
return "DOSU_TELEMETRY_DISABLED";
|
|
11631
|
+
}
|
|
11632
|
+
return;
|
|
11633
|
+
}
|
|
11634
|
+
function isTelemetryEnabled(settings2 = loadTelemetrySettings()) {
|
|
11635
|
+
if (telemetryDisabledByEnvironment() !== undefined)
|
|
11636
|
+
return false;
|
|
11637
|
+
return settings2.disabled !== true;
|
|
11638
|
+
}
|
|
11639
|
+
function getOrCreateInstallID() {
|
|
11640
|
+
const current = readTelemetrySettings();
|
|
11641
|
+
if (current.status === "current" && current.settings.install_id) {
|
|
11642
|
+
return current.settings.install_id;
|
|
11643
|
+
}
|
|
11644
|
+
if (current.status !== "current" && current.status !== "missing")
|
|
11645
|
+
return;
|
|
11646
|
+
const installID = randomUUID();
|
|
11647
|
+
const settings2 = current.status === "current" ? current.settings : emptyTelemetrySettings();
|
|
11648
|
+
settings2.install_id = installID;
|
|
11649
|
+
return writeTelemetrySettings(settings2) ? installID : undefined;
|
|
11650
|
+
}
|
|
11651
|
+
function resetInstallID() {
|
|
11652
|
+
const current = readTelemetrySettings();
|
|
11653
|
+
if (current.status !== "current" && current.status !== "missing")
|
|
11654
|
+
return;
|
|
11655
|
+
const settings2 = current.status === "current" ? current.settings : emptyTelemetrySettings();
|
|
11656
|
+
const installID = randomUUID();
|
|
11657
|
+
settings2.install_id = installID;
|
|
11658
|
+
return writeTelemetrySettings(settings2) ? installID : undefined;
|
|
11659
|
+
}
|
|
11660
|
+
function readTelemetrySettings() {
|
|
11661
|
+
const path3 = getTelemetrySettingsPath();
|
|
11662
|
+
let file;
|
|
11663
|
+
try {
|
|
11664
|
+
file = lstatSync(path3);
|
|
11665
|
+
} catch (error) {
|
|
11666
|
+
if (isErrorCode(error, "ENOENT")) {
|
|
11667
|
+
return { status: "missing", settings: emptyTelemetrySettings() };
|
|
11668
|
+
}
|
|
11669
|
+
return { status: "error", settings: disabledTelemetrySettings() };
|
|
11670
|
+
}
|
|
11671
|
+
if (!file.isFile() || file.size > MAX_TELEMETRY_SETTINGS_BYTES) {
|
|
11672
|
+
return { status: "invalid", settings: disabledTelemetrySettings() };
|
|
11673
|
+
}
|
|
11674
|
+
let content;
|
|
11675
|
+
try {
|
|
11676
|
+
content = readFileSync16(path3, "utf-8");
|
|
11677
|
+
} catch {
|
|
11678
|
+
return { status: "error", settings: disabledTelemetrySettings() };
|
|
11679
|
+
}
|
|
11680
|
+
let raw;
|
|
11681
|
+
try {
|
|
11682
|
+
raw = JSON.parse(content);
|
|
11683
|
+
} catch {
|
|
11684
|
+
return { status: "invalid", settings: disabledTelemetrySettings() };
|
|
11685
|
+
}
|
|
11686
|
+
if (!isRecord3(raw))
|
|
11687
|
+
return { status: "invalid", settings: disabledTelemetrySettings() };
|
|
11688
|
+
if (raw.schema_version !== TELEMETRY_SCHEMA_VERSION) {
|
|
11689
|
+
const status = "schema_version" in raw ? "unsupported" : "invalid";
|
|
11690
|
+
return { status, settings: disabledTelemetrySettings() };
|
|
11691
|
+
}
|
|
11692
|
+
if ("disabled" in raw && typeof raw.disabled !== "boolean") {
|
|
11693
|
+
return { status: "invalid", settings: disabledTelemetrySettings() };
|
|
11694
|
+
}
|
|
11695
|
+
const settings2 = emptyTelemetrySettings();
|
|
11696
|
+
if (raw.disabled === true)
|
|
11697
|
+
settings2.disabled = true;
|
|
11698
|
+
if (typeof raw.install_id === "string" && isUUID(raw.install_id)) {
|
|
11699
|
+
settings2.install_id = raw.install_id;
|
|
11700
|
+
}
|
|
11701
|
+
return { status: "current", settings: settings2 };
|
|
11702
|
+
}
|
|
11703
|
+
function writeTelemetrySettings(settings2) {
|
|
11704
|
+
const path3 = getTelemetrySettingsPath();
|
|
11705
|
+
const dir = getConfigDir();
|
|
11706
|
+
const temporaryPath = `${path3}.${process.pid}.${randomUUID()}.tmp`;
|
|
11707
|
+
try {
|
|
11708
|
+
if (!existsSync18(dir))
|
|
11709
|
+
mkdirSync9(dir, { recursive: true, mode: 448 });
|
|
11710
|
+
writeFileSync9(temporaryPath, `${JSON.stringify(settings2, null, 2)}
|
|
11711
|
+
`, {
|
|
11712
|
+
flag: "wx",
|
|
11713
|
+
mode: 384
|
|
11714
|
+
});
|
|
11715
|
+
renameSync3(temporaryPath, path3);
|
|
11716
|
+
return true;
|
|
11717
|
+
} catch {
|
|
11718
|
+
try {
|
|
11719
|
+
unlinkSync2(temporaryPath);
|
|
11720
|
+
} catch {}
|
|
11721
|
+
return false;
|
|
11722
|
+
}
|
|
11723
|
+
}
|
|
11724
|
+
function emptyTelemetrySettings() {
|
|
11725
|
+
return { schema_version: TELEMETRY_SCHEMA_VERSION };
|
|
11726
|
+
}
|
|
11727
|
+
function disabledTelemetrySettings() {
|
|
11728
|
+
return { schema_version: TELEMETRY_SCHEMA_VERSION, disabled: true };
|
|
11729
|
+
}
|
|
11730
|
+
function isEnabledEnvironmentFlag(value) {
|
|
11731
|
+
if (value === undefined)
|
|
11732
|
+
return false;
|
|
11733
|
+
const normalized = value.trim().toLowerCase();
|
|
11734
|
+
if (normalized === "")
|
|
11735
|
+
return false;
|
|
11736
|
+
return !["0", "false", "no", "off"].includes(normalized);
|
|
11737
|
+
}
|
|
11738
|
+
function isUUID(value) {
|
|
11739
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
11740
|
+
}
|
|
11741
|
+
function isRecord3(value) {
|
|
11742
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11743
|
+
}
|
|
11744
|
+
function isErrorCode(error, code) {
|
|
11745
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
11746
|
+
}
|
|
11747
|
+
var TELEMETRY_SCHEMA_VERSION = 1, TELEMETRY_SETTINGS_FILENAME = "telemetry.json", MAX_TELEMETRY_SETTINGS_BYTES;
|
|
11748
|
+
var init_settings = __esm(() => {
|
|
11749
|
+
init_config();
|
|
11750
|
+
MAX_TELEMETRY_SETTINGS_BYTES = 16 * 1024;
|
|
11751
|
+
});
|
|
11752
|
+
|
|
11753
|
+
// src/telemetry/debug-id.ts
|
|
11754
|
+
var BUNDLE_DEBUG_ID_PLACEHOLDER = "2facad12-755f-3f33-6475-6e2164756e21";
|
|
11755
|
+
|
|
11756
|
+
// src/telemetry/telemetry.ts
|
|
11757
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
11758
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
11759
|
+
import { request as httpRequest2 } from "node:http";
|
|
11760
|
+
import { request as httpsRequest } from "node:https";
|
|
11761
|
+
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
11762
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
11763
|
+
function safeString(value, pattern, fallback) {
|
|
11764
|
+
if (typeof value !== "string" || !pattern.test(value))
|
|
11765
|
+
return fallback;
|
|
11766
|
+
return value;
|
|
11767
|
+
}
|
|
11768
|
+
function canonicalCommand(value) {
|
|
11769
|
+
if (typeof value !== "string")
|
|
11770
|
+
return UNKNOWN_COMMAND;
|
|
11771
|
+
const command = value.trim();
|
|
11772
|
+
if (command.length > 80)
|
|
11773
|
+
return UNKNOWN_COMMAND;
|
|
11774
|
+
if (!/^[a-z][a-z0-9-]*(?: [a-z][a-z0-9-]*){0,3}$/.test(command)) {
|
|
11775
|
+
return UNKNOWN_COMMAND;
|
|
11776
|
+
}
|
|
11777
|
+
return command;
|
|
11778
|
+
}
|
|
11779
|
+
function normalizeContext(context) {
|
|
11780
|
+
const isAuthenticated2 = context?.isAuthenticated === true;
|
|
11781
|
+
const id = safeRead(context?.user, "id");
|
|
11782
|
+
const email = safeRead(context?.user, "email");
|
|
11783
|
+
const user = isAuthenticated2 && validUserId(id) ? { id, ...validEmail(email) ? { email } : {} } : undefined;
|
|
11784
|
+
return {
|
|
11785
|
+
mode: context?.mode === "oss" ? "oss" : "cloud",
|
|
11786
|
+
isAuthenticated: isAuthenticated2,
|
|
11787
|
+
...user ? { user } : {}
|
|
11788
|
+
};
|
|
11789
|
+
}
|
|
11790
|
+
function normalizeExitCode(value, fallback = 1) {
|
|
11791
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
11792
|
+
return fallback;
|
|
11793
|
+
return Math.min(255, Math.max(0, Math.trunc(value)));
|
|
11794
|
+
}
|
|
11795
|
+
function normalizeRuntime(runtime) {
|
|
11796
|
+
return {
|
|
11797
|
+
version: safeString(runtime.version, /^[A-Za-z0-9.+_-]{1,32}$/, "unknown"),
|
|
11798
|
+
installChannel: safeString(runtime.installChannel, /^[A-Za-z][A-Za-z0-9_-]{0,31}$/, "unknown"),
|
|
11799
|
+
platform: safeString(runtime.platform, /^[A-Za-z0-9_-]{1,24}$/, "unknown"),
|
|
11800
|
+
arch: safeString(runtime.arch, /^[A-Za-z0-9_-]{1,24}$/, "unknown"),
|
|
11801
|
+
runtime: safeString(runtime.runtime, /^[A-Za-z][A-Za-z0-9_-]{0,23}$/, "unknown"),
|
|
11802
|
+
runtimeMajor: Math.min(9999, Math.max(0, Math.trunc(runtime.runtimeMajor) || 0)),
|
|
11803
|
+
isCi: runtime.isCi === true,
|
|
11804
|
+
isTty: runtime.isTty === true
|
|
11805
|
+
};
|
|
11806
|
+
}
|
|
11807
|
+
function validInstallId(value) {
|
|
11808
|
+
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
11809
|
+
}
|
|
11810
|
+
function validUserId(value) {
|
|
11811
|
+
return validInstallId(value);
|
|
11812
|
+
}
|
|
11813
|
+
function validEmail(value) {
|
|
11814
|
+
return typeof value === "string" && value.length <= 254 && /^[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$/.test(value);
|
|
11815
|
+
}
|
|
11816
|
+
function validEventId(value) {
|
|
11817
|
+
return typeof value === "string" && /^[0-9a-f]{32}$/i.test(value);
|
|
11818
|
+
}
|
|
11819
|
+
function validDebugId(value) {
|
|
11820
|
+
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
11821
|
+
}
|
|
11822
|
+
function validErrorType(value) {
|
|
11823
|
+
return typeof value === "string" && SAFE_ERROR_TYPES.has(value);
|
|
11824
|
+
}
|
|
11825
|
+
function validErrorCode(value) {
|
|
11826
|
+
return typeof value === "string" && SAFE_ERROR_CODES.has(value);
|
|
11827
|
+
}
|
|
11828
|
+
function validStatus(value) {
|
|
11829
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599;
|
|
11830
|
+
}
|
|
11831
|
+
function objectLike(value) {
|
|
11832
|
+
return typeof value === "object" && value !== null || typeof value === "function";
|
|
11833
|
+
}
|
|
11834
|
+
function safeRead(value, key) {
|
|
11835
|
+
if (!objectLike(value))
|
|
11836
|
+
return;
|
|
11837
|
+
try {
|
|
11838
|
+
return Reflect.get(value, key);
|
|
11839
|
+
} catch {
|
|
11840
|
+
return;
|
|
11841
|
+
}
|
|
11842
|
+
}
|
|
11843
|
+
function parseStack(stack) {
|
|
11844
|
+
if (typeof stack !== "string" || !CLI_PACKAGE_ROOT)
|
|
11845
|
+
return [];
|
|
11846
|
+
const frames = [];
|
|
11847
|
+
const lines = stack.slice(0, 1e5).split(`
|
|
11848
|
+
`, 200);
|
|
11849
|
+
for (const originalLine of lines) {
|
|
11850
|
+
if (frames.length >= MAX_STACK_FRAMES)
|
|
11851
|
+
break;
|
|
11852
|
+
const parsed = parseOwnedStackLine(originalLine, CLI_PACKAGE_ROOT);
|
|
11853
|
+
if (!parsed)
|
|
11854
|
+
continue;
|
|
11855
|
+
const { filename, lineno, colno } = parsed;
|
|
11856
|
+
if (!Number.isSafeInteger(lineno) || !Number.isSafeInteger(colno) || lineno < 1 || colno < 1 || lineno > 1e7 || colno > 1e7) {
|
|
11857
|
+
continue;
|
|
11858
|
+
}
|
|
11859
|
+
frames.push({ filename, lineno, colno, in_app: true });
|
|
11860
|
+
}
|
|
11861
|
+
return frames;
|
|
11862
|
+
}
|
|
11863
|
+
function detectCliPackageRoot() {
|
|
11864
|
+
try {
|
|
11865
|
+
const modulePath = fileURLToPath2(import.meta.url).replaceAll("\\", "/");
|
|
11866
|
+
for (const suffix of ["/src/telemetry/telemetry.ts", "/bin/dosu.js"]) {
|
|
11867
|
+
if (modulePath.endsWith(suffix))
|
|
11868
|
+
return modulePath.slice(0, -suffix.length);
|
|
11869
|
+
}
|
|
11870
|
+
} catch {}
|
|
11871
|
+
return;
|
|
11872
|
+
}
|
|
11873
|
+
function parseOwnedStackLine(originalLine, packageRoot) {
|
|
11874
|
+
const line = originalLine.replaceAll("\\", "/");
|
|
11875
|
+
const match = line.match(/^\s*at\s+.*\s+\((.+):(\d+):(\d+)\)\s*$/) ?? line.match(/^\s*at\s+(.+):(\d+):(\d+)\s*$/);
|
|
11876
|
+
if (!match?.[1] || !match[2] || !match[3])
|
|
11877
|
+
return;
|
|
11878
|
+
let absolutePath = match[1];
|
|
11879
|
+
try {
|
|
11880
|
+
if (absolutePath.startsWith("file://"))
|
|
11881
|
+
absolutePath = fileURLToPath2(absolutePath);
|
|
11882
|
+
} catch {
|
|
11883
|
+
return;
|
|
11884
|
+
}
|
|
11885
|
+
if (!isAbsolute(absolutePath))
|
|
11886
|
+
return;
|
|
11887
|
+
const resolvedPath = resolve(absolutePath);
|
|
11888
|
+
const relativePath = relative(packageRoot, resolvedPath);
|
|
11889
|
+
if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)) {
|
|
11890
|
+
return;
|
|
11891
|
+
}
|
|
11892
|
+
const filename = relativePath.replaceAll("\\", "/");
|
|
11893
|
+
if (!/^(?:src\/(?:[A-Za-z0-9_.-]+\/)*[A-Za-z0-9_.-]+\.(?:[cm]?[jt]sx?)|bin\/dosu\.js)$/.test(filename)) {
|
|
11894
|
+
return;
|
|
11895
|
+
}
|
|
11896
|
+
try {
|
|
11897
|
+
if (!existsSync19(resolvedPath))
|
|
11898
|
+
return;
|
|
11899
|
+
} catch {
|
|
11900
|
+
return;
|
|
11901
|
+
}
|
|
11902
|
+
return { filename, lineno: Number(match[2]), colno: Number(match[3]) };
|
|
11903
|
+
}
|
|
11904
|
+
function sanitizeError(error) {
|
|
11905
|
+
const data = safeRead(error, "data");
|
|
11906
|
+
const typeCandidate = safeRead(error, "name");
|
|
11907
|
+
const codeCandidates = [safeRead(data, "code"), safeRead(error, "code")];
|
|
11908
|
+
const statusCandidates = [
|
|
11909
|
+
safeRead(data, "httpStatus"),
|
|
11910
|
+
safeRead(error, "status"),
|
|
11911
|
+
safeRead(error, "statusCode")
|
|
11912
|
+
];
|
|
11913
|
+
const exitCodeCandidate = safeRead(error, "exitCode");
|
|
11914
|
+
const code = codeCandidates.find(validErrorCode);
|
|
11915
|
+
const status = statusCandidates.find(validStatus);
|
|
11916
|
+
const exitCode = typeof exitCodeCandidate === "number" && Number.isFinite(exitCodeCandidate) ? normalizeExitCode(exitCodeCandidate) : undefined;
|
|
11917
|
+
return {
|
|
11918
|
+
type: validErrorType(typeCandidate) ? typeCandidate : "Error",
|
|
11919
|
+
...code ? { code } : {},
|
|
11920
|
+
...status ? { status } : {},
|
|
11921
|
+
frames: parseStack(safeRead(error, "stack")),
|
|
11922
|
+
...exitCode === undefined ? {} : { exitCode }
|
|
11923
|
+
};
|
|
11924
|
+
}
|
|
11925
|
+
function durationBucket(durationMs) {
|
|
11926
|
+
const duration = Number.isFinite(durationMs) ? Math.max(0, durationMs) : 0;
|
|
11927
|
+
if (duration < 100)
|
|
11928
|
+
return "<100ms";
|
|
11929
|
+
if (duration < 500)
|
|
11930
|
+
return "100-499ms";
|
|
11931
|
+
if (duration < 2000)
|
|
11932
|
+
return "500ms-1.9s";
|
|
11933
|
+
if (duration < 1e4)
|
|
11934
|
+
return "2-9.9s";
|
|
11935
|
+
if (duration < 60000)
|
|
11936
|
+
return "10-59s";
|
|
11937
|
+
return "60s+";
|
|
11938
|
+
}
|
|
11939
|
+
function buildPostHogPayload(input) {
|
|
11940
|
+
const context = normalizeContext(input.context);
|
|
11941
|
+
const runtime = normalizeRuntime(input.runtime);
|
|
11942
|
+
const errorCode = validErrorCode(input.errorCode) ? input.errorCode : undefined;
|
|
11943
|
+
const result = input.result === "success" || input.result === "validation_error" ? input.result : "failure";
|
|
11944
|
+
return {
|
|
11945
|
+
api_key: input.apiKey,
|
|
11946
|
+
distinct_id: context.user?.id ?? (validInstallId(input.installId) ? input.installId : FALLBACK_INSTALL_ID),
|
|
11947
|
+
event: "cli_command_completed",
|
|
11948
|
+
properties: {
|
|
11949
|
+
$geoip_disable: true,
|
|
11950
|
+
...context.user ? {} : { $process_person_profile: false },
|
|
11951
|
+
schema_version: 1,
|
|
11952
|
+
command: canonicalCommand(input.command),
|
|
11953
|
+
result,
|
|
11954
|
+
duration_bucket: durationBucket(input.durationMs),
|
|
11955
|
+
cli_version: runtime.version,
|
|
11956
|
+
install_channel: runtime.installChannel,
|
|
11957
|
+
platform: runtime.platform,
|
|
11958
|
+
arch: runtime.arch,
|
|
11959
|
+
runtime: runtime.runtime,
|
|
11960
|
+
runtime_major: runtime.runtimeMajor,
|
|
11961
|
+
is_ci: runtime.isCi,
|
|
11962
|
+
is_tty: runtime.isTty,
|
|
11963
|
+
mode: context.mode,
|
|
11964
|
+
is_authenticated: context.isAuthenticated,
|
|
11965
|
+
exit_code: normalizeExitCode(input.exitCode),
|
|
11966
|
+
...errorCode ? { error_code: errorCode } : {}
|
|
11967
|
+
}
|
|
11968
|
+
};
|
|
11969
|
+
}
|
|
11970
|
+
function parsePostHogProjectToken(value) {
|
|
11971
|
+
if (typeof value !== "string")
|
|
11972
|
+
return null;
|
|
11973
|
+
const token = value.trim();
|
|
11974
|
+
return /^phc_[A-Za-z0-9_-]{3,252}$/.test(token) ? token : null;
|
|
11975
|
+
}
|
|
11976
|
+
function parseTelemetryWebAppURL(value, allowInsecureLoopback = false) {
|
|
11977
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 2048)
|
|
11978
|
+
return null;
|
|
11979
|
+
try {
|
|
11980
|
+
const url = new URL(value.trim());
|
|
11981
|
+
if (!url.hostname || url.username || url.password || url.search || url.hash)
|
|
11982
|
+
return null;
|
|
11983
|
+
const loopbackHosts = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
11984
|
+
const secure = url.protocol === "https:";
|
|
11985
|
+
const allowedDevelopmentOrigin = allowInsecureLoopback && url.protocol === "http:" && loopbackHosts.has(url.hostname);
|
|
11986
|
+
if (!secure && !allowedDevelopmentOrigin)
|
|
11987
|
+
return null;
|
|
11988
|
+
return url.toString().replace(/\/$/, "");
|
|
11989
|
+
} catch {
|
|
11990
|
+
return null;
|
|
11991
|
+
}
|
|
11992
|
+
}
|
|
11993
|
+
function parseSentryDsn(value) {
|
|
11994
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 2048)
|
|
11995
|
+
return null;
|
|
11996
|
+
const dsn = value.trim();
|
|
11997
|
+
try {
|
|
11998
|
+
const url = new URL(dsn);
|
|
11999
|
+
if (url.protocol !== "https:" || !url.hostname || !url.username || url.password || url.search || url.hash || !/^[A-Za-z0-9_.-]{1,128}$/.test(url.username) || url.username.toLowerCase().startsWith("sntry")) {
|
|
12000
|
+
return null;
|
|
12001
|
+
}
|
|
12002
|
+
const segments = url.pathname.split("/").filter(Boolean);
|
|
12003
|
+
const projectId = segments.pop();
|
|
12004
|
+
if (!projectId || !/^[A-Za-z0-9_-]{1,128}$/.test(projectId))
|
|
12005
|
+
return null;
|
|
12006
|
+
if (segments.some((segment) => !/^[A-Za-z0-9._~-]{1,128}$/.test(segment)))
|
|
12007
|
+
return null;
|
|
12008
|
+
const prefix = segments.length > 0 ? `/${segments.join("/")}` : "";
|
|
12009
|
+
return {
|
|
12010
|
+
dsn,
|
|
12011
|
+
endpoint: `${url.protocol}//${url.host}${prefix}/api/${projectId}/envelope/`,
|
|
12012
|
+
projectId,
|
|
12013
|
+
publicKey: url.username
|
|
12014
|
+
};
|
|
12015
|
+
} catch {
|
|
12016
|
+
return null;
|
|
12017
|
+
}
|
|
12018
|
+
}
|
|
12019
|
+
function sentryTags(command, context, runtime, error) {
|
|
12020
|
+
return {
|
|
12021
|
+
schema_version: "1",
|
|
12022
|
+
command,
|
|
12023
|
+
cli_version: runtime.version,
|
|
12024
|
+
install_channel: runtime.installChannel,
|
|
12025
|
+
os: runtime.platform,
|
|
12026
|
+
arch: runtime.arch,
|
|
12027
|
+
runtime: runtime.runtime,
|
|
12028
|
+
runtime_major: String(runtime.runtimeMajor),
|
|
12029
|
+
is_ci: String(runtime.isCi),
|
|
12030
|
+
is_tty: String(runtime.isTty),
|
|
12031
|
+
mode: context.mode,
|
|
12032
|
+
is_authenticated: String(context.isAuthenticated),
|
|
12033
|
+
...error.code ? { error_code: error.code } : {},
|
|
12034
|
+
...error.status ? { http_status: String(error.status) } : {},
|
|
12035
|
+
...error.exitCode === undefined ? {} : { exit_code: String(error.exitCode) }
|
|
12036
|
+
};
|
|
12037
|
+
}
|
|
12038
|
+
function buildSentryEnvelope(input) {
|
|
12039
|
+
const parsedDsn = parseSentryDsn(input.dsn);
|
|
12040
|
+
if (!parsedDsn || !validEventId(input.eventId))
|
|
12041
|
+
return null;
|
|
12042
|
+
const context = normalizeContext(input.context);
|
|
12043
|
+
const runtime = normalizeRuntime(input.runtime);
|
|
12044
|
+
const command = canonicalCommand(input.command);
|
|
12045
|
+
const debugId = validDebugId(input.debugId) ? input.debugId.toLowerCase() : undefined;
|
|
12046
|
+
const error = {
|
|
12047
|
+
type: validErrorType(input.error.type) ? input.error.type : "Error",
|
|
12048
|
+
...validErrorCode(input.error.code) ? { code: input.error.code } : {},
|
|
12049
|
+
...validStatus(input.error.status) ? { status: input.error.status } : {},
|
|
12050
|
+
...typeof input.error.exitCode === "number" && Number.isFinite(input.error.exitCode) ? { exitCode: normalizeExitCode(input.error.exitCode) } : {},
|
|
12051
|
+
frames: input.error.frames.slice(0, MAX_STACK_FRAMES).map((frame) => {
|
|
12052
|
+
const filename = /^(?:src\/(?:[A-Za-z0-9_.-]+\/)*[A-Za-z0-9_.-]+\.(?:[cm]?[jt]sx?)|bin\/dosu\.js)$/.test(frame.filename) ? frame.filename : "src/unknown.ts";
|
|
12053
|
+
return {
|
|
12054
|
+
filename,
|
|
12055
|
+
...debugId && filename === "bin/dosu.js" ? { abs_path: BUNDLE_CODE_FILE } : {},
|
|
12056
|
+
lineno: Math.min(1e7, Math.max(1, Math.trunc(frame.lineno) || 1)),
|
|
12057
|
+
colno: Math.min(1e7, Math.max(1, Math.trunc(frame.colno) || 1)),
|
|
12058
|
+
in_app: true
|
|
12059
|
+
};
|
|
12060
|
+
}).reverse()
|
|
12061
|
+
};
|
|
12062
|
+
const exceptionValue = {
|
|
12063
|
+
type: error.type,
|
|
12064
|
+
value: error.code ?? error.type,
|
|
12065
|
+
...error.frames.length > 0 ? { stacktrace: { frames: error.frames } } : {}
|
|
12066
|
+
};
|
|
12067
|
+
const newestFrame = error.frames.at(-1);
|
|
12068
|
+
const safeCallsite = newestFrame ? `${newestFrame.filename}:${newestFrame.lineno}` : "unknown";
|
|
12069
|
+
const timestampMs = Number.isFinite(input.timestampMs) ? Math.max(0, input.timestampMs) : 0;
|
|
12070
|
+
const mappedBundle = debugId && error.frames.some((frame) => frame.abs_path === BUNDLE_CODE_FILE);
|
|
12071
|
+
const event = {
|
|
12072
|
+
event_id: input.eventId.toLowerCase(),
|
|
12073
|
+
timestamp: timestampMs / 1000,
|
|
12074
|
+
platform: "node",
|
|
12075
|
+
level: "error",
|
|
12076
|
+
release: `dosu-cli@${runtime.version}`,
|
|
12077
|
+
tags: sentryTags(command, context, runtime, error),
|
|
12078
|
+
...context.user ? { user: context.user } : {},
|
|
12079
|
+
...mappedBundle ? {
|
|
12080
|
+
debug_meta: {
|
|
12081
|
+
images: [{ type: "sourcemap", code_file: BUNDLE_CODE_FILE, debug_id: debugId }]
|
|
12082
|
+
}
|
|
12083
|
+
} : {},
|
|
12084
|
+
fingerprint: ["dosu-cli", command, error.type, error.code ?? "unknown", safeCallsite],
|
|
12085
|
+
exception: { values: [exceptionValue] }
|
|
12086
|
+
};
|
|
12087
|
+
const envelopeHeader = {
|
|
12088
|
+
event_id: input.eventId.toLowerCase(),
|
|
12089
|
+
dsn: parsedDsn.dsn,
|
|
12090
|
+
sent_at: new Date(timestampMs).toISOString()
|
|
12091
|
+
};
|
|
12092
|
+
return {
|
|
12093
|
+
endpoint: parsedDsn.endpoint,
|
|
12094
|
+
body: `${JSON.stringify(envelopeHeader)}
|
|
12095
|
+
${JSON.stringify({ type: "event" })}
|
|
12096
|
+
${JSON.stringify(event)}`
|
|
12097
|
+
};
|
|
12098
|
+
}
|
|
12099
|
+
function fetchWithoutRedirect(url, init = {}) {
|
|
12100
|
+
let parsedURL;
|
|
12101
|
+
try {
|
|
12102
|
+
parsedURL = new URL(url);
|
|
12103
|
+
if (parsedURL.protocol !== "http:" && parsedURL.protocol !== "https:") {
|
|
12104
|
+
return Promise.reject(new Error("unsupported telemetry protocol"));
|
|
12105
|
+
}
|
|
12106
|
+
} catch (error) {
|
|
12107
|
+
return Promise.reject(error);
|
|
12108
|
+
}
|
|
12109
|
+
return new Promise((resolve2, reject) => {
|
|
12110
|
+
let request;
|
|
12111
|
+
let response;
|
|
12112
|
+
let settled = false;
|
|
12113
|
+
const signal = init.signal;
|
|
12114
|
+
const cleanup = () => signal?.removeEventListener("abort", onAbort);
|
|
12115
|
+
const fail = (error) => {
|
|
12116
|
+
if (settled)
|
|
12117
|
+
return;
|
|
12118
|
+
settled = true;
|
|
12119
|
+
cleanup();
|
|
12120
|
+
response?.destroy();
|
|
12121
|
+
request?.socket?.destroy();
|
|
12122
|
+
request?.destroy();
|
|
12123
|
+
reject(error);
|
|
12124
|
+
};
|
|
12125
|
+
const succeed = (value) => {
|
|
12126
|
+
if (settled)
|
|
12127
|
+
return;
|
|
12128
|
+
settled = true;
|
|
12129
|
+
cleanup();
|
|
12130
|
+
response?.destroy();
|
|
12131
|
+
request?.socket?.destroy();
|
|
12132
|
+
request?.destroy();
|
|
12133
|
+
resolve2(value);
|
|
12134
|
+
};
|
|
12135
|
+
const onAbort = () => {
|
|
12136
|
+
const error = new Error("telemetry request aborted");
|
|
12137
|
+
error.name = "AbortError";
|
|
12138
|
+
fail(error);
|
|
12139
|
+
};
|
|
12140
|
+
try {
|
|
12141
|
+
if (signal?.aborted) {
|
|
12142
|
+
onAbort();
|
|
12143
|
+
return;
|
|
12144
|
+
}
|
|
12145
|
+
const body = init.body;
|
|
12146
|
+
if (body !== undefined && body !== null && typeof body !== "string") {
|
|
12147
|
+
fail(new Error("unsupported telemetry request body"));
|
|
12148
|
+
return;
|
|
12149
|
+
}
|
|
12150
|
+
const headers = Object.fromEntries(new Headers(init.headers).entries());
|
|
12151
|
+
const transport = parsedURL.protocol === "https:" ? httpsRequest : httpRequest2;
|
|
12152
|
+
request = transport(parsedURL, {
|
|
12153
|
+
method: init.method ?? "GET",
|
|
12154
|
+
headers,
|
|
12155
|
+
agent: false
|
|
12156
|
+
}, (incoming) => {
|
|
12157
|
+
response = incoming;
|
|
12158
|
+
const chunks = [];
|
|
12159
|
+
let totalBytes = 0;
|
|
12160
|
+
incoming.on("data", (chunk) => {
|
|
12161
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
12162
|
+
totalBytes += bytes.byteLength;
|
|
12163
|
+
if (totalBytes > MAX_RESPONSE_BYTES) {
|
|
12164
|
+
fail(new Error("telemetry response too large"));
|
|
12165
|
+
return;
|
|
12166
|
+
}
|
|
12167
|
+
chunks.push(bytes);
|
|
12168
|
+
});
|
|
12169
|
+
incoming.once("error", fail);
|
|
12170
|
+
incoming.once("end", () => {
|
|
12171
|
+
try {
|
|
12172
|
+
const responseHeaders = new Headers;
|
|
12173
|
+
for (let index = 0;index < incoming.rawHeaders.length; index += 2) {
|
|
12174
|
+
const name = incoming.rawHeaders[index];
|
|
12175
|
+
const value = incoming.rawHeaders[index + 1];
|
|
12176
|
+
if (name && value)
|
|
12177
|
+
responseHeaders.append(name, value);
|
|
12178
|
+
}
|
|
12179
|
+
const status = incoming.statusCode;
|
|
12180
|
+
if (!status)
|
|
12181
|
+
throw new Error("telemetry response missing status");
|
|
12182
|
+
succeed(new Response(chunks.length > 0 ? Buffer.concat(chunks) : null, {
|
|
12183
|
+
status,
|
|
12184
|
+
statusText: incoming.statusMessage,
|
|
12185
|
+
headers: responseHeaders
|
|
12186
|
+
}));
|
|
12187
|
+
} catch (error) {
|
|
12188
|
+
fail(error);
|
|
12189
|
+
}
|
|
12190
|
+
});
|
|
12191
|
+
});
|
|
12192
|
+
request.once("error", fail);
|
|
12193
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
12194
|
+
request.end(body);
|
|
12195
|
+
} catch (error) {
|
|
12196
|
+
fail(error);
|
|
12197
|
+
}
|
|
12198
|
+
});
|
|
12199
|
+
}
|
|
12200
|
+
async function sendHttpsRequest(url, init, fetcher = fetchWithoutRedirect) {
|
|
12201
|
+
try {
|
|
12202
|
+
if (new URL(url).protocol !== "https:")
|
|
12203
|
+
return false;
|
|
12204
|
+
} catch {
|
|
12205
|
+
return false;
|
|
12206
|
+
}
|
|
12207
|
+
const controller = new AbortController;
|
|
12208
|
+
let timer;
|
|
12209
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
12210
|
+
timer = setTimeout(() => {
|
|
12211
|
+
controller.abort();
|
|
12212
|
+
reject(new Error("telemetry request timed out"));
|
|
12213
|
+
}, REQUEST_TIMEOUT_MS);
|
|
12214
|
+
});
|
|
12215
|
+
try {
|
|
12216
|
+
const request = fetcher(url, { ...init, redirect: "error", signal: controller.signal });
|
|
12217
|
+
const result = await Promise.race([request, timeout]);
|
|
12218
|
+
return result.ok;
|
|
12219
|
+
} catch {
|
|
12220
|
+
return false;
|
|
12221
|
+
} finally {
|
|
12222
|
+
controller.abort();
|
|
12223
|
+
if (timer !== undefined)
|
|
12224
|
+
clearTimeout(timer);
|
|
12225
|
+
}
|
|
12226
|
+
}
|
|
12227
|
+
function environmentFlag(value) {
|
|
12228
|
+
if (value === undefined)
|
|
12229
|
+
return false;
|
|
12230
|
+
const normalized = value.trim().toLowerCase();
|
|
12231
|
+
return normalized !== "" && !["0", "false", "no", "off"].includes(normalized);
|
|
12232
|
+
}
|
|
12233
|
+
function runtimeNameAndMajor() {
|
|
12234
|
+
const versions = process.versions;
|
|
12235
|
+
const runtime = versions.bun ? "bun" : "node";
|
|
12236
|
+
const version = versions.bun ?? versions.node;
|
|
12237
|
+
return { runtime, runtimeMajor: Number.parseInt(version.split(".")[0] ?? "0", 10) || 0 };
|
|
12238
|
+
}
|
|
12239
|
+
function resolveRuntime(dependencies, env) {
|
|
12240
|
+
const detected = runtimeNameAndMajor();
|
|
12241
|
+
return normalizeRuntime({
|
|
12242
|
+
version: dependencies.version ?? VERSION,
|
|
12243
|
+
installChannel: dependencies.installChannel ?? INSTALL_CHANNEL,
|
|
12244
|
+
platform: dependencies.platform ?? process.platform,
|
|
12245
|
+
arch: dependencies.arch ?? process.arch,
|
|
12246
|
+
runtime: dependencies.runtime ?? detected.runtime,
|
|
12247
|
+
runtimeMajor: dependencies.runtimeMajor ?? detected.runtimeMajor,
|
|
12248
|
+
isCi: dependencies.isCi ?? environmentFlag(env.CI),
|
|
12249
|
+
isTty: dependencies.isTty ?? process.stdout.isTTY === true
|
|
12250
|
+
});
|
|
12251
|
+
}
|
|
12252
|
+
function validationFailure(exitCode, error) {
|
|
12253
|
+
if (exitCode === 2)
|
|
12254
|
+
return true;
|
|
12255
|
+
if (error?.type === "CliUsageError")
|
|
12256
|
+
return true;
|
|
12257
|
+
if (!error?.code)
|
|
12258
|
+
return false;
|
|
12259
|
+
return error.code.startsWith("commander.") || ["BAD_REQUEST", "INVALID_ARGUMENT", "UNPROCESSABLE_CONTENT", "VALIDATION_ERROR"].includes(error.code);
|
|
12260
|
+
}
|
|
12261
|
+
function safeNow(now) {
|
|
12262
|
+
try {
|
|
12263
|
+
const value = now();
|
|
12264
|
+
return Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
12265
|
+
} catch {
|
|
12266
|
+
return 0;
|
|
12267
|
+
}
|
|
12268
|
+
}
|
|
12269
|
+
function safeUuid(generate) {
|
|
12270
|
+
try {
|
|
12271
|
+
const value = generate();
|
|
12272
|
+
return validInstallId(value) ? value : undefined;
|
|
12273
|
+
} catch {
|
|
12274
|
+
return;
|
|
12275
|
+
}
|
|
12276
|
+
}
|
|
12277
|
+
function eventId(generate) {
|
|
12278
|
+
const uuid = safeUuid(generate);
|
|
12279
|
+
return uuid?.replaceAll("-", "");
|
|
12280
|
+
}
|
|
12281
|
+
function createCommandTelemetry(settings2, dependencies = {}) {
|
|
12282
|
+
const env = dependencies.env ?? process.env;
|
|
12283
|
+
const fetcher = dependencies.fetch;
|
|
12284
|
+
const now = dependencies.now ?? Date.now;
|
|
12285
|
+
const generateUuid = dependencies.randomUUID ?? randomUUID2;
|
|
12286
|
+
const writeStderr = dependencies.stderr ?? ((payload) => process.stderr.write(`${payload}
|
|
12287
|
+
`));
|
|
12288
|
+
const webAppURL = dependencies.webAppURL ?? getWebAppURL;
|
|
12289
|
+
const runtime = resolveRuntime(dependencies, env);
|
|
12290
|
+
const debug = env.DOSU_TELEMETRY_DEBUG === "1";
|
|
12291
|
+
const disabled = settings2.disabled === true || environmentFlag(env.DO_NOT_TRACK) || environmentFlag(env.DOSU_TELEMETRY_DISABLED);
|
|
12292
|
+
const rawAnalyticsToken = dependencies.env ? env.DOSU_POSTHOG_PROJECT_TOKEN_OVERRIDE ?? env.DOSU_POSTHOG_PROJECT_TOKEN : process.env.DOSU_POSTHOG_PROJECT_TOKEN_OVERRIDE ?? "phc_Uo9RxhN0HRk8gZkPlT18BCr7eqsM0MPWVW88HZB95V5";
|
|
12293
|
+
const rawSentryDsn = dependencies.env ? env.DOSU_CLI_SENTRY_DSN_OVERRIDE ?? env.DOSU_CLI_SENTRY_DSN : process.env.DOSU_CLI_SENTRY_DSN_OVERRIDE ?? "https://f6b3e51dea6f50746316aa1896df76e0@o4505364738670592.ingest.us.sentry.io/4511883653283840";
|
|
12294
|
+
const analyticsToken = parsePostHogProjectToken(rawAnalyticsToken) ?? undefined;
|
|
12295
|
+
const sentryDsn = parseSentryDsn(rawSentryDsn)?.dsn;
|
|
12296
|
+
let started = false;
|
|
12297
|
+
let terminal = false;
|
|
12298
|
+
let startedAt = 0;
|
|
12299
|
+
let command = UNKNOWN_COMMAND;
|
|
12300
|
+
let context = normalizeContext(undefined);
|
|
12301
|
+
let installIdResolved = false;
|
|
12302
|
+
let resolvedInstallId = settings2.install_id;
|
|
12303
|
+
function installId() {
|
|
12304
|
+
if (validInstallId(resolvedInstallId))
|
|
12305
|
+
return resolvedInstallId;
|
|
12306
|
+
if (installIdResolved)
|
|
12307
|
+
return;
|
|
12308
|
+
installIdResolved = true;
|
|
12309
|
+
try {
|
|
12310
|
+
resolvedInstallId = dependencies.resolveInstallId?.();
|
|
12311
|
+
} catch {
|
|
12312
|
+
resolvedInstallId = undefined;
|
|
12313
|
+
}
|
|
12314
|
+
return validInstallId(resolvedInstallId) ? resolvedInstallId : undefined;
|
|
12315
|
+
}
|
|
12316
|
+
function debugPayload(payload) {
|
|
12317
|
+
try {
|
|
12318
|
+
writeStderr(payload);
|
|
12319
|
+
} catch {}
|
|
12320
|
+
}
|
|
12321
|
+
async function dispatch(result, exitCode, error) {
|
|
12322
|
+
try {
|
|
12323
|
+
const tasks = [];
|
|
12324
|
+
if (!disabled && analyticsToken) {
|
|
12325
|
+
const id = context.user?.id ?? installId();
|
|
12326
|
+
if (id) {
|
|
12327
|
+
const payload = buildPostHogPayload({
|
|
12328
|
+
apiKey: analyticsToken,
|
|
12329
|
+
...context.user ? {} : { installId: id },
|
|
12330
|
+
command,
|
|
12331
|
+
result,
|
|
12332
|
+
durationMs: safeNow(now) - startedAt,
|
|
12333
|
+
exitCode,
|
|
12334
|
+
errorCode: error?.code,
|
|
12335
|
+
context,
|
|
12336
|
+
runtime
|
|
12337
|
+
});
|
|
12338
|
+
const body = JSON.stringify(payload);
|
|
12339
|
+
if (debug) {
|
|
12340
|
+
debugPayload(body);
|
|
12341
|
+
} else {
|
|
12342
|
+
const base = parseTelemetryWebAppURL(webAppURL());
|
|
12343
|
+
if (base) {
|
|
12344
|
+
tasks.push(sendHttpsRequest(`${base}/ph-api/i/v0/e/`, {
|
|
12345
|
+
method: "POST",
|
|
12346
|
+
headers: { "content-type": "application/json" },
|
|
12347
|
+
body
|
|
12348
|
+
}, fetcher));
|
|
12349
|
+
}
|
|
12350
|
+
}
|
|
12351
|
+
}
|
|
12352
|
+
}
|
|
12353
|
+
if (!disabled && result === "failure" && error && sentryDsn) {
|
|
12354
|
+
const id = eventId(generateUuid);
|
|
12355
|
+
const envelope = id ? buildSentryEnvelope({
|
|
12356
|
+
dsn: sentryDsn,
|
|
12357
|
+
command,
|
|
12358
|
+
context,
|
|
12359
|
+
runtime,
|
|
12360
|
+
error,
|
|
12361
|
+
eventId: id,
|
|
12362
|
+
timestampMs: safeNow(now),
|
|
12363
|
+
debugId: BUNDLE_DEBUG_ID_PLACEHOLDER
|
|
12364
|
+
}) : null;
|
|
12365
|
+
if (envelope) {
|
|
12366
|
+
if (debug) {
|
|
12367
|
+
debugPayload(envelope.body);
|
|
12368
|
+
} else {
|
|
12369
|
+
tasks.push(sendHttpsRequest(envelope.endpoint, {
|
|
12370
|
+
method: "POST",
|
|
12371
|
+
headers: { "content-type": "application/x-sentry-envelope" },
|
|
12372
|
+
body: envelope.body
|
|
12373
|
+
}, fetcher));
|
|
12374
|
+
}
|
|
12375
|
+
}
|
|
12376
|
+
}
|
|
12377
|
+
await Promise.all(tasks);
|
|
12378
|
+
} catch {}
|
|
12379
|
+
}
|
|
12380
|
+
return {
|
|
12381
|
+
start(commandName, commandContext) {
|
|
12382
|
+
if (started || terminal)
|
|
12383
|
+
return;
|
|
12384
|
+
started = true;
|
|
12385
|
+
command = canonicalCommand(commandName);
|
|
12386
|
+
context = normalizeContext(commandContext);
|
|
12387
|
+
startedAt = safeNow(now);
|
|
12388
|
+
},
|
|
12389
|
+
async complete(exitCode = 0) {
|
|
12390
|
+
if (!started || terminal)
|
|
12391
|
+
return;
|
|
12392
|
+
terminal = true;
|
|
12393
|
+
const normalizedExitCode = normalizeExitCode(exitCode, 0);
|
|
12394
|
+
const result = normalizedExitCode === 0 ? "success" : validationFailure(normalizedExitCode, undefined) ? "validation_error" : "failure";
|
|
12395
|
+
const error = result === "failure" ? { type: "CommandExitError", frames: [], exitCode: normalizedExitCode } : undefined;
|
|
12396
|
+
await dispatch(result, normalizedExitCode, error);
|
|
12397
|
+
},
|
|
12398
|
+
async fail(rawError) {
|
|
12399
|
+
if (!started || terminal)
|
|
12400
|
+
return;
|
|
12401
|
+
terminal = true;
|
|
12402
|
+
const error = sanitizeError(rawError);
|
|
12403
|
+
const exitCode = error.exitCode ?? 1;
|
|
12404
|
+
const result = validationFailure(exitCode, error) ? "validation_error" : "failure";
|
|
12405
|
+
await dispatch(result, exitCode, error);
|
|
12406
|
+
}
|
|
12407
|
+
};
|
|
12408
|
+
}
|
|
12409
|
+
var REQUEST_TIMEOUT_MS = 500, MAX_RESPONSE_BYTES, MAX_STACK_FRAMES = 20, UNKNOWN_COMMAND = "unknown", FALLBACK_INSTALL_ID = "00000000-0000-4000-8000-000000000000", BUNDLE_CODE_FILE = "app:///bin/dosu.js", CLI_PACKAGE_ROOT, SAFE_ERROR_TYPES, SAFE_ERROR_CODES;
|
|
12410
|
+
var init_telemetry = __esm(() => {
|
|
12411
|
+
MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
12412
|
+
CLI_PACKAGE_ROOT = detectCliPackageRoot();
|
|
12413
|
+
SAFE_ERROR_TYPES = new Set([
|
|
12414
|
+
"AbortError",
|
|
12415
|
+
"AggregateError",
|
|
12416
|
+
"CommanderError",
|
|
12417
|
+
"CliUsageError",
|
|
12418
|
+
"CommandExitError",
|
|
12419
|
+
"Error",
|
|
12420
|
+
"OAuthCallbackError",
|
|
12421
|
+
"RangeError",
|
|
12422
|
+
"ReferenceError",
|
|
12423
|
+
"SessionExpiredError",
|
|
12424
|
+
"SyntaxError",
|
|
12425
|
+
"TicketHttpError",
|
|
12426
|
+
"TRPCClientError",
|
|
12427
|
+
"TypeError"
|
|
12428
|
+
]);
|
|
12429
|
+
SAFE_ERROR_CODES = new Set([
|
|
12430
|
+
"ABORT_ERR",
|
|
12431
|
+
"BAD_GATEWAY",
|
|
12432
|
+
"BAD_REQUEST",
|
|
12433
|
+
"CLIENT_CLOSED_REQUEST",
|
|
12434
|
+
"CONFLICT",
|
|
12435
|
+
"EACCES",
|
|
12436
|
+
"EAI_AGAIN",
|
|
12437
|
+
"EBUSY",
|
|
12438
|
+
"ECONNREFUSED",
|
|
12439
|
+
"ECONNRESET",
|
|
12440
|
+
"EEXIST",
|
|
12441
|
+
"EHOSTUNREACH",
|
|
12442
|
+
"EINVAL",
|
|
12443
|
+
"EISDIR",
|
|
12444
|
+
"ELOOP",
|
|
12445
|
+
"EMFILE",
|
|
12446
|
+
"ENAMETOOLONG",
|
|
12447
|
+
"ENETUNREACH",
|
|
12448
|
+
"ENFILE",
|
|
12449
|
+
"ENOENT",
|
|
12450
|
+
"ENOMEM",
|
|
12451
|
+
"ENOSPC",
|
|
12452
|
+
"ENOTFOUND",
|
|
12453
|
+
"ENOTDIR",
|
|
12454
|
+
"EPIPE",
|
|
12455
|
+
"EPERM",
|
|
12456
|
+
"EROFS",
|
|
12457
|
+
"ETIMEDOUT",
|
|
12458
|
+
"FORBIDDEN",
|
|
12459
|
+
"GATEWAY_TIMEOUT",
|
|
12460
|
+
"IMPORT_ALREADY_IN_PROGRESS",
|
|
12461
|
+
"INTERNAL_SERVER_ERROR",
|
|
12462
|
+
"INVALID_ARGUMENT",
|
|
12463
|
+
"METHOD_NOT_SUPPORTED",
|
|
12464
|
+
"NOT_FOUND",
|
|
12465
|
+
"NOT_IMPLEMENTED",
|
|
12466
|
+
"PARSE_ERROR",
|
|
12467
|
+
"PAYLOAD_TOO_LARGE",
|
|
12468
|
+
"PAYMENT_REQUIRED",
|
|
12469
|
+
"PRECONDITION_FAILED",
|
|
12470
|
+
"SERVICE_UNAVAILABLE",
|
|
12471
|
+
"TIMEOUT",
|
|
12472
|
+
"TOO_MANY_REQUESTS",
|
|
12473
|
+
"UNAUTHORIZED",
|
|
12474
|
+
"UNPROCESSABLE_CONTENT",
|
|
12475
|
+
"UNSUPPORTED_MEDIA_TYPE",
|
|
12476
|
+
"VALIDATION_ERROR",
|
|
12477
|
+
"commander.conflictingOption",
|
|
12478
|
+
"commander.error",
|
|
12479
|
+
"commander.excessArguments",
|
|
12480
|
+
"commander.invalidArgument",
|
|
12481
|
+
"commander.missingArgument",
|
|
12482
|
+
"commander.missingMandatoryOptionValue",
|
|
12483
|
+
"commander.optionMissingArgument",
|
|
12484
|
+
"commander.unknownCommand",
|
|
12485
|
+
"commander.unknownOption"
|
|
12486
|
+
]);
|
|
12487
|
+
});
|
|
12488
|
+
|
|
11556
12489
|
// src/setup/analytics.ts
|
|
11557
12490
|
async function trackCliOnboardingEvent(cfg, onboardingRunID, event, properties = {}) {
|
|
11558
|
-
if (!cfg.active_account?.session.access_token)
|
|
11559
|
-
return;
|
|
11560
12491
|
try {
|
|
11561
|
-
|
|
11562
|
-
|
|
12492
|
+
if (!isTelemetryEnabled())
|
|
12493
|
+
return;
|
|
12494
|
+
if (!analyticsReleaseEnabled())
|
|
12495
|
+
return;
|
|
12496
|
+
if (!cfg.active_account?.session.access_token)
|
|
12497
|
+
return;
|
|
12498
|
+
if (!isUUID2(onboardingRunID))
|
|
12499
|
+
return;
|
|
12500
|
+
const input = {
|
|
11563
12501
|
event,
|
|
11564
12502
|
properties: {
|
|
11565
12503
|
...baseProperties(cfg),
|
|
11566
12504
|
onboarding_run_id: onboardingRunID,
|
|
11567
|
-
...properties
|
|
12505
|
+
...allowlistedWorkflowProperties(properties)
|
|
11568
12506
|
}
|
|
11569
|
-
}
|
|
12507
|
+
};
|
|
12508
|
+
if (printDebugPayload(input))
|
|
12509
|
+
return;
|
|
12510
|
+
await withTimeout((signal) => createAnalyticsClient(cfg.active_account?.session.access_token, signal).user.trackCliOnboardingEvent.mutate(input), TRACKING_TIMEOUT_MS);
|
|
11570
12511
|
} catch (err) {
|
|
11571
|
-
|
|
11572
|
-
logger.debug("setup", `CLI onboarding analytics failed: ${event}: ${msg}`);
|
|
12512
|
+
logTrackingFailure("analytics", event, err);
|
|
11573
12513
|
}
|
|
11574
12514
|
}
|
|
11575
12515
|
async function trackCliOnboardingPreAuthEvent(onboardingRunID, event, properties = {}) {
|
|
11576
12516
|
try {
|
|
11577
|
-
|
|
11578
|
-
|
|
12517
|
+
if (!isTelemetryEnabled())
|
|
12518
|
+
return;
|
|
12519
|
+
if (!analyticsReleaseEnabled())
|
|
12520
|
+
return;
|
|
12521
|
+
if (!isUUID2(onboardingRunID))
|
|
12522
|
+
return;
|
|
12523
|
+
const input = {
|
|
11579
12524
|
event,
|
|
11580
12525
|
onboarding_run_id: onboardingRunID,
|
|
11581
12526
|
properties: {
|
|
11582
12527
|
...baseProperties(emptyConfig()),
|
|
11583
|
-
...properties
|
|
12528
|
+
...allowlistedWorkflowProperties(properties)
|
|
11584
12529
|
}
|
|
11585
|
-
}
|
|
12530
|
+
};
|
|
12531
|
+
if (printDebugPayload(input))
|
|
12532
|
+
return;
|
|
12533
|
+
await withTimeout((signal) => createAnalyticsClient(undefined, signal).user.trackCliOnboardingPreAuthEvent.mutate(input), TRACKING_TIMEOUT_MS);
|
|
11586
12534
|
} catch (err) {
|
|
11587
|
-
|
|
11588
|
-
logger.debug("setup", `CLI onboarding pre-auth analytics failed: ${event}: ${msg}`);
|
|
12535
|
+
logTrackingFailure("pre-auth analytics", event, err);
|
|
11589
12536
|
}
|
|
11590
12537
|
}
|
|
12538
|
+
function logTrackingFailure(kind, event, error) {
|
|
12539
|
+
try {
|
|
12540
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12541
|
+
logger.debug("setup", `CLI onboarding ${kind} failed: ${event}: ${message}`);
|
|
12542
|
+
} catch {}
|
|
12543
|
+
}
|
|
12544
|
+
function printDebugPayload(payload) {
|
|
12545
|
+
if (process.env.DOSU_TELEMETRY_DEBUG !== "1")
|
|
12546
|
+
return false;
|
|
12547
|
+
console.error(`[dosu telemetry:posthog] ${JSON.stringify(payload)}`);
|
|
12548
|
+
return true;
|
|
12549
|
+
}
|
|
12550
|
+
function analyticsReleaseEnabled() {
|
|
12551
|
+
return Boolean(parsePostHogProjectToken(process.env.DOSU_POSTHOG_PROJECT_TOKEN_OVERRIDE ?? "phc_Uo9RxhN0HRk8gZkPlT18BCr7eqsM0MPWVW88HZB95V5"));
|
|
12552
|
+
}
|
|
11591
12553
|
function baseProperties(cfg) {
|
|
11592
12554
|
return {
|
|
11593
|
-
cli_version: VERSION,
|
|
11594
|
-
|
|
11595
|
-
|
|
12555
|
+
cli_version: safeIdentifier(VERSION, 32),
|
|
12556
|
+
install_channel: safeIdentifier(INSTALL_CHANNEL, 32),
|
|
12557
|
+
platform: safeIdentifier(process.platform, 24),
|
|
12558
|
+
arch: safeIdentifier(process.arch, 24),
|
|
11596
12559
|
mode: cfg.mode ?? "cloud",
|
|
11597
|
-
org_id: cfg.active_account?.target?.org_id,
|
|
11598
|
-
deployment_id: cfg.active_account?.target?.deployment_id,
|
|
11599
|
-
space_id: cfg.active_account?.target?.space_id
|
|
12560
|
+
org_id: safeIdentifier(cfg.active_account?.target?.org_id, 128),
|
|
12561
|
+
deployment_id: safeIdentifier(cfg.active_account?.target?.deployment_id, 128),
|
|
12562
|
+
space_id: safeIdentifier(cfg.active_account?.target?.space_id, 128)
|
|
11600
12563
|
};
|
|
11601
12564
|
}
|
|
11602
|
-
function
|
|
11603
|
-
const
|
|
12565
|
+
function allowlistedWorkflowProperties(properties) {
|
|
12566
|
+
const input = properties;
|
|
12567
|
+
const safe = {};
|
|
12568
|
+
if (typeof input.has_deployment_option === "boolean") {
|
|
12569
|
+
safe.has_deployment_option = input.has_deployment_option;
|
|
12570
|
+
}
|
|
12571
|
+
if (input.mode_option === "cloud" || input.mode_option === "oss") {
|
|
12572
|
+
safe.mode_option = input.mode_option;
|
|
12573
|
+
}
|
|
12574
|
+
if (input.flow_kind === "onboarding" || input.flow_kind === "oss" || input.flow_kind === "setup") {
|
|
12575
|
+
safe.flow_kind = input.flow_kind;
|
|
12576
|
+
}
|
|
12577
|
+
if (typeof input.reason === "string" && SETUP_FAILURE_REASONS.has(input.reason)) {
|
|
12578
|
+
safe.reason = input.reason;
|
|
12579
|
+
}
|
|
12580
|
+
if (typeof input.provider_count === "number" && Number.isInteger(input.provider_count) && input.provider_count >= 0 && input.provider_count <= 50) {
|
|
12581
|
+
safe.provider_count = input.provider_count;
|
|
12582
|
+
}
|
|
12583
|
+
if (Array.isArray(input.providers)) {
|
|
12584
|
+
safe.providers = input.providers.filter((provider) => typeof provider === "string" && /^[a-z][a-z0-9-]{0,31}$/.test(provider)).slice(0, 50);
|
|
12585
|
+
}
|
|
12586
|
+
for (const key of ["completed_mcp", "completed_skill", "completed_agents_md"]) {
|
|
12587
|
+
if (typeof input[key] === "boolean")
|
|
12588
|
+
safe[key] = input[key];
|
|
12589
|
+
}
|
|
12590
|
+
return safe;
|
|
12591
|
+
}
|
|
12592
|
+
function safeIdentifier(value, maxLength) {
|
|
12593
|
+
return typeof value === "string" && value.length <= maxLength && /^[A-Za-z0-9][A-Za-z0-9._+-]*$/.test(value) ? value : undefined;
|
|
12594
|
+
}
|
|
12595
|
+
function isUUID2(value) {
|
|
12596
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
12597
|
+
}
|
|
12598
|
+
function createAnalyticsClient(accessToken, requestSignal) {
|
|
12599
|
+
const webAppURL = parseTelemetryWebAppURL(getWebAppURL(), process.env.DOSU_DEV === "true");
|
|
11604
12600
|
if (!webAppURL) {
|
|
11605
|
-
throw new Error("
|
|
12601
|
+
throw new Error("Secure web app URL not configured");
|
|
11606
12602
|
}
|
|
11607
12603
|
return createTRPCClient({
|
|
11608
12604
|
links: [
|
|
@@ -11610,19 +12606,32 @@ function createAnonymousClient() {
|
|
|
11610
12606
|
url: `${webAppURL}/api/cli-trpc`,
|
|
11611
12607
|
transformer: dist_default,
|
|
11612
12608
|
headers: {
|
|
11613
|
-
"x-dosu-cli-contract": CLI_CONTRACT_HASH
|
|
12609
|
+
"x-dosu-cli-contract": CLI_CONTRACT_HASH,
|
|
12610
|
+
...accessToken ? { "Supabase-Access-Token": accessToken } : {}
|
|
12611
|
+
},
|
|
12612
|
+
fetch: (url, options) => {
|
|
12613
|
+
const target = typeof url === "string" ? url : url instanceof URL ? url.toString() : url.url;
|
|
12614
|
+
return fetchWithoutRedirect(target, {
|
|
12615
|
+
...options,
|
|
12616
|
+
redirect: "error",
|
|
12617
|
+
...requestSignal ? { signal: requestSignal } : {}
|
|
12618
|
+
});
|
|
11614
12619
|
}
|
|
11615
12620
|
})
|
|
11616
12621
|
]
|
|
11617
12622
|
});
|
|
11618
12623
|
}
|
|
11619
|
-
async function withTimeout(
|
|
12624
|
+
async function withTimeout(operation, timeoutMs) {
|
|
12625
|
+
const controller = new AbortController;
|
|
11620
12626
|
let timeout;
|
|
11621
12627
|
try {
|
|
11622
12628
|
return await Promise.race([
|
|
11623
|
-
|
|
12629
|
+
operation(controller.signal),
|
|
11624
12630
|
new Promise((_2, reject) => {
|
|
11625
|
-
timeout = setTimeout(() =>
|
|
12631
|
+
timeout = setTimeout(() => {
|
|
12632
|
+
controller.abort();
|
|
12633
|
+
reject(new Error("tracking timeout"));
|
|
12634
|
+
}, timeoutMs);
|
|
11626
12635
|
})
|
|
11627
12636
|
]);
|
|
11628
12637
|
} finally {
|
|
@@ -11630,13 +12639,32 @@ async function withTimeout(promise, timeoutMs) {
|
|
|
11630
12639
|
clearTimeout(timeout);
|
|
11631
12640
|
}
|
|
11632
12641
|
}
|
|
11633
|
-
var TRACKING_TIMEOUT_MS =
|
|
12642
|
+
var SETUP_FAILURE_REASONS, TRACKING_TIMEOUT_MS = 500;
|
|
11634
12643
|
var init_analytics = __esm(() => {
|
|
11635
12644
|
init_dist();
|
|
11636
12645
|
init_dist4();
|
|
11637
|
-
init_trpc();
|
|
11638
12646
|
init_config();
|
|
11639
12647
|
init_logger();
|
|
12648
|
+
init_settings();
|
|
12649
|
+
init_telemetry();
|
|
12650
|
+
SETUP_FAILURE_REASONS = new Set([
|
|
12651
|
+
"access_denied",
|
|
12652
|
+
"api_key_failed",
|
|
12653
|
+
"bad_oauth_state",
|
|
12654
|
+
"cloud_setup_context_failed",
|
|
12655
|
+
"deployment_resolution_failed",
|
|
12656
|
+
"invalid_request",
|
|
12657
|
+
"invalid_scope",
|
|
12658
|
+
"mcp_selection_cancelled",
|
|
12659
|
+
"oauth_callback_error",
|
|
12660
|
+
"onboarding_incomplete_after_handshake",
|
|
12661
|
+
"server_error",
|
|
12662
|
+
"temporarily_unavailable",
|
|
12663
|
+
"unauthorized_client",
|
|
12664
|
+
"unexpected_auth_error",
|
|
12665
|
+
"unsupported_response_type",
|
|
12666
|
+
"web_onboarding_incomplete"
|
|
12667
|
+
]);
|
|
11640
12668
|
});
|
|
11641
12669
|
|
|
11642
12670
|
// src/setup/audit-handoff.ts
|
|
@@ -11778,34 +12806,6 @@ var init_rules_step = __esm(() => {
|
|
|
11778
12806
|
init_styles();
|
|
11779
12807
|
});
|
|
11780
12808
|
|
|
11781
|
-
// src/auth/errors.ts
|
|
11782
|
-
var exports_errors = {};
|
|
11783
|
-
__export(exports_errors, {
|
|
11784
|
-
OAuthCallbackError: () => OAuthCallbackError
|
|
11785
|
-
});
|
|
11786
|
-
var OAuthCallbackError;
|
|
11787
|
-
var init_errors = __esm(() => {
|
|
11788
|
-
OAuthCallbackError = class OAuthCallbackError extends Error {
|
|
11789
|
-
error;
|
|
11790
|
-
errorCode;
|
|
11791
|
-
errorDescription;
|
|
11792
|
-
constructor(message, details = {}) {
|
|
11793
|
-
super(message);
|
|
11794
|
-
this.name = "OAuthCallbackError";
|
|
11795
|
-
this.error = details.error;
|
|
11796
|
-
this.errorCode = details.errorCode;
|
|
11797
|
-
this.errorDescription = details.errorDescription;
|
|
11798
|
-
}
|
|
11799
|
-
get userMessage() {
|
|
11800
|
-
const desc = this.errorDescription ?? this.message;
|
|
11801
|
-
if (this.errorCode === "bad_oauth_state" || /state/i.test(desc)) {
|
|
11802
|
-
return `Authentication failed: ${desc}. Run \`dosu login\` again.`;
|
|
11803
|
-
}
|
|
11804
|
-
return `Authentication failed: ${desc}`;
|
|
11805
|
-
}
|
|
11806
|
-
};
|
|
11807
|
-
});
|
|
11808
|
-
|
|
11809
12809
|
// src/auth/server.ts
|
|
11810
12810
|
function escapeHtml(value) {
|
|
11811
12811
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -11983,8 +12983,8 @@ h1 {
|
|
|
11983
12983
|
async function startCallbackServer(opts = {}) {
|
|
11984
12984
|
let resolveToken;
|
|
11985
12985
|
let rejectToken;
|
|
11986
|
-
const tokenPromise = new Promise((
|
|
11987
|
-
resolveToken =
|
|
12986
|
+
const tokenPromise = new Promise((resolve2, reject) => {
|
|
12987
|
+
resolveToken = resolve2;
|
|
11988
12988
|
rejectToken = reject;
|
|
11989
12989
|
});
|
|
11990
12990
|
const http = __require("node:http");
|
|
@@ -12042,8 +13042,8 @@ async function startCallbackServer(opts = {}) {
|
|
|
12042
13042
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
12043
13043
|
res.end(buildSuccessHtml(email ?? undefined, opts.successVariant ?? "auth"));
|
|
12044
13044
|
});
|
|
12045
|
-
await new Promise((
|
|
12046
|
-
httpServer.listen(0, "localhost", () =>
|
|
13045
|
+
await new Promise((resolve2) => {
|
|
13046
|
+
httpServer.listen(0, "localhost", () => resolve2());
|
|
12047
13047
|
});
|
|
12048
13048
|
httpServer.unref();
|
|
12049
13049
|
const addr = httpServer.address();
|
|
@@ -12213,17 +13213,21 @@ __export(exports_flow2, {
|
|
|
12213
13213
|
stepDetectTools: () => stepDetectTools,
|
|
12214
13214
|
stepConfigureTools: () => stepConfigureTools,
|
|
12215
13215
|
runSetup: () => runSetup,
|
|
12216
|
-
runInstallSkill: () => runInstallSkill
|
|
13216
|
+
runInstallSkill: () => runInstallSkill,
|
|
13217
|
+
cliAuthFailureReason: () => cliAuthFailureReason
|
|
12217
13218
|
});
|
|
12218
|
-
import { randomUUID } from "node:crypto";
|
|
13219
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
13220
|
+
function trackInBackground(tracking) {
|
|
13221
|
+
tracking.catch(() => {});
|
|
13222
|
+
}
|
|
12219
13223
|
async function runSetup(opts = {}) {
|
|
12220
|
-
const onboardingRunID =
|
|
13224
|
+
const onboardingRunID = randomUUID3();
|
|
12221
13225
|
logger.info("setup", `Setup flow started${opts.deploymentID ? ` deployment=${opts.deploymentID}` : ""}${opts.mode ? ` mode=${opts.mode}` : ""}`);
|
|
12222
13226
|
intro("Dosu CLI Setup");
|
|
12223
|
-
|
|
13227
|
+
trackInBackground(trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_launch_attempted", {
|
|
12224
13228
|
has_deployment_option: Boolean(opts.deploymentID),
|
|
12225
13229
|
mode_option: opts.mode
|
|
12226
|
-
});
|
|
13230
|
+
}));
|
|
12227
13231
|
let cfg = loadConfig();
|
|
12228
13232
|
applyModeOverride(cfg, opts);
|
|
12229
13233
|
if (opts.deploymentID) {
|
|
@@ -12234,7 +13238,7 @@ async function runSetup(opts = {}) {
|
|
|
12234
13238
|
if (!authed)
|
|
12235
13239
|
return;
|
|
12236
13240
|
cfg = authed.cfg;
|
|
12237
|
-
|
|
13241
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_auth_completed"));
|
|
12238
13242
|
let apiClient = new Client(cfg);
|
|
12239
13243
|
let cloudSetupContext = null;
|
|
12240
13244
|
if (cfg.mode !== MODE_OSS) {
|
|
@@ -12242,39 +13246,39 @@ async function runSetup(opts = {}) {
|
|
|
12242
13246
|
s.start("Loading your workspace...");
|
|
12243
13247
|
cloudSetupContext = await resolveCloudSetupContext(cfg);
|
|
12244
13248
|
if (!cloudSetupContext) {
|
|
12245
|
-
|
|
13249
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
|
|
12246
13250
|
reason: "cloud_setup_context_failed"
|
|
12247
|
-
});
|
|
13251
|
+
}));
|
|
12248
13252
|
s.stop("Workspace load failed");
|
|
12249
13253
|
return;
|
|
12250
13254
|
}
|
|
12251
13255
|
s.stop("Workspace loaded");
|
|
12252
13256
|
}
|
|
12253
|
-
|
|
13257
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_started", {
|
|
12254
13258
|
flow_kind: cloudSetupContext ? cloudSetupContext.finishedOnboarding ? "setup" : "onboarding" : "oss"
|
|
12255
|
-
});
|
|
13259
|
+
}));
|
|
12256
13260
|
const needsHandshake = cfg.mode !== MODE_OSS && cloudSetupContext !== null && !cloudSetupContext.finishedOnboarding && !opts.deploymentID;
|
|
12257
13261
|
if (needsHandshake) {
|
|
12258
13262
|
const handshook = await stepSetupHandshake(cfg, onboardingRunID);
|
|
12259
13263
|
if (!handshook) {
|
|
12260
|
-
|
|
13264
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
|
|
12261
13265
|
reason: "web_onboarding_incomplete"
|
|
12262
|
-
});
|
|
13266
|
+
}));
|
|
12263
13267
|
return;
|
|
12264
13268
|
}
|
|
12265
13269
|
apiClient = new Client(cfg);
|
|
12266
13270
|
const refreshed = await resolveCloudSetupContext(cfg);
|
|
12267
13271
|
if (refreshed === null) {
|
|
12268
|
-
|
|
13272
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
|
|
12269
13273
|
reason: "cloud_setup_context_failed"
|
|
12270
|
-
});
|
|
13274
|
+
}));
|
|
12271
13275
|
return;
|
|
12272
13276
|
}
|
|
12273
13277
|
if (!refreshed.finishedOnboarding) {
|
|
12274
13278
|
log.warn("Your account still needs onboarding. Finish it in the browser at the Dosu app, then re-run `dosu setup`.");
|
|
12275
|
-
|
|
13279
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
|
|
12276
13280
|
reason: "onboarding_incomplete_after_handshake"
|
|
12277
|
-
});
|
|
13281
|
+
}));
|
|
12278
13282
|
process.exitCode = 1;
|
|
12279
13283
|
return;
|
|
12280
13284
|
}
|
|
@@ -12283,43 +13287,43 @@ async function runSetup(opts = {}) {
|
|
|
12283
13287
|
if (!cfg.active_account?.target?.deployment_id || opts.deploymentID) {
|
|
12284
13288
|
const ok = await resolveDeployment(apiClient, cfg, opts);
|
|
12285
13289
|
if (!ok) {
|
|
12286
|
-
|
|
13290
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
|
|
12287
13291
|
reason: "deployment_resolution_failed"
|
|
12288
|
-
});
|
|
13292
|
+
}));
|
|
12289
13293
|
return;
|
|
12290
13294
|
}
|
|
12291
13295
|
}
|
|
12292
13296
|
const apiKey = await stepMintAPIKey(apiClient, cfg);
|
|
12293
13297
|
if (!apiKey) {
|
|
12294
|
-
|
|
13298
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
|
|
12295
13299
|
reason: "api_key_failed"
|
|
12296
|
-
});
|
|
13300
|
+
}));
|
|
12297
13301
|
return;
|
|
12298
13302
|
}
|
|
12299
13303
|
updateTarget(cfg, { api_key: apiKey });
|
|
12300
13304
|
saveConfig(cfg);
|
|
12301
13305
|
const configured = await stepConfigureMcpTools(cfg);
|
|
12302
13306
|
if (configured === null) {
|
|
12303
|
-
|
|
13307
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_cancelled", {
|
|
12304
13308
|
reason: "mcp_selection_cancelled"
|
|
12305
|
-
});
|
|
13309
|
+
}));
|
|
12306
13310
|
return;
|
|
12307
13311
|
}
|
|
12308
13312
|
const mcpConfiguredThisRun = configured.some((result) => result.action === "install" || result.action === "skip");
|
|
12309
13313
|
const configuredProviders = configured.filter((result) => (result.action === "install" || result.action === "skip") && !result.error);
|
|
12310
13314
|
const mcpCompleted = configuredProviders.length > 0;
|
|
12311
13315
|
if (mcpCompleted) {
|
|
12312
|
-
|
|
13316
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_mcp_configured", {
|
|
12313
13317
|
provider_count: configuredProviders.length,
|
|
12314
13318
|
providers: configuredProviders.map((result) => result.provider.id())
|
|
12315
|
-
});
|
|
13319
|
+
}));
|
|
12316
13320
|
}
|
|
12317
13321
|
let skillCompleted = false;
|
|
12318
13322
|
const skillProviders = configuredProviders.map((result) => result.provider).filter((provider) => skillInstallTargetForProvider(provider.id()) !== null);
|
|
12319
13323
|
if (skillProviders.length > 0) {
|
|
12320
13324
|
skillCompleted = await runInstallSkill(skillProviders);
|
|
12321
13325
|
if (skillCompleted) {
|
|
12322
|
-
|
|
13326
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_skill_installed"));
|
|
12323
13327
|
}
|
|
12324
13328
|
}
|
|
12325
13329
|
let agentsMdCompleted = false;
|
|
@@ -12331,11 +13335,11 @@ async function runSetup(opts = {}) {
|
|
|
12331
13335
|
handoffToAudit = await offerAuditHandoff();
|
|
12332
13336
|
}
|
|
12333
13337
|
if (mcpCompleted || skillCompleted || agentsMdCompleted) {
|
|
12334
|
-
|
|
13338
|
+
trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_completed", {
|
|
12335
13339
|
completed_mcp: mcpCompleted,
|
|
12336
13340
|
completed_skill: skillCompleted,
|
|
12337
13341
|
completed_agents_md: agentsMdCompleted
|
|
12338
|
-
});
|
|
13342
|
+
}));
|
|
12339
13343
|
}
|
|
12340
13344
|
if (cfg.mode === MODE_OSS) {
|
|
12341
13345
|
outro("Setup complete! Using open-source libraries only.\n\nTips: Run `dosu setup --mode cloud` to connect your own repos.");
|
|
@@ -12447,7 +13451,7 @@ async function stepAuthenticate(existingCfg, onboardingRunID) {
|
|
|
12447
13451
|
}
|
|
12448
13452
|
}
|
|
12449
13453
|
if (onboardingRunID) {
|
|
12450
|
-
|
|
13454
|
+
trackInBackground(trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_auth_started"));
|
|
12451
13455
|
}
|
|
12452
13456
|
return await openBrowserForSetup(cfg, onboardingRunID);
|
|
12453
13457
|
}
|
|
@@ -12484,25 +13488,30 @@ async function openBrowserForSetup(cfg, onboardingRunID) {
|
|
|
12484
13488
|
} catch (err) {
|
|
12485
13489
|
const msg = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
12486
13490
|
logger.error("setup", `Auth failed: ${msg}`);
|
|
12487
|
-
|
|
12488
|
-
if (err instanceof OAuthCallbackError2) {
|
|
13491
|
+
if (err instanceof OAuthCallbackError) {
|
|
12489
13492
|
log.error(err.userMessage);
|
|
12490
13493
|
if (onboardingRunID) {
|
|
12491
|
-
|
|
12492
|
-
reason: err
|
|
12493
|
-
});
|
|
13494
|
+
trackInBackground(trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_auth_failed", {
|
|
13495
|
+
reason: cliAuthFailureReason(err)
|
|
13496
|
+
}));
|
|
12494
13497
|
}
|
|
12495
13498
|
return null;
|
|
12496
13499
|
}
|
|
12497
13500
|
log.error(`Authentication failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
12498
13501
|
if (onboardingRunID) {
|
|
12499
|
-
|
|
12500
|
-
reason:
|
|
12501
|
-
});
|
|
13502
|
+
trackInBackground(trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_auth_failed", {
|
|
13503
|
+
reason: cliAuthFailureReason(err)
|
|
13504
|
+
}));
|
|
12502
13505
|
}
|
|
12503
13506
|
return null;
|
|
12504
13507
|
}
|
|
12505
13508
|
}
|
|
13509
|
+
function cliAuthFailureReason(err) {
|
|
13510
|
+
if (!(err instanceof OAuthCallbackError))
|
|
13511
|
+
return "unexpected_auth_error";
|
|
13512
|
+
const code = err.errorCode;
|
|
13513
|
+
return code && OAUTH_ANALYTICS_REASONS.has(code) ? code : "oauth_callback_error";
|
|
13514
|
+
}
|
|
12506
13515
|
async function stepSetupHandshake(cfg, onboardingRunID) {
|
|
12507
13516
|
logger.info("setup", "Step: setup handshake");
|
|
12508
13517
|
log.info("Almost there — finish setting up in the browser and we'll pick up from here.");
|
|
@@ -12800,9 +13809,10 @@ function stepShowSummary(results) {
|
|
|
12800
13809
|
log.success("All agents already configured. No changes needed.");
|
|
12801
13810
|
}
|
|
12802
13811
|
}
|
|
12803
|
-
var SETUP_HANDSHAKE_TIMEOUT_MS = 1800000;
|
|
13812
|
+
var OAUTH_ANALYTICS_REASONS, SETUP_HANDSHAKE_TIMEOUT_MS = 1800000;
|
|
12804
13813
|
var init_flow2 = __esm(() => {
|
|
12805
13814
|
init_dist8();
|
|
13815
|
+
init_errors();
|
|
12806
13816
|
init_client();
|
|
12807
13817
|
init_skill();
|
|
12808
13818
|
init_config();
|
|
@@ -12813,11 +13823,21 @@ var init_flow2 = __esm(() => {
|
|
|
12813
13823
|
init_audit_handoff();
|
|
12814
13824
|
init_rules_step();
|
|
12815
13825
|
init_styles();
|
|
13826
|
+
OAUTH_ANALYTICS_REASONS = new Set([
|
|
13827
|
+
"access_denied",
|
|
13828
|
+
"bad_oauth_state",
|
|
13829
|
+
"invalid_request",
|
|
13830
|
+
"invalid_scope",
|
|
13831
|
+
"server_error",
|
|
13832
|
+
"temporarily_unavailable",
|
|
13833
|
+
"unauthorized_client",
|
|
13834
|
+
"unsupported_response_type"
|
|
13835
|
+
]);
|
|
12816
13836
|
});
|
|
12817
13837
|
|
|
12818
13838
|
// src/commands/insights.ts
|
|
12819
|
-
import { existsSync as
|
|
12820
|
-
import { dirname as dirname7, join as
|
|
13839
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync10, readdirSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "node:fs";
|
|
13840
|
+
import { dirname as dirname7, join as join30 } from "node:path";
|
|
12821
13841
|
function shuffled(arr) {
|
|
12822
13842
|
const copy2 = [...arr];
|
|
12823
13843
|
for (let i2 = copy2.length - 1;i2 > 0; i2--) {
|
|
@@ -12921,17 +13941,17 @@ function makeAskFn(cfg) {
|
|
|
12921
13941
|
};
|
|
12922
13942
|
}
|
|
12923
13943
|
function insightsDir() {
|
|
12924
|
-
return
|
|
13944
|
+
return join30(getConfigDir(), "insights");
|
|
12925
13945
|
}
|
|
12926
13946
|
function reportPath(timestamp) {
|
|
12927
13947
|
const dir = insightsDir();
|
|
12928
13948
|
if (!timestamp)
|
|
12929
|
-
return
|
|
13949
|
+
return join30(dir, "latest.html");
|
|
12930
13950
|
const iso = timestamp.toISOString().slice(0, 19).replace(/:/g, "-");
|
|
12931
|
-
return
|
|
13951
|
+
return join30(dir, `report-${iso}Z.html`);
|
|
12932
13952
|
}
|
|
12933
13953
|
function pruneOldReports(dir, keepN) {
|
|
12934
|
-
if (!
|
|
13954
|
+
if (!existsSync20(dir))
|
|
12935
13955
|
return;
|
|
12936
13956
|
let entries;
|
|
12937
13957
|
try {
|
|
@@ -12943,7 +13963,7 @@ function pruneOldReports(dir, keepN) {
|
|
|
12943
13963
|
const reports = entries.filter((f2) => REPORT_FILE_PATTERN.test(f2)).sort().reverse();
|
|
12944
13964
|
for (const f2 of reports.slice(keepN)) {
|
|
12945
13965
|
try {
|
|
12946
|
-
|
|
13966
|
+
unlinkSync3(join30(dir, f2));
|
|
12947
13967
|
} catch (err) {
|
|
12948
13968
|
logger.debug("insights", `failed to prune ${f2}: ${err instanceof Error ? err.message : err}`);
|
|
12949
13969
|
}
|
|
@@ -13016,9 +14036,9 @@ function defaultRunner(cfg) {
|
|
|
13016
14036
|
render: renderHTML,
|
|
13017
14037
|
writeFile: (path3, content) => {
|
|
13018
14038
|
const dir = dirname7(path3);
|
|
13019
|
-
if (!
|
|
13020
|
-
|
|
13021
|
-
|
|
14039
|
+
if (!existsSync20(dir))
|
|
14040
|
+
mkdirSync10(dir, { recursive: true, mode: 448 });
|
|
14041
|
+
writeFileSync10(path3, content, { mode: 384 });
|
|
13022
14042
|
},
|
|
13023
14043
|
prune: pruneOldReports,
|
|
13024
14044
|
openInBrowser: async (path3) => {
|
|
@@ -13442,7 +14462,7 @@ Could not open a browser automatically.`);
|
|
|
13442
14462
|
throw new Error("Authentication timed out. Run 'dosu login' to try again.");
|
|
13443
14463
|
}
|
|
13444
14464
|
function sleep5(ms) {
|
|
13445
|
-
return new Promise((
|
|
14465
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
13446
14466
|
}
|
|
13447
14467
|
var POLL_INTERVAL_MS = 5000;
|
|
13448
14468
|
var init_device = __esm(() => {
|
|
@@ -13811,7 +14831,15 @@ var init_flow3 = __esm(() => {
|
|
|
13811
14831
|
// src/cli/cli.ts
|
|
13812
14832
|
init_commander();
|
|
13813
14833
|
init_client();
|
|
13814
|
-
import {
|
|
14834
|
+
import {
|
|
14835
|
+
closeSync,
|
|
14836
|
+
constants,
|
|
14837
|
+
fstatSync,
|
|
14838
|
+
openSync,
|
|
14839
|
+
readFileSync as readFileSync19,
|
|
14840
|
+
readSync,
|
|
14841
|
+
unlinkSync as unlinkSync4
|
|
14842
|
+
} from "node:fs";
|
|
13815
14843
|
|
|
13816
14844
|
// src/commands/analytics.ts
|
|
13817
14845
|
init_commander();
|
|
@@ -15986,7 +17014,7 @@ init_dist();
|
|
|
15986
17014
|
init_commander();
|
|
15987
17015
|
init_trpc();
|
|
15988
17016
|
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
15989
|
-
import { readFileSync as
|
|
17017
|
+
import { readFileSync as readFileSync17 } from "node:fs";
|
|
15990
17018
|
function requireConfig10() {
|
|
15991
17019
|
return requireLoginConfig();
|
|
15992
17020
|
}
|
|
@@ -16162,7 +17190,7 @@ function reviewCommand() {
|
|
|
16162
17190
|
let body = opts.body;
|
|
16163
17191
|
if (opts.bodyFile) {
|
|
16164
17192
|
try {
|
|
16165
|
-
body =
|
|
17193
|
+
body = readFileSync17(opts.bodyFile, "utf-8");
|
|
16166
17194
|
} catch (err) {
|
|
16167
17195
|
console.error(import_picocolors19.default.red(`Failed to read --body-file: ${err.message}`));
|
|
16168
17196
|
process.exit(1);
|
|
@@ -16480,6 +17508,71 @@ function suggestCommand() {
|
|
|
16480
17508
|
return cmd;
|
|
16481
17509
|
}
|
|
16482
17510
|
|
|
17511
|
+
// src/commands/telemetry.ts
|
|
17512
|
+
init_commander();
|
|
17513
|
+
init_settings();
|
|
17514
|
+
init_telemetry();
|
|
17515
|
+
function statusPayload() {
|
|
17516
|
+
const settings2 = loadTelemetrySettings();
|
|
17517
|
+
const environmentOverride = telemetryDisabledByEnvironment();
|
|
17518
|
+
const webAppURL = getWebAppURL();
|
|
17519
|
+
const commandWebAppURL = parseTelemetryWebAppURL(webAppURL);
|
|
17520
|
+
const setupWebAppURL = parseTelemetryWebAppURL(webAppURL, process.env.DOSU_DEV === "true");
|
|
17521
|
+
const analyticsReleaseToken = parsePostHogProjectToken(process.env.DOSU_POSTHOG_PROJECT_TOKEN_OVERRIDE ?? "phc_Uo9RxhN0HRk8gZkPlT18BCr7eqsM0MPWVW88HZB95V5");
|
|
17522
|
+
return {
|
|
17523
|
+
schema_version: settings2.schema_version,
|
|
17524
|
+
enabled: isTelemetryEnabled(settings2),
|
|
17525
|
+
destinations: {
|
|
17526
|
+
command_analytics: Boolean(commandWebAppURL && analyticsReleaseToken),
|
|
17527
|
+
setup_analytics: Boolean(setupWebAppURL && analyticsReleaseToken),
|
|
17528
|
+
error_diagnostics: Boolean(parseSentryDsn(process.env.DOSU_CLI_SENTRY_DSN_OVERRIDE ?? "https://f6b3e51dea6f50746316aa1896df76e0@o4505364738670592.ingest.us.sentry.io/4511883653283840"))
|
|
17529
|
+
},
|
|
17530
|
+
environment_override: environmentOverride ?? null,
|
|
17531
|
+
debug_mode: process.env.DOSU_TELEMETRY_DEBUG === "1",
|
|
17532
|
+
telemetry_id: settings2.install_id ?? null
|
|
17533
|
+
};
|
|
17534
|
+
}
|
|
17535
|
+
function printHumanStatus() {
|
|
17536
|
+
const status = statusPayload();
|
|
17537
|
+
console.log(`Telemetry: ${status.enabled ? "enabled" : "disabled"}`);
|
|
17538
|
+
console.log(`Destinations: command analytics PostHog ${status.destinations.command_analytics ? "configured" : "not configured"}, setup analytics Dosu API ${status.destinations.setup_analytics ? "configured" : "not configured"}, error diagnostics Sentry ${status.destinations.error_diagnostics ? "configured" : "not configured"}`);
|
|
17539
|
+
if (status.environment_override) {
|
|
17540
|
+
console.log(`Environment override: ${status.environment_override}`);
|
|
17541
|
+
}
|
|
17542
|
+
if (status.debug_mode)
|
|
17543
|
+
console.log("Debug mode: on (payloads are printed to stderr, not sent)");
|
|
17544
|
+
if (status.telemetry_id)
|
|
17545
|
+
console.log(`Telemetry ID: ${status.telemetry_id}`);
|
|
17546
|
+
console.log("Telemetry fields never include raw command lines, free-form arguments or option values, user source files, local paths, credentials, error messages, or debug.log; setup analytics uses only documented coarse fields and its existing Dosu session header only for API authorization.");
|
|
17547
|
+
}
|
|
17548
|
+
function updateTelemetry(enabled) {
|
|
17549
|
+
if (!setTelemetryEnabled(enabled)) {
|
|
17550
|
+
throw new Error("Could not save telemetry settings");
|
|
17551
|
+
}
|
|
17552
|
+
console.log(`Telemetry ${enabled ? "enabled" : "disabled"}.`);
|
|
17553
|
+
}
|
|
17554
|
+
function telemetryCommand() {
|
|
17555
|
+
const command = new Command("telemetry").description("Manage privacy-preserving telemetry");
|
|
17556
|
+
command.command("status").description("Show telemetry state and destination configuration").option("--json", "Output as JSON").action((opts) => {
|
|
17557
|
+
if (opts.json) {
|
|
17558
|
+
console.log(JSON.stringify(statusPayload(), null, 2));
|
|
17559
|
+
return;
|
|
17560
|
+
}
|
|
17561
|
+
printHumanStatus();
|
|
17562
|
+
});
|
|
17563
|
+
command.command("enable").description("Enable telemetry").action(() => updateTelemetry(true));
|
|
17564
|
+
command.command("disable").description("Disable telemetry").action(() => updateTelemetry(false));
|
|
17565
|
+
command.command("reset").description("Rotate the local pseudonymous telemetry ID (does not delete prior events)").action(() => {
|
|
17566
|
+
const previous = loadTelemetrySettings().install_id;
|
|
17567
|
+
const next = previous ? resetInstallID() : getOrCreateInstallID();
|
|
17568
|
+
if (!next)
|
|
17569
|
+
throw new Error("Could not save telemetry settings");
|
|
17570
|
+
console.log(`Telemetry ID ${previous ? "rotated" : "created"}: ${next}`);
|
|
17571
|
+
console.log("This does not delete events already retained by telemetry providers.");
|
|
17572
|
+
});
|
|
17573
|
+
return command;
|
|
17574
|
+
}
|
|
17575
|
+
|
|
16483
17576
|
// src/commands/threads.ts
|
|
16484
17577
|
init_commander();
|
|
16485
17578
|
init_trpc();
|
|
@@ -16765,8 +17858,8 @@ function owningPackageManager(entrypoint, platform4, comSpec, env = process.env,
|
|
|
16765
17858
|
}
|
|
16766
17859
|
const owners = Object.keys(PACKAGE_MANAGERS).filter((manager) => packageRoots(manager, platform4, comSpec, env, cwd).some((root) => {
|
|
16767
17860
|
try {
|
|
16768
|
-
const
|
|
16769
|
-
return
|
|
17861
|
+
const relative2 = path3.relative(realpathSync(root), realEntrypoint);
|
|
17862
|
+
return relative2 !== ".." && !relative2.startsWith(`..${path3.sep}`) && !path3.isAbsolute(relative2);
|
|
16770
17863
|
} catch {
|
|
16771
17864
|
return false;
|
|
16772
17865
|
}
|
|
@@ -16860,14 +17953,16 @@ init_config();
|
|
|
16860
17953
|
init_logger();
|
|
16861
17954
|
init_providers();
|
|
16862
17955
|
init_styles();
|
|
17956
|
+
init_settings();
|
|
17957
|
+
init_telemetry();
|
|
16863
17958
|
init_skill_update_check();
|
|
16864
17959
|
|
|
16865
17960
|
// src/version/update-check.ts
|
|
16866
17961
|
init_config();
|
|
16867
17962
|
init_logger();
|
|
16868
17963
|
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
16869
|
-
import { existsSync as
|
|
16870
|
-
import { join as
|
|
17964
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync11, readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "node:fs";
|
|
17965
|
+
import { join as join31 } from "node:path";
|
|
16871
17966
|
var CACHE_FILENAME3 = "update-check.json";
|
|
16872
17967
|
var CHECK_INTERVAL_MS3 = 6 * 60 * 60 * 1000;
|
|
16873
17968
|
var FETCH_TIMEOUT_MS3 = 1000;
|
|
@@ -16894,14 +17989,14 @@ function isNewerVersion(latest, current) {
|
|
|
16894
17989
|
return false;
|
|
16895
17990
|
}
|
|
16896
17991
|
function getCachePath3() {
|
|
16897
|
-
return
|
|
17992
|
+
return join31(getConfigDir(), CACHE_FILENAME3);
|
|
16898
17993
|
}
|
|
16899
17994
|
function readCache() {
|
|
16900
17995
|
try {
|
|
16901
17996
|
const path3 = getCachePath3();
|
|
16902
|
-
if (!
|
|
17997
|
+
if (!existsSync21(path3))
|
|
16903
17998
|
return null;
|
|
16904
|
-
const data = JSON.parse(
|
|
17999
|
+
const data = JSON.parse(readFileSync18(path3, "utf-8"));
|
|
16905
18000
|
if (typeof data.lastCheck === "number" && isValidVersion(data.latestVersion)) {
|
|
16906
18001
|
return data;
|
|
16907
18002
|
}
|
|
@@ -16913,10 +18008,10 @@ function readCache() {
|
|
|
16913
18008
|
function writeCache(cache) {
|
|
16914
18009
|
try {
|
|
16915
18010
|
const dir = getConfigDir();
|
|
16916
|
-
if (!
|
|
16917
|
-
|
|
18011
|
+
if (!existsSync21(dir)) {
|
|
18012
|
+
mkdirSync11(dir, { recursive: true, mode: 448 });
|
|
16918
18013
|
}
|
|
16919
|
-
|
|
18014
|
+
writeFileSync11(getCachePath3(), JSON.stringify(cache), { mode: 384 });
|
|
16920
18015
|
} catch {}
|
|
16921
18016
|
}
|
|
16922
18017
|
async function fetchLatestVersion() {
|
|
@@ -17008,6 +18103,104 @@ function isHookEntrypointInvocation(argv) {
|
|
|
17008
18103
|
function shouldRunBackgroundChecks(actionName, argv) {
|
|
17009
18104
|
return actionName !== "upgrade" && !isHookEntrypointInvocation(argv);
|
|
17010
18105
|
}
|
|
18106
|
+
var TELEMETRY_EXCLUDED_COMMANDS = new Set([
|
|
18107
|
+
"hooks user-prompt-submit",
|
|
18108
|
+
"hooks post-tool-use",
|
|
18109
|
+
"hooks stop"
|
|
18110
|
+
]);
|
|
18111
|
+
var TELEMETRY_FLUSH_TIMEOUT_MS = 750;
|
|
18112
|
+
var MAX_TELEMETRY_CONFIG_BYTES = 64 * 1024;
|
|
18113
|
+
|
|
18114
|
+
class CliUsageError extends Error {
|
|
18115
|
+
exitCode = 1;
|
|
18116
|
+
constructor(message) {
|
|
18117
|
+
super(message);
|
|
18118
|
+
this.name = "CliUsageError";
|
|
18119
|
+
}
|
|
18120
|
+
}
|
|
18121
|
+
function commandTelemetryName(actionCommand) {
|
|
18122
|
+
const segments = [];
|
|
18123
|
+
let current = actionCommand;
|
|
18124
|
+
while (current.parent) {
|
|
18125
|
+
segments.unshift(current.name());
|
|
18126
|
+
current = current.parent;
|
|
18127
|
+
}
|
|
18128
|
+
if (segments.length > 0)
|
|
18129
|
+
return segments.join(" ");
|
|
18130
|
+
return actionCommand.args.length > 0 ? "unknown" : "tui";
|
|
18131
|
+
}
|
|
18132
|
+
function shouldTrackCommand(command) {
|
|
18133
|
+
if (command === "telemetry" || command.startsWith("telemetry "))
|
|
18134
|
+
return false;
|
|
18135
|
+
return !TELEMETRY_EXCLUDED_COMMANDS.has(command);
|
|
18136
|
+
}
|
|
18137
|
+
function commandTelemetryContext() {
|
|
18138
|
+
try {
|
|
18139
|
+
const cfg = loadConfigForTelemetry();
|
|
18140
|
+
if (!cfg)
|
|
18141
|
+
return { mode: "cloud", isAuthenticated: false };
|
|
18142
|
+
const authenticated = isAuthenticated(cfg);
|
|
18143
|
+
const accessToken = authenticated ? cfg.active_account.session.access_token : "";
|
|
18144
|
+
const configUserID = getConfigUserID(cfg);
|
|
18145
|
+
const tokenUserID = getAccessTokenUserID(accessToken);
|
|
18146
|
+
const userID = configUserID && configUserID === tokenUserID ? configUserID : undefined;
|
|
18147
|
+
const email = userID ? getAccessTokenEmail(accessToken) : undefined;
|
|
18148
|
+
return {
|
|
18149
|
+
mode: cfg.mode === MODE_OSS ? "oss" : "cloud",
|
|
18150
|
+
isAuthenticated: authenticated,
|
|
18151
|
+
...userID ? { user: { id: userID, ...email ? { email } : {} } } : {}
|
|
18152
|
+
};
|
|
18153
|
+
} catch {
|
|
18154
|
+
return { mode: "cloud", isAuthenticated: false };
|
|
18155
|
+
}
|
|
18156
|
+
}
|
|
18157
|
+
function loadConfigForTelemetry() {
|
|
18158
|
+
let fd;
|
|
18159
|
+
try {
|
|
18160
|
+
const nonblocking = typeof constants.O_NONBLOCK === "number" ? constants.O_NONBLOCK : 0;
|
|
18161
|
+
fd = openSync(getConfigPath(), constants.O_RDONLY | nonblocking);
|
|
18162
|
+
const file = fstatSync(fd);
|
|
18163
|
+
if (!file.isFile() || file.size > MAX_TELEMETRY_CONFIG_BYTES)
|
|
18164
|
+
return;
|
|
18165
|
+
const content = Buffer.alloc(MAX_TELEMETRY_CONFIG_BYTES + 1);
|
|
18166
|
+
const bytesRead = readSync(fd, content, 0, content.byteLength, 0);
|
|
18167
|
+
if (bytesRead > MAX_TELEMETRY_CONFIG_BYTES)
|
|
18168
|
+
return;
|
|
18169
|
+
return parseConfig(JSON.parse(content.subarray(0, bytesRead).toString("utf8")));
|
|
18170
|
+
} catch {
|
|
18171
|
+
return;
|
|
18172
|
+
} finally {
|
|
18173
|
+
if (fd !== undefined) {
|
|
18174
|
+
try {
|
|
18175
|
+
closeSync(fd);
|
|
18176
|
+
} catch {}
|
|
18177
|
+
}
|
|
18178
|
+
}
|
|
18179
|
+
}
|
|
18180
|
+
function startTelemetry(telemetry, command, context) {
|
|
18181
|
+
if (!telemetry)
|
|
18182
|
+
return false;
|
|
18183
|
+
try {
|
|
18184
|
+
telemetry.start(command, context);
|
|
18185
|
+
return true;
|
|
18186
|
+
} catch {
|
|
18187
|
+
return false;
|
|
18188
|
+
}
|
|
18189
|
+
}
|
|
18190
|
+
async function finishTelemetry(operation) {
|
|
18191
|
+
let timeout;
|
|
18192
|
+
try {
|
|
18193
|
+
await Promise.race([
|
|
18194
|
+
Promise.resolve().then(operation),
|
|
18195
|
+
new Promise((resolve2) => {
|
|
18196
|
+
timeout = setTimeout(resolve2, TELEMETRY_FLUSH_TIMEOUT_MS);
|
|
18197
|
+
})
|
|
18198
|
+
]);
|
|
18199
|
+
} catch {} finally {
|
|
18200
|
+
if (timeout)
|
|
18201
|
+
clearTimeout(timeout);
|
|
18202
|
+
}
|
|
18203
|
+
}
|
|
17011
18204
|
function suggestClosestCommand(input, program2) {
|
|
17012
18205
|
let best;
|
|
17013
18206
|
let bestDistance = Infinity;
|
|
@@ -17034,8 +18227,10 @@ function editDistance2(a3, b2) {
|
|
|
17034
18227
|
}
|
|
17035
18228
|
return prev[b2.length];
|
|
17036
18229
|
}
|
|
17037
|
-
function createProgram() {
|
|
18230
|
+
function createProgram(options = {}) {
|
|
17038
18231
|
const program2 = new Command;
|
|
18232
|
+
let telemetryStarted = false;
|
|
18233
|
+
let telemetryValidationFailure = false;
|
|
17039
18234
|
program2.name("dosu").description("Dosu CLI - Manage MCP servers for AI tools").version(getVersionString(), "-v, --version").helpCommand("help [command]", "Show help for a command").option("--debug", "Enable debug logging to stderr", false).hook("preAction", async (thisCommand, actionCommand) => {
|
|
17040
18235
|
const opts = thisCommand.optsWithGlobals();
|
|
17041
18236
|
logger.init({ debug: opts.debug });
|
|
@@ -17046,6 +18241,20 @@ function createProgram() {
|
|
|
17046
18241
|
checkForSkillUpdates();
|
|
17047
18242
|
checkForReadyTasks();
|
|
17048
18243
|
}
|
|
18244
|
+
const command = commandTelemetryName(actionCommand);
|
|
18245
|
+
if (options.telemetry && shouldTrackCommand(command)) {
|
|
18246
|
+
telemetryStarted = startTelemetry(options.telemetry, command, commandTelemetryContext());
|
|
18247
|
+
}
|
|
18248
|
+
}).hook("postAction", async () => {
|
|
18249
|
+
const exitCode = Number(process.exitCode ?? 0);
|
|
18250
|
+
const telemetry = options.telemetry;
|
|
18251
|
+
if (telemetryStarted && telemetry) {
|
|
18252
|
+
if (telemetryValidationFailure) {
|
|
18253
|
+
await finishTelemetry(() => telemetry.fail(new CliUsageError("expected CLI usage error")));
|
|
18254
|
+
} else {
|
|
18255
|
+
await finishTelemetry(() => telemetry.complete(Number.isFinite(exitCode) ? exitCode : 1));
|
|
18256
|
+
}
|
|
18257
|
+
}
|
|
17049
18258
|
}).allowExcessArguments(true).action(async () => {
|
|
17050
18259
|
const command = program2.args[0];
|
|
17051
18260
|
if (command !== undefined) {
|
|
@@ -17057,6 +18266,7 @@ function createProgram() {
|
|
|
17057
18266
|
message += `
|
|
17058
18267
|
Run 'dosu --help' to see available commands.`;
|
|
17059
18268
|
console.error(message);
|
|
18269
|
+
telemetryValidationFailure = true;
|
|
17060
18270
|
process.exitCode = 1;
|
|
17061
18271
|
return;
|
|
17062
18272
|
}
|
|
@@ -17218,20 +18428,20 @@ Run 'dosu --help' to see available commands.`;
|
|
|
17218
18428
|
try {
|
|
17219
18429
|
provider = getProvider(toolId.toLowerCase());
|
|
17220
18430
|
} catch {
|
|
17221
|
-
throw new
|
|
18431
|
+
throw new CliUsageError(`unknown tool '${toolId}'. Use 'dosu mcp list' to see available tools`);
|
|
17222
18432
|
}
|
|
17223
18433
|
const cfg = loadConfig();
|
|
17224
18434
|
if (!isAuthenticated(cfg)) {
|
|
17225
|
-
throw new
|
|
18435
|
+
throw new CliUsageError("not logged in. Run 'dosu login' first");
|
|
17226
18436
|
}
|
|
17227
18437
|
if (isTokenExpired(cfg) && !await ensureFreshSession(cfg)) {
|
|
17228
|
-
throw new
|
|
18438
|
+
throw new CliUsageError("session expired. Run 'dosu login' to re-authenticate");
|
|
17229
18439
|
}
|
|
17230
18440
|
if (cfg.mode !== MODE_OSS && !cfg.active_account?.target?.deployment_id) {
|
|
17231
|
-
throw new
|
|
18441
|
+
throw new CliUsageError("no MCP selected. Run 'dosu' to open the TUI and select an MCP");
|
|
17232
18442
|
}
|
|
17233
18443
|
if (!cfg.active_account?.target?.api_key) {
|
|
17234
|
-
throw new
|
|
18444
|
+
throw new CliUsageError("no API key available. Run 'dosu setup' to create one");
|
|
17235
18445
|
}
|
|
17236
18446
|
if (provider.id() === "manual") {
|
|
17237
18447
|
provider.install(cfg, false, { showSecret: opts.showSecret });
|
|
@@ -17284,6 +18494,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
|
|
|
17284
18494
|
program2.addCommand(reviewCommand());
|
|
17285
18495
|
program2.addCommand(sourcesCommand());
|
|
17286
18496
|
program2.addCommand(suggestCommand());
|
|
18497
|
+
program2.addCommand(telemetryCommand());
|
|
17287
18498
|
program2.addCommand(topicsCommand());
|
|
17288
18499
|
program2.addCommand(threadsCommand());
|
|
17289
18500
|
program2.addCommand(skillCommand());
|
|
@@ -17310,14 +18521,14 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
|
|
|
17310
18521
|
return;
|
|
17311
18522
|
}
|
|
17312
18523
|
if (opts.tool || opts.loginTicket) {
|
|
17313
|
-
throw new
|
|
18524
|
+
throw new CliUsageError("--tool and --login-ticket require --agent");
|
|
17314
18525
|
}
|
|
17315
18526
|
const { runSetup: runSetup2 } = await Promise.resolve().then(() => (init_flow2(), exports_flow2));
|
|
17316
18527
|
let mode;
|
|
17317
18528
|
if (opts.mode !== undefined) {
|
|
17318
18529
|
const normalized = opts.mode.toLowerCase();
|
|
17319
18530
|
if (normalized !== "oss" && normalized !== "cloud") {
|
|
17320
|
-
throw new
|
|
18531
|
+
throw new CliUsageError(`invalid --mode value '${opts.mode}' (expected 'oss' or 'cloud')`);
|
|
17321
18532
|
}
|
|
17322
18533
|
mode = normalized;
|
|
17323
18534
|
}
|
|
@@ -17327,7 +18538,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
|
|
|
17327
18538
|
const logPath = logger.getLogPath();
|
|
17328
18539
|
if (opts.clear) {
|
|
17329
18540
|
try {
|
|
17330
|
-
|
|
18541
|
+
unlinkSync4(logPath);
|
|
17331
18542
|
console.log("Log file deleted.");
|
|
17332
18543
|
} catch {
|
|
17333
18544
|
console.log("No log file to delete.");
|
|
@@ -17337,7 +18548,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
|
|
|
17337
18548
|
if (opts.tail !== undefined) {
|
|
17338
18549
|
const n2 = typeof opts.tail === "string" ? parseInt(opts.tail, 10) || 50 : 50;
|
|
17339
18550
|
try {
|
|
17340
|
-
const content =
|
|
18551
|
+
const content = readFileSync19(logPath, "utf-8");
|
|
17341
18552
|
const lines = content.split(`
|
|
17342
18553
|
`);
|
|
17343
18554
|
console.log(lines.slice(-n2).join(`
|
|
@@ -17364,8 +18575,27 @@ async function ensureFreshSession(cfg) {
|
|
|
17364
18575
|
}
|
|
17365
18576
|
}
|
|
17366
18577
|
async function execute() {
|
|
17367
|
-
const
|
|
17368
|
-
|
|
18578
|
+
const telemetry = isHookEntrypointInvocation(process.argv) ? undefined : processCommandTelemetry();
|
|
18579
|
+
const program2 = createProgram({ telemetry });
|
|
18580
|
+
try {
|
|
18581
|
+
await program2.parseAsync(process.argv);
|
|
18582
|
+
} catch (err) {
|
|
18583
|
+
if (telemetry)
|
|
18584
|
+
await finishTelemetry(() => telemetry.fail(err));
|
|
18585
|
+
throw err;
|
|
18586
|
+
}
|
|
18587
|
+
}
|
|
18588
|
+
function processCommandTelemetry() {
|
|
18589
|
+
try {
|
|
18590
|
+
const settings2 = loadTelemetrySettings();
|
|
18591
|
+
if (!isTelemetryEnabled(settings2))
|
|
18592
|
+
return;
|
|
18593
|
+
return createCommandTelemetry({}, {
|
|
18594
|
+
resolveInstallId: () => settings2.install_id ?? getOrCreateInstallID()
|
|
18595
|
+
});
|
|
18596
|
+
} catch {
|
|
18597
|
+
return;
|
|
18598
|
+
}
|
|
17369
18599
|
}
|
|
17370
18600
|
|
|
17371
18601
|
// src/index.ts
|
|
@@ -17383,3 +18613,5 @@ execute().catch((err) => {
|
|
|
17383
18613
|
}
|
|
17384
18614
|
process.exit(1);
|
|
17385
18615
|
});
|
|
18616
|
+
|
|
18617
|
+
//# debugId=2facad12-755f-3f33-6475-6e2164756e21
|