cascade-ai 0.12.3 → 0.12.5

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/dist/cli.cjs CHANGED
@@ -6,7 +6,7 @@ var genai = require('@google/genai');
6
6
  var ink = require('ink');
7
7
  var commander = require('commander');
8
8
  var React2 = require('react');
9
- var chalk11 = require('chalk');
9
+ var chalk9 = require('chalk');
10
10
  var dotenv = require('dotenv');
11
11
  var fs21 = require('fs');
12
12
  var path23 = require('path');
@@ -64,7 +64,7 @@ function _interopNamespace(e) {
64
64
  var Anthropic__default = /*#__PURE__*/_interopDefault(Anthropic);
65
65
  var OpenAI__default = /*#__PURE__*/_interopDefault(OpenAI);
66
66
  var React2__default = /*#__PURE__*/_interopDefault(React2);
67
- var chalk11__default = /*#__PURE__*/_interopDefault(chalk11);
67
+ var chalk9__default = /*#__PURE__*/_interopDefault(chalk9);
68
68
  var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
69
69
  var fs21__default = /*#__PURE__*/_interopDefault(fs21);
70
70
  var path23__default = /*#__PURE__*/_interopDefault(path23);
@@ -87,50 +87,21 @@ var parser__default = /*#__PURE__*/_interopDefault(parser);
87
87
  var jwt__default = /*#__PURE__*/_interopDefault(jwt);
88
88
 
89
89
  // Cascade AI — Multi-tier AI Orchestration System
90
- var __create = Object.create;
91
90
  var __defProp = Object.defineProperty;
92
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
93
91
  var __getOwnPropNames = Object.getOwnPropertyNames;
94
- var __getProtoOf = Object.getPrototypeOf;
95
- var __hasOwnProp = Object.prototype.hasOwnProperty;
96
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
97
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
98
- }) : x)(function(x) {
99
- if (typeof require !== "undefined") return require.apply(this, arguments);
100
- throw Error('Dynamic require of "' + x + '" is not supported');
101
- });
102
92
  var __esm = (fn, res) => function __init() {
103
93
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
104
94
  };
105
- var __commonJS = (cb, mod) => function __require2() {
106
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
107
- };
108
95
  var __export = (target, all) => {
109
96
  for (var name in all)
110
97
  __defProp(target, name, { get: all[name], enumerable: true });
111
98
  };
112
- var __copyProps = (to, from, except, desc) => {
113
- if (from && typeof from === "object" || typeof from === "function") {
114
- for (let key of __getOwnPropNames(from))
115
- if (!__hasOwnProp.call(to, key) && key !== except)
116
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
117
- }
118
- return to;
119
- };
120
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
121
- // If the importer is in node compatibility mode or this is not an ESM
122
- // file that has been converted to a CommonJS file using a Babel-
123
- // compatible transform (i.e. "__esModule" has not been set), then set
124
- // "default" to the CommonJS "module.exports" for node compatibility.
125
- __defProp(target, "default", { value: mod, enumerable: true }) ,
126
- mod
127
- ));
128
99
 
129
100
  // src/constants.ts
130
101
  var CASCADE_VERSION, CASCADE_CONFIG_FILE, CASCADE_DB_FILE, CASCADE_DASHBOARD_SECRET_FILE, GLOBAL_CONFIG_DIR, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_RUNTIME_DB_FILE, DEFAULT_DASHBOARD_PORT, DEFAULT_CONTEXT_LIMIT, DEFAULT_AUTO_SUMMARIZE_AT, MODELS, T1_MODEL_PRIORITY, T2_MODEL_PRIORITY, T3_MODEL_PRIORITY, VISION_MODEL_PRIORITY, COMPLEXITY_T2_COUNT, THEME_NAMES, DEFAULT_THEME, OLLAMA_BASE_URL, LM_STUDIO_BASE_URL, AZURE_BASE_URL_TEMPLATE, TOOL_NAMES, DEFAULT_APPROVAL_REQUIRED;
