@dosu/cli 0.59.0 → 0.60.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 (3) hide show
  1. package/README.md +6 -4
  2. package/bin/dosu.js +165 -75
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -206,10 +206,12 @@ installation history is never aliased to an account. Setup-funnel events are lin
206
206
  and may include documented coarse setup choices. `DO_NOT_TRACK=1` and
207
207
  `DOSU_TELEMETRY_DISABLED=1` disable all telemetry for the process. Dosu never collects
208
208
  prompts, raw command lines, free-form argument or option values, user source code, file contents,
209
- local paths, raw environment-variable names or values, credentials, raw error messages, or
210
- `debug.log`. See
211
- [Telemetry and privacy](docs/telemetry.md) for the exact event fields, destinations, retention, and
212
- controls.
209
+ local paths, credentials, raw error messages, or `debug.log`. Environment-variable names and values
210
+ are not collected, with one exception: when a managed Claude Code settings conflict prevents a
211
+ study run, Dosu reports the allowlisted public Claude Code setting/variable names that caused the
212
+ conflict (never their values) to help diagnose why knowledge sync fails due to settings conflicts.
213
+ See [Telemetry and privacy](docs/telemetry.md) for the exact event fields, destinations, retention,
214
+ and controls.
213
215
 
214
216
  ## Configuration
215
217
 
package/bin/dosu.js CHANGED
@@ -1083,7 +1083,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
1083
1083
  function getVersionString() {
1084
1084
  return `v${VERSION}`;
1085
1085
  }
1086
- var VERSION = "0.59.0", INSTALL_CHANNEL = "npm";
1086
+ var VERSION = "0.60.1", INSTALL_CHANNEL = "npm";
1087
1087
 
1088
1088
  // src/debug/logger.ts
