@wrongstack/tui 0.267.0 → 0.268.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/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { writeErr, resolveProjectDir, wstackGlobalRoot, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, projectSlug, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
1
+ import { writeErr, resolveProjectDir, wstackGlobalRoot, createHqPublisherFromEnv, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, projectSlug, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
2
2
  export { buildGoalPreamble } from '@wrongstack/core';
3
3
  import { Box as Box$1, useInput, useStdin, useStdout, Text as Text$1, render, useApp, measureElement, Static } from 'ink';
4
4
  import { randomUUID } from 'crypto';
@@ -88,6 +88,13 @@ var Box = forwardRef(function Box2({ borderColor, backgroundColor, ...rest }, re
88
88
  }
89
89
  );
90
90
  });
91
+ function snapshotTokenCounter(tokenCounter) {
92
+ return {
93
+ usage: tokenCounter.total(),
94
+ cost: tokenCounter.estimateCost(),
95
+ cacheStats: tokenCounter.cacheStats()
96
+ };
97
+ }
91
98
  function useTokenCounterRefresh(tokenCounter, events) {
92
99
  const [data, setData] = useState(
93
100
  () => tokenCounter ? {
@@ -97,13 +104,15 @@ function useTokenCounterRefresh(tokenCounter, events) {
97
104
  } : void 0
98
105
  );
99
106
  useEffect(() => {
100
- if (!tokenCounter || !events) return;
107
+ if (!tokenCounter) {
108
+ setData(void 0);
109
+ return;
110
+ }
111
+ const snapshot = () => snapshotTokenCounter(tokenCounter);
112
+ setData(snapshot());
113
+ if (!events) return;
101
114
  const off = events.on("token.accounted", () => {
102
- setData({
103
- usage: tokenCounter.total(),
104
- cost: tokenCounter.estimateCost(),
105
- cacheStats: tokenCounter.cacheStats()
106
- });
115
+ setData(snapshot());
107
116
  });
108
117
  return off;
109
118
  }, [tokenCounter, events]);
@@ -175,6 +184,7 @@ function StatusBar({
175
184
  context,
176
185
  contextStrategy,
177
186
  hiddenItems,
187
+ mode = "detailed",
178
188
  events,
179
189
  eternalStage,
180
190
  goalSummary,
@@ -238,6 +248,68 @@ function StatusBar({
238
248
  const countdownColor = nextStepsAutoSubmitCountdown != null ? nextStepsAutoSubmitCountdown > 20 ? "green" : nextStepsAutoSubmitCountdown > 10 ? "yellow" : "red" : "green";
239
249
  const hasTaskActivity = tasks && (tasks.pending > 0 || tasks.inProgress > 0 || tasks.completed > 0 || tasks.blocked > 0 || tasks.failed > 0);
240
250
  const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) && !hiddenSet.has("todos") || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) && !hiddenSet.has("plan") || hasTaskActivity && !hiddenSet.has("tasks") || fleetHasActivity && !hiddenSet.has("fleet") || showBrain || showDebugStream || showEnhance || hasNextStepsAutoSubmit;
251
+ const minimalWorkParts = [
252
+ queueCount > 0 ? `q${queueCount}` : "",
253
+ todos && !hiddenSet.has("todos") && todos.inProgress + todos.pending > 0 ? `todo ${todos.inProgress}/${todos.pending}` : "",
254
+ hasTaskActivity && !hiddenSet.has("tasks") ? `task ${tasks.inProgress}/${tasks.pending}` : "",
255
+ fleetHasActivity && !hiddenSet.has("fleet") ? fleet ? `agent \u25B6${fleet.running} \xB7${fleet.idle}` : `agent ${subagentCount}` : "",
256
+ typeof processCount === "number" && processCount > 0 ? `proc ${processCount}` : ""
257
+ ].filter(Boolean);
258
+ if (mode === "minimum") {
259
+ const ctxMax = context?.max;
260
+ const ctxRatio = context && ctxMax ? context.used / ctxMax : void 0;
261
+ const ctxClampedRatio = ctxRatio !== void 0 ? Math.min(ctxRatio, 1) : void 0;
262
+ const ctxPctText = ctxRatio !== void 0 ? `${Math.min(Math.round(ctxRatio * 100), 100)}%` : void 0;
263
+ return /* @__PURE__ */ jsx(
264
+ Box,
265
+ {
266
+ flexDirection: "column",
267
+ paddingX: 1,
268
+ borderStyle: "single",
269
+ borderTop: true,
270
+ borderBottom: false,
271
+ borderLeft: false,
272
+ borderRight: false,
273
+ children: /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
274
+ version ? /* @__PURE__ */ jsxs(Text, { children: [
275
+ /* @__PURE__ */ jsx(Text, { color: "blue", bold: true, children: "WS" }),
276
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
277
+ " v",
278
+ version
279
+ ] })
280
+ ] }) : null,
281
+ version ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
282
+ thinking ? /* @__PURE__ */ jsx(WaveText, { text: `${statePrefix} ${stateLabel}`, phase: spinnerIdx }) : /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
283
+ statePrefix,
284
+ " ",
285
+ stateLabel
286
+ ] }),
287
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
288
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: model }),
289
+ ctxClampedRatio !== void 0 && ctxPctText && ctxMax !== void 0 && !hiddenSet.has("context") ? /* @__PURE__ */ jsxs(Fragment, { children: [
290
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
291
+ /* @__PURE__ */ jsxs(Text, { color: ctxClampedRatio < 0.6 ? "green" : ctxClampedRatio < 0.75 ? "yellow" : "red", children: [
292
+ "ctx ",
293
+ ctxPctText,
294
+ "/",
295
+ fmtTok(ctxMax)
296
+ ] })
297
+ ] }) : null,
298
+ cost && cost.total > 0 && !hiddenSet.has("cost") ? /* @__PURE__ */ jsxs(Fragment, { children: [
299
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
300
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
301
+ "$",
302
+ cost.total.toFixed(4)
303
+ ] })
304
+ ] }) : null,
305
+ minimalWorkParts.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
306
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
307
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: minimalWorkParts.slice(0, 3).join(" \xB7 ") })
308
+ ] }) : null
309
+ ] })
310
+ }
311
+ );
312
+ }
241
313
  return /* @__PURE__ */ jsxs(
242
314
  Box,
243
315
  {
@@ -290,6 +362,8 @@ function StatusBar({
290
362
  renderMeter(clampedRatio, 8),
291
363
  " ",
292
364
  pctText,
365
+ "/",
366
+ fmtTok(context.max),
293
367
  contextStrategy ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
294
368
  " [",
295
369
  contextStrategy,
@@ -1151,6 +1225,36 @@ function FleetMonitor({
1151
1225
  ] }) : null
1152
1226
  ] });
1153
1227
  }
