cascade-ai 0.2.12 → 0.3.0

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
@@ -130,7 +130,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
130
130
  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
131
  var init_constants = __esm({
132
132
  "src/constants.ts"() {
133
- CASCADE_VERSION = "0.2.12";
133
+ CASCADE_VERSION = "0.3.0";
134
134
  CASCADE_CONFIG_FILE = ".cascade/config.json";
135
135
  CASCADE_DB_FILE = ".cascade/memory.db";
136
136
  CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
@@ -1922,8 +1922,8 @@ Original error: ${err.message}`
1922
1922
  upsertRuntimeNode(node) {
1923
1923
  this.enqueueWrite(() => {
1924
1924
  this.db.prepare(`
1925
- INSERT INTO runtime_nodes (tier_id, session_id, parent_id, role, label, status, current_action, progress_pct, updated_at, workspace_path, is_global)
1926
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1925
+ INSERT INTO runtime_nodes (tier_id, session_id, parent_id, role, label, status, current_action, progress_pct, updated_at, workspace_path, is_global, output)
1926
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1927
1927
  ON CONFLICT(tier_id) DO UPDATE SET
1928
1928
  session_id = excluded.session_id,
1929
1929
  parent_id = excluded.parent_id,
@@ -1934,7 +1934,8 @@ Original error: ${err.message}`
1934
1934
  progress_pct = excluded.progress_pct,
1935
1935
  updated_at = excluded.updated_at,
1936
1936
  workspace_path = excluded.workspace_path,
1937
- is_global = excluded.is_global
1937
+ is_global = excluded.is_global,
1938
+ output = excluded.output
1938
1939
  `).run(
1939
1940
  node.tierId,
1940
1941
  node.sessionId,
@@ -1946,7 +1947,8 @@ Original error: ${err.message}`
1946
1947
  node.progressPct ?? null,
1947
1948
  node.updatedAt,
1948
1949
  node.workspacePath ?? null,
1949
- node.isGlobal ? 1 : 0
1950
+ node.isGlobal ? 1 : 0,
1951
+ node.output ?? null
1950
1952
  );
1951
1953
  });
1952
1954
  }
@@ -1967,14 +1969,15 @@ Original error: ${err.message}`
1967
1969
  progressPct: row.progress_pct ?? void 0,
1968
1970
  updatedAt: row.updated_at,
1969
1971
  workspacePath: row.workspace_path ?? void 0,
1970
- isGlobal: row.is_global === 1
1972
+ isGlobal: row.is_global === 1,
1973
+ output: row.output ?? void 0
1971
1974
  }));
1972
1975
  }