1089
1089
  import {
@@ -13741,12 +13741,70 @@ var init_sync = __esm(() => {
13741
13741
  init_watermark();
13742
13742
  });
13743
13743
 
13744
+ // src/learner/conflicts.ts
13745
+ import { existsSync as existsSync13, readFileSync as readFileSync15 } from "node:fs";
13746
+ function managedSettingsPaths(platform = process.platform) {
13747
+ switch (platform) {
13748
+ case "darwin":
13749
+ return ["/Library/Application Support/ClaudeCode/managed-settings.json"];
13750
+ case "win32":
13751
+ return ["C:\\ProgramData\\ClaudeCode\\managed-settings.json"];
13752
+ default:
13753
+ return ["/etc/claude-code/managed-settings.json"];
13754
+ }
13755
+ }
13756
+ function conflictingKeysIn(settings) {
13757
+ const keys = [];
13758
+ for (const key of CONFLICTING_KEYS) {
13759
+ if (key in settings)
13760
+ keys.push(key);
13761
+ }
13762
+ const env = settings.env;
13763
+ if (typeof env === "object" && env !== null && !Array.isArray(env)) {
13764
+ for (const name of Object.keys(env)) {
13765
+ if (CONFLICTING_ENV_PREFIXES.some((p) => name.startsWith(p)))
13766
+ keys.push(`env.${name}`);
13767
+ }
13768
+ }
13769
+ return keys;
13770
+ }
13771
+ function detectSettingsConflicts(paths = managedSettingsPaths()) {
13772
+ const conflicts = [];
13773
+ for (const file of paths) {
13774
+ if (!existsSync13(file))
13775
+ continue;
13776
+ let settings;
13777
+ try {
13778
+ settings = JSON.parse(readFileSync15(file, "utf8"));
13779
+ } catch {
13780
+ conflicts.push({ file, keys: [UNREADABLE_SETTINGS_KEY] });
13781
+ continue;
13782
+ }
13783
+ if (typeof settings !== "object" || settings === null)
13784
+ continue;
13785
+ const keys = conflictingKeysIn(settings);
13786
+ if (keys.length > 0)
13787
+ conflicts.push({ file, keys });
13788
+ }
13789
+ return conflicts;
13790
+ }
13791
+ var CONFLICTING_KEYS, CONFLICTING_ENV_PREFIXES, UNREADABLE_SETTINGS_KEY = "<unreadable or invalid JSON>";
13792
+ var init_conflicts = __esm(() => {
13793
+ CONFLICTING_KEYS = [
13794
+ "apiKeyHelper",
13795
+ "forceLoginMethod",
13796
+ "awsAuthRefresh",
13797
+ "awsCredentialExport"
13798
+ ];
13799
+ CONFLICTING_ENV_PREFIXES = ["ANTHROPIC_", "CLAUDE_CODE_", "AWS_"];
13800
+ });
13801
+
13744
13802
  // src/telemetry/debug-id.ts
13745
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "ecb91fd5-693a-ffc0-6475-6e2164756e21";
13803
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "9d93d312-f9af-7e47-6475-6e2164756e21";
13746
13804
 
13747
13805
  // src/telemetry/telemetry.ts
13748
13806
  import { randomUUID as randomUUID2 } from "node:crypto";
13749
- import { existsSync as existsSync13 } from "node:fs";
13807
+ import { existsSync as existsSync14 } from "node:fs";
13750
13808
  import { request as httpRequest2 } from "node:http";
13751
13809
  import { request as httpsRequest } from "node:https";
13752
13810
  import { isAbsolute, relative, resolve as resolve2, sep } from "node:path";
@@ -13884,7 +13942,7 @@ function parseOwnedStackLine(originalLine, packageRoot) {
13884
13942
  return;
13885
13943
  }
13886
13944
  try {
13887
- if (!existsSync13(resolvedPath))
13945
+ if (!existsSync14(resolvedPath))
13888
13946
  return;
13889
13947
  } catch {
13890
13948
  return;
@@ -13970,6 +14028,29 @@ function allowlisted(value, allowed) {
13970
14028
  function matching(value, pattern) {
13971
14029
  return typeof value === "string" && pattern.test(value) ? value : undefined;
13972
14030
  }
14031
+ function conflictKeysFacet(value) {
14032
+ if (!Array.isArray(value))
14033
+ return;
14034
+ const keys = new Set;
14035
+ for (const raw of value) {
14036
+ if (typeof raw !== "string")
14037
+ continue;
14038
+ if (SETTINGS_CONFLICT_KEYS.has(raw))
14039
+ keys.add(raw);
14040
+ else if (raw === UNREADABLE_SETTINGS_KEY)
14041
+ keys.add("unreadable");
14042
+ else
14043
+ keys.add(SETTINGS_CONFLICT_FAMILIES.find(([p]) => raw.startsWith(p))?.[1] ?? "other");
14044
+ }
14045
+ let joined = "";
14046
+ for (const key of [...keys].sort()) {
14047
+ const next = joined ? `${joined},${key}` : key;
14048
+ if (next.length > MAX_CONFLICT_KEYS_LENGTH)
14049
+ break;
14050
+ joined = next;
14051
+ }
14052
+ return joined || undefined;
14053
+ }
13973
14054
  function sanitizeFacets(facets) {
13974
14055
  if (!facets || typeof facets !== "object")
13975
14056
  return {};
@@ -13977,6 +14058,7 @@ function sanitizeFacets(facets) {
13977
14058
  const status = allowlisted(facets.sync_status, SYNC_STATUSES);
13978
14059
  const learner = allowlisted(facets.learner_outcome, LEARNER_OUTCOMES);
13979
14060
  const gatewayReason = allowlisted(facets.gateway_reason, GATEWAY_REASONS);
14061
+ const conflictKeys = conflictKeysFacet(facets.settings_conflict_keys);
13980
14062
  const claudeSource = allowlisted(facets.claude_code_source, CLAUDE_CODE_SOURCES);
13981
14063
  const claudeVersion = matching(facets.claude_code_version, CLAUDE_CODE_VERSION_PATTERN);
13982
14064
  const model = matching(facets.learner_model, LEARNER_MODEL_PATTERN);
@@ -13988,6 +14070,7 @@ function sanitizeFacets(facets) {
13988
14070
  ...facets.notes_written !== undefined ? { notes_written: countBucket(facets.notes_written) } : {},
13989
14071
  ...learner ? { learner_outcome: learner } : {},
13990
14072
  ...gatewayReason ? { gateway_reason: gatewayReason } : {},
14073
+ ...conflictKeys ? { settings_conflict_keys: conflictKeys } : {},
13991
14074
  ...claudeSource ? { claude_code_source: claudeSource } : {},
13992
14075
  ...claudeVersion ? { claude_code_version: claudeVersion } : {},
13993
14076
  ...model ? { learner_model: model } : {},
@@ -14115,7 +14198,8 @@ function exceptionSummary(command, error, facets) {
14115
14198
  const outcome = facets.learner_outcome ?? facets.sync_status;
14116
14199
  if (!outcome)
14117
14200
  return error.code ?? error.type;
14118
- return `${command}: ${outcome}${facets.gateway_reason ? ` (${facets.gateway_reason})` : ""}`;
14201
+ const detail = facets.gateway_reason ?? facets.settings_conflict_keys;
14202
+ return `${command}: ${outcome}${detail ? ` (${detail})` : ""}`;
14119
14203
  }
14120
14204
  function buildSentryEnvelope(input) {
14121
14205
  const parsedDsn = parseSentryDsn(input.dsn);
@@ -14517,8 +14601,9 @@ function createCommandTelemetry(settings, dependencies = {}) {
14517
14601
  function shouldSendToSentry(error) {
14518
14602
  return !["SESSION_EXPIRED", "SESSION_PERSISTENCE_ERROR"].includes(error.code ?? "");
14519
14603
  }
14520
- 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, CLAUDE_CODE_VERSION_PATTERN, LEARNER_MODEL_PATTERN, BACKFILL_OFFERS, SENTRY_FACET_TAGS, pendingFacets;
14604
+ 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;
14521
14605
  var init_telemetry = __esm(() => {
14606
+ init_conflicts();
14522
14607
  MAX_RESPONSE_BYTES = 1024 * 1024;
14523
14608
  CLI_PACKAGE_ROOT = detectCliPackageRoot();
14524
14609
  SAFE_ERROR_TYPES = new Set([
@@ -14623,6 +14708,11 @@ var init_telemetry = __esm(() => {
14623
14708
  "quota_exceeded",
14624
14709
  "gateway_rejected",
14625
14710
  "claude_code_missing",
14711
+ "max_turns",
14712
+ "run_failed",
14713
+ "no_result",
14714
+ "timed_out",
14715
+ "sdk_error",
14626
14716
  "error"
14627
14717
  ]);
14628
14718
  GATEWAY_REASONS = new Set([
@@ -14635,6 +14725,58 @@ var init_telemetry = __esm(() => {
14635
14725
  "other"
14636
14726
  ]);
14637
14727
  CLAUDE_CODE_SOURCES = new Set(["sdk", "system", "missing"]);
14728
+ SETTINGS_CONFLICT_KEYS = new Set([
14729
+ "apiKeyHelper",
14730
+ "forceLoginMethod",
14731
+ "awsAuthRefresh",
14732
+ "awsCredentialExport",
14733
+ "env.ANTHROPIC_API_KEY",
14734
+ "env.ANTHROPIC_AUTH_TOKEN",
14735
+ "env.ANTHROPIC_BASE_URL",
14736
+ "env.ANTHROPIC_CUSTOM_HEADERS",
14737
+ "env.ANTHROPIC_MODEL",
14738
+ "env.ANTHROPIC_SMALL_FAST_MODEL",
14739
+ "env.ANTHROPIC_DEFAULT_OPUS_MODEL",
14740
+ "env.ANTHROPIC_DEFAULT_SONNET_MODEL",
14741
+ "env.ANTHROPIC_DEFAULT_HAIKU_MODEL",
14742
+ "env.ANTHROPIC_BEDROCK_BASE_URL",
14743
+ "env.ANTHROPIC_VERTEX_BASE_URL",
14744
+ "env.ANTHROPIC_VERTEX_PROJECT_ID",
14745
+ "env.ANTHROPIC_FOUNDRY_BASE_URL",
14746
+ "env.ANTHROPIC_FOUNDRY_API_KEY",
14747
+ "env.ANTHROPIC_AWS_BASE_URL",
14748
+ "env.ANTHROPIC_BEDROCK_MANTLE_BASE_URL",
14749
+ "env.ANTHROPIC_AWS_API_KEY",
14750
+ "env.ANTHROPIC_PROFILE",
14751
+ "env.ANTHROPIC_ENVIRONMENT_KEY",
14752
+ "env.ANTHROPIC_IDENTITY_TOKEN",
14753
+ "env.ANTHROPIC_FEDERATION_RULE_ID",
14754
+ "env.ANTHROPIC_SERVICE_ACCOUNT_ID",
14755
+ "env.CLAUDE_CODE_USE_BEDROCK",
14756
+ "env.CLAUDE_CODE_USE_VERTEX",
14757
+ "env.CLAUDE_CODE_USE_FOUNDRY",
14758
+ "env.CLAUDE_CODE_USE_MANTLE",
14759
+ "env.CLAUDE_CODE_USE_ANTHROPIC_AWS",
14760
+ "env.CLAUDE_CODE_OAUTH_TOKEN",
14761
+ "env.CLAUDE_CODE_API_BASE_URL",
14762
+ "env.CLAUDE_CODE_SKIP_BEDROCK_AUTH",
14763
+ "env.CLAUDE_CODE_SKIP_VERTEX_AUTH",
14764
+ "env.CLAUDE_CODE_API_KEY_HELPER_TTL_MS",
14765
+ "env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC",
14766
+ "env.CLAUDE_CODE_ENABLE_TELEMETRY",
14767
+ "env.CLAUDE_CODE_MAX_OUTPUT_TOKENS",
14768
+ "env.AWS_REGION",
14769
+ "env.AWS_PROFILE",
14770
+ "env.AWS_BEARER_TOKEN_BEDROCK",
14771
+ "env.AWS_ACCESS_KEY_ID",
14772
+ "env.AWS_SECRET_ACCESS_KEY",
14773
+ "env.AWS_SESSION_TOKEN"
14774
+ ]);
14775
+ SETTINGS_CONFLICT_FAMILIES = [
14776
+ ["env.ANTHROPIC_", "env.ANTHROPIC_other"],
14777
+ ["env.CLAUDE_CODE_", "env.CLAUDE_CODE_other"],
14778
+ ["env.AWS_", "env.AWS_other"]
14779
+ ];
14638
14780
  CLAUDE_CODE_VERSION_PATTERN = /^\d{1,4}\.\d{1,4}\.\d{1,6}(?:-[0-9A-Za-z]{1,16}(?:\.[0-9A-Za-z]{1,16}){0,3})?$/;
14639
14781
  LEARNER_MODEL_PATTERN = /^claude-[a-z0-9.-]{1,56}$/;
14640
14782
  BACKFILL_OFFERS = new Set([
@@ -14649,6 +14791,7 @@ var init_telemetry = __esm(() => {
14649
14791
  "sync_status",
14650
14792
  "learner_outcome",
14651
14793
  "gateway_reason",
14794
+ "settings_conflict_keys",
14652
14795
  "claude_code_source",
14653
14796
  "claude_code_version",
14654
14797
  "learner_model"
@@ -14682,7 +14825,7 @@ var init_agent_select = __esm(() => {
14682
14825
  });
14683
14826
 
14684
14827
  // src/incognito/agents.ts
14685
- import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync15, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "node:fs";
14828
+ import { existsSync as existsSync15, mkdirSync as mkdirSync9, readFileSync as readFileSync16, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "node:fs";
14686
14829
  import { homedir as homedir4 } from "node:os";
14687
14830
  import { dirname as dirname5, join as join13 } from "node:path";
14688
14831
  function withFrontmatter(body) {
@@ -14707,18 +14850,18 @@ function fileAgent(options) {
14707
14850
  commandPath,
14708
14851
  isEnabled: () => {
14709
14852
  const path = commandPath();
14710
- if (!existsSync14(path))
14853
+ if (!existsSync15(path))
14711
14854
  return false;
14712
14855
  try {
14713
- return readFileSync15(path, "utf-8").includes(INCOGNITO_MARKER);
14856
+ return readFileSync16(path, "utf-8").includes(INCOGNITO_MARKER);
14714
14857
  } catch {
14715
14858
  return false;
14716
14859
  }
14717
14860
  },
14718
14861
  enable: () => {
14719
14862
  const path = commandPath();
14720
- if (existsSync14(path)) {
14721
- if (readFileSync15(path, "utf-8") === content)
14863
+ if (existsSync15(path)) {
14864
+ if (readFileSync16(path, "utf-8") === content)
14722
14865
  return "unchanged";
14723
14866
  writeFileSync10(path, content, "utf-8");
14724
14867
  return "updated";
@@ -14729,7 +14872,7 @@ function fileAgent(options) {
14729
14872
  },
14730
14873
  disable: () => {
14731
14874
  const path = commandPath();
14732
- if (!existsSync14(path))
14875
+ if (!existsSync15(path))
14733
14876
  return "not_found";
14734
14877
  unlinkSync2(path);
14735
14878
  return "removed";
@@ -15171,64 +15314,6 @@ function createRunConfigDir() {
15171
15314
  }
15172
15315
  var init_config_dir = () => {};
15173
15316
 
15174
- // src/learner/conflicts.ts
15175
- import { existsSync as existsSync15, readFileSync as readFileSync16 } from "node:fs";
15176
- function managedSettingsPaths(platform = process.platform) {
15177
- switch (platform) {
15178
- case "darwin":
15179
- return ["/Library/Application Support/ClaudeCode/managed-settings.json"];
15180
- case "win32":
15181
- return ["C:\\ProgramData\\ClaudeCode\\managed-settings.json"];
15182
- default:
15183
- return ["/etc/claude-code/managed-settings.json"];
15184
- }
15185
- }
15186
- function conflictingKeysIn(settings) {
15187
- const keys = [];
15188
- for (const key of CONFLICTING_KEYS) {
15189
- if (key in settings)
15190
- keys.push(key);
15191
- }
15192
- const env = settings.env;
15193
- if (typeof env === "object" && env !== null && !Array.isArray(env)) {
15194
- for (const name of Object.keys(env)) {
15195
- if (CONFLICTING_ENV_PREFIXES.some((p) => name.startsWith(p)))
15196
- keys.push(`env.${name}`);
15197
- }
15198
- }
15199
- return keys;
15200
- }
15201
- function detectSettingsConflicts(paths = managedSettingsPaths()) {
15202
- const conflicts = [];
15203
- for (const file of paths) {
15204
- if (!existsSync15(file))
15205
- continue;
15206
- let settings;
15207
- try {
15208
- settings = JSON.parse(readFileSync16(file, "utf8"));
15209
- } catch {
15210
- conflicts.push({ file, keys: ["<unreadable or invalid JSON>"] });
15211
- continue;
15212
- }
15213
- if (typeof settings !== "object" || settings === null)
15214
- continue;
15215
- const keys = conflictingKeysIn(settings);
15216
- if (keys.length > 0)
15217
- conflicts.push({ file, keys });
15218
- }
15219
- return conflicts;
15220
- }
15221
- var CONFLICTING_KEYS, CONFLICTING_ENV_PREFIXES;
15222
- var init_conflicts = __esm(() => {
15223
- CONFLICTING_KEYS = [
15224
- "apiKeyHelper",
15225
- "forceLoginMethod",
15226
- "awsAuthRefresh",
15227
- "awsCredentialExport"
15228
- ];
15229
- CONFLICTING_ENV_PREFIXES = ["ANTHROPIC_", "CLAUDE_CODE_", "AWS_"];
15230
- });
15231
-
15232
15317
  // src/learner/env.ts
15233
15318
  function isStripped(name) {
15234
15319
  return STRIPPED_NAMES.has(name) || STRIPPED_PREFIXES.some((p) => name.startsWith(p));
@@ -58365,7 +58450,8 @@ async function runLearner(options) {
58365
58450
  outcome: "settings_conflict",
58366
58451
  notesWritten: 0,
58367
58452
  turns: 0,
58368
- message: `Refusing to run: conflicting Claude Code settings would override the study run's auth (${detail})`
58453
+ message: `Refusing to run: conflicting Claude Code settings would override the study run's auth (${detail})`,
58454
+ conflictKeys: conflicts.flatMap((c) => c.keys)
58369
58455
  };
58370
58456
  }
58371
58457
  const gatewayURL = options.gatewayURL ?? getLlmGatewayURL();
@@ -58522,13 +58608,16 @@ async function runLearner(options) {
58522
58608
  }
58523
58609
  if (message.subtype !== "success" || message.is_error) {
58524
58610
  logger.debug("learner", `run ${runID} failed: ${text}`);
58525
- return finish("error", "Study run failed; see debug log for details.");
58611
+ if (message.subtype === "error_max_turns") {
58612
+ return finish("max_turns", "Study run hit its turn limit before finishing.");
58613
+ }
58614
+ return finish("run_failed", "Study run failed; see debug log for details.");
58526
58615
  }
58527
58616
  logger.debug("learner", `run ${runID} completed: ${turns} turns, ${notesWritten} suggested pages`);
58528
58617
  return finish("completed", text);
58529
58618
  }
58530
58619
  }
58531
- return finish("error", "Study run ended without a result.");
58620
+ return finish("no_result", "Study run ended without a result.");
58532
58621
  } catch (error) {
58533
58622
  const text = error instanceof Error ? error.message : String(error);
58534
58623
  const gatewayError = classifyGatewayError(text) ?? classifyGatewayRejection(text);
@@ -58536,7 +58625,7 @@ async function runLearner(options) {
58536
58625
  return finish(gatewayError.outcome, gatewayError.message, gatewayError.reason);
58537
58626
  }
58538
58627
  logger.debug("learner", `run ${runID} threw: ${text}`);
58539
- return finish("error", abort.signal.aborted ? "Study run timed out and was aborted." : "Study run failed; see debug log for details.");
58628
+ return abort.signal.aborted ? finish("timed_out", "Study run timed out and was aborted.") : finish("sdk_error", "Study run failed; see debug log for details.");
58540
58629
  } finally {
58541
58630
  clearTimeout(timer);
58542
58631
  configDir.cleanup();
@@ -58803,6 +58892,7 @@ function learnerFacets(learner) {
58803
58892
  return {
58804
58893
  learner_outcome: learner.outcome,
58805
58894
  ...learner.gatewayReason ? { gateway_reason: learner.gatewayReason } : {},
58895
+ ...learner.conflictKeys ? { settings_conflict_keys: learner.conflictKeys } : {},
58806
58896
  ...learner.claudeCodeSource ? { claude_code_source: learner.claudeCodeSource } : {},
58807
58897
  ...learner.claudeCodeVersion ? { claude_code_version: learner.claudeCodeVersion } : {},
58808
58898
  ...learner.model ? { learner_model: learner.model } : {}
@@ -67761,4 +67851,4 @@ main().catch((err) => {
67761
67851
  process.exit(1);
67762
67852
  });
67763
67853
 
67764
- //# debugId=ecb91fd5-693a-ffc0-6475-6e2164756e21
67854
+ //# debugId=9d93d312-f9af-7e47-6475-6e2164756e21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.59.0",
3
+ "version": "0.60.1",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Manage MCP servers for AI tools",
6
6
  "license": "MIT",