@cesarus777/opencode-cgp 0.1.0 → 0.2.2

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/tui.js CHANGED
@@ -114,6 +114,154 @@ var monitorRpc = Rpc.define({
114
114
  methods: { read: { input: readSchema, output: resultSchema } },
115
115
  events: { changed: { schema: batchSchema } }
116
116
  });
117
+ var nonnegative = { type: "number", minimum: 0 };
118
+ var performanceSchema = object({
119
+ observedSince: count,
120
+ at: count,
121
+ sessionCreatedAt: count,
122
+ sessionOutputTokens: count,
123
+ status: enumeration("waiting", "streaming", "idle", "unavailable"),
124
+ partial: { type: "boolean" },
125
+ liveTps: nonnegative,
126
+ averageModelTps: nonnegative,
127
+ averageSessionTps: nonnegative,
128
+ ttftMs: nonnegative,
129
+ latestRequestTps: nonnegative,
130
+ requestId: text,
131
+ requestAgent: text,
132
+ requestModel: text,
133
+ requestOutputTokens: count,
134
+ requestStartedAt: count,
135
+ firstOutputAt: count,
136
+ streamEndedAt: count,
137
+ estimatedOutputTokens: nonnegative,
138
+ modelOutputTokens: nonnegative,
139
+ modelDurationMs: nonnegative,
140
+ completedRequests: count,
141
+ tokenSource: enumeration("estimated", "reported", "unavailable")
142
+ }, [
143
+ "sessionCreatedAt",
144
+ "observedSince",
145
+ "at",
146
+ "status",
147
+ "partial",
148
+ "estimatedOutputTokens",
149
+ "modelOutputTokens",
150
+ "modelDurationMs",
151
+ "completedRequests",
152
+ "tokenSource"
153
+ ]);
154
+ var performanceRow = {
155
+ ...row,
156
+ properties: { ...row.properties, performance: performanceSchema }
157
+ };
158
+ var performanceBatchSchema = object({
159
+ ...batchFields,
160
+ upserts: array(performanceRow)
161
+ });
162
+ var performanceResultSchema = object({
163
+ ...batchFields,
164
+ upserts: array(performanceRow),
165
+ unavailable: resultSchema.properties.unavailable ?? {}
166
+ });
167
+ var performanceRpc = Rpc.define({
168
+ id: "context-guard.monitor.v2",
169
+ methods: { read: { input: readSchema, output: performanceResultSchema } },
170
+ events: { changed: { schema: performanceBatchSchema } }
171
+ });
172
+ function isPerformanceBatch(value) {
173
+ return valid(value, performanceBatchSchema) && uniqueRows(value);
174
+ }
175
+ function isPerformanceResult(value) {
176
+ return valid(value, performanceResultSchema) && uniqueRows(value);
177
+ }
178
+ function isPerformanceSnapshot(value) {
179
+ return valid(value, performanceSchema);
180
+ }
181
+ var chartPointSchema = object({
182
+ time: count,
183
+ agent: text,
184
+ model: text,
185
+ breakBefore: { type: "boolean" },
186
+ partial: { type: "boolean" },
187
+ liveTps: nonnegative,
188
+ averageModelTps: nonnegative,
189
+ averageSessionTps: nonnegative,
190
+ sessionOutputTokens: count
191
+ }, ["time", "breakBefore", "partial"]);
192
+ var chartRequestSchema = object({
193
+ time: count,
194
+ requestId: text,
195
+ started: count,
196
+ agent: text,
197
+ model: text,
198
+ ttftMs: nonnegative,
199
+ outputTokens: count,
200
+ durationMs: nonnegative,
201
+ tps: nonnegative,
202
+ partial: { type: "boolean" }
203
+ }, ["time", "requestId", "started", "partial"]);
204
+ var historyReadSchema = object({
205
+ schemaVersion: { const: 1 },
206
+ sessionId: text,
207
+ from: count,
208
+ to: count,
209
+ maxPoints: { type: "integer", minimum: 16, maximum: 500 }
210
+ });
211
+ var historyResultSchema = object({
212
+ schemaVersion: { const: 1 },
213
+ generatedAt: count,
214
+ enabled: { type: "boolean" },
215
+ truncated: { type: "boolean" },
216
+ metadata: object({
217
+ schema: { const: 1 },
218
+ retainedFrom: count,
219
+ retainedBytes: count,
220
+ skippedBytes: count,
221
+ malformedRecords: count,
222
+ completeness: enumeration("bounded-retention")
223
+ }, [
224
+ "schema",
225
+ "retainedBytes",
226
+ "skippedBytes",
227
+ "malformedRecords",
228
+ "completeness"
229
+ ]),
230
+ data: object({
231
+ schema: { const: 1 },
232
+ omittedSessions: count,
233
+ omittedGaps: count,
234
+ maxPoints: count,
235
+ gaps: array(object({ time: count, sessionId: text, reason: text }), 128),
236
+ series: array(object({
237
+ sessionId: text,
238
+ parentId: text,
239
+ agents: array(text, 1024),
240
+ models: array(text, 1024),
241
+ points: array(chartPointSchema, 500),
242
+ requests: array(chartRequestSchema, 500),
243
+ originalPoints: count
244
+ }, [
245
+ "sessionId",
246
+ "agents",
247
+ "models",
248
+ "points",
249
+ "requests",
250
+ "originalPoints"
251
+ ]), 1)
252
+ }, ["schema", "omittedSessions", "maxPoints", "gaps", "series"])
253
+ });
254
+ var historyRpc = Rpc.define({
255
+ id: "context-guard.history.v1",
256
+ methods: { read: { input: historyReadSchema, output: historyResultSchema } },
257
+ events: {}
258
+ });
259
+ function isHistoryRead(value) {
260
+ return valid(value, historyReadSchema) && record(value) && typeof value.from === "number" && typeof value.to === "number" && value.from <= value.to && value.to - value.from <= 7 * 86400000;
261
+ }
262
+ function isHistoryResult(value) {
263
+ return valid(value, historyResultSchema);
264
+ }
117
265
  function record(x) {
118
266
  return typeof x === "object" && x !== null && !Array.isArray(x);
119
267
  }
@@ -164,14 +312,14 @@ function uniqueRows(value) {
164
312
  }
165
313
 
166
314
  // src/tui.tsx
167
- import { effect as _$effect4 } from "@opentui/solid";
168
- import { createTextNode as _$createTextNode4 } from "@opentui/solid";
169
- import { insertNode as _$insertNode4 } from "@opentui/solid";
170
- import { setProp as _$setProp4 } from "@opentui/solid";
171
- import { createElement as _$createElement4 } from "@opentui/solid";
172
- import { createComponent as _$createComponent4 } from "@opentui/solid";
315
+ import { effect as _$effect5 } from "@opentui/solid";
316
+ import { createTextNode as _$createTextNode3 } from "@opentui/solid";
317
+ import { insertNode as _$insertNode5 } from "@opentui/solid";
318
+ import { setProp as _$setProp5 } from "@opentui/solid";
319
+ import { createElement as _$createElement5 } from "@opentui/solid";
320
+ import { createComponent as _$createComponent5 } from "@opentui/solid";
173
321
  import { Plugin } from "@opencode/plugin/tui";
