cascade-ai 0.12.2 → 0.12.4
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 +183 -121
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +182 -120
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +36 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +36 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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';
|
|
@@ -3189,15 +3189,15 @@ function SafeTextInput(props) {
|
|
|
3189
3189
|
const displayValue = mask ? mask.repeat(value.length) : value;
|
|
3190
3190
|
let rendered;
|
|
3191
3191
|
if (displayValue.length === 0) {
|
|
3192
|
-
rendered = showCursor && focus ? placeholder.length > 0 ?
|
|
3192
|
+
rendered = showCursor && focus ? placeholder.length > 0 ? chalk9.inverse(placeholder[0]) + chalk9.grey(placeholder.slice(1)) : chalk9.inverse(" ") : placeholder.length > 0 ? chalk9.grey(placeholder) : "";
|
|
3193
3193
|
} else if (!showCursor || !focus) {
|
|
3194
3194
|
rendered = displayValue;
|
|
3195
3195
|
} else {
|
|
3196
3196
|
let out = "";
|
|
3197
3197
|
for (let i = 0; i < displayValue.length; i++) {
|
|
3198
|
-
out += i === cursorOffset ?
|
|
3198
|
+
out += i === cursorOffset ? chalk9.inverse(displayValue[i]) : displayValue[i];
|
|
3199
3199
|
}
|
|
3200
|
-
if (cursorOffset >= displayValue.length) out +=
|
|
3200
|
+
if (cursorOffset >= displayValue.length) out += chalk9.inverse(" ");
|
|
3201
3201
|
rendered = out;
|
|
3202
3202
|
}
|
|
3203
3203
|
return /* @__PURE__ */ jsx(Text, { children: rendered });
|
|
@@ -4047,7 +4047,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
|
|
|
4047
4047
|
}
|
|
4048
4048
|
for (const tier of ["T1", "T2", "T3"]) {
|
|
4049
4049
|
const override = tier === "T1" ? config.models.t1 : tier === "T2" ? config.models.t2 : config.models.t3;
|
|
4050
|
-
if (!override) continue;
|
|
4050
|
+
if (!override || override === "auto") continue;
|
|
4051
4051
|
const model = this.selector.selectForTier(tier, override);
|
|
4052
4052
|
if (!model) {
|
|
4053
4053
|
const knownProviders = ["anthropic", "openai", "gemini", "azure", "openai-compatible", "ollama"];
|
|
@@ -11450,7 +11450,7 @@ function StatusBarInternal({
|
|
|
11450
11450
|
const savedStr = savedUsd > 0 ? ` \xB7 saved $${savedUsd.toFixed(4)}` : "";
|
|
11451
11451
|
const rightStr = ` ${formatTokens(tokens)} \xB7 $${costUsd.toFixed(4)}${savedStr} ${isExecuting ? "\u26A1" : "\xB7"} `;
|
|
11452
11452
|
const gap = Math.max(0, width - leftStr.length - rightStr.length);
|
|
11453
|
-
const line =
|
|
11453
|
+
const line = chalk9.bgHex(theme.colors.primary).hex(theme.colors.background)(chalk9.bold(leftStr) + " ".repeat(gap) + rightStr);
|
|
11454
11454
|
return /* @__PURE__ */ jsx(Text, { children: line });
|
|
11455
11455
|
}
|
|
11456
11456
|
function formatTokens(n) {
|
|
@@ -11861,7 +11861,7 @@ function renderContent(content, theme) {
|
|
|
11861
11861
|
i
|
|
11862
11862
|
);
|
|
11863
11863
|
}
|
|
11864
|
-
const rendered = part.replace(/\*\*(.*?)\*\*/g, (_, t) =>
|
|
11864
|
+
const rendered = part.replace(/\*\*(.*?)\*\*/g, (_, t) => chalk9.bold(t)).replace(/`(.*?)`/g, (_, t) => chalk9.bgHex(theme.colors.border)(t));
|
|
11865
11865
|
return /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: rendered }, i);
|
|
11866
11866
|
});
|
|
11867
11867
|
}
|
|
@@ -14067,20 +14067,20 @@ async function initCommand(workspacePath = process.cwd()) {
|
|
|
14067
14067
|
const mdPath = path23.join(workspacePath, "CASCADE.md");
|
|
14068
14068
|
if (!await fileExists(mdPath)) {
|
|
14069
14069
|
await createDefaultCascadeMd(workspacePath);
|
|
14070
|
-
spin.succeed(
|
|
14070
|
+
spin.succeed(chalk9.green("Created CASCADE.md"));
|
|
14071
14071
|
}
|
|
14072
14072
|
const ignorePath = path23.join(workspacePath, ".cascadeignore");
|
|
14073
14073
|
if (!await fileExists(ignorePath)) {
|
|
14074
14074
|
await createDefaultIgnoreFile(workspacePath);
|
|
14075
|
-
spin.succeed(
|
|
14075
|
+
spin.succeed(chalk9.green("Created .cascadeignore"));
|
|
14076
14076
|
}
|
|
14077
14077
|
spin.stop();
|
|
14078
14078
|
console.log();
|
|
14079
|
-
console.log(
|
|
14079
|
+
console.log(chalk9.magenta(" \u25C8 Cascade AI \u2014 Project initialized"));
|
|
14080
14080
|
console.log();
|
|
14081
14081
|
const configPath = path23.join(workspacePath, CASCADE_CONFIG_FILE);
|
|
14082
14082
|
if (await fileExists(configPath)) {
|
|
14083
|
-
console.log(
|
|
14083
|
+
console.log(chalk9.yellow(" .cascade/config.json already exists \u2014 launching wizard to reconfigure."));
|
|
14084
14084
|
console.log();
|
|
14085
14085
|
}
|
|
14086
14086
|
const config = await runSetupWizard(workspacePath);
|
|
@@ -14088,10 +14088,10 @@ async function initCommand(workspacePath = process.cwd()) {
|
|
|
14088
14088
|
await cm.load();
|
|
14089
14089
|
await cm.updateConfig(config);
|
|
14090
14090
|
console.log();
|
|
14091
|
-
console.log(
|
|
14091
|
+
console.log(chalk9.green(" \u25C8 Setup complete! Run `cascade` to start."));
|
|
14092
14092
|
console.log();
|
|
14093
14093
|
} catch (err) {
|
|
14094
|
-
console.error(
|
|
14094
|
+
console.error(chalk9.red(`Init failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
14095
14095
|
process.exit(1);
|
|
14096
14096
|
}
|
|
14097
14097
|
}
|
|
@@ -14237,7 +14237,7 @@ function maskSecret(secret) {
|
|
|
14237
14237
|
|
|
14238
14238
|
// src/cli/commands/doctor.ts
|
|
14239
14239
|
async function doctorCommand() {
|
|
14240
|
-
console.log(
|
|
14240
|
+
console.log(chalk9.magenta("\n \u25C8 Cascade Doctor \u2014 System Diagnostics\n"));
|
|
14241
14241
|
const checks = [];
|
|
14242
14242
|
const nodeVersion = process.versions.node;
|
|
14243
14243
|
const [major] = nodeVersion.split(".").map(Number);
|
|
@@ -14329,22 +14329,22 @@ async function doctorCommand() {
|
|
|
14329
14329
|
} catch {
|
|
14330
14330
|
}
|
|
14331
14331
|
for (const c of checks) {
|
|
14332
|
-
const icon = c.ok ?
|
|
14333
|
-
const label = c.ok ?
|
|
14334
|
-
const detail = c.detail ?
|
|
14332
|
+
const icon = c.ok ? chalk9.green(" \u2713") : chalk9.yellow(" \u25CB");
|
|
14333
|
+
const label = c.ok ? chalk9.white(c.label) : chalk9.gray(c.label);
|
|
14334
|
+
const detail = c.detail ? chalk9.gray(` \u2014 ${c.detail}`) : "";
|
|
14335
14335
|
console.log(`${icon} ${label}${detail}`);
|
|
14336
14336
|
}
|
|
14337
14337
|
const failures = checks.filter((c) => !c.ok);
|
|
14338
14338
|
console.log();
|
|
14339
14339
|
if (failures.length === 0) {
|
|
14340
|
-
console.log(
|
|
14340
|
+
console.log(chalk9.green(" All checks passed!\n"));
|
|
14341
14341
|
} else {
|
|
14342
14342
|
const critical = failures.filter((c) => c.label.includes("Node") || c.label.includes("API key"));
|
|
14343
14343
|
if (critical.length) {
|
|
14344
|
-
console.log(
|
|
14344
|
+
console.log(chalk9.yellow(` ${critical.length} issue(s) need attention.
|
|
14345
14345
|
`));
|
|
14346
14346
|
} else {
|
|
14347
|
-
console.log(
|
|
14347
|
+
console.log(chalk9.gray(` ${failures.length} optional item(s) not configured.
|
|
14348
14348
|
`));
|
|
14349
14349
|
}
|
|
14350
14350
|
}
|
|
@@ -14371,14 +14371,14 @@ async function updateCommand() {
|
|
|
14371
14371
|
const { stdout } = await execAsync2("npm show cascade-ai version", { timeout: 1e4 });
|
|
14372
14372
|
const latest = stdout.trim().split("\n").filter(Boolean).pop() ?? "";
|
|
14373
14373
|
if (latest === CASCADE_VERSION) {
|
|
14374
|
-
spin.succeed(
|
|
14374
|
+
spin.succeed(chalk9.green(`Already up to date (v${CASCADE_VERSION})`));
|
|
14375
14375
|
return;
|
|
14376
14376
|
}
|
|
14377
14377
|
spin.text = `Updating cascade-ai ${CASCADE_VERSION} \u2192 ${latest}\u2026`;
|
|
14378
14378
|
await execAsync2("npm install -g cascade-ai@latest", { timeout: 6e4 });
|
|
14379
|
-
spin.succeed(
|
|
14379
|
+
spin.succeed(chalk9.green(`Updated to v${latest}! Restart your terminal.`));
|
|
14380
14380
|
} catch (err) {
|
|
14381
|
-
spin.fail(
|
|
14381
|
+
spin.fail(chalk9.red(`Update failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
14382
14382
|
}
|
|
14383
14383
|
}
|
|
14384
14384
|
init_constants();
|
|
@@ -14543,6 +14543,11 @@ var DashboardSocket = class {
|
|
|
14543
14543
|
emitToSocket(socketId, event, data) {
|
|
14544
14544
|
this.io.sockets.sockets.get(socketId)?.emit(event, data);
|
|
14545
14545
|
}
|
|
14546
|
+
onConfigGet(callback) {
|
|
14547
|
+
this.io.on("connection", (socket) => {
|
|
14548
|
+
socket.on("config:get", () => callback(socket.id));
|
|
14549
|
+
});
|
|
14550
|
+
}
|
|
14546
14551
|
onCascadeRun(callback) {
|
|
14547
14552
|
this.io.on("connection", (socket) => {
|
|
14548
14553
|
socket.on("cascade:run", (payload) => {
|
|
@@ -14592,6 +14597,16 @@ var DashboardServer = class {
|
|
|
14592
14597
|
this.socket.onSessionRate((sessionId, rating) => {
|
|
14593
14598
|
this.activeSessions.get(sessionId)?.rateLastRun(rating);
|
|
14594
14599
|
});
|
|
14600
|
+
this.socket.onConfigGet((socketId) => {
|
|
14601
|
+
this.socket.emitToSocket(socketId, "config:current", {
|
|
14602
|
+
models: this.config.models ?? {},
|
|
14603
|
+
budget: {
|
|
14604
|
+
maxCostPerRun: this.config.budget?.maxCostPerRunUsd,
|
|
14605
|
+
autoBias: this.config.autoBias
|
|
14606
|
+
},
|
|
14607
|
+
providersWithKey: (this.config.providers ?? []).filter((p) => typeof p.apiKey === "string" && p.apiKey.length > 0).map((p) => p.type)
|
|
14608
|
+
});
|
|
14609
|
+
});
|
|
14595
14610
|
this.socket.onConfigUpdate((data) => {
|
|
14596
14611
|
if (data.keys) {
|
|
14597
14612
|
for (const [type, apiKey] of Object.entries(data.keys)) {
|
|
@@ -14602,7 +14617,11 @@ var DashboardServer = class {
|
|
|
14602
14617
|
}
|
|
14603
14618
|
}
|
|
14604
14619
|
if (data.models) {
|
|
14605
|
-
|
|
14620
|
+
const models = this.config.models;
|
|
14621
|
+
for (const [tier, val] of Object.entries(data.models)) {
|
|
14622
|
+
if (val && val !== "auto") models[tier] = val;
|
|
14623
|
+
else delete models[tier];
|
|
14624
|
+
}
|
|
14606
14625
|
}
|
|
14607
14626
|
if (data.budget) {
|
|
14608
14627
|
if (typeof data.budget.maxCostPerRun === "number") {
|
|
@@ -14612,6 +14631,7 @@ var DashboardServer = class {
|
|
|
14612
14631
|
this.config.autoBias = data.budget.autoBias;
|
|
14613
14632
|
}
|
|
14614
14633
|
}
|
|
14634
|
+
this.persistConfig();
|
|
14615
14635
|
});
|
|
14616
14636
|
this.socket.onCascadeRun(async (prompt, model, socketId) => {
|
|
14617
14637
|
const sessionId = randomUUID();
|
|
@@ -14688,6 +14708,20 @@ var DashboardServer = class {
|
|
|
14688
14708
|
getSocket() {
|
|
14689
14709
|
return this.socket;
|
|
14690
14710
|
}
|
|
14711
|
+
/**
|
|
14712
|
+
* Write the in-memory config back to the workspace config file so mutations
|
|
14713
|
+
* made over the socket (Settings → Save) persist across restarts. Best-effort:
|
|
14714
|
+
* a write failure is logged but never crashes the running dashboard.
|
|
14715
|
+
*/
|
|
14716
|
+
persistConfig() {
|
|
14717
|
+
try {
|
|
14718
|
+
const configPath = path23.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
14719
|
+
fs21.mkdirSync(path23.dirname(configPath), { recursive: true });
|
|
14720
|
+
fs21.writeFileSync(configPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
14721
|
+
} catch (err) {
|
|
14722
|
+
console.warn(`[dashboard] Failed to persist config: ${err instanceof Error ? err.message : String(err)}`);
|
|
14723
|
+
}
|
|
14724
|
+
}
|
|
14691
14725
|
/**
|
|
14692
14726
|
* Produce a stable dashboard JWT signing secret.
|
|
14693
14727
|
*
|
|
@@ -15187,10 +15221,10 @@ async function dashboardCommand(config, workspacePath = process.cwd()) {
|
|
|
15187
15221
|
process.once("exit", onExit);
|
|
15188
15222
|
try {
|
|
15189
15223
|
await server.start();
|
|
15190
|
-
spin.succeed(
|
|
15224
|
+
spin.succeed(chalk9.green(`Dashboard running at http://localhost:${port}`));
|
|
15191
15225
|
server.refreshRuntime("workspace");
|
|
15192
15226
|
server.refreshRuntime("global");
|
|
15193
|
-
console.log(
|
|
15227
|
+
console.log(chalk9.gray(` Press Ctrl+C to stop
|
|
15194
15228
|
`));
|
|
15195
15229
|
await new Promise(() => {
|
|
15196
15230
|
});
|
|
@@ -15199,7 +15233,7 @@ async function dashboardCommand(config, workspacePath = process.cwd()) {
|
|
|
15199
15233
|
await server.stop().catch(() => {
|
|
15200
15234
|
});
|
|
15201
15235
|
onExit();
|
|
15202
|
-
spin.fail(
|
|
15236
|
+
spin.fail(chalk9.red(`Dashboard failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
15203
15237
|
process.exit(1);
|
|
15204
15238
|
}
|
|
15205
15239
|
}
|
|
@@ -15210,15 +15244,15 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15210
15244
|
const store = new MemoryStore(path23.join(workspacePath, CASCADE_DB_FILE));
|
|
15211
15245
|
try {
|
|
15212
15246
|
const identities = store.listIdentities();
|
|
15213
|
-
console.log(
|
|
15247
|
+
console.log(chalk9.bold("\n Identities:"));
|
|
15214
15248
|
if (identities.length === 0) {
|
|
15215
|
-
console.log(
|
|
15249
|
+
console.log(chalk9.gray(" No identities found."));
|
|
15216
15250
|
} else {
|
|
15217
15251
|
identities.forEach((id) => {
|
|
15218
|
-
const defaultLabel = id.isDefault ?
|
|
15219
|
-
console.log(` - ${
|
|
15220
|
-
console.log(
|
|
15221
|
-
if (id.description) console.log(
|
|
15252
|
+
const defaultLabel = id.isDefault ? chalk9.green(" [Default]") : "";
|
|
15253
|
+
console.log(` - ${chalk9.cyan(id.name)}${defaultLabel}`);
|
|
15254
|
+
console.log(chalk9.gray(` ID: ${id.id}`));
|
|
15255
|
+
if (id.description) console.log(chalk9.gray(` ${id.description}`));
|
|
15222
15256
|
});
|
|
15223
15257
|
}
|
|
15224
15258
|
console.log();
|
|
@@ -15244,9 +15278,9 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15244
15278
|
isDefault: !!options.default,
|
|
15245
15279
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
15246
15280
|
});
|
|
15247
|
-
console.log(
|
|
15281
|
+
console.log(chalk9.green(`
|
|
15248
15282
|
Successfully created identity: ${name} (${id})`));
|
|
15249
|
-
if (options.default) console.log(
|
|
15283
|
+
if (options.default) console.log(chalk9.green(" Set as default."));
|
|
15250
15284
|
console.log();
|
|
15251
15285
|
} finally {
|
|
15252
15286
|
store.close();
|
|
@@ -15258,7 +15292,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15258
15292
|
const identities = store.listIdentities();
|
|
15259
15293
|
const match = identities.find((i) => i.id === query || i.name.toLowerCase() === query.toLowerCase());
|
|
15260
15294
|
if (!match) {
|
|
15261
|
-
console.error(
|
|
15295
|
+
console.error(chalk9.red(`
|
|
15262
15296
|
Identity '${query}' not found.
|
|
15263
15297
|
`));
|
|
15264
15298
|
process.exit(1);
|
|
@@ -15268,7 +15302,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15268
15302
|
store.updateIdentity(existingDefault.id, { isDefault: false });
|
|
15269
15303
|
}
|
|
15270
15304
|
store.updateIdentity(match.id, { isDefault: true });
|
|
15271
|
-
console.log(
|
|
15305
|
+
console.log(chalk9.green(`
|
|
15272
15306
|
Identity ${match.name} is now the default.
|
|
15273
15307
|
`));
|
|
15274
15308
|
} finally {
|
|
@@ -15278,7 +15312,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
|
|
|
15278
15312
|
return identity;
|
|
15279
15313
|
}
|
|
15280
15314
|
async function modelsCommand(options = {}) {
|
|
15281
|
-
console.log(
|
|
15315
|
+
console.log(chalk9.magenta("\n \u25C8 Cascade Models\n"));
|
|
15282
15316
|
const cm = new ConfigManager(process.cwd());
|
|
15283
15317
|
await cm.load();
|
|
15284
15318
|
const config = cm.getConfig();
|
|
@@ -15286,16 +15320,16 @@ async function modelsCommand(options = {}) {
|
|
|
15286
15320
|
try {
|
|
15287
15321
|
await router.init(config);
|
|
15288
15322
|
} catch (err) {
|
|
15289
|
-
console.error(
|
|
15323
|
+
console.error(chalk9.red(` Failed to initialize router: ${err instanceof Error ? err.message : String(err)}`));
|
|
15290
15324
|
process.exit(1);
|
|
15291
15325
|
}
|
|
15292
15326
|
await withTimeout(router.refreshLiveData(), 6e3, "live data timeout").catch(() => {
|
|
15293
15327
|
});
|
|
15294
15328
|
const liveData = router.getLiveData();
|
|
15295
15329
|
const tiers = [
|
|
15296
|
-
{ tier: "T1", label: "T1 Administrator", color:
|
|
15297
|
-
{ tier: "T2", label: "T2 Manager", color:
|
|
15298
|
-
{ tier: "T3", label: "T3 Worker", color:
|
|
15330
|
+
{ tier: "T1", label: "T1 Administrator", color: chalk9.hex("#7C6AF7") },
|
|
15331
|
+
{ tier: "T2", label: "T2 Manager", color: chalk9.hex("#5AB4E8") },
|
|
15332
|
+
{ tier: "T3", label: "T3 Worker", color: chalk9.hex("#5AE8A4") }
|
|
15299
15333
|
];
|
|
15300
15334
|
let anyMissing = false;
|
|
15301
15335
|
for (const { tier, label, color } of tiers) {
|
|
@@ -15304,48 +15338,72 @@ async function modelsCommand(options = {}) {
|
|
|
15304
15338
|
const costIn = model.inputCostPer1kTokens === 0 ? "free" : `$${model.inputCostPer1kTokens.toFixed(4)}/1K in`;
|
|
15305
15339
|
const costOut = model.outputCostPer1kTokens === 0 ? "free" : `$${model.outputCostPer1kTokens.toFixed(4)}/1K out`;
|
|
15306
15340
|
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 ?
|
|
15341
|
+
const local = model.isLocal ? chalk9.gray(" [local]") : "";
|
|
15342
|
+
const vision = model.isVisionCapable ? chalk9.gray(" \u{1F441}") : "";
|
|
15309
15343
|
const bench = Math.round(benchmarkScore01(model, "mixed") * 100);
|
|
15310
15344
|
console.log(
|
|
15311
|
-
` ${color.bold(tier)} ${
|
|
15345
|
+
` ${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
15346
|
);
|
|
15313
15347
|
} else {
|
|
15314
|
-
console.log(` ${color.bold(tier)} ${
|
|
15348
|
+
console.log(` ${color.bold(tier)} ${chalk9.red("No model available")} ${chalk9.gray(`(check provider config for ${label})`)}`);
|
|
15315
15349
|
anyMissing = true;
|
|
15316
15350
|
}
|
|
15317
15351
|
}
|
|
15318
15352
|
console.log();
|
|
15319
15353
|
const providers = config.providers.map((p) => p.type).join(", ") || "(none)";
|
|
15320
|
-
console.log(
|
|
15354
|
+
console.log(chalk9.gray(` Configured providers: ${providers}`));
|
|
15321
15355
|
if (liveData) {
|
|
15322
15356
|
const src = liveData.getDataSource();
|
|
15323
15357
|
const gen = liveData.getGeneratedAt();
|
|
15324
15358
|
const srcLabel = src === "live" ? "live (just fetched)" : src === "cache" ? "cached" : "bundled";
|
|
15325
|
-
console.log(
|
|
15359
|
+
console.log(chalk9.gray(
|
|
15326
15360
|
` Benchmark data: ${srcLabel}` + (gen ? ` \xB7 updated ${gen.slice(0, 10)}` : "") + ` \xB7 pricing: ${liveData.hasLivePricing() ? "live (OpenRouter)" : "catalog"}`
|
|
15327
15361
|
));
|
|
15328
15362
|
}
|
|
15329
15363
|
if (options.verbose) {
|
|
15330
15364
|
console.log();
|
|
15331
|
-
console.log(
|
|
15365
|
+
console.log(chalk9.white(" Available models by provider:\n"));
|
|
15332
15366
|
const allProviderTypes = [...new Set(config.providers.map((p) => p.type))];
|
|
15333
15367
|
for (const providerType of allProviderTypes) {
|
|
15334
15368
|
const available = router.getModelsForProvider(providerType);
|
|
15335
15369
|
if (available.length === 0) continue;
|
|
15336
|
-
console.log(
|
|
15370
|
+
console.log(chalk9.gray(` ${providerType}:`));
|
|
15337
15371
|
for (const m of available) {
|
|
15338
15372
|
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(` ${
|
|
15373
|
+
console.log(` ${chalk9.white(col(m.name, 28))}${chalk9.gray(m.id)}${chalk9.yellow(override)}`);
|
|
15340
15374
|
}
|
|
15341
15375
|
console.log();
|
|
15342
15376
|
}
|
|
15343
15377
|
}
|
|
15344
15378
|
if (anyMissing) {
|
|
15345
|
-
console.log(
|
|
15379
|
+
console.log(chalk9.yellow(" Some tiers have no available model. Run `cascade doctor` for details.\n"));
|
|
15346
15380
|
} else {
|
|
15347
|
-
console.log(
|
|
15381
|
+
console.log(chalk9.green(" All tiers are configured.\n"));
|
|
15382
|
+
}
|
|
15383
|
+
}
|
|
15384
|
+
async function setModelCommand(action, tierArg, value) {
|
|
15385
|
+
const tier = (tierArg ?? "").toLowerCase();
|
|
15386
|
+
if (!["t1", "t2", "t3"].includes(tier)) {
|
|
15387
|
+
console.error(chalk9.red(` Invalid tier "${tierArg ?? ""}". Use t1, t2, or t3.`));
|
|
15388
|
+
console.log(chalk9.gray(" e.g. cascade models set t1 anthropic:claude-opus-4-8"));
|
|
15389
|
+
process.exit(1);
|
|
15390
|
+
}
|
|
15391
|
+
const override = action === "unset" ? "auto" : (value ?? "").trim();
|
|
15392
|
+
if (action === "set" && !override) {
|
|
15393
|
+
console.error(chalk9.red(' Missing value. e.g. cascade models set t3 openai:gpt-4o-mini (or "auto")'));
|
|
15394
|
+
process.exit(1);
|
|
15348
15395
|
}
|
|
15396
|
+
const cm = new ConfigManager(process.cwd());
|
|
15397
|
+
await cm.load();
|
|
15398
|
+
const config = cm.getConfig();
|
|
15399
|
+
const models = { ...config.models };
|
|
15400
|
+
if (override === "auto") delete models[tier];
|
|
15401
|
+
else models[tier] = override;
|
|
15402
|
+
await cm.updateConfig({ models });
|
|
15403
|
+
const label = override === "auto" ? chalk9.gray("auto (routing decides)") : chalk9.white(override);
|
|
15404
|
+
console.log(chalk9.green(`
|
|
15405
|
+
\u2713 ${tier.toUpperCase()} model set to ${label}
|
|
15406
|
+
`));
|
|
15349
15407
|
}
|
|
15350
15408
|
function col(s, width) {
|
|
15351
15409
|
return s.length < width ? s.padEnd(width) : `${s} `;
|
|
@@ -15367,7 +15425,7 @@ async function exportCommand(options = {}) {
|
|
|
15367
15425
|
}
|
|
15368
15426
|
store = new MemoryStore(dbPath);
|
|
15369
15427
|
} catch (err) {
|
|
15370
|
-
spin.fail(
|
|
15428
|
+
spin.fail(chalk9.red(`Cannot open memory store: ${err instanceof Error ? err.message : String(err)}`));
|
|
15371
15429
|
process.exit(1);
|
|
15372
15430
|
}
|
|
15373
15431
|
try {
|
|
@@ -15375,7 +15433,7 @@ async function exportCommand(options = {}) {
|
|
|
15375
15433
|
if (options.sessionId) {
|
|
15376
15434
|
const session2 = store.getSession(options.sessionId);
|
|
15377
15435
|
if (!session2) {
|
|
15378
|
-
spin.fail(
|
|
15436
|
+
spin.fail(chalk9.red(`Session "${options.sessionId}" not found.`));
|
|
15379
15437
|
process.exit(1);
|
|
15380
15438
|
}
|
|
15381
15439
|
sessions = [session2];
|
|
@@ -15383,14 +15441,14 @@ async function exportCommand(options = {}) {
|
|
|
15383
15441
|
const limit = options.last ?? 10;
|
|
15384
15442
|
sessions = store.listSessions(void 0, limit);
|
|
15385
15443
|
if (sessions.length === 0) {
|
|
15386
|
-
spin.warn(
|
|
15444
|
+
spin.warn(chalk9.yellow("No sessions found."));
|
|
15387
15445
|
return;
|
|
15388
15446
|
}
|
|
15389
15447
|
const latest = sessions[0];
|
|
15390
15448
|
const full = store.getSession(latest.id);
|
|
15391
15449
|
sessions = full ? [full] : [];
|
|
15392
15450
|
if (sessions.length === 0) {
|
|
15393
|
-
spin.fail(
|
|
15451
|
+
spin.fail(chalk9.red("Could not load latest session."));
|
|
15394
15452
|
process.exit(1);
|
|
15395
15453
|
}
|
|
15396
15454
|
}
|
|
@@ -15402,15 +15460,15 @@ async function exportCommand(options = {}) {
|
|
|
15402
15460
|
const defaultFile = `cascade-export-${safeName}${ext}`;
|
|
15403
15461
|
const outPath = options.output ? path23.resolve(options.output) : path23.join(process.cwd(), defaultFile);
|
|
15404
15462
|
await fs9.writeFile(outPath, content, "utf-8");
|
|
15405
|
-
spin.succeed(
|
|
15463
|
+
spin.succeed(chalk9.green(`Exported to ${chalk9.white(outPath)}`));
|
|
15406
15464
|
const messageCount = Array.isArray(session.messages) ? session.messages.length : 0;
|
|
15407
15465
|
console.log();
|
|
15408
|
-
console.log(
|
|
15409
|
-
console.log(
|
|
15410
|
-
console.log(
|
|
15466
|
+
console.log(chalk9.gray(` Session: ${session.title}`));
|
|
15467
|
+
console.log(chalk9.gray(` Messages: ${messageCount}`));
|
|
15468
|
+
console.log(chalk9.gray(` Format: ${format}`));
|
|
15411
15469
|
console.log();
|
|
15412
15470
|
} catch (err) {
|
|
15413
|
-
spin.fail(
|
|
15471
|
+
spin.fail(chalk9.red(`Export failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
15414
15472
|
process.exit(1);
|
|
15415
15473
|
}
|
|
15416
15474
|
}
|
|
@@ -15467,9 +15525,9 @@ function buildJsonExport(session) {
|
|
|
15467
15525
|
async function linkCommand(target, options = {}) {
|
|
15468
15526
|
const found = await discoverCredentials();
|
|
15469
15527
|
if (found.length === 0) {
|
|
15470
|
-
console.log(
|
|
15471
|
-
console.log(
|
|
15472
|
-
console.log(
|
|
15528
|
+
console.log(chalk9.yellow("\n No reusable credentials found.\n"));
|
|
15529
|
+
console.log(chalk9.gray(" Cascade looks for Claude Code, Codex, Gemini CLI, and GitHub Copilot logins,"));
|
|
15530
|
+
console.log(chalk9.gray(" plus ANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY in your environment.\n"));
|
|
15473
15531
|
return;
|
|
15474
15532
|
}
|
|
15475
15533
|
if (!target) {
|
|
@@ -15478,7 +15536,7 @@ async function linkCommand(target, options = {}) {
|
|
|
15478
15536
|
}
|
|
15479
15537
|
const provider = normalizeProvider(target);
|
|
15480
15538
|
if (!provider) {
|
|
15481
|
-
console.log(
|
|
15539
|
+
console.log(chalk9.red(`
|
|
15482
15540
|
Unknown provider "${target}". Use one of: anthropic, openai, gemini.
|
|
15483
15541
|
`));
|
|
15484
15542
|
return;
|
|
@@ -15486,46 +15544,46 @@ async function linkCommand(target, options = {}) {
|
|
|
15486
15544
|
const candidates2 = found.filter((c) => c.provider === provider);
|
|
15487
15545
|
const chosen = candidates2.find((c) => c.directlyUsable) ?? candidates2[0];
|
|
15488
15546
|
if (!chosen) {
|
|
15489
|
-
console.log(
|
|
15547
|
+
console.log(chalk9.yellow(`
|
|
15490
15548
|
No detected credential maps to "${provider}".
|
|
15491
15549
|
`));
|
|
15492
15550
|
return;
|
|
15493
15551
|
}
|
|
15494
15552
|
if (!chosen.directlyUsable) {
|
|
15495
|
-
console.log(
|
|
15553
|
+
console.log(chalk9.yellow(`
|
|
15496
15554
|
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(
|
|
15555
|
+
if (chosen.warning) console.log(chalk9.gray(` ${chosen.warning}`));
|
|
15556
|
+
console.log(chalk9.gray(" Cascade won't adopt it because it would create a non-working provider.\n"));
|
|
15499
15557
|
return;
|
|
15500
15558
|
}
|
|
15501
15559
|
if (chosen.kind === "oauth" && !options.acceptRisk) {
|
|
15502
|
-
console.log(
|
|
15560
|
+
console.log(chalk9.yellow(`
|
|
15503
15561
|
${chosen.sourceTool} provides a subscription OAuth token, not an API key.`));
|
|
15504
|
-
if (chosen.warning) console.log(
|
|
15505
|
-
console.log(
|
|
15506
|
-
console.log(
|
|
15562
|
+
if (chosen.warning) console.log(chalk9.gray(` ${chosen.warning}`));
|
|
15563
|
+
console.log(chalk9.gray(" Re-run with --accept-risk to adopt it anyway:\n"));
|
|
15564
|
+
console.log(chalk9.cyan(` cascade link ${provider} --accept-risk
|
|
15507
15565
|
`));
|
|
15508
15566
|
return;
|
|
15509
15567
|
}
|
|
15510
15568
|
await adoptCredential(chosen, options.workspace ?? process.cwd());
|
|
15511
|
-
console.log(
|
|
15569
|
+
console.log(chalk9.green(`
|
|
15512
15570
|
\u2713 Linked ${provider} using your ${chosen.sourceTool} credential (${maskSecret(chosen.secret)}).`));
|
|
15513
15571
|
if (chosen.kind === "oauth") {
|
|
15514
|
-
console.log(
|
|
15572
|
+
console.log(chalk9.gray(" Adopted as an OAuth bearer token \u2014 revoke it in the source tool to disable."));
|
|
15515
15573
|
}
|
|
15516
|
-
console.log(
|
|
15574
|
+
console.log(chalk9.gray(" Run `cascade doctor` to verify, or `cascade` to start.\n"));
|
|
15517
15575
|
}
|
|
15518
15576
|
function printDiscovered(found) {
|
|
15519
|
-
console.log(
|
|
15577
|
+
console.log(chalk9.magenta("\n \u25C8 Detected credentials\n"));
|
|
15520
15578
|
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(
|
|
15579
|
+
const usable = c.directlyUsable ? chalk9.green("usable") : chalk9.yellow("needs vendor backend");
|
|
15580
|
+
const kind = c.kind === "oauth" ? chalk9.yellow("oauth") : chalk9.gray("api-key");
|
|
15581
|
+
console.log(` ${chalk9.white(c.provider.padEnd(18))} ${chalk9.gray(maskSecret(c.secret).padEnd(12))} ${kind} ${usable}`);
|
|
15582
|
+
console.log(chalk9.gray(` from ${c.sourceTool}`));
|
|
15583
|
+
if (c.warning) console.log(chalk9.yellow(` \u26A0 ${c.warning}`));
|
|
15526
15584
|
}
|
|
15527
|
-
console.log(
|
|
15528
|
-
console.log(
|
|
15585
|
+
console.log(chalk9.gray("\n Adopt one with: ") + chalk9.cyan("cascade link <provider> [--accept-risk]"));
|
|
15586
|
+
console.log(chalk9.gray(" --accept-risk is required for subscription OAuth tokens.\n"));
|
|
15529
15587
|
}
|
|
15530
15588
|
function normalizeProvider(target) {
|
|
15531
15589
|
const t = target.toLowerCase();
|
|
@@ -15558,12 +15616,12 @@ async function telemetryCommand(action) {
|
|
|
15558
15616
|
if (action === "status") {
|
|
15559
15617
|
const state = config.telemetry?.enabled ? "ON" : "OFF";
|
|
15560
15618
|
console.log();
|
|
15561
|
-
console.log(
|
|
15619
|
+
console.log(chalk9.magenta(" \u25C8 Cascade Telemetry"));
|
|
15562
15620
|
console.log();
|
|
15563
|
-
console.log(` Status: ${config.telemetry?.enabled ?
|
|
15564
|
-
console.log(
|
|
15621
|
+
console.log(` Status: ${config.telemetry?.enabled ? chalk9.green(state) : chalk9.gray(state)}`);
|
|
15622
|
+
console.log(chalk9.gray(" Scope: anonymous session metadata only (no prompts/outputs)"));
|
|
15565
15623
|
console.log();
|
|
15566
|
-
console.log(
|
|
15624
|
+
console.log(chalk9.gray(" Toggle with: cascade telemetry on | cascade telemetry off"));
|
|
15567
15625
|
console.log();
|
|
15568
15626
|
return;
|
|
15569
15627
|
}
|
|
@@ -15577,11 +15635,11 @@ async function telemetryCommand(action) {
|
|
|
15577
15635
|
});
|
|
15578
15636
|
console.log();
|
|
15579
15637
|
if (enabled) {
|
|
15580
|
-
console.log(
|
|
15581
|
-
console.log(
|
|
15638
|
+
console.log(chalk9.green(` \u2713 Telemetry enabled.`));
|
|
15639
|
+
console.log(chalk9.gray(" Anonymous session metadata (no prompts, no outputs) will be sent."));
|
|
15582
15640
|
} else {
|
|
15583
|
-
console.log(
|
|
15584
|
-
console.log(
|
|
15641
|
+
console.log(chalk9.yellow(` \u2713 Telemetry disabled.`));
|
|
15642
|
+
console.log(chalk9.gray(" No events will be transmitted from this workspace."));
|
|
15585
15643
|
}
|
|
15586
15644
|
console.log();
|
|
15587
15645
|
}
|
|
@@ -15591,11 +15649,11 @@ async function statsCommand() {
|
|
|
15591
15649
|
await tracker.load();
|
|
15592
15650
|
const all = tracker.getAll();
|
|
15593
15651
|
if (all.size === 0) {
|
|
15594
|
-
console.log(
|
|
15652
|
+
console.log(chalk9.dim("\n No routing history yet \u2014 run some tasks first.\n"));
|
|
15595
15653
|
return;
|
|
15596
15654
|
}
|
|
15597
|
-
console.log(
|
|
15598
|
-
console.log(
|
|
15655
|
+
console.log(chalk9.magenta("\n \u25C8 Auto-Routing History\n"));
|
|
15656
|
+
console.log(chalk9.dim(" Per-task-type model performance learned from past runs.\n"));
|
|
15599
15657
|
for (const taskType of TASK_TYPES) {
|
|
15600
15658
|
const entries = [];
|
|
15601
15659
|
for (const [key, stat] of all) {
|
|
@@ -15607,21 +15665,21 @@ async function statsCommand() {
|
|
|
15607
15665
|
}
|
|
15608
15666
|
if (entries.length === 0) continue;
|
|
15609
15667
|
entries.sort((a, b) => b.successRate - a.successRate || b.samples - a.samples);
|
|
15610
|
-
console.log(
|
|
15668
|
+
console.log(chalk9.bold(` ${taskType.toUpperCase()}`));
|
|
15611
15669
|
const header = ` ${"Model".padEnd(36)} ${"Success".padEnd(9)} ${"Samples".padEnd(9)} Avg cost`;
|
|
15612
|
-
console.log(
|
|
15613
|
-
console.log(
|
|
15670
|
+
console.log(chalk9.dim(header));
|
|
15671
|
+
console.log(chalk9.dim(" " + "\u2500".repeat(62)));
|
|
15614
15672
|
for (const e of entries) {
|
|
15615
15673
|
const pct = `${Math.round(e.successRate * 100)}%`;
|
|
15616
15674
|
const cost = e.avgCostUsd < 1e-4 ? "<$0.0001" : `$${e.avgCostUsd.toFixed(4)}`;
|
|
15617
|
-
const color = e.successRate >= 0.8 ?
|
|
15675
|
+
const color = e.successRate >= 0.8 ? chalk9.green : e.successRate >= 0.5 ? chalk9.yellow : chalk9.red;
|
|
15618
15676
|
console.log(
|
|
15619
|
-
` ${e.modelId.padEnd(36)} ${color(pct.padEnd(9))} ${String(e.samples).padEnd(9)} ${
|
|
15677
|
+
` ${e.modelId.padEnd(36)} ${color(pct.padEnd(9))} ${String(e.samples).padEnd(9)} ${chalk9.dim(cost)}`
|
|
15620
15678
|
);
|
|
15621
15679
|
}
|
|
15622
15680
|
console.log();
|
|
15623
15681
|
}
|
|
15624
|
-
console.log(
|
|
15682
|
+
console.log(chalk9.dim(" tip: use /rate good | bad after a task to improve these scores.\n"));
|
|
15625
15683
|
}
|
|
15626
15684
|
|
|
15627
15685
|
// src/cli/index.ts
|
|
@@ -15636,7 +15694,7 @@ function warnIfBuildIsStale() {
|
|
|
15636
15694
|
if (pkg.name !== "cascade-ai") continue;
|
|
15637
15695
|
if (pkg.version && pkg.version !== CASCADE_VERSION) {
|
|
15638
15696
|
console.error(
|
|
15639
|
-
|
|
15697
|
+
chalk9.yellow(
|
|
15640
15698
|
`\u26A0 Stale build: compiled output is v${CASCADE_VERSION} but the source tree is v${pkg.version}.
|
|
15641
15699
|
Run: npm install && npm run build`
|
|
15642
15700
|
)
|
|
@@ -15704,13 +15762,17 @@ program.command("dashboard").description("Launch the web dashboard").option("-p,
|
|
|
15704
15762
|
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
15763
|
await runHeadless(prompt, { theme: opts.theme, workspace: process.cwd(), identity: opts.identity });
|
|
15706
15764
|
});
|
|
15707
|
-
program.command("models").description("List
|
|
15708
|
-
|
|
15765
|
+
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) => {
|
|
15766
|
+
if (action === "set" || action === "unset") {
|
|
15767
|
+
await setModelCommand(action, tier, value);
|
|
15768
|
+
} else {
|
|
15769
|
+
await modelsCommand({ verbose: opts.verbose });
|
|
15770
|
+
}
|
|
15709
15771
|
});
|
|
15710
15772
|
program.command("telemetry [action]").description("Toggle anonymous usage telemetry (on | off | status). Default: status").action(async (action) => {
|
|
15711
15773
|
const normalized = (action ?? "status").toLowerCase();
|
|
15712
15774
|
if (normalized !== "on" && normalized !== "off" && normalized !== "status") {
|
|
15713
|
-
console.error(
|
|
15775
|
+
console.error(chalk9.red(`Unknown action: ${action}. Use: on | off | status`));
|
|
15714
15776
|
process.exit(1);
|
|
15715
15777
|
}
|
|
15716
15778
|
await telemetryCommand(normalized);
|
|
@@ -15732,14 +15794,14 @@ async function startRepl(options) {
|
|
|
15732
15794
|
try {
|
|
15733
15795
|
await cm.load();
|
|
15734
15796
|
} catch (err) {
|
|
15735
|
-
console.error(
|
|
15736
|
-
console.error(
|
|
15797
|
+
console.error(chalk9.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
|
|
15798
|
+
console.error(chalk9.gray("Run `cascade init` to set up this directory."));
|
|
15737
15799
|
process.exit(1);
|
|
15738
15800
|
}
|
|
15739
15801
|
let config = cm.getConfig();
|
|
15740
15802
|
const needsSetup = !config.providers?.length || config.providers.every((p) => p.type !== "ollama" && !p.apiKey);
|
|
15741
15803
|
if (needsSetup) {
|
|
15742
|
-
console.log(
|
|
15804
|
+
console.log(chalk9.magenta(" \u25C8 No providers configured \u2014 launching setup wizard\u2026"));
|
|
15743
15805
|
console.log();
|
|
15744
15806
|
config = await runSetupWizard(workspacePath);
|
|
15745
15807
|
await cm.updateConfig(config);
|
|
@@ -15773,24 +15835,24 @@ async function runHeadless(prompt, options) {
|
|
|
15773
15835
|
try {
|
|
15774
15836
|
await cm.load();
|
|
15775
15837
|
} catch (err) {
|
|
15776
|
-
console.error(
|
|
15777
|
-
console.error(
|
|
15838
|
+
console.error(chalk9.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
|
|
15839
|
+
console.error(chalk9.gray("Run `cascade init` to set up this directory."));
|
|
15778
15840
|
process.exit(1);
|
|
15779
15841
|
}
|
|
15780
15842
|
const config = cm.getConfig();
|
|
15781
15843
|
const needsSetup = !config.providers?.length || config.providers.every((p) => p.type !== "ollama" && !p.apiKey);
|
|
15782
15844
|
if (needsSetup) {
|
|
15783
|
-
console.error(
|
|
15845
|
+
console.error(chalk9.red("No providers configured. Run `cascade init` first."));
|
|
15784
15846
|
process.exit(1);
|
|
15785
15847
|
}
|
|
15786
15848
|
const cascade = new Cascade(config, workspacePath);
|
|
15787
15849
|
try {
|
|
15788
15850
|
await cascade.init();
|
|
15789
15851
|
} catch (err) {
|
|
15790
|
-
console.error(
|
|
15852
|
+
console.error(chalk9.red(`Initialization failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
15791
15853
|
process.exit(1);
|
|
15792
15854
|
}
|
|
15793
|
-
console.error(
|
|
15855
|
+
console.error(chalk9.gray(" \u25C8 Running headlessly \u2014 tool approvals are auto-granted."));
|
|
15794
15856
|
let lastProgress = "";
|
|
15795
15857
|
cascade.on("tier:status", (ev) => {
|
|
15796
15858
|
const action = ev?.currentAction?.trim();
|
|
@@ -15798,7 +15860,7 @@ async function runHeadless(prompt, options) {
|
|
|
15798
15860
|
const line = ` \xB7 ${ev.role ?? ""} ${action}`.trimEnd();
|
|
15799
15861
|
if (line === lastProgress) return;
|
|
15800
15862
|
lastProgress = line;
|
|
15801
|
-
console.error(
|
|
15863
|
+
console.error(chalk9.gray(line));
|
|
15802
15864
|
});
|
|
15803
15865
|
try {
|
|
15804
15866
|
const result = await cascade.run({
|
|
@@ -15809,7 +15871,7 @@ async function runHeadless(prompt, options) {
|
|
|
15809
15871
|
});
|
|
15810
15872
|
process.stdout.write(result.output.trimEnd() + "\n");
|
|
15811
15873
|
} catch (err) {
|
|
15812
|
-
console.error(
|
|
15874
|
+
console.error(chalk9.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
15813
15875
|
await cascade.close().catch(() => {
|
|
15814
15876
|
});
|
|
15815
15877
|
process.exit(1);
|
|
@@ -15821,10 +15883,10 @@ async function runHeadless(prompt, options) {
|
|
|
15821
15883
|
function printBanner() {
|
|
15822
15884
|
if (process.stdout.columns < 60) return;
|
|
15823
15885
|
console.log();
|
|
15824
|
-
console.log(
|
|
15825
|
-
console.log(
|
|
15826
|
-
console.log(
|
|
15827
|
-
console.log(
|
|
15886
|
+
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"));
|
|
15887
|
+
console.log(chalk9.hex("#7C6AF7").bold(" \u2551") + chalk9.white.bold(" \u25C8 CASCADE AI") + chalk9.gray(" v" + CASCADE_VERSION + " ") + chalk9.hex("#7C6AF7").bold("\u2551"));
|
|
15888
|
+
console.log(chalk9.hex("#7C6AF7").bold(" \u2551") + chalk9.gray(" Multi-Tier Orchestration ") + chalk9.hex("#7C6AF7").bold("\u2551"));
|
|
15889
|
+
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
15890
|
console.log();
|
|
15829
15891
|
}
|
|
15830
15892
|
program.parse(process.argv);
|