1973
1976
  addRuntimeNodeLog(log) {
1974
1977
  this.enqueueWrite(() => {
1975
1978
  this.db.prepare(`
1976
- INSERT INTO runtime_node_logs (id, session_id, tier_id, role, label, status, current_action, progress_pct, timestamp, workspace_path, is_global)
1977
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1979
+ INSERT INTO runtime_node_logs (id, session_id, tier_id, role, label, status, current_action, progress_pct, timestamp, workspace_path, is_global, output)
1980
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1978
1981
  `).run(
1979
1982
  log.id,
1980
1983
  log.sessionId,
@@ -1986,7 +1989,8 @@ Original error: ${err.message}`
1986
1989
  log.progressPct ?? null,
1987
1990
  log.timestamp,
1988
1991
  log.workspacePath ?? null,
1989
- log.isGlobal ? 1 : 0
1992
+ log.isGlobal ? 1 : 0,
1993
+ log.output ?? null
1990
1994
  );
1991
1995
  this.db.prepare(`
1992
1996
  DELETE FROM runtime_node_logs
@@ -2029,7 +2033,8 @@ Original error: ${err.message}`
2029
2033
  progressPct: row.progress_pct ?? void 0,
2030
2034
  timestamp: row.timestamp,
2031
2035
  workspacePath: row.workspace_path ?? void 0,
2032
- isGlobal: row.is_global === 1
2036
+ isGlobal: row.is_global === 1,
2037
+ output: row.output ?? void 0
2033
2038
  }));
2034
2039
  }
2035
2040
  // ── Messages ──────────────────────────────────
@@ -2356,7 +2361,8 @@ Original error: ${err.message}`
2356
2361
  progress_pct INTEGER,
2357
2362
  updated_at TEXT NOT NULL,
2358
2363
  workspace_path TEXT,
2359
- is_global INTEGER NOT NULL DEFAULT 0
2364
+ is_global INTEGER NOT NULL DEFAULT 0,
2365
+ output TEXT
2360
2366
  );
2361
2367
 
2362
2368
  CREATE INDEX IF NOT EXISTS idx_runtime_nodes_session ON runtime_nodes(session_id);
@@ -2373,7 +2379,8 @@ Original error: ${err.message}`
2373
2379
  progress_pct INTEGER,
2374
2380
  timestamp TEXT NOT NULL,
2375
2381
  workspace_path TEXT,
2376
- is_global INTEGER NOT NULL DEFAULT 0
2382
+ is_global INTEGER NOT NULL DEFAULT 0,
2383
+ output TEXT
2377
2384
  );
2378
2385
 
2379
2386
  CREATE TABLE IF NOT EXISTS model_cache (
@@ -2402,6 +2409,14 @@ Original error: ${err.message}`
2402
2409
 
2403
2410
  CREATE INDEX IF NOT EXISTS idx_file_snapshots_session ON file_snapshots(session_id);
2404
2411
  `);
2412
+ try {
2413
+ this.db.exec("ALTER TABLE runtime_nodes ADD COLUMN output TEXT");
2414
+ } catch {
2415
+ }
2416
+ try {
2417
+ this.db.exec("ALTER TABLE runtime_node_logs ADD COLUMN output TEXT");
2418
+ } catch {
2419
+ }
2405
2420
  }
2406
2421
  // ── Deserializers ─────────────────────────────
2407
2422
  deserializeSession(row, messages) {
@@ -3630,7 +3645,7 @@ var BaseTier = class extends EventEmitter__default.default {
3630
3645
  getStatus() {
3631
3646
  return this.status;
3632
3647
  }
3633
- setStatus(status) {
3648
+ setStatus(status, output) {
3634
3649
  this.status = status;
3635
3650
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3636
3651
  const event = {
@@ -3639,7 +3654,8 @@ var BaseTier = class extends EventEmitter__default.default {
3639
3654
  parentId: this.parentId,
3640
3655
  label: this.label,
3641
3656
  status,
3642
- timestamp
3657
+ timestamp,
3658
+ output
3643
3659
  };
3644
3660
  this.emit("status", event);
3645
3661
  this.emit("tier:status", event);
@@ -3665,7 +3681,8 @@ var BaseTier = class extends EventEmitter__default.default {
3665
3681
  status: this.status,
3666
3682
  currentAction: update.currentAction,
3667
3683
  progressPct: update.progressPct,
3668
- timestamp
3684
+ timestamp,
3685
+ output: update.output
3669
3686
  });
3670
3687
  }
3671
3688
  buildMessage(type, to, payload) {
@@ -4046,16 +4063,17 @@ Now execute your subtask using this context where relevant.`
4046
4063
  return this.buildResult("ESCALATED", output, { checksRun, passed, failed }, issues, correctionAttempts);
4047
4064
  }
4048
4065
  }
4049
- this.setStatus("COMPLETED");
4050
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Subtask complete", status: "IN_PROGRESS" });
4066
+ this.setStatus("COMPLETED", output);
4067
+ this.sendStatusUpdate({ progressPct: 100, currentAction: "Subtask complete", status: "IN_PROGRESS", output });
4051
4068
  this.peerBus?.publish(this.id, assignment.subtaskId, output, "COMPLETED");
4052
4069
  return this.buildResult("COMPLETED", output, { checksRun, passed, failed }, issues, correctionAttempts);
4053
4070
  } catch (err) {
4054
4071
  const errMsg = err instanceof Error ? err.message : String(err);
4055
4072
  issues.push(`Execution error: ${errMsg}`);
4056
- this.setStatus("FAILED");
4057
- this.peerBus?.publish(this.id, assignment.subtaskId, errMsg, "FAILED");
4058
- return this.buildResult("ESCALATED", output || errMsg, { checksRun, passed, failed }, issues, correctionAttempts);
4073
+ const finalOutput = output || errMsg;
4074
+ this.setStatus("FAILED", finalOutput);
4075
+ this.peerBus?.publish(this.id, assignment.subtaskId, finalOutput, "FAILED");
4076
+ return this.buildResult("ESCALATED", finalOutput, { checksRun, passed, failed }, issues, correctionAttempts);
4059
4077
  }
4060
4078
  }