174
- import { Show as Show3 } from "solid-js";
322
+ import { Show as Show4 } from "solid-js";
175
323
 
176
324
  // src/tui/state.ts
177
325
  import { createSignal } from "solid-js";
@@ -413,7 +561,7 @@ class SnapshotClient {
413
561
  const value = await abortable(this.transport.read(location, ids, signal), signal);
414
562
  if (generation !== this.generation)
415
563
  throw new Error("Obsolete read");
416
- if (!isResult(value)) {
564
+ if (!isPerformanceResult(value)) {
417
565
  this.connection = "incompatible";
418
566
  throw new Error("Incompatible snapshot");
419
567
  }
@@ -486,7 +634,7 @@ class SnapshotClient {
486
634
  for await (const value of this.transport.subscribe(this.location, signal)) {
487
635
  if (signal.aborted || generation !== this.generation)
488
636
  return;
489
- if (!isBatch(value)) {
637
+ if (!isPerformanceBatch(value)) {
490
638
  this.connection = "incompatible";
491
639
  this.changed();
492
640
  continue;
@@ -661,6 +809,7 @@ function createGuardState(context) {
661
809
  scheduleExpiry();
662
810
  };
663
811
  const rpc = context.client.rpc(monitorRpc);
812
+ const liveRpc = context.client.rpc(performanceRpc);
664
813
  const clients = new Map;
665
814
  let inventory, currentId = "", controller;
666
815
  let scanGeneration = 0, scanning = false, maxNodes = 1024;
@@ -744,10 +893,20 @@ function createGuardState(context) {
744
893
  let c = clients.get(key);
745
894
  if (!c) {
746
895
  const location = sample.location;
896
+ let selectedRpc = rpc;
897
+ try {
898
+ const probe = await liveRpc.read({ schemaVersion: 1, sessionIds: [] }, { location, signal });
899
+ if (isPerformanceResult(probe))
900
+ selectedRpc = liveRpc;
901
+ } catch {
902
+ }
903
+ if (signal.aborted || generation !== scanGeneration)
904
+ return;
905
+ const source = selectedRpc;
747
906
  c = new SnapshotClient({
748
- read: (_key, ids, requestSignal) => rpc.read({ schemaVersion: 1, sessionIds: ids }, { location, signal: requestSignal }),
907
+ read: (_key, ids, requestSignal) => source.read({ schemaVersion: 1, sessionIds: ids }, { location, signal: requestSignal }),
749
908
  subscribe: async function* (_key, requestSignal) {
750
- for await (const event of rpc.events.subscribe("changed", {
909
+ for await (const event of source.events.subscribe("changed", {
751
910
  signal: requestSignal
752
911
  })) {
753
912
  if (event.location && sameLocation(event.location, location))
@@ -880,6 +1039,15 @@ function createGuardState(context) {
880
1039
  return {
881
1040
  version,
882
1041
  acquire,
1042
+ async history(id, from, to, signal) {
1043
+ const info = inventory?.sessions.get(id);
1044
+ if (!info)
1045
+ throw new Error("Session location unavailable");
1046
+ const result = await context.client.rpc(historyRpc).read({ schemaVersion: 1, sessionId: id, from, to, maxPoints: 240 }, { location: info.location, signal });
1047
+ if (!isHistoryResult(result))
1048
+ throw new Error("Incompatible history service");
1049
+ return result;
1050
+ },
883
1051
  rows,
884
1052
  dispose: stop,
885
1053
  age(id) {
@@ -986,6 +1154,7 @@ function rowLines(row2, width) {
986
1154
  const label = clip(`${prefix}${row2.node.agent ?? row2.node.sessionId}`, Math.max(1, width - cells(suffix)));
987
1155
  return [
988
1156
  clip(`${label}${suffix}`, width),
1157
+ ...performanceLines(row2, width),
989
1158
  ...wrap(`${quantity(m?.tokens)}/${quantity(s?.capacityTokens)} input; to ${quantity(row2.triggerDeltaTokens)}`, width),
990
1159
  ...s && s.compaction.phase !== "idle" ? wrap(`compact: ${s.compaction.phase}`, width) : [],
991
1160
  ...row2.node.interrupted ? [clip("interrupted", width)] : [],
@@ -1005,6 +1174,7 @@ function detailLines(row2, width, expanded = false, ageMs = 0) {
1005
1174
  const headroom = row2.triggerDeltaTokens;
1006
1175
  const lines = [
1007
1176
  `${s.agent ?? "?"} / ${s.model ?? "?"}`,
1177
+ ...performanceLines(row2, width),
1008
1178
  `${m?.confidence === "approximate" ? "~" : ""}${quantity(m?.tokens)} / ${quantity(s.capacityTokens)} input`,
1009
1179
  `${row2.utilizationPercent?.toFixed(1) ?? "?"}% ${row2.pressure === "crossed" ? "!! crossed" : row2.pressure === "near" ? "! near" : row2.freshness.toUpperCase()}`,
1010
1180
  `Trigger ${threshold.type === "ratio" ? `${threshold.value * 100}%` : `${threshold.value} ${threshold.type}`} (${s.policy.comparison})`,
@@ -1042,6 +1212,72 @@ function wrap(value, width) {
1042
1212
  result.push(part);
1043
1213
  return result;
1044
1214
  }
1215
+ function performanceLines(row2, width) {
1216
+ const p = row2.snapshot?.performance;
1217
+ if (!p)
1218
+ return [];
1219
+ const value = (n) => n === undefined ? "?" : n.toFixed(1);
1220
+ return [
1221
+ ...wrap(`TPS ${p.status === "waiting" ? "waiting" : `${p.status === "streaming" ? "~" : ""}${value(p.liveTps)}`} \xB7 ${p.status}${p.partial ? " \xB7 partial" : ""}`, width),
1222
+ ...wrap(`Avg model ${value(p.averageModelTps)} \xB7 Avg session ${value(p.averageSessionTps)}`, width),
1223
+ ...wrap(`TTFT ${p.ttftMs === undefined ? "?" : `~${(p.ttftMs / 1000).toFixed(2)}s`}${p.latestRequestTps === undefined ? "" : ` \xB7 Last ${value(p.latestRequestTps)} t/s`}`, width)
1224
+ ];
1225
+ }
1226
+
1227
+ // src/tui/contextchart.ts
1228
+ function updateContextTrace(previous, row2) {
1229
+ const snapshot = row2?.snapshot;
1230
+ const model = snapshot?.model ?? row2?.node.model;
1231
+ const capacity = snapshot?.capacityTokens;
1232
+ const sessionId = row2?.node.sessionId ?? "";
1233
+ const samples = previous?.sessionId === sessionId && previous.model === model && previous.capacity === capacity ? previous.samples : [];
1234
+ const measurement2 = snapshot?.measurement;
1235
+ const valid2 = (row2?.freshness === "fresh" || row2?.freshness === "stale") && measurement2 && Number.isFinite(measurement2.tokens) && measurement2.tokens >= 0;
1236
+ const at = measurement2?.at ?? snapshot?.observedAt;
1237
+ let next = samples;
1238
+ if (at !== undefined && Number.isFinite(at)) {
1239
+ const sample = {
1240
+ at,
1241
+ ...valid2 ? { tokens: measurement2.tokens } : {}
1242
+ };
1243
+ const last = samples.at(-1);
1244
+ if (!last || at > last.at)
1245
+ next = [...samples, sample].slice(-96);
1246
+ else if (at === last.at && sample.tokens !== last.tokens)
1247
+ next = [...samples.slice(0, -1), sample];
1248
+ }
1249
+ return { sessionId, model, capacity, samples: next };
1250
+ }
1251
+ function contextChart(samples, capacity, trigger, width) {
1252
+ if (capacity === undefined || !Number.isFinite(capacity) || capacity <= 0 || width < 4)
1253
+ return [];
1254
+ const height = 8;
1255
+ const gutter = width >= 16 ? 4 : 0;
1256
+ const size = Math.max(1, Math.min(96, width - gutter - 2));
1257
+ const values = samples.slice(-size);
1258
+ const offset = size - values.length;
1259
+ const thresholdRow = trigger !== undefined && Number.isFinite(trigger) && trigger >= 0 && trigger <= capacity ? Math.round((1 - trigger / capacity) * (height - 1)) : -1;
1260
+ const blocks = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
1261
+ const lines = Array.from({ length: height }, (_, row2) => {
1262
+ const threshold = row2 === thresholdRow;
1263
+ const axis = gutter ? (row2 === 0 ? "100%" : row2 === height - 1 ? "0%" : "").padStart(gutter) : "";
1264
+ const plot = Array.from({ length: size }, (_2, col) => {
1265
+ const value = values[col - offset]?.tokens;
1266
+ const fill = value === undefined ? 0 : Math.max(0, Math.min(8, Math.ceil((Math.min(value / capacity, 1) * height - (height - row2 - 1)) * 8)));
1267
+ if (threshold)
1268
+ return fill > 0 ? "\u2542" : "\u2504";
1269
+ if (value === 0 && row2 === height - 1)
1270
+ return "\u2581";
1271
+ return blocks[fill] ?? " ";
1272
+ }).join("");
1273
+ return { line: `${axis}\u2502${plot}\u2502`, threshold };
1274
+ });
1275
+ lines.push({
1276
+ line: `${" ".repeat(gutter)}\u2514${"\u2500".repeat(size)}\u2518`,
1277
+ threshold: false
1278
+ });
1279
+ return lines;
1280
+ }
1045
1281
 
1046
1282
  // src/tui/compact.tsx
1047
1283
  import { createTextNode as _$createTextNode } from "@opentui/solid";
@@ -1077,7 +1313,7 @@ function progress(ratio, width) {
1077
1313
  const filled = valid2 ? Math.round(Math.min(1, ratio) * size) : 0;
1078
1314
  return clip("\u2588".repeat(filled) + "\u2591".repeat(size - filled) + " " + label, width);
1079
1315
  }
1080
- function mainSections(row2, width, age) {
1316
+ function mainSections(row2, width, age, samples) {
1081
1317
  if (!row2)
1082
1318
  return [{ tone: "base", lines: wrap("Loading session family...", width) }];
1083
1319
  const s = row2.snapshot, m = s?.measurement;
@@ -1086,6 +1322,7 @@ function mainSections(row2, width, age) {
1086
1322
  const ratio = (total) => measured !== undefined && total !== undefined && total > 0 ? measured / total : undefined;
1087
1323
  const remaining = measured !== undefined && s?.policy.triggerTokens !== undefined ? s.policy.triggerTokens - measured : undefined;
1088
1324
  return [
1325
+ ...row2.snapshot?.performance ? [{ tone: "base", lines: performanceLines(row2, width) }] : [],
1089
1326
  {
1090
1327
  tone: "execution",
1091
1328
  lines: columns(`${row2.node.agent ?? s?.agent ?? "Main"} \xB7 ${row2.node.model ?? s?.model ?? "?"}`, row2.node.status.toUpperCase(), width)
@@ -1097,7 +1334,14 @@ function mainSections(row2, width, age) {
1097
1334
  ...columns("Context", `${tokens(measured)} / ${tokens(s?.capacityTokens)}`, width)
1098
1335
  ]
1099
1336
  },
1100
- { tone: "pressure", lines: [progress(ratio(s?.capacityTokens), width)] },
1337
+ ...contextChart(samples ?? (m && valid2 ? [{ at: m.at, tokens: m.tokens }] : []), s?.capacityTokens, s?.policy.triggerTokens, width).map(({ line, threshold }) => ({
1338
+ tone: threshold ? "threshold" : "pressure",
1339
+ lines: [line]
1340
+ })),
1341
+ {
1342
+ tone: "base",
1343
+ lines: wrap(`${ratio(s?.capacityTokens) === undefined ? "?" : Math.round((ratio(s?.capacityTokens) ?? 0) * 100)}% used \xB7 recent samples \u2192 now`, width)
1344
+ },
1101
1345
  {
1102
1346
  tone: "base",
1103
1347
  lines: [
@@ -1108,7 +1352,8 @@ function mainSections(row2, width, age) {
1108
1352
  {
1109
1353
  tone: "pressure",
1110
1354
  lines: [
1111
- progress(ratio(s?.policy.triggerTokens), width),
1355
+ ...wrap(`${ratio(s?.policy.triggerTokens) === undefined ? "?" : Math.round((ratio(s?.policy.triggerTokens) ?? 0) * 100)}% of threshold \xB7 \u2504 trigger`, width),
1356
+ ...s?.capacityTokens !== undefined && s.policy.triggerTokens !== undefined && s.policy.triggerTokens > s.capacityTokens ? wrap("Threshold above chart capacity", width) : [],
1112
1357
  ...wrap(remaining === undefined ? "Compaction distance unknown" : remaining < 0 ? `${tokens(-remaining)} tokens over threshold` : `${tokens(remaining)} tokens until compaction`, width)
1113
1358
  ]
1114
1359
  },
@@ -1146,6 +1391,7 @@ function agentLines(row2, width) {
1146
1391
  const capacity = row2.snapshot?.capacityTokens;
1147
1392
  const pressure = row2.pressure === "crossed" ? "CRITICAL" : row2.pressure === "near" ? "WARNING" : "";
1148
1393
  return [
1394
+ ...performanceLines(row2, width),
1149
1395
  progress(measured !== undefined && capacity !== undefined && capacity > 0 ? measured / capacity : undefined, width),
1150
1396
  ...wrap(`${tokens(measured)} / ${tokens(capacity)}${pressure ? ` \xB7 ${pressure}` : ""}`, width),
1151
1397
  ...wrap(`${row2.node.status.toUpperCase()}${row2.freshness !== "fresh" ? ` \xB7 ${row2.freshness.toUpperCase()}` : ""}${row2.node.interrupted ? " \xB7 interrupted" : ""}`, width),
@@ -1225,6 +1471,7 @@ function CompactSidebar(props) {
1225
1471
  setCollapsed(new Set);
1226
1472
  });
1227
1473
  const current = createMemo(() => props.rows.find((r) => r.node.sessionId === props.sessionID));
1474
+ const trace = createMemo((previous) => updateContextTrace(previous, current()));
1228
1475
  const tree = createMemo(() => subagentTree(props.rows, props.sessionID, collapsed(), hideCompleted(), byPressure()));
1229
1476
  const entries = createMemo(() => new Map(tree().visible.map((entry) => [entry.row.node.sessionId, entry])));
1230
1477
  const toggle = (id) => setCollapsed((previous) => {
@@ -1314,7 +1561,7 @@ function CompactSidebar(props) {
1314
1561
  });
1315
1562
  _$insert(_el$2, _$createComponent(Index, {
1316
1563
  get each() {
1317
- return mainSections(current(), width(), props.state.age(props.sessionID));
1564
+ return mainSections(current(), width(), props.state.age(props.sessionID), trace().samples);
1318
1565
  },
1319
1566
  children: (section2) => _$createComponent(Index, {
1320
1567
  get each() {
@@ -1323,7 +1570,7 @@ function CompactSidebar(props) {
1323
1570
  children: (line) => (() => {
1324
1571
  var _el$13 = _$createElement("text");
1325
1572
  _$insert(_el$13, () => line() || " ");
1326
- _$effect((_$p) => _$setProp(_el$13, "fg", section2().tone === "execution" ? executionColor(current()) : section2().tone === "pressure" ? pressureColor(current()) : section2().tone === "measurement" ? current()?.freshness === "fresh" ? colors().muted : colors().feedback.warning.base : colors().base, _$p));
1573
+ _$effect((_$p) => _$setProp(_el$13, "fg", section2().tone === "execution" ? executionColor(current()) : section2().tone === "threshold" ? colors().feedback.warning.base : section2().tone === "pressure" ? pressureColor(current()) : section2().tone === "measurement" ? current()?.freshness === "fresh" ? colors().muted : colors().feedback.warning.base : colors().base, _$p));
1327
1574
  return _el$13;
1328
1575
  })()
1329
1576
  })
@@ -1469,6 +1716,8 @@ function GuardView(props) {
1469
1716
  onCleanup(() => consumer.release());
1470
1717
  const rows = createMemo2(() => props.family ?? props.state.rows([], !props.expanded));
1471
1718
  const current = createMemo2(() => rows().find((row2) => row2.node.sessionId === props.sessionID));
1719
+ const trace = createMemo2((previous) => updateContextTrace(previous, props.expanded ? current() : undefined));
1720
+ const chart = createMemo2(() => contextChart(trace().samples, current()?.snapshot?.capacityTokens, current()?.snapshot?.policy.triggerTokens, props.width));
1472
1721
  const detail = createMemo2(() => {
1473
1722
  const lines = detailLines(current(), props.width, props.expanded, props.state.age(props.sessionID));
1474
1723
  if (props.expanded) {
@@ -1536,26 +1785,48 @@ function GuardView(props) {
1536
1785
  _$insert2(_el$5, () => clip(`${props.state.connection()} / ${props.state.health()?.enforcement ?? "?"}`, props.width));
1537
1786
  _$insert2(_el$, _$createComponent2(For2, {
1538
1787
  get each() {
1539
- return detail();
1788
+ return chart();
1540
1789
  },
1541
- children: (line) => (() => {
1790
+ children: (item) => (() => {
1542
1791
  var _el$1 = _$createElement2("text");
1543
- _$insert2(_el$1, line);
1544
- _$effect2((_$p) => _$setProp2(_el$1, "fg", props.context.theme.text.base, _$p));
1792
+ _$insert2(_el$1, () => item.line);
1793
+ _$effect2((_$p) => _$setProp2(_el$1, "fg", item.threshold ? props.context.theme.text.feedback.warning.base : props.context.theme.text.muted, _$p));
1545
1794
  return _el$1;
1546
1795
  })()
1547
1796
  }), _el$6);
1548
1797
  _$insert2(_el$, _$createComponent2(For2, {
1549
1798
  get each() {
1550
- return props.state.health()?.reasons ?? [];
1799
+ return wrap("Recent context samples \u2192 now \xB7 \u2504 trigger", props.width);
1551
1800
  },
1552
- children: (reason) => (() => {
1801
+ children: (line) => (() => {
1553
1802
  var _el$10 = _$createElement2("text");
1554
- _$insert2(_el$10, () => clip(reason, props.width));
1555
- _$effect2((_$p) => _$setProp2(_el$10, "fg", props.context.theme.text.feedback.warning.base, _$p));
1803
+ _$insert2(_el$10, line);
1804
+ _$effect2((_$p) => _$setProp2(_el$10, "fg", props.context.theme.text.muted, _$p));
1556
1805
  return _el$10;
1557
1806
  })()
1558
1807
  }), _el$6);
1808
+ _$insert2(_el$, _$createComponent2(For2, {
1809
+ get each() {
1810
+ return detail();
1811
+ },
1812
+ children: (line) => (() => {
1813
+ var _el$11 = _$createElement2("text");
1814
+ _$insert2(_el$11, line);
1815
+ _$effect2((_$p) => _$setProp2(_el$11, "fg", props.context.theme.text.base, _$p));
1816
+ return _el$11;
1817
+ })()
1818
+ }), _el$6);
1819
+ _$insert2(_el$, _$createComponent2(For2, {
1820
+ get each() {
1821
+ return props.state.health()?.reasons ?? [];
1822
+ },
1823
+ children: (reason) => (() => {
1824
+ var _el$12 = _$createElement2("text");
1825
+ _$insert2(_el$12, () => clip(reason, props.width));
1826
+ _$effect2((_$p) => _$setProp2(_el$12, "fg", props.context.theme.text.feedback.warning.base, _$p));
1827
+ return _el$12;
1828
+ })()
1829
+ }), _el$6);
1559
1830
  _$insert2(_el$6, (() => {
1560
1831
  var _c$2 = _$memo2(() => props.state.health()?.mode === "observe");
1561
1832
  return () => _c$2() ? current()?.pressure === "crossed" ? "Observe: would compact" : "Observe: no admission" : "";
@@ -1569,9 +1840,9 @@ function GuardView(props) {
1569
1840
  return visible();
1570
1841
  },
1571
1842
  children: (row2) => (() => {
1572
- var _el$11 = _$createElement2("box");
1573
- _$setProp2(_el$11, "flexDirection", "column");
1574
- _$setProp2(_el$11, "onMouseDown", () => {
1843
+ var _el$13 = _$createElement2("box");
1844
+ _$setProp2(_el$13, "flexDirection", "column");
1845
+ _$setProp2(_el$13, "onMouseDown", () => {
1575
1846
  if (row2.hidden)
1576
1847
  props.state.expand(row2.node.sessionId);
1577
1848
  else {
@@ -1583,19 +1854,19 @@ function GuardView(props) {
1583
1854
  });
1584
1855
  }
1585
1856
  });
1586
- _$insert2(_el$11, _$createComponent2(For2, {
1857
+ _$insert2(_el$13, _$createComponent2(For2, {
1587
1858
  get each() {
1588
1859
  return rowLines(row2, Math.max(1, props.width - (props.expanded ? 2 : 0))).map((line) => props.expanded ? `${row2.node.sessionId === props.selectedId ? ">" : " "} ${line}` : line);
1589
1860
  },
1590
1861
  children: (line) => (() => {
1591
- var _el$12 = _$createElement2("text");
1592
- _$insert2(_el$12, line);
1593
- _$effect2((_$p) => _$setProp2(_el$12, "fg", row2.pressure === "crossed" ? props.context.theme.text.feedback.error.base : row2.pressure === "near" ? props.context.theme.text.feedback.warning.base : props.context.theme.text.base, _$p));
1594
- return _el$12;
1862
+ var _el$14 = _$createElement2("text");
1863
+ _$insert2(_el$14, line);
1864
+ _$effect2((_$p) => _$setProp2(_el$14, "fg", row2.pressure === "crossed" ? props.context.theme.text.feedback.error.base : row2.pressure === "near" ? props.context.theme.text.feedback.warning.base : props.context.theme.text.base, _$p));
1865
+ return _el$14;
1595
1866
  })()
1596
1867
  }));
1597
- _$effect2((_$p) => _$setProp2(_el$11, "id", `context-guard.row.${row2.node.sessionId}`, _$p));
1598
- return _el$11;
1868
+ _$effect2((_$p) => _$setProp2(_el$13, "id", `context-guard.row.${row2.node.sessionId}`, _$p));
1869
+ return _el$13;
1599
1870
  })()
1600
1871
  }), _el$0);
1601
1872
  _$setProp2(_el$0, "onMouseDown", () => props.context.ui.panel.open("context-guard.monitor"));
@@ -1626,26 +1897,242 @@ function GuardView(props) {
1626
1897
  }
1627
1898
 
1628
1899
  // src/tui/panel.tsx
1900
+ import { effect as _$effect4 } from "@opentui/solid";
1901
+ import { memo as _$memo3 } from "@opentui/solid";
1902
+ import { insertNode as _$insertNode4 } from "@opentui/solid";
1903
+ import { insert as _$insert4 } from "@opentui/solid";
1904
+ import { createComponent as _$createComponent4 } from "@opentui/solid";
1905
+ import { use as _$use } from "@opentui/solid";
1906
+ import { setProp as _$setProp4 } from "@opentui/solid";
1907
+ import { createElement as _$createElement4 } from "@opentui/solid";
1908
+ import { createSignal as createSignal4, createMemo as createMemo3, createEffect as createEffect4, onCleanup as onCleanup3, Show as Show3, For as For4 } from "solid-js";
1909
+
1910
+ // src/tui/charts.tsx
1629
1911
  import { effect as _$effect3 } from "@opentui/solid";
1630
- import { insert as _$insert3 } from "@opentui/solid";
1631
- import { createTextNode as _$createTextNode3 } from "@opentui/solid";
1632
1912
  import { insertNode as _$insertNode3 } from "@opentui/solid";
1913
+ import { insert as _$insert3 } from "@opentui/solid";
1633
1914
  import { createComponent as _$createComponent3 } from "@opentui/solid";
1634
1915
  import { setProp as _$setProp3 } from "@opentui/solid";
1635
- import { use as _$use } from "@opentui/solid";
1636
1916
  import { createElement as _$createElement3 } from "@opentui/solid";
1637
- import { createSignal as createSignal3, createMemo as createMemo3, createEffect as createEffect3, onCleanup as onCleanup2 } from "solid-js";
1917
+ import { createEffect as createEffect3, createSignal as createSignal3, onCleanup as onCleanup2, For as For3 } from "solid-js";
1918
+
1919
+ // src/tui/chartformat.ts
1920
+ function columns2(points, from, to, width, gaps = []) {
1921
+ const size = Math.max(1, Math.min(120, Math.floor(width))), values = Array.from({ length: size });
1922
+ const column = (time) => Math.max(0, Math.min(size - 1, Math.floor((time - from) / Math.max(1, to - from) * (size - 1))));
1923
+ let min = Infinity, max = -Infinity;
1924
+ for (const point of points) {
1925
+ if (point.time < from || point.time > to || point.value === undefined || !Number.isFinite(point.value) || point.value < 0)
1926
+ continue;
1927
+ min = Math.min(min, point.value);
1928
+ max = Math.max(max, point.value);
1929
+ const i = column(point.time);
1930
+ values[i] = Math.max(values[i] ?? -Infinity, point.value);
1931
+ }
1932
+ for (const time of gaps)
1933
+ if (time >= from && time <= to)
1934
+ values[column(time)] = undefined;
1935
+ return { values, column, min, max };
1936
+ }
1937
+ function sparkline(points, from, to, width, gaps = []) {
1938
+ const { values, column, min, max } = columns2(points, from, to, width, gaps);
1939
+ const bars = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
1940
+ const chars = values.map((v) => v === undefined ? " " : bars[Math.min(7, Math.floor(v / Math.max(1, max) * 7))] ?? "\u2581");
1941
+ for (const time of gaps)
1942
+ if (time >= from && time <= to)
1943
+ chars[column(time)] = "\u2506";
1944
+ return { line: chars.join(""), ...min === Infinity ? {} : { min, max } };
1945
+ }
1946
+ var chartMetrics = [
1947
+ { label: "Live TPS ~", unit: "t/s", key: "liveTps", source: "points" },
1948
+ { label: "Avg model", unit: "t/s", key: "averageModelTps", source: "points" },
1949
+ {
1950
+ label: "Avg session",
1951
+ unit: "t/s",
1952
+ key: "averageSessionTps",
1953
+ source: "points"
1954
+ },
1955
+ { label: "TTFT ~", unit: "s", key: "ttftMs", source: "requests" },
1956
+ { label: "Request throughput", unit: "t/s", key: "tps", source: "requests" },
1957
+ {
1958
+ label: "Cumulative output",
1959
+ unit: "tokens",
1960
+ key: "sessionOutputTokens",
1961
+ source: "points"
1962
+ }
1963
+ ];
1964
+ function metricPlot(points, from, to, width, gaps = []) {
1965
+ const label = (value) => value >= 1e6 ? `${(value / 1e6).toFixed(1)}M` : value >= 1000 ? `${(value / 1000).toFixed(1)}k` : value.toFixed(1);
1966
+ const peak = Math.max(0, ...points.filter((p) => p.time >= from && p.time <= to && Number.isFinite(p.value)).map((p) => p.value ?? 0));
1967
+ const scale = Math.max(1, peak);
1968
+ const gutter = width >= 20 ? Math.max(label(scale).length, 3) : 0;
1969
+ const { values, column } = columns2(points, from, to, Math.max(1, width - gutter - 2), gaps);
1970
+ const gapColumns = new Set(gaps.filter((time) => time >= from && time <= to).map(column));
1971
+ const height = 6;
1972
+ const blocks = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
1973
+ const lines = Array.from({ length: height }, (_, row2) => {
1974
+ const axis = gutter ? (row2 === 0 ? label(scale) : row2 === height - 1 ? "0.0" : "").padStart(gutter) : "";
1975
+ return `${axis}\u2502${values.map((value, i) => {
1976
+ if (gapColumns.has(i))
1977
+ return "\u2506";
1978
+ if (value === undefined)
1979
+ return " ";
1980
+ const fill = Math.max(0, Math.min(8, Math.ceil((value / scale * height - (height - row2 - 1)) * 8)));
1981
+ return value === 0 && row2 === height - 1 ? "\u2581" : blocks[fill];
1982
+ }).join("")}\u2502`;
1983
+ });
1984
+ lines.push(`${" ".repeat(gutter)}\u2514${"\u2500".repeat(values.length)}\u2518`);
1985
+ const start = new Date(from).toISOString().slice(11, 16), end = new Date(to).toISOString().slice(11, 16);
1986
+ const axisWidth = values.length + 2;
1987
+ if (axisWidth >= 11)
1988
+ lines.push(`${" ".repeat(gutter)}${start}${" ".repeat(axisWidth - 10)}${end}`);
1989
+ return lines;
1990
+ }
1991
+ function historyChartLines(result, width, from, to, metricIndex = 0) {
1992
+ if (!result.enabled)
1993
+ return wrap("History recording is disabled on this server.", width);
1994
+ const series = result.data.series[0];
1995
+ if (!series)
1996
+ return wrap("No retained measurements in this window.", width);
1997
+ const gaps = result.data.gaps.map((g) => g.time);
1998
+ const observations = (key) => series.points.map((p) => ({
1999
+ time: p.time,
2000
+ ...p[key] === undefined ? {} : { value: p[key] }
2001
+ }));
2002
+ const requests = (key) => series.requests.map((p) => ({
2003
+ time: p.time,
2004
+ ...p[key] === undefined ? {} : { value: key === "ttftMs" ? p[key] / 1000 : p[key] }
2005
+ }));
2006
+ const metric2 = chartMetrics[metricIndex] ?? chartMetrics[0];
2007
+ const points = metric2.source === "points" ? observations(metric2.key) : requests(metric2.key);
2008
+ const plotted = sparkline(points, from, to, width - 2, gaps);
2009
+ return [
2010
+ ...wrap(`\u2039 ${metric2.label} \u203A \xB7 ${metricIndex + 1}/${chartMetrics.length}`, width),
2011
+ ...wrap(plotted.min === undefined ? "No measurements for this metric." : `${plotted.min.toFixed(1)}\u2013${plotted.max?.toFixed(1)} ${metric2.unit} \xB7 observed range`, width),
2012
+ "",
2013
+ ...metricPlot(points, from, to, width, gaps),
2014
+ "",
2015
+ ...wrap("UTC time \u2192 \xB7 peaks per column", width),
2016
+ ...wrap("blank = no sample \xB7 \u2506 = gap", width),
2017
+ ...wrap(`${new Date(from).toISOString()} \u2192 ${new Date(to).toISOString()}`, width),
2018
+ ...series.points.some((p) => p.partial) ? wrap("Partial timing coverage; averages include only matched model durations.", width) : [],
2019
+ ...result.truncated ? wrap("Downsampled/bounded history; some older requests or gap markers may be omitted.", width) : [],
2020
+ ...result.metadata.malformedRecords ? wrap(`${result.metadata.malformedRecords} malformed/partial records skipped.`, width) : []
2021
+ ];
2022
+ }
2023
+
2024
+ // src/tui/charts.tsx
2025
+ function HistoryCharts(props) {
2026
+ const [result, setResult] = createSignal3();
2027
+ const [status, setStatus] = createSignal3("Loading retained history...");
2028
+ const [range, setRange] = createSignal3({
2029
+ from: 0,
2030
+ to: 0
2031
+ });
2032
+ createEffect3(() => {
2033
+ const { sessionId: id, windowMs } = props;
2034
+ props.refresh;
2035
+ let pending = false, disposed = false;
2036
+ let controller;
2037
+ setResult(undefined);
2038
+ async function read() {
2039
+ if (pending || disposed)
2040
+ return;
2041
+ pending = true;
2042
+ controller = new AbortController;
2043
+ const to = Date.now(), from = Math.max(0, to - windowMs);
2044
+ try {
2045
+ const next = await props.state.history(id, from, to, AbortSignal.any([controller.signal, AbortSignal.timeout(5000)]));
2046
+ if (!disposed) {
2047
+ setResult(next);
2048
+ setRange({
2049
+ from,
2050
+ to
2051
+ });
2052
+ setStatus("");
2053
+ }
2054
+ } catch {
2055
+ if (!disposed)
2056
+ setStatus("History unavailable. The owning server must support chart history RPC. Press r to retry.");
2057
+ } finally {
2058
+ pending = false;
2059
+ }
2060
+ }
2061
+ read();
2062
+ const timer = setInterval(() => {
2063
+ read();
2064
+ }, 5000);
2065
+ onCleanup2(() => {
2066
+ disposed = true;
2067
+ controller?.abort();
2068
+ clearInterval(timer);
2069
+ });
2070
+ });
2071
+ const lines = () => {
2072
+ const current = result();
2073
+ return current ? historyChartLines(current, Math.max(4, props.width), range().from, range().to, props.metricIndex) : [];
2074
+ };
2075
+ return (() => {
2076
+ var _el$ = _$createElement3("box"), _el$2 = _$createElement3("box");
2077
+ _$insertNode3(_el$, _el$2);
2078
+ _$setProp3(_el$, "flexDirection", "column");
2079
+ _$insert3(_el$, _$createComponent3(For3, {
2080
+ get each() {
2081
+ return wrap(`Performance charts \xB7 ${props.sessionId}`, props.width);
2082
+ },
2083
+ children: (line) => (() => {
2084
+ var _el$3 = _$createElement3("text");
2085
+ _$insert3(_el$3, line);
2086
+ _$effect3((_$p) => _$setProp3(_el$3, "fg", props.context.theme.text.base, _$p));
2087
+ return _el$3;
2088
+ })()
2089
+ }), _el$2);
2090
+ _$insert3(_el$, _$createComponent3(For3, {
2091
+ get each() {
2092
+ return wrap(status(), props.width);
2093
+ },
2094
+ children: (line) => (() => {
2095
+ var _el$4 = _$createElement3("text");
2096
+ _$insert3(_el$4, line);
2097
+ _$effect3((_$p) => _$setProp3(_el$4, "fg", props.context.theme.text.muted, _$p));
2098
+ return _el$4;
2099
+ })()
2100
+ }), _el$2);
2101
+ _$setProp3(_el$2, "flexDirection", "column");
2102
+ _$setProp3(_el$2, "paddingTop", 1);
2103
+ _$insert3(_el$2, _$createComponent3(For3, {
2104
+ get each() {
2105
+ return lines();
2106
+ },
2107
+ children: (line) => (() => {
2108
+ var _el$5 = _$createElement3("text");
2109
+ _$insert3(_el$5, line || " ");
2110
+ _$effect3((_$p) => _$setProp3(_el$5, "fg", props.context.theme.text.base, _$p));
2111
+ return _el$5;
2112
+ })()
2113
+ }));
2114
+ return _el$;
2115
+ })();
2116
+ }
2117
+
2118
+ // src/tui/panel.tsx
1638
2119
  function GuardPanel(props) {
1639
- const [inspectId, setInspectId] = createSignal3();
1640
- const [selected, setSelected] = createSignal3(props.input.sessionID);
1641
- const [order, setOrder] = createSignal3([]);
2120
+ const [showCharts, setShowCharts] = createSignal4(false);
2121
+ const [metricIndex, setMetricIndex] = createSignal4(0);
2122
+ const width = () => Math.max(4, props.input.width - 4);
2123
+ const windows = [300000, 3600000, 86400000, 7 * 86400000];
2124
+ const [windowIndex, setWindowIndex] = createSignal4(1);
2125
+ const [chartRefresh, setChartRefresh] = createSignal4(0);
2126
+ const [inspectId, setInspectId] = createSignal4();
2127
+ const [selected, setSelected] = createSignal4(props.input.sessionID);
2128
+ const [order, setOrder] = createSignal4([]);
1642
2129
  const rows = createMemo3(() => props.state.rows(order()));
1643
2130
  const offset = () => Math.max(0, rows().findIndex((row2) => row2.node.sessionId === selected()));
1644
- createEffect3(() => {
2131
+ createEffect4(() => {
1645
2132
  if (!props.input.focused)
1646
2133
  setOrder([]);
1647
2134
  });
1648
- createEffect3(() => {
2135
+ createEffect4(() => {
1649
2136
  setSelected(props.input.sessionID);
1650
2137
  setOrder([]);
1651
2138
  });
@@ -1666,7 +2153,7 @@ function GuardPanel(props) {
1666
2153
  props.context.renderer.setFrameCallback(follow);
1667
2154
  props.context.renderer.requestRender();
1668
2155
  }
1669
- onCleanup2(() => {
2156
+ onCleanup3(() => {
1670
2157
  if (follow)
1671
2158
  props.context.renderer.removeFrameCallback(follow);
1672
2159
  });
@@ -1675,12 +2162,55 @@ function GuardPanel(props) {
1675
2162
  const row2 = rows()[Math.max(0, Math.min(rows().length - 1, offset() + delta))];
1676
2163
  if (row2) {
1677
2164
  setSelected(row2.node.sessionId);
1678
- revealSelection();
2165
+ if (!showCharts())
2166
+ revealSelection();
1679
2167
  }
1680
2168
  }
1681
2169
  props.context.keymap.layer(() => ({
1682
2170
  enabled: () => props.input.focused,
1683
2171
  commands: [{
2172
+ id: "context-guard.close",
2173
+ title: "Close Context Guard",
2174
+ bind: "q",
2175
+ run: () => props.input.close()
2176
+ }, {
2177
+ id: "context-guard.chart-previous",
2178
+ title: "Previous chart metric",
2179
+ bind: "left",
2180
+ run: () => {
2181
+ if (showCharts())
2182
+ setMetricIndex((i) => (i + chartMetrics.length - 1) % chartMetrics.length);
2183
+ }
2184
+ }, {
2185
+ id: "context-guard.chart-next",
2186
+ title: "Next chart metric",
2187
+ bind: "right",
2188
+ run: () => {
2189
+ if (showCharts())
2190
+ setMetricIndex((i) => (i + 1) % chartMetrics.length);
2191
+ }
2192
+ }, {
2193
+ id: "context-guard.charts",
2194
+ title: "Toggle performance charts",
2195
+ bind: "c",
2196
+ run: () => setShowCharts((v) => !v)
2197
+ }, {
2198
+ id: "context-guard.chart-shorter",
2199
+ title: "Shorter chart window",
2200
+ bind: "[",
2201
+ run: () => {
2202
+ if (showCharts())
2203
+ setWindowIndex((i) => Math.max(0, i - 1));
2204
+ }
2205
+ }, {
2206
+ id: "context-guard.chart-longer",
2207
+ title: "Longer chart window",
2208
+ bind: "]",
2209
+ run: () => {
2210
+ if (showCharts())
2211
+ setWindowIndex((i) => Math.min(windows.length - 1, i + 1));
2212
+ }
2213
+ }, {
1684
2214
  id: "context-guard.inspect",
1685
2215
  title: "Inspect selected session",
1686
2216
  bind: "i",
@@ -1692,6 +2222,7 @@ function GuardPanel(props) {
1692
2222
  run: () => {
1693
2223
  setOrder([]);
1694
2224
  props.state.refresh();
2225
+ setChartRefresh((n) => n + 1);
1695
2226
  }
1696
2227
  }, {
1697
2228
  id: "context-guard.load-more",
@@ -1729,18 +2260,26 @@ function GuardPanel(props) {
1729
2260
  }
1730
2261
  }]
1731
2262
  }));
2263
+ const hints = () => showCharts() ? ["c back \xB7 q close", "\u2190 / \u2192 metric \xB7 \u2191 / \u2193 session", `[ / ] window \xB7 ${["5 minutes", "1 hour", "24 hours", "7 days"][windowIndex()]}`, "r refresh \xB7 Enter open session"] : ["c charts \xB7 q close", `\u2191 / \u2193 select ${offset() + 1} \xB7 Enter open`, "space expand \xB7 i inspect", "r refresh \xB7 l load more"];
1732
2264
  return (() => {
1733
- var _el$ = _$createElement3("scrollbox"), _el$2 = _$createElement3("text"), _el$4 = _$createElement3("text"), _el$5 = _$createTextNode3(`up/down select `), _el$6 = _$createTextNode3(`; Enter open`), _el$7 = _$createElement3("text"), _el$9 = _$createElement3("text"), _el$1 = _$createElement3("text");
1734
- _$insertNode3(_el$, _el$2);
1735
- _$insertNode3(_el$, _el$4);
1736
- _$insertNode3(_el$, _el$7);
1737
- _$insertNode3(_el$, _el$9);
1738
- _$insertNode3(_el$, _el$1);
2265
+ var _el$ = _$createElement4("box"), _el$2 = _$createElement4("scrollbox"), _el$3 = _$createElement4("box"), _el$4 = _$createElement4("text"), _el$5 = _$createElement4("box");
2266
+ _$insertNode4(_el$, _el$2);
2267
+ _$insertNode4(_el$, _el$5);
2268
+ _$setProp4(_el$, "flexDirection", "column");
2269
+ _$setProp4(_el$, "flexGrow", 1);
2270
+ _$setProp4(_el$, "paddingLeft", 2);
2271
+ _$setProp4(_el$, "paddingRight", 2);
2272
+ _$setProp4(_el$, "paddingTop", 1);
2273
+ _$setProp4(_el$, "paddingBottom", 1);
2274
+ _$insertNode4(_el$2, _el$3);
1739
2275
  _$use((value) => {
1740
2276
  scroll = value;
1741
- }, _el$);
1742
- _$setProp3(_el$, "flexGrow", 1);
1743
- _$insert3(_el$, _$createComponent3(GuardView, {
2277
+ }, _el$2);
2278
+ _$setProp4(_el$2, "flexGrow", 1);
2279
+ _$setProp4(_el$2, "minHeight", 0);
2280
+ _$insertNode4(_el$3, _el$4);
2281
+ _$setProp4(_el$3, "flexDirection", "column");
2282
+ _$insert4(_el$3, _$createComponent4(GuardView, {
1744
2283
  get sessionID() {
1745
2284
  return props.input.sessionID;
1746
2285
  },
@@ -1751,7 +2290,7 @@ function GuardPanel(props) {
1751
2290
  return props.context;
1752
2291
  },
1753
2292
  get width() {
1754
- return Math.max(10, props.input.width - 4);
2293
+ return width();
1755
2294
  },
1756
2295
  expanded: true,
1757
2296
  get family() {
@@ -1763,28 +2302,60 @@ function GuardPanel(props) {
1763
2302
  get inspectId() {
1764
2303
  return inspectId();
1765
2304
  }
1766
- }), _el$2);
1767
- _$insertNode3(_el$2, _$createTextNode3(`r refresh / l load more`));
1768
- _$insertNode3(_el$4, _el$5);
1769
- _$insertNode3(_el$4, _el$6);
1770
- _$insert3(_el$4, () => offset() + 1, _el$6);
1771
- _$insertNode3(_el$7, _$createTextNode3(`space expand / i inspect selected`));
1772
- _$insertNode3(_el$9, _$createTextNode3(`Guard input = prompt + caches.`));
1773
- _$insertNode3(_el$1, _$createTextNode3(`Native Context uses different totals.`));
1774
- _$effect3((_p$) => {
1775
- var _v$ = props.context.theme.text.muted, _v$2 = props.context.theme.text.muted, _v$3 = props.context.theme.text.muted, _v$4 = props.context.theme.text.muted, _v$5 = props.context.theme.text.muted;
1776
- _v$ !== _p$.e && (_p$.e = _$setProp3(_el$2, "fg", _v$, _p$.e));
1777
- _v$2 !== _p$.t && (_p$.t = _$setProp3(_el$4, "fg", _v$2, _p$.t));
1778
- _v$3 !== _p$.a && (_p$.a = _$setProp3(_el$7, "fg", _v$3, _p$.a));
1779
- _v$4 !== _p$.o && (_p$.o = _$setProp3(_el$9, "fg", _v$4, _p$.o));
1780
- _v$5 !== _p$.i && (_p$.i = _$setProp3(_el$1, "fg", _v$5, _p$.i));
2305
+ }), _el$4);
2306
+ _$insert4(_el$4, () => wrap("Guard input = prompt + caches. Native Context uses different totals.", width()).join("\n"));
2307
+ _$insert4(_el$2, _$createComponent4(Show3, {
2308
+ get when() {
2309
+ return showCharts();
2310
+ },
2311
+ get children() {
2312
+ return _$createComponent4(HistoryCharts, {
2313
+ get sessionId() {
2314
+ return selected();
2315
+ },
2316
+ get windowMs() {
2317
+ return windows[windowIndex()] ?? 3600000;
2318
+ },
2319
+ get metricIndex() {
2320
+ return metricIndex();
2321
+ },
2322
+ get refresh() {
2323
+ return chartRefresh();
2324
+ },
2325
+ get width() {
2326
+ return width();
2327
+ },
2328
+ get state() {
2329
+ return props.state;
2330
+ },
2331
+ get context() {
2332
+ return props.context;
2333
+ }
2334
+ });
2335
+ }
2336
+ }), null);
2337
+ _$setProp4(_el$5, "flexDirection", "column");
2338
+ _$setProp4(_el$5, "flexShrink", 0);
2339
+ _$setProp4(_el$5, "paddingTop", 1);
2340
+ _$insert4(_el$5, _$createComponent4(For4, {
2341
+ get each() {
2342
+ return hints().flatMap((hint) => wrap(hint, width()));
2343
+ },
2344
+ children: (line) => (() => {
2345
+ var _el$6 = _$createElement4("text");
2346
+ _$insert4(_el$6, line);
2347
+ _$effect4((_$p) => _$setProp4(_el$6, "fg", props.context.theme.text.muted, _$p));
2348
+ return _el$6;
2349
+ })()
2350
+ }));
2351
+ _$effect4((_p$) => {
2352
+ var _v$ = !showCharts(), _v$2 = props.context.theme.text.muted;
2353
+ _v$ !== _p$.e && (_p$.e = _$setProp4(_el$3, "visible", _v$, _p$.e));
2354
+ _v$2 !== _p$.t && (_p$.t = _$setProp4(_el$4, "fg", _v$2, _p$.t));
1781
2355
  return _p$;
1782
2356
  }, {
1783
2357
  e: undefined,
1784
- t: undefined,
1785
- a: undefined,
1786
- o: undefined,
1787
- i: undefined
2358
+ t: undefined
1788
2359
  });
1789
2360
  return _el$;
1790
2361
  })();
@@ -1801,7 +2372,7 @@ var tui_default = Plugin.define({
1801
2372
  try {
1802
2373
  unregister.push(context.ui.slot({
1803
2374
  append: "sidebar.content",
1804
- render: (input) => _$createComponent4(GuardView, {
2375
+ render: (input) => _$createComponent5(GuardView, {
1805
2376
  get sessionID() {
1806
2377
  return input.sessionID;
1807
2378
  },
@@ -1812,12 +2383,12 @@ var tui_default = Plugin.define({
1812
2383
  }));
1813
2384
  unregister.push(context.ui.slot({
1814
2385
  append: "session.panel",
1815
- render: (input) => _$createComponent4(Show3, {
2386
+ render: (input) => _$createComponent5(Show4, {
1816
2387
  get when() {
1817
2388
  return input.name === "context-guard.monitor";
1818
2389
  },
1819
2390
  get children() {
1820
- return _$createComponent4(GuardPanel, {
2391
+ return _$createComponent5(GuardPanel, {
1821
2392
  input,
1822
2393
  state,
1823
2394
  context
@@ -1827,15 +2398,15 @@ var tui_default = Plugin.define({
1827
2398
  }));
1828
2399
  unregister.push(context.ui.slot({
1829
2400
  append: "session.composer.top",
1830
- render: (input) => _$createComponent4(Show3, {
2401
+ render: (input) => _$createComponent5(Show4, {
1831
2402
  get when() {
1832
2403
  return context.data.session.get(input.sessionID)?.parentID;
1833
2404
  },
1834
2405
  get children() {
1835
- var _el$ = _$createElement4("text");
1836
- _$insertNode4(_el$, _$createTextNode4(`Context Guard: open panel`));
1837
- _$setProp4(_el$, "onMouseDown", () => context.ui.panel.open("context-guard.monitor"));
1838
- _$effect4((_$p) => _$setProp4(_el$, "fg", context.theme.text.muted, _$p));
2406
+ var _el$ = _$createElement5("text");
2407
+ _$insertNode5(_el$, _$createTextNode3(`Context Guard: open panel`));
2408
+ _$setProp5(_el$, "onMouseDown", () => context.ui.panel.open("context-guard.monitor"));
2409
+ _$effect5((_$p) => _$setProp5(_el$, "fg", context.theme.text.muted, _$p));
1839
2410
  return _el$;
1840
2411
  }
1841
2412
  })