@dosu/cli 0.67.0 → 0.67.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/dosu.js +334 -192
  2. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -47,6 +47,111 @@ var __esm = (fn, res, err) => () => {
47
47
  };
48
48
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
49
49
 
50
+ // node_modules/picocolors/picocolors.js
51
+ var require_picocolors = __commonJS(function(exports, module) {
52
+ var p = process || {};
53
+ var argv = p.argv || [];
54
+ var env = p.env || {};
55
+ var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
56
+ var formatter = (open, close, replace = open) => (input) => {
57
+ let string = "" + input, index = string.indexOf(close, open.length);
58
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
59
+ };
60
+ var replaceClose = (string, close, replace, index) => {
61
+ let result = "", cursor = 0;
62
+ do {
63
+ result += string.substring(cursor, index) + replace;
64
+ cursor = index + close.length;
65
+ index = string.indexOf(close, cursor);
66
+ } while (~index);
67
+ return result + string.substring(cursor);
68
+ };
69
+ var createColors = (enabled = isColorSupported) => {
70
+ let f = enabled ? formatter : () => String;
71
+ return {
72
+ isColorSupported: enabled,
73
+ reset: f("\x1B[0m", "\x1B[0m"),
74
+ bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
75
+ dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
76
+ italic: f("\x1B[3m", "\x1B[23m"),
77
+ underline: f("\x1B[4m", "\x1B[24m"),
78
+ inverse: f("\x1B[7m", "\x1B[27m"),
79
+ hidden: f("\x1B[8m", "\x1B[28m"),
80
+ strikethrough: f("\x1B[9m", "\x1B[29m"),
81
+ black: f("\x1B[30m", "\x1B[39m"),
82
+ red: f("\x1B[31m", "\x1B[39m"),
83
+ green: f("\x1B[32m", "\x1B[39m"),
84
+ yellow: f("\x1B[33m", "\x1B[39m"),
85
+ blue: f("\x1B[34m", "\x1B[39m"),
86
+ magenta: f("\x1B[35m", "\x1B[39m"),
87
+ cyan: f("\x1B[36m", "\x1B[39m"),
88
+ white: f("\x1B[37m", "\x1B[39m"),
89
+ gray: f("\x1B[90m", "\x1B[39m"),
90
+ bgBlack: f("\x1B[40m", "\x1B[49m"),
91
+ bgRed: f("\x1B[41m", "\x1B[49m"),
92
+ bgGreen: f("\x1B[42m", "\x1B[49m"),
93
+ bgYellow: f("\x1B[43m", "\x1B[49m"),
94
+ bgBlue: f("\x1B[44m", "\x1B[49m"),
95
+ bgMagenta: f("\x1B[45m", "\x1B[49m"),
96
+ bgCyan: f("\x1B[46m", "\x1B[49m"),
97
+ bgWhite: f("\x1B[47m", "\x1B[49m"),
98
+ blackBright: f("\x1B[90m", "\x1B[39m"),
99
+ redBright: f("\x1B[91m", "\x1B[39m"),
100
+ greenBright: f("\x1B[92m", "\x1B[39m"),
101
+ yellowBright: f("\x1B[93m", "\x1B[39m"),
102
+ blueBright: f("\x1B[94m", "\x1B[39m"),
103
+ magentaBright: f("\x1B[95m", "\x1B[39m"),
104
+ cyanBright: f("\x1B[96m", "\x1B[39m"),
105
+ whiteBright: f("\x1B[97m", "\x1B[39m"),
106
+ bgBlackBright: f("\x1B[100m", "\x1B[49m"),
107
+ bgRedBright: f("\x1B[101m", "\x1B[49m"),
108
+ bgGreenBright: f("\x1B[102m", "\x1B[49m"),
109
+ bgYellowBright: f("\x1B[103m", "\x1B[49m"),
110
+ bgBlueBright: f("\x1B[104m", "\x1B[49m"),
111
+ bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
112
+ bgCyanBright: f("\x1B[106m", "\x1B[49m"),
113
+ bgWhiteBright: f("\x1B[107m", "\x1B[49m")
114
+ };
115
+ };
116
+ module.exports = createColors();
117
+ module.exports.createColors = createColors;
118
+ });
119
+
120
+ // src/cli/command-error.ts
121
+ function isCommandError(error) {
122
+ return error instanceof CommandError;
123
+ }
124
+ var COMMAND_ERROR_CODES, CommandError;
125
+ var init_command_error = __esm(() => {
126
+ COMMAND_ERROR_CODES = [
127
+ "NOT_LOGGED_IN",
128
+ "NO_ORG_SELECTED",
129
+ "NO_API_KEY",
130
+ "NO_LIBRARY_SELECTED",
131
+ "NO_DEPLOYMENT_SELECTED",
132
+ "ORG_UNAVAILABLE",
133
+ "LIBRARY_UNAVAILABLE",
134
+ "DEPLOYMENT_UNAVAILABLE",
135
+ "SCOPE_MISMATCH",
136
+ "DEPLOYMENT_NOT_FOUND",
137
+ "DEPLOYMENT_AMBIGUOUS",
138
+ "NOT_MCP_DEPLOYMENT",
139
+ "REVIEW_ITEM_NOT_FOUND",
140
+ "INVALID_ARGUMENT"
141
+ ];
142
+ CommandError = class CommandError extends Error {
143
+ code;
144
+ details;
145
+ exitCode = 1;
146
+ constructor(code, message, details = []) {
147
+ super(message);
148
+ this.code = code;
149
+ this.details = details;
150
+ this.name = "CommandError";
151
+ }
152
+ };
153
+ });
154
+
50
155
  // src/statusline/argv.ts
