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.cjs CHANGED
@@ -6,6 +6,7 @@ var genai = require('@google/genai');
6
6
  var dns = require('dns');
7
7
  var http = require('http');
8
8
  var https = require('https');
9
+ var zlib = require('zlib');
9
10
  var stream = require('stream');
10
11
  var ink = require('ink');
11
12
  var commander = require('commander');
@@ -69,6 +70,7 @@ var OpenAI__default = /*#__PURE__*/_interopDefault(OpenAI);
69
70
  var dns__default = /*#__PURE__*/_interopDefault(dns);
70
71
  var http__default = /*#__PURE__*/_interopDefault(http);
71
72
  var https__default = /*#__PURE__*/_interopDefault(https);
73
+ var zlib__default = /*#__PURE__*/_interopDefault(zlib);
72
74
  var React2__default = /*#__PURE__*/_interopDefault(React2);
73
75
  var chalk9__default = /*#__PURE__*/_interopDefault(chalk9);
74
76
  var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
@@ -107,7 +109,7 @@ var __export = (target, all) => {
107
109
  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;
108
110
  var init_constants = __esm({
109
111
  "src/constants.ts"() {
110
- CASCADE_VERSION = "0.12.18";
112
+ CASCADE_VERSION = "0.12.20";
111
113
  CASCADE_CONFIG_FILE = ".cascade/config.json";
112
114
  CASCADE_DB_FILE = ".cascade/memory.db";
113
115
  CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
@@ -1214,12 +1216,11 @@ var init_gemini = __esm({
1214
1216
  }
1215
1217
  });
1216
1218
  function preferIpv4Host(url) {
1217
- if (!url) return url;
1218
- return url.replace(/^(https?:\/\/)localhost(?=[:/]|$)/i, "$1127.0.0.1");
1219
+ return url;
1219
1220
  }
1220
- async function nodeHttpFetch(input, init = {}) {
1221
+ async function nodeHttpFetch(input, init = {}, redirectCount = 0) {
1221
1222
  const urlStr = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
1222
- const u = new URL(urlStr);
1223
+ const u = new URL(preferIpv4Host(urlStr) ?? urlStr);
1223
1224
  const lib = u.protocol === "https:" ? https__default.default : http__default.default;
1224
1225
  const method = (init.method ?? "GET").toUpperCase();
1225
1226
  const headers = {};
@@ -1229,6 +1230,9 @@ async function nodeHttpFetch(input, init = {}) {
1229
1230
  });
1230
1231
  else if (Array.isArray(h)) for (const [k, v] of h) headers[k] = v;
1231
1232
  else if (h) Object.assign(headers, h);
1233
+ if (!Object.keys(headers).some((k) => k.toLowerCase() === "accept-encoding")) {
1234
+ headers["accept-encoding"] = "gzip, deflate, br";
1235
+ }
1232
1236
  const body = init.body == null ? void 0 : typeof init.body === "string" ? init.body : Buffer.from(init.body);
1233
1237
  return new Promise((resolve, reject) => {
1234
1238
  const req = lib.request(
@@ -1240,14 +1244,30 @@ async function nodeHttpFetch(input, init = {}) {
1240
1244
  headers
1241
1245
  },
1242
1246
  (res) => {
1243
- const stream$1 = stream.Readable.toWeb(res);
1247
+ const status = res.statusCode ?? 200;
1248
+ const location = res.headers.location;
1249
+ if (status >= 300 && status < 400 && location && redirectCount < MAX_REDIRECTS) {
1250
+ res.resume();
1251
+ const nextUrl = new URL(location, u).href;
1252
+ const downgrade = status === 303 || (status === 301 || status === 302) && method !== "GET" && method !== "HEAD";
1253
+ const nextInit = downgrade ? { ...init, method: "GET", body: void 0 } : init;
1254
+ resolve(nodeHttpFetch(nextUrl, nextInit, redirectCount + 1));
1255
+ return;
1256
+ }
1257
+ const encoding = (res.headers["content-encoding"] ?? "").toLowerCase();
1258
+ let bodyStream = res;
1259
+ if (encoding === "gzip" || encoding === "x-gzip") bodyStream = res.pipe(zlib__default.default.createGunzip());
1260
+ else if (encoding === "deflate") bodyStream = res.pipe(zlib__default.default.createInflate());
1261
+ else if (encoding === "br") bodyStream = res.pipe(zlib__default.default.createBrotliDecompress());
1262
+ const stream$1 = stream.Readable.toWeb(bodyStream);
1244
1263
  const respHeaders = new Headers();
1245
1264
  for (const [k, v] of Object.entries(res.headers)) {
1265
+ if (k === "content-encoding" || k === "content-length") continue;
1246
1266
  if (Array.isArray(v)) respHeaders.set(k, v.join(", "));
1247
1267
  else if (typeof v === "string") respHeaders.set(k, v);
1248
1268
  }
1249
1269
  resolve(new Response(stream$1, {
1250
- status: res.statusCode ?? 200,
1270
+ status,
1251
1271
  statusText: res.statusMessage ?? "",
1252
1272
  headers: respHeaders
1253
1273
  }));
@@ -1259,12 +1279,14 @@ async function nodeHttpFetch(input, init = {}) {
1259
1279
  req.end();
1260
1280
  });
1261
1281
  }
1282
+ var MAX_REDIRECTS;
1262
1283
  var init_net = __esm({
1263
1284
  "src/utils/net.ts"() {
1264
1285
  try {
1265
1286
  dns__default.default.setDefaultResultOrder("ipv4first");
1266
1287
  } catch {
1267
1288
  }
1289
+ MAX_REDIRECTS = 5;
1268
1290
  }
1269
1291
  });
1270
1292
 
@@ -8968,7 +8990,7 @@ var SsrfBlockedError = class extends Error {
8968
8990
  }
8969
8991
  };
8970
8992
  var ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
8971
- var MAX_REDIRECTS = 5;
8993
+ var MAX_REDIRECTS2 = 5;
8972
8994
  function allowLocal() {
8973
8995
  return process.env["CASCADE_ALLOW_LOCAL_FETCH"] === "1";
8974
8996
  }
@@ -9036,7 +9058,7 @@ async function assertPublicUrl(rawUrl) {
9036
9058
  }
9037
9059
  async function safeFetch(rawUrl, init = {}) {
9038
9060
  let currentUrl = (await assertPublicUrl(rawUrl)).toString();
9039
- for (let i = 0; i <= MAX_REDIRECTS; i++) {
9061
+ for (let i = 0; i <= MAX_REDIRECTS2; i++) {
9040
9062
  const resp = await fetch(currentUrl, { ...init, redirect: "manual" });
9041
9063
  if (resp.status < 300 || resp.status >= 400) return resp;
9042
9064
  const location = resp.headers.get("location");
@@ -9045,7 +9067,7 @@ async function safeFetch(rawUrl, init = {}) {
9045
9067
  await assertPublicUrl(next.toString());
9046
9068
  currentUrl = next.toString();
9047
9069
  }
9048
- throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS}).`);
9070
+ throw new SsrfBlockedError(`Too many redirects (>${MAX_REDIRECTS2}).`);
9049
9071
  }
9050
9072
 
9051
9073
  // src/tools/web-fetch.ts
@@ -10995,135 +11017,126 @@ init_ollama();
10995
11017
  init_openai_compatible();
10996
11018
 
10997
11019
  // src/cli/themes/index.ts
10998
- var cascadeTheme = {
10999
- name: "cascade",
11000
- colors: {
11001
- primary: "#7C6AF7",
11002
- // Cascade violet
11003
- secondary: "#A78BFA",
11004
- accent: "#06B6D4",
11005
- // Cyan
11006
- success: "#10B981",
11007
- warning: "#F59E0B",
11008
- error: "#EF4444",
11009
- info: "#3B82F6",
11010
- muted: "#6B7280",
11011
- background: "#0F0F1A",
11012
- foreground: "#E2E8F0",
11013
- border: "#2D2B55",
11014
- t1Color: "#7C6AF7",
11015
- // Violet
11016
- t2Color: "#06B6D4",
11017
- // Cyan
11018
- t3Color: "#10B981"
11019
- // Green
11020
- }
11021
- };
11022
- var darkTheme = {
11023
- name: "dark",
11024
- colors: {
11025
- primary: "#60A5FA",
11026
- secondary: "#818CF8",
11027
- accent: "#34D399",
11028
- success: "#34D399",
11029
- warning: "#FBBF24",
11030
- error: "#F87171",
11031
- info: "#60A5FA",
11032
- muted: "#6B7280",
11033
- background: "#111827",
11034
- foreground: "#F9FAFB",
11035
- border: "#374151",
11036
- t1Color: "#60A5FA",
11037
- t2Color: "#818CF8",
11038
- t3Color: "#34D399"
11039
- }
11040
- };
11041
- var lightTheme = {
11042
- name: "light",
11043
- colors: {
11044
- primary: "#2563EB",
11045
- secondary: "#7C3AED",
11046
- accent: "#0891B2",
11047
- success: "#059669",
11048
- warning: "#D97706",
11049
- error: "#DC2626",
11050
- info: "#2563EB",
11051
- muted: "#6B7280",
11052
- background: "#FFFFFF",
11053
- foreground: "#111827",
11054
- border: "#E5E7EB",
11055
- t1Color: "#2563EB",
11056
- t2Color: "#7C3AED",
11057
- t3Color: "#059669"
11058
- }
11059
- };
11060
- var draculaTheme = {
11061
- name: "dracula",
11062
- colors: {
11063
- primary: "#BD93F9",
11064
- secondary: "#FF79C6",
11065
- accent: "#8BE9FD",
11066
- success: "#50FA7B",
11067
- warning: "#FFB86C",
11068
- error: "#FF5555",
11069
- info: "#8BE9FD",
11070
- muted: "#6272A4",
11071
- background: "#282A36",
11072
- foreground: "#F8F8F2",
11073
- border: "#44475A",
11074
- t1Color: "#BD93F9",
11075
- t2Color: "#FF79C6",
11076
- t3Color: "#50FA7B"
11077
- }
11078
- };
11079
- var nordTheme = {
11080
- name: "nord",
11081
- colors: {
11082
- primary: "#88C0D0",
11083
- secondary: "#81A1C1",
11084
- accent: "#A3BE8C",
11085
- success: "#A3BE8C",
11086
- warning: "#EBCB8B",
11087
- error: "#BF616A",
11088
- info: "#5E81AC",
11089
- muted: "#4C566A",
11090
- background: "#2E3440",
11091
- foreground: "#ECEFF4",
11092
- border: "#3B4252",
11093
- t1Color: "#88C0D0",
11094
- t2Color: "#81A1C1",
11095
- t3Color: "#A3BE8C"
11096
- }
11020
+ function defineTheme(name, colors) {
11021
+ return { name, colors };
11022
+ }
11023
+ var midnightTheme = defineTheme("midnight", {
11024
+ primary: "#8B7CF9",
11025
+ secondary: "#B7AEFF",
11026
+ accent: "#42D3E7",
11027
+ success: "#3DDC97",
11028
+ warning: "#F7B84B",
11029
+ error: "#FF6685",
11030
+ info: "#67A8FF",
11031
+ muted: "#7C819B",
11032
+ background: "#080A12",
11033
+ foreground: "#EDF0FA",
11034
+ border: "#292D42",
11035
+ t1Color: "#F7B84B",
11036
+ t2Color: "#A98BFF",
11037
+ t3Color: "#42D3E7"
11038
+ });
11039
+ var auroraTheme = defineTheme("aurora", {
11040
+ primary: "#6F8CFF",
11041
+ secondary: "#A78BFA",
11042
+ accent: "#45E0B8",
11043
+ success: "#45E0B8",
11044
+ warning: "#FFD166",
11045
+ error: "#FF6B8A",
11046
+ info: "#6FB7FF",
11047
+ muted: "#7890A8",
11048
+ background: "#071019",
11049
+ foreground: "#EAF7F5",
11050
+ border: "#20384A",
11051
+ t1Color: "#FFD166",
11052
+ t2Color: "#8B9CFF",
11053
+ t3Color: "#45E0B8"
11054
+ });
11055
+ var emberTheme = defineTheme("ember", {
11056
+ primary: "#FF8A5B",
11057
+ secondary: "#FFB36B",
11058
+ accent: "#F7C75B",
11059
+ success: "#72D69A",
11060
+ warning: "#F7C75B",
11061
+ error: "#FF647C",
11062
+ info: "#73B7FF",
11063
+ muted: "#9A8078",
11064
+ background: "#120C0B",
11065
+ foreground: "#FFF1E9",
11066
+ border: "#463027",
11067
+ t1Color: "#F7C75B",
11068
+ t2Color: "#FF8A5B",
11069
+ t3Color: "#72D69A"
11070
+ });
11071
+ var tideTheme = defineTheme("tide", {
11072
+ primary: "#4DA8FF",
11073
+ secondary: "#65C7F7",
11074
+ accent: "#51E1D4",
11075
+ success: "#63D9A5",
11076
+ warning: "#F2C879",
11077
+ error: "#F0718B",
11078
+ info: "#4DA8FF",
11079
+ muted: "#71899C",
11080
+ background: "#061017",
11081
+ foreground: "#E8F5FA",
11082
+ border: "#1C3947",
11083
+ t1Color: "#F2C879",
11084
+ t2Color: "#65A8F7",
11085
+ t3Color: "#51E1D4"
11086
+ });
11087
+ var bloomTheme = defineTheme("bloom", {
11088
+ primary: "#C084FC",
11089
+ secondary: "#F08BB4",
11090
+ accent: "#7DD3FC",
11091
+ success: "#6EE7B7",
11092
+ warning: "#FBCB78",
11093
+ error: "#FB7185",
11094
+ info: "#7DD3FC",
11095
+ muted: "#9B83A8",
11096
+ background: "#140D19",
11097
+ foreground: "#F8EEFC",
11098
+ border: "#412B4D",
11099
+ t1Color: "#FBCB78",
11100
+ t2Color: "#C084FC",
11101
+ t3Color: "#7DD3FC"
11102
+ });
11103
+ var daybreakTheme = defineTheme("daybreak", {
11104
+ primary: "#6857D9",
11105
+ secondary: "#826AE6",
11106
+ accent: "#087F91",
11107
+ success: "#087A55",
11108
+ warning: "#A86408",
11109
+ error: "#C83253",
11110
+ info: "#2563A8",
11111
+ muted: "#667085",
11112
+ background: "#F7F7FB",
11113
+ foreground: "#202336",
11114
+ border: "#D9DCE8",
11115
+ t1Color: "#A86408",
11116
+ t2Color: "#6857D9",
11117
+ t3Color: "#087F91"
11118
+ });
11119
+ var canonicalThemes = {
11120
+ midnight: midnightTheme,
11121
+ aurora: auroraTheme,
11122
+ ember: emberTheme,
11123
+ tide: tideTheme,
11124
+ bloom: bloomTheme,
11125
+ daybreak: daybreakTheme
11097
11126
  };
11098
- var solarizedTheme = {
11099
- name: "solarized",
11100
- colors: {
11101
- primary: "#268BD2",
11102
- secondary: "#2AA198",
11103
- accent: "#B58900",
11104
- success: "#859900",
11105
- warning: "#CB4B16",
11106
- error: "#DC322F",
11107
- info: "#268BD2",
11108
- muted: "#657B83",
11109
- background: "#002B36",
11110
- foreground: "#839496",
11111
- border: "#073642",
11112
- t1Color: "#268BD2",
11113
- t2Color: "#2AA198",
11114
- t3Color: "#859900"
11115
- }
11127
+ var THEME_ALIASES = {
11128
+ cascade: "midnight",
11129
+ dark: "aurora",
11130
+ light: "daybreak",
11131
+ dracula: "bloom",
11132
+ nord: "tide",
11133
+ solarized: "ember"
11116
11134
  };
11117
- var themes = /* @__PURE__ */ new Map([
11118
- ["cascade", cascadeTheme],
11119
- ["dark", darkTheme],
11120
- ["light", lightTheme],
11121
- ["dracula", draculaTheme],
11122
- ["nord", nordTheme],
11123
- ["solarized", solarizedTheme]
11124
- ]);
11135
+ function resolveThemeName(name) {
11136
+ return (name in canonicalThemes ? name : THEME_ALIASES[name]) || "midnight";
11137
+ }
11125
11138
  function getTheme(name) {
11126
- return themes.get(name) ?? cascadeTheme;
11139
+ return canonicalThemes[resolveThemeName(name)] ?? midnightTheme;
11127
11140
  }
11128
11141
 
11129
11142
  // src/cli/slash/index.ts
@@ -11377,6 +11390,13 @@ var FIXED_CHROME_ROWS = 1 + // StatusBar
11377
11390
  3;
11378
11391
  var STREAM_TAIL_ROWS = 9;
11379
11392
  var SLASH_PANEL_ROWS = 11;
11393
+ function computeAdaptiveLayoutMode(columns, rows) {
11394
+ const safeColumns = Number.isFinite(columns) && columns > 0 ? columns : 100;
11395
+ const safeRows = Number.isFinite(rows) && rows > 0 ? rows : 40;
11396
+ if (safeColumns < 80 || safeRows < 24) return "narrow";
11397
+ if (safeColumns < 120 || safeRows < 32) return "medium";
11398
+ return "wide";
11399
+ }
11380
11400
  var TREE_ROWS_FULL = 10;
11381
11401
  var TREE_ROWS_COMPACT = 4;
11382
11402
  var TIMELINE_ROWS = 4;
@@ -11636,7 +11656,7 @@ function formatTokens(n) {
11636
11656
  var StatusBar = React2__default.default.memo(StatusBarInternal);
11637
11657
  function HintBarInternal({ theme, isExecuting }) {
11638
11658
  if (isExecuting) return null;
11639
- return /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { paddingLeft: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.accent, dimColor: true, children: "/help \xB7 /clear \xB7 /theme \xB7 /cost \xB7 /model \xB7 /export" }) });
11659
+ return /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { paddingLeft: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.accent, dimColor: true, children: "/ commands \xB7 \u2191\u2193 history \xB7 Esc cancel \xB7 Ctrl+C exit" }) });
11640
11660
  }
11641
11661
  var HintBar = React2__default.default.memo(HintBarInternal);
11642
11662
  function ApprovalPrompt({ request, theme, onDecision }) {
@@ -11960,6 +11980,53 @@ function CostTracker({
11960
11980
  ] })
11961
11981
  ] });
11962
11982
  }
11983
+ function CompactStatus({ theme, activeT2Count, activeT3Count, currentAction, activeTool, isStreaming }) {
11984
+ const activeCount = activeT2Count + activeT3Count;
11985
+ const isActive = isStreaming || activeCount > 0;
11986
+ const rightHint = isActive ? /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.muted, children: [
11987
+ "T2:",
11988
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.accent, children: activeT2Count }),
11989
+ " T3:",
11990
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.accent, children: activeT3Count })
11991
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.muted, children: [
11992
+ "[",
11993
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.accent, bold: true, children: "tree" }),
11994
+ "]"
11995
+ ] });
11996
+ return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { paddingX: 1, borderStyle: "single", borderTop: false, borderLeft: false, borderRight: false, borderColor: theme.colors.border, children: [
11997
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { flexGrow: 1, children: isActive ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11998
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.accent, bold: true, children: [
11999
+ /* @__PURE__ */ jsxRuntime.jsx(Spinner__default.default, { type: "hamburger" }),
12000
+ " "
12001
+ ] }),
12002
+ activeTool ? (
12003
+ // Show active tool prominently
12004
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
12005
+ /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: "yellow", bold: true, children: [
12006
+ "\u2699 ",
12007
+ activeTool
12008
+ ] }),
12009
+ currentAction && !currentAction.startsWith("Using tool:") && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.muted, children: [
12010
+ " \u2503 ",
12011
+ currentAction.length > 60 ? currentAction.slice(0, 57) + "..." : currentAction
12012
+ ] })
12013
+ ] })
12014
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
12015
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.accent, bold: true, children: activeCount > 0 ? `WORKING: ${activeCount} AGENTS` : "ORCHESTRATING" }),
12016
+ currentAction && /* @__PURE__ */ jsxRuntime.jsxs(ink.Text, { color: theme.colors.muted, children: [
12017
+ " \u2503 ",
12018
+ currentAction.length > 80 ? currentAction.slice(0, 77) + "..." : currentAction
12019
+ ] })
12020
+ ] })
12021
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { children: [
12022
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.muted, children: "\u25CF SYSTEM IDLE " }),
12023
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.muted, children: "\u2503 Press " }),
12024
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.accent, bold: true, children: "/" }),
12025
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.muted, children: " for command palette" })
12026
+ ] }) }),
12027
+ /* @__PURE__ */ jsxRuntime.jsx(ink.Box, { children: rightHint })
12028
+ ] });
12029
+ }
11963
12030
  function ChatMessage({ role, content, theme, timestamp, isStreaming }) {
11964
12031
  const { label, color, prefix } = getRoleStyle(role, theme);
11965
12032
  return /* @__PURE__ */ jsxRuntime.jsxs(ink.Box, { flexDirection: "column", marginY: 1, children: [
@@ -12264,6 +12331,19 @@ function tailLines(text, n) {
12264
12331
  const lines = text.split("\n");
12265
12332
  return lines.slice(-8);
12266
12333
  }
12334
+ function activeTierSummary(root) {
12335
+ const summary = { t2: 0, t3: 0 };
12336
+ const visit = (node) => {
12337
+ if (node.status === "ACTIVE") {
12338
+ if (node.role === "T2") summary.t2 += 1;
12339
+ if (node.role === "T3") summary.t3 += 1;
12340
+ summary.action ??= node.currentAction;
12341
+ }
12342
+ node.children?.forEach(visit);
12343
+ };
12344
+ if (root) visit(root);
12345
+ return summary;
12346
+ }
12267
12347
  function WelcomeBanner({ theme, config, workspacePath, sessionId }) {
12268
12348
  const t1 = config.models?.t1 ?? "auto";
12269
12349
  const t2 = config.models?.t2 ?? "auto";
@@ -13161,13 +13241,15 @@ ${lastUser.content}`;
13161
13241
  };
13162
13242
  }, [stdout]);
13163
13243
  const width = termSize.columns;
13244
+ const adaptiveMode = computeAdaptiveLayoutMode(termSize.columns, termSize.rows);
13164
13245
  const budgetOpts = {
13165
13246
  isTypingCommand,
13166
- showCost: state.showCost,
13167
- showDetails: state.showDetails,
13168
- showComms: state.showComms && state.peerEvents.length > 0
13247
+ showCost: state.showCost && adaptiveMode !== "narrow",
13248
+ showDetails: state.showDetails && adaptiveMode === "wide",
13249
+ showComms: state.showComms && state.peerEvents.length > 0 && adaptiveMode === "wide"
13169
13250
  };
13170
13251
  const liveBudget = computeLiveAreaBudget(termSize.rows, budgetOpts);
13252
+ const tierSummary = activeTierSummary(state.agentTree);
13171
13253
  const transcriptRows = altScreen ? computeTranscriptRows(termSize.rows, liveBudget, { ...budgetOpts, treeVisible: state.agentTree != null }) : 0;
13172
13254
  const transcriptLines = altScreen ? flattenTranscript(state.messages) : [];
13173
13255
  const transcript = altScreen ? windowTranscript(transcriptLines, historyOffset, transcriptRows) : null;
@@ -13257,10 +13339,28 @@ ${lastUser.content}`;
13257
13339
  onClose: () => setIsShowingModels(false)
13258
13340
  }
13259
13341
  ) }),
13260
- /* @__PURE__ */ jsxRuntime.jsx(AgentTree, { root: state.agentTree, theme, scrollOffset: treeScrollOffset, maxRows: liveBudget.treeMaxRows }),
13261
- state.showComms && liveBudget.commsMaxEvents > 0 && /* @__PURE__ */ jsxRuntime.jsx(PeerFeed, { events: state.peerEvents, theme, maxRows: liveBudget.commsMaxEvents }),
13262
- state.showDetails && liveBudget.showTimeline && /* @__PURE__ */ jsxRuntime.jsx(TimelinePanel, { nodes: [...treeNodesRef.current.values()], theme, currentIndex: timelineIndex, onChangeIndex: setTimelineIndex }),
13263
- state.showCost && /* @__PURE__ */ jsxRuntime.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 }),
13342
+ adaptiveMode === "narrow" && state.agentTree ? /* @__PURE__ */ jsxRuntime.jsx(
13343
+ CompactStatus,
13344
+ {
13345
+ theme,
13346
+ activeT2Count: tierSummary.t2,
13347
+ activeT3Count: tierSummary.t3,
13348
+ currentAction: tierSummary.action ?? state.agentTree.currentAction,
13349
+ activeTool: state.activeTool,
13350
+ isStreaming: state.isStreaming
13351
+ }
13352
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
13353
+ AgentTree,
13354
+ {
13355
+ root: state.agentTree,
13356
+ theme,
13357
+ scrollOffset: treeScrollOffset,
13358
+ maxRows: adaptiveMode === "medium" ? Math.min(4, liveBudget.treeMaxRows) : liveBudget.treeMaxRows
13359
+ }
13360
+ ),
13361
+ adaptiveMode === "wide" && state.showComms && liveBudget.commsMaxEvents > 0 && /* @__PURE__ */ jsxRuntime.jsx(PeerFeed, { events: state.peerEvents, theme, maxRows: liveBudget.commsMaxEvents }),
13362
+ adaptiveMode === "wide" && state.showDetails && liveBudget.showTimeline && /* @__PURE__ */ jsxRuntime.jsx(TimelinePanel, { nodes: [...treeNodesRef.current.values()], theme, currentIndex: timelineIndex, onChangeIndex: setTimelineIndex }),
13363
+ adaptiveMode !== "narrow" && state.showCost && /* @__PURE__ */ jsxRuntime.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 }),
13264
13364
  liveBudget.collapsed && (state.showCost || state.showDetails || state.agentTree != null) && /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { color: theme.colors.muted, dimColor: true, children: " \u25B8 panels collapsed (small terminal)" }),
13265
13365
  state.approvalRequest && /* @__PURE__ */ jsxRuntime.jsx(ApprovalPrompt, { request: state.approvalRequest, theme, onDecision: (decision) => {
13266
13366
  dispatch({ type: "SET_APPROVAL", request: null });