4061
4079
  sendToPeer(toId, content) {
@@ -4738,8 +4756,9 @@ var T2Manager = class extends BaseTier {
4738
4756
  const summary = await this.aggregateResults(assignment, t3Results);
4739
4757
  const issues = t3Results.filter((r) => r.status !== "COMPLETED").flatMap((r) => r.issues);
4740
4758
  const overallStatus = this.determineStatus(t3Results);
4741
- this.setStatus(overallStatus === "COMPLETED" ? "COMPLETED" : "FAILED");
4742
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Section complete", status: "IN_PROGRESS" });
4759
+ const isOk = overallStatus === "COMPLETED" || overallStatus === "PARTIAL";
4760
+ this.setStatus(isOk ? "COMPLETED" : "FAILED", summary);
4761
+ this.sendStatusUpdate({ progressPct: 100, currentAction: "Section complete", status: "IN_PROGRESS", output: summary });
4743
4762
  const result = {
4744
4763
  sectionId: assignment.sectionId,
4745
4764
  sectionTitle: assignment.sectionTitle,
@@ -4752,7 +4771,7 @@ var T2Manager = class extends BaseTier {
4752
4771
  return result;
4753
4772
  } catch (err) {
4754
4773
  const errMsg = err instanceof Error ? err.message : String(err);
4755
- this.setStatus("FAILED");
4774
+ this.setStatus("FAILED", errMsg);
4756
4775
  const failedResult = {
4757
4776
  sectionId: assignment.sectionId,
4758
4777
  sectionTitle: assignment.sectionTitle,
@@ -5317,8 +5336,8 @@ Create a CORRECTION PLAN that contains only the new sections needed to fix the i
5317
5336
  status: "IN_PROGRESS"
5318
5337
  });
5319
5338
  const output = await this.compileFinalOutput(userPrompt, plan, allT2Results);
5320
- this.setStatus("COMPLETED");
5321
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Task complete", status: "IN_PROGRESS" });
5339
+ this.setStatus("COMPLETED", output);
5340
+ this.sendStatusUpdate({ progressPct: 100, currentAction: "Task complete", status: "IN_PROGRESS", output });
5322
5341
  return { output, t2Results: allT2Results, taskId: this.taskId, complexity: plan.complexity };
5323
5342
  }
5324
5343
  getEscalations() {
@@ -8275,35 +8294,69 @@ function AgentTree({ root, theme }) {
8275
8294
  }
8276
8295
  function T2Row({ node, theme, isLast }) {
8277
8296
  const connector = isLast ? "\u2514\u2500 " : "\u251C\u2500 ";
8278
- const t3Active = countByRoleAndStatus(node, "T3", "ACTIVE");
8279
- const t3Total = countByRole(node, "T3");
8280
- const workerSuffix = t3Total > 0 ? ` T3\xD7${t3Total}` : "";
8297
+ const t3Nodes = (node.children ?? []).filter((c) => c.role === "T3");
8298
+ const t3ActiveCount = t3Nodes.filter((c) => c.status === "ACTIVE").length;
8281
8299
  const label = stripRolePrefix(node.label, node.role);
8282
8300
  const action = node.currentAction ? ` ${node.currentAction.slice(0, 38)}` : "";
8301
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [
8302
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { children: [
8303
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.muted, children: [
8304
+ " ",
8305
+ connector
8306
+ ] }),
8307
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.t2Color, bold: true, children: "[T2]" }),
8308
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.foreground, children: [
8309
+ " ",
8310
+ label
8311
+ ] }),
8312
+ node.status === "ACTIVE" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8313
+ action ? /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.muted, children: action }) : null,
8314
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }),
8315
+ /* @__PURE__ */ jsxRuntime.jsx(Spinner__default.default, { type: "dots" }),
8316
+ t3ActiveCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.muted, children: [
8317
+ " (",
8318
+ t3ActiveCount,
8319
+ " running)"
8320
+ ] }) : null
8321
+ ] }),
8322
+ node.status === "COMPLETED" && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.success, children: " \u2714" }),
8323
+ node.status === "FAILED" && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.error, children: " \u2718" }),
8324
+ node.status === "ESCALATED" && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.warning, children: " \u25B2" })
8325
+ ] }),
8326
+ t3Nodes.map((t3, idx) => /* @__PURE__ */ jsxRuntime.jsx(
8327
+ T3Row,
8328
+ {
8329
+ node: t3,
8330
+ theme,
8331
+ isLast: idx === t3Nodes.length - 1,
8332
+ parentIsLast: isLast
8333
+ },
8334
+ t3.id
8335
+ ))
8336
+ ] });
8337
+ }
8338
+ function T3Row({ node, theme, isLast, parentIsLast }) {
8339
+ const indent = parentIsLast ? " " : " \u2502 ";
8340
+ const connector = isLast ? "\u2514\u2500 " : "\u251C\u2500 ";
8341
+ const label = stripRolePrefix(node.label, node.role);
8342
+ const action = node.currentAction ? ` ${node.currentAction.slice(0, 42)}` : "";
8283
8343
  return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { children: [
8284
8344
  /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.muted, children: [
8285
- " ",
8345
+ indent,
8286
8346
  connector
8287
8347
  ] }),
8288
- /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.t2Color, bold: true, children: "[T2]" }),
8289
- /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.foreground, children: [
8348
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.t3Color, children: "[T3]" }),
8349
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.muted, children: [
8290
8350
  " ",
8291
8351
  label
8292
8352
  ] }),