131
102
  var init_constants = __esm({
132
103
  "src/constants.ts"() {
133
- CASCADE_VERSION = "0.9.6";
104
+ CASCADE_VERSION = "0.12.5";
134
105
  CASCADE_CONFIG_FILE = ".cascade/config.json";
135
106
  CASCADE_DB_FILE = ".cascade/memory.db";
136
107
  CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
@@ -446,63 +417,6 @@ var init_constants = __esm({
446
417
  }
447
418
  });
448
419
 
449
- // node_modules/keytar/build/Release/keytar.node
450
- var keytar_default;
451
- var init_keytar = __esm({
452
- "node_modules/keytar/build/Release/keytar.node"() {
453
- keytar_default = "./keytar-VMICNFEJ.node";
454
- }
455
- });
456
-
457
- // node-file:/home/runner/work/Cascade-AI/Cascade-AI/node_modules/keytar/build/Release/keytar.node
458
- var require_keytar = __commonJS({
459
- "node-file:/home/runner/work/Cascade-AI/Cascade-AI/node_modules/keytar/build/Release/keytar.node"(exports, module) {
460
- init_keytar();
461
- try {
462
- module.exports = __require(keytar_default);
463
- } catch {
464
- }
465
- }
466
- });
467
-
468
- // node_modules/keytar/lib/keytar.js
469
- var require_keytar2 = __commonJS({
470
- "node_modules/keytar/lib/keytar.js"(exports, module) {
471
- var keytar = require_keytar();
472
- function checkRequired(val, name) {
473
- if (!val || val.length <= 0) {
474
- throw new Error(name + " is required.");
475
- }
476
- }
477
- module.exports = {
478
- getPassword: function(service, account) {
479
- checkRequired(service, "Service");
480
- checkRequired(account, "Account");
481
- return keytar.getPassword(service, account);
482
- },
483
- setPassword: function(service, account, password) {
484
- checkRequired(service, "Service");
485
- checkRequired(account, "Account");
486
- checkRequired(password, "Password");
487
- return keytar.setPassword(service, account, password);
488
- },
489
- deletePassword: function(service, account) {
490
- checkRequired(service, "Service");
491
- checkRequired(account, "Account");
492
- return keytar.deletePassword(service, account);
493
- },
494
- findPassword: function(service) {
495
- checkRequired(service, "Service");
496
- return keytar.findPassword(service);
497
- },
498
- findCredentials: function(service) {
499
- checkRequired(service, "Service");
500
- return keytar.findCredentials(service);
501
- }
502
- };
503
- }
504
- });
505
-
506
420
  // src/providers/base.ts
507
421
  var BaseProvider;
508
422
  var init_base = __esm({
@@ -1512,7 +1426,7 @@ var PBKDF2_ITERATIONS = 1e5;
1512
1426
  var KEYTAR_SERVICE = "cascade-ai";
1513
1427
  async function loadKeytar() {
1514
1428
  try {
1515
- const mod = await Promise.resolve().then(() => __toESM(require_keytar2(), 1));
1429
+ const mod = await import('keytar');
1516
1430
  const candidate = mod.default ?? mod;
1517
1431
  if (typeof candidate.getPassword !== "function") return null;
1518
1432
  return candidate;
@@ -3236,15 +3150,15 @@ function SafeTextInput(props) {
3236
3150
  const displayValue = mask ? mask.repeat(value.length) : value;
3237
3151
  let rendered;
3238
3152
  if (displayValue.length === 0) {
3239
- rendered = showCursor && focus ? placeholder.length > 0 ? chalk11__default.default.inverse(placeholder[0]) + chalk11__default.default.grey(placeholder.slice(1)) : chalk11__default.default.inverse(" ") : placeholder.length > 0 ? chalk11__default.default.grey(placeholder) : "";
3153
+ rendered = showCursor && focus ? placeholder.length > 0 ? chalk9__default.default.inverse(placeholder[0]) + chalk9__default.default.grey(placeholder.slice(1)) : chalk9__default.default.inverse(" ") : placeholder.length > 0 ? chalk9__default.default.grey(placeholder) : "";
3240
3154
  } else if (!showCursor || !focus) {
3241
3155
  rendered = displayValue;
3242
3156
  } else {
3243
3157
  let out = "";
3244
3158
  for (let i = 0; i < displayValue.length; i++) {
3245
- out += i === cursorOffset ? chalk11__default.default.inverse(displayValue[i]) : displayValue[i];
3159
+ out += i === cursorOffset ? chalk9__default.default.inverse(displayValue[i]) : displayValue[i];
3246
3160
  }
3247
- if (cursorOffset >= displayValue.length) out += chalk11__default.default.inverse(" ");
3161
+ if (cursorOffset >= displayValue.length) out += chalk9__default.default.inverse(" ");
3248
3162
  rendered = out;
3249
3163
  }
3250
3164
  return /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: rendered });
@@ -4094,7 +4008,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
4094
4008
  }
4095
4009
  for (const tier of ["T1", "T2", "T3"]) {
4096
4010
  const override = tier === "T1" ? config.models.t1 : tier === "T2" ? config.models.t2 : config.models.t3;
4097
- if (!override) continue;
4011
+ if (!override || override === "auto") continue;
4098
4012
  const model = this.selector.selectForTier(tier, override);
4099
4013
  if (!model) {
4100
4014
  const knownProviders = ["anthropic", "openai", "gemini", "azure", "openai-compatible", "ollama"];
@@ -11497,7 +11411,7 @@ function StatusBarInternal({
11497
11411
  const savedStr = savedUsd > 0 ? ` \xB7 saved $${savedUsd.toFixed(4)}` : "";
11498
11412
  const rightStr = ` ${formatTokens(tokens)} \xB7 $${costUsd.toFixed(4)}${savedStr} ${isExecuting ? "\u26A1" : "\xB7"} `;
11499
11413
  const gap = Math.max(0, width - leftStr.length - rightStr.length);
11500
- const line = chalk11__default.default.bgHex(theme.colors.primary).hex(theme.colors.background)(chalk11__default.default.bold(leftStr) + " ".repeat(gap) + rightStr);
11414
+ const line = chalk9__default.default.bgHex(theme.colors.primary).hex(theme.colors.background)(chalk9__default.default.bold(leftStr) + " ".repeat(gap) + rightStr);
11501
11415
  return /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: line });
11502
11416
  }
11503
11417
  function formatTokens(n) {
@@ -11908,7 +11822,7 @@ function renderContent(content, theme) {
11908
11822
  i
11909
11823
  );
11910
11824
  }
11911
- const rendered = part.replace(/\*\*(.*?)\*\*/g, (_, t) => chalk11__default.default.bold(t)).replace(/`(.*?)`/g, (_, t) => chalk11__default.default.bgHex(theme.colors.border)(t));
11825
+ const rendered = part.replace(/\*\*(.*?)\*\*/g, (_, t) => chalk9__default.default.bold(t)).replace(/`(.*?)`/g, (_, t) => chalk9__default.default.bgHex(theme.colors.border)(t));
11912
11826
  return /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { wrap: "wrap", children: rendered }, i);
11913
11827
  });
11914
11828
  }
@@ -14114,20 +14028,20 @@ async function initCommand(workspacePath = process.cwd()) {
14114
14028
  const mdPath = path23__default.default.join(workspacePath, "CASCADE.md");
14115
14029
  if (!await fileExists(mdPath)) {
14116
14030
  await createDefaultCascadeMd(workspacePath);
14117
- spin.succeed(chalk11__default.default.green("Created CASCADE.md"));
14031
+ spin.succeed(chalk9__default.default.green("Created CASCADE.md"));
14118
14032
  }
14119
14033
  const ignorePath = path23__default.default.join(workspacePath, ".cascadeignore");
14120
14034
  if (!await fileExists(ignorePath)) {
14121
14035
  await createDefaultIgnoreFile(workspacePath);
14122
- spin.succeed(chalk11__default.default.green("Created .cascadeignore"));
14036
+ spin.succeed(chalk9__default.default.green("Created .cascadeignore"));
14123
14037
  }
14124
14038
  spin.stop();
14125
14039
  console.log();
14126
- console.log(chalk11__default.default.magenta(" \u25C8 Cascade AI \u2014 Project initialized"));
14040
+ console.log(chalk9__default.default.magenta(" \u25C8 Cascade AI \u2014 Project initialized"));
14127
14041
  console.log();
14128
14042
  const configPath = path23__default.default.join(workspacePath, CASCADE_CONFIG_FILE);
14129
14043
  if (await fileExists(configPath)) {
14130
- console.log(chalk11__default.default.yellow(" .cascade/config.json already exists \u2014 launching wizard to reconfigure."));
14044
+ console.log(chalk9__default.default.yellow(" .cascade/config.json already exists \u2014 launching wizard to reconfigure."));
14131
14045
  console.log();
14132
14046
  }
14133
14047
  const config = await runSetupWizard(workspacePath);
@@ -14135,10 +14049,10 @@ async function initCommand(workspacePath = process.cwd()) {
14135
14049
  await cm.load();
14136
14050
  await cm.updateConfig(config);
14137
14051
  console.log();
14138
- console.log(chalk11__default.default.green(" \u25C8 Setup complete! Run `cascade` to start."));
14052
+ console.log(chalk9__default.default.green(" \u25C8 Setup complete! Run `cascade` to start."));
14139
14053
  console.log();
14140
14054
  } catch (err) {
14141
- console.error(chalk11__default.default.red(`Init failed: ${err instanceof Error ? err.message : String(err)}`));
14055
+ console.error(chalk9__default.default.red(`Init failed: ${err instanceof Error ? err.message : String(err)}`));
14142
14056
  process.exit(1);
14143
14057
  }
14144
14058
  }
@@ -14284,7 +14198,7 @@ function maskSecret(secret) {
14284
14198
 
14285
14199
  // src/cli/commands/doctor.ts
14286
14200
  async function doctorCommand() {
14287
- console.log(chalk11__default.default.magenta("\n \u25C8 Cascade Doctor \u2014 System Diagnostics\n"));
14201
+ console.log(chalk9__default.default.magenta("\n \u25C8 Cascade Doctor \u2014 System Diagnostics\n"));
14288
14202
  const checks = [];
14289
14203
  const nodeVersion = process.versions.node;
14290
14204
  const [major] = nodeVersion.split(".").map(Number);
@@ -14348,7 +14262,7 @@ async function doctorCommand() {
14348
14262
  });
14349
14263
  let keystoreBackend = "file (AES-256-GCM)";
14350
14264
  try {
14351
- await Promise.resolve().then(() => __toESM(require_keytar2(), 1));
14265
+ await import('keytar');
14352
14266
  keystoreBackend = "keytar (OS keychain)";
14353
14267
  } catch {
14354
14268
  }
@@ -14376,22 +14290,22 @@ async function doctorCommand() {
14376
14290
  } catch {
14377
14291
  }
14378
14292
  for (const c of checks) {
14379
- const icon = c.ok ? chalk11__default.default.green(" \u2713") : chalk11__default.default.yellow(" \u25CB");
14380
- const label = c.ok ? chalk11__default.default.white(c.label) : chalk11__default.default.gray(c.label);
14381
- const detail = c.detail ? chalk11__default.default.gray(` \u2014 ${c.detail}`) : "";
14293
+ const icon = c.ok ? chalk9__default.default.green(" \u2713") : chalk9__default.default.yellow(" \u25CB");
14294
+ const label = c.ok ? chalk9__default.default.white(c.label) : chalk9__default.default.gray(c.label);
14295
+ const detail = c.detail ? chalk9__default.default.gray(` \u2014 ${c.detail}`) : "";
14382
14296
  console.log(`${icon} ${label}${detail}`);
14383
14297
  }
14384
14298
  const failures = checks.filter((c) => !c.ok);
14385
14299
  console.log();
14386
14300
  if (failures.length === 0) {
14387
- console.log(chalk11__default.default.green(" All checks passed!\n"));
14301
+ console.log(chalk9__default.default.green(" All checks passed!\n"));
14388
14302
  } else {
14389
14303
  const critical = failures.filter((c) => c.label.includes("Node") || c.label.includes("API key"));
14390
14304
  if (critical.length) {
14391
- console.log(chalk11__default.default.yellow(` ${critical.length} issue(s) need attention.
14305
+ console.log(chalk9__default.default.yellow(` ${critical.length} issue(s) need attention.
14392
14306
  `));
14393
14307
  } else {
14394
- console.log(chalk11__default.default.gray(` ${failures.length} optional item(s) not configured.
14308
+ console.log(chalk9__default.default.gray(` ${failures.length} optional item(s) not configured.
14395
14309
  `));
14396
14310
  }
14397
14311
  }
@@ -14418,14 +14332,14 @@ async function updateCommand() {
14418
14332
  const { stdout } = await execAsync2("npm show cascade-ai version", { timeout: 1e4 });
14419
14333
  const latest = stdout.trim().split("\n").filter(Boolean).pop() ?? "";
14420
14334
  if (latest === CASCADE_VERSION) {
14421
- spin.succeed(chalk11__default.default.green(`Already up to date (v${CASCADE_VERSION})`));
14335
+ spin.succeed(chalk9__default.default.green(`Already up to date (v${CASCADE_VERSION})`));
14422
14336
  return;
14423
14337
  }
14424
14338
  spin.text = `Updating cascade-ai ${CASCADE_VERSION} \u2192 ${latest}\u2026`;
14425
14339
  await execAsync2("npm install -g cascade-ai@latest", { timeout: 6e4 });
14426
- spin.succeed(chalk11__default.default.green(`Updated to v${latest}! Restart your terminal.`));
14340
+ spin.succeed(chalk9__default.default.green(`Updated to v${latest}! Restart your terminal.`));
14427
14341
  } catch (err) {
14428
- spin.fail(chalk11__default.default.red(`Update failed: ${err instanceof Error ? err.message : String(err)}`));
14342
+ spin.fail(chalk9__default.default.red(`Update failed: ${err instanceof Error ? err.message : String(err)}`));
14429
14343
  }
14430
14344
  }
14431
14345
  init_constants();
@@ -14590,6 +14504,11 @@ var DashboardSocket = class {
14590
14504
  emitToSocket(socketId, event, data) {
14591
14505
  this.io.sockets.sockets.get(socketId)?.emit(event, data);
14592
14506
  }
14507
+ onConfigGet(callback) {
14508
+ this.io.on("connection", (socket) => {
14509
+ socket.on("config:get", () => callback(socket.id));
14510
+ });
14511
+ }
14593
14512
  onCascadeRun(callback) {
14594
14513
  this.io.on("connection", (socket) => {
14595
14514
  socket.on("cascade:run", (payload) => {
@@ -14639,6 +14558,16 @@ var DashboardServer = class {
14639
14558
  this.socket.onSessionRate((sessionId, rating) => {
14640
14559
  this.activeSessions.get(sessionId)?.rateLastRun(rating);
14641
14560
  });
14561
+ this.socket.onConfigGet((socketId) => {
14562
+ this.socket.emitToSocket(socketId, "config:current", {
14563
+ models: this.config.models ?? {},
14564
+ budget: {
14565
+ maxCostPerRun: this.config.budget?.maxCostPerRunUsd,
14566
+ autoBias: this.config.autoBias
14567
+ },
14568
+ providersWithKey: (this.config.providers ?? []).filter((p) => typeof p.apiKey === "string" && p.apiKey.length > 0).map((p) => p.type)
14569
+ });
14570
+ });
14642
14571
  this.socket.onConfigUpdate((data) => {
14643
14572
  if (data.keys) {
14644
14573
  for (const [type, apiKey] of Object.entries(data.keys)) {
@@ -14649,7 +14578,11 @@ var DashboardServer = class {
14649
14578
  }
14650
14579
  }
14651
14580
  if (data.models) {
14652
- this.config.models = { ...this.config.models, ...data.models };
14581
+ const models = this.config.models;
14582
+ for (const [tier, val] of Object.entries(data.models)) {
14583
+ if (val && val !== "auto") models[tier] = val;
14584
+ else delete models[tier];
14585
+ }
14653
14586
  }
14654
14587
  if (data.budget) {
14655
14588
  if (typeof data.budget.maxCostPerRun === "number") {
@@ -14659,6 +14592,7 @@ var DashboardServer = class {
14659
14592
  this.config.autoBias = data.budget.autoBias;
14660
14593
  }
14661
14594
  }
14595
+ this.persistConfig();
14662
14596
  });
14663
14597
  this.socket.onCascadeRun(async (prompt, model, socketId) => {
14664
14598
  const sessionId = crypto.randomUUID();
@@ -14735,6 +14669,20 @@ var DashboardServer = class {
14735
14669
  getSocket() {
14736
14670
  return this.socket;
14737
14671
  }
14672
+ /**
14673
+ * Write the in-memory config back to the workspace config file so mutations
14674
+ * made over the socket (Settings → Save) persist across restarts. Best-effort:
14675
+ * a write failure is logged but never crashes the running dashboard.
14676
+ */
14677
+ persistConfig() {
14678
+ try {
14679
+ const configPath = path23__default.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
14680
+ fs21__default.default.mkdirSync(path23__default.default.dirname(configPath), { recursive: true });
14681
+ fs21__default.default.writeFileSync(configPath, JSON.stringify(this.config, null, 2), "utf-8");
14682
+ } catch (err) {
14683
+ console.warn(`[dashboard] Failed to persist config: ${err instanceof Error ? err.message : String(err)}`);
14684
+ }
14685
+ }
14738
14686
  /**
14739
14687
  * Produce a stable dashboard JWT signing secret.
14740
14688
  *
@@ -15234,10 +15182,10 @@ async function dashboardCommand(config, workspacePath = process.cwd()) {
15234
15182
  process.once("exit", onExit);
15235
15183
  try {
15236
15184
  await server.start();
15237
- spin.succeed(chalk11__default.default.green(`Dashboard running at http://localhost:${port}`));
15185
+ spin.succeed(chalk9__default.default.green(`Dashboard running at http://localhost:${port}`));
15238
15186
  server.refreshRuntime("workspace");
15239
15187
  server.refreshRuntime("global");
15240
- console.log(chalk11__default.default.gray(` Press Ctrl+C to stop
15188
+ console.log(chalk9__default.default.gray(` Press Ctrl+C to stop
15241
15189
  `));
15242
15190
  await new Promise(() => {
15243
15191
  });
@@ -15246,7 +15194,7 @@ async function dashboardCommand(config, workspacePath = process.cwd()) {
15246
15194
  await server.stop().catch(() => {
15247
15195
  });
15248
15196
  onExit();
15249
- spin.fail(chalk11__default.default.red(`Dashboard failed: ${err instanceof Error ? err.message : String(err)}`));
15197
+ spin.fail(chalk9__default.default.red(`Dashboard failed: ${err instanceof Error ? err.message : String(err)}`));
15250
15198
  process.exit(1);
15251
15199
  }
15252
15200
  }
@@ -15257,15 +15205,15 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
15257
15205
  const store = new MemoryStore(path23__default.default.join(workspacePath, CASCADE_DB_FILE));
15258
15206
  try {
15259
15207
  const identities = store.listIdentities();
15260
- console.log(chalk11__default.default.bold("\n Identities:"));
15208
+ console.log(chalk9__default.default.bold("\n Identities:"));
15261
15209
  if (identities.length === 0) {
15262
- console.log(chalk11__default.default.gray(" No identities found."));
15210
+ console.log(chalk9__default.default.gray(" No identities found."));
15263
15211
  } else {
15264
15212
  identities.forEach((id) => {
15265
- const defaultLabel = id.isDefault ? chalk11__default.default.green(" [Default]") : "";
15266
- console.log(` - ${chalk11__default.default.cyan(id.name)}${defaultLabel}`);
15267
- console.log(chalk11__default.default.gray(` ID: ${id.id}`));
15268
- if (id.description) console.log(chalk11__default.default.gray(` ${id.description}`));
15213
+ const defaultLabel = id.isDefault ? chalk9__default.default.green(" [Default]") : "";
15214
+ console.log(` - ${chalk9__default.default.cyan(id.name)}${defaultLabel}`);
15215
+ console.log(chalk9__default.default.gray(` ID: ${id.id}`));
15216
+ if (id.description) console.log(chalk9__default.default.gray(` ${id.description}`));
15269
15217
  });
15270
15218
  }
15271
15219
  console.log();
@@ -15291,9 +15239,9 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
15291
15239
  isDefault: !!options.default,
15292
15240
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
15293
15241
  });
15294
- console.log(chalk11__default.default.green(`
15242
+ console.log(chalk9__default.default.green(`
15295
15243
  Successfully created identity: ${name} (${id})`));
15296
- if (options.default) console.log(chalk11__default.default.green(" Set as default."));
15244
+ if (options.default) console.log(chalk9__default.default.green(" Set as default."));
15297
15245
  console.log();
15298
15246
  } finally {
15299
15247
  store.close();
@@ -15305,7 +15253,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
15305
15253
  const identities = store.listIdentities();
15306
15254
  const match = identities.find((i) => i.id === query || i.name.toLowerCase() === query.toLowerCase());
15307
15255
  if (!match) {
15308
- console.error(chalk11__default.default.red(`
15256
+ console.error(chalk9__default.default.red(`
15309
15257
  Identity '${query}' not found.
15310
15258
  `));
15311
15259
  process.exit(1);
@@ -15315,7 +15263,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
15315
15263
  store.updateIdentity(existingDefault.id, { isDefault: false });
15316
15264
  }
15317
15265
  store.updateIdentity(match.id, { isDefault: true });
15318
- console.log(chalk11__default.default.green(`
15266
+ console.log(chalk9__default.default.green(`
15319
15267
  Identity ${match.name} is now the default.
15320
15268
  `));
15321
15269
  } finally {
@@ -15325,7 +15273,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
15325
15273
  return identity;
15326
15274
  }
15327
15275
  async function modelsCommand(options = {}) {
15328
- console.log(chalk11__default.default.magenta("\n \u25C8 Cascade Models\n"));
15276
+ console.log(chalk9__default.default.magenta("\n \u25C8 Cascade Models\n"));
15329
15277
  const cm = new ConfigManager(process.cwd());
15330
15278
  await cm.load();
15331
15279
  const config = cm.getConfig();
@@ -15333,16 +15281,16 @@ async function modelsCommand(options = {}) {
15333
15281
  try {
15334
15282
  await router.init(config);
15335
15283
  } catch (err) {
15336
- console.error(chalk11__default.default.red(` Failed to initialize router: ${err instanceof Error ? err.message : String(err)}`));
15284
+ console.error(chalk9__default.default.red(` Failed to initialize router: ${err instanceof Error ? err.message : String(err)}`));
15337
15285
  process.exit(1);
15338
15286
  }
15339
15287
  await withTimeout(router.refreshLiveData(), 6e3, "live data timeout").catch(() => {
15340
15288
  });
15341
15289
  const liveData = router.getLiveData();
15342
15290
  const tiers = [
15343
- { tier: "T1", label: "T1 Administrator", color: chalk11__default.default.hex("#7C6AF7") },
15344
- { tier: "T2", label: "T2 Manager", color: chalk11__default.default.hex("#5AB4E8") },
15345
- { tier: "T3", label: "T3 Worker", color: chalk11__default.default.hex("#5AE8A4") }
15291
+ { tier: "T1", label: "T1 Administrator", color: chalk9__default.default.hex("#7C6AF7") },
15292
+ { tier: "T2", label: "T2 Manager", color: chalk9__default.default.hex("#5AB4E8") },
15293
+ { tier: "T3", label: "T3 Worker", color: chalk9__default.default.hex("#5AE8A4") }
15346
15294
  ];
15347
15295
  let anyMissing = false;
15348
15296
  for (const { tier, label, color } of tiers) {
@@ -15351,48 +15299,72 @@ async function modelsCommand(options = {}) {
15351
15299
  const costIn = model.inputCostPer1kTokens === 0 ? "free" : `$${model.inputCostPer1kTokens.toFixed(4)}/1K in`;
15352
15300
  const costOut = model.outputCostPer1kTokens === 0 ? "free" : `$${model.outputCostPer1kTokens.toFixed(4)}/1K out`;
15353
15301
  const ctx = model.contextWindow >= 1e6 ? `${(model.contextWindow / 1e6).toFixed(1)}M ctx` : `${(model.contextWindow / 1e3).toFixed(0)}K ctx`;
15354
- const local = model.isLocal ? chalk11__default.default.gray(" [local]") : "";
15355
- const vision = model.isVisionCapable ? chalk11__default.default.gray(" \u{1F441}") : "";
15302
+ const local = model.isLocal ? chalk9__default.default.gray(" [local]") : "";
15303
+ const vision = model.isVisionCapable ? chalk9__default.default.gray(" \u{1F441}") : "";
15356
15304
  const bench = Math.round(benchmarkScore01(model, "mixed") * 100);
15357
15305
  console.log(
15358
- ` ${color.bold(tier)} ${chalk11__default.default.white(col(model.name, 24))}${chalk11__default.default.gray(col(model.provider, 16))}` + (options.verbose ? `${chalk11__default.default.gray(col(ctx, 12))}${chalk11__default.default.gray(col(`bench ${bench}/100`, 14))}${chalk11__default.default.gray(`${costIn}, ${costOut}`)}` : `${chalk11__default.default.gray(col(ctx, 10))}${chalk11__default.default.gray(`bench ${bench}/100`)}`) + local + vision
15306
+ ` ${color.bold(tier)} ${chalk9__default.default.white(col(model.name, 24))}${chalk9__default.default.gray(col(model.provider, 16))}` + (options.verbose ? `${chalk9__default.default.gray(col(ctx, 12))}${chalk9__default.default.gray(col(`bench ${bench}/100`, 14))}${chalk9__default.default.gray(`${costIn}, ${costOut}`)}` : `${chalk9__default.default.gray(col(ctx, 10))}${chalk9__default.default.gray(`bench ${bench}/100`)}`) + local + vision
15359
15307
  );
15360
15308
  } else {
15361
- console.log(` ${color.bold(tier)} ${chalk11__default.default.red("No model available")} ${chalk11__default.default.gray(`(check provider config for ${label})`)}`);
15309
+ console.log(` ${color.bold(tier)} ${chalk9__default.default.red("No model available")} ${chalk9__default.default.gray(`(check provider config for ${label})`)}`);
15362
15310
  anyMissing = true;
15363
15311
  }
15364
15312
  }
15365
15313
  console.log();
15366
15314
  const providers = config.providers.map((p) => p.type).join(", ") || "(none)";
15367
- console.log(chalk11__default.default.gray(` Configured providers: ${providers}`));
15315
+ console.log(chalk9__default.default.gray(` Configured providers: ${providers}`));
15368
15316
  if (liveData) {
15369
15317
  const src = liveData.getDataSource();
15370
15318
  const gen = liveData.getGeneratedAt();
15371
15319
  const srcLabel = src === "live" ? "live (just fetched)" : src === "cache" ? "cached" : "bundled";
15372
- console.log(chalk11__default.default.gray(
15320
+ console.log(chalk9__default.default.gray(
15373
15321
  ` Benchmark data: ${srcLabel}` + (gen ? ` \xB7 updated ${gen.slice(0, 10)}` : "") + ` \xB7 pricing: ${liveData.hasLivePricing() ? "live (OpenRouter)" : "catalog"}`
15374
15322
  ));
15375
15323
  }
15376
15324
  if (options.verbose) {
15377
15325
  console.log();
15378
- console.log(chalk11__default.default.white(" Available models by provider:\n"));
15326
+ console.log(chalk9__default.default.white(" Available models by provider:\n"));
15379
15327
  const allProviderTypes = [...new Set(config.providers.map((p) => p.type))];
15380
15328
  for (const providerType of allProviderTypes) {
15381
15329
  const available = router.getModelsForProvider(providerType);
15382
15330
  if (available.length === 0) continue;
15383
- console.log(chalk11__default.default.gray(` ${providerType}:`));
15331
+ console.log(chalk9__default.default.gray(` ${providerType}:`));
15384
15332
  for (const m of available) {
15385
15333
  const override = config.models.t1 === m.id ? " \u2190 T1" : config.models.t2 === m.id ? " \u2190 T2" : config.models.t3 === m.id ? " \u2190 T3" : "";
15386
- console.log(` ${chalk11__default.default.white(col(m.name, 28))}${chalk11__default.default.gray(m.id)}${chalk11__default.default.yellow(override)}`);
15334
+ console.log(` ${chalk9__default.default.white(col(m.name, 28))}${chalk9__default.default.gray(m.id)}${chalk9__default.default.yellow(override)}`);
15387
15335
  }
15388
15336
  console.log();
15389
15337
  }
15390
15338
  }
15391
15339
  if (anyMissing) {
15392
- console.log(chalk11__default.default.yellow(" Some tiers have no available model. Run `cascade doctor` for details.\n"));
15340
+ console.log(chalk9__default.default.yellow(" Some tiers have no available model. Run `cascade doctor` for details.\n"));
15393
15341
  } else {
15394
- console.log(chalk11__default.default.green(" All tiers are configured.\n"));
15342
+ console.log(chalk9__default.default.green(" All tiers are configured.\n"));
15343
+ }
15344
+ }
15345
+ async function setModelCommand(action, tierArg, value) {
15346
+ const tier = (tierArg ?? "").toLowerCase();
15347
+ if (!["t1", "t2", "t3"].includes(tier)) {
15348
+ console.error(chalk9__default.default.red(` Invalid tier "${tierArg ?? ""}". Use t1, t2, or t3.`));
15349
+ console.log(chalk9__default.default.gray(" e.g. cascade models set t1 anthropic:claude-opus-4-8"));
15350
+ process.exit(1);
15351
+ }
15352
+ const override = action === "unset" ? "auto" : (value ?? "").trim();
15353
+ if (action === "set" && !override) {
15354
+ console.error(chalk9__default.default.red(' Missing value. e.g. cascade models set t3 openai:gpt-4o-mini (or "auto")'));
15355
+ process.exit(1);
15395
15356
  }
15357
+ const cm = new ConfigManager(process.cwd());
15358
+ await cm.load();
15359
+ const config = cm.getConfig();
15360
+ const models = { ...config.models };
15361
+ if (override === "auto") delete models[tier];
15362
+ else models[tier] = override;
15363
+ await cm.updateConfig({ models });
15364
+ const label = override === "auto" ? chalk9__default.default.gray("auto (routing decides)") : chalk9__default.default.white(override);
15365
+ console.log(chalk9__default.default.green(`
15366
+ \u2713 ${tier.toUpperCase()} model set to ${label}
15367
+ `));
15396
15368
  }
15397
15369
  function col(s, width) {
15398
15370
  return s.length < width ? s.padEnd(width) : `${s} `;
@@ -15414,7 +15386,7 @@ async function exportCommand(options = {}) {
15414
15386
  }
15415
15387
  store = new MemoryStore(dbPath);
15416
15388
  } catch (err) {
15417
- spin.fail(chalk11__default.default.red(`Cannot open memory store: ${err instanceof Error ? err.message : String(err)}`));
15389
+ spin.fail(chalk9__default.default.red(`Cannot open memory store: ${err instanceof Error ? err.message : String(err)}`));
15418
15390
  process.exit(1);
15419
15391
  }
15420
15392
  try {
@@ -15422,7 +15394,7 @@ async function exportCommand(options = {}) {
15422
15394
  if (options.sessionId) {
15423
15395
  const session2 = store.getSession(options.sessionId);
15424
15396
  if (!session2) {
15425
- spin.fail(chalk11__default.default.red(`Session "${options.sessionId}" not found.`));
15397
+ spin.fail(chalk9__default.default.red(`Session "${options.sessionId}" not found.`));
15426
15398
  process.exit(1);
15427
15399
  }
15428
15400
  sessions = [session2];
@@ -15430,14 +15402,14 @@ async function exportCommand(options = {}) {
15430
15402
  const limit = options.last ?? 10;
15431
15403
  sessions = store.listSessions(void 0, limit);
15432
15404
  if (sessions.length === 0) {
15433
- spin.warn(chalk11__default.default.yellow("No sessions found."));
15405
+ spin.warn(chalk9__default.default.yellow("No sessions found."));
15434
15406
  return;
15435
15407
  }
15436
15408
  const latest = sessions[0];
15437
15409
  const full = store.getSession(latest.id);
15438
15410
  sessions = full ? [full] : [];
15439
15411
  if (sessions.length === 0) {
15440
- spin.fail(chalk11__default.default.red("Could not load latest session."));
15412
+ spin.fail(chalk9__default.default.red("Could not load latest session."));
15441
15413
  process.exit(1);
15442
15414
  }
15443
15415
  }
@@ -15449,15 +15421,15 @@ async function exportCommand(options = {}) {
15449
15421
  const defaultFile = `cascade-export-${safeName}${ext}`;
15450
15422
  const outPath = options.output ? path23__default.default.resolve(options.output) : path23__default.default.join(process.cwd(), defaultFile);
15451
15423
  await fs9__default.default.writeFile(outPath, content, "utf-8");
15452
- spin.succeed(chalk11__default.default.green(`Exported to ${chalk11__default.default.white(outPath)}`));
15424
+ spin.succeed(chalk9__default.default.green(`Exported to ${chalk9__default.default.white(outPath)}`));
15453
15425
  const messageCount = Array.isArray(session.messages) ? session.messages.length : 0;
15454
15426
  console.log();
15455
- console.log(chalk11__default.default.gray(` Session: ${session.title}`));
15456
- console.log(chalk11__default.default.gray(` Messages: ${messageCount}`));
15457
- console.log(chalk11__default.default.gray(` Format: ${format}`));
15427
+ console.log(chalk9__default.default.gray(` Session: ${session.title}`));
15428
+ console.log(chalk9__default.default.gray(` Messages: ${messageCount}`));
15429
+ console.log(chalk9__default.default.gray(` Format: ${format}`));
15458
15430
  console.log();
15459
15431
  } catch (err) {
15460
- spin.fail(chalk11__default.default.red(`Export failed: ${err instanceof Error ? err.message : String(err)}`));
15432
+ spin.fail(chalk9__default.default.red(`Export failed: ${err instanceof Error ? err.message : String(err)}`));
15461
15433
  process.exit(1);
15462
15434
  }
15463
15435
  }
@@ -15514,9 +15486,9 @@ function buildJsonExport(session) {
15514
15486
  async function linkCommand(target, options = {}) {
15515
15487
  const found = await discoverCredentials();
15516
15488
  if (found.length === 0) {
15517
- console.log(chalk11__default.default.yellow("\n No reusable credentials found.\n"));
15518
- console.log(chalk11__default.default.gray(" Cascade looks for Claude Code, Codex, Gemini CLI, and GitHub Copilot logins,"));
15519
- console.log(chalk11__default.default.gray(" plus ANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY in your environment.\n"));
15489
+ console.log(chalk9__default.default.yellow("\n No reusable credentials found.\n"));
15490
+ console.log(chalk9__default.default.gray(" Cascade looks for Claude Code, Codex, Gemini CLI, and GitHub Copilot logins,"));
15491
+ console.log(chalk9__default.default.gray(" plus ANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY in your environment.\n"));
15520
15492
  return;
15521
15493
  }
15522
15494
  if (!target) {
@@ -15525,7 +15497,7 @@ async function linkCommand(target, options = {}) {
15525
15497
  }
15526
15498
  const provider = normalizeProvider(target);
15527
15499
  if (!provider) {
15528
- console.log(chalk11__default.default.red(`
15500
+ console.log(chalk9__default.default.red(`
15529
15501
  Unknown provider "${target}". Use one of: anthropic, openai, gemini.
15530
15502
  `));
15531
15503
  return;
@@ -15533,46 +15505,46 @@ async function linkCommand(target, options = {}) {
15533
15505
  const candidates2 = found.filter((c) => c.provider === provider);
15534
15506
  const chosen = candidates2.find((c) => c.directlyUsable) ?? candidates2[0];
15535
15507
  if (!chosen) {
15536
- console.log(chalk11__default.default.yellow(`
15508
+ console.log(chalk9__default.default.yellow(`
15537
15509
  No detected credential maps to "${provider}".
15538
15510
  `));
15539
15511
  return;
15540
15512
  }
15541
15513
  if (!chosen.directlyUsable) {
15542
- console.log(chalk11__default.default.yellow(`
15514
+ console.log(chalk9__default.default.yellow(`
15543
15515
  Found a ${chosen.sourceTool} credential, but it can't be used against the standard ${provider} API.`));
15544
- if (chosen.warning) console.log(chalk11__default.default.gray(` ${chosen.warning}`));
15545
- console.log(chalk11__default.default.gray(" Cascade won't adopt it because it would create a non-working provider.\n"));
15516
+ if (chosen.warning) console.log(chalk9__default.default.gray(` ${chosen.warning}`));
15517
+ console.log(chalk9__default.default.gray(" Cascade won't adopt it because it would create a non-working provider.\n"));
15546
15518
  return;
15547
15519
  }
15548
15520
  if (chosen.kind === "oauth" && !options.acceptRisk) {
15549
- console.log(chalk11__default.default.yellow(`
15521
+ console.log(chalk9__default.default.yellow(`
15550
15522
  ${chosen.sourceTool} provides a subscription OAuth token, not an API key.`));
15551
- if (chosen.warning) console.log(chalk11__default.default.gray(` ${chosen.warning}`));
15552
- console.log(chalk11__default.default.gray(" Re-run with --accept-risk to adopt it anyway:\n"));
15553
- console.log(chalk11__default.default.cyan(` cascade link ${provider} --accept-risk
15523
+ if (chosen.warning) console.log(chalk9__default.default.gray(` ${chosen.warning}`));
15524
+ console.log(chalk9__default.default.gray(" Re-run with --accept-risk to adopt it anyway:\n"));
15525
+ console.log(chalk9__default.default.cyan(` cascade link ${provider} --accept-risk
15554
15526
  `));
15555
15527
  return;
15556
15528
  }
15557
15529
  await adoptCredential(chosen, options.workspace ?? process.cwd());
15558
- console.log(chalk11__default.default.green(`
15530
+ console.log(chalk9__default.default.green(`
15559
15531
  \u2713 Linked ${provider} using your ${chosen.sourceTool} credential (${maskSecret(chosen.secret)}).`));
15560
15532
  if (chosen.kind === "oauth") {
15561
- console.log(chalk11__default.default.gray(" Adopted as an OAuth bearer token \u2014 revoke it in the source tool to disable."));
15533
+ console.log(chalk9__default.default.gray(" Adopted as an OAuth bearer token \u2014 revoke it in the source tool to disable."));
15562
15534
  }
15563
- console.log(chalk11__default.default.gray(" Run `cascade doctor` to verify, or `cascade` to start.\n"));
15535
+ console.log(chalk9__default.default.gray(" Run `cascade doctor` to verify, or `cascade` to start.\n"));
15564
15536
  }
15565
15537
  function printDiscovered(found) {
15566
- console.log(chalk11__default.default.magenta("\n \u25C8 Detected credentials\n"));
15538
+ console.log(chalk9__default.default.magenta("\n \u25C8 Detected credentials\n"));
15567
15539
  for (const c of found) {
15568
- const usable = c.directlyUsable ? chalk11__default.default.green("usable") : chalk11__default.default.yellow("needs vendor backend");
15569
- const kind = c.kind === "oauth" ? chalk11__default.default.yellow("oauth") : chalk11__default.default.gray("api-key");
15570
- console.log(` ${chalk11__default.default.white(c.provider.padEnd(18))} ${chalk11__default.default.gray(maskSecret(c.secret).padEnd(12))} ${kind} ${usable}`);
15571
- console.log(chalk11__default.default.gray(` from ${c.sourceTool}`));
15572
- if (c.warning) console.log(chalk11__default.default.yellow(` \u26A0 ${c.warning}`));
15540
+ const usable = c.directlyUsable ? chalk9__default.default.green("usable") : chalk9__default.default.yellow("needs vendor backend");
15541
+ const kind = c.kind === "oauth" ? chalk9__default.default.yellow("oauth") : chalk9__default.default.gray("api-key");
15542
+ console.log(` ${chalk9__default.default.white(c.provider.padEnd(18))} ${chalk9__default.default.gray(maskSecret(c.secret).padEnd(12))} ${kind} ${usable}`);
15543
+ console.log(chalk9__default.default.gray(` from ${c.sourceTool}`));
15544
+ if (c.warning) console.log(chalk9__default.default.yellow(` \u26A0 ${c.warning}`));
15573
15545
  }
15574
- console.log(chalk11__default.default.gray("\n Adopt one with: ") + chalk11__default.default.cyan("cascade link <provider> [--accept-risk]"));
15575
- console.log(chalk11__default.default.gray(" --accept-risk is required for subscription OAuth tokens.\n"));
15546
+ console.log(chalk9__default.default.gray("\n Adopt one with: ") + chalk9__default.default.cyan("cascade link <provider> [--accept-risk]"));
15547
+ console.log(chalk9__default.default.gray(" --accept-risk is required for subscription OAuth tokens.\n"));
15576
15548
  }
15577
15549
  function normalizeProvider(target) {
15578
15550
  const t = target.toLowerCase();
@@ -15605,12 +15577,12 @@ async function telemetryCommand(action) {
15605
15577
  if (action === "status") {
15606
15578
  const state = config.telemetry?.enabled ? "ON" : "OFF";
15607
15579
  console.log();
15608
- console.log(chalk11__default.default.magenta(" \u25C8 Cascade Telemetry"));
15580
+ console.log(chalk9__default.default.magenta(" \u25C8 Cascade Telemetry"));
15609
15581
  console.log();
15610
- console.log(` Status: ${config.telemetry?.enabled ? chalk11__default.default.green(state) : chalk11__default.default.gray(state)}`);
15611
- console.log(chalk11__default.default.gray(" Scope: anonymous session metadata only (no prompts/outputs)"));
15582
+ console.log(` Status: ${config.telemetry?.enabled ? chalk9__default.default.green(state) : chalk9__default.default.gray(state)}`);
15583
+ console.log(chalk9__default.default.gray(" Scope: anonymous session metadata only (no prompts/outputs)"));
15612
15584
  console.log();
15613
- console.log(chalk11__default.default.gray(" Toggle with: cascade telemetry on | cascade telemetry off"));
15585
+ console.log(chalk9__default.default.gray(" Toggle with: cascade telemetry on | cascade telemetry off"));
15614
15586
  console.log();
15615
15587
  return;
15616
15588
  }
@@ -15624,11 +15596,11 @@ async function telemetryCommand(action) {
15624
15596
  });
15625
15597
  console.log();
15626
15598
  if (enabled) {
15627
- console.log(chalk11__default.default.green(` \u2713 Telemetry enabled.`));
15628
- console.log(chalk11__default.default.gray(" Anonymous session metadata (no prompts, no outputs) will be sent."));
15599
+ console.log(chalk9__default.default.green(` \u2713 Telemetry enabled.`));
15600
+ console.log(chalk9__default.default.gray(" Anonymous session metadata (no prompts, no outputs) will be sent."));
15629
15601
  } else {
15630
- console.log(chalk11__default.default.yellow(` \u2713 Telemetry disabled.`));
15631
- console.log(chalk11__default.default.gray(" No events will be transmitted from this workspace."));
15602
+ console.log(chalk9__default.default.yellow(` \u2713 Telemetry disabled.`));
15603
+ console.log(chalk9__default.default.gray(" No events will be transmitted from this workspace."));
15632
15604
  }
15633
15605
  console.log();
15634
15606
  }
@@ -15638,11 +15610,11 @@ async function statsCommand() {
15638
15610
  await tracker.load();
15639
15611
  const all = tracker.getAll();
15640
15612
  if (all.size === 0) {
15641
- console.log(chalk11__default.default.dim("\n No routing history yet \u2014 run some tasks first.\n"));
15613
+ console.log(chalk9__default.default.dim("\n No routing history yet \u2014 run some tasks first.\n"));
15642
15614
  return;
15643
15615
  }
15644
- console.log(chalk11__default.default.magenta("\n \u25C8 Auto-Routing History\n"));
15645
- console.log(chalk11__default.default.dim(" Per-task-type model performance learned from past runs.\n"));
15616
+ console.log(chalk9__default.default.magenta("\n \u25C8 Auto-Routing History\n"));
15617
+ console.log(chalk9__default.default.dim(" Per-task-type model performance learned from past runs.\n"));
15646
15618
  for (const taskType of TASK_TYPES) {
15647
15619
  const entries = [];
15648
15620
  for (const [key, stat] of all) {
@@ -15654,21 +15626,21 @@ async function statsCommand() {
15654
15626
  }
15655
15627
  if (entries.length === 0) continue;
15656
15628
  entries.sort((a, b) => b.successRate - a.successRate || b.samples - a.samples);
15657
- console.log(chalk11__default.default.bold(` ${taskType.toUpperCase()}`));
15629
+ console.log(chalk9__default.default.bold(` ${taskType.toUpperCase()}`));
15658
15630
  const header = ` ${"Model".padEnd(36)} ${"Success".padEnd(9)} ${"Samples".padEnd(9)} Avg cost`;
15659
- console.log(chalk11__default.default.dim(header));
15660
- console.log(chalk11__default.default.dim(" " + "\u2500".repeat(62)));
15631
+ console.log(chalk9__default.default.dim(header));
15632
+ console.log(chalk9__default.default.dim(" " + "\u2500".repeat(62)));
15661
15633
  for (const e of entries) {
15662
15634
  const pct = `${Math.round(e.successRate * 100)}%`;
15663
15635
  const cost = e.avgCostUsd < 1e-4 ? "<$0.0001" : `$${e.avgCostUsd.toFixed(4)}`;
15664
- const color = e.successRate >= 0.8 ? chalk11__default.default.green : e.successRate >= 0.5 ? chalk11__default.default.yellow : chalk11__default.default.red;
15636
+ const color = e.successRate >= 0.8 ? chalk9__default.default.green : e.successRate >= 0.5 ? chalk9__default.default.yellow : chalk9__default.default.red;
15665
15637
  console.log(
15666
- ` ${e.modelId.padEnd(36)} ${color(pct.padEnd(9))} ${String(e.samples).padEnd(9)} ${chalk11__default.default.dim(cost)}`
15638
+ ` ${e.modelId.padEnd(36)} ${color(pct.padEnd(9))} ${String(e.samples).padEnd(9)} ${chalk9__default.default.dim(cost)}`
15667
15639
  );
15668
15640
  }
15669
15641
  console.log();
15670
15642
  }
15671
- console.log(chalk11__default.default.dim(" tip: use /rate good | bad after a task to improve these scores.\n"));
15643
+ console.log(chalk9__default.default.dim(" tip: use /rate good | bad after a task to improve these scores.\n"));
15672
15644
  }
15673
15645
 
15674
15646
  // src/cli/index.ts
@@ -15683,7 +15655,7 @@ function warnIfBuildIsStale() {
15683
15655
  if (pkg.name !== "cascade-ai") continue;
15684
15656
  if (pkg.version && pkg.version !== CASCADE_VERSION) {
15685
15657
  console.error(
15686
- chalk11__default.default.yellow(
15658
+ chalk9__default.default.yellow(
15687
15659
  `\u26A0 Stale build: compiled output is v${CASCADE_VERSION} but the source tree is v${pkg.version}.
15688
15660
  Run: npm install && npm run build`
15689
15661
  )
@@ -15751,13 +15723,17 @@ program.command("dashboard").description("Launch the web dashboard").option("-p,
15751
15723
  program.command("run <prompt>").description("Run a single prompt and exit").option("-t, --theme <name>", "Color theme", DEFAULT_THEME).option("-i, --identity <name>", "Identity name or ID").action(async (prompt, opts) => {
15752
15724
  await runHeadless(prompt, { theme: opts.theme, workspace: process.cwd(), identity: opts.identity });
15753
15725
  });
15754
- program.command("models").description("List available AI models for each tier").option("-v, --verbose", "Show all models per provider with pricing").action(async (opts) => {
15755
- await modelsCommand({ verbose: opts.verbose });
15726
+ program.command("models [action] [tier] [value]").description("List AI models per tier, or set/unset a tier provider+model (e.g. models set t1 anthropic:claude-opus-4-8)").option("-v, --verbose", "Show all models per provider with pricing").action(async (action, tier, value, opts) => {
15727
+ if (action === "set" || action === "unset") {
15728
+ await setModelCommand(action, tier, value);
15729
+ } else {
15730
+ await modelsCommand({ verbose: opts.verbose });
15731
+ }
15756
15732
  });
15757
15733
  program.command("telemetry [action]").description("Toggle anonymous usage telemetry (on | off | status). Default: status").action(async (action) => {
15758
15734
  const normalized = (action ?? "status").toLowerCase();
15759
15735
  if (normalized !== "on" && normalized !== "off" && normalized !== "status") {
15760
- console.error(chalk11__default.default.red(`Unknown action: ${action}. Use: on | off | status`));
15736
+ console.error(chalk9__default.default.red(`Unknown action: ${action}. Use: on | off | status`));
15761
15737
  process.exit(1);
15762
15738
  }
15763
15739
  await telemetryCommand(normalized);
@@ -15779,14 +15755,14 @@ async function startRepl(options) {
15779
15755
  try {
15780
15756
  await cm.load();
15781
15757
  } catch (err) {
15782
- console.error(chalk11__default.default.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
15783
- console.error(chalk11__default.default.gray("Run `cascade init` to set up this directory."));
15758
+ console.error(chalk9__default.default.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
15759
+ console.error(chalk9__default.default.gray("Run `cascade init` to set up this directory."));
15784
15760
  process.exit(1);
15785
15761
  }
15786
15762
  let config = cm.getConfig();
15787
15763
  const needsSetup = !config.providers?.length || config.providers.every((p) => p.type !== "ollama" && !p.apiKey);
15788
15764
  if (needsSetup) {
15789
- console.log(chalk11__default.default.magenta(" \u25C8 No providers configured \u2014 launching setup wizard\u2026"));
15765
+ console.log(chalk9__default.default.magenta(" \u25C8 No providers configured \u2014 launching setup wizard\u2026"));
15790
15766
  console.log();
15791
15767
  config = await runSetupWizard(workspacePath);
15792
15768
  await cm.updateConfig(config);
@@ -15820,24 +15796,24 @@ async function runHeadless(prompt, options) {
15820
15796
  try {
15821
15797
  await cm.load();
15822
15798
  } catch (err) {
15823
- console.error(chalk11__default.default.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
15824
- console.error(chalk11__default.default.gray("Run `cascade init` to set up this directory."));
15799
+ console.error(chalk9__default.default.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
15800
+ console.error(chalk9__default.default.gray("Run `cascade init` to set up this directory."));
15825
15801
  process.exit(1);
15826
15802
  }
15827
15803
  const config = cm.getConfig();
15828
15804
  const needsSetup = !config.providers?.length || config.providers.every((p) => p.type !== "ollama" && !p.apiKey);
15829
15805
  if (needsSetup) {
15830
- console.error(chalk11__default.default.red("No providers configured. Run `cascade init` first."));
15806
+ console.error(chalk9__default.default.red("No providers configured. Run `cascade init` first."));
15831
15807
  process.exit(1);
15832
15808
  }
15833
15809
  const cascade = new Cascade(config, workspacePath);
15834
15810
  try {
15835
15811
  await cascade.init();
15836
15812
  } catch (err) {
15837
- console.error(chalk11__default.default.red(`Initialization failed: ${err instanceof Error ? err.message : String(err)}`));
15813
+ console.error(chalk9__default.default.red(`Initialization failed: ${err instanceof Error ? err.message : String(err)}`));
15838
15814
  process.exit(1);
15839
15815
  }
15840
- console.error(chalk11__default.default.gray(" \u25C8 Running headlessly \u2014 tool approvals are auto-granted."));
15816
+ console.error(chalk9__default.default.gray(" \u25C8 Running headlessly \u2014 tool approvals are auto-granted."));
15841
15817
  let lastProgress = "";
15842
15818
  cascade.on("tier:status", (ev) => {
15843
15819
  const action = ev?.currentAction?.trim();
@@ -15845,7 +15821,7 @@ async function runHeadless(prompt, options) {
15845
15821
  const line = ` \xB7 ${ev.role ?? ""} ${action}`.trimEnd();
15846
15822
  if (line === lastProgress) return;
15847
15823
  lastProgress = line;
15848
- console.error(chalk11__default.default.gray(line));
15824
+ console.error(chalk9__default.default.gray(line));
15849
15825
  });
15850
15826
  try {
15851
15827
  const result = await cascade.run({
@@ -15856,7 +15832,7 @@ async function runHeadless(prompt, options) {
15856
15832
  });
15857
15833
  process.stdout.write(result.output.trimEnd() + "\n");
15858
15834
  } catch (err) {
15859
- console.error(chalk11__default.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
15835
+ console.error(chalk9__default.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
15860
15836
  await cascade.close().catch(() => {
15861
15837
  });
15862
15838
  process.exit(1);
@@ -15868,10 +15844,10 @@ async function runHeadless(prompt, options) {
15868
15844
  function printBanner() {
15869
15845
  if (process.stdout.columns < 60) return;
15870
15846
  console.log();
15871
- console.log(chalk11__default.default.hex("#7C6AF7").bold(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
15872
- console.log(chalk11__default.default.hex("#7C6AF7").bold(" \u2551") + chalk11__default.default.white.bold(" \u25C8 CASCADE AI") + chalk11__default.default.gray(" v" + CASCADE_VERSION + " ") + chalk11__default.default.hex("#7C6AF7").bold("\u2551"));
15873
- console.log(chalk11__default.default.hex("#7C6AF7").bold(" \u2551") + chalk11__default.default.gray(" Multi-Tier Orchestration ") + chalk11__default.default.hex("#7C6AF7").bold("\u2551"));
15874
- console.log(chalk11__default.default.hex("#7C6AF7").bold(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
15847
+ console.log(chalk9__default.default.hex("#7C6AF7").bold(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
15848
+ console.log(chalk9__default.default.hex("#7C6AF7").bold(" \u2551") + chalk9__default.default.white.bold(" \u25C8 CASCADE AI") + chalk9__default.default.gray(" v" + CASCADE_VERSION + " ") + chalk9__default.default.hex("#7C6AF7").bold("\u2551"));
15849
+ console.log(chalk9__default.default.hex("#7C6AF7").bold(" \u2551") + chalk9__default.default.gray(" Multi-Tier Orchestration ") + chalk9__default.default.hex("#7C6AF7").bold("\u2551"));
15850
+ console.log(chalk9__default.default.hex("#7C6AF7").bold(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
15875
15851
  console.log();
15876
15852
  }
15877
15853
  program.parse(process.argv);