@cesarus777/opencode-cgp 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -936,6 +936,51 @@ function executionStatus(known, nativeRunning, evidence) {
936
936
  return known ? "idle" : "unknown";
937
937
  }
938
938
 
939
+ // src/historyclient.ts
940
+ function historyFailure(error, signal) {
941
+ if (signal?.aborted && signal.reason instanceof DOMException && signal.reason.name === "TimeoutError" || error instanceof DOMException && error.name === "TimeoutError")
942
+ return new HistoryFailure("timeout");
943
+ if (error instanceof HistoryFailure)
944
+ return error;
945
+ const code = typeof error === "object" && error !== null && "type" in error ? error.type : undefined;
946
+ return new HistoryFailure(code === "rpc.unavailable" || code === "rpc.method_not_found" ? "unsupported" : code === "rpc.invalid_output" ? "incompatible" : code === "rpc.invalid_input" ? "rejected" : "unavailable");
947
+ }
948
+ function checkedHistory(value, sessionId) {
949
+ if (!isHistoryResult(value) || value.data.series.some((series) => series.sessionId !== sessionId))
950
+ throw new HistoryFailure("incompatible");
951
+ return value;
952
+ }
953
+ function historyStatusLines(input) {
954
+ const messages = {
955
+ unsupported: "History service is unavailable in this server location. Check that the owning server has a plugin version with chart history. Press r to check again.",
956
+ timeout: "History request timed out. Press r to retry.",
957
+ incompatible: "History response is incompatible. Check client/server plugin versions. Press r to retry.",
958
+ rejected: "History request was rejected. Check client/server plugin versions. Press r to retry.",
959
+ unavailable: "History could not be loaded. Press r to retry."
960
+ };
961
+ return [
962
+ ...input.status === "loading" ? [
963
+ input.loadedAt === undefined ? "Loading retained history\u2026" : "Updating history \xB7 showing previous results"
964
+ ] : input.status === "disabled" ? [
965
+ "History recording is disabled in this server location. Press r to check again after configuration changes."
966
+ ] : input.status === "unavailable" ? [messages[input.reason ?? "unavailable"]] : [],
967
+ ...input.stale && input.loadedAt !== undefined ? [
968
+ `Showing previous results \xB7 last loaded ${new Date(input.loadedAt).toISOString()}`
969
+ ] : []
970
+ ];
971
+ }
972
+ var HistoryFailure;
973
+ var init_historyclient = __esm(() => {
974
+ init_rpc();
975
+ HistoryFailure = class HistoryFailure extends Error {
976
+ reason;
977
+ constructor(reason) {
978
+ super(`History ${reason}`);
979
+ this.reason = reason;
980
+ }
981
+ };
982
+ });
983
+
939
984
  // src/tui/transport.ts
