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 +186 -210
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +185 -209
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +38 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +38 -94
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/keytar-VMICNFEJ.node +0 -0
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { GoogleGenAI, HarmBlockThreshold, HarmCategory } from '@google/genai';
|
|
|
4
4
|
import { render, Box, Text, useStdout, useApp, useInput, Static } from 'ink';
|
|
5
5
|
import { Command } from 'commander';
|
|
6
6
|
import React2, { useState, useReducer, useRef, useCallback, useEffect, useMemo } from 'react';
|
|
7
|
-
import
|
|
7
|
+
import chalk9 from 'chalk';
|
|
8
8
|
import dotenv from 'dotenv';
|
|
9
9
|
import fs21 from 'fs';
|
|
10
10
|
import path23 from 'path';
|
|
@@ -40,50 +40,21 @@ import parser from 'socket.io-msgpack-parser';
|
|
|
40
40
|
import jwt from 'jsonwebtoken';
|
|
41
41
|
|
|
42
42
|
// Cascade AI — Multi-tier AI Orchestration System
|
|
43
|
-
var __create = Object.create;
|
|
44
43
|
var __defProp = Object.defineProperty;
|
|
45
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
46
44
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
47
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
48
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
49
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
50
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
51
|
-
}) : x)(function(x) {
|
|
52
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
53
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
54
|
-
});
|
|
55
45
|
var __esm = (fn, res) => function __init() {
|
|
56
46
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
57
47
|
};
|
|
58
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
59
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
60
|
-
};
|
|
61
48
|
var __export = (target, all) => {
|
|
62
49
|
for (var name in all)
|
|
63
50
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
64
51
|
};
|
|
65
|
-
var __copyProps = (to, from, except, desc) => {
|
|
66
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
67
|
-
for (let key of __getOwnPropNames(from))
|
|
68
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
69
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
70
|
-
}
|
|
71
|
-
return to;
|
|
72
|
-
};
|
|
73
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
74
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
75
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
76
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
77
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
78
|
-
__defProp(target, "default", { value: mod, enumerable: true }) ,
|
|
79
|
-
mod
|
|
80
|
-
));
|
|
81
52
|
|
|
82
53
|
// src/constants.ts
|
|
83
54
|
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;
|
|
84
55
|
var init_constants = __esm({
|
|
85
56
|
"src/constants.ts"() {
|
|
86
|
-
CASCADE_VERSION = "0.
|
|
57
|
+
CASCADE_VERSION = "0.12.5";
|
|
87
58
|
CASCADE_CONFIG_FILE = ".cascade/config.json";
|
|
88
59
|
CASCADE_DB_FILE = ".cascade/memory.db";
|
|
89
60
|
CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
|
|
@@ -399,63 +370,6 @@ var init_constants = __esm({
|
|
|
399
370
|
}
|
|
400
371
|
});
|
|
401
372
|
|
|
402
|
-
// node_modules/keytar/build/Release/keytar.node
|
|
403
|
-
var keytar_default;
|
|
404
|
-
var init_keytar = __esm({
|
|
405
|
-
"node_modules/keytar/build/Release/keytar.node"() {
|
|
406
|
-
keytar_default = "./keytar-VMICNFEJ.node";
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
// node-file:/home/runner/work/Cascade-AI/Cascade-AI/node_modules/keytar/build/Release/keytar.node
|
|
411
|
-
var require_keytar = __commonJS({
|
|
412
|
-
"node-file:/home/runner/work/Cascade-AI/Cascade-AI/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
413
|
-
init_keytar();
|
|
414
|
-
try {
|
|
415
|
-
module.exports = __require(keytar_default);
|
|
416
|
-
} catch {
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
// node_modules/keytar/lib/keytar.js
|
|
422
|
-
var require_keytar2 = __commonJS({
|
|
423
|
-
"node_modules/keytar/lib/keytar.js"(exports, module) {
|
|
424
|
-
var keytar = require_keytar();
|
|
425
|
-
function checkRequired(val, name) {
|
|
426
|
-
if (!val || val.length <= 0) {
|
|
427
|
-
throw new Error(name + " is required.");
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
module.exports = {
|
|
431
|
-
getPassword: function(service, account) {
|
|
432
|
-
checkRequired(service, "Service");
|
|
433
|
-
checkRequired(account, "Account");
|
|
434
|
-
return keytar.getPassword(service, account);
|
|
435
|
-
},
|
|
436
|
-
setPassword: function(service, account, password) {
|
|
437
|
-
checkRequired(service, "Service");
|
|
438
|
-
checkRequired(account, "Account");
|
|
439
|
-
checkRequired(password, "Password");
|
|
440
|
-
return keytar.setPassword(service, account, password);
|
|
441
|
-
},
|
|
442
|
-
deletePassword: function(service, account) {
|
|
443
|
-
checkRequired(service, "Service");
|
|
444
|
-
checkRequired(account, "Account");
|
|
445
|
-
return keytar.deletePassword(service, account);
|
|
446
|
-
},
|
|
447
|
-
findPassword: function(service) {
|
|
448
|
-
checkRequired(service, "Service");
|
|
449
|
-
return keytar.findPassword(service);
|
|
450
|
-
},
|
|
451
|
-
findCredentials: function(service) {
|
|
452
|
-
checkRequired(service, "Service");
|
|
453
|
-
return keytar.findCredentials(service);
|
|
454
|
-
}
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
|
|
459
373
|
// src/providers/base.ts
|
|
460
374
|
var BaseProvider;
|
|
461
375
|
var init_base = __esm({
|
|
@@ -1465,7 +1379,7 @@ var PBKDF2_ITERATIONS = 1e5;
|
|
|
1465
1379
|
var KEYTAR_SERVICE = "cascade-ai";
|
|
1466
1380
|
async function loadKeytar() {
|
|
1467
1381
|
try {
|
|
1468
|
-
const mod = await
|
|
1382
|
+
const mod = await import('keytar');
|
|
1469
1383
|
const candidate = mod.default ?? mod;
|
|
1470
1384
|
if (typeof candidate.getPassword !== "function") return null;
|
|
1471
1385
|
return candidate;
|
|
@@ -3189,15 +3103,15 @@ function SafeTextInput(props) {
|
|
|
3189
3103
|
const displayValue = mask ? mask.repeat(value.length) : value;
|
|
3190
3104
|
let rendered;
|
|
3191
3105
|
if (displayValue.length === 0) {
|
|
3192
|
-
rendered = showCursor && focus ? placeholder.length > 0 ?
|
|
3106
|
+
rendered = showCursor && focus ? placeholder.length > 0 ? chalk9.inverse(placeholder[0]) + chalk9.grey(placeholder.slice(1)) : chalk9.inverse(" ") : placeholder.length > 0 ? chalk9.grey(placeholder) : "";
|
|
3193
3107
|
} else if (!showCursor || !focus) {
|
|
3194
3108
|
rendered = displayValue;
|
|
3195
3109
|
} else {
|
|
3196
3110
|
let out = "";
|
|
3197
3111
|
for (let i = 0; i < displayValue.length; i++) {
|
|
3198
|
-
out += i === cursorOffset ?
|
|
3112
|
+
out += i === cursorOffset ? chalk9.inverse(displayValue[i]) : displayValue[i];
|
|
3199
3113
|
}
|
|
3200
|
-
if (cursorOffset >= displayValue.length) out +=
|
|
3114
|
+
if (cursorOffset >= displayValue.length) out += chalk9.inverse(" ");
|
|
3201
3115
|
rendered = out;
|
|
3202
3116
|
}
|
|
3203
3117
|
return /* @__PURE__ */ jsx(Text, { children: rendered });
|
|
@@ -4047,7 +3961,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
|
|
|
4047
3961
|
}
|
|
4048
3962
|
for (const tier of ["T1", "T2", "T3"]) {
|
|
4049
3963
|
const override = tier === "T1" ? config.models.t1 : tier === "T2" ? config.models.t2 : config.models.t3;
|
|
4050
|
-
if (!override) continue;
|
|
3964
|
+
if (!override || override === "auto") continue;
|
|
4051
3965
|
const model = this.selector.selectForTier(tier, override);
|
|
4052
3966
|
if (!model) {
|
|
4053
3967
|
const knownProviders = ["anthropic", "openai", "gemini", "azure", "openai-compatible", "ollama"];
|
|
@@ -11450,7 +11364,7 @@ function StatusBarInternal({
|
|
|
11450
11364
|
const savedStr = savedUsd > 0 ? ` \xB7 saved $${savedUsd.toFixed(4)}` : "";
|
|
11451
11365
|
const rightStr = ` ${formatTokens(tokens)} \xB7 $${costUsd.toFixed(4)}${savedStr} ${isExecuting ? "\u26A1" : "\xB7"} `;
|
|
11452
11366
|
const gap = Math.max(0, width - leftStr.length - rightStr.length);
|
|
11453
|
-
const line =
|
|
11367
|
+
const line = chalk9.bgHex(theme.colors.primary).hex(theme.colors.background)(chalk9.bold(leftStr) + " ".repeat(gap) + rightStr);
|
|
11454
11368
|
return /* @__PURE__ */ jsx(Text, { children: line });
|
|
11455
11369
|
}
|
|
11456
11370
|
function formatTokens(n) {
|
|
@@ -11861,7 +11775,7 @@ function renderContent(content, theme) {
|
|
|
11861
11775
|
i
|
|
11862
11776
|
);
|
|
11863
11777
|
}
|
|
11864
|
-
const rendered = part.replace(/\*\*(.*?)\*\*/g, (_, t) =>
|
|
11778
|
+
const rendered = part.replace(/\*\*(.*?)\*\*/g, (_, t) => chalk9.bold(t)).replace(/`(.*?)`/g, (_, t) => chalk9.bgHex(theme.colors.border)(t));
|
|
11865
11779
|
return /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: rendered }, i);
|
|
11866
11780
|
});
|
|
11867
11781
|
}
|
|
@@ -14067,20 +13981,20 @@ async function initCommand(workspacePath = process.cwd()) {
|
|
|
14067
13981
|
const mdPath = path23.join(workspacePath, "CASCADE.md");
|
|
14068
13982
|
if (!await fileExists(mdPath)) {
|
|
14069
13983
|
await createDefaultCascadeMd(workspacePath);
|
|
14070
|
-
spin.succeed(
|
|
13984
|
+
spin.succeed(chalk9.green("Created CASCADE.md"));
|
|
14071
13985
|
}
|
|
14072
13986
|
const ignorePath = path23.join(workspacePath, ".cascadeignore");
|
|
14073
13987
|
if (!await fileExists(ignorePath)) {
|
|
14074
13988
|
await createDefaultIgnoreFile(workspacePath);
|
|
14075
|
-
spin.succeed(
|
|
13989
|
+
spin.succeed(chalk9.green("Created .cascadeignore"));
|
|
14076
13990
|
}
|
|
14077
13991
|
spin.stop();
|
|
14078
13992
|
console.log();
|
|
14079
|
-
console.log(
|
|
13993
|
+
console.log(chalk9.magenta(" \u25C8 Cascade AI \u2014 Project initialized"));
|
|
14080
13994
|
console.log();
|
|
14081
13995
|
const configPath = path23.join(workspacePath, CASCADE_CONFIG_FILE);
|
|
14082
13996
|
if (await fileExists(configPath)) {
|
|
14083
|
-
console.log(
|
|
13997
|
+
console.log(chalk9.yellow(" .cascade/config.json already exists \u2014 launching wizard to reconfigure."));
|
|
14084
13998
|
console.log();
|
|
14085
13999
|
}
|
|
14086
14000
|
const config = await runSetupWizard(workspacePath);
|
|
@@ -14088,10 +14002,10 @@ async function initCommand(workspacePath = process.cwd()) {
|
|
|
14088
14002
|
await cm.load();
|
|
14089
14003
|
await cm.updateConfig(config);
|
|
14090
14004
|
console.log();
|
|
14091
|
-
console.log(
|
|
14005
|
+
console.log(chalk9.green(" \u25C8 Setup complete! Run `cascade` to start."));
|
|
14092
14006
|
console.log();
|
|
14093
14007
|
} catch (err) {
|
|
14094
|
-
console.error(
|
|
14008
|
+
console.error(chalk9.red(`Init failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
14095
14009
|
process.exit(1);
|
|
14096
14010
|
}
|
|
14097
14011
|
}
|
|
@@ -14237,7 +14151,7 @@ function maskSecret(secret) {
|
|
|
14237
14151
|
|
|
14238
14152
|
// src/cli/commands/doctor.ts
|
|
14239
14153
|
async function doctorCommand() {
|
|
14240
|
-
console.log(
|
|
14154
|
+
console.log(chalk9.magenta("\n \u25C8 Cascade Doctor \u2014 System Diagnostics\n"));
|
|
14241
14155
|
const checks = [];
|
|
14242
14156
|
const nodeVersion = process.versions.node;
|
|
14243
14157
|
const [major] = nodeVersion.split(".").map(Number);
|
|
@@ -14301,7 +14215,7 @@ async function doctorCommand() {
|
|
|
14301
14215
|
});
|
|
14302
14216
|
let keystoreBackend = "file (AES-256-GCM)";
|
|
14303
14217
|
try {
|
|
14304
|
-
await
|
|
14218
|
+
await import('keytar');
|
|
14305
14219
|
keystoreBackend = "keytar (OS keychain)";
|
|
14306
14220
|
} catch {
|
|
14307
14221
|
}
|
|
@@ -14329,22 +14243,22 @@ async function doctorCommand() {
|
|
|
14329
14243
|
} catch {
|
|
14330
14244
|
}
|
|
14331
14245
|
for (const c of checks) {
|
|
14332
|
-
const icon = c.ok ?
|
|
14333
|
-
const label = c.ok ?
|
|
14334
|
-
const detail = c.detail ?
|
|
14246
|
+
const icon = c.ok ? chalk9.green(" \u2713") : chalk9.yellow(" \u25CB");
|
|
14247
|
+
const label = c.ok ? chalk9.white(c.label) : chalk9.gray(c.label);
|
|
14248
|
+
const detail = c.detail ? chalk9.gray(` \u2014 ${c.detail}`) : "";
|
|
14335
14249
|
console.log(`${icon} ${label}${detail}`);
|
|
14336
14250
|
}
|
|
14337
14251
|
const failures = checks.filter((c) => !c.ok);
|
|
14338
14252
|
console.log();
|
|
14339
14253
|
if (failures.length === 0) {
|
|
14340
|
-
console.log(
|
|
14254
|
+
console.log(chalk9.green(" All checks passed!\n"));
|
|
14341
14255
|
} else {
|
|
14342
14256
|
const critical = failures.filter((c) => c.label.includes("Node") || c.label.includes("API key"));
|
|
14343
14257
|
if (critical.length) {
|
|
14344
|
-
console.log(
|
|
14258
|
+
console.log(chalk9.yellow(` ${critical.length} issue(s) need attention.
|
|
14345
14259
|
`));
|
|
14346
14260
|
} else {
|
|
14347
|
-
console.log(
|
|
14261
|
+
console.log(chalk9.gray(` ${failures.length} optional item(s) not configured.
|
|
14348
14262
|
`));
|
|
14349
14263
|
}
|
|
14350
14264
|
}
|
|
@@ -14371,14 +14285,14 @@ async function updateCommand() {
|
|
|
14371
14285
|
const { stdout } = await execAsync2("npm show cascade-ai version", { timeout: 1e4 });
|
|
14372
14286
|
const latest = stdout.trim().split("\n").filter(Boolean).pop() ?? "";
|
|
14373
14287
|
if (latest === CASCADE_VERSION) {
|
|
14374
|
-
spin.succeed(
|
|
14288
|
+
spin.succeed(chalk9.green(`Already up to date (v${CASCADE_VERSION})`));
|
|
14375
14289
|
return;
|
|
14376
14290
|
}
|
|
14377
14291
|
spin.text = `Updating cascade-ai ${CASCADE_VERSION} \u2192 ${latest}\u2026`;
|
|
14378
14292
|
await execAsync2("npm install -g cascade-ai@latest", { timeout: 6e4 });
|
|
14379
|
-
spin.succeed(
|
|
14293
|
+
spin.succeed(chalk9.green(`Updated to v${latest}! Restart your terminal.`));
|
|
14380
14294
|
} catch (err) {
|
|
14381
|
-
spin.fail(
|
|
14295
|
+
spin.fail(chalk9.red(`Update failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
14382
14296
|
}
|
|
14383
14297
|
}
|
|
14384
14298
|
init_constants();
|
|
@@ -14543,6 +14457,11 @@ var DashboardSocket = class {
|
|
|
14543
14457
|
emitToSocket(socketId, event, data) {
|
|
14544
14458
|
this.io.sockets.sockets.get(socketId)?.emit(event, data);
|
|
14545
14459
|
}
|
|
14460
|
+
onConfigGet(callback) {
|
|
14461
|
+
this.io.on("connection", (socket) => {
|
|
14462
|
+
socket.on("config:get", () => callback(socket.id));
|
|
14463
|
+
});
|
|
14464
|
+
}
|
|
14546
14465
|
onCascadeRun(callback) {
|
|
14547
14466
|
this.io.on("connection", (socket) => {
|
|
14548
14467
|
socket.on("cascade:run", (payload) => {
|
|
@@ -14592,6 +14511,16 @@ var DashboardServer = class {
|
|
|
14592
14511
|
this.socket.onSessionRate((sessionId, rating) => {
|
|
14593
14512
|
this.activeSessions.get(sessionId)?.rateLastRun(rating);
|
|
14594
14513
|
});
|
|
14514
|
+
this.socket.onConfigGet((socketId) => {
|
|
14515
|
+
this.socket.emitToSocket(socketId, "config:current", {
|
|
14516
|
+
models: this.config.models ?? {},
|
|
14517
|
+
budget: {
|
|
14518
|
+
maxCostPerRun: this.config.budget?.maxCostPerRunUsd,
|
|
14519
|
+
autoBias: this.config.autoBias
|
|
14520
|
+
},
|
|
14521
|
+
providersWithKey: (this.config.providers ?? []).filter((p) => typeof p.apiKey === "string" && p.apiKey.length > 0).map((p) => p.type)
|
|
14522
|
+
});
|
|
14523
|
+
});
|
|
14595
14524
|
this.socket.onConfigUpdate((data) => {
|
|
14596
14525
|
if (data.keys) {
|
|
14597
14526
|
for (const [type, apiKey] of Object.entries(data.keys)) {
|
|
@@ -14602,7 +14531,11 @@ var DashboardServer = class {
|
|
|
14602
14531
|
}
|
|
14603
14532
|
}
|
|
14604
14533
|
if (data.models) {
|
|
14605
|
-
|
|
14534
|
+
const models = this.config.models;
|
|
14535
|
+
for (const [tier, val] of Object.entries(data.models)) {
|
|
14536
|
+
if (val && val !== "auto") models[tier] = val;
|
|
14537
|
+
else delete models[tier];
|
|
14538
|
+
}
|
|
14606
14539
|
}
|
|
14607
14540
|
if (data.budget) {
|
|
14608
14541
|
if (typeof data.budget.maxCostPerRun === "number") {
|
|
@@ -14612,6 +14545,7 @@ var DashboardServer = class {
|
|
|
14612
14545
|
this.config.autoBias = data.budget.autoBias;
|
|
14613
14546
|
}
|
|
14614
14547
|
}
|
|
14548
|
+
this.persistConfig();
|
|
14615
14549
|
});
|
|
14616
14550
|
this.socket.onCascadeRun(async (prompt, model, socketId) => {
|
|
14617
14551
|
const sessionId = randomUUID();
|
|
@@ -14688,6 +14622,20 @@ var DashboardServer = class {
|
|
|
14688
14622
|
getSocket() {
|
|
14689
14623
|
return this.socket;
|
|
14690
14624
|
}
|
|
14625
|
+
/**
|
|
14626
|
+
* Write the in-memory config back to the workspace config file so mutations
|
|
14627
|
+
* made over the socket (Settings → Save) persist across restarts. Best-effort:
|
|
14628
|
+
* a write failure is logged but never crashes the running dashboard.
|
|
14629
|
+
*/
|
|
14630
|
+
persistConfig() {
|
|
14631
|
+
try {
|
|
14632
|
+
const configPath = path23.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
14633
|
+
fs21.mkdirSync(path23.dirname(configPath), { recursive: true });
|
|
14634
|
+
fs21.writeFileSync(configPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
14635
|
+
} catch (err) {
|
|
14636
|
+
console.warn(`[dashboard] Failed to persist config: ${err instanceof Error ? err.message : String(err)}`);
|
|
14637
|
+
}
|
|
14638
|
+
}
|
|
14691
14639
|
/**
|
|
14692
14640
|
* Produce a stable dashboard JWT signing secret.
|
|
14693
14641
|
*
|
|
@@ -15187,10 +15135,10 @@ async function dashboardCommand(config, workspacePath = process.cwd()) {
|
|
|
15187
15135
|
process.once("exit", onExit);
|
|
15188
15136
|
try {
|
|
15189
15137
|
await server.start();
|
|
15190
|
-
spin.succeed(
|
|
15138
|
+
spin.succeed(chalk9.green(`Dashboard running at http://localhost:${port}`));
|
|
15191
15139
|
server.refreshRuntime("workspace");
|
|
15192
15140
|
server.refreshRuntime("global");
|
|
15193
|
-
console.log(
|
|
15141
|
+
console.log(chalk9.gray(` Press Ctrl+C to stop
|
|
15194
15142
|
`));
|
|
15195
15143
|
await new Promise(() => {
|
|
15196
15144
|
});
|
|
@@ -15199,7 +15147,7 @@ async function dashboardCommand(config, workspacePath = process.cwd()) {
|
|
|
15199
15147
|
await server.stop().catch(() => {
|
|
15200
15148
|
});
|
|
15201
15149
|
onExit();
|
|
15202
|
-
spin.fail(
|
|
15150
|
+
spin.fail(chalk9.red(`Dashboard failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
15203
15151
|
process.exit(1);
|
|
15204
15152
|
}
|
|
15205
15153
|
}
|
|
@@ -15210,15 +15158,15 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15210
15158
|
const store = new MemoryStore(path23.join(workspacePath, CASCADE_DB_FILE));
|
|
15211
15159
|
try {
|
|
15212
15160
|
const identities = store.listIdentities();
|
|
15213
|
-
console.log(
|
|
15161
|
+
console.log(chalk9.bold("\n Identities:"));
|
|
15214
15162
|
if (identities.length === 0) {
|
|
15215
|
-
console.log(
|
|
15163
|
+
console.log(chalk9.gray(" No identities found."));
|
|
15216
15164
|
} else {
|
|
15217
15165
|
identities.forEach((id) => {
|
|
15218
|
-
const defaultLabel = id.isDefault ?
|
|
15219
|
-
console.log(` - ${
|
|
15220
|
-
console.log(
|
|
15221
|
-
if (id.description) console.log(
|
|
15166
|
+
const defaultLabel = id.isDefault ? chalk9.green(" [Default]") : "";
|
|
15167
|
+
console.log(` - ${chalk9.cyan(id.name)}${defaultLabel}`);
|
|
15168
|
+
console.log(chalk9.gray(` ID: ${id.id}`));
|
|
15169
|
+
if (id.description) console.log(chalk9.gray(` ${id.description}`));
|
|
15222
15170
|
});
|
|
15223
15171
|
}
|
|
15224
15172
|
console.log();
|
|
@@ -15244,9 +15192,9 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15244
15192
|
isDefault: !!options.default,
|
|
15245
15193
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
15246
15194
|
});
|
|
15247
|
-
console.log(
|
|
15195
|
+
console.log(chalk9.green(`
|
|
15248
15196
|
Successfully created identity: ${name} (${id})`));
|
|
15249
|
-
if (options.default) console.log(
|
|
15197
|
+
if (options.default) console.log(chalk9.green(" Set as default."));
|
|
15250
15198
|
console.log();
|
|
15251
15199
|
} finally {
|
|
15252
15200
|
store.close();
|
|
@@ -15258,7 +15206,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15258
15206
|
const identities = store.listIdentities();
|
|
15259
15207
|
const match = identities.find((i) => i.id === query || i.name.toLowerCase() === query.toLowerCase());
|
|
15260
15208
|
if (!match) {
|
|
15261
|
-
console.error(
|
|
15209
|
+
console.error(chalk9.red(`
|
|
15262
15210
|
Identity '${query}' not found.
|
|
15263
15211
|
`));
|
|
15264
15212
|
process.exit(1);
|
|
@@ -15268,7 +15216,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15268
15216
|
store.updateIdentity(existingDefault.id, { isDefault: false });
|
|
15269
15217
|
}
|
|
15270
15218
|
store.updateIdentity(match.id, { isDefault: true });
|
|
15271
|
-
console.log(
|
|
15219
|
+
console.log(chalk9.green(`
|
|
15272
15220
|
Identity ${match.name} is now the default.
|
|
15273
15221
|
`));
|
|
15274
15222
|
} finally {
|
|
@@ -15278,7 +15226,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15278
15226
|
return identity;
|
|
15279
15227
|
}
|
|
15280
15228
|
async function modelsCommand(options = {}) {
|
|
15281
|
-
console.log(
|
|
15229
|
+
console.log(chalk9.magenta("\n \u25C8 Cascade Models\n"));
|
|
15282
15230
|
const cm = new ConfigManager(process.cwd());
|
|
15283
15231
|
await cm.load();
|
|
15284
15232
|
const config = cm.getConfig();
|
|
@@ -15286,16 +15234,16 @@ async function modelsCommand(options = {}) {
|
|
|
15286
15234
|
try {
|
|
15287
15235
|
await router.init(config);
|
|
15288
15236
|
} catch (err) {
|
|
15289
|
-
console.error(
|
|
15237
|
+
console.error(chalk9.red(` Failed to initialize router: ${err instanceof Error ? err.message : String(err)}`));
|
|
15290
15238
|
process.exit(1);
|
|
15291
15239
|
}
|
|
15292
15240
|
await withTimeout(router.refreshLiveData(), 6e3, "live data timeout").catch(() => {
|
|
15293
15241
|
});
|
|
15294
15242
|
const liveData = router.getLiveData();
|
|
15295
15243
|
const tiers = [
|
|
15296
|
-
{ tier: "T1", label: "T1 Administrator", color:
|
|
15297
|
-
{ tier: "T2", label: "T2 Manager", color:
|
|
15298
|
-
{ tier: "T3", label: "T3 Worker", color:
|
|
15244
|
+
{ tier: "T1", label: "T1 Administrator", color: chalk9.hex("#7C6AF7") },
|
|
15245
|
+
{ tier: "T2", label: "T2 Manager", color: chalk9.hex("#5AB4E8") },
|
|
15246
|
+
{ tier: "T3", label: "T3 Worker", color: chalk9.hex("#5AE8A4") }
|
|
15299
15247
|
];
|
|
15300
15248
|
let anyMissing = false;
|
|
15301
15249
|
for (const { tier, label, color } of tiers) {
|
|
@@ -15304,48 +15252,72 @@ async function modelsCommand(options = {}) {
|
|
|
15304
15252
|
const costIn = model.inputCostPer1kTokens === 0 ? "free" : `$${model.inputCostPer1kTokens.toFixed(4)}/1K in`;
|
|
15305
15253
|
const costOut = model.outputCostPer1kTokens === 0 ? "free" : `$${model.outputCostPer1kTokens.toFixed(4)}/1K out`;
|
|
15306
15254
|
const ctx = model.contextWindow >= 1e6 ? `${(model.contextWindow / 1e6).toFixed(1)}M ctx` : `${(model.contextWindow / 1e3).toFixed(0)}K ctx`;
|
|
15307
|
-
const local = model.isLocal ?
|
|
15308
|
-
const vision = model.isVisionCapable ?
|
|
15255
|
+
const local = model.isLocal ? chalk9.gray(" [local]") : "";
|
|
15256
|
+
const vision = model.isVisionCapable ? chalk9.gray(" \u{1F441}") : "";
|
|
15309
15257
|
const bench = Math.round(benchmarkScore01(model, "mixed") * 100);
|
|
15310
15258
|
console.log(
|
|
15311
|
-
` ${color.bold(tier)} ${
|
|
15259
|
+
` ${color.bold(tier)} ${chalk9.white(col(model.name, 24))}${chalk9.gray(col(model.provider, 16))}` + (options.verbose ? `${chalk9.gray(col(ctx, 12))}${chalk9.gray(col(`bench ${bench}/100`, 14))}${chalk9.gray(`${costIn}, ${costOut}`)}` : `${chalk9.gray(col(ctx, 10))}${chalk9.gray(`bench ${bench}/100`)}`) + local + vision
|
|
15312
15260
|
);
|
|
15313
15261
|
} else {
|
|
15314
|
-
console.log(` ${color.bold(tier)} ${
|
|
15262
|
+
console.log(` ${color.bold(tier)} ${chalk9.red("No model available")} ${chalk9.gray(`(check provider config for ${label})`)}`);
|
|
15315
15263
|
anyMissing = true;
|
|
15316
15264
|
}
|
|
15317
15265
|
}
|
|
15318
15266
|
console.log();
|
|
15319
15267
|
const providers = config.providers.map((p) => p.type).join(", ") || "(none)";
|
|
15320
|
-
console.log(
|
|
15268
|
+
console.log(chalk9.gray(` Configured providers: ${providers}`));
|
|
15321
15269
|
if (liveData) {
|
|
15322
15270
|
const src = liveData.getDataSource();
|
|
15323
15271
|
const gen = liveData.getGeneratedAt();
|
|
15324
15272
|
const srcLabel = src === "live" ? "live (just fetched)" : src === "cache" ? "cached" : "bundled";
|
|
15325
|
-
console.log(
|
|
15273
|
+
console.log(chalk9.gray(
|
|
15326
15274
|
` Benchmark data: ${srcLabel}` + (gen ? ` \xB7 updated ${gen.slice(0, 10)}` : "") + ` \xB7 pricing: ${liveData.hasLivePricing() ? "live (OpenRouter)" : "catalog"}`
|
|
15327
15275
|
));
|
|
15328
15276
|
}
|
|
15329
15277
|
if (options.verbose) {
|
|
15330
15278
|
console.log();
|
|
15331
|
-
console.log(
|
|
15279
|
+
console.log(chalk9.white(" Available models by provider:\n"));
|
|
15332
15280
|
const allProviderTypes = [...new Set(config.providers.map((p) => p.type))];
|
|
15333
15281
|
for (const providerType of allProviderTypes) {
|
|
15334
15282
|
const available = router.getModelsForProvider(providerType);
|
|
15335
15283
|
if (available.length === 0) continue;
|
|
15336
|
-
console.log(
|
|
15284
|
+
console.log(chalk9.gray(` ${providerType}:`));
|
|
15337
15285
|
for (const m of available) {
|
|
15338
15286
|
const override = config.models.t1 === m.id ? " \u2190 T1" : config.models.t2 === m.id ? " \u2190 T2" : config.models.t3 === m.id ? " \u2190 T3" : "";
|
|
15339
|
-
console.log(` ${
|
|
15287
|
+
console.log(` ${chalk9.white(col(m.name, 28))}${chalk9.gray(m.id)}${chalk9.yellow(override)}`);
|
|
15340
15288
|
}
|
|
15341
15289
|
console.log();
|
|
15342
15290
|
}
|
|
15343
15291
|
}
|
|
15344
15292
|
if (anyMissing) {
|
|
15345
|
-
console.log(
|
|
15293
|
+
console.log(chalk9.yellow(" Some tiers have no available model. Run `cascade doctor` for details.\n"));
|
|
15346
15294
|
} else {
|
|
15347
|
-
console.log(
|
|
15295
|
+
console.log(chalk9.green(" All tiers are configured.\n"));
|
|
15296
|
+
}
|
|
15297
|
+
}
|
|
15298
|
+
async function setModelCommand(action, tierArg, value) {
|
|
15299
|
+
const tier = (tierArg ?? "").toLowerCase();
|
|
15300
|
+
if (!["t1", "t2", "t3"].includes(tier)) {
|
|
15301
|
+
console.error(chalk9.red(` Invalid tier "${tierArg ?? ""}". Use t1, t2, or t3.`));
|
|
15302
|
+
console.log(chalk9.gray(" e.g. cascade models set t1 anthropic:claude-opus-4-8"));
|
|
15303
|
+
process.exit(1);
|
|
15304
|
+
}
|
|
15305
|
+
const override = action === "unset" ? "auto" : (value ?? "").trim();
|
|
15306
|
+
if (action === "set" && !override) {
|
|
15307
|
+
console.error(chalk9.red(' Missing value. e.g. cascade models set t3 openai:gpt-4o-mini (or "auto")'));
|
|
15308
|
+
process.exit(1);
|
|
15348
15309
|
}
|
|
15310
|
+
const cm = new ConfigManager(process.cwd());
|
|
15311
|
+
await cm.load();
|
|
15312
|
+
const config = cm.getConfig();
|
|
15313
|
+
const models = { ...config.models };
|
|
15314
|
+
if (override === "auto") delete models[tier];
|
|
15315
|
+
else models[tier] = override;
|
|
15316
|
+
await cm.updateConfig({ models });
|
|
15317
|
+
const label = override === "auto" ? chalk9.gray("auto (routing decides)") : chalk9.white(override);
|
|
15318
|
+
console.log(chalk9.green(`
|
|
15319
|
+
\u2713 ${tier.toUpperCase()} model set to ${label}
|
|
15320
|
+
`));
|
|
15349
15321
|
}
|
|
15350
15322
|
function col(s, width) {
|
|
15351
15323
|
return s.length < width ? s.padEnd(width) : `${s} `;
|
|
@@ -15367,7 +15339,7 @@ async function exportCommand(options = {}) {
|
|
|
15367
15339
|
}
|
|
15368
15340
|
store = new MemoryStore(dbPath);
|
|
15369
15341
|
} catch (err) {
|
|
15370
|
-
spin.fail(
|
|
15342
|
+
spin.fail(chalk9.red(`Cannot open memory store: ${err instanceof Error ? err.message : String(err)}`));
|
|
15371
15343
|
process.exit(1);
|
|
15372
15344
|
}
|
|
15373
15345
|
try {
|
|
@@ -15375,7 +15347,7 @@ async function exportCommand(options = {}) {
|
|
|
15375
15347
|
if (options.sessionId) {
|
|
15376
15348
|
const session2 = store.getSession(options.sessionId);
|
|
15377
15349
|
if (!session2) {
|
|
15378
|
-
spin.fail(
|
|
15350
|
+
spin.fail(chalk9.red(`Session "${options.sessionId}" not found.`));
|
|
15379
15351
|
process.exit(1);
|
|
15380
15352
|
}
|
|
15381
15353
|
sessions = [session2];
|
|
@@ -15383,14 +15355,14 @@ async function exportCommand(options = {}) {
|
|
|
15383
15355
|
const limit = options.last ?? 10;
|
|
15384
15356
|
sessions = store.listSessions(void 0, limit);
|
|
15385
15357
|
if (sessions.length === 0) {
|
|
15386
|
-
spin.warn(
|
|
15358
|
+
spin.warn(chalk9.yellow("No sessions found."));
|
|
15387
15359
|
return;
|
|
15388
15360
|
}
|
|
15389
15361
|
const latest = sessions[0];
|
|
15390
15362
|
const full = store.getSession(latest.id);
|
|
15391
15363
|
sessions = full ? [full] : [];
|
|
15392
15364
|
if (sessions.length === 0) {
|
|
15393
|
-
spin.fail(
|
|
15365
|
+
spin.fail(chalk9.red("Could not load latest session."));
|
|
15394
15366
|
process.exit(1);
|
|
15395
15367
|
}
|
|
15396
15368
|
}
|
|
@@ -15402,15 +15374,15 @@ async function exportCommand(options = {}) {
|
|
|
15402
15374
|
const defaultFile = `cascade-export-${safeName}${ext}`;
|
|
15403
15375
|
const outPath = options.output ? path23.resolve(options.output) : path23.join(process.cwd(), defaultFile);
|
|
15404
15376
|
await fs9.writeFile(outPath, content, "utf-8");
|
|
15405
|
-
spin.succeed(
|
|
15377
|
+
spin.succeed(chalk9.green(`Exported to ${chalk9.white(outPath)}`));
|
|
15406
15378
|
const messageCount = Array.isArray(session.messages) ? session.messages.length : 0;
|
|
15407
15379
|
console.log();
|
|
15408
|
-
console.log(
|
|
15409
|
-
console.log(
|
|
15410
|
-
console.log(
|
|
15380
|
+
console.log(chalk9.gray(` Session: ${session.title}`));
|
|
15381
|
+
console.log(chalk9.gray(` Messages: ${messageCount}`));
|
|
15382
|
+
console.log(chalk9.gray(` Format: ${format}`));
|
|
15411
15383
|
console.log();
|
|
15412
15384
|
} catch (err) {
|
|
15413
|
-
spin.fail(
|
|
15385
|
+
spin.fail(chalk9.red(`Export failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
15414
15386
|
process.exit(1);
|
|
15415
15387
|
}
|
|
15416
15388
|
}
|
|
@@ -15467,9 +15439,9 @@ function buildJsonExport(session) {
|
|
|
15467
15439
|
async function linkCommand(target, options = {}) {
|
|
15468
15440
|
const found = await discoverCredentials();
|
|
15469
15441
|
if (found.length === 0) {
|
|
15470
|
-
console.log(
|
|
15471
|
-
console.log(
|
|
15472
|
-
console.log(
|
|
15442
|
+
console.log(chalk9.yellow("\n No reusable credentials found.\n"));
|
|
15443
|
+
console.log(chalk9.gray(" Cascade looks for Claude Code, Codex, Gemini CLI, and GitHub Copilot logins,"));
|
|
15444
|
+
console.log(chalk9.gray(" plus ANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY in your environment.\n"));
|
|
15473
15445
|
return;
|
|
15474
15446
|
}
|
|
15475
15447
|
if (!target) {
|
|
@@ -15478,7 +15450,7 @@ async function linkCommand(target, options = {}) {
|
|
|
15478
15450
|
}
|
|
15479
15451
|
const provider = normalizeProvider(target);
|
|
15480
15452
|
if (!provider) {
|
|
15481
|
-
console.log(
|
|
15453
|
+
console.log(chalk9.red(`
|
|
15482
15454
|
Unknown provider "${target}". Use one of: anthropic, openai, gemini.
|
|
15483
15455
|
`));
|
|
15484
15456
|
return;
|
|
@@ -15486,46 +15458,46 @@ async function linkCommand(target, options = {}) {
|
|
|
15486
15458
|
const candidates2 = found.filter((c) => c.provider === provider);
|
|
15487
15459
|
const chosen = candidates2.find((c) => c.directlyUsable) ?? candidates2[0];
|
|
15488
15460
|
if (!chosen) {
|
|
15489
|
-
console.log(
|
|
15461
|
+
console.log(chalk9.yellow(`
|
|
15490
15462
|
No detected credential maps to "${provider}".
|
|
15491
15463
|
`));
|
|
15492
15464
|
return;
|
|
15493
15465
|
}
|
|
15494
15466
|
if (!chosen.directlyUsable) {
|
|
15495
|
-
console.log(
|
|
15467
|
+
console.log(chalk9.yellow(`
|
|
15496
15468
|
Found a ${chosen.sourceTool} credential, but it can't be used against the standard ${provider} API.`));
|
|
15497
|
-
if (chosen.warning) console.log(
|
|
15498
|
-
console.log(
|
|
15469
|
+
if (chosen.warning) console.log(chalk9.gray(` ${chosen.warning}`));
|
|
15470
|
+
console.log(chalk9.gray(" Cascade won't adopt it because it would create a non-working provider.\n"));
|
|
15499
15471
|
return;
|
|
15500
15472
|
}
|
|
15501
15473
|
if (chosen.kind === "oauth" && !options.acceptRisk) {
|
|
15502
|
-
console.log(
|
|
15474
|
+
console.log(chalk9.yellow(`
|
|
15503
15475
|
${chosen.sourceTool} provides a subscription OAuth token, not an API key.`));
|
|
15504
|
-
if (chosen.warning) console.log(
|
|
15505
|
-
console.log(
|
|
15506
|
-
console.log(
|
|
15476
|
+
if (chosen.warning) console.log(chalk9.gray(` ${chosen.warning}`));
|
|
15477
|
+
console.log(chalk9.gray(" Re-run with --accept-risk to adopt it anyway:\n"));
|
|
15478
|
+
console.log(chalk9.cyan(` cascade link ${provider} --accept-risk
|
|
15507
15479
|
`));
|
|
15508
15480
|
return;
|
|
15509
15481
|
}
|
|
15510
15482
|
await adoptCredential(chosen, options.workspace ?? process.cwd());
|
|
15511
|
-
console.log(
|
|
15483
|
+
console.log(chalk9.green(`
|
|
15512
15484
|
\u2713 Linked ${provider} using your ${chosen.sourceTool} credential (${maskSecret(chosen.secret)}).`));
|
|
15513
15485
|
if (chosen.kind === "oauth") {
|
|
15514
|
-
console.log(
|
|
15486
|
+
console.log(chalk9.gray(" Adopted as an OAuth bearer token \u2014 revoke it in the source tool to disable."));
|
|
15515
15487
|
}
|
|
15516
|
-
console.log(
|
|
15488
|
+
console.log(chalk9.gray(" Run `cascade doctor` to verify, or `cascade` to start.\n"));
|
|
15517
15489
|
}
|
|
15518
15490
|
function printDiscovered(found) {
|
|
15519
|
-
console.log(
|
|
15491
|
+
console.log(chalk9.magenta("\n \u25C8 Detected credentials\n"));
|
|
15520
15492
|
for (const c of found) {
|
|
15521
|
-
const usable = c.directlyUsable ?
|
|
15522
|
-
const kind = c.kind === "oauth" ?
|
|
15523
|
-
console.log(` ${
|
|
15524
|
-
console.log(
|
|
15525
|
-
if (c.warning) console.log(
|
|
15493
|
+
const usable = c.directlyUsable ? chalk9.green("usable") : chalk9.yellow("needs vendor backend");
|
|
15494
|
+
const kind = c.kind === "oauth" ? chalk9.yellow("oauth") : chalk9.gray("api-key");
|
|
15495
|
+
console.log(` ${chalk9.white(c.provider.padEnd(18))} ${chalk9.gray(maskSecret(c.secret).padEnd(12))} ${kind} ${usable}`);
|
|
15496
|
+
console.log(chalk9.gray(` from ${c.sourceTool}`));
|
|
15497
|
+
if (c.warning) console.log(chalk9.yellow(` \u26A0 ${c.warning}`));
|
|
15526
15498
|
}
|
|
15527
|
-
console.log(
|
|
15528
|
-
console.log(
|
|
15499
|
+
console.log(chalk9.gray("\n Adopt one with: ") + chalk9.cyan("cascade link <provider> [--accept-risk]"));
|
|
15500
|
+
console.log(chalk9.gray(" --accept-risk is required for subscription OAuth tokens.\n"));
|
|
15529
15501
|
}
|
|
15530
15502
|
function normalizeProvider(target) {
|
|
15531
15503
|
const t = target.toLowerCase();
|
|
@@ -15558,12 +15530,12 @@ async function telemetryCommand(action) {
|
|
|
15558
15530
|
if (action === "status") {
|
|
15559
15531
|
const state = config.telemetry?.enabled ? "ON" : "OFF";
|
|
15560
15532
|
console.log();
|
|
15561
|
-
console.log(
|
|
15533
|
+
console.log(chalk9.magenta(" \u25C8 Cascade Telemetry"));
|
|
15562
15534
|
console.log();
|
|
15563
|
-
console.log(` Status: ${config.telemetry?.enabled ?
|
|
15564
|
-
console.log(
|
|
15535
|
+
console.log(` Status: ${config.telemetry?.enabled ? chalk9.green(state) : chalk9.gray(state)}`);
|
|
15536
|
+
console.log(chalk9.gray(" Scope: anonymous session metadata only (no prompts/outputs)"));
|
|
15565
15537
|
console.log();
|
|
15566
|
-
console.log(
|
|
15538
|
+
console.log(chalk9.gray(" Toggle with: cascade telemetry on | cascade telemetry off"));
|
|
15567
15539
|
console.log();
|
|
15568
15540
|
return;
|
|
15569
15541
|
}
|
|
@@ -15577,11 +15549,11 @@ async function telemetryCommand(action) {
|
|
|
15577
15549
|
});
|
|
15578
15550
|
console.log();
|
|
15579
15551
|
if (enabled) {
|
|
15580
|
-
console.log(
|
|
15581
|
-
console.log(
|
|
15552
|
+
console.log(chalk9.green(` \u2713 Telemetry enabled.`));
|
|
15553
|
+
console.log(chalk9.gray(" Anonymous session metadata (no prompts, no outputs) will be sent."));
|
|
15582
15554
|
} else {
|
|
15583
|
-
console.log(
|
|
15584
|
-
console.log(
|
|
15555
|
+
console.log(chalk9.yellow(` \u2713 Telemetry disabled.`));
|
|
15556
|
+
console.log(chalk9.gray(" No events will be transmitted from this workspace."));
|
|
15585
15557
|
}
|
|
15586
15558
|
console.log();
|
|
15587
15559
|
}
|
|
@@ -15591,11 +15563,11 @@ async function statsCommand() {
|
|
|
15591
15563
|
await tracker.load();
|
|
15592
15564
|
const all = tracker.getAll();
|
|
15593
15565
|
if (all.size === 0) {
|
|
15594
|
-
console.log(
|
|
15566
|
+
console.log(chalk9.dim("\n No routing history yet \u2014 run some tasks first.\n"));
|
|
15595
15567
|
return;
|
|
15596
15568
|
}
|
|
15597
|
-
console.log(
|
|
15598
|
-
console.log(
|
|
15569
|
+
console.log(chalk9.magenta("\n \u25C8 Auto-Routing History\n"));
|
|
15570
|
+
console.log(chalk9.dim(" Per-task-type model performance learned from past runs.\n"));
|
|
15599
15571
|
for (const taskType of TASK_TYPES) {
|
|
15600
15572
|
const entries = [];
|
|
15601
15573
|
for (const [key, stat] of all) {
|
|
@@ -15607,21 +15579,21 @@ async function statsCommand() {
|
|
|
15607
15579
|
}
|
|
15608
15580
|
if (entries.length === 0) continue;
|
|
15609
15581
|
entries.sort((a, b) => b.successRate - a.successRate || b.samples - a.samples);
|
|
15610
|
-
console.log(
|
|
15582
|
+
console.log(chalk9.bold(` ${taskType.toUpperCase()}`));
|
|
15611
15583
|
const header = ` ${"Model".padEnd(36)} ${"Success".padEnd(9)} ${"Samples".padEnd(9)} Avg cost`;
|
|
15612
|
-
console.log(
|
|
15613
|
-
console.log(
|
|
15584
|
+
console.log(chalk9.dim(header));
|
|
15585
|
+
console.log(chalk9.dim(" " + "\u2500".repeat(62)));
|
|
15614
15586
|
for (const e of entries) {
|
|
15615
15587
|
const pct = `${Math.round(e.successRate * 100)}%`;
|
|
15616
15588
|
const cost = e.avgCostUsd < 1e-4 ? "<$0.0001" : `$${e.avgCostUsd.toFixed(4)}`;
|
|
15617
|
-
const color = e.successRate >= 0.8 ?
|
|
15589
|
+
const color = e.successRate >= 0.8 ? chalk9.green : e.successRate >= 0.5 ? chalk9.yellow : chalk9.red;
|
|
15618
15590
|
console.log(
|
|
15619
|
-
` ${e.modelId.padEnd(36)} ${color(pct.padEnd(9))} ${String(e.samples).padEnd(9)} ${
|
|
15591
|
+
` ${e.modelId.padEnd(36)} ${color(pct.padEnd(9))} ${String(e.samples).padEnd(9)} ${chalk9.dim(cost)}`
|
|
15620
15592
|
);
|
|
15621
15593
|
}
|
|
15622
15594
|
console.log();
|
|
15623
15595
|
}
|
|
15624
|
-
console.log(
|
|
15596
|
+
console.log(chalk9.dim(" tip: use /rate good | bad after a task to improve these scores.\n"));
|
|
15625
15597
|
}
|
|
15626
15598
|
|
|
15627
15599
|
// src/cli/index.ts
|
|
@@ -15636,7 +15608,7 @@ function warnIfBuildIsStale() {
|
|
|
15636
15608
|
if (pkg.name !== "cascade-ai") continue;
|
|
15637
15609
|
if (pkg.version && pkg.version !== CASCADE_VERSION) {
|
|
15638
15610
|
console.error(
|
|
15639
|
-
|
|
15611
|
+
chalk9.yellow(
|
|
15640
15612
|
`\u26A0 Stale build: compiled output is v${CASCADE_VERSION} but the source tree is v${pkg.version}.
|
|
15641
15613
|
Run: npm install && npm run build`
|
|
15642
15614
|
)
|
|
@@ -15704,13 +15676,17 @@ program.command("dashboard").description("Launch the web dashboard").option("-p,
|
|
|
15704
15676
|
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) => {
|
|
15705
15677
|
await runHeadless(prompt, { theme: opts.theme, workspace: process.cwd(), identity: opts.identity });
|
|
15706
15678
|
});
|
|
15707
|
-
program.command("models").description("List
|
|
15708
|
-
|
|
15679
|
+
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) => {
|
|
15680
|
+
if (action === "set" || action === "unset") {
|
|
15681
|
+
await setModelCommand(action, tier, value);
|
|
15682
|
+
} else {
|
|
15683
|
+
await modelsCommand({ verbose: opts.verbose });
|
|
15684
|
+
}
|
|
15709
15685
|
});
|
|
15710
15686
|
program.command("telemetry [action]").description("Toggle anonymous usage telemetry (on | off | status). Default: status").action(async (action) => {
|
|
15711
15687
|
const normalized = (action ?? "status").toLowerCase();
|
|
15712
15688
|
if (normalized !== "on" && normalized !== "off" && normalized !== "status") {
|
|
15713
|
-
console.error(
|
|
15689
|
+
console.error(chalk9.red(`Unknown action: ${action}. Use: on | off | status`));
|
|
15714
15690
|
process.exit(1);
|
|
15715
15691
|
}
|
|
15716
15692
|
await telemetryCommand(normalized);
|
|
@@ -15732,14 +15708,14 @@ async function startRepl(options) {
|
|
|
15732
15708
|
try {
|
|
15733
15709
|
await cm.load();
|
|
15734
15710
|
} catch (err) {
|
|
15735
|
-
console.error(
|
|
15736
|
-
console.error(
|
|
15711
|
+
console.error(chalk9.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
|
|
15712
|
+
console.error(chalk9.gray("Run `cascade init` to set up this directory."));
|
|
15737
15713
|
process.exit(1);
|
|
15738
15714
|
}
|
|
15739
15715
|
let config = cm.getConfig();
|
|
15740
15716
|
const needsSetup = !config.providers?.length || config.providers.every((p) => p.type !== "ollama" && !p.apiKey);
|
|
15741
15717
|
if (needsSetup) {
|
|
15742
|
-
console.log(
|
|
15718
|
+
console.log(chalk9.magenta(" \u25C8 No providers configured \u2014 launching setup wizard\u2026"));
|
|
15743
15719
|
console.log();
|
|
15744
15720
|
config = await runSetupWizard(workspacePath);
|
|
15745
15721
|
await cm.updateConfig(config);
|
|
@@ -15773,24 +15749,24 @@ async function runHeadless(prompt, options) {
|
|
|
15773
15749
|
try {
|
|
15774
15750
|
await cm.load();
|
|
15775
15751
|
} catch (err) {
|
|
15776
|
-
console.error(
|
|
15777
|
-
console.error(
|
|
15752
|
+
console.error(chalk9.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
|
|
15753
|
+
console.error(chalk9.gray("Run `cascade init` to set up this directory."));
|
|
15778
15754
|
process.exit(1);
|
|
15779
15755
|
}
|
|
15780
15756
|
const config = cm.getConfig();
|
|
15781
15757
|
const needsSetup = !config.providers?.length || config.providers.every((p) => p.type !== "ollama" && !p.apiKey);
|
|
15782
15758
|
if (needsSetup) {
|
|
15783
|
-
console.error(
|
|
15759
|
+
console.error(chalk9.red("No providers configured. Run `cascade init` first."));
|
|
15784
15760
|
process.exit(1);
|
|
15785
15761
|
}
|
|
15786
15762
|
const cascade = new Cascade(config, workspacePath);
|
|
15787
15763
|
try {
|
|
15788
15764
|
await cascade.init();
|
|
15789
15765
|
} catch (err) {
|
|
15790
|
-
console.error(
|
|
15766
|
+
console.error(chalk9.red(`Initialization failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
15791
15767
|
process.exit(1);
|
|
15792
15768
|
}
|
|
15793
|
-
console.error(
|
|
15769
|
+
console.error(chalk9.gray(" \u25C8 Running headlessly \u2014 tool approvals are auto-granted."));
|
|
15794
15770
|
let lastProgress = "";
|
|
15795
15771
|
cascade.on("tier:status", (ev) => {
|
|
15796
15772
|
const action = ev?.currentAction?.trim();
|
|
@@ -15798,7 +15774,7 @@ async function runHeadless(prompt, options) {
|
|
|
15798
15774
|
const line = ` \xB7 ${ev.role ?? ""} ${action}`.trimEnd();
|
|
15799
15775
|
if (line === lastProgress) return;
|
|
15800
15776
|
lastProgress = line;
|
|
15801
|
-
console.error(
|
|
15777
|
+
console.error(chalk9.gray(line));
|
|
15802
15778
|
});
|
|
15803
15779
|
try {
|
|
15804
15780
|
const result = await cascade.run({
|
|
@@ -15809,7 +15785,7 @@ async function runHeadless(prompt, options) {
|
|
|
15809
15785
|
});
|
|
15810
15786
|
process.stdout.write(result.output.trimEnd() + "\n");
|
|
15811
15787
|
} catch (err) {
|
|
15812
|
-
console.error(
|
|
15788
|
+
console.error(chalk9.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
15813
15789
|
await cascade.close().catch(() => {
|
|
15814
15790
|
});
|
|
15815
15791
|
process.exit(1);
|
|
@@ -15821,10 +15797,10 @@ async function runHeadless(prompt, options) {
|
|
|
15821
15797
|
function printBanner() {
|
|
15822
15798
|
if (process.stdout.columns < 60) return;
|
|
15823
15799
|
console.log();
|
|
15824
|
-
console.log(
|
|
15825
|
-
console.log(
|
|
15826
|
-
console.log(
|
|
15827
|
-
console.log(
|
|
15800
|
+
console.log(chalk9.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"));
|
|
15801
|
+
console.log(chalk9.hex("#7C6AF7").bold(" \u2551") + chalk9.white.bold(" \u25C8 CASCADE AI") + chalk9.gray(" v" + CASCADE_VERSION + " ") + chalk9.hex("#7C6AF7").bold("\u2551"));
|
|
15802
|
+
console.log(chalk9.hex("#7C6AF7").bold(" \u2551") + chalk9.gray(" Multi-Tier Orchestration ") + chalk9.hex("#7C6AF7").bold("\u2551"));
|
|
15803
|
+
console.log(chalk9.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"));
|
|
15828
15804
|
console.log();
|
|
15829
15805
|
}
|
|
15830
15806
|
program.parse(process.argv);
|