1228
+ var TOOL_GLYPHS = {
1229
+ file: "\u25A4",
1230
+ edit: "\u270E",
1231
+ search: "\u2315",
1232
+ folder: "\u25A3",
1233
+ terminal: "\u2318",
1234
+ web: "\u25C8",
1235
+ git: "\u2387",
1236
+ tree: "\u2630",
1237
+ code: "\u2699",
1238
+ test: "\u2697",
1239
+ package: "\u2B22",
1240
+ document: "\u2637",
1241
+ scaffold: "\u2731",
1242
+ todo: "\u2610",
1243
+ plan: "\u2756",
1244
+ task: "\u25AA",
1245
+ meta: "\u274F",
1246
+ index: "\u229B",
1247
+ json: "\u2317",
1248
+ diff: "\u2206",
1249
+ logs: "\u2261",
1250
+ settings: "\u2699",
1251
+ brain: "\u2726",
1252
+ fallback: "\u2022"
1253
+ };
1254
+ function getToolVisual(name) {
1255
+ const id = getToolIcon(name);
1256
+ return { glyph: TOOL_GLYPHS[id], color: TOOL_ICON_CONFIG[id].color };
1257
+ }
1154
1258
  var STATUS2 = {
1155
1259
  idle: { icon: "\u25CB", color: "gray" },
1156
1260
  running: { icon: "\u25B6", color: "yellow" },
@@ -1159,22 +1263,19 @@ var STATUS2 = {
1159
1263
  timeout: { icon: "\u23F1", color: "yellow" },
1160
1264
  stopped: { icon: "\u2298", color: "gray" }
1161
1265
  };
1162
- function isTerminal(status) {
1266
+ var IDLE_HIDE_MS = 6e4;
1267
+ var EMPTY_AGENTS_CLOSE_DELAY_MS = 7500;
1268
+ function isTerminalAgentStatus(status) {
1163
1269
  return status === "success" || status === "failed" || status === "timeout" || status === "stopped";
1164
1270
  }
1165
- var IDLE_HIDE_MS = 6e4;
1166
- function selectLiveAgents(all, now, idleHideMs = IDLE_HIDE_MS) {
1167
- const visible = all.filter((e) => {
1168
- if (isTerminal(e.status)) return false;
1169
- if (e.status === "running") return true;
1170
- return now - e.lastEventAt < idleHideMs;
1171
- });
1172
- return visible.sort((a, b) => {
1173
- if (a.status === "running" && b.status !== "running") return -1;
1174
- if (a.status !== "running" && b.status === "running") return 1;
1175
- if (a.status === "running") return a.startedAt - b.startedAt;
1176
- return b.lastEventAt - a.lastEventAt;
1177
- });
1271
+ function isLeaderEntry(entry) {
1272
+ return entry.id === "leader" || entry.name === "LEADER";
1273
+ }
1274
+ function selectLiveAgents(all, _now, _idleHideMs = IDLE_HIDE_MS) {
1275
+ const leader = all.find(isLeaderEntry);
1276
+ const activeSubagents = all.filter((entry) => !isLeaderEntry(entry) && !isTerminalAgentStatus(entry.status));
1277
+ const showLeader = leader !== void 0 && (leader.status !== "idle" || activeSubagents.length > 0);
1278
+ return all.filter((entry) => isLeaderEntry(entry) ? showLeader : activeSubagents.some((active) => active.id === entry.id));
1178
1279
  }
1179
1280
  function fmtTokens2(n) {
1180
1281
  if (n < 1e3) return String(n);
@@ -1186,6 +1287,86 @@ function snippet(s2, max = 72) {
1186
1287
  if (oneLine2.length <= max) return oneLine2;
1187
1288
  return `${oneLine2.slice(0, max - 1)}\u2026`;
1188
1289
  }
1290
+ function fmtShortDuration(ms) {
1291
+ if (ms < 1e3) return `${Math.max(0, Math.round(ms))}ms`;
1292
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(ms < 1e4 ? 1 : 0)}s`;
1293
+ const m = Math.floor(ms / 6e4);
1294
+ const s2 = Math.floor(ms % 6e4 / 1e3);
1295
+ return `${m}m${s2.toString().padStart(2, "0")}s`;
1296
+ }
1297
+ function fmtSignedTokens(n) {
1298
+ return n <= 0 ? "0" : fmtTokens2(n);
1299
+ }
1300
+ function fmtOptionalTimestamp(ms) {
1301
+ if (!ms || ms <= 0) return "unknown";
1302
+ return new Date(ms).toLocaleTimeString("en-US", { hour12: false });
1303
+ }
1304
+ function formatContextRunway(tokens, maxTokens) {
1305
+ if (!tokens || !maxTokens || maxTokens <= 0) return "ctx unknown";
1306
+ const left = Math.max(0, maxTokens - tokens);
1307
+ return `${fmtTokens2(tokens)}/${fmtTokens2(maxTokens)} \xB7 ${fmtSignedTokens(left)} free`;
1308
+ }
1309
+ function formatRecentToolChip(tool) {
1310
+ const status = tool.ok === false ? "\u2717" : "\u2713";
1311
+ const duration = typeof tool.durationMs === "number" ? ` ${fmtShortDuration(tool.durationMs)}` : "";
1312
+ const lines = typeof tool.outputLines === "number" && tool.outputLines > 0 ? ` ${tool.outputLines}L` : "";
1313
+ const bytes = typeof tool.outputBytes === "number" && tool.outputBytes > 0 ? ` ${fmtTokens2(tool.outputBytes)}B` : "";
1314
+ return `${status} ${tool.name}${duration}${lines}${bytes}`;
1315
+ }
1316
+ function formatAgentDetailHeader(entry) {
1317
+ return entry.name || entry.id;
1318
+ }
1319
+ function agentRisk(entry) {
1320
+ const pct = entry.ctxPct ?? 0;
1321
+ if (entry.budgetWarning || entry.failureReason || pct >= 0.9) return "critical";
1322
+ if (pct >= 0.75 || (entry.extensions ?? 0) > 0) return "hot";
1323
+ if (entry.status === "running" || pct >= 0.55) return "busy";
1324
+ return "calm";
1325
+ }
1326
+ function riskMeta(risk) {
1327
+ switch (risk) {
1328
+ case "critical":
1329
+ return { icon: "\u25C6", color: "red", label: "critical" };
1330
+ case "hot":
1331
+ return { icon: "\u25B2", color: "yellow", label: "hot" };
1332
+ case "busy":
1333
+ return { icon: "\u25CF", color: "cyan", label: "busy" };
1334
+ case "calm":
1335
+ return { icon: "\u25CB", color: "green", label: "calm" };
1336
+ }
1337
+ }
1338
+ function currentAction(entry, now) {
1339
+ if (entry.currentTool) return `\u2192 ${entry.currentTool.name} ${fmtShortDuration(now - entry.currentTool.startedAt)}`;
1340
+ if (entry.status === "running") return "thinking";
1341
+ const last = entry.recentTools[entry.recentTools.length - 1];
1342
+ if (last) return `last ${last.name}`;
1343
+ const msg = entry.recentMessages[entry.recentMessages.length - 1];
1344
+ if (msg) return `msg ${snippet(msg.text, 34)}`;
1345
+ return "standing by";
1346
+ }
1347
+ function selectAgentDetail(live, selectedId) {
1348
+ return live.find((entry) => entry.id === selectedId) ?? live.find(isLeaderEntry) ?? live[0];
1349
+ }
1350
+ function nextEmptyAgentsCloseStartedAt(liveCount, now, currentStartedAt) {
1351
+ if (liveCount > 0) return void 0;
1352
+ return currentStartedAt ?? now;
1353
+ }
1354
+ function shouldCloseEmptyAgentsMonitor(liveCount, now, emptyStartedAt, delayMs = EMPTY_AGENTS_CLOSE_DELAY_MS) {
1355
+ return liveCount === 0 && emptyStartedAt !== void 0 && now - emptyStartedAt >= delayMs;
1356
+ }
1357
+ function selectHotAgent(entries) {
1358
+ const riskScore = { critical: 3, hot: 2, busy: 1, calm: 0 };
1359
+ return [...entries].sort((a, b) => {
1360
+ const ar = riskScore[agentRisk(a)];
1361
+ const br = riskScore[agentRisk(b)];
1362
+ if (br !== ar) return br - ar;
1363
+ const bp = b.ctxPct ?? 0;
1364
+ const ap = a.ctxPct ?? 0;
1365
+ if (bp !== ap) return bp - ap;
1366
+ if (b.toolCalls !== a.toolCalls) return b.toolCalls - a.toolCalls;
1367
+ return b.lastEventAt - a.lastEventAt;
1368
+ }).at(0);
1369
+ }
1189
1370
  function ContextBar({
1190
1371
  pct,
1191
1372
  tokens,
@@ -1214,10 +1395,13 @@ function AgentRow({
1214
1395
  const s2 = STATUS2[entry.status];
1215
1396
  const elapsed = entry.status === "running" ? fmtElapsed(Math.max(0, now - entry.startedAt)) : entry.status;
1216
1397
  const modelLabel = fmtModelLabel(entry.provider, entry.model);
1398
+ const activity = sparkline(bucketActivity(entry.recentTools, now, 10, 3e3));
1399
+ const risk = riskMeta(agentRisk(entry));
1217
1400
  const ctxCostStr = entry.ctxCost !== void 0 && entry.ctxCost > 0 ? ` ctx ${entry.ctxCost.toFixed(4)}` : "";
1218
1401
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1219
1402
  /* @__PURE__ */ jsx(Text, { color: selected ? "magenta" : "gray", children: selected ? "\u25B6" : " " }),
1220
1403
  /* @__PURE__ */ jsx(Text, { color: s2.color, bold: true, children: s2.icon }),
1404
+ /* @__PURE__ */ jsx(Text, { color: risk.color, children: risk.icon }),
1221
1405
  /* @__PURE__ */ jsx(Text, { bold: selected, ...selected ? { color: "magenta" } : {}, children: entry.name }),
1222
1406
  modelLabel ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: modelLabel }) : null,
1223
1407
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
@@ -1227,17 +1411,10 @@ function AgentRow({
1227
1411
  entry.toolCalls,
1228
1412
  "t"
1229
1413
  ] }),
1414
+ activity ? /* @__PURE__ */ jsx(Text, { color: "green", children: activity }) : null,
1230
1415
  entry.ctxPct !== void 0 ? /* @__PURE__ */ jsx(ContextBar, { pct: entry.ctxPct, tokens: entry.ctxTokens, maxTokens: entry.ctxMaxTokens }) : null,
1231
1416
  ctxCostStr ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: ctxCostStr }) : null,
1232
- entry.status === "running" && entry.currentTool ? /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
1233
- "\u2192 ",
1234
- entry.currentTool.name,
1235
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1236
- " (",
1237
- Math.max(0, now - entry.currentTool.startedAt),
1238
- "ms)"
1239
- ] })
1240
- ] }) : null,
1417
+ /* @__PURE__ */ jsx(Text, { color: entry.currentTool ? "cyan" : "gray", children: currentAction(entry, now) }),
1241
1418
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed }),
1242
1419
  entry.extensions && entry.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1243
1420
  "\u26A1\xD7",
@@ -1257,162 +1434,280 @@ function AgentDetail({
1257
1434
  const lastTool = entry.recentTools[entry.recentTools.length - 1];
1258
1435
  const lastMessage = entry.recentMessages[entry.recentMessages.length - 1];
1259
1436
  const streamTail = entry.streamingText ? snippet(entry.streamingText.slice(-160)) : "";
1260
- const modelLabel = fmtModelLabel(entry.provider, entry.model);
1261
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 4, borderStyle: "single", borderColor: "magenta", borderLeft: true, children: [
1262
- spark || lastTool ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1263
- /* @__PURE__ */ jsx(Text, { color: "green", children: spark || "" }),
1264
- lastTool ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1265
- "last: ",
1266
- lastTool.name,
1267
- typeof lastTool.durationMs === "number" ? ` ${lastTool.durationMs}ms` : "",
1268
- lastTool.ok === false ? " \u2717" : ""
1269
- ] }) : null
1270
- ] }) : null,
1271
- !modelLabel && (entry.provider || entry.model) ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1272
- "provider: ",
1273
- entry.provider || "(leader)",
1274
- " \xB7 model: ",
1275
- entry.model || "\u2014"
1276
- ] }) }) : null,
1277
- entry.cost > 0 || entry.ctxCost && entry.ctxCost > 0 ? /* @__PURE__ */ jsxs(Box, { children: [
1278
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "cost: " }),
1279
- entry.cost > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1280
- "$",
1281
- entry.cost.toFixed(4),
1282
- " total"
1283
- ] }) : null,
1284
- entry.cost > 0 && entry.ctxCost && entry.ctxCost > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }) : null,
1285
- entry.ctxCost && entry.ctxCost > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1286
- "$",
1287
- entry.ctxCost.toFixed(4),
1288
- " ctx"
1289
- ] }) : null
1290
- ] }) : null,
1291
- entry.status === "running" && streamTail ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1292
- ">",
1293
- " ",
1294
- streamTail
1295
- ] }) }) : null,
1296
- (entry.status !== "running" || !streamTail) && lastMessage ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1297
- "msg: ",
1298
- snippet(lastMessage.text)
1299
- ] }) }) : null,
1300
- entry.budgetWarning ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1301
- "\u26A1 ",
1302
- entry.budgetWarning.kind,
1303
- " ",
1304
- entry.budgetWarning.used,
1305
- "/",
1306
- entry.budgetWarning.limit,
1307
- " \u2014 extending"
1308
- ] }) }) : null,
1309
- entry.failureReason && entry.status !== "success" ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "red", children: [
1310
- "\u2717 ",
1311
- entry.failureReason
1312
- ] }) }) : null
1313
- ] });
1437
+ const risk = riskMeta(agentRisk(entry));
1438
+ const ctxLine = formatContextRunway(entry.ctxTokens, entry.ctxMaxTokens);
1439
+ const modelLabel = fmtModelLabel(entry.provider, entry.model) || [entry.provider, entry.model].filter(Boolean).join("/");
1440
+ return /* @__PURE__ */ jsx(Box, { alignSelf: "stretch", flexDirection: "column", width: "100%", flexGrow: 1, children: /* @__PURE__ */ jsxs(
1441
+ Box,
1442
+ {
1443
+ alignSelf: "stretch",
1444
+ flexDirection: "column",
1445
+ width: "100%",
1446
+ flexGrow: 1,
1447
+ paddingX: 1,
1448
+ borderStyle: "single",
1449
+ borderColor: "magenta",
1450
+ children: [
1451
+ /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 1, children: /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: formatAgentDetailHeader(entry) }) }),
1452
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1453
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "id" }),
1454
+ /* @__PURE__ */ jsx(Text, { children: entry.id }),
1455
+ modelLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [
1456
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 model" }),
1457
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: modelLabel })
1458
+ ] }) : null,
1459
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 status" }),
1460
+ /* @__PURE__ */ jsxs(Text, { color: STATUS2[entry.status].color, children: [
1461
+ STATUS2[entry.status].icon,
1462
+ " ",
1463
+ entry.status
1464
+ ] })
1465
+ ] }),
1466
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1467
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "runtime" }),
1468
+ /* @__PURE__ */ jsx(Text, { children: fmtElapsed(Math.max(0, now - entry.startedAt)) }),
1469
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 started" }),
1470
+ /* @__PURE__ */ jsx(Text, { children: fmtOptionalTimestamp(entry.startedAt) }),
1471
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 last event" }),
1472
+ /* @__PURE__ */ jsxs(Text, { children: [
1473
+ fmtShortDuration(Math.max(0, now - entry.lastEventAt)),
1474
+ " ago"
1475
+ ] }),
1476
+ entry.extensions && entry.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1477
+ "\xB7 extensions \u26A1\xD7",
1478
+ entry.extensions
1479
+ ] }) : null
1480
+ ] }),
1481
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1482
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "throughput" }),
1483
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
1484
+ entry.iterations,
1485
+ " iterations"
1486
+ ] }),
1487
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
1488
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
1489
+ entry.toolCalls,
1490
+ " tools"
1491
+ ] }),
1492
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 current" }),
1493
+ /* @__PURE__ */ jsx(Text, { color: entry.currentTool ? "cyan" : "gray", children: currentAction(entry, now) })
1494
+ ] }),
1495
+ spark || lastTool ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1496
+ /* @__PURE__ */ jsx(Text, { color: "green", children: spark || "" }),
1497
+ lastTool ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1498
+ "last: ",
1499
+ lastTool.name,
1500
+ typeof lastTool.durationMs === "number" ? ` ${lastTool.durationMs}ms` : "",
1501
+ lastTool.ok === false ? " \u2717" : ""
1502
+ ] }) : null
1503
+ ] }) : null,
1504
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1505
+ /* @__PURE__ */ jsxs(Text, { color: risk.color, children: [
1506
+ risk.icon,
1507
+ " ",
1508
+ risk.label
1509
+ ] }),
1510
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "ctx" }),
1511
+ /* @__PURE__ */ jsx(Text, { color: risk.color, children: ctxLine }),
1512
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1513
+ "idle ",
1514
+ fmtShortDuration(Math.max(0, now - entry.lastEventAt))
1515
+ ] })
1516
+ ] }),
1517
+ entry.cost > 0 || entry.ctxCost && entry.ctxCost > 0 ? /* @__PURE__ */ jsxs(Box, { children: [
1518
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "cost: " }),
1519
+ entry.cost > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1520
+ "$",
1521
+ entry.cost.toFixed(4),
1522
+ " total"
1523
+ ] }) : null,
1524
+ entry.cost > 0 && entry.ctxCost && entry.ctxCost > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }) : null,
1525
+ entry.ctxCost && entry.ctxCost > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1526
+ "$",
1527
+ entry.ctxCost.toFixed(4),
1528
+ " ctx"
1529
+ ] }) : null
1530
+ ] }) : null,
1531
+ entry.transcriptPath ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1532
+ "transcript: ",
1533
+ snippet(entry.transcriptPath, 120)
1534
+ ] }) }) : null,
1535
+ entry.recentTools.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1536
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "recent" }),
1537
+ entry.recentTools.slice(-4).map((tool, i) => {
1538
+ const visual = getToolVisual(tool.name);
1539
+ return (
1540
+ // biome-ignore lint/suspicious/noArrayIndexKey: recent tool entries do not carry stable ids.
1541
+ /* @__PURE__ */ jsx(Text, { color: tool.ok === false ? "red" : visual.color, children: `\u2039${visual.glyph} ${formatRecentToolChip(tool)}\u203A` }, `${tool.name}-${tool.at}-${i}`)
1542
+ );
1543
+ })
1544
+ ] }) : null,
1545
+ entry.status === "running" && streamTail ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1546
+ ">",
1547
+ " ",
1548
+ streamTail
1549
+ ] }) }) : null,
1550
+ (entry.status !== "running" || !streamTail) && lastMessage ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1551
+ "msg: ",
1552
+ snippet(lastMessage.text)
1553
+ ] }) }) : null,
1554
+ entry.budgetWarning ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1555
+ "\u26A1 ",
1556
+ entry.budgetWarning.kind,
1557
+ " ",
1558
+ entry.budgetWarning.used,
1559
+ "/",
1560
+ entry.budgetWarning.limit,
1561
+ " \u2014 extending"
1562
+ ] }) }) : null,
1563
+ entry.failureReason && entry.status !== "success" ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "red", children: [
1564
+ "\u2717 ",
1565
+ entry.failureReason
1566
+ ] }) }) : null
1567
+ ]
1568
+ }
1569
+ ) });
1314
1570
  }
1315
1571
  function AgentsMonitor({
1316
1572
  entries,
1317
1573
  totalCost,
1318
1574
  leaderCost = 0,
1319
1575
  totalTokens,
1320
- nowTick
1576
+ nowTick,
1577
+ onClose
1321
1578
  }) {
1322
1579
  const all = Object.values(entries);
1323
1580
  const grandCost = leaderCost + totalCost;
1324
- const live = useMemo(() => selectLiveAgents(all, nowTick), [all, nowTick]);
1325
- const [selectedIndex, setSelectedIndex] = useState(0);
1326
- const safeIndex = Math.min(selectedIndex, Math.max(0, live.length - 1));
1581
+ const live = useMemo(() => selectLiveAgents(all), [all, nowTick]);
1582
+ const [selectedId, setSelectedId] = useState(void 0);
1583
+ const [emptyAgentsCloseStartedAt, setEmptyAgentsCloseStartedAt] = useState(void 0);
1584
+ useEffect(() => {
1585
+ const nextStartedAt = nextEmptyAgentsCloseStartedAt(live.length, nowTick, emptyAgentsCloseStartedAt);
1586
+ if (nextStartedAt !== emptyAgentsCloseStartedAt) setEmptyAgentsCloseStartedAt(nextStartedAt);
1587
+ if (shouldCloseEmptyAgentsMonitor(live.length, nowTick, nextStartedAt)) onClose?.();
1588
+ }, [emptyAgentsCloseStartedAt, live.length, nowTick, onClose]);
1589
+ const selected = selectAgentDetail(live, selectedId);
1590
+ const selectedIndex = selected ? live.findIndex((entry) => entry.id === selected.id) : -1;
1327
1591
  useInput((_input, key) => {
1592
+ if (live.length === 0) return;
1328
1593
  if (key.upArrow) {
1329
- setSelectedIndex((prev) => Math.max(0, prev - 1));
1594
+ const next = Math.max(0, selectedIndex - 1);
1595
+ setSelectedId(live[next]?.id);
1330
1596
  } else if (key.downArrow) {
1331
- setSelectedIndex((prev) => Math.min(live.length - 1, prev + 1));
1597
+ const next = Math.min(live.length - 1, selectedIndex + 1);
1598
+ setSelectedId(live[next]?.id);
1332
1599
  }
1333
1600
  });
1334
1601
  const running = live.filter((e) => e.status === "running").length;
1335
1602
  const totalDone = all.filter((e) => e.status === "success").length;
1336
1603
  const totalFailed = all.filter((e) => e.status === "failed" || e.status === "timeout").length;
1337
- const hiddenIdle = all.filter(
1604
+ const staleIdle = all.filter(
1338
1605
  (e) => e.status === "idle" && nowTick - e.lastEventAt >= IDLE_HIDE_MS
1339
1606
  ).length;
1340
- const selected = live[safeIndex];
1341
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
1342
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1343
- /* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "AGENTS \xB7 LIVE" }),
1344
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1345
- /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1346
- "\u25B6",
1347
- running
1348
- ] }),
1349
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
1350
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "done" }),
1351
- /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1352
- "\u2713",
1353
- totalDone
1354
- ] }),
1355
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
1356
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "failed" }),
1357
- totalFailed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
1358
- "\u2717",
1359
- totalFailed
1360
- ] }) : null,
1361
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 \u2191\u2193 nav \xB7 Ctrl+G / F3 close" })
1362
- ] }),
1363
- live.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1364
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "models" }),
1365
- (() => {
1366
- const seen = /* @__PURE__ */ new Map();
1367
- for (const e of live) {
1368
- if (e.model) seen.set(e.name ?? e.id, `${e.provider ?? "?"}/${e.model}`);
1369
- }
1370
- return [...seen.entries()].slice(0, 4).map(([name, mod]) => /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1371
- name,
1372
- ":",
1373
- mod
1374
- ] }, name));
1375
- })()
1376
- ] }) : null,
1377
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1378
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "shown" }),
1379
- /* @__PURE__ */ jsx(Text, { color: "magenta", children: live.length }),
1380
- totalTokens ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1381
- " ",
1382
- fmtTokens2(totalTokens.input),
1383
- "\u2191 ",
1384
- fmtTokens2(totalTokens.output),
1385
- "\u2193"
1386
- ] }) : null,
1387
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "total" }),
1388
- /* @__PURE__ */ jsxs(Text, { color: "green", bold: true, children: [
1389
- "$",
1390
- grandCost.toFixed(4)
1391
- ] }),
1392
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1393
- "(leader $",
1394
- leaderCost.toFixed(4),
1395
- " \xB7 fleet $",
1396
- totalCost.toFixed(4),
1397
- ")"
1398
- ] }),
1399
- hiddenIdle > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1400
- "\xB7 ",
1401
- hiddenIdle,
1402
- " idle hidden"
1403
- ] }) : null
1404
- ] }),
1405
- live.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No live agents \u2014 spawn with /spawn or /fleet dispatch." }) : null,
1406
- live.map((e) => /* @__PURE__ */ jsx(AgentRow, { entry: e, now: nowTick, selected: e.id === selected?.id }, e.id)),
1407
- selected ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
1408
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingLeft: 2, children: [
1409
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500" }),
1410
- /* @__PURE__ */ jsx(Text, { color: "magenta", children: selected.name }),
1411
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "details \u2500\u2500\u2500" })
1412
- ] }),
1413
- /* @__PURE__ */ jsx(AgentDetail, { entry: selected, now: nowTick })
1414
- ] }) : null
1415
- ] });
1607
+ const hotAgent = selectHotAgent(live);
1608
+ const pressure = live.length > 0 ? live.reduce((max, e) => Math.max(max, e.ctxPct ?? 0), 0) : 0;
1609
+ const toolCalls = live.reduce((sum, e) => sum + e.toolCalls, 0);
1610
+ const iterations = live.reduce((sum, e) => sum + e.iterations, 0);
1611
+ return /* @__PURE__ */ jsxs(
1612
+ Box,
1613
+ {
1614
+ alignSelf: "stretch",
1615
+ flexDirection: "column",
1616
+ width: "100%",
1617
+ borderStyle: "round",
1618
+ borderColor: "magenta",
1619
+ paddingX: 1,
1620
+ flexGrow: 1,
1621
+ children: [
1622
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1623
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "AGENTS \xB7 LIVE" }),
1624
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1625
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1626
+ "\u25B6",
1627
+ running
1628
+ ] }),
1629
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
1630
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "done" }),
1631
+ /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1632
+ "\u2713",
1633
+ totalDone
1634
+ ] }),
1635
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
1636
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "failed" }),
1637
+ totalFailed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
1638
+ "\u2717",
1639
+ totalFailed
1640
+ ] }) : null,
1641
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 \u2191\u2193 nav \xB7 Ctrl+G / F3 close" })
1642
+ ] }),
1643
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1644
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "pulse" }),
1645
+ /* @__PURE__ */ jsxs(Text, { color: pressure >= 0.9 ? "red" : pressure >= 0.75 ? "yellow" : "green", children: [
1646
+ "max ctx ",
1647
+ Math.round(pressure * 100),
1648
+ "%"
1649
+ ] }),
1650
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 hot" }),
1651
+ hotAgent ? /* @__PURE__ */ jsxs(Text, { color: riskMeta(agentRisk(hotAgent)).color, children: [
1652
+ hotAgent.name,
1653
+ " ",
1654
+ hotAgent.ctxPct !== void 0 ? `${Math.round(hotAgent.ctxPct * 100)}%` : ""
1655
+ ] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "none" }),
1656
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 throughput" }),
1657
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
1658
+ iterations,
1659
+ "L/",
1660
+ toolCalls,
1661
+ "t"
1662
+ ] })
1663
+ ] }),
1664
+ live.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1665
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "models" }),
1666
+ (() => {
1667
+ const seen = /* @__PURE__ */ new Map();
1668
+ for (const e of live) {
1669
+ if (e.model) seen.set(e.name ?? e.id, `${e.provider ?? "?"}/${e.model}`);
1670
+ }
1671
+ return [...seen.entries()].slice(0, 4).map(([name, mod]) => /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1672
+ name,
1673
+ ":",
1674
+ mod
1675
+ ] }, name));
1676
+ })()
1677
+ ] }) : null,
1678
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1679
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "shown" }),
1680
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: live.length }),
1681
+ totalTokens ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1682
+ " ",
1683
+ fmtTokens2(totalTokens.input),
1684
+ "\u2191 ",
1685
+ fmtTokens2(totalTokens.output),
1686
+ "\u2193"
1687
+ ] }) : null,
1688
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "total" }),
1689
+ /* @__PURE__ */ jsxs(Text, { color: "green", bold: true, children: [
1690
+ "$",
1691
+ grandCost.toFixed(4)
1692
+ ] }),
1693
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1694
+ "(leader $",
1695
+ leaderCost.toFixed(4),
1696
+ " \xB7 fleet $",
1697
+ totalCost.toFixed(4),
1698
+ ")"
1699
+ ] }),
1700
+ staleIdle > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1701
+ "\xB7 ",
1702
+ staleIdle,
1703
+ " idle stale"
1704
+ ] }) : null
1705
+ ] }),
1706
+ live.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No live agents \u2014 spawn with /spawn or /fleet dispatch." }) : null,
1707
+ live.map((e) => e.id === selected?.id ? /* @__PURE__ */ jsx(AgentDetail, { entry: e, now: nowTick }, e.id) : /* @__PURE__ */ jsx(AgentRow, { entry: e, now: nowTick, selected: false }, e.id))
1708
+ ]
1709
+ }
1710
+ );
1416
1711
  }
1417
1712
  var AUTONOMY_OPTIONS = [
1418
1713
  {
@@ -1872,25 +2167,121 @@ function FleetPanel({
1872
2167
  ] }) : null
1873
2168
  ] });
1874
2169
  }
1875
- var F_KEY_ENTRIES = [
1876
- { key: 1, label: "Project switcher", action: "projectPickerOpen" },
1877
- { key: 2, label: "Fleet orchestration monitor", action: "toggleMonitor" },
1878
- { key: 3, label: "Agents live monitor", action: "toggleAgentsMonitor" },
1879
- { key: 4, label: "Worktree monitor", action: "toggleWorktreeMonitor" },
1880
- { key: 5, label: "Autonomy settings", action: "togglePlanPanel" },
1881
- { key: 6, label: "Todos monitor overlay", action: "toggleTodosMonitor" },
1882
- { key: 7, label: "Queue panel", action: "toggleQueuePanel" },
1883
- { key: 8, label: "Process list overlay", action: "toggleProcessList" },
1884
- { key: 9, label: "Goal panel", action: "toggleGoalPanel" },
1885
- { key: 10, label: "Live sessions panel", action: "toggleSessionsPanel" },
1886
- { key: 11, label: "Coordinator monitor", action: "toggleCoordinatorMonitor" },
1887
- { key: 12, label: "Status line picker", action: "statuslineOpen" }
2170
+
2171
+ // src/f-key-panels.ts
2172
+ var F_KEY_PANEL_ENTRIES = [
2173
+ {
2174
+ key: 1,
2175
+ label: "Project switcher",
2176
+ action: "projectPickerOpen",
2177
+ helpKeys: "F1",
2178
+ helpDescription: "project switcher (also /project)"
2179
+ },
2180
+ {
2181
+ key: 2,
2182
+ label: "Fleet orchestration monitor",
2183
+ action: "toggleMonitor",
2184
+ helpKeys: "Ctrl+F / F2",
2185
+ helpDescription: "fleet orchestration monitor"
2186
+ },
2187
+ {
2188
+ key: 3,
2189
+ label: "Agents live monitor",
2190
+ action: "toggleAgentsMonitor",
2191
+ helpKeys: "Ctrl+G / F3",
2192
+ helpDescription: "agents live monitor"
2193
+ },
2194
+ {
2195
+ key: 4,
2196
+ label: "Worktree monitor",
2197
+ action: "toggleWorktreeMonitor",
2198
+ helpKeys: "Ctrl+T / F4",
2199
+ helpDescription: "worktree monitor"
2200
+ },
2201
+ {
2202
+ key: 5,
2203
+ label: "Plan panel",
2204
+ action: "togglePlanPanel",
2205
+ helpKeys: "F5",
2206
+ helpDescription: "plan panel"
2207
+ },
2208
+ {
2209
+ key: 6,
2210
+ label: "Todos monitor overlay",
2211
+ action: "toggleTodosMonitor",
2212
+ helpKeys: "F6",
2213
+ helpDescription: "todos monitor overlay"
2214
+ },
2215
+ {
2216
+ key: 7,
2217
+ label: "Queue panel",
2218
+ action: "toggleQueuePanel",
2219
+ helpKeys: "F7",
2220
+ helpDescription: "queue panel"
2221
+ },
2222
+ {
2223
+ key: 8,
2224
+ label: "Process list overlay",
2225
+ action: "toggleProcessList",
2226
+ helpKeys: "F8",
2227
+ helpDescription: "process list overlay"
2228
+ },
2229
+ {
2230
+ key: 9,
2231
+ label: "Goal panel",
2232
+ action: "toggleGoalPanel",
2233
+ helpKeys: "F9",
2234
+ helpDescription: "goal panel"
2235
+ },
2236
+ {
2237
+ key: 10,
2238
+ label: "Live sessions panel",
2239
+ action: "toggleSessionsPanel",
2240
+ helpKeys: "F10",
2241
+ helpDescription: "live sessions panel"
2242
+ },
2243
+ {
2244
+ key: 11,
2245
+ label: "Coordinator monitor",
2246
+ action: "toggleCoordinatorMonitor",
2247
+ helpKeys: "F11",
2248
+ helpDescription: "coordinator monitor"
2249
+ },
2250
+ {
2251
+ key: 12,
2252
+ label: "Status line picker",
2253
+ action: "statuslineOpen",
2254
+ helpKeys: "F12",
2255
+ helpDescription: "status line picker"
2256
+ }
1888
2257
  ];
2258
+ var PAYLOAD_FREE_ACTIONS = /* @__PURE__ */ new Set([
2259
+ "toggleMonitor",
2260
+ "toggleAgentsMonitor",
2261
+ "toggleWorktreeMonitor",
2262
+ "togglePlanPanel",
2263
+ "toggleTodosMonitor",
2264
+ "toggleQueuePanel",
2265
+ "toggleProcessList",
2266
+ "toggleGoalPanel",
2267
+ "toggleSessionsPanel",
2268
+ "toggleCoordinatorMonitor"
2269
+ ]);
2270
+ function actionForFKeyPanel(entry, hiddenItems = []) {
2271
+ if (entry.action === "projectPickerOpen") return null;
2272
+ if (entry.action === "statuslineOpen") {
2273
+ return { type: "statuslineOpen", hiddenItems: [...hiddenItems] };
2274
+ }
2275
+ if (PAYLOAD_FREE_ACTIONS.has(entry.action)) {
2276
+ return { type: entry.action };
2277
+ }
2278
+ return null;
2279
+ }
1889
2280
  function FKeyPicker({ selected }) {
1890
2281
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, flexShrink: 0, children: [
1891
2282
  /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 F-Key Panels \u2501\u2501" }),
1892
2283
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \xB7 Enter open \xB7 Esc close" }),
1893
- F_KEY_ENTRIES.map((entry) => {
2284
+ F_KEY_PANEL_ENTRIES.map((entry) => {
1894
2285
  const idx = entry.key - 1;
1895
2286
  const isSelected = idx === selected;
1896
2287
  const marker = isSelected ? "\u25B8" : " ";
@@ -2006,36 +2397,6 @@ function MailboxPanel({
2006
2397
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "/mailbox \u2014 Esc to close" }) })
2007
2398
  ] });
2008
2399
  }
2009
- var TOOL_GLYPHS = {
2010
- file: "\u25A4",
2011
- edit: "\u270E",
2012
- search: "\u2315",
2013
- folder: "\u25A3",
2014
- terminal: "\u2318",
2015
- web: "\u25C8",
2016
- git: "\u2387",
2017
- tree: "\u2630",
2018
- code: "\u2699",
2019
- test: "\u2697",
2020
- package: "\u2B22",
2021
- document: "\u2637",
2022
- scaffold: "\u2731",
2023
- todo: "\u2610",
2024
- plan: "\u2756",
2025
- task: "\u25AA",
2026
- meta: "\u274F",
2027
- index: "\u229B",
2028
- json: "\u2317",
2029
- diff: "\u2206",
2030
- logs: "\u2261",
2031
- settings: "\u2699",
2032
- brain: "\u2726",
2033
- fallback: "\u2022"
2034
- };
2035
- function getToolVisual(name) {
2036
- const id = getToolIcon(name);
2037
- return { glyph: TOOL_GLYPHS[id], color: TOOL_ICON_CONFIG[id].color };
2038
- }
2039
2400
  function helpSections() {
2040
2401
  const nav = [];
2041
2402
  nav.push(
@@ -2047,16 +2408,10 @@ function helpSections() {
2047
2408
  {
2048
2409
  title: "Monitors",
2049
2410
  entries: [
2050
- { keys: "F1", desc: "project switcher (also /project)" },
2051
- { keys: "Ctrl+F / F2", desc: "fleet orchestration monitor" },
2052
- { keys: "Ctrl+G / F3", desc: "agents live monitor" },
2053
- { keys: "Ctrl+T / F4", desc: "worktree monitor" },
2054
- { keys: "F5", desc: "autonomy settings (also Ctrl+S)" },
2055
- { keys: "F6", desc: "todos monitor overlay" },
2056
- { keys: "F7", desc: "queue panel" },
2057
- { keys: "F8", desc: "process list overlay" },
2058
- { keys: "F9", desc: "goal panel" },
2059
- { keys: "F10", desc: "live sessions panel" },
2411
+ ...F_KEY_PANEL_ENTRIES.map((entry) => ({
2412
+ keys: entry.helpKeys,
2413
+ desc: entry.helpDescription
2414
+ })),
2060
2415
  { keys: "Esc", desc: "close the open monitor / overlay" }
2061
2416
  ]
2062
2417
  },
@@ -6162,6 +6517,14 @@ var CONTEXT_MODE_DESCS = {
6162
6517
  deep: "Larger context for complex tasks",
6163
6518
  archival: "Maximize context retention"
6164
6519
  };
6520
+ var STATUSLINE_MODES = ["minimum", "detailed"];
6521
+ var REASONING_MODES = ["auto", "on", "off"];
6522
+ var REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
6523
+ var CACHE_TTLS = ["default", "5m", "1h"];
6524
+ var STATUSLINE_MODE_DESCS = {
6525
+ minimum: "Single line with essential chips only",
6526
+ detailed: "Full multi-line statusline (default)"
6527
+ };
6165
6528
  var MAX_ITERATIONS_PRESETS = [100, 200, 500, 1e3, 0];
6166
6529
  var MAX_CONCURRENT_PRESETS = [1, 3, 5, 10, 25, 50, 0];
6167
6530
  var AUTO_PROCEED_MAX_PRESETS = [10, 25, 50, 100, 250, 0];
@@ -6192,7 +6555,7 @@ var MODE_DESC = {
6192
6555
  suggest: "Shows next-step suggestions after each turn",
6193
6556
  auto: "Self-driving \u2014 agent continues automatically"
6194
6557
  };
6195
- var SETTINGS_FIELD_COUNT = 29;
6558
+ var SETTINGS_FIELD_COUNT = 34;
6196
6559
  var CONFIG_SCOPES = ["global", "project"];
6197
6560
  function SettingsPicker({
6198
6561
  field,
@@ -6224,6 +6587,11 @@ function SettingsPicker({
6224
6587
  enhanceEnabled,
6225
6588
  enhanceLanguage,
6226
6589
  debugStream,
6590
+ statuslineMode,
6591
+ reasoningMode,
6592
+ reasoningEffort,
6593
+ reasoningPreserve,
6594
+ cacheTtl,
6227
6595
  configScope,
6228
6596
  hint
6229
6597
  }) {
@@ -6378,6 +6746,28 @@ function SettingsPicker({
6378
6746
  value: enhanceLanguage,
6379
6747
  detail: "original (keep language) | english (translate)"
6380
6748
  },
6749
+ // ── Reasoning ──
6750
+ { section: "Reasoning" },
6751
+ {
6752
+ label: "Reasoning mode",
6753
+ value: reasoningMode,
6754
+ detail: "auto (provider default) | on | off"
6755
+ },
6756
+ {
6757
+ label: "Reasoning effort",
6758
+ value: reasoningEffort,
6759
+ detail: "none\u2013max (model-dependent)"
6760
+ },
6761
+ {
6762
+ label: "Preserve thinking",
6763
+ value: boolVal(reasoningPreserve),
6764
+ detail: "Keep reasoning across turns"
6765
+ },
6766
+ {
6767
+ label: "Cache TTL",
6768
+ value: cacheTtl,
6769
+ detail: "Prompt cache TTL (5m | 1h)"
6770
+ },
6381
6771
  // ── Debug ──
6382
6772
  { section: "Debug" },
6383
6773
  {
@@ -6385,6 +6775,11 @@ function SettingsPicker({
6385
6775
  value: boolVal(debugStream),
6386
6776
  detail: "Hex-dump raw SSE bytes to stderr"
6387
6777
  },
6778
+ {
6779
+ label: "Statusline",
6780
+ value: statuslineMode,
6781
+ detail: STATUSLINE_MODE_DESCS[statuslineMode]
6782
+ },
6388
6783
  {
6389
6784
  label: "Config scope",
6390
6785
  value: configScope,
@@ -8262,6 +8657,26 @@ function buildSteeringPreamble(snapshot, newDirection) {
8262
8657
  lines.push("]");
8263
8658
  return lines.join("\n");
8264
8659
  }
8660
+ function closePanels(state) {
8661
+ return {
8662
+ monitorOpen: false,
8663
+ agentsMonitorOpen: false,
8664
+ helpOpen: false,
8665
+ todosMonitorOpen: false,
8666
+ queuePanelOpen: false,
8667
+ processListOpen: false,
8668
+ planPanelOpen: false,
8669
+ goalPanelOpen: false,
8670
+ sessionsPanelOpen: false,
8671
+ settingsPicker: { ...state.settingsPicker, open: false },
8672
+ statuslinePicker: { ...state.statuslinePicker, open: false },
8673
+ projectPicker: { ...state.projectPicker, open: false },
8674
+ fKeyPicker: { ...state.fKeyPicker, open: false },
8675
+ autoPhase: state.autoPhase ? { ...state.autoPhase, monitorOpen: false } : state.autoPhase,
8676
+ worktreeMonitorOpen: false,
8677
+ coordinator: { ...state.coordinator, monitorOpen: false }
8678
+ };
8679
+ }
8265
8680
  var MAX_TOOL_STREAM_RETAINED_CHARS = 1e5;
8266
8681
  var MAX_RETAINED_INPUT_CHARS = 2048;
8267
8682
  var MAX_RETAINED_INPUT_DEPTH = 4;
@@ -8529,6 +8944,7 @@ function reducer(state, action) {
8529
8944
  case "modelPickerOpen":
8530
8945
  return {
8531
8946
  ...state,
8947
+ ...closePanels(state),
8532
8948
  modelPicker: {
8533
8949
  open: true,
8534
8950
  step: "provider",
@@ -8616,6 +9032,7 @@ function reducer(state, action) {
8616
9032
  case "autonomyPickerOpen":
8617
9033
  return {
8618
9034
  ...state,
9035
+ ...closePanels(state),
8619
9036
  autonomyPicker: { open: true, options: action.options, selected: 0, hint: void 0 }
8620
9037
  };
8621
9038
  case "autonomyPickerClose":
@@ -8640,6 +9057,7 @@ function reducer(state, action) {
8640
9057
  case "resumePickerOpen":
8641
9058
  return {
8642
9059
  ...state,
9060
+ ...closePanels(state),
8643
9061
  resumePicker: { open: true, sessions: action.sessions, selected: 0, busy: false, hint: void 0, error: void 0 }
8644
9062
  };
8645
9063
  case "resumePickerClose":
@@ -8669,6 +9087,7 @@ function reducer(state, action) {
8669
9087
  case "settingsOpen":
8670
9088
  return {
8671
9089
  ...state,
9090
+ ...closePanels(state),
8672
9091
  settingsPicker: {
8673
9092
  open: true,
8674
9093
  field: 0,
@@ -8700,6 +9119,11 @@ function reducer(state, action) {
8700
9119
  enhanceEnabled: action.enhanceEnabled,
8701
9120
  enhanceLanguage: action.enhanceLanguage,
8702
9121
  debugStream: action.debugStream,
9122
+ statuslineMode: action.statuslineMode,
9123
+ reasoningMode: action.reasoningMode,
9124
+ reasoningEffort: action.reasoningEffort,
9125
+ reasoningPreserve: action.reasoningPreserve,
9126
+ cacheTtl: action.cacheTtl,
8703
9127
  configScope: action.configScope,
8704
9128
  hint: void 0
8705
9129
  }
@@ -8813,11 +9237,36 @@ function reducer(state, action) {
8813
9237
  }
8814
9238
  if (f === 27) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
8815
9239
  if (f === 28) {
9240
+ const i = STATUSLINE_MODES.indexOf(sp.statuslineMode);
9241
+ const base = i < 0 ? STATUSLINE_MODES.indexOf("detailed") : i;
9242
+ const next = (base + action.delta + STATUSLINE_MODES.length) % STATUSLINE_MODES.length;
9243
+ return { ...state, settingsPicker: { ...sp, statuslineMode: expectDefined$1(STATUSLINE_MODES[next]), hint: void 0 } };
9244
+ }
9245
+ if (f === 29) {
8816
9246
  const i = CONFIG_SCOPES.indexOf(sp.configScope);
8817
9247
  const base = i < 0 ? 0 : i;
8818
9248
  const next = (base + action.delta + CONFIG_SCOPES.length) % CONFIG_SCOPES.length;
8819
9249
  return { ...state, settingsPicker: { ...sp, configScope: expectDefined$1(CONFIG_SCOPES[next]), hint: void 0 } };
8820
9250
  }
9251
+ if (f === 30) {
9252
+ const i = REASONING_MODES.indexOf(sp.reasoningMode);
9253
+ const base = i < 0 ? 0 : i;
9254
+ const next = (base + action.delta + REASONING_MODES.length) % REASONING_MODES.length;
9255
+ return { ...state, settingsPicker: { ...sp, reasoningMode: expectDefined$1(REASONING_MODES[next]), hint: void 0 } };
9256
+ }
9257
+ if (f === 31) {
9258
+ const i = REASONING_EFFORTS.indexOf(sp.reasoningEffort);
9259
+ const base = i < 0 ? REASONING_EFFORTS.indexOf("high") : i;
9260
+ const next = (base + action.delta + REASONING_EFFORTS.length) % REASONING_EFFORTS.length;
9261
+ return { ...state, settingsPicker: { ...sp, reasoningEffort: expectDefined$1(REASONING_EFFORTS[next]), hint: void 0 } };
9262
+ }
9263
+ if (f === 32) return { ...state, settingsPicker: { ...sp, reasoningPreserve: !sp.reasoningPreserve, hint: void 0 } };
9264
+ if (f === 33) {
9265
+ const i = CACHE_TTLS.indexOf(sp.cacheTtl);
9266
+ const base = i < 0 ? 0 : i;
9267
+ const next = (base + action.delta + CACHE_TTLS.length) % CACHE_TTLS.length;
9268
+ return { ...state, settingsPicker: { ...sp, cacheTtl: expectDefined$1(CACHE_TTLS[next]), hint: void 0 } };
9269
+ }
8821
9270
  return state;
8822
9271
  }
8823
9272
  case "settingsHint":
@@ -8826,6 +9275,7 @@ function reducer(state, action) {
8826
9275
  case "statuslineOpen":
8827
9276
  return {
8828
9277
  ...state,
9278
+ ...closePanels(state),
8829
9279
  statuslinePicker: { open: true, field: 0, hiddenItems: action.hiddenItems, visibleChips: state.statuslinePicker.visibleChips, hint: void 0 }
8830
9280
  };
8831
9281
  case "statuslineClose":
@@ -8881,6 +9331,7 @@ function reducer(state, action) {
8881
9331
  case "projectPickerOpen":
8882
9332
  return {
8883
9333
  ...state,
9334
+ ...closePanels(state),
8884
9335
  projectPicker: {
8885
9336
  open: true,
8886
9337
  allItems: action.items,
@@ -8921,7 +9372,7 @@ function reducer(state, action) {
8921
9372
  case "projectPickerHint":
8922
9373
  return { ...state, projectPicker: { ...state.projectPicker, hint: action.text } };
8923
9374
  case "fKeyPickerOpen":
8924
- return { ...state, fKeyPicker: { open: true, selected: 0 } };
9375
+ return { ...state, ...closePanels(state), fKeyPicker: { open: true, selected: 0 } };
8925
9376
  case "fKeyPickerClose":
8926
9377
  return { ...state, fKeyPicker: { open: false, selected: 0 } };
8927
9378
  case "fKeyPickerMove": {
@@ -9266,35 +9717,35 @@ function reducer(state, action) {
9266
9717
  }
9267
9718
  case "toggleMonitor": {
9268
9719
  const opening = !state.monitorOpen;
9269
- return opening ? { ...state, monitorOpen: true, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, monitorOpen: false };
9720
+ return opening ? { ...state, ...closePanels(state), monitorOpen: true } : { ...state, monitorOpen: false };
9270
9721
  }
9271
9722
  case "toggleAgentsMonitor": {
9272
9723
  const opening = !state.agentsMonitorOpen;
9273
- return opening ? { ...state, agentsMonitorOpen: true, monitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, agentsMonitorOpen: false };
9724
+ return opening ? { ...state, ...closePanels(state), agentsMonitorOpen: true } : { ...state, agentsMonitorOpen: false };
9274
9725
  }
9275
9726
  case "toggleHelp": {
9276
9727
  const opening = !state.helpOpen;
9277
- return opening ? { ...state, helpOpen: true, monitorOpen: false, agentsMonitorOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, helpOpen: false };
9728
+ return opening ? { ...state, ...closePanels(state), helpOpen: true } : { ...state, helpOpen: false };
9278
9729
  }
9279
9730
  case "toggleTodosMonitor": {
9280
9731
  const opening = !state.todosMonitorOpen;
9281
- return opening ? { ...state, todosMonitorOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, todosMonitorOpen: false };
9732
+ return opening ? { ...state, ...closePanels(state), todosMonitorOpen: true } : { ...state, todosMonitorOpen: false };
9282
9733
  }
9283
9734
  case "toggleQueuePanel": {
9284
9735
  const opening = !state.queuePanelOpen;
9285
- return opening ? { ...state, queuePanelOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, queuePanelOpen: false };
9736
+ return opening ? { ...state, ...closePanels(state), queuePanelOpen: true } : { ...state, queuePanelOpen: false };
9286
9737
  }
9287
9738
  case "toggleProcessList": {
9288
9739
  const opening = !state.processListOpen;
9289
- return opening ? { ...state, processListOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, goalPanelOpen: false } : { ...state, processListOpen: false };
9740
+ return opening ? { ...state, ...closePanels(state), processListOpen: true } : { ...state, processListOpen: false };
9290
9741
  }
9291
9742
  case "togglePlanPanel": {
9292
9743
  const opening = !state.planPanelOpen;
9293
- return opening ? { ...state, planPanelOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, planPanelOpen: false };
9744
+ return opening ? { ...state, ...closePanels(state), planPanelOpen: true } : { ...state, planPanelOpen: false };
9294
9745
  }
9295
9746
  case "toggleGoalPanel": {
9296
9747
  const opening = !state.goalPanelOpen;
9297
- return opening ? { ...state, goalPanelOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false } : { ...state, goalPanelOpen: false };
9748
+ return opening ? { ...state, ...closePanels(state), goalPanelOpen: true } : { ...state, goalPanelOpen: false };
9298
9749
  }
9299
9750
  case "checkpointReceived": {
9300
9751
  const existing = state.checkpoints.find((c) => c.promptIndex === action.cp.promptIndex);
@@ -9380,9 +9831,14 @@ function reducer(state, action) {
9380
9831
  }
9381
9832
  case "autoPhaseMonitorToggle": {
9382
9833
  if (!state.autoPhase) return state;
9383
- return {
9834
+ const opening = !state.autoPhase.monitorOpen;
9835
+ return opening ? {
9384
9836
  ...state,
9385
- autoPhase: { ...state.autoPhase, monitorOpen: !state.autoPhase.monitorOpen }
9837
+ ...closePanels(state),
9838
+ autoPhase: { ...state.autoPhase, monitorOpen: true }
9839
+ } : {
9840
+ ...state,
9841
+ autoPhase: { ...state.autoPhase, monitorOpen: false }
9386
9842
  };
9387
9843
  }
9388
9844
  case "autoPhaseReset": {
@@ -9414,7 +9870,8 @@ function reducer(state, action) {
9414
9870
  return { ...state, worktrees: next };
9415
9871
  }
9416
9872
  case "worktreeMonitorToggle": {
9417
- return { ...state, worktreeMonitorOpen: !state.worktreeMonitorOpen };
9873
+ const opening = !state.worktreeMonitorOpen;
9874
+ return opening ? { ...state, ...closePanels(state), worktreeMonitorOpen: true } : { ...state, worktreeMonitorOpen: false };
9418
9875
  }
9419
9876
  // --- In-app chat scroll ---
9420
9877
  case "scrollBy": {
@@ -9609,7 +10066,8 @@ function reducer(state, action) {
9609
10066
  return { ...state, debugStreamStats: null };
9610
10067
  }
9611
10068
  case "toggleSessionsPanel": {
9612
- return { ...state, sessionsPanelOpen: !state.sessionsPanelOpen };
10069
+ const opening = !state.sessionsPanelOpen;
10070
+ return opening ? { ...state, ...closePanels(state), sessionsPanelOpen: true, sessionResumeConfirm: null } : { ...state, sessionsPanelOpen: false, sessionResumeConfirm: null };
9613
10071
  }
9614
10072
  case "sessionsPanelSet": {
9615
10073
  const sessions = Array.isArray(action.sessions) ? action.sessions : [];
@@ -9714,15 +10172,8 @@ function reducer(state, action) {
9714
10172
  const opening = !state.coordinator.monitorOpen;
9715
10173
  return opening ? {
9716
10174
  ...state,
9717
- coordinator: { ...state.coordinator, monitorOpen: true },
9718
- // Close other monitors when opening coordinator
9719
- monitorOpen: false,
9720
- agentsMonitorOpen: false,
9721
- helpOpen: false,
9722
- todosMonitorOpen: false,
9723
- queuePanelOpen: false,
9724
- processListOpen: false,
9725
- goalPanelOpen: false
10175
+ ...closePanels(state),
10176
+ coordinator: { ...state.coordinator, monitorOpen: true }
9726
10177
  } : { ...state, coordinator: { ...state.coordinator, monitorOpen: false } };
9727
10178
  }
9728
10179
  }
@@ -9842,6 +10293,9 @@ function App({
9842
10293
  subscribeCoordinatorEvents,
9843
10294
  onCoordinatorStart,
9844
10295
  onCoordinatorStop,
10296
+ // Reserved for the coordinator monitor panel: terminal-driven task discovery/claim.
10297
+ onCoordinatorTasks: _onCoordinatorTasks,
10298
+ onCoordinatorClaim: _onCoordinatorClaim,
9845
10299
  coordinatorRunning = false,
9846
10300
  clientId
9847
10301
  }) {
@@ -10003,7 +10457,7 @@ function App({
10003
10457
  },
10004
10458
  autonomyPicker: { open: false, options: [], selected: 0 },
10005
10459
  resumePicker: { open: false, sessions: [], selected: 0, busy: false, hint: void 0, error: void 0 },
10006
- settingsPicker: { open: false, field: 0, mode: "off", delayMs: 0, titleAnimation: true, yolo: false, streamFleet: true, chime: false, confirmExit: true, nextPrediction: false, featureMcp: true, featurePlugins: true, featureMemory: true, featureSkills: true, featureModelsRegistry: true, tokenSavingTier: "off", allowOutsideProjectRoot: true, contextAutoCompact: true, contextStrategy: "hybrid", contextMode: "balanced", maxConcurrent: 10, logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500, autoProceedMaxIterations: 50, enhanceDelayMs: 6e4, enhanceEnabled: true, enhanceLanguage: "original", debugStream: false, configScope: "global" },
10460
+ settingsPicker: { open: false, field: 0, mode: "off", delayMs: 0, titleAnimation: true, yolo: false, streamFleet: true, chime: false, confirmExit: true, nextPrediction: false, featureMcp: true, featurePlugins: true, featureMemory: true, featureSkills: true, featureModelsRegistry: true, tokenSavingTier: "off", allowOutsideProjectRoot: true, contextAutoCompact: true, contextStrategy: "hybrid", contextMode: "balanced", maxConcurrent: 10, logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500, autoProceedMaxIterations: 50, enhanceDelayMs: 6e4, enhanceEnabled: true, enhanceLanguage: "original", debugStream: false, statuslineMode: "detailed", reasoningMode: "auto", reasoningEffort: "high", reasoningPreserve: false, cacheTtl: "default", configScope: "global" },
10007
10461
  statuslinePicker: { open: false, field: 0, hiddenItems: [], visibleChips: [], hint: void 0 },
10008
10462
  projectPicker: { open: false, allItems: [], items: [], selected: 0, filter: "", hint: void 0 },
10009
10463
  fKeyPicker: { open: false, selected: 0 },
@@ -10137,6 +10591,7 @@ function App({
10137
10591
  });
10138
10592
  }, [agent.ctx, projectRoot]);
10139
10593
  const liveSettings = getSettings?.();
10594
+ const liveStatuslineMode = liveSettings?.statuslineMode ?? "detailed";
10140
10595
  const chimeRef = useRef(chime);
10141
10596
  chimeRef.current = liveSettings?.chime ?? chime;
10142
10597
  const confirmExitRef = useRef(confirmExit);
@@ -10200,11 +10655,11 @@ function App({
10200
10655
  async (checkpointIndex) => {
10201
10656
  const sessionId = agent.ctx.session.id;
10202
10657
  if (!sessionId) return;
10203
- const rewinder = new DefaultSessionRewinder(sessionsDir ?? "", projectRoot ?? agent.ctx.cwd);
10658
+ const rewinder = new DefaultSessionRewinder(sessionsDir ?? "", agent.ctx.projectRoot ?? agent.ctx.cwd);
10204
10659
  await rewinder.rewindToCheckpoint(sessionId, checkpointIndex);
10205
10660
  await agent.ctx.session.truncateToCheckpoint(checkpointIndex);
10206
10661
  },
10207
- [agent.ctx.session, sessionsDir, projectRoot, agent.ctx.cwd]
10662
+ [agent.ctx.session, sessionsDir, agent.ctx.projectRoot, agent.ctx.cwd]
10208
10663
  );
10209
10664
  const setDraft = (buffer, cursor) => {
10210
10665
  draftRef.current = { buffer, cursor };
@@ -10501,8 +10956,8 @@ function App({
10501
10956
  const leaderEntry = {
10502
10957
  id: "leader",
10503
10958
  name: "LEADER",
10504
- provider,
10505
- model,
10959
+ provider: liveProvider,
10960
+ model: liveModel,
10506
10961
  status: state.status === "running" || state.status === "streaming" || state.leader.iterating ? "running" : "idle",
10507
10962
  streamingText: "",
10508
10963
  iterations: state.leader.iterations,
@@ -10521,7 +10976,7 @@ function App({
10521
10976
  ctxMaxTokens: state.leader.ctxMaxTokens ?? effectiveMaxContext
10522
10977
  };
10523
10978
  return { leader: leaderEntry, ...state.fleet };
10524
- }, [state.fleet, state.leader, state.status, provider, model, effectiveMaxContext, tokenCounter]);
10979
+ }, [state.fleet, state.leader, state.status, liveProvider, liveModel, effectiveMaxContext, tokenCounter]);
10525
10980
  const [planCounts, setPlanCounts] = useState(null);
10526
10981
  useEffect(() => {
10527
10982
  const planPath = agent.ctx.meta["plan.path"];
@@ -10716,6 +11171,11 @@ function App({
10716
11171
  enhanceEnabled: sp.enhanceEnabled,
10717
11172
  enhanceLanguage: sp.enhanceLanguage,
10718
11173
  debugStream: sp.debugStream,
11174
+ statuslineMode: sp.statuslineMode,
11175
+ reasoningMode: sp.reasoningMode,
11176
+ reasoningEffort: sp.reasoningEffort,
11177
+ reasoningPreserve: sp.reasoningPreserve,
11178
+ cacheTtl: sp.cacheTtl,
10719
11179
  configScope: sp.configScope
10720
11180
  });
10721
11181
  }
@@ -11126,6 +11586,11 @@ function App({
11126
11586
  enhanceEnabled: s2.enhanceEnabled ?? true,
11127
11587
  enhanceLanguage: s2.enhanceLanguage ?? "original",
11128
11588
  debugStream: s2.debugStream ?? false,
11589
+ statuslineMode: s2.statuslineMode ?? "detailed",
11590
+ reasoningMode: s2.reasoningMode ?? "auto",
11591
+ reasoningEffort: s2.reasoningEffort ?? "high",
11592
+ reasoningPreserve: s2.reasoningPreserve ?? false,
11593
+ cacheTtl: s2.cacheTtl ?? "default",
11129
11594
  configScope: s2.configScope ?? "global"
11130
11595
  });
11131
11596
  }, [getSettings]);
@@ -11264,6 +11729,11 @@ function App({
11264
11729
  enhanceEnabled: sp.enhanceEnabled,
11265
11730
  enhanceLanguage: sp.enhanceLanguage,
11266
11731
  debugStream: sp.debugStream,
11732
+ statuslineMode: sp.statuslineMode,
11733
+ reasoningMode: sp.reasoningMode,
11734
+ reasoningEffort: sp.reasoningEffort,
11735
+ reasoningPreserve: sp.reasoningPreserve,
11736
+ cacheTtl: sp.cacheTtl,
11267
11737
  configScope: sp.configScope
11268
11738
  })).then((err) => {
11269
11739
  if (err) dispatch({ type: "settingsHint", text: err });
@@ -11298,6 +11768,11 @@ function App({
11298
11768
  state.settingsPicker.enhanceEnabled,
11299
11769
  state.settingsPicker.enhanceLanguage,
11300
11770
  state.settingsPicker.debugStream,
11771
+ state.settingsPicker.statuslineMode,
11772
+ state.settingsPicker.reasoningMode,
11773
+ state.settingsPicker.reasoningEffort,
11774
+ state.settingsPicker.reasoningPreserve,
11775
+ state.settingsPicker.cacheTtl,
11301
11776
  saveSettings
11302
11777
  ]);
11303
11778
  useEffect(() => {
@@ -12162,13 +12637,13 @@ function App({
12162
12637
  if (item.kind === "project") {
12163
12638
  await onProjectSelect?.(item.key, item.kind);
12164
12639
  dispatch({ type: "projectPickerClose" });
12165
- requestExit?.(42);
12640
+ dispatch({ type: "addEntry", entry: { kind: "info", text: `Switched project: ${item.label.trim()}.` } });
12166
12641
  return;
12167
12642
  }
12168
12643
  dispatch({ type: "projectPickerClose" });
12169
12644
  if (item.key === "new-session") {
12170
12645
  await onProjectSelect?.(item.key, item.kind);
12171
- requestExit?.(42);
12646
+ dispatch({ type: "addEntry", entry: { kind: "info", text: "Started a fresh session in this project." } });
12172
12647
  } else if (item.key === "prev-sessions") {
12173
12648
  void submit("/resume");
12174
12649
  }
@@ -12332,10 +12807,15 @@ function App({
12332
12807
  }
12333
12808
  if (isEnter) {
12334
12809
  const selected = state.fKeyPicker.selected;
12335
- const entry = F_KEY_ENTRIES[selected];
12810
+ const entry = F_KEY_PANEL_ENTRIES[selected];
12336
12811
  if (!entry) return;
12337
12812
  dispatch({ type: "fKeyPickerClose" });
12338
- dispatch({ type: entry.action });
12813
+ if (entry.action === "projectPickerOpen") {
12814
+ openProjectPicker();
12815
+ return;
12816
+ }
12817
+ const action = actionForFKeyPanel(entry, state.statuslinePicker.hiddenItems);
12818
+ if (action) dispatch(action);
12339
12819
  return;
12340
12820
  }
12341
12821
  return;
@@ -12595,6 +13075,10 @@ function App({
12595
13075
  dispatch({ type: "toggleCoordinatorMonitor" });
12596
13076
  return;
12597
13077
  }
13078
+ if (key.fn === 12) {
13079
+ dispatch({ type: "statuslineOpen", hiddenItems: state.statuslinePicker.hiddenItems });
13080
+ return;
13081
+ }
12598
13082
  if (key.ctrl && input === "s") {
12599
13083
  if (state.settingsPicker.open) {
12600
13084
  dispatch({ type: "settingsClose" });
@@ -12637,6 +13121,11 @@ function App({
12637
13121
  enhanceEnabled: cfg.enhanceEnabled ?? true,
12638
13122
  enhanceLanguage: cfg.enhanceLanguage ?? "original",
12639
13123
  debugStream: cfg.debugStream ?? false,
13124
+ statuslineMode: cfg.statuslineMode ?? "detailed",
13125
+ reasoningMode: cfg.reasoningMode ?? "auto",
13126
+ reasoningEffort: cfg.reasoningEffort ?? "high",
13127
+ reasoningPreserve: cfg.reasoningPreserve ?? false,
13128
+ cacheTtl: cfg.cacheTtl ?? "default",
12640
13129
  configScope: cfg.configScope ?? "global"
12641
13130
  });
12642
13131
  }
@@ -13562,6 +14051,7 @@ User message:
13562
14051
  );
13563
14052
  const inputHeight = Math.max(1, inputCellRows.length);
13564
14053
  const hideInput = enhanceActive || state.helpOpen || state.processListOpen;
14054
+ const lowerFunctionPanelOpen = state.monitorOpen || state.agentsMonitorOpen || (state.autoPhase?.monitorOpen ?? false) || state.worktreeMonitorOpen || state.planPanelOpen || state.todosMonitorOpen || state.queuePanelOpen || state.processListOpen || state.goalPanelOpen;
13565
14055
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 0, children: [
13566
14056
  mouseMode ? /* @__PURE__ */ jsx(
13567
14057
  ScrollableHistory,
@@ -13682,6 +14172,11 @@ User message:
13682
14172
  enhanceEnabled: state.settingsPicker.enhanceEnabled,
13683
14173
  enhanceLanguage: state.settingsPicker.enhanceLanguage,
13684
14174
  debugStream: state.settingsPicker.debugStream,
14175
+ statuslineMode: state.settingsPicker.statuslineMode,
14176
+ reasoningMode: state.settingsPicker.reasoningMode,
14177
+ reasoningEffort: state.settingsPicker.reasoningEffort,
14178
+ reasoningPreserve: state.settingsPicker.reasoningPreserve,
14179
+ cacheTtl: state.settingsPicker.cacheTtl,
13685
14180
  configScope: state.settingsPicker.configScope,
13686
14181
  hint: state.settingsPicker.hint
13687
14182
  }
@@ -13860,6 +14355,7 @@ User message:
13860
14355
  subagentCount: Object.keys(state.fleet).length,
13861
14356
  processCount: getProcessRegistry().activeCount,
13862
14357
  hiddenItems,
14358
+ mode: liveStatuslineMode,
13863
14359
  visibleChips: state.statuslinePicker.visibleChips,
13864
14360
  events,
13865
14361
  eternalStage: state.eternalStage,
@@ -13896,7 +14392,8 @@ User message:
13896
14392
  totalCost: state.fleetCost,
13897
14393
  leaderCost: tokenCounter?.estimateCost().total ?? 0,
13898
14394
  totalTokens: state.fleetTokens,
13899
- nowTick
14395
+ nowTick,
14396
+ onClose: () => dispatch({ type: "toggleAgentsMonitor" })
13900
14397
  }
13901
14398
  ) : state.autoPhase?.monitorOpen ? /* @__PURE__ */ jsx(
13902
14399
  PhaseMonitor,
@@ -13924,6 +14421,21 @@ User message:
13924
14421
  nowTick,
13925
14422
  collabSession: state.collabSession
13926
14423
  }
14424
+ ) : state.planPanelOpen ? /* @__PURE__ */ jsx(
14425
+ PlanPanel,
14426
+ {
14427
+ projectRoot: agent.ctx.projectRoot,
14428
+ sessionId: agent.ctx.session?.id ?? null,
14429
+ onClose: () => dispatch({ type: "togglePlanPanel" })
14430
+ }
14431
+ ) : state.queuePanelOpen ? /* @__PURE__ */ jsx(QueuePanel, { items: state.queue }) : state.processListOpen ? /* @__PURE__ */ jsx(ProcessListMonitor, {}) : state.goalPanelOpen ? /* @__PURE__ */ jsx(
14432
+ GoalPanel,
14433
+ {
14434
+ goal: state.goalSummary,
14435
+ onCoordinatorStart: onCoordinatorStart ?? void 0,
14436
+ onCoordinatorStop: onCoordinatorStop ?? void 0,
14437
+ coordinatorRunning
14438
+ }
13927
14439
  ) : director ? /* @__PURE__ */ jsx(
13928
14440
  FleetPanel,
13929
14441
  {
@@ -13933,7 +14445,7 @@ User message:
13933
14445
  collabSession: state.collabSession
13934
14446
  }
13935
14447
  ) : null,
13936
- state.autoPhase && !state.autoPhase.monitorOpen ? /* @__PURE__ */ jsx(
14448
+ state.autoPhase && !lowerFunctionPanelOpen ? /* @__PURE__ */ jsx(
13937
14449
  PhasePanel,
13938
14450
  {
13939
14451
  phases: state.autoPhase.phases,
@@ -13941,26 +14453,7 @@ User message:
13941
14453
  nowTick
13942
14454
  }
13943
14455
  ) : null,
13944
- Object.keys(state.worktrees).length > 0 && !state.worktreeMonitorOpen && !state.monitorOpen ? /* @__PURE__ */ jsx(WorktreePanel, { worktrees: state.worktrees, nowTick }) : null,
13945
- state.queuePanelOpen ? /* @__PURE__ */ jsx(QueuePanel, { items: state.queue }) : null,
13946
- state.processListOpen ? /* @__PURE__ */ jsx(ProcessListMonitor, {}) : null,
13947
- state.planPanelOpen ? /* @__PURE__ */ jsx(
13948
- PlanPanel,
13949
- {
13950
- projectRoot,
13951
- sessionId: agent.ctx.session?.id ?? null,
13952
- onClose: () => dispatch({ type: "togglePlanPanel" })
13953
- }
13954
- ) : null,
13955
- state.goalPanelOpen ? /* @__PURE__ */ jsx(
13956
- GoalPanel,
13957
- {
13958
- goal: state.goalSummary,
13959
- onCoordinatorStart: onCoordinatorStart ?? void 0,
13960
- onCoordinatorStop: onCoordinatorStop ?? void 0,
13961
- coordinatorRunning
13962
- }
13963
- ) : null,
14456
+ Object.keys(state.worktrees).length > 0 && !lowerFunctionPanelOpen ? /* @__PURE__ */ jsx(WorktreePanel, { worktrees: state.worktrees, nowTick }) : null,
13964
14457
  (() => {
13965
14458
  const anyMonitorOpen = state.agentsMonitorOpen || (state.autoPhase?.monitorOpen ?? false) || state.worktreeMonitorOpen || state.todosMonitorOpen || state.monitorOpen || state.processListOpen || state.queuePanelOpen || state.goalPanelOpen;
13966
14459
  let nextPanelHint;
@@ -14208,7 +14701,9 @@ async function runTui(opts) {
14208
14701
  if (!opts.projectRoot) return null;
14209
14702
  try {
14210
14703
  const projectDir = resolveProjectDir(opts.projectRoot, wstackGlobalRoot());
14211
- const mailbox = new GlobalMailbox(projectDir, opts.events);
14704
+ const hqPublisher = createHqPublisherFromEnv({ clientKind: "tui", projectRoot: opts.projectRoot, projectName: path5.basename(opts.projectRoot), appConfig: opts.appConfig });
14705
+ hqPublisher?.connect();
14706
+ const mailbox = new GlobalMailbox(projectDir, opts.events, hqPublisher);
14212
14707
  const clientId = `tui@${randomUUID().slice(0, 8)}`;
14213
14708
  await mailbox.registerClient({
14214
14709
  clientId,
@@ -14360,7 +14855,12 @@ async function runTui(opts) {
14360
14855
  subscribeCoordinatorEvents: opts.subscribeCoordinatorEvents,
14361
14856
  onPanelOpen: opts.onPanelOpen,
14362
14857
  onCoordinatorStart: opts.onCoordinatorStart,
14363
- onCoordinatorStop: opts.onCoordinatorStop
14858
+ onCoordinatorStop: opts.onCoordinatorStop,
14859
+ onCoordinatorTasks: opts.onCoordinatorTasks,
14860
+ onCoordinatorClaim: opts.onCoordinatorClaim,
14861
+ onCoordinatorComplete: opts.onCoordinatorComplete,
14862
+ onCoordinatorFail: opts.onCoordinatorFail,
14863
+ onCoordinatorStatus: opts.onCoordinatorStatus
14364
14864
  }),
14365
14865
  { exitOnCtrlC: false, stdin: inkStdin }
14366
14866
  );