940
985
  class SnapshotClient {
941
986
  transport;
@@ -1628,6 +1673,7 @@ class DashboardController {
1628
1673
  pendingHistory;
1629
1674
  historyAbort;
1630
1675
  historyBusy = false;
1676
+ historyReason;
1631
1677
  historyStatus = "idle";
1632
1678
  refreshTimer;
1633
1679
  ageTimer;
@@ -1919,6 +1965,7 @@ class DashboardController {
1919
1965
  }
1920
1966
  cancelHistory() {
1921
1967
  this.historyGeneration++;
1968
+ this.historyReason = undefined;
1922
1969
  this.pendingHistory = undefined;
1923
1970
  this.historyAbort?.abort();
1924
1971
  }
@@ -1972,10 +2019,10 @@ class DashboardController {
1972
2019
  }, signal);
1973
2020
  if (signal.aborted || task.generation !== this.historyGeneration)
1974
2021
  return;
1975
- if (!isHistoryResult(result) || result.data.series.some((series) => series.sessionId !== task.sessionId))
1976
- throw new Error("Invalid history response");
2022
+ checkedHistory(result, task.sessionId);
1977
2023
  this.cache.set(task.key, {
1978
2024
  directory: task.state.port.location.directory,
2025
+ loadedAt: this.now(),
1979
2026
  valid: true,
1980
2027
  result: structuredClone(result),
1981
2028
  from,
@@ -1987,12 +2034,16 @@ class DashboardController {
1987
2034
  this.cache.delete(oldest);
1988
2035
  }
1989
2036
  this.historyStatus = result.enabled ? "ready" : "disabled";
1990
- } catch {
1991
- if (task.generation === this.historyGeneration && !task.scope.aborted)
2037
+ } catch (error) {
2038
+ if (task.generation === this.historyGeneration && !task.scope.aborted) {
1992
2039
  this.historyStatus = "unavailable";
2040
+ this.historyReason = historyFailure(error, signal).reason;
2041
+ }
1993
2042
  } finally {
1994
- if (task.generation === this.historyGeneration && signal.aborted && !task.scope.aborted)
2043
+ if (task.generation === this.historyGeneration && signal.aborted && !task.scope.aborted) {
1995
2044
  this.historyStatus = "unavailable";
2045
+ this.historyReason = historyFailure(undefined, signal).reason;
2046
+ }
1996
2047
  this.historyBusy = false;
1997
2048
  if (this.historyAbort === controller)
1998
2049
  this.historyAbort = undefined;
@@ -2077,12 +2128,13 @@ class DashboardController {
2077
2128
  ...selected ? { selected } : {},
2078
2129
  history: {
2079
2130
  status: this.historyStatus,
2131
+ ...this.historyReason ? { reason: this.historyReason } : {},
2080
2132
  windowMs: this.windowMs,
2081
2133
  maxWindowMs: 604800000,
2082
2134
  maxPoints: 500,
2083
2135
  stale: this.historyStatus === "loading" || this.historyStatus === "unavailable" || !this.running,
2084
2136
  ...state.selected ? { sessionId: state.selected } : {},
2085
- ...cached ? { from: cached.from, to: cached.to } : {},
2137
+ ...cached ? { from: cached.from, to: cached.to, loadedAt: cached.loadedAt } : {},
2086
2138
  ...projected ? { result: projected.result, summary: projected.summary } : {},
2087
2139
  notices: projected?.notices ?? [
2088
2140
  "bounded-retention",
@@ -2100,7 +2152,7 @@ class DashboardController {
2100
2152
  }
2101
2153
  }
2102
2154
  var init_controller = __esm(() => {
2103
- init_rpc();
2155
+ init_historyclient();
2104
2156
  init_transport();
2105
2157
  init_inventory();
2106
2158
  init_models();
@@ -2272,13 +2324,12 @@ async function connectDashboard(options, discovery = Service) {
2272
2324
  async history(input, signal) {
2273
2325
  if (!isHistoryRead(input))
2274
2326
  throw new Error("History requires one session, at most seven days and 16\u2013500 points");
2327
+ const requestSignal = deadline(signal);
2275
2328
  try {
2276
- const result = await client.rpc(historyRpc).read(input, { location, signal: deadline(signal) });
2277
- if (!isHistoryResult(result))
2278
- throw new Error;
2279
- return result;
2280
- } catch {
2281
- throw new Error("Context Guard history unavailable or incompatible in this location");
2329
+ const result = await client.rpc(historyRpc).read(input, { location, signal: requestSignal });
2330
+ return checkedHistory(result, input.sessionId);
2331
+ } catch (error) {
2332
+ throw historyFailure(error, requestSignal);
2282
2333
  }
2283
2334
  }
2284
2335
  };
@@ -2295,10 +2346,214 @@ async function connectDashboard(options, discovery = Service) {
2295
2346
  };
2296
2347
  }
2297
2348
  var init_connection = __esm(() => {
2349
+ init_historyclient();
2298
2350
  init_rpc();
2299
2351
  init_port();
2300
2352
  });
2301
2353
 
2354
+ // src/tui/quantity.ts
2355
+ function tokens(value) {
2356
+ if (value === undefined || !Number.isFinite(value))
2357
+ return "?";
2358
+ const magnitude = Math.abs(value);
2359
+ if (magnitude >= 1e6)
2360
+ return `${+(value / 1e6).toFixed(1)}M`;
2361
+ if (magnitude >= 1000)
2362
+ return `${+(value / 1000).toFixed(1)}K`;
2363
+ return String(value);
2364
+ }
2365
+
2366
+ // src/tui/statusformat.ts
2367
+ function freshnessLabel(row2) {
2368
+ switch (row2?.freshness) {
2369
+ case "fresh":
2370
+ return;
2371
+ case "stale":
2372
+ return "Measurement out of date";
2373
+ case "invalid":
2374
+ return "Usage unavailable";
2375
+ default:
2376
+ return "Usage unknown";
2377
+ }
2378
+ }
2379
+ function measurementLabel(row2, ageMs) {
2380
+ const m = row2?.snapshot?.measurement;
2381
+ if (!m || row2?.freshness === "missing")
2382
+ return "Usage unknown";
2383
+ if (row2?.freshness === "invalid")
2384
+ return "Usage unavailable";
2385
+ const age = ageMs === undefined ? "" : ` \xB7 measured ${Math.floor(Math.max(0, ageMs) / 1000)}s ago`;
2386
+ return `${m.confidence === "reported" ? "Provider reported" : "Estimated"}${age}${row2?.freshness === "stale" ? " \xB7 out of date" : ""}`;
2387
+ }
2388
+ function measurementExplanation(row2) {
2389
+ const m = row2.snapshot?.measurement;
2390
+ if (!m || row2.freshness === "missing")
2391
+ return ["No measurement available."];
2392
+ if (row2.freshness === "invalid")
2393
+ return ["Measurement cannot be used for this session."];
2394
+ return [
2395
+ m.scope === "completed-request" ? "Usage from the last completed request; not the next request's size." : "Usage for the prepared request; not a completed request.",
2396
+ m.provenance === "serialized-estimate" ? "Estimate from serialized request content." : "Provider usage includes input and cache tokens."
2397
+ ];
2398
+ }
2399
+ function compactionLabel(row2, compact = false) {
2400
+ const phase = row2?.snapshot?.compaction.phase;
2401
+ if (!phase || phase === "idle")
2402
+ return;
2403
+ if (compact)
2404
+ return {
2405
+ requesting: "Requesting",
2406
+ accepted: "Waiting",
2407
+ running: "Compacting",
2408
+ "awaiting-measurement": "Checking",
2409
+ blocked: "Retry held",
2410
+ uncertain: "Unconfirmed"
2411
+ }[phase];
2412
+ return {
2413
+ requesting: "Requesting compaction",
2414
+ accepted: "Compaction request accepted \xB7 waiting to start",
2415
+ running: "Compaction running",
2416
+ "awaiting-measurement": "Compaction ended \xB7 checking context reduction",
2417
+ blocked: "Automatic compaction retry suppressed",
2418
+ uncertain: "Completion unconfirmed \xB7 automatic retry suppressed"
2419
+ }[phase];
2420
+ }
2421
+ function reasonExplanation(reason) {
2422
+ switch (reason) {
2423
+ case "below-threshold":
2424
+ return "Context is below the policy threshold.";
2425
+ case "threshold-crossed":
2426
+ return "Context reached the policy threshold; this does not guarantee compaction.";
2427
+ case "missing-usage":
2428
+ return "No measurement available for the policy decision.";
2429
+ case "model-changed":
2430
+ return "The measurement belongs to a different model.";
2431
+ case "invalid-usage":
2432
+ return "The measurement cannot be used for the policy decision.";
2433
+ case "stale-usage":
2434
+ return "The policy measurement is out of date.";
2435
+ case "missing-model-budget":
2436
+ return "Model capacity is unavailable for this threshold.";
2437
+ case "incompatible-model-budget":
2438
+ return "The threshold is incompatible with model capacity.";
2439
+ case "compaction-failed":
2440
+ return "Compaction failed; automatic retries are limited after repeated failures.";
2441
+ case "reclaim-unverifiable":
2442
+ return "Context reduction could not be verified with comparable provider readings.";
2443
+ case "insufficient-reclaim":
2444
+ return "Measured context reduction was below the required minimum.";
2445
+ case "admission-outcome-unknown":
2446
+ return "Whether the compaction request was accepted is unconfirmed.";
2447
+ case "completion-event-timeout":
2448
+ return "No confirming completion event arrived within the waiting period.";
2449
+ case "restart-needs-lifecycle-evidence":
2450
+ return "The previous request needs confirming lifecycle evidence after restart.";
2451
+ case "event-stream-gap":
2452
+ return "Automatic requests are suspended after an event gap; reload required.";
2453
+ case "persistence-unavailable":
2454
+ return "Safety storage is unavailable; repair storage and reload.";
2455
+ case "capacity-exceeded":
2456
+ return "Monitoring limit reached; some sessions are unavailable.";
2457
+ case "model-metadata-unavailable":
2458
+ return "Some model limits are unavailable.";
2459
+ default:
2460
+ return "See diagnostic codes.";
2461
+ }
2462
+ }
2463
+ function pressureLabel(row2) {
2464
+ if (row2?.freshness !== "fresh")
2465
+ return "Threshold pressure unknown";
2466
+ switch (row2.pressure) {
2467
+ case "crossed":
2468
+ return "Threshold reached";
2469
+ case "near":
2470
+ return "Near threshold";
2471
+ case "normal":
2472
+ return "Below threshold";
2473
+ default:
2474
+ return "Threshold pressure unknown";
2475
+ }
2476
+ }
2477
+ function thresholdDistance(row2, compact = false) {
2478
+ const delta = row2?.triggerDeltaTokens;
2479
+ if (row2?.freshness !== "fresh" || row2.pressure === "unknown" || delta === undefined || !Number.isFinite(delta))
2480
+ return "pressure unknown";
2481
+ if (delta === 0)
2482
+ return row2.pressure === "crossed" ? "Threshold reached" : "At threshold \xB7 requires more";
2483
+ if (compact)
2484
+ return `${tokens(Math.abs(delta))} ${delta < 0 ? "over" : "below"}${row2.pressure === "near" ? " \xB7 Near threshold" : delta < 0 ? " \xB7 Threshold reached" : ""}`;
2485
+ return `${tokens(Math.abs(delta))} ${Math.abs(delta) === 1 ? "token" : "tokens"} ${delta < 0 ? "over" : "below"} threshold`;
2486
+ }
2487
+ function guardStatusLines(health, compact = false) {
2488
+ switch (health?.enforcement) {
2489
+ case "observing":
2490
+ return compact ? ["Observing", "No Guard compact"] : ["Observing \xB7 Guard won't request compaction"];
2491
+ case "available":
2492
+ return compact ? ["Guard requests", "enabled"] : ["Guard automatic requests enabled"];
2493
+ case "disabled":
2494
+ return ["Guard disabled"];
2495
+ case "suspended": {
2496
+ const gap = health.reasons.includes("event-stream-gap");
2497
+ const storage = health.reasons.includes("persistence-unavailable");
2498
+ return compact ? [
2499
+ "Guard suspended",
2500
+ ...storage ? ["Storage: repair"] : [],
2501
+ ...gap ? ["Reload required"] : storage ? ["Then reload"] : ["See Details"]
2502
+ ] : [
2503
+ "Guard suspended" + (storage ? " \xB7 safety storage unavailable; repair storage and reload" : "") + (gap ? " \xB7 reload required" : storage ? "" : " \xB7 see Details")
2504
+ ];
2505
+ }
2506
+ default:
2507
+ return ["Guard status unknown"];
2508
+ }
2509
+ }
2510
+ function panelStatus(health) {
2511
+ return guardStatusLines(health).join(" \xB7 ");
2512
+ }
2513
+ function connectionLabel(connection, compact = false) {
2514
+ switch (connection) {
2515
+ case "loading":
2516
+ return "Connecting";
2517
+ case "live":
2518
+ return "Live";
2519
+ case "reconnecting":
2520
+ return "Reconnecting";
2521
+ case "unavailable":
2522
+ return compact ? "Unavailable" : "Connection unavailable";
2523
+ case "incompatible":
2524
+ return compact ? "Unsupported" : "Monitoring unsupported";
2525
+ }
2526
+ }
2527
+ function connectionNotice(connection, retainedMeasurements, compact = false) {
2528
+ if (connection === "live")
2529
+ return;
2530
+ return retainedMeasurements ? compact ? "Last data shown" : "Showing last received measurements" : compact ? "No measurements" : "No measurements available";
2531
+ }
2532
+ function monitorStatusLines(connection, health, retainedMeasurements, compact = false) {
2533
+ const notice = connectionNotice(connection, retainedMeasurements, compact);
2534
+ const reasons = health?.reasons ?? [];
2535
+ const limited = reasons.includes("capacity-exceeded");
2536
+ const model = reasons.includes("model-metadata-unavailable");
2537
+ const attention = health?.enforcement !== "suspended" && reasons.length > 0;
2538
+ return [
2539
+ ...health && connection !== "live" ? [compact ? "Last known:" : "Last known Guard:"] : [],
2540
+ ...guardStatusLines(health, compact),
2541
+ ...attention ? compact ? [limited ? "Monitor limit" : model ? "Limits unknown" : "See Details"] : [
2542
+ ...limited ? ["Monitoring limit reached \xB7 some sessions unavailable"] : [],
2543
+ ...model ? ["Some model limits unavailable \xB7 context may be unknown"] : [],
2544
+ ...!limited && !model ? ["Guard needs attention \xB7 see Details"] : []
2545
+ ] : [],
2546
+ ...notice ? [notice] : []
2547
+ ];
2548
+ }
2549
+ var contextHistoryLegend;
2550
+ var init_statusformat = __esm(() => {
2551
+ contextHistoryLegend = [
2552
+ "Recent samples \u2192 now \xB7 \u2504 threshold",
2553
+ "Dim = last known context"
2554
+ ];
2555
+ });
2556
+
2302
2557
  // src/tui/format.ts
2303
2558
  function quantity(n) {
2304
2559
  return n === undefined || !Number.isFinite(n) ? "?" : Math.abs(n) >= 1e6 ? `${(n / 1e6).toFixed(1)}m` : Math.abs(n) >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);
@@ -2326,22 +2581,6 @@ function clip(value, width) {
2326
2581
  }
2327
2582
  return width < 3 ? ".".repeat(Math.max(0, width)) : result + "...";
2328
2583
  }
2329
- function rowLines(row2, width) {
2330
- const s = row2.snapshot, m = s?.measurement;
2331
- const prefix = row2.current ? "* " : row2.depth > 5 ? ".../" : " ".repeat(Math.min(row2.depth, 5)) + "|-";
2332
- const percent = row2.utilizationPercent === undefined ? "?" : `${row2.utilizationPercent.toFixed(1)}%`;
2333
- const warning = row2.freshness === "stale" ? " STALE" : row2.pressure === "crossed" ? " !! crossed" : row2.pressure === "near" ? " ! near" : "";
2334
- const suffix = ` ${statuses[row2.node.status]} ${m?.confidence === "approximate" ? "~" : ""}${percent}${warning}`;
2335
- const label = clip(`${prefix}${row2.node.agent ?? row2.node.sessionId}`, Math.max(1, width - cells(suffix)));
2336
- return [
2337
- clip(`${label}${suffix}`, width),
2338
- ...performanceLines(row2, width),
2339
- ...wrap(`${quantity(m?.tokens)}/${quantity(s?.capacityTokens)} input; to ${quantity(row2.triggerDeltaTokens)}`, width),
2340
- ...s && s.compaction.phase !== "idle" ? wrap(`compact: ${s.compaction.phase}`, width) : [],
2341
- ...row2.node.interrupted ? [clip("interrupted", width)] : [],
2342
- ...row2.hidden ? wrap(`+ ${row2.hidden} completed descendants`, width) : []
2343
- ];
2344
- }
2345
2584
  function detailLines(row2, width, expanded = false, ageMs = 0) {
2346
2585
  const s = row2?.snapshot, m = s?.measurement;
2347
2586
  if (!row2)
@@ -2352,22 +2591,29 @@ function detailLines(row2, width, expanded = false, ageMs = 0) {
2352
2591
  ...wrap("Guard: not monitored / unavailable", width)
2353
2592
  ];
2354
2593
  const threshold = s.policy.configured;
2355
- const headroom = row2.triggerDeltaTokens;
2594
+ const valid2 = row2.freshness === "fresh" || row2.freshness === "stale";
2356
2595
  const lines = [
2357
2596
  `${s.agent ?? "?"} / ${s.model ?? "?"}`,
2597
+ `${row2.freshness === "stale" ? "Last measured" : "Context"} ${valid2 && m?.confidence === "approximate" ? "~" : ""}${quantity(valid2 ? m?.tokens : undefined)} / ${quantity(s.capacityTokens)} input`,
2598
+ `${valid2 ? row2.utilizationPercent?.toFixed(1) ?? "?" : "?"}% capacity \xB7 ${pressureLabel(row2)}`,
2599
+ `Threshold ${quantity(s.policy.triggerTokens)} \xB7 ${thresholdDistance(row2)}`,
2600
+ measurementLabel(row2, ageMs),
2601
+ ...measurementExplanation(row2),
2602
+ compactionLabel(row2) ?? "No compaction request in progress.",
2603
+ ...s.compaction.blockedReason ? [reasonExplanation(s.compaction.blockedReason)] : [],
2604
+ `Recorded policy decision: ${reasonExplanation(s.policy.reason)}`,
2358
2605
  ...performanceLines(row2, width),
2359
- `${m?.confidence === "approximate" ? "~" : ""}${quantity(m?.tokens)} / ${quantity(s.capacityTokens)} input`,
2360
- `${row2.utilizationPercent?.toFixed(1) ?? "?"}% ${row2.pressure === "crossed" ? "!! crossed" : row2.pressure === "near" ? "! near" : row2.freshness.toUpperCase()}`,
2361
- `Trigger ${threshold.type === "ratio" ? `${threshold.value * 100}%` : `${threshold.value} ${threshold.type}`} (${s.policy.comparison})`,
2362
- `Resolved trigger ${s.policy.triggerTokens ?? "?"}`,
2363
- `Until trigger ${quantity(headroom)}`,
2364
- `Compact: ${s.compaction.phase}`,
2365
- `${s.compaction.armed ? "armed" : "disarmed"}${s.compaction.blockedReason ? ` / ${s.compaction.blockedReason}` : ""}`,
2366
- m ? `${m.confidence} ${m.scope}` : "measurement unknown",
2367
- m ? `${Math.floor(Math.max(0, ageMs) / 1000)}s ago; ${row2.freshness}` : ""
2606
+ ...s.performance ? [
2607
+ "TPS: tokens per second. TTFT: time to first output (text or reasoning); approximate.",
2608
+ "Live TPS is estimated; completed rates use provider output including reasoning and matched timing.",
2609
+ "Model average uses matched request durations; session average includes idle and tool time.",
2610
+ ...s.performance.partial ? [
2611
+ "Incomplete timing coverage for model averages; only matched observed durations are included."
2612
+ ] : []
2613
+ ] : []
2368
2614
  ];
2369
2615
  if (expanded)
2370
- lines.push(`Policy ${s.policy.id}: ${s.policy.reason}`, `Limits in/context/out ${quantity(s.limits?.input)}/${quantity(s.limits?.context)}/${quantity(s.limits?.output)}`, `Output reserve ${quantity(s.outputReserveTokens)}`, `Provenance ${m?.provenance ?? "?"}`, `Cooldown until ${s.compaction.cooldownUntil ?? "?"}`, `Cumulative (${s.cumulativeScope})`, `Input ${quantity(s.cumulative?.input)} output ${quantity(s.cumulative?.output)}`, `Reasoning ${quantity(s.cumulative?.reasoning)}`, `Cache read ${quantity(s.cumulative?.cache.read)} write ${quantity(s.cumulative?.cache.write)}`);
2616
+ lines.push("Diagnostic codes and accounting:", `Compaction phase: ${s.compaction.phase}`, `Armed: ${s.compaction.armed} (one eligibility condition, not permission to compact)`, `Blocked reason: ${s.compaction.blockedReason ?? "?"}`, `Measurement confidence: ${m?.confidence ?? "?"}`, `Measurement scope: ${m?.scope ?? "?"}`, `Measurement freshness: ${row2.freshness}`, `Trigger ${threshold.type === "ratio" ? `${threshold.value * 100}%` : `${threshold.value} ${threshold.type}`} (${s.policy.comparison})`, `Resolved trigger ${s.policy.triggerTokens ?? "?"}`, `Policy ${s.policy.id}: ${s.policy.reason}`, `Pressure code: ${row2.pressure}`, `Recorded tokens: ${quantity(m?.tokens)}`, `Limits in/context/out ${quantity(s.limits?.input)}/${quantity(s.limits?.context)}/${quantity(s.limits?.output)}`, `Output reserve ${quantity(s.outputReserveTokens)}`, `Provenance ${m?.provenance ?? "?"}`, `Cooldown until ${s.compaction.cooldownUntil ?? "?"}`, `Cumulative (${s.cumulativeScope})`, `Input ${quantity(s.cumulative?.input)} output ${quantity(s.cumulative?.output)}`, `Reasoning ${quantity(s.cumulative?.reasoning)}`, `Cache read ${quantity(s.cumulative?.cache.read)} write ${quantity(s.cumulative?.cache.write)}`);
2371
2617
  return lines.filter(Boolean).flatMap((line) => wrap(line, width));
2372
2618
  }
2373
2619
  function sanitize(value) {
@@ -2404,16 +2650,10 @@ function performanceLines(row2, width) {
2404
2650
  ...wrap(`TTFT ${p.ttftMs === undefined ? "?" : `~${(p.ttftMs / 1000).toFixed(2)}s`}${p.latestRequestTps === undefined ? "" : ` \xB7 Last ${value(p.latestRequestTps)} t/s`}`, width)
2405
2651
  ];
2406
2652
  }
2407
- var segmenter, statuses;
2653
+ var segmenter;
2408
2654
  var init_format = __esm(() => {
2655
+ init_statusformat();
2409
2656
  segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
2410
- statuses = {
2411
- running: "RUN",
2412
- idle: "IDLE",
2413
- completed: "DONE",
2414
- failed: "FAIL",
2415
- unknown: "?"
2416
- };
2417
2657
  });
2418
2658
 
2419
2659
  // src/tui/chartformat.ts
@@ -2627,11 +2867,157 @@ var init_modelview = __esm(() => {
2627
2867
  ];
2628
2868
  });
2629
2869
 
2870
+ // src/tui/panelformat.ts
2871
+ function panelSummary(row2, width, age, compact = false) {
2872
+ if (!row2)
2873
+ return [clip("No sessions available \xB7 r refresh", width)];
2874
+ const snapshot = row2.snapshot;
2875
+ const valid2 = row2.freshness === "fresh" || row2.freshness === "stale";
2876
+ const prefix = row2.freshness === "stale" ? "Last measured" : "Context";
2877
+ const percent = `${row2.utilizationPercent === undefined ? "?" : Math.round(row2.utilizationPercent)}%`;
2878
+ const estimate = valid2 && snapshot?.measurement?.confidence === "approximate" ? "~" : "";
2879
+ const identity = `${width < 28 ? ">" : "Selected:"} ${row2.node.agent ?? row2.node.sessionId}${row2.current ? width < 28 ? " *" : " (current)" : ""}`;
2880
+ const threshold = `Threshold ${tokens(snapshot?.policy.triggerTokens)} \xB7 ${thresholdDistance(row2)}`;
2881
+ const occupancy = compact ? `${prefix} ${estimate}${percent}` : `${prefix} ${estimate}${tokens(valid2 ? snapshot?.measurement?.tokens : undefined)}/${tokens(snapshot?.capacityTokens)} \xB7 ${percent}`;
2882
+ return [
2883
+ clip(identity, width),
2884
+ clip(occupancy, width),
2885
+ ...!compact ? [
2886
+ clip(cells(threshold) <= width ? threshold : thresholdDistance(row2), width),
2887
+ clip(`${row2.node.model ?? snapshot?.model ?? "Model unknown"} \xB7 ${panelStatuses[row2.node.status]}`, width),
2888
+ ...wrap(measurementLabel(row2, age), width)
2889
+ ] : []
2890
+ ];
2891
+ }
2892
+ function tableLine(identity, status, context, threshold, width) {
2893
+ const pad = (value, size) => {
2894
+ const text2 = clip(value, size);
2895
+ return text2 + " ".repeat(Math.max(0, size - cells(text2)));
2896
+ };
2897
+ return `${pad(identity, width - 47)} ${pad(status, 8)} ${pad(context, 7)} ${pad(threshold, 29)}`;
2898
+ }
2899
+ function panelRowHeading(label, width) {
2900
+ return width >= 72 ? tableLine(label, "State", "Context", "Threshold", width) : clip(label, width);
2901
+ }
2902
+ function panelRowLines(row2, width, selected) {
2903
+ const marker = `${selected ? ">" : " "}${row2.current ? "*" : " "}`;
2904
+ const indent = " ".repeat(Math.min(row2.depth, Math.floor(width / 24))) + (row2.depth ? "\u2514 " : "");
2905
+ const identity = `${marker} ${indent}${row2.node.agent ?? row2.node.sessionId}`;
2906
+ const percent = `${(row2.freshness === "fresh" || row2.freshness === "stale") && row2.snapshot?.measurement?.confidence === "approximate" ? "~" : ""}${row2.utilizationPercent === undefined ? "?" : Math.round(row2.utilizationPercent)}%`;
2907
+ const status = width < 28 ? {
2908
+ running: "RUN",
2909
+ idle: "IDLE",
2910
+ completed: "DONE",
2911
+ failed: "FAIL",
2912
+ unknown: "?"
2913
+ }[row2.node.status] : panelStatuses[row2.node.status];
2914
+ const distance = thresholdDistance(row2, true);
2915
+ const pad = (value, size) => {
2916
+ const text2 = clip(value, size);
2917
+ return text2 + " ".repeat(Math.max(0, size - cells(text2)));
2918
+ };
2919
+ const lines = width >= 72 ? [tableLine(identity, status, percent, distance, width)] : [
2920
+ `${pad(identity, Math.max(1, width - status.length - 1))} ${status}`,
2921
+ clip(`${percent} context \xB7 ${distance}`, width)
2922
+ ];
2923
+ const exception = [
2924
+ freshnessLabel(row2),
2925
+ compactionLabel(row2),
2926
+ row2.node.interrupted ? "interrupted" : "",
2927
+ row2.hidden ? `+${row2.hidden} hidden \xB7 Space expands` : ""
2928
+ ].filter(Boolean).join(" \xB7 ");
2929
+ if (exception)
2930
+ lines.push(...wrap(exception, width));
2931
+ return lines.map((line) => clip(line, width));
2932
+ }
2933
+ var panelStatuses;
2934
+ var init_panelformat = __esm(() => {
2935
+ init_format();
2936
+ init_statusformat();
2937
+ init_statusformat();
2938
+ panelStatuses = {
2939
+ running: "RUNNING",
2940
+ idle: "IDLE",
2941
+ completed: "DONE",
2942
+ failed: "FAILED",
2943
+ unknown: "UNKNOWN"
2944
+ };
2945
+ });
2946
+
2630
2947
  // src/dashboard/terminalview.ts
2631
- function overviewRow(row2) {
2948
+ function diagnosticRow(row2) {
2632
2949
  const s = row2.snapshot;
2633
2950
  const valid2 = row2.freshness === "fresh" || row2.freshness === "stale";
2634
- return `${" ".repeat(Math.min(row2.depth, 12))}${row2.depth ? "\u2514 " : ""}${row2.node.agent ?? "unknown agent"} / ${row2.node.model ?? "unknown model"} [${row2.node.sessionId}] ${row2.node.status} | prompt ${quantity(valid2 ? s?.measurement?.tokens : undefined)}/${quantity(s?.capacityTokens)} | occupancy ${row2.utilizationPercent?.toFixed(1) ?? "?"}% | trigger ${quantity(s?.policy.triggerTokens)} headroom ${quantity(row2.triggerDeltaTokens)} | pressure ${row2.pressure} | compact ${s?.compaction.phase ?? "unavailable"} | performance ${s?.performance?.status ?? "unavailable"} | live TPS ${quantity(row2.performanceAvailable && row2.performanceFreshness !== "invalid" ? s?.performance?.liveTps : undefined)} | age ${row2.measurementAgeMs === undefined ? "unknown" : `${Math.floor(row2.measurementAgeMs / 1000)}s`} | inventory ${row2.inventoryStale ? "stale" : "fresh"}, live ${row2.liveStale ? "stale" : "fresh"}, usage ${row2.freshness}, performance ${row2.performanceFreshness}${s?.measurement?.confidence === "approximate" ? " estimated" : ""}${s?.performance?.tokenSource === "estimated" ? " estimated TPS" : ""}${s?.performance?.partial ? " partial" : ""}${row2.hidden ? ` | ${row2.hidden} hidden descendants` : ""}`;
2951
+ return `${" ".repeat(Math.min(row2.depth, 12))}${row2.depth ? "\u2514 " : ""}${row2.node.agent ?? "unknown agent"} / ${row2.node.model ?? "unknown model"} [${row2.node.sessionId}] ${row2.node.status} | ${row2.freshness === "stale" ? "Last measured" : "Context"} ${quantity(valid2 ? s?.measurement?.tokens : undefined)}/${quantity(s?.capacityTokens)} | occupancy ${row2.utilizationPercent?.toFixed(1) ?? "?"}% | threshold ${quantity(s?.policy.triggerTokens)} \xB7 ${thresholdDistance(row2)} | ${pressureLabel(row2)} | compact ${s?.compaction.phase ?? "unavailable"} | performance ${s?.performance?.status ?? "unavailable"} | live TPS ${quantity(row2.performanceAvailable && row2.performanceFreshness !== "invalid" ? s?.performance?.liveTps : undefined)} | age ${row2.measurementAgeMs === undefined ? "unknown" : `${Math.floor(row2.measurementAgeMs / 1000)}s`} | inventory ${row2.inventoryStale ? "stale" : "fresh"}, live ${row2.liveStale ? "stale" : "fresh"}, usage ${row2.freshness}, performance ${row2.performanceFreshness}${s?.measurement?.confidence === "approximate" ? " estimated" : ""}${s?.performance?.tokenSource === "estimated" ? " estimated TPS" : ""}${s?.performance?.partial ? " partial" : ""}${row2.hidden ? ` | ${row2.hidden} hidden descendants` : ""}`;
2952
+ }
2953
+ function pad(value, width) {
2954
+ const text2 = clip(value, width);
2955
+ return text2 + " ".repeat(Math.max(0, width - cells(text2)));
2956
+ }
2957
+ function overviewColumns(identity, state, context, threshold, width) {
2958
+ return `${pad(identity, width - 44)} ${pad(state, 7)} ${pad(context, 7)} ${pad(threshold, 27)}`;
2959
+ }
2960
+ function overviewHeading(width) {
2961
+ return width >= 72 ? [overviewColumns("Agent / model", "State", "Context", "Threshold", width)] : [];
2962
+ }
2963
+ function overviewLabels(rows) {
2964
+ const segmenter2 = new Intl.Segmenter(undefined, { granularity: "grapheme" });
2965
+ const suffixes = rows.map((row2) => [...segmenter2.segment(clip(row2.node.sessionId, 4096))].slice(-8).map((part) => part.segment).join(""));
2966
+ const counts = new Map;
2967
+ for (const suffix of suffixes)
2968
+ counts.set(suffix, (counts.get(suffix) ?? 0) + 1);
2969
+ return suffixes.map((suffix, index) => counts.get(suffix) === 1 ? suffix : `#${index + 1}`);
2970
+ }
2971
+ function overviewRowLines(row2, width, selected, label, position, maxLines = 3) {
2972
+ const valid2 = row2.freshness === "fresh" || row2.freshness === "stale";
2973
+ const percent = `${valid2 && row2.snapshot?.measurement?.confidence === "approximate" ? "~" : ""}${valid2 && row2.utilizationPercent !== undefined ? Math.round(row2.utilizationPercent) : "?"}%`;
2974
+ const context = `${row2.freshness === "stale" ? "Last measured " : ""}${percent}`;
2975
+ const distance = thresholdDistance(row2, true);
2976
+ const threshold = (distance === "At threshold \xB7 requires more" ? "At threshold; requires more" : distance).replace(" \xB7 Threshold reached", " \xB7 reached");
2977
+ const state = width < 28 ? {
2978
+ running: "RUN",
2979
+ idle: "IDLE",
2980
+ completed: "DONE",
2981
+ failed: "FAIL",
2982
+ unknown: "?"
2983
+ }[row2.node.status] : panelStatuses[row2.node.status];
2984
+ const identityWidth = width >= 72 ? width - 44 : Math.max(1, width - cells(state) - 1);
2985
+ const marker = selected ? "> " : " ";
2986
+ const tag = width >= 100 ? ` [${label}]` : ` #${position + 1}`;
2987
+ const indent = row2.depth && identityWidth >= 22 ? `${" ".repeat(Math.min(row2.depth, Math.max(0, Math.floor(identityWidth / 8) - 1)))}\u2514 ` : "";
2988
+ const name = `${row2.node.agent ?? "unknown agent"}${width >= 40 ? ` / ${row2.node.model ?? "unknown model"}` : ""}`;
2989
+ const identity = marker + indent + clip(name, Math.max(1, identityWidth - cells(marker + indent + tag))) + tag;
2990
+ const metric2 = `${context} context \xB7 ${threshold}`;
2991
+ const shortThreshold = threshold.replace("pressure unknown", "?").replace("At threshold; requires more", "At; needs more").replace(" \xB7 Near threshold", " near").replace(" \xB7 reached", " reached").replace("Threshold reached", "Reached");
2992
+ const shortMetric = `${context} \xB7 T ${shortThreshold}`;
2993
+ const pressure = row2.freshness !== "fresh" || row2.pressure === "unknown" ? "Threshold ?" : row2.pressure === "crossed" ? "Reached" : row2.triggerDeltaTokens === 0 ? "At; needs more" : row2.pressure === "near" ? "Near threshold" : "Below threshold";
2994
+ const metrics = [metric2, shortMetric, `${context} \xB7 ${pressure}`];
2995
+ const fittedMetric = metrics.find((line) => cells(line) <= width);
2996
+ const lines = width >= 72 ? [
2997
+ overviewColumns(identity, state, row2.freshness === "stale" ? "Last" : percent, threshold, width)
2998
+ ] : [`${pad(identity, identityWidth)} ${state}`, fittedMetric ?? context];
2999
+ const lifecycle = compactionLabel(row2);
3000
+ const exceptions = [
3001
+ ...width >= 72 && row2.freshness === "stale" ? [context] : [],
3002
+ ...width < 72 && !fittedMetric ? [pressure] : [],
3003
+ ...row2.node.status === "failed" ? ["Agent failed"] : [],
3004
+ ...row2.node.interrupted ? ["Interrupted"] : [],
3005
+ ...lifecycle ? [cells(lifecycle) <= width - 6 ? lifecycle : compactionLabel(row2, true)] : [],
3006
+ ...row2.freshness !== "fresh" ? [freshnessLabel(row2)] : [],
3007
+ ...row2.inventoryStale ? ["Inventory stale"] : [],
3008
+ ...row2.liveStale ? ["Live data stale"] : [],
3009
+ ...row2.hidden ? [`${row2.hidden} hidden descendants`] : []
3010
+ ].filter((value) => value !== undefined);
3011
+ if (exceptions.length) {
3012
+ let shown = 1;
3013
+ let text2 = exceptions[0] ?? "";
3014
+ while (shown < exceptions.length && cells(text2 + " \xB7 " + exceptions[shown]) <= width - 6) {
3015
+ text2 += " \xB7 " + exceptions[shown++];
3016
+ }
3017
+ const more = shown < exceptions.length ? ` +${exceptions.length - shown}` : "";
3018
+ lines.push(clip(text2, Math.max(0, width - cells(more))) + more);
3019
+ }
3020
+ return lines.slice(0, Math.max(1, maxLines)).map((line) => clip(line, width));
2635
3021
  }
2636
3022
  function pathValue(object2, path) {
2637
3023
  let value = object2;
@@ -2646,8 +3032,11 @@ function terminalDetail(row2) {
2646
3032
  if (!row2)
2647
3033
  return ["No selected session; choose one in overview."];
2648
3034
  return [
2649
- overviewRow(row2),
2650
3035
  `Session ID: ${row2.node.sessionId}`,
3036
+ ...detailLines(row2, 4096, false, row2.measurementAgeMs),
3037
+ ...row2.node.interrupted ? ["Agent execution interrupted"] : [],
3038
+ "Diagnostic codes and accounting:",
3039
+ diagnosticRow(row2),
2651
3040
  `Parent ID: ${row2.node.parentId ?? "unknown/unavailable"}`,
2652
3041
  "All snapshot fields (timestamps are Unix milliseconds):",
2653
3042
  ...snapshotFields.map((path) => `${path}: ${scalar(pathValue(row2.snapshot, path))}`),
@@ -2656,6 +3045,8 @@ function terminalDetail(row2) {
2656
3045
  }
2657
3046
  function historyObservations(view, metricIndex) {
2658
3047
  const metric2 = chartMetrics[metricIndex] ?? chartMetrics[0];
3048
+ if (!view.history.result?.enabled)
3049
+ return [];
2659
3050
  return view.history.result?.data.series.flatMap((series) => metric2.source === "points" ? series.points.map((point) => ({
2660
3051
  time: point.time,
2661
3052
  value: point[metric2.key],
@@ -2684,14 +3075,15 @@ function terminalHistory(view, width, metricIndex, sample) {
2684
3075
  ];
2685
3076
  const selected = observations[Math.min(sample, Math.max(0, observations.length - 1))];
2686
3077
  return [
2687
- `History: ${h.status}${h.stale ? " \xB7 stale cached results" : ""} \xB7 ${h.windowMs / 60000} minutes \xB7 ${metric2.label} (${metric2.unit})`,
3078
+ `History: ${h.status} \xB7 ${h.windowMs / 60000} minutes \xB7 ${metric2.label} (${metric2.unit})`,
3079
+ ...historyStatusLines(h),
2688
3080
  "Left/Right metric \xB7 w window \xB7 [/] exact sample/request \xB7 Up/Down scroll",
2689
3081
  "Retention bounded to seven days; maximum 500 points and 500 requests per session.",
2690
3082
  ...h.notices,
2691
- ...h.summary ? [
3083
+ ...h.result?.enabled && h.summary ? [
2692
3084
  `Matched requests ${h.summary.matchedRequests}/${h.summary.observedRequests}; output ${scalar(h.summary.outputTokens)}; duration ms ${scalar(h.summary.durationMs)}; average model TPS ${scalar(h.summary.averageModelTps)}${h.summary.partial ? " \xB7 partial" : ""}`
2693
3085
  ] : [],
2694
- ...h.from === undefined || h.to === undefined ? [] : [
3086
+ ...!h.result?.enabled || h.from === undefined || h.to === undefined ? [] : [
2695
3087
  `${new Date(h.from).toISOString()} \u2192 ${new Date(h.to).toISOString()}`,
2696
3088
  ...metricPlot(observations.map((p) => ({
2697
3089
  time: p.time,
@@ -2703,9 +3095,9 @@ function terminalHistory(view, width, metricIndex, sample) {
2703
3095
  `Exact ${metric2.source === "points" ? "sample" : "request"} ${Math.min(sample + 1, observations.length)}/${observations.length}:`,
2704
3096
  ...Object.entries(selected.details).map(([key, value]) => `${key}: ${scalar(value)}`),
2705
3097
  `Selected ${metric2.label}: ${scalar(selected.value)} ${metric2.unit}`
2706
- ] : [
3098
+ ] : h.status === "ready" && h.result?.enabled ? [
2707
3099
  "No retained measurements for this metric; values unknown/unavailable."
2708
- ]
3100
+ ] : []
2709
3101
  ];
2710
3102
  }
2711
3103
  function wrapped(lines, width) {
@@ -2715,17 +3107,33 @@ function wrapped(lines, width) {
2715
3107
  return cells(clean) <= available ? [clean] : wrap(clean, available);
2716
3108
  });
2717
3109
  }
2718
- function headerLines(view, width) {
3110
+ function headerLines(view, width, height = 24) {
3111
+ const compact = width < 28;
3112
+ const small = height < 18;
3113
+ if (width < 16 || height < 8)
3114
+ return [
3115
+ clip(connectionLabel(view.connection, true), width),
3116
+ clip(panelStatus(view.health), width),
3117
+ clip(`Location: ${view.location}`, width)
3118
+ ];
2719
3119
  return [
2720
- clip(`Context Guard \xB7 ${view.screen} \xB7 ${view.connection} \xB7 enforcement ${view.health?.enforcement ?? "unknown"}`, width),
2721
- clip(`Known ${view.inventory.total} \xB7 monitored ${view.inventory.monitored} \xB7 active ${view.inventory.active} \xB7 inventory ${view.inventory.stale ? "stale" : "fresh"}${view.inventory.complete ? "" : " / partial"}`, width),
2722
- clip(`Location: ${view.location}`, width)
3120
+ clip(`${connectionLabel(view.connection, compact)} \xB7 ${compact ? width >= 20 ? "Context Guard" : "Guard" : `Context Guard \xB7 ${view.screen}`}`, width),
3121
+ ...monitorStatusLines(view.connection, view.health, view.rows.some((row2) => row2.snapshot?.measurement !== undefined), compact).flatMap((line) => wrap(line, width)),
3122
+ ...small ? [
3123
+ clip(`Selected: ${view.selected?.node.agent ?? view.selectedSessionId ?? "none"}`, width)
3124
+ ] : [
3125
+ clip(`Known ${view.inventory.total} \xB7 monitored ${view.inventory.monitored} \xB7 active ${view.inventory.active} \xB7 inventory ${view.inventory.stale ? "stale" : "fresh"}${view.inventory.complete ? "" : " / partial"}`, width),
3126
+ clip(`Location: ${view.location}`, width)
3127
+ ]
2723
3128
  ];
2724
3129
  }
2725
3130
  var snapshotFields, scalar = (value) => value === undefined || value === null ? "unknown/unavailable" : typeof value === "number" && !Number.isFinite(value) ? "invalid" : String(value), terminalHelp;
2726
3131
  var init_terminalview = __esm(() => {
3132
+ init_historyclient();
2727
3133
  init_chartformat();
2728
3134
  init_format();
3135
+ init_statusformat();
3136
+ init_panelformat();
2729
3137
  snapshotFields = [
2730
3138
  "sessionId",
2731
3139
  "parentId",
@@ -2798,6 +3206,9 @@ var init_terminalview = __esm(() => {
2798
3206
  "Models charts: Left/Right metric \xB7 w window \xB7 [/] bucket \xB7 d request details",
2799
3207
  "Models list/request details: n/p pages \xB7 f exact agent filter \xB7 r refresh",
2800
3208
  "Up/Down or j/k: select session in overview; scroll other screens",
3209
+ "Overview: compact columns/cards; Enter or 2 for full identity and diagnostics",
3210
+ "Overview PageUp/PageDown selects by visible rows; #N identifies a row in narrow layouts",
3211
+ "Overview T means threshold; +N means more diagnostics in Details",
2801
3212
  "PageUp/PageDown: move by a page \xB7 Home/End: first/last",
2802
3213
  "Left/Right: history metric (six metrics) \xB7 w: cycle 5m/1h/24h/7d",
2803
3214
  "[ / ]: previous/next exact history sample or request",
@@ -2836,6 +3247,8 @@ class TerminalShell {
2836
3247
  input = "";
2837
3248
  notice = "";
2838
3249
  rowOffset = 0;
3250
+ overviewScope = "";
3251
+ overviewPage = 1;
2839
3252
  historyIdentity = "";
2840
3253
  constructor(controller, quit) {
2841
3254
  this.controller = controller;
@@ -3024,7 +3437,7 @@ class TerminalShell {
3024
3437
  const delta = name === "down" || name === "j" ? 1 : name === "up" || name === "k" ? -1 : name === "pagedown" ? page : name === "pageup" ? -page : 0;
3025
3438
  if (view.screen === "overview" && !this.help) {
3026
3439
  const index = view.rows.findIndex((row3) => row3.node.sessionId === view.selectedSessionId);
3027
- const next = name === "home" ? 0 : name === "end" ? view.rows.length - 1 : Math.max(0, Math.min(view.rows.length - 1, index + delta));
3440
+ const next = name === "home" ? 0 : name === "end" ? view.rows.length - 1 : Math.max(0, Math.min(view.rows.length - 1, index + (name === "pagedown" ? this.overviewPage : name === "pageup" ? -this.overviewPage : delta)));
3028
3441
  const row2 = view.rows[next];
3029
3442
  if (row2 && (delta || name === "home" || name === "end"))
3030
3443
  this.controller.selectSession(row2.node.sessionId);
@@ -3055,18 +3468,24 @@ class TerminalShell {
3055
3468
  this.scroll = 0;
3056
3469
  this.historyIdentity = identity;
3057
3470
  }
3058
- const footer = this.editor ? `${this.editor}> ${this.input} [Enter apply; Esc cancel${this.editor === "location" ? "; Tab remembered" : ""}]` : "? help q quit \xB7 1 overview 2 detail 3 history 4 models \xB7 / search f filters l location r refresh";
3471
+ const footer = this.editor ? `${this.editor}> ${this.input} [Enter apply; Esc cancel${this.editor === "location" ? "; Tab remembered" : ""}]` : view.screen === "overview" && !this.help ? width < 40 ? width >= 22 ? "2 detail ? help q quit" : "2 detail ? q quit" : width < 72 ? "2 detail \xB7 q quit \xB7 ? help \xB7 \u2191\u2193 select" : "Enter detail \xB7 q quit \xB7 ? help \xB7 \u2191\u2193 select \xB7 3 history 4 models / search f filters l location r refresh" : width < 40 ? "? help q quit" : "? help q quit \xB7 1 overview 2 detail 3 history 4 models \xB7 / search f filters l location r refresh";
3059
3472
  if (height < 5)
3060
3473
  return [
3061
3474
  clip("Context Guard \xB7 ? help \xB7 q quit", width),
3062
3475
  ...wrapped([footer], width)
3063
3476
  ].slice(0, height).join("\n");
3064
- const header = headerLines(view, width);
3065
- const available = height - header.length - 1;
3477
+ const header = headerLines(view, width, height);
3478
+ if (view.screen === "overview" && !this.help) {
3479
+ while (header.length > height - 2 && /^(Known |Location: |Selected: )/.test(header.at(-1) ?? ""))
3480
+ header.pop();
3481
+ header.splice(Math.max(0, height - 2));
3482
+ }
3483
+ const available = Math.max(0, height - header.length - 1);
3066
3484
  const notices = [
3485
+ ...view.screen === "overview" && view.selectedSessionId && !view.rows.some((row2) => row2.node.sessionId === view.selectedSessionId) ? ["Selection hidden by filters \xB7 \u2191\u2193 selects a visible session"] : [],
3067
3486
  ...view.notices,
3068
3487
  ...view.inventory.notices,
3069
- ...view.health?.reasons ?? [],
3488
+ ...view.screen === "detail" ? view.health?.reasons.map((reason) => `Health reason code: ${reason}`) ?? [] : [],
3070
3489
  ...this.notice ? [this.notice] : [],
3071
3490
  ...view.screen !== "models" && Object.values(view.filters).some(Boolean) ? [
3072
3491
  `Filters: search=${view.filters.search} agent=${view.filters.agent} model=${view.filters.model}`
@@ -3076,23 +3495,38 @@ class TerminalShell {
3076
3495
  if (this.help)
3077
3496
  body = wrapped(terminalHelp, width);
3078
3497
  else if (view.screen === "overview") {
3079
- const rows = view.rows.map((row2) => wrapped([
3080
- `${row2.node.sessionId === view.selectedSessionId ? "> " : " "}${overviewRow(row2)}`
3081
- ], width));
3498
+ const scope = JSON.stringify([view.location, view.filters]);
3499
+ if (scope !== this.overviewScope) {
3500
+ this.rowOffset = 0;
3501
+ this.overviewScope = scope;
3502
+ }
3503
+ const heading = available >= 4 ? overviewHeading(width) : [];
3504
+ const noticeBudget = Math.min(notices.length, Math.floor((available - heading.length) / 4));
3505
+ const status = notices.slice(0, noticeBudget).map((notice, index) => clip(index === noticeBudget - 1 && notices.length > noticeBudget ? `${notices.length} notices \xB7 see Details` : notice, width));
3506
+ const budget = Math.max(1, available - heading.length - status.length);
3507
+ const labels = overviewLabels(view.rows);
3508
+ const rows = view.rows.map((row2, index) => overviewRowLines(row2, width, row2.node.sessionId === view.selectedSessionId, labels[index] ?? `#${index + 1}`, index, budget));
3082
3509
  const selected = view.rows.findIndex((row2) => row2.node.sessionId === view.selectedSessionId);
3083
3510
  const start = rows.slice(0, Math.max(0, selected)).reduce((n, row2) => n + row2.length, 0);
3084
3511
  const end = start + (rows[selected]?.length ?? 0);
3085
- const status = wrapped(notices, width);
3086
- const budget = Math.max(1, available - Math.min(status.length, Math.floor(available / 3)));
3087
3512
  if (start < this.rowOffset)
3088
3513
  this.rowOffset = start;
3089
3514
  if (end > this.rowOffset + budget)
3090
3515
  this.rowOffset = Math.max(start, end - budget);
3091
3516
  const flat = rows.flat();
3092
3517
  this.rowOffset = Math.max(0, Math.min(this.rowOffset, Math.max(0, flat.length - budget)));
3518
+ let cursor = 0;
3519
+ this.overviewPage = Math.max(1, rows.filter((row2) => {
3520
+ const start2 = cursor;
3521
+ cursor += row2.length;
3522
+ return start2 >= this.rowOffset && cursor <= this.rowOffset + budget;
3523
+ }).length);
3093
3524
  body = [
3094
- ...status.slice(0, available - budget),
3095
- ...flat.length ? flat.slice(this.rowOffset, this.rowOffset + budget) : ["No matching sessions; / search, f filters, r refresh."]
3525
+ ...status,
3526
+ ...heading,
3527
+ ...flat.length ? flat.slice(this.rowOffset, this.rowOffset + budget) : [
3528
+ clip("No matching sessions; / search, f filters, r refresh.", width)
3529
+ ]
3096
3530
  ];
3097
3531
  return [
3098
3532
  ...header,