cascade-ai 0.12.18 → 0.12.20

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.js CHANGED
@@ -4,6 +4,7 @@ import { GoogleGenAI, HarmBlockThreshold, HarmCategory } from '@google/genai';
4
4
  import dns from 'dns';
5
5
  import http, { createServer } from 'http';
6
6
  import https from 'https';
7
+ import zlib from 'zlib';
7
8
  import { Readable } from 'stream';
8
9
  import { render, Box, Text, useStdout, useApp, useInput, Static } from 'ink';
9
10
  import { Command } from 'commander';
@@ -57,7 +58,7 @@ var __export = (target, all) => {
57
58
  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;
58
59
  var init_constants = __esm({
59
60
  "src/constants.ts"() {
60
- CASCADE_VERSION = "0.12.18";
61
+ CASCADE_VERSION = "0.12.20";
61
62
  CASCADE_CONFIG_FILE = ".cascade/config.json";
62
63
  CASCADE_DB_FILE = ".cascade/memory.db";
63
64
  CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
@@ -1164,12 +1165,11 @@ var init_gemini = __esm({
1164
1165
  }
1165
1166
  });
1166
1167
  function preferIpv4Host(url) {
1167
- if (!url) return url;
1168
- return url.replace(/^(https?:\/\/)localhost(?=[:/]|$)/i, "$1127.0.0.1");
1168
+ return url;
1169
1169
  }
1170
- async function nodeHttpFetch(input, init = {}) {
1170
+ async function nodeHttpFetch(input, init = {}, redirectCount = 0) {
1171
1171
  const urlStr = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
1172
- const u = new URL(urlStr);
1172
+ const u = new URL(preferIpv4Host(urlStr) ?? urlStr);
1173
1173
  const lib = u.protocol === "https:" ? https : http;
1174
1174
  const method = (init.method ?? "GET").toUpperCase();
1175
1175
  const headers = {};
@@ -1179,6 +1179,9 @@ async function nodeHttpFetch(input, init = {}) {
1179
1179
  });
1180
1180
  else if (Array.isArray(h)) for (const [k, v] of h) headers[k] = v;
1181
1181
  else if (h) Object.assign(headers, h);
1182
+ if (!Object.keys(headers).some((k) => k.toLowerCase() === "accept-encoding")) {
1183
+ headers["accept-encoding"] = "gzip, deflate, br";
1184
+ }
1182
1185
  const body = init.body == null ? void 0 : typeof init.body === "string" ? init.body : Buffer.from(init.body);
1183
1186
  return new Promise((resolve, reject) => {
1184
1187
  const req = lib.request(
@@ -1190,14 +1193,30 @@ async function nodeHttpFetch(input, init = {}) {
1190
1193
  headers
1191
1194
  },
1192
1195
  (res) => {
1193
- const stream = Readable.toWeb(res);
1196
+ const status = res.statusCode ?? 200;
1197
+ const location = res.headers.location;
1198
+ if (status >= 300 && status < 400 && location && redirectCount < MAX_REDIRECTS) {
1199
+ res.resume();
1200
+ const nextUrl = new URL(location, u).href;
1201
+ const downgrade = status === 303 || (status === 301 || status === 302) && method !== "GET" && method !== "HEAD";
1202
+ const nextInit = downgrade ? { ...init, method: "GET", body: void 0 } : init;
1203
+ resolve(nodeHttpFetch(nextUrl, nextInit, redirectCount + 1));
1204
+ return;
1205
+ }
1206
+ const encoding = (res.headers["content-encoding"] ?? "").toLowerCase();
1207
+ let bodyStream = res;
1208
+ if (encoding === "gzip" || encoding === "x-gzip") bodyStream = res.pipe(zlib.createGunzip());
1209
+ else if (encoding === "deflate") bodyStream = res.pipe(zlib.createInflate());
1210
+ else if (encoding === "br") bodyStream = res.pipe(zlib.createBrotliDecompress());
1211
+ const stream = Readable.toWeb(bodyStream);
1194
1212
  const respHeaders = new Headers();
1195
1213
  for (const [k, v] of Object.entries(res.headers)) {
1214
+ if (k === "content-encoding" || k === "content-length") continue;
1196
1215
  if (Array.isArray(v)) respHeaders.set(k, v.join(", "));
1197
1216
  else if (typeof v === "string") respHeaders.set(k, v);
1198
1217
  }
1199
1218
  resolve(new Response(stream, {
1200
- status: res.statusCode ?? 200,
1219
+ status,
1201
1220
  statusText: res.statusMessage ?? "",
1202
1221
  headers: respHeaders
1203
1222
  }));
@@ -1209,12 +1228,14 @@ async function nodeHttpFetch(input, init = {}) {
1209
1228
  req.end();
1210
1229
  });
1211
1230
  }
1231
+ var MAX_REDIRECTS;
1212
1232
  var init_net = __esm({
1213
1233
  "src/utils/net.ts"() {
1214
1234
  try {
1215
1235
  dns.setDefaultResultOrder("ipv4first");
1216
1236
  } catch {
1217
1237
  }
1238
+ MAX_REDIRECTS = 5;
1218
1239
  }
1219
1240
  });
1220
1241
 
@@ -8918,7 +8939,7 @@ var SsrfBlockedError = class extends Error {
8918
8939
  }
8919
8940
  };
8920
8941
  var ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
8921
- var MAX_REDIRECTS = 5;
8942
+ var MAX_REDIRECTS2 = 5;
8922
8943
  function allowLocal() {
8923
8944
  return process.env["CASCADE_ALLOW_LOCAL_FETCH"] === "1";
8924
8945
  }
@@ -8986,7 +9007,7 @@ async function assertPublicUrl(rawUrl) {
8986
9007
  }
8987
9008
  async function safeFetch(rawUrl, init = {}) {
8988
9009
  let currentUrl = (await assertPublicUrl(rawUrl)).toString();
8989
- for (let i = 0; i <= MAX_REDIRECTS; i++) {
9010
+ for (let i = 0; i <= MAX_REDIRECTS2; i++) {
8990
9011
  const resp = await fetch(currentUrl, { ...init, redirect: "manual" });
8991
9012
  if (resp.status < 300 || resp.status >= 400) return resp;
8992
9013
  const location = resp.headers.get("location");
@@ -8995,7 +9016,7 @@ async function safeFetch(rawUrl, init = {}) {
8995
9016
  await assertPublicUrl(next.toString());
8996
9017
  currentUrl = next.toString();
8997
9018
  }
8998
- throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS}).`);
9019
+ throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS2}).`);
8999
9020
  }
9000
9021
 
9001
9022
  // src/tools/web-fetch.ts
@@ -10945,135 +10966,126 @@ init_ollama();
10945
10966
  init_openai_compatible();
10946
10967
 
10947
10968
  // src/cli/themes/index.ts
10948
- var cascadeTheme = {
10949
- name: "cascade",
10950
- colors: {
10951
- primary: "#7C6AF7",
10952
- // Cascade violet
10953
- secondary: "#A78BFA",
10954
- accent: "#06B6D4",
10955
- // Cyan
10956
- success: "#10B981",
10957
- warning: "#F59E0B",
10958
- error: "#EF4444",
10959
- info: "#3B82F6",
10960
- muted: "#6B7280",
10961
- background: "#0F0F1A",
10962
- foreground: "#E2E8F0",
10963
- border: "#2D2B55",
10964
- t1Color: "#7C6AF7",
10965
- // Violet
10966
- t2Color: "#06B6D4",
10967
- // Cyan
10968
- t3Color: "#10B981"
10969
- // Green
10970
- }
10971
- };
10972
- var darkTheme = {
10973
- name: "dark",
10974
- colors: {
10975
- primary: "#60A5FA",
10976
- secondary: "#818CF8",
10977
- accent: "#34D399",
10978
- success: "#34D399",
10979
- warning: "#FBBF24",
10980
- error: "#F87171",
10981
- info: "#60A5FA",
10982
- muted: "#6B7280",
10983
- background: "#111827",
10984
- foreground: "#F9FAFB",
10985
- border: "#374151",
10986
- t1Color: "#60A5FA",
10987
- t2Color: "#818CF8",
10988
- t3Color: "#34D399"
10989
- }
10990
- };
10991
- var lightTheme = {
10992
- name: "light",
10993
- colors: {
10994
- primary: "#2563EB",
10995
- secondary: "#7C3AED",
10996
- accent: "#0891B2",
10997
- success: "#059669",
10998
- warning: "#D97706",
10999
- error: "#DC2626",
11000
- info: "#2563EB",
11001
- muted: "#6B7280",
11002
- background: "#FFFFFF",
11003
- foreground: "#111827",
11004
- border: "#E5E7EB",
11005
- t1Color: "#2563EB",
11006
- t2Color: "#7C3AED",
11007
- t3Color: "#059669"
11008
- }
11009
- };
11010
- var draculaTheme = {
11011
- name: "dracula",
11012
- colors: {
11013
- primary: "#BD93F9",
11014
- secondary: "#FF79C6",
11015
- accent: "#8BE9FD",
11016
- success: "#50FA7B",
11017
- warning: "#FFB86C",
11018
- error: "#FF5555",
11019
- info: "#8BE9FD",
11020
- muted: "#6272A4",
11021
- background: "#282A36",
11022
- foreground: "#F8F8F2",
11023
- border: "#44475A",
11024
- t1Color: "#BD93F9",
11025
- t2Color: "#FF79C6",
11026
- t3Color: "#50FA7B"
11027
- }
11028
- };
11029
- var nordTheme = {
11030
- name: "nord",
11031
- colors: {
11032
- primary: "#88C0D0",
11033
- secondary: "#81A1C1",
11034
- accent: "#A3BE8C",
11035
- success: "#A3BE8C",
11036
- warning: "#EBCB8B",
11037
- error: "#BF616A",
11038
- info: "#5E81AC",
11039
- muted: "#4C566A",
11040
- background: "#2E3440",
11041
- foreground: "#ECEFF4",
11042
- border: "#3B4252",
11043
- t1Color: "#88C0D0",
11044
- t2Color: "#81A1C1",
11045
- t3Color: "#A3BE8C"
11046
- }
10969
+ function defineTheme(name, colors) {
10970
+ return { name, colors };
10971
+ }
10972
+ var midnightTheme = defineTheme("midnight", {
10973
+ primary: "#8B7CF9",
10974
+ secondary: "#B7AEFF",
10975
+ accent: "#42D3E7",
10976
+ success: "#3DDC97",
10977
+ warning: "#F7B84B",
10978
+ error: "#FF6685",
10979
+ info: "#67A8FF",
10980
+ muted: "#7C819B",
10981
+ background: "#080A12",
10982
+ foreground: "#EDF0FA",
10983
+ border: "#292D42",
10984
+ t1Color: "#F7B84B",
10985
+ t2Color: "#A98BFF",
10986
+ t3Color: "#42D3E7"
10987
+ });
10988
+ var auroraTheme = defineTheme("aurora", {
10989
+ primary: "#6F8CFF",
10990
+ secondary: "#A78BFA",
10991
+ accent: "#45E0B8",
10992
+ success: "#45E0B8",
10993
+ warning: "#FFD166",
10994
+ error: "#FF6B8A",
10995
+ info: "#6FB7FF",
10996
+ muted: "#7890A8",
10997
+ background: "#071019",
10998
+ foreground: "#EAF7F5",
10999
+ border: "#20384A",
11000
+ t1Color: "#FFD166",
11001
+ t2Color: "#8B9CFF",
11002
+ t3Color: "#45E0B8"
11003
+ });
11004
+ var emberTheme = defineTheme("ember", {
11005
+ primary: "#FF8A5B",
11006
+ secondary: "#FFB36B",
11007
+ accent: "#F7C75B",
11008
+ success: "#72D69A",
11009
+ warning: "#F7C75B",
11010
+ error: "#FF647C",
11011
+ info: "#73B7FF",
11012
+ muted: "#9A8078",
11013
+ background: "#120C0B",
11014
+ foreground: "#FFF1E9",
11015
+ border: "#463027",
11016
+ t1Color: "#F7C75B",
11017
+ t2Color: "#FF8A5B",
11018
+ t3Color: "#72D69A"
11019
+ });
11020
+ var tideTheme = defineTheme("tide", {
11021
+ primary: "#4DA8FF",
11022
+ secondary: "#65C7F7",
11023
+ accent: "#51E1D4",
11024
+ success: "#63D9A5",
11025
+ warning: "#F2C879",
11026
+ error: "#F0718B",
11027
+ info: "#4DA8FF",
11028
+ muted: "#71899C",
11029
+ background: "#061017",
11030
+ foreground: "#E8F5FA",
11031
+ border: "#1C3947",
11032
+ t1Color: "#F2C879",
11033
+ t2Color: "#65A8F7",
11034
+ t3Color: "#51E1D4"
11035
+ });
11036
+ var bloomTheme = defineTheme("bloom", {
11037
+ primary: "#C084FC",
11038
+ secondary: "#F08BB4",
11039
+ accent: "#7DD3FC",
11040
+ success: "#6EE7B7",
11041
+ warning: "#FBCB78",
11042
+ error: "#FB7185",
11043
+ info: "#7DD3FC",
11044
+ muted: "#9B83A8",
11045
+ background: "#140D19",
11046
+ foreground: "#F8EEFC",
11047
+ border: "#412B4D",
11048
+ t1Color: "#FBCB78",
11049
+ t2Color: "#C084FC",
11050
+ t3Color: "#7DD3FC"
11051
+ });
11052
+ var daybreakTheme = defineTheme("daybreak", {
11053
+ primary: "#6857D9",
11054
+ secondary: "#826AE6",
11055
+ accent: "#087F91",
11056
+ success: "#087A55",
11057
+ warning: "#A86408",
11058
+ error: "#C83253",
11059
+ info: "#2563A8",
11060
+ muted: "#667085",
11061
+ background: "#F7F7FB",
11062
+ foreground: "#202336",
11063
+ border: "#D9DCE8",
11064
+ t1Color: "#A86408",
11065
+ t2Color: "#6857D9",
11066
+ t3Color: "#087F91"
11067
+ });
11068
+ var canonicalThemes = {
11069
+ midnight: midnightTheme,
11070
+ aurora: auroraTheme,
11071
+ ember: emberTheme,
11072
+ tide: tideTheme,
11073
+ bloom: bloomTheme,
11074
+ daybreak: daybreakTheme
11047
11075
  };
11048
- var solarizedTheme = {
11049
- name: "solarized",
11050
- colors: {
11051
- primary: "#268BD2",
11052
- secondary: "#2AA198",
11053
- accent: "#B58900",
11054
- success: "#859900",
11055
- warning: "#CB4B16",
11056
- error: "#DC322F",
11057
- info: "#268BD2",
11058
- muted: "#657B83",
11059
- background: "#002B36",
11060
- foreground: "#839496",
11061
- border: "#073642",
11062
- t1Color: "#268BD2",
11063
- t2Color: "#2AA198",
11064
- t3Color: "#859900"
11065
- }
11076
+ var THEME_ALIASES = {
11077
+ cascade: "midnight",
11078
+ dark: "aurora",
11079
+ light: "daybreak",
11080
+ dracula: "bloom",
11081
+ nord: "tide",
11082
+ solarized: "ember"
11066
11083
  };
11067
- var themes = /* @__PURE__ */ new Map([
11068
- ["cascade", cascadeTheme],
11069
- ["dark", darkTheme],
11070
- ["light", lightTheme],
11071
- ["dracula", draculaTheme],
11072
- ["nord", nordTheme],
11073
- ["solarized", solarizedTheme]
11074
- ]);
11084
+ function resolveThemeName(name) {
11085
+ return (name in canonicalThemes ? name : THEME_ALIASES[name]) || "midnight";
11086
+ }
11075
11087
  function getTheme(name) {
11076
- return themes.get(name) ?? cascadeTheme;
11088
+ return canonicalThemes[resolveThemeName(name)] ?? midnightTheme;
11077
11089
  }
11078
11090
 
11079
11091
  // src/cli/slash/index.ts
@@ -11327,6 +11339,13 @@ var FIXED_CHROME_ROWS = 1 + // StatusBar
11327
11339
  3;
11328
11340
  var STREAM_TAIL_ROWS = 9;
11329
11341
  var SLASH_PANEL_ROWS = 11;
11342
+ function computeAdaptiveLayoutMode(columns, rows) {
11343
+ const safeColumns = Number.isFinite(columns) && columns > 0 ? columns : 100;
11344
+ const safeRows = Number.isFinite(rows) && rows > 0 ? rows : 40;
11345
+ if (safeColumns < 80 || safeRows < 24) return "narrow";
11346
+ if (safeColumns < 120 || safeRows < 32) return "medium";
11347
+ return "wide";
11348
+ }
11330
11349
  var TREE_ROWS_FULL = 10;
11331
11350
  var TREE_ROWS_COMPACT = 4;
11332
11351
  var TIMELINE_ROWS = 4;
@@ -11586,7 +11605,7 @@ function formatTokens(n) {
11586
11605
  var StatusBar = React2.memo(StatusBarInternal);
11587
11606
  function HintBarInternal({ theme, isExecuting }) {
11588
11607
  if (isExecuting) return null;
11589
- return /* @__PURE__ */ jsx(Box, { paddingLeft: 1, children: /* @__PURE__ */ jsx(Text, { color: theme.colors.accent, dimColor: true, children: "/help \xB7 /clear \xB7 /theme \xB7 /cost \xB7 /model \xB7 /export" }) });
11608
+ return /* @__PURE__ */ jsx(Box, { paddingLeft: 1, children: /* @__PURE__ */ jsx(Text, { color: theme.colors.accent, dimColor: true, children: "/ commands \xB7 \u2191\u2193 history \xB7 Esc cancel \xB7 Ctrl+C exit" }) });
11590
11609
  }
11591
11610
  var HintBar = React2.memo(HintBarInternal);
11592
11611
  function ApprovalPrompt({ request, theme, onDecision }) {
@@ -11910,6 +11929,53 @@ function CostTracker({
11910
11929
  ] })
11911
11930
  ] });
11912
11931
  }
11932
+ function CompactStatus({ theme, activeT2Count, activeT3Count, currentAction, activeTool, isStreaming }) {
11933
+ const activeCount = activeT2Count + activeT3Count;
11934
+ const isActive = isStreaming || activeCount > 0;
11935
+ const rightHint = isActive ? /* @__PURE__ */ jsxs(Text, { color: theme.colors.muted, children: [
11936
+ "T2:",
11937
+ /* @__PURE__ */ jsx(Text, { color: theme.colors.accent, children: activeT2Count }),
11938
+ " T3:",
11939
+ /* @__PURE__ */ jsx(Text, { color: theme.colors.accent, children: activeT3Count })
11940
+ ] }) : /* @__PURE__ */ jsxs(Text, { color: theme.colors.muted, children: [
11941
+ "[",
11942
+ /* @__PURE__ */ jsx(Text, { color: theme.colors.accent, bold: true, children: "tree" }),
11943
+ "]"
11944
+ ] });
11945
+ return /* @__PURE__ */ jsxs(Box, { paddingX: 1, borderStyle: "single", borderTop: false, borderLeft: false, borderRight: false, borderColor: theme.colors.border, children: [
11946
+ /* @__PURE__ */ jsx(Box, { flexGrow: 1, children: isActive ? /* @__PURE__ */ jsxs(Fragment, { children: [
11947
+ /* @__PURE__ */ jsxs(Text, { color: theme.colors.accent, bold: true, children: [
11948
+ /* @__PURE__ */ jsx(Spinner, { type: "hamburger" }),
11949
+ " "
11950
+ ] }),
11951
+ activeTool ? (
11952
+ // Show active tool prominently
11953
+ /* @__PURE__ */ jsxs(Fragment, { children: [
11954
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", bold: true, children: [
11955
+ "\u2699 ",
11956
+ activeTool
11957
+ ] }),
11958
+ currentAction && !currentAction.startsWith("Using tool:") && /* @__PURE__ */ jsxs(Text, { color: theme.colors.muted, children: [
11959
+ " \u2503 ",
11960
+ currentAction.length > 60 ? currentAction.slice(0, 57) + "..." : currentAction
11961
+ ] })
11962
+ ] })
11963
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
11964
+ /* @__PURE__ */ jsx(Text, { color: theme.colors.accent, bold: true, children: activeCount > 0 ? `WORKING: ${activeCount} AGENTS` : "ORCHESTRATING" }),
11965
+ currentAction && /* @__PURE__ */ jsxs(Text, { color: theme.colors.muted, children: [
11966
+ " \u2503 ",
11967
+ currentAction.length > 80 ? currentAction.slice(0, 77) + "..." : currentAction
11968
+ ] })
11969
+ ] })
11970
+ ] }) : /* @__PURE__ */ jsxs(Box, { children: [
11971
+ /* @__PURE__ */ jsx(Text, { color: theme.colors.muted, children: "\u25CF SYSTEM IDLE " }),
11972
+ /* @__PURE__ */ jsx(Text, { color: theme.colors.muted, children: "\u2503 Press " }),
11973
+ /* @__PURE__ */ jsx(Text, { color: theme.colors.accent, bold: true, children: "/" }),
11974
+ /* @__PURE__ */ jsx(Text, { color: theme.colors.muted, children: " for command palette" })
11975
+ ] }) }),
11976
+ /* @__PURE__ */ jsx(Box, { children: rightHint })
11977
+ ] });
11978
+ }
11913
11979
  function ChatMessage({ role, content, theme, timestamp, isStreaming }) {
11914
11980
  const { label, color, prefix } = getRoleStyle(role, theme);
11915
11981
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
@@ -12214,6 +12280,19 @@ function tailLines(text, n) {
12214
12280
  const lines = text.split("\n");
12215
12281
  return lines.slice(-8);
12216
12282
  }
12283
+ function activeTierSummary(root) {
12284
+ const summary = { t2: 0, t3: 0 };
12285
+ const visit = (node) => {
12286
+ if (node.status === "ACTIVE") {
12287
+ if (node.role === "T2") summary.t2 += 1;
12288
+ if (node.role === "T3") summary.t3 += 1;
12289
+ summary.action ??= node.currentAction;
12290
+ }
12291
+ node.children?.forEach(visit);
12292
+ };
12293
+ if (root) visit(root);
12294
+ return summary;
12295
+ }
12217
12296
  function WelcomeBanner({ theme, config, workspacePath, sessionId }) {
12218
12297
  const t1 = config.models?.t1 ?? "auto";
12219
12298
  const t2 = config.models?.t2 ?? "auto";
@@ -13111,13 +13190,15 @@ ${lastUser.content}`;
13111
13190
  };
13112
13191
  }, [stdout]);
13113
13192
  const width = termSize.columns;
13193
+ const adaptiveMode = computeAdaptiveLayoutMode(termSize.columns, termSize.rows);
13114
13194
  const budgetOpts = {
13115
13195
  isTypingCommand,
13116
- showCost: state.showCost,
13117
- showDetails: state.showDetails,
13118
- showComms: state.showComms && state.peerEvents.length > 0
13196
+ showCost: state.showCost && adaptiveMode !== "narrow",
13197
+ showDetails: state.showDetails && adaptiveMode === "wide",
13198
+ showComms: state.showComms && state.peerEvents.length > 0 && adaptiveMode === "wide"
13119
13199
  };
13120
13200
  const liveBudget = computeLiveAreaBudget(termSize.rows, budgetOpts);
13201
+ const tierSummary = activeTierSummary(state.agentTree);
13121
13202
  const transcriptRows = altScreen ? computeTranscriptRows(termSize.rows, liveBudget, { ...budgetOpts, treeVisible: state.agentTree != null }) : 0;
13122
13203
  const transcriptLines = altScreen ? flattenTranscript(state.messages) : [];
13123
13204
  const transcript = altScreen ? windowTranscript(transcriptLines, historyOffset, transcriptRows) : null;
@@ -13207,10 +13288,28 @@ ${lastUser.content}`;
13207
13288
  onClose: () => setIsShowingModels(false)
13208
13289
  }
13209
13290
  ) }),