51
156
  function agentFromArgv(argv) {
52
157
  for (let i = 0;i < argv.length; i++) {
@@ -1006,76 +1111,6 @@ var init_config_helpers = __esm(() => {
1006
1111
  writeFileAtomic = import_write_file_atomic.default;
1007
1112
  });
1008
1113
 
1009
- // node_modules/picocolors/picocolors.js
1010
- var require_picocolors = __commonJS(function(exports, module) {
1011
- var p = process || {};
1012
- var argv = p.argv || [];
1013
- var env = p.env || {};
1014
- var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
1015
- var formatter = (open, close, replace = open) => (input) => {
1016
- let string = "" + input, index = string.indexOf(close, open.length);
1017
- return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
1018
- };
1019
- var replaceClose = (string, close, replace, index) => {
1020
- let result = "", cursor = 0;
1021
- do {
1022
- result += string.substring(cursor, index) + replace;
1023
- cursor = index + close.length;
1024
- index = string.indexOf(close, cursor);
1025
- } while (~index);
1026
- return result + string.substring(cursor);
1027
- };
1028
- var createColors = (enabled = isColorSupported) => {
1029
- let f = enabled ? formatter : () => String;
1030
- return {
1031
- isColorSupported: enabled,
1032
- reset: f("\x1B[0m", "\x1B[0m"),
1033
- bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
1034
- dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
1035
- italic: f("\x1B[3m", "\x1B[23m"),
1036
- underline: f("\x1B[4m", "\x1B[24m"),
1037
- inverse: f("\x1B[7m", "\x1B[27m"),
1038
- hidden: f("\x1B[8m", "\x1B[28m"),
1039
- strikethrough: f("\x1B[9m", "\x1B[29m"),
1040
- black: f("\x1B[30m", "\x1B[39m"),
1041
- red: f("\x1B[31m", "\x1B[39m"),
1042
- green: f("\x1B[32m", "\x1B[39m"),
1043
- yellow: f("\x1B[33m", "\x1B[39m"),
1044
- blue: f("\x1B[34m", "\x1B[39m"),
1045
- magenta: f("\x1B[35m", "\x1B[39m"),
1046
- cyan: f("\x1B[36m", "\x1B[39m"),
1047
- white: f("\x1B[37m", "\x1B[39m"),
1048
- gray: f("\x1B[90m", "\x1B[39m"),
1049
- bgBlack: f("\x1B[40m", "\x1B[49m"),
1050
- bgRed: f("\x1B[41m", "\x1B[49m"),
1051
- bgGreen: f("\x1B[42m", "\x1B[49m"),
1052
- bgYellow: f("\x1B[43m", "\x1B[49m"),
1053
- bgBlue: f("\x1B[44m", "\x1B[49m"),
1054
- bgMagenta: f("\x1B[45m", "\x1B[49m"),
1055
- bgCyan: f("\x1B[46m", "\x1B[49m"),
1056
- bgWhite: f("\x1B[47m", "\x1B[49m"),
1057
- blackBright: f("\x1B[90m", "\x1B[39m"),
1058
- redBright: f("\x1B[91m", "\x1B[39m"),
1059
- greenBright: f("\x1B[92m", "\x1B[39m"),
1060
- yellowBright: f("\x1B[93m", "\x1B[39m"),
1061
- blueBright: f("\x1B[94m", "\x1B[39m"),
1062
- magentaBright: f("\x1B[95m", "\x1B[39m"),
1063
- cyanBright: f("\x1B[96m", "\x1B[39m"),
1064
- whiteBright: f("\x1B[97m", "\x1B[39m"),
1065
- bgBlackBright: f("\x1B[100m", "\x1B[49m"),
1066
- bgRedBright: f("\x1B[101m", "\x1B[49m"),
1067
- bgGreenBright: f("\x1B[102m", "\x1B[49m"),
1068
- bgYellowBright: f("\x1B[103m", "\x1B[49m"),
1069
- bgBlueBright: f("\x1B[104m", "\x1B[49m"),
1070
- bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
1071
- bgCyanBright: f("\x1B[106m", "\x1B[49m"),
1072
- bgWhiteBright: f("\x1B[107m", "\x1B[49m")
1073
- };
1074
- };
1075
- module.exports = createColors();
1076
- module.exports.createColors = createColors;
1077
- });
1078
-
1079
1114
  // src/version/version.ts
1080
1115
  function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
1081
1116
  return channel === "npm" && (env.npm_lifecycle_event === "npx" || env.npm_command === "exec");
@@ -1083,7 +1118,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
1083
1118
  function getVersionString() {
1084
1119
  return `v${VERSION}`;
1085
1120
  }
1086
- var VERSION = "0.67.0", INSTALL_CHANNEL = "npm";
1121
+ var VERSION = "0.67.1", INSTALL_CHANNEL = "npm";
1087
1122
 
1088
1123
  // src/debug/logger.ts
1089
1124
  import {
@@ -1173,18 +1208,18 @@ function writeEntry(level, mod, message) {
1173
1208
  } catch {}
1174
1209
  if (debugToConsole) {
1175
1210
  const colorize = {
1176
- DEBUG: import_picocolors.default.dim,
1177
- INFO: import_picocolors.default.cyan,
1178
- WARN: import_picocolors.default.yellow,
1179
- ERROR: import_picocolors.default.red
1211
+ DEBUG: import_picocolors2.default.dim,
1212
+ INFO: import_picocolors2.default.cyan,
1213
+ WARN: import_picocolors2.default.yellow,
1214
+ ERROR: import_picocolors2.default.red
1180
1215
  }[level];
1181
1216
  console.error(colorize(line.trimEnd()));
1182
1217
  }
1183
1218
  }
1184
- var import_picocolors, MAX_LOG_SIZE = 1048576, TRUNCATE_KEEP = 524288, LOG_FILENAME = "debug.log", REDACTED = "[REDACTED]", SECRET_QUERY_KEYS, initialized = false, debugToConsole = false, logFilePath = null, ANSI_PATTERN, logger;
1219
+ var import_picocolors2, MAX_LOG_SIZE = 1048576, TRUNCATE_KEEP = 524288, LOG_FILENAME = "debug.log", REDACTED = "[REDACTED]", SECRET_QUERY_KEYS, initialized = false, debugToConsole = false, logFilePath = null, ANSI_PATTERN, logger;
1185
1220
  var init_logger = __esm(() => {
1186
1221
  init_config();
1187
- import_picocolors = __toESM(require_picocolors(), 1);
1222
+ import_picocolors2 = __toESM(require_picocolors(), 1);
1188
1223
  SECRET_QUERY_KEYS = [
1189
1224
  "access_token",
1190
1225
  "refresh_token",
@@ -7187,8 +7222,7 @@ var init_arguments = __esm(() => {
7187
7222
  function requireLoginConfig() {
7188
7223
  const cfg = loadConfig();
7189
7224
  if (!cfg.active_account?.session.access_token) {
7190
- console.error(import_picocolors2.default.red("Not logged in. Run 'dosu login' first."));
7191
- process.exit(1);
7225
+ throw new CommandError("NOT_LOGGED_IN", "Not logged in. Run 'dosu login' first.");
7192
7226
  }
7193
7227
  return cfg;
7194
7228
  }
@@ -7196,22 +7230,20 @@ function requireOrgConfig() {
7196
7230
  const cfg = requireLoginConfig();
7197
7231
  const orgId = cfg.active_account?.target?.org_id;
7198
7232
  if (!orgId) {
7199
- console.error(import_picocolors2.default.red("Missing org config. Run 'dosu setup' to reconfigure."));
7200
- process.exit(1);
7233
+ throw new CommandError("NO_ORG_SELECTED", "Missing org config. Run 'dosu setup' to reconfigure.");
7201
7234
  }
7202
7235
  return { cfg, orgId };
7203
7236
  }
7204
7237
  function requireAPIKey(cfg) {
7205
- if (!cfg.active_account?.target?.api_key) {
7206
- console.error(import_picocolors2.default.red("API key not configured. Run 'dosu setup' first."));
7207
- process.exit(1);
7238
+ const apiKey = cfg.active_account?.target?.api_key;
7239
+ if (!apiKey) {
7240
+ throw new CommandError("NO_API_KEY", "API key not configured. Run 'dosu setup' first.");
7208
7241
  }
7209
- return cfg.active_account?.target?.api_key;
7242
+ return apiKey;
7210
7243
  }
7211
- var import_picocolors2;
7212
7244
  var init_auth = __esm(() => {
7245
+ init_command_error();
7213
7246
  init_config();
7214
- import_picocolors2 = __toESM(require_picocolors(), 1);
7215
7247
  });
7216
7248
 
7217
7249
  // node_modules/fast-string-truncated-width/dist/utils.js
@@ -11430,8 +11462,16 @@ function requireConfig4() {
11430
11462
  return requireLoginConfig();
11431
11463
  }
11432
11464
  async function listAccessibleDeployments(client, activeOrgId) {
11433
- if (activeOrgId)
11434
- return client.workspaces.listForOrg.query(activeOrgId);
11465
+ if (activeOrgId) {
11466
+ const deployments = await client.workspaces.listForOrg.query(activeOrgId);
11467
+ if (deployments.length > 0)
11468
+ return deployments;
11469
+ const orgs = await client.organization.getOrganizations.query({});
11470
+ if (!orgs.some((org) => org.org_id === activeOrgId)) {
11471
+ throw new CommandError("ORG_UNAVAILABLE", "The saved organization is not available to this account.", ["Run 'dosu setup' to choose an organization and MCP deployment."]);
11472
+ }
11473
+ return deployments;
11474
+ }
11435
11475
  const orgs = await client.organization.getOrganizations.query({});
11436
11476
  const deployments = await Promise.all(orgs.map((org) => client.workspaces.listForOrg.query(org.org_id)));
11437
11477
  return deployments.flat();
@@ -11445,15 +11485,11 @@ async function resolveDeploymentId(client, activeOrgId, id) {
11445
11485
  if (matches.length === 1)
11446
11486
  return matches[0].deployment_id;
11447
11487
  if (matches.length === 0) {
11448
- console.error(import_picocolors15.default.red(`Deployment not found: ${id}`));
11449
- console.error(import_picocolors15.default.dim("Expected a full deployment ID (UUID). Run 'dosu deployments list --json' to see full IDs."));
11450
- process.exit(1);
11451
- }
11452
- console.error(import_picocolors15.default.red(`Ambiguous deployment ID prefix: ${id} matches ${matches.length}:`));
11453
- for (const d of matches) {
11454
- console.error(import_picocolors15.default.dim(` ${d.deployment_id} ${d.name}`));
11488
+ throw new CommandError("DEPLOYMENT_NOT_FOUND", `Deployment not found: ${id}`, [
11489
+ "Expected a full deployment ID (UUID). Run 'dosu deployments list --json' to see full IDs."
11490
+ ]);
11455
11491
  }
11456
- process.exit(1);
11492
+ throw new CommandError("DEPLOYMENT_AMBIGUOUS", `Ambiguous deployment ID prefix: ${id} matches ${matches.length}:`, matches.map((d) => ` ${d.deployment_id} ${d.name}`));
11457
11493
  }
11458
11494
  function deploymentsCommand() {
11459
11495
  const cmd = new Command("deployments").description("Select the MCP deployment (and its Library) this CLI uses; not for Agents");
@@ -11484,14 +11520,12 @@ ${import_picocolors15.default.dim(`Current: ${cfg.active_account?.target?.deploy
11484
11520
  cmd.command("info").description("Show the selected MCP deployment").option("--json", "Output as JSON").action(async (opts) => {
11485
11521
  const cfg = requireConfig4();
11486
11522
  if (!cfg.active_account?.target?.deployment_id) {
11487
- console.error(import_picocolors15.default.red("No deployment selected. Run 'dosu setup' or 'dosu deployments switch'."));
11488
- process.exit(1);
11523
+ throw new CommandError("NO_DEPLOYMENT_SELECTED", "No deployment selected. Run 'dosu setup' or 'dosu deployments switch'.");
11489
11524
  }
11490
11525
  const client = createTypedClient(cfg);
11491
11526
  const deployment = await client.workspaces.get.query(cfg.active_account?.target?.deployment_id);
11492
11527
  if (!deployment) {
11493
- console.error(import_picocolors15.default.red(`Deployment not found: ${cfg.active_account?.target?.deployment_id}`));
11494
- process.exit(1);
11528
+ throw new CommandError("DEPLOYMENT_UNAVAILABLE", `Deployment not found: ${cfg.active_account?.target?.deployment_id}`);
11495
11529
  }
11496
11530
  if (opts.json) {
11497
11531
  printResult(deployment, opts);
@@ -11514,12 +11548,10 @@ ${import_picocolors15.default.dim(`Current: ${cfg.active_account?.target?.deploy
11514
11548
  const id = await resolveDeploymentId(client, cfg.active_account?.target?.org_id, rawId);
11515
11549
  const deployment = await client.workspaces.get.query(id);
11516
11550
  if (!deployment) {
11517
- console.error(import_picocolors15.default.red(`Deployment not found: ${id}`));
11518
- process.exit(1);
11551
+ throw new CommandError("DEPLOYMENT_NOT_FOUND", `Deployment not found: ${id}`);
11519
11552
  }
11520
11553
  if (deployment.provider_slug !== MCP_PROVIDER_SLUG) {
11521
- console.error(import_picocolors15.default.red(`Not a Dosu MCP deployment: ${id}`));
11522
- process.exit(1);
11554
+ throw new CommandError("NOT_MCP_DEPLOYMENT", `Not a Dosu MCP deployment: ${id}`);
11523
11555
  }
11524
11556
  const apiKey = await new Client(cfg).createAPIKey(deployment.deployment_id, "dosu-cli");
11525
11557
  updateTarget(cfg, {
@@ -11542,6 +11574,7 @@ ${import_picocolors15.default.dim(`Current: ${cfg.active_account?.target?.deploy
11542
11574
  var import_picocolors15, MCP_PROVIDER_SLUG = "dosu_mcp";
11543
11575
  var init_deployments = __esm(() => {
11544
11576
  init_commander();
11577
+ init_command_error();
11545
11578
  init_client();
11546
11579
  init_trpc();
11547
11580
  init_config();
@@ -14290,7 +14323,7 @@ var init_conflicts = __esm(() => {
14290
14323
  });
14291
14324
 
14292
14325
  // src/telemetry/debug-id.ts
14293
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "5d3e9365-4283-2b42-6475-6e2164756e21";
14326
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "152ccbaa-13cc-83fc-6475-6e2164756e21";
14294
14327
 
14295
14328
  // src/telemetry/telemetry.ts
14296
14329
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -15089,10 +15122,11 @@ function createCommandTelemetry(settings, dependencies = {}) {
15089
15122
  };
15090
15123
  }
15091
15124
  function shouldSendToSentry(error) {
15092
- return !["SESSION_EXPIRED", "SESSION_PERSISTENCE_ERROR"].includes(error.code ?? "");
15125
+ return !EXPECTED_STATE_ERROR_CODES.has(error.code ?? "");
15093
15126
  }
15094
- 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, SYNC_TRIGGERS, SYNC_STATUSES, LEARNER_OUTCOMES, GATEWAY_REASONS, CLAUDE_CODE_SOURCES, SETTINGS_CONFLICT_KEYS, SETTINGS_CONFLICT_FAMILIES, MAX_CONFLICT_KEYS_LENGTH = 200, CLAUDE_CODE_VERSION_PATTERN, LEARNER_MODEL_PATTERN, BACKFILL_OFFERS, SENTRY_FACET_TAGS, pendingFacets;
15127
+ 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, EXPECTED_STATE_ERROR_CODES, SYNC_TRIGGERS, SYNC_STATUSES, LEARNER_OUTCOMES, GATEWAY_REASONS, CLAUDE_CODE_SOURCES, SETTINGS_CONFLICT_KEYS, SETTINGS_CONFLICT_FAMILIES, MAX_CONFLICT_KEYS_LENGTH = 200, CLAUDE_CODE_VERSION_PATTERN, LEARNER_MODEL_PATTERN, BACKFILL_OFFERS, SENTRY_FACET_TAGS, pendingFacets;
15095
15128
  var init_telemetry = __esm(() => {
15129
+ init_command_error();
15096
15130
  init_conflicts();
15097
15131
  MAX_RESPONSE_BYTES = 1024 * 1024;
15098
15132
  CLI_PACKAGE_ROOT = detectCliPackageRoot();
@@ -15173,7 +15207,13 @@ var init_telemetry = __esm(() => {
15173
15207
  "commander.missingMandatoryOptionValue",
15174
15208
  "commander.optionMissingArgument",
15175
15209
  "commander.unknownCommand",
15176
- "commander.unknownOption"
15210
+ "commander.unknownOption",
15211
+ ...COMMAND_ERROR_CODES
15212
+ ]);
15213
+ EXPECTED_STATE_ERROR_CODES = new Set([
15214
+ "SESSION_EXPIRED",
15215
+ "SESSION_PERSISTENCE_ERROR",
15216
+ ...COMMAND_ERROR_CODES
15177
15217
  ]);
15178
15218
  SYNC_TRIGGERS = new Set(["hook", "manual", "bootstrap"]);
15179
15219
  SYNC_STATUSES = new Set([
@@ -60317,25 +60357,27 @@ function bareMessageId(id) {
60317
60357
  function truncateId(id) {
60318
60358
  return (isDraftId(id) ? bareMessageId(id) : id).slice(0, 8);
60319
60359
  }
60360
+ function reviewItemNotFound(id) {
60361
+ return new CommandError("REVIEW_ITEM_NOT_FOUND", `No review item found for '${id}'. Run 'dosu review list' to see pending items.`);
60362
+ }
60320
60363
  async function requireChange(client, id) {
60321
60364
  try {
60322
60365
  return await client.review.getChange.query({ id });
60323
60366
  } catch (err) {
60324
- if (isNotFound(err) || isInvalidId(err)) {
60325
- console.error(import_picocolors27.default.red(`No review item found for '${id}'. Run 'dosu review list' to see pending items.`));
60326
- process.exit(1);
60327
- }
60367
+ if (isNotFound(err) || isInvalidId(err))
60368
+ throw reviewItemNotFound(id);
60328
60369
  throw err;
60329
60370
  }
60330
60371
  }
60331
60372
  async function requireDraft(client, id) {
60332
60373
  const draft = await client.messages.getMessage.query(bareMessageId(id));
60333
- if (!draft) {
60334
- console.error(import_picocolors27.default.red(`No review item found for '${id}'. Run 'dosu review list' to see pending items.`));
60335
- process.exit(1);
60336
- }
60374
+ if (!draft)
60375
+ throw reviewItemNotFound(id);
60337
60376
  return draft;
60338
60377
  }
60378
+ function invalidArgument(message) {
60379
+ return new CommandError("INVALID_ARGUMENT", message);
60380
+ }
60339
60381
  function humanizeSource(origin, version) {
60340
60382
  switch (origin) {
60341
60383
  case "manual_update":
@@ -60387,10 +60429,8 @@ function printDraftPreview(draft) {
60387
60429
  console.log();
60388
60430
  console.log(draft.body ?? "");
60389
60431
  }
60390
- function failScope(message, hint = SELECT_LIBRARY_HINT) {
60391
- console.error(import_picocolors27.default.red(message));
60392
- console.error(import_picocolors27.default.dim(hint));
60393
- process.exit(1);
60432
+ function failScope(code, message, hint = SELECT_LIBRARY_HINT) {
60433
+ throw new CommandError(code, message, [hint]);
60394
60434
  }
60395
60435
  async function lookupLibrary(client, spaceId) {
60396
60436
  try {
@@ -60409,13 +60449,13 @@ async function resolveReviewScope(client, spaceId, deploymentId) {
60409
60449
  deploymentId ? client.workspaces.get.query(deploymentId) : Promise.resolve(undefined)
60410
60450
  ]);
60411
60451
  if (deploymentId && !deployment) {
60412
- failScope(`The selected MCP deployment (${deploymentId}) is unavailable: it was deleted, or the ` + "signed-in account cannot access it.");
60452
+ failScope("DEPLOYMENT_UNAVAILABLE", `The selected MCP deployment (${deploymentId}) is unavailable: it was deleted, or the ` + "signed-in account cannot access it.");
60413
60453
  }
60414
60454
  if (deployment && deployment.space_id !== spaceId) {
60415
- failScope(`The saved Library (${spaceId}) does not match the Library of the selected MCP ` + `deployment (${deployment.space_id}).`, `Run 'dosu deployments switch ${deployment.deployment_id}' to save that deployment's ` + "Library again, or choose another MCP deployment with 'dosu deployments list'.");
60455
+ failScope("SCOPE_MISMATCH", `The saved Library (${spaceId}) does not match the Library of the selected MCP ` + `deployment (${deployment.space_id}).`, `Run 'dosu deployments switch ${deployment.deployment_id}' to save that deployment's ` + "Library again, or choose another MCP deployment with 'dosu deployments list'.");
60416
60456
  }
60417
60457
  if (!library.found || !store) {
60418
- failScope(`The selected Library (${spaceId}) is unavailable: it was deleted, or the signed-in ` + "account cannot access it.");
60458
+ failScope("LIBRARY_UNAVAILABLE", `The selected Library (${spaceId}) is unavailable: it was deleted, or the signed-in ` + "account cannot access it.");
60419
60459
  }
60420
60460
  return {
60421
60461
  knowledgeStoreId: store.id,
@@ -60443,15 +60483,14 @@ function reviewCommand() {
60443
60483
  try {
60444
60484
  range = resolveTimeRange(opts.since, opts.until);
60445
60485
  } catch (err) {
60446
- console.error(import_picocolors27.default.red(`${err.message}.`));
60447
- process.exit(1);
60486
+ throw invalidArgument(`${err.message}.`);
60448
60487
  }
60449
60488
  const rangeLabel = describeTimeRange(range);
60450
60489
  const inRange = rangeLabel ? ` ${rangeLabel}` : "";
60451
60490
  const cfg = requireConfig10();
60452
60491
  const target = cfg.active_account?.target;
60453
60492
  if (!target?.space_id) {
60454
- failScope("No Library selected. The review list reads the Library of the selected MCP deployment.");
60493
+ failScope("NO_LIBRARY_SELECTED", "No Library selected. The review list reads the Library of the selected MCP deployment.");
60455
60494
  }
60456
60495
  const client = createTypedClient(cfg);
60457
60496
  const scope = await resolveReviewScope(client, target.space_id, target.deployment_id);
@@ -60532,30 +60571,22 @@ function reviewCommand() {
60532
60571
  const cfg = requireConfig10();
60533
60572
  const client = createTypedClient(cfg);
60534
60573
  if (opts.body !== undefined && opts.bodyFile !== undefined) {
60535
- console.error(import_picocolors27.default.red("Pass only one of --body or --body-file."));
60536
- process.exit(1);
60574
+ throw invalidArgument("Pass only one of --body or --body-file.");
60537
60575
  }
60538
60576
  let body = opts.body;
60539
60577
  if (opts.bodyFile) {
60540
60578
  try {
60541
60579
  body = readFileSync19(opts.bodyFile, "utf-8");
60542
60580
  } catch (err) {
60543
- console.error(import_picocolors27.default.red(`Failed to read --body-file: ${err.message}`));
60544
- process.exit(1);
60581
+ throw invalidArgument(`Failed to read --body-file: ${err.message}`);
60545
60582
  }
60546
60583
  }
60547
60584
  if (body === undefined && opts.title === undefined) {
60548
- console.error(import_picocolors27.default.red("Nothing to edit. Pass --title and/or --body/--body-file."));
60549
- process.exit(1);
60585
+ throw invalidArgument("Nothing to edit. Pass --title and/or --body/--body-file.");
60550
60586
  }
60551
60587
  if (isDraftId(id)) {
60552
- if (opts.title !== undefined) {
60553
- console.error(import_picocolors27.default.red("Draft replies support --body only (no --title)."));
60554
- process.exit(1);
60555
- }
60556
- if (body === undefined) {
60557
- console.error(import_picocolors27.default.red("Draft replies require --body or --body-file."));
60558
- process.exit(1);
60588
+ if (opts.title !== undefined || body === undefined) {
60589
+ throw invalidArgument("Draft replies support --body only (no --title).");
60559
60590
  }
60560
60591
  await requireDraft(client, id);
60561
60592
  await client.messages.saveDraft.mutate({
@@ -60571,8 +60602,7 @@ function reviewCommand() {
60571
60602
  });
60572
60603
  } catch (err) {
60573
60604
  if (isNotFound(err)) {
60574
- console.error(import_picocolors27.default.red(`No pending review item found for '${id}'. Run 'dosu review list' to see editable items.`));
60575
- process.exit(1);
60605
+ throw new CommandError("REVIEW_ITEM_NOT_FOUND", `No pending review item found for '${id}'. Run 'dosu review list' to see editable items.`);
60576
60606
  }
60577
60607
  throw err;
60578
60608
  }
@@ -60653,8 +60683,7 @@ function reviewCommand() {
60653
60683
  const client = createTypedClient(cfg);
60654
60684
  if (isDraftId(id)) {
60655
60685
  await requireDraft(client, id);
60656
- console.error(import_picocolors27.default.red("Revert is not supported for draft replies. A rejected draft is regenerated on the next agent run."));
60657
- process.exit(1);
60686
+ throw invalidArgument("Revert is not supported for draft replies. A rejected draft is regenerated on the next agent run.");
60658
60687
  }
60659
60688
  await requireChange(client, id);
60660
60689
  await client.page.updatePublicationStatus.mutate({
@@ -60674,6 +60703,7 @@ var import_picocolors27, DRAFT_MESSAGE_ID_PREFIX = "draft_message:", SELECT_LIBR
60674
60703
  var init_review = __esm(() => {
60675
60704
  init_dist();
60676
60705
  init_commander();
60706
+ init_command_error();
60677
60707
  init_trpc();
60678
60708
  init_auth();
60679
60709
  init_confirmation();
@@ -60767,7 +60797,7 @@ Use [commands.md](references/commands.md) as the sole detailed command and flag
60767
60797
  ## Handle failures literally
60768
60798
 
60769
60799
  - \`Not logged in\` or an unrecoverable expired session: run \`dosu login\` (agent setup may instead return a ticket flow).
60770
- - Missing organization, Library, deployment, or API-key context: run the appropriate \`dosu setup\` flow.
60800
+ - Missing or unavailable organization, Library, deployment, or API-key context: tell the user which \`dosu setup\` flow fixes it. Plain \`dosu setup\` is interactive, so don't start it for them unless they ask.
60771
60801
  - Wrong or unexpected Library context: read \`dosu status --json\` and \`dosu deployments info --json\` before changing anything. Switch only to an MCP deployment the user named or confirmed; never pick the first one listed, and never switch just because a list came back empty.
60772
60802
  - Skill guidance out of date: \`dosu skill update\` rewrites the installed skill from the running CLI version. Some agents read skills only when a session starts, so start a new session if the change does not appear. Installed files show the skill is on disk, not that the agent loaded it.
60773
60803
  - \`confirmRequired\`: no write occurred.
@@ -66695,6 +66725,63 @@ var init_incognito_backfill_check = __esm(() => {
66695
66725
  import_picocolors38 = __toESM(require_picocolors(), 1);
66696
66726
  });
66697
66727
 
66728
+ // src/cli/fatal-error.ts
66729
+ function read2(value, key) {
66730
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
66731
+ return;
66732
+ }
66733
+ try {
66734
+ return Reflect.get(value, key);
66735
+ } catch {
66736
+ return;
66737
+ }
66738
+ }
66739
+ function tokenOf2(data, key) {
66740
+ const value = read2(data, key);
66741
+ if (typeof value !== "string")
66742
+ return;
66743
+ const trimmed = value.trim();
66744
+ return REQUEST_ID_PATTERN2.test(trimmed) ? trimmed : undefined;
66745
+ }
66746
+ function statusOf2(data) {
66747
+ const value = read2(data, "httpStatus");
66748
+ return typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599 ? value : undefined;
66749
+ }
66750
+ function fatalErrorDiagnostics2(err) {
66751
+ const data = read2(err, "data");
66752
+ if (!data)
66753
+ return;
66754
+ const code = tokenOf2(data, "code");
66755
+ const path = tokenOf2(data, "path");
66756
+ const status = statusOf2(data);
66757
+ const requestId = tokenOf2(data, "requestId");
66758
+ const parts = [
66759
+ code && `code=${code}`,
66760
+ path && `path=${path}`,
66761
+ status && `status=${status}`,
66762
+ requestId && `request_id=${requestId}`
66763
+ ].filter(Boolean);
66764
+ return parts.length > 0 ? parts.join(" ") : undefined;
66765
+ }
66766
+ function printFatalError2(err) {
66767
+ if (isCommandError(err)) {
66768
+ console.error(import_picocolors39.default.red(err.message));
66769
+ for (const line of err.details)
66770
+ console.error(import_picocolors39.default.dim(line));
66771
+ return;
66772
+ }
66773
+ console.error(read2(err, "message") ?? err);
66774
+ const diagnostics = fatalErrorDiagnostics2(err);
66775
+ if (diagnostics)
66776
+ console.error(diagnostics);
66777
+ }
66778
+ var import_picocolors39, REQUEST_ID_PATTERN2;
66779
+ var init_fatal_error = __esm(() => {
66780
+ init_command_error();
66781
+ import_picocolors39 = __toESM(require_picocolors(), 1);
66782
+ REQUEST_ID_PATTERN2 = /^[A-Za-z0-9][A-Za-z0-9:._-]{0,127}$/;
66783
+ });
66784
+
66698
66785
  // src/tui/analytics-view.ts
66699
66786
  function analyticsListHeight(rows) {
66700
66787
  const room = frameMaxLines(rows) - ANALYTICS_VIEW_CHROME_LINES;
@@ -66813,7 +66900,7 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
66813
66900
  const rows = analyticsTabRows(tab, state, pageStats);
66814
66901
  const { visible, above, below } = windowReport(rows, scroll, height);
66815
66902
  const empty = tab === "overview" ? "No analytics yet. They appear after the first study run." : tab === "projects" ? "No per-project history yet. It fills in as sessions are studied." : pagesPending ? "Loading page analytics..." : "No page analytics yet.";
66816
- const listRows = visible.length > 0 ? visible.map((row) => import_picocolors39.default.dim(row)) : [import_picocolors39.default.dim(empty)];
66903
+ const listRows = visible.length > 0 ? visible.map((row) => import_picocolors40.default.dim(row)) : [import_picocolors40.default.dim(empty)];
66817
66904
  const scrollParts = [];
66818
66905
  if (above > 0)
66819
66906
  scrollParts.push(`↑ ${above} earlier`);
@@ -66829,9 +66916,9 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
66829
66916
  ], tab, width, { spread: false }),
66830
66917
  "",
66831
66918
  ...listRows,
66832
- ...scrollParts.length > 0 ? [import_picocolors39.default.dim(scrollParts.join(" · "))] : [],
66919
+ ...scrollParts.length > 0 ? [import_picocolors40.default.dim(scrollParts.join(" · "))] : [],
66833
66920
  "",
66834
- import_picocolors39.default.dim("tab switch · ↑↓ scroll · esc back")
66921
+ import_picocolors40.default.dim("tab switch · ↑↓ scroll · esc back")
66835
66922
  ];
66836
66923
  return lines.join(`
66837
66924
  `);
@@ -66928,7 +67015,7 @@ ${CLEAR_BELOW2}`);
66928
67015
  input.on("data", onData);
66929
67016
  });
66930
67017
  }
66931
- var import_picocolors39, ESC8, HIDE_CURSOR4, SHOW_CURSOR4, CTRL_C5, KEY_UP5, KEY_DOWN5, KEY_RIGHT4, KEY_LEFT4, CURSOR_HOME2, CLEAR_BELOW2, CLEAR_EOL2, ANALYTICS_VIEW_POLL_MS = 1000, ANALYTICS_VIEW_LINES = 14, ANALYTICS_VIEW_CHROME_LINES = 8, ANALYTICS_VIEW_TABS, TOP_PAGES_LIMIT = 5, TOP_CITED_DAYS = 30, label = (text) => text.padEnd(26);
67018
+ var import_picocolors40, ESC8, HIDE_CURSOR4, SHOW_CURSOR4, CTRL_C5, KEY_UP5, KEY_DOWN5, KEY_RIGHT4, KEY_LEFT4, CURSOR_HOME2, CLEAR_BELOW2, CLEAR_EOL2, ANALYTICS_VIEW_POLL_MS = 1000, ANALYTICS_VIEW_LINES = 14, ANALYTICS_VIEW_CHROME_LINES = 8, ANALYTICS_VIEW_TABS, TOP_PAGES_LIMIT = 5, TOP_CITED_DAYS = 30, label = (text) => text.padEnd(26);
66932
67019
  var init_analytics_view = __esm(() => {
66933
67020
  init_trpc();
66934
67021
  init_config();
@@ -66936,7 +67023,7 @@ var init_analytics_view = __esm(() => {
66936
67023
  init_alt_screen();
66937
67024
  init_layout();
66938
67025
  init_menu();
66939
- import_picocolors39 = __toESM(require_picocolors(), 1);
67026
+ import_picocolors40 = __toESM(require_picocolors(), 1);
66940
67027
  ESC8 = String.fromCharCode(27);
66941
67028
  HIDE_CURSOR4 = `${ESC8}[?25l`;
66942
67029
  SHOW_CURSOR4 = `${ESC8}[?25h`;
@@ -66954,7 +67041,7 @@ var init_analytics_view = __esm(() => {
66954
67041
  // src/tui/banner.ts
66955
67042
  function paintLogoRow(row) {
66956
67043
  return row.map(([tone, art]) => {
66957
- if (!import_picocolors40.default.isColorSupported)
67044
+ if (!import_picocolors41.default.isColorSupported)
66958
67045
  return art;
66959
67046
  const { fg, fallback } = LOGO_TONES[tone];
66960
67047
  return hasTruecolor() ? `${fg}${art}\x1B[39m` : fallback(art);
@@ -66985,14 +67072,14 @@ function wrapValue(text, room) {
66985
67072
  }
66986
67073
  function checklistRows(ctx, width) {
66987
67074
  const on = brand(CHECK2);
66988
- const off = import_picocolors40.default.dim(CIRCLE);
67075
+ const off = import_picocolors41.default.dim(CIRCLE);
66989
67076
  const rows = [["workspace", ctx.directory]];
66990
67077
  rows.push([
66991
67078
  "account",
66992
- ctx.sessionExpired ? `${off} ${import_picocolors40.default.yellow("session expired")} ${import_picocolors40.default.dim(`${DOT3} run Log in`)}` : ctx.signedIn ? `${on} signed in` : `${off} ${import_picocolors40.default.dim(`not signed in ${DOT3} run Setup`)}`
67079
+ ctx.sessionExpired ? `${off} ${import_picocolors41.default.yellow("session expired")} ${import_picocolors41.default.dim(`${DOT3} run Log in`)}` : ctx.signedIn ? `${on} signed in` : `${off} ${import_picocolors41.default.dim(`not signed in ${DOT3} run Setup`)}`
66993
67080
  ]);
66994
67081
  const missing = new Set(ctx.setupMissing ?? []);
66995
- const warnRow = `${off} ${import_picocolors40.default.yellow("not configured")} ${import_picocolors40.default.dim(`${DOT3} run Setup`)}`;
67082
+ const warnRow = `${off} ${import_picocolors41.default.yellow("not configured")} ${import_picocolors41.default.dim(`${DOT3} run Setup`)}`;
66996
67083
  if (missing.has("MCP"))
66997
67084
  rows.push(["mcp", warnRow]);
66998
67085
  else if (ctx.deploymentName)
@@ -67004,7 +67091,7 @@ function checklistRows(ctx, width) {
67004
67091
  if (ctx.repoAgentsMd) {
67005
67092
  rows.push([
67006
67093
  "repo",
67007
- ctx.repoAgentsMd === "current" ? `${on} AGENTS.md has the Dosu section` : `${off} ${import_picocolors40.default.yellow(ctx.repoAgentsMd === "outdated" ? "AGENTS.md Dosu section outdated" : "AGENTS.md missing the Dosu section")} ${import_picocolors40.default.dim(`${DOT3} run Setup`)}`
67094
+ ctx.repoAgentsMd === "current" ? `${on} AGENTS.md has the Dosu section` : `${off} ${import_picocolors41.default.yellow(ctx.repoAgentsMd === "outdated" ? "AGENTS.md Dosu section outdated" : "AGENTS.md missing the Dosu section")} ${import_picocolors41.default.dim(`${DOT3} run Setup`)}`
67008
67095
  ]);
67009
67096
  }
67010
67097
  if (missing.has("agents"))
@@ -67016,20 +67103,20 @@ function checklistRows(ctx, width) {
67016
67103
  if (ctx.studying) {
67017
67104
  rows.push([
67018
67105
  "sync",
67019
- `\uD83D\uDCDA ${brand("studying sessions...")} ${import_picocolors40.default.dim(`${DOT3} see activity`)}`
67106
+ `\uD83D\uDCDA ${brand("studying sessions...")} ${import_picocolors41.default.dim(`${DOT3} see activity`)}`
67020
67107
  ]);
67021
67108
  }
67022
67109
  if (ctx.update) {
67023
67110
  rows.push([
67024
67111
  "update",
67025
- `${import_picocolors40.default.yellow(`↑ ${ctx.update.version} available`)} ${import_picocolors40.default.dim(`${DOT3} ${ctx.update.hint}`)}`
67112
+ `${import_picocolors41.default.yellow(`↑ ${ctx.update.version} available`)} ${import_picocolors41.default.dim(`${DOT3} ${ctx.update.hint}`)}`
67026
67113
  ]);
67027
67114
  }
67028
67115
  const labelWidth = Math.max(...rows.map(([label]) => label.length));
67029
67116
  const valueColumn = LOGO_WIDTH + COLUMN_GAP.length + labelWidth + LABEL_GAP.length;
67030
67117
  const room = Math.max(1, width - valueColumn);
67031
67118
  const indent = " ".repeat(labelWidth + LABEL_GAP.length);
67032
- return rows.flatMap(([label, value]) => wrapValue(value, room).map((line, i) => i === 0 ? `${import_picocolors40.default.dim(label.padEnd(labelWidth))}${LABEL_GAP}${line}` : `${indent}${line}`));
67119
+ return rows.flatMap(([label, value]) => wrapValue(value, room).map((line, i) => i === 0 ? `${import_picocolors41.default.dim(label.padEnd(labelWidth))}${LABEL_GAP}${line}` : `${indent}${line}`));
67033
67120
  }
67034
67121
  function bannerWidth(columns = process.stdout.columns ?? 80) {
67035
67122
  return columns - layoutMargin(columns) - 1;
@@ -67039,7 +67126,7 @@ function renderBanner(ctx, width = bannerWidth()) {
67039
67126
  const text = [
67040
67127
  ...checklistRows(ctx, width),
67041
67128
  "",
67042
- `${brandBadge("dosu-cli")} ${import_picocolors40.default.dim(`${ctx.version} ${DOT3} ${ctx.webAppHost}`)}`
67129
+ `${brandBadge("dosu-cli")} ${import_picocolors41.default.dim(`${ctx.version} ${DOT3} ${ctx.webAppHost}`)}`
67043
67130
  ];
67044
67131
  const height = Math.max(logo.length, text.length);
67045
67132
  const combined = [];
@@ -67052,11 +67139,11 @@ function renderBanner(ctx, width = bannerWidth()) {
67052
67139
  return ["", ...combined, ""].join(`
67053
67140
  `);
67054
67141
  }
67055
- var import_picocolors40, CHECK2 = "✔", CIRCLE = "○", DOT3 = "·", LOGO_ROWS, LOGO_MARK, LOGO_WIDTH, LOGO_TONES, COLUMN_GAP = " ", LABEL_GAP = " ", LIST_SEP;
67142
+ var import_picocolors41, CHECK2 = "✔", CIRCLE = "○", DOT3 = "·", LOGO_ROWS, LOGO_MARK, LOGO_WIDTH, LOGO_TONES, COLUMN_GAP = " ", LABEL_GAP = " ", LIST_SEP;
67056
67143
  var init_banner = __esm(() => {
67057
67144
  init_styles();
67058
67145
  init_layout();
67059
- import_picocolors40 = __toESM(require_picocolors(), 1);
67146
+ import_picocolors41 = __toESM(require_picocolors(), 1);
67060
67147
  LOGO_ROWS = [
67061
67148
  [["sage", "▄▄▄▄▄▄"]],
67062
67149
  [["sage", "██ ▀▄"]],
@@ -67067,8 +67154,8 @@ var init_banner = __esm(() => {
67067
67154
  LOGO_MARK = LOGO_ROWS.map((row) => row.map(([, art]) => art).join(""));
67068
67155
  LOGO_WIDTH = Math.max(...LOGO_MARK.map((row) => row.length));
67069
67156
  LOGO_TONES = {
67070
- sage: { fg: "\x1B[38;2;180;187;145m", fallback: import_picocolors40.default.green },
67071
- moss: { fg: "\x1B[38;2;119;133;97m", fallback: (art) => import_picocolors40.default.dim(import_picocolors40.default.green(art)) }
67157
+ sage: { fg: "\x1B[38;2;180;187;145m", fallback: import_picocolors41.default.green },
67158
+ moss: { fg: "\x1B[38;2;119;133;97m", fallback: (art) => import_picocolors41.default.dim(import_picocolors41.default.green(art)) }
67072
67159
  };
67073
67160
  LIST_SEP = ` ${DOT3} `;
67074
67161
  });
@@ -67181,16 +67268,16 @@ function renderPagesFrame(model, width, selected) {
67181
67268
  const body = [];
67182
67269
  let scrollHint = "";
67183
67270
  if (model.phase === "loading") {
67184
- body.push(import_picocolors41.default.dim("Loading pages…"));
67271
+ body.push(import_picocolors42.default.dim("Loading pages…"));
67185
67272
  } else if (model.phase === "error") {
67186
- body.push(import_picocolors41.default.yellow(clip3(model.message, width)));
67273
+ body.push(import_picocolors42.default.yellow(clip3(model.message, width)));
67187
67274
  } else if (model.pages.length === 0) {
67188
- body.push(import_picocolors41.default.dim("No pages in this Library yet."));
67275
+ body.push(import_picocolors42.default.dim("No pages in this Library yet."));
67189
67276
  } else {
67190
67277
  const rows = pageRows2(model.pages, width - 2);
67191
67278
  const { start, above } = windowSelection(rows.length, selected);
67192
67279
  const visible = rows.slice(start, start + PAGES_VIEW_LINES);
67193
- body.push(...visible.map((row, i) => start + i === selected ? `${brand("▸")} ${import_picocolors41.default.bold(row)}` : ` ${import_picocolors41.default.dim(row)}`));
67280
+ body.push(...visible.map((row, i) => start + i === selected ? `${brand("▸")} ${import_picocolors42.default.bold(row)}` : ` ${import_picocolors42.default.dim(row)}`));
67194
67281
  const below = Math.max(0, Math.max(model.total, rows.length) - start - PAGES_VIEW_LINES);
67195
67282
  const parts = [];
67196
67283
  if (above > 0)
@@ -67199,14 +67286,14 @@ function renderPagesFrame(model, width, selected) {
67199
67286
  parts.push(`↓ ${below} more`);
67200
67287
  scrollHint = parts.join(" · ");
67201
67288
  }
67202
- const count = model.phase === "ready" ? ` ${import_picocolors41.default.dim(model.pages.length < model.total ? `(${model.pages.length} of ${model.total})` : `(${model.pages.length})`)}` : "";
67289
+ const count = model.phase === "ready" ? ` ${import_picocolors42.default.dim(model.pages.length < model.total ? `(${model.pages.length} of ${model.total})` : `(${model.pages.length})`)}` : "";
67203
67290
  const lines = [
67204
67291
  `${breadcrumb(["home", "pages"], width)}${count}`,
67205
67292
  "",
67206
67293
  ...body,
67207
- ...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
67294
+ ...scrollHint ? [import_picocolors42.default.dim(scrollHint)] : [],
67208
67295
  "",
67209
- import_picocolors41.default.dim("↑↓ move · enter open · esc back")
67296
+ import_picocolors42.default.dim("↑↓ move · enter open · esc back")
67210
67297
  ];
67211
67298
  return lines.join(`
67212
67299
  `);
@@ -67215,9 +67302,9 @@ function renderPageFrame(page, content, width, scroll) {
67215
67302
  const body = [];
67216
67303
  let scrollHint = "";
67217
67304
  if (content.phase === "loading") {
67218
- body.push(import_picocolors41.default.dim("Loading page…"));
67305
+ body.push(import_picocolors42.default.dim("Loading page…"));
67219
67306
  } else if (content.phase === "error") {
67220
- body.push(import_picocolors41.default.yellow(clip3(content.message, width)));
67307
+ body.push(import_picocolors42.default.yellow(clip3(content.message, width)));
67221
67308
  } else {
67222
67309
  const rows = wrapBody(content.body, width);
67223
67310
  const { visible, above, below } = windowReport(rows, scroll, PAGE_BODY_LINES);
@@ -67232,12 +67319,12 @@ function renderPageFrame(page, content, width, scroll) {
67232
67319
  const meta = `${page.type} · ${page.published ? "published" : "draft"} · updated ${page.updated_at.slice(0, 10)}`;
67233
67320
  const lines = [
67234
67321
  breadcrumb(["home", "pages", page.title], width),
67235
- import_picocolors41.default.dim(clip3(meta, width)),
67322
+ import_picocolors42.default.dim(clip3(meta, width)),
67236
67323
  "",
67237
67324
  ...body,
67238
- ...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
67325
+ ...scrollHint ? [import_picocolors42.default.dim(scrollHint)] : [],
67239
67326
  "",
67240
- import_picocolors41.default.dim("↑↓ scroll · esc back to pages")
67327
+ import_picocolors42.default.dim("↑↓ scroll · esc back to pages")
67241
67328
  ];
67242
67329
  return lines.join(`
67243
67330
  `);
@@ -67386,7 +67473,7 @@ ${CLEAR_BELOW3}`);
67386
67473
  input.on("data", onData);
67387
67474
  });
67388
67475
  }
67389
- var import_picocolors41, ESC9, HIDE_CURSOR5, SHOW_CURSOR5, CTRL_C6, KEY_UP6, KEY_DOWN6, CURSOR_HOME3, CLEAR_BELOW3, CLEAR_EOL3, PAGES_VIEW_LINES = 12, PAGE_BODY_LINES = 14, PAGES_FETCH_BATCH = 100;
67476
+ var import_picocolors42, ESC9, HIDE_CURSOR5, SHOW_CURSOR5, CTRL_C6, KEY_UP6, KEY_DOWN6, CURSOR_HOME3, CLEAR_BELOW3, CLEAR_EOL3, PAGES_VIEW_LINES = 12, PAGE_BODY_LINES = 14, PAGES_FETCH_BATCH = 100;
67390
67477
  var init_pages_view = __esm(() => {
67391
67478
  init_trpc();
67392
67479
  init_config();
@@ -67396,7 +67483,7 @@ var init_pages_view = __esm(() => {
67396
67483
  init_analytics_view();
67397
67484
  init_layout();
67398
67485
  init_menu();
67399
- import_picocolors41 = __toESM(require_picocolors(), 1);
67486
+ import_picocolors42 = __toESM(require_picocolors(), 1);
67400
67487
  ESC9 = String.fromCharCode(27);
67401
67488
  HIDE_CURSOR5 = `${ESC9}[?25l`;
67402
67489
  SHOW_CURSOR5 = `${ESC9}[?25h`;
@@ -67509,7 +67596,7 @@ function isSetUp(cfg) {
67509
67596
  }
67510
67597
  function setupHint(cfg) {
67511
67598
  const started = Boolean(cfg.active_account?.target);
67512
- return import_picocolors42.default.yellow(started ? `incomplete · missing ${missingSetupSteps(cfg).join(" + ")}` : "not set up yet");
67599
+ return import_picocolors43.default.yellow(started ? `incomplete · missing ${missingSetupSteps(cfg).join(" + ")}` : "not set up yet");
67513
67600
  }
67514
67601
  function isStudying() {
67515
67602
  try {
@@ -67754,7 +67841,7 @@ function handleLogout(cfg) {
67754
67841
  saveConfig(cfg);
67755
67842
  log2.success("Credentials cleared.");
67756
67843
  }
67757
- var import_picocolors42, ESC10, CLEAR_SCREEN;
67844
+ var import_picocolors43, ESC10, CLEAR_SCREEN;
67758
67845
  var init_tui = __esm(() => {
67759
67846
  init_client();
67760
67847
  init_config();
@@ -67778,7 +67865,7 @@ var init_tui = __esm(() => {
67778
67865
  init_menu();
67779
67866
  init_pages_view();
67780
67867
  init_prompts();
67781
- import_picocolors42 = __toESM(require_picocolors(), 1);
67868
+ import_picocolors43 = __toESM(require_picocolors(), 1);
67782
67869
  ESC10 = String.fromCharCode(27);
67783
67870
  CLEAR_SCREEN = `${ESC10}[2J${ESC10}[H`;
67784
67871
  });
@@ -68881,11 +68968,20 @@ async function execute() {
68881
68968
  try {
68882
68969
  await program.parseAsync(process.argv);
68883
68970
  } catch (err) {
68971
+ printFatalError2(err);
68972
+ logFatalError(err);
68884
68973
  if (telemetry)
68885
68974
  await finishTelemetry(() => telemetry.fail(err));
68886
- throw err;
68975
+ process.exit(1);
68887
68976
  }
68888
68977
  }
68978
+ function logFatalError(err) {
68979
+ try {
68980
+ const message = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
68981
+ const diagnostics = fatalErrorDiagnostics2(err);
68982
+ logger.error("cli", diagnostics ? `${message} (${diagnostics})` : message);
68983
+ } catch {}
68984
+ }
68889
68985
  function processCommandTelemetry() {
68890
68986
  try {
68891
68987
  const settings = loadTelemetrySettings();
@@ -68934,8 +69030,63 @@ var init_cli = __esm(() => {
68934
69030
  init_skill_update_check();
68935
69031
  init_update_check();
68936
69032
  init_errors();
69033
+ init_fatal_error();
68937
69034
  });
68938
69035
 
69036
+ // src/cli/fatal-error.ts
69037
+ init_command_error();
69038
+ var import_picocolors = __toESM(require_picocolors(), 1);
69039
+ var REQUEST_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9:._-]{0,127}$/;
69040
+ function read(value, key) {
69041
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
69042
+ return;
69043
+ }
69044
+ try {
69045
+ return Reflect.get(value, key);
69046
+ } catch {
69047
+ return;
69048
+ }
69049
+ }
69050
+ function tokenOf(data, key) {
69051
+ const value = read(data, key);
69052
+ if (typeof value !== "string")
69053
+ return;
69054
+ const trimmed = value.trim();
69055
+ return REQUEST_ID_PATTERN.test(trimmed) ? trimmed : undefined;
69056
+ }
69057
+ function statusOf(data) {
69058
+ const value = read(data, "httpStatus");
69059
+ return typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599 ? value : undefined;
69060
+ }
69061
+ function fatalErrorDiagnostics(err) {
69062
+ const data = read(err, "data");
69063
+ if (!data)
69064
+ return;
69065
+ const code = tokenOf(data, "code");
69066
+ const path = tokenOf(data, "path");
69067
+ const status = statusOf(data);
69068
+ const requestId = tokenOf(data, "requestId");
69069
+ const parts = [
69070
+ code && `code=${code}`,
69071
+ path && `path=${path}`,
69072
+ status && `status=${status}`,
69073
+ requestId && `request_id=${requestId}`
69074
+ ].filter(Boolean);
69075
+ return parts.length > 0 ? parts.join(" ") : undefined;
69076
+ }
69077
+ function printFatalError(err) {
69078
+ if (isCommandError(err)) {
69079
+ console.error(import_picocolors.default.red(err.message));
69080
+ for (const line of err.details)
69081
+ console.error(import_picocolors.default.dim(line));
69082
+ return;
69083
+ }
69084
+ console.error(read(err, "message") ?? err);
69085
+ const diagnostics = fatalErrorDiagnostics(err);
69086
+ if (diagnostics)
69087
+ console.error(diagnostics);
69088
+ }
69089
+
68939
69090
  // src/statusline/argv.ts
68940
69091
  var RENDER_ARGV = ["knowledge", "statusline", "render"];
68941
69092
  function isStatuslineRenderArgv(argv) {
@@ -68954,17 +69105,8 @@ async function main() {
68954
69105
  await execute();
68955
69106
  }
68956
69107
  main().catch((err) => {
68957
- console.error(err.message ?? err);
68958
- const data = err?.data;
68959
- if (data && (data.code || data.path || data.httpStatus)) {
68960
- const parts = [
68961
- data.code && `code=${data.code}`,
68962
- data.path && `path=${data.path}`,
68963
- data.httpStatus && `status=${data.httpStatus}`
68964
- ].filter(Boolean);
68965
- console.error(parts.join(" "));
68966
- }
69108
+ printFatalError(err);
68967
69109
  process.exit(1);
68968
69110
  });
68969
69111
 
68970
- //# debugId=5d3e9365-4283-2b42-6475-6e2164756e21
69112
+ //# debugId=152ccbaa-13cc-83fc-6475-6e2164756e21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.67.0",
3
+ "version": "0.67.1",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Set up Dosu MCP for AI tools and work with Dosu Libraries, docs, and reviews",
6
6
  "license": "MIT",