8293
- workerSuffix ? /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.muted, children: workerSuffix }) : null,
8294
8353
  node.status === "ACTIVE" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8295
8354
  action ? /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.muted, children: action }) : null,
8296
8355
  /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: " " }),
8297
- /* @__PURE__ */ jsxRuntime.jsx(Spinner__default.default, { type: "dots" }),
8298
- t3Active > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.muted, children: [
8299
- " (",
8300
- t3Active,
8301
- " running)"
8302
- ] }) : null
8356
+ /* @__PURE__ */ jsxRuntime.jsx(Spinner__default.default, { type: "dots" })
8303
8357
  ] }),
8304
8358
  node.status === "COMPLETED" && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.success, children: " \u2714" }),
8305
- node.status === "FAILED" && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.error, children: " \u2718" }),
8306
- node.status === "ESCALATED" && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.warning, children: " \u25B2" })
8359
+ node.status === "FAILED" && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.error, children: " \u2718" })
8307
8360
  ] });
8308
8361
  }
8309
8362
  function hasActiveOrFailed(node) {
@@ -8915,7 +8968,7 @@ function Repl({ config, workspacePath, themeName, initialPrompt, identityName })
8915
8968
  treeNodesRef.current.set(event.tierId, node);
8916
8969
  const store = storeRef.current;
8917
8970
  if (store) {
8918
- const runtimeNode = { tierId: node.id, sessionId: sessionIdRef.current, parentId: node.parentId, role: node.role, label: node.label, status: node.status, currentAction: node.currentAction, progressPct: node.progressPct, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), workspacePath, isGlobal: false };
8971
+ const runtimeNode = { tierId: node.id, sessionId: sessionIdRef.current, parentId: node.parentId, role: node.role, label: node.label, status: node.status, currentAction: node.currentAction, progressPct: node.progressPct, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), workspacePath, isGlobal: false, output: event.output };
8919
8972
  store.upsertRuntimeNode(runtimeNode);
8920
8973
  globalStoreRef.current?.upsertRuntimeNode({ ...runtimeNode, isGlobal: true });
8921
8974
  }
@@ -8926,7 +8979,6 @@ function Repl({ config, workspacePath, themeName, initialPrompt, identityName })
8926
8979
  React5.useEffect(() => {
8927
8980
  const originalWarn = console.warn;
8928
8981
  const originalLog = console.log;
8929
- process.stdout.write("\x1Bc");
8930
8982
  console.warn = (...args) => {
8931
8983
  const msg = args.join(" ");
8932
8984
  if (msg.includes("non-text parts") || msg.includes("functionCall")) return;
@@ -11036,8 +11088,8 @@ var DashboardServer = class {
11036
11088
  void (async () => {
11037
11089
  const cascade = new Cascade(this.config, this.workspacePath, this.store);
11038
11090
  cascade.on("stream:token", (e) => {
11039
- this.socket.broadcast("stream:token", { sessionId, token: e.text });
11040
- this.socket.broadcastToRoom(`session:${sessionId}`, "stream:token", { sessionId, token: e.text });
11091
+ this.socket.broadcast("stream:token", { sessionId, tierId: e.tierId, text: e.text });
11092
+ this.socket.broadcastToRoom(`session:${sessionId}`, "stream:token", { sessionId, tierId: e.tierId, text: e.text });
11041
11093
  });
11042
11094
  cascade.on("tier:status", (e) => {
11043
11095
  this.socket.broadcast("tier:status", { sessionId, ...e });
@@ -11473,6 +11525,9 @@ async function startRepl(options) {
11473
11525
  await cm.load();
11474
11526
  config = cm.getConfig();
11475
11527
  }
11528
+ if (process.stdout.isTTY) {
11529
+ process.stdout.write("\x1B[2J\x1B[H");
11530
+ }
11476
11531
  const { waitUntilExit } = ink.render(
11477
11532
  React5__default.default.createElement(Repl, {
11478
11533
  config,