13210
- /* @__PURE__ */ jsx(AgentTree, { root: state.agentTree, theme, scrollOffset: treeScrollOffset, maxRows: liveBudget.treeMaxRows }),
13211
- state.showComms && liveBudget.commsMaxEvents > 0 && /* @__PURE__ */ jsx(PeerFeed, { events: state.peerEvents, theme, maxRows: liveBudget.commsMaxEvents }),
13212
- state.showDetails && liveBudget.showTimeline && /* @__PURE__ */ jsx(TimelinePanel, { nodes: [...treeNodesRef.current.values()], theme, currentIndex: timelineIndex, onChangeIndex: setTimelineIndex }),
13213
- state.showCost && /* @__PURE__ */ jsx(CostTracker, { theme, totalTokens: state.totalTokens, totalCostUsd: state.totalCostUsd, callsByProvider: state.callsByProvider, callsByTier: state.callsByTier, costByTier: state.costByTier, tokensByTier: state.tokensByTier, compact: liveBudget.costCompact, savedUsd: state.savedUsd, savedPct: state.savedPct }),
13291
+ adaptiveMode === "narrow" && state.agentTree ? /* @__PURE__ */ jsx(
13292
+ CompactStatus,
13293
+ {
13294
+ theme,
13295
+ activeT2Count: tierSummary.t2,
13296
+ activeT3Count: tierSummary.t3,
13297
+ currentAction: tierSummary.action ?? state.agentTree.currentAction,
13298
+ activeTool: state.activeTool,
13299
+ isStreaming: state.isStreaming
13300
+ }
13301
+ ) : /* @__PURE__ */ jsx(
13302
+ AgentTree,
13303
+ {
13304
+ root: state.agentTree,
13305
+ theme,
13306
+ scrollOffset: treeScrollOffset,
13307
+ maxRows: adaptiveMode === "medium" ? Math.min(4, liveBudget.treeMaxRows) : liveBudget.treeMaxRows
13308
+ }
13309
+ ),
13310
+ adaptiveMode === "wide" && state.showComms && liveBudget.commsMaxEvents > 0 && /* @__PURE__ */ jsx(PeerFeed, { events: state.peerEvents, theme, maxRows: liveBudget.commsMaxEvents }),
13311
+ adaptiveMode === "wide" && state.showDetails && liveBudget.showTimeline && /* @__PURE__ */ jsx(TimelinePanel, { nodes: [...treeNodesRef.current.values()], theme, currentIndex: timelineIndex, onChangeIndex: setTimelineIndex }),
13312
+ adaptiveMode !== "narrow" && state.showCost && /* @__PURE__ */ jsx(CostTracker, { theme, totalTokens: state.totalTokens, totalCostUsd: state.totalCostUsd, callsByProvider: state.callsByProvider, callsByTier: state.callsByTier, costByTier: state.costByTier, tokensByTier: state.tokensByTier, compact: liveBudget.costCompact, savedUsd: state.savedUsd, savedPct: state.savedPct }),
13214
13313
  liveBudget.collapsed && (state.showCost || state.showDetails || state.agentTree != null) && /* @__PURE__ */ jsx(Text, { color: theme.colors.muted, dimColor: true, children: " \u25B8 panels collapsed (small terminal)" }),
13215
13314
  state.approvalRequest && /* @__PURE__ */ jsx(ApprovalPrompt, { request: state.approvalRequest, theme, onDecision: (decision) => {
13216
13315
  dispatch({ type: "SET_APPROVAL", request: null });