@cesarus777/opencode-cgp 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js CHANGED
@@ -1,174 +1,33 @@
1
1
  // @bun
2
- // src/rpc.ts
3
- import { Rpc } from "@opencode/plugin/rpc";
4
- var count = {
5
- type: "integer",
6
- minimum: 0,
7
- maximum: Number.MAX_SAFE_INTEGER
8
- };
9
- var text = { type: "string", minLength: 1, maxLength: 512 };
10
- var enumeration = (...values) => ({ type: "string", enum: values });
11
- var object = (properties, required = Object.keys(properties)) => ({
12
- type: "object",
13
- properties,
14
- required,
15
- additionalProperties: false
16
- });
17
- var array = (items, maxItems = 128) => ({
18
- type: "array",
19
- items,
20
- maxItems
21
- });
22
- var measurement = object({
23
- tokens: count,
24
- at: count,
25
- model: text,
26
- requestId: text,
27
- provenance: enumeration("provider-normalized", "serialized-estimate"),
28
- confidence: enumeration("reported", "approximate"),
29
- scope: enumeration("completed-request", "prepared-request")
30
- }, ["tokens", "at", "model", "provenance", "confidence", "scope"]);
31
- var row = object({
32
- sessionId: text,
33
- revision: count,
34
- observedAt: count,
35
- parentId: text,
36
- agent: text,
37
- model: text,
38
- measurement,
39
- limits: object({ context: count, input: count, output: count }, [
40
- "context",
41
- "output"
42
- ]),
43
- capacityTokens: count,
44
- outputReserveTokens: count,
45
- peakTokens: count,
46
- policy: object({
47
- id: text,
48
- configured: object({
49
- type: enumeration("tokens", "ratio", "remaining"),
50
- value: { type: "number", minimum: 0 }
51
- }),
52
- triggerTokens: { type: "number" },
53
- comparison: enumeration(">=", ">"),
54
- reason: enumeration("missing-usage", "model-changed", "invalid-usage", "stale-usage", "missing-model-budget", "incompatible-model-budget", "threshold-crossed", "below-threshold"),
55
- crossed: { type: "boolean" }
56
- }, ["id", "configured", "comparison", "reason", "crossed"]),
57
- compaction: object({
58
- phase: enumeration("idle", "requesting", "accepted", "running", "awaiting-measurement", "blocked", "uncertain"),
59
- count,
60
- armed: { type: "boolean" },
61
- blockedReason: enumeration("session-removed", "compaction-failed", "reclaim-unverifiable", "insufficient-reclaim", "completion-event-timeout", "admission-outcome-unknown", "restart-needs-lifecycle-evidence"),
62
- lastAttempt: count,
63
- lastCompleted: count,
64
- cooldownUntil: count
65
- }, ["phase", "armed"]),
66
- cumulative: object({
67
- input: count,
68
- output: count,
69
- reasoning: count,
70
- cache: object({ read: count, write: count })
71
- }),
72
- cumulativeScope: enumeration("session", "unknown"),
73
- lastObservedActive: { type: "boolean" }
74
- }, [
75
- "sessionId",
76
- "revision",
77
- "observedAt",
78
- "policy",
79
- "compaction",
80
- "cumulativeScope",
81
- "lastObservedActive"
82
- ]);
83
- var batchFields = {
84
- schemaVersion: { const: 1 },
85
- epoch: text,
86
- sequence: count,
87
- generatedAt: count,
88
- health: object({
89
- enabled: { type: "boolean" },
90
- mode: enumeration("observe", "enforce"),
91
- enforcement: enumeration("observing", "available", "suspended", "disabled"),
92
- reasons: array(enumeration("event-stream-gap", "persistence-unavailable", "capacity-exceeded", "model-metadata-unavailable"), 8),
93
- staleMs: count,
94
- maxSessions: count
95
- }),
96
- upserts: array(row),
97
- removed: array(object({
98
- sessionId: text,
99
- revision: count,
100
- reason: enumeration("deleted", "evicted")
101
- }))
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
102
17
  };
103
- var readSchema = object({
104
- schemaVersion: { const: 1 },
105
- sessionIds: { ...array(text), uniqueItems: true }
106
- });
107
- var batchSchema = object(batchFields);
108
- var resultSchema = object({
109
- ...batchFields,
110
- unavailable: array(object({ sessionId: text, reason: enumeration("not-monitored") }))
111
- });
112
- var monitorRpc = Rpc.define({
113
- id: "context-guard.monitor.v1",
114
- methods: { read: { input: readSchema, output: resultSchema } },
115
- events: { changed: { schema: batchSchema } }
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 }
18
+ var __export = (target, all) => {
19
+ for (var name in all)
20
+ __defProp(target, name, {
21
+ get: all[name],
22
+ enumerable: true,
23
+ configurable: true,
24
+ set: (newValue) => all[name] = () => newValue
25
+ });
157
26
  };
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
- });
27
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
28
+
29
+ // src/rpc.ts
30
+ import { Rpc } from "@opencode/plugin/rpc";
172
31
  function isPerformanceBatch(value) {
173
32
  return valid(value, performanceBatchSchema) && uniqueRows(value);
174
33
  }
@@ -178,84 +37,6 @@ function isPerformanceResult(value) {
178
37
  function isPerformanceSnapshot(value) {
179
38
  return valid(value, performanceSchema);
180
39
  }
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
40
  function isHistoryRead(value) {
260
41
  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
42
  }
@@ -310,19 +91,252 @@ function uniqueRows(value) {
310
91
  const ids = [...value.upserts, ...value.removed].map((v) => record(v) ? v.sessionId : undefined);
311
92
  return ids.length <= 128 && new Set(ids).size === ids.length;
312
93
  }
313
-
314
- // src/tui.tsx
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";
321
- import { Plugin } from "@opencode/plugin/tui";
322
- import { Show as Show4 } from "solid-js";
323
-
324
- // src/tui/state.ts
325
- import { createSignal } from "solid-js";
94
+ var count, text, enumeration = (...values) => ({ type: "string", enum: values }), object = (properties, required = Object.keys(properties)) => ({
95
+ type: "object",
96
+ properties,
97
+ required,
98
+ additionalProperties: false
99
+ }), array = (items, maxItems = 128) => ({
100
+ type: "array",
101
+ items,
102
+ maxItems
103
+ }), measurement, row, batchFields, readSchema, batchSchema, resultSchema, monitorRpc, nonnegative, performanceSchema, performanceRow, performanceBatchSchema, performanceResultSchema, performanceRpc, chartPointSchema, chartRequestSchema, historyReadSchema, historyResultSchema, historyRpc;
104
+ var init_rpc = __esm(() => {
105
+ count = {
106
+ type: "integer",
107
+ minimum: 0,
108
+ maximum: Number.MAX_SAFE_INTEGER
109
+ };
110
+ text = { type: "string", minLength: 1, maxLength: 512 };
111
+ measurement = object({
112
+ tokens: count,
113
+ at: count,
114
+ model: text,
115
+ requestId: text,
116
+ provenance: enumeration("provider-normalized", "serialized-estimate"),
117
+ confidence: enumeration("reported", "approximate"),
118
+ scope: enumeration("completed-request", "prepared-request")
119
+ }, ["tokens", "at", "model", "provenance", "confidence", "scope"]);
120
+ row = object({
121
+ sessionId: text,
122
+ revision: count,
123
+ observedAt: count,
124
+ parentId: text,
125
+ agent: text,
126
+ model: text,
127
+ measurement,
128
+ limits: object({ context: count, input: count, output: count }, [
129
+ "context",
130
+ "output"
131
+ ]),
132
+ capacityTokens: count,
133
+ outputReserveTokens: count,
134
+ peakTokens: count,
135
+ policy: object({
136
+ id: text,
137
+ configured: object({
138
+ type: enumeration("tokens", "ratio", "remaining"),
139
+ value: { type: "number", minimum: 0 }
140
+ }),
141
+ triggerTokens: { type: "number" },
142
+ comparison: enumeration(">=", ">"),
143
+ reason: enumeration("missing-usage", "model-changed", "invalid-usage", "stale-usage", "missing-model-budget", "incompatible-model-budget", "threshold-crossed", "below-threshold"),
144
+ crossed: { type: "boolean" }
145
+ }, ["id", "configured", "comparison", "reason", "crossed"]),
146
+ compaction: object({
147
+ phase: enumeration("idle", "requesting", "accepted", "running", "awaiting-measurement", "blocked", "uncertain"),
148
+ count,
149
+ armed: { type: "boolean" },
150
+ blockedReason: enumeration("session-removed", "compaction-failed", "reclaim-unverifiable", "insufficient-reclaim", "completion-event-timeout", "admission-outcome-unknown", "restart-needs-lifecycle-evidence"),
151
+ lastAttempt: count,
152
+ lastCompleted: count,
153
+ cooldownUntil: count
154
+ }, ["phase", "armed"]),
155
+ cumulative: object({
156
+ input: count,
157
+ output: count,
158
+ reasoning: count,
159
+ cache: object({ read: count, write: count })
160
+ }),
161
+ cumulativeScope: enumeration("session", "unknown"),
162
+ lastObservedActive: { type: "boolean" }
163
+ }, [
164
+ "sessionId",
165
+ "revision",
166
+ "observedAt",
167
+ "policy",
168
+ "compaction",
169
+ "cumulativeScope",
170
+ "lastObservedActive"
171
+ ]);
172
+ batchFields = {
173
+ schemaVersion: { const: 1 },
174
+ epoch: text,
175
+ sequence: count,
176
+ generatedAt: count,
177
+ health: object({
178
+ enabled: { type: "boolean" },
179
+ mode: enumeration("observe", "enforce"),
180
+ enforcement: enumeration("observing", "available", "suspended", "disabled"),
181
+ reasons: array(enumeration("event-stream-gap", "persistence-unavailable", "capacity-exceeded", "model-metadata-unavailable"), 8),
182
+ staleMs: count,
183
+ maxSessions: count
184
+ }),
185
+ upserts: array(row),
186
+ removed: array(object({
187
+ sessionId: text,
188
+ revision: count,
189
+ reason: enumeration("deleted", "evicted")
190
+ }))
191
+ };
192
+ readSchema = object({
193
+ schemaVersion: { const: 1 },
194
+ sessionIds: { ...array(text), uniqueItems: true }
195
+ });
196
+ batchSchema = object(batchFields);
197
+ resultSchema = object({
198
+ ...batchFields,
199
+ unavailable: array(object({ sessionId: text, reason: enumeration("not-monitored") }))
200
+ });
201
+ monitorRpc = Rpc.define({
202
+ id: "context-guard.monitor.v1",
203
+ methods: { read: { input: readSchema, output: resultSchema } },
204
+ events: { changed: { schema: batchSchema } }
205
+ });
206
+ nonnegative = { type: "number", minimum: 0 };
207
+ performanceSchema = object({
208
+ observedSince: count,
209
+ at: count,
210
+ sessionCreatedAt: count,
211
+ sessionOutputTokens: count,
212
+ status: enumeration("waiting", "streaming", "idle", "unavailable"),
213
+ partial: { type: "boolean" },
214
+ liveTps: nonnegative,
215
+ averageModelTps: nonnegative,
216
+ averageSessionTps: nonnegative,
217
+ ttftMs: nonnegative,
218
+ latestRequestTps: nonnegative,
219
+ requestId: text,
220
+ requestAgent: text,
221
+ requestModel: text,
222
+ requestOutputTokens: count,
223
+ requestStartedAt: count,
224
+ firstOutputAt: count,
225
+ streamEndedAt: count,
226
+ estimatedOutputTokens: nonnegative,
227
+ modelOutputTokens: nonnegative,
228
+ modelDurationMs: nonnegative,
229
+ completedRequests: count,
230
+ tokenSource: enumeration("estimated", "reported", "unavailable")
231
+ }, [
232
+ "sessionCreatedAt",
233
+ "observedSince",
234
+ "at",
235
+ "status",
236
+ "partial",
237
+ "estimatedOutputTokens",
238
+ "modelOutputTokens",
239
+ "modelDurationMs",
240
+ "completedRequests",
241
+ "tokenSource"
242
+ ]);
243
+ performanceRow = {
244
+ ...row,
245
+ properties: { ...row.properties, performance: performanceSchema }
246
+ };
247
+ performanceBatchSchema = object({
248
+ ...batchFields,
249
+ upserts: array(performanceRow)
250
+ });
251
+ performanceResultSchema = object({
252
+ ...batchFields,
253
+ upserts: array(performanceRow),
254
+ unavailable: resultSchema.properties.unavailable ?? {}
255
+ });
256
+ performanceRpc = Rpc.define({
257
+ id: "context-guard.monitor.v2",
258
+ methods: { read: { input: readSchema, output: performanceResultSchema } },
259
+ events: { changed: { schema: performanceBatchSchema } }
260
+ });
261
+ chartPointSchema = object({
262
+ time: count,
263
+ agent: text,
264
+ model: text,
265
+ breakBefore: { type: "boolean" },
266
+ partial: { type: "boolean" },
267
+ liveTps: nonnegative,
268
+ averageModelTps: nonnegative,
269
+ averageSessionTps: nonnegative,
270
+ sessionOutputTokens: count
271
+ }, ["time", "breakBefore", "partial"]);
272
+ chartRequestSchema = object({
273
+ time: count,
274
+ requestId: text,
275
+ started: count,
276
+ agent: text,
277
+ model: text,
278
+ ttftMs: nonnegative,
279
+ outputTokens: count,
280
+ durationMs: nonnegative,
281
+ tps: nonnegative,
282
+ partial: { type: "boolean" }
283
+ }, ["time", "requestId", "started", "partial"]);
284
+ historyReadSchema = object({
285
+ schemaVersion: { const: 1 },
286
+ sessionId: text,
287
+ from: count,
288
+ to: count,
289
+ maxPoints: { type: "integer", minimum: 16, maximum: 500 }
290
+ });
291
+ historyResultSchema = object({
292
+ schemaVersion: { const: 1 },
293
+ generatedAt: count,
294
+ enabled: { type: "boolean" },
295
+ truncated: { type: "boolean" },
296
+ metadata: object({
297
+ schema: { const: 1 },
298
+ retainedFrom: count,
299
+ retainedBytes: count,
300
+ skippedBytes: count,
301
+ malformedRecords: count,
302
+ completeness: enumeration("bounded-retention")
303
+ }, [
304
+ "schema",
305
+ "retainedBytes",
306
+ "skippedBytes",
307
+ "malformedRecords",
308
+ "completeness"
309
+ ]),
310
+ data: object({
311
+ schema: { const: 1 },
312
+ omittedSessions: count,
313
+ omittedGaps: count,
314
+ maxPoints: count,
315
+ gaps: array(object({ time: count, sessionId: text, reason: text }), 128),
316
+ series: array(object({
317
+ sessionId: text,
318
+ parentId: text,
319
+ agents: array(text, 1024),
320
+ models: array(text, 1024),
321
+ points: array(chartPointSchema, 500),
322
+ requests: array(chartRequestSchema, 500),
323
+ originalPoints: count
324
+ }, [
325
+ "sessionId",
326
+ "agents",
327
+ "models",
328
+ "points",
329
+ "requests",
330
+ "originalPoints"
331
+ ]), 1)
332
+ }, ["schema", "omittedSessions", "maxPoints", "gaps", "series"])
333
+ });
334
+ historyRpc = Rpc.define({
335
+ id: "context-guard.history.v1",
336
+ methods: { read: { input: historyReadSchema, output: historyResultSchema } },
337
+ events: {}
338
+ });
339
+ });
326
340
 
327
341
  // src/family.ts
328
342
  function metric(snapshot, now, staleMs) {
@@ -427,131 +441,6 @@ function executionStatus(known, nativeRunning, evidence) {
427
441
  return known ? "idle" : "unknown";
428
442
  }
429
443
 
430
- // src/tui/contextchart.ts
431
- function updateContextTrace(previous, row2) {
432
- const snapshot = row2?.snapshot;
433
- const sessionId = row2?.node.sessionId ?? "";
434
- const sameSession = previous?.sessionId === sessionId;
435
- const model = snapshot?.model ?? row2?.node.model ?? (sameSession ? previous?.model : undefined);
436
- const capacity = snapshot?.capacityTokens ?? (sameSession && model === previous?.model ? previous?.capacity : undefined);
437
- const compatible = sameSession && previous?.model === model && previous.capacity === capacity;
438
- const samples = compatible ? previous.samples : [];
439
- const completed = snapshot?.compaction.lastCompleted ?? (compatible ? previous.lastCompleted : undefined);
440
- let pending = compatible ? previous.pendingCompleted : undefined;
441
- if (completed !== undefined && completed !== previous?.lastCompleted)
442
- pending = completed;
443
- const measurement2 = snapshot?.measurement;
444
- const valid2 = (row2?.freshness === "fresh" || row2?.freshness === "stale") && measurement2 && Number.isFinite(measurement2.tokens) && measurement2.tokens >= 0;
445
- const at = measurement2?.at ?? snapshot?.observedAt;
446
- let next = samples;
447
- if (at !== undefined && Number.isFinite(at)) {
448
- const last = samples.at(-1);
449
- if (!last || at >= last.at) {
450
- const reset = valid2 && (at === last?.at && last.compacted === true || pending !== undefined && measurement2.at >= pending && measurement2.confidence === "reported" && measurement2.scope === "completed-request" && snapshot?.compaction.phase !== "running");
451
- const waiting = pending !== undefined && !reset;
452
- const tokens = valid2 && !waiting ? Math.max(reset ? 0 : last?.tokens ?? 0, measurement2.tokens) : last?.tokens;
453
- const held = tokens !== undefined && (!valid2 || waiting || tokens !== measurement2.tokens);
454
- const sample = {
455
- at,
456
- ...tokens === undefined ? {} : { tokens },
457
- ...held ? { held: true } : {},
458
- ...reset || at === last?.at && last.compacted ? { compacted: true } : {}
459
- };
460
- if (reset)
461
- pending = undefined;
462
- if (!last || at > last.at) {
463
- const bridge = last?.tokens !== undefined && at - last.at > 2500 ? [{ at: at - 1, tokens: last.tokens, held: true }] : [];
464
- next = [...samples, ...bridge, sample].slice(-96);
465
- } else if (sample.tokens !== last.tokens || sample.held !== last.held || sample.compacted !== last.compacted) {
466
- next = [...samples.slice(0, -1), sample];
467
- }
468
- }
469
- }
470
- return {
471
- sessionId,
472
- model,
473
- capacity,
474
- samples: next,
475
- ...completed === undefined ? {} : { lastCompleted: completed },
476
- ...pending === undefined ? {} : { pendingCompleted: pending }
477
- };
478
- }
479
-
480
- class ContextTraceStore {
481
- traces = new Map;
482
- update(row2) {
483
- if (!row2)
484
- return updateContextTrace(undefined, undefined);
485
- const id = row2.node.sessionId;
486
- const trace = updateContextTrace(this.traces.get(id), row2);
487
- this.traces.delete(id);
488
- this.traces.set(id, trace);
489
- if (this.traces.size > 128) {
490
- const oldest = this.traces.keys().next().value;
491
- if (oldest !== undefined)
492
- this.traces.delete(oldest);
493
- }
494
- return trace;
495
- }
496
- clear() {
497
- this.traces.clear();
498
- }
499
- }
500
- function contextChart(samples, capacity, trigger, width, now) {
501
- if (capacity === undefined || !Number.isFinite(capacity) || capacity <= 0 || width < 4)
502
- return [];
503
- const height = 8;
504
- const gutter = width >= 16 ? 4 : 0;
505
- const size = Math.max(1, Math.min(96, width - gutter - 2));
506
- const last = samples.at(-1);
507
- const tail = now !== undefined && last?.tokens !== undefined && now - last.at > 2500 ? [{ at: now, tokens: last.tokens, held: true }] : [];
508
- const values = [...samples, ...tail].slice(-size);
509
- const offset = size - values.length;
510
- const thresholdRow = trigger !== undefined && Number.isFinite(trigger) && trigger >= 0 && trigger <= capacity ? Math.round((1 - trigger / capacity) * (height - 1)) : -1;
511
- const blocks = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
512
- const lines = Array.from({ length: height }, (_, row2) => {
513
- const threshold = row2 === thresholdRow;
514
- const axis = gutter ? (row2 === 0 ? "100%" : row2 === height - 1 ? "0%" : "").padStart(gutter) : "";
515
- const plot = Array.from({ length: size }, (_2, col) => {
516
- const sample = values[col - offset];
517
- const value = sample?.tokens;
518
- const fill = value === undefined ? 0 : Math.max(0, Math.min(8, Math.ceil((Math.min(value / capacity, 1) * height - (height - row2 - 1)) * 8)));
519
- if (sample?.held && value !== undefined) {
520
- const top = Math.min(height - 1, Math.max(0, height - Math.ceil(Math.min(value / capacity, 1) * height)));
521
- if (row2 === top)
522
- return "\u2508";
523
- if (fill > 0)
524
- return "\u2591";
525
- }
526
- if (threshold)
527
- return fill > 0 ? "\u2542" : "\u2504";
528
- if (value === 0 && row2 === height - 1)
529
- return "\u2581";
530
- return blocks[fill] ?? " ";
531
- });
532
- const line = `${axis}\u2502${plot.join("")}\u2502`;
533
- if (!values.some((sample) => sample.held))
534
- return { line, threshold };
535
- const segments = [{ text: `${axis}\u2502`, held: false }];
536
- for (let col = 0;col < plot.length; col++) {
537
- const text2 = plot[col] ?? " ";
538
- const held = values[col - offset]?.held === true;
539
- const previous = segments.at(-1);
540
- if (previous?.held === held)
541
- segments[segments.length - 1] = { text: previous.text + text2, held };
542
- else
543
- segments.push({ text: text2, held });
544
- }
545
- segments.push({ text: "\u2502", held: false });
546
- return { line, threshold, segments };
547
- });
548
- lines.push({
549
- line: `${" ".repeat(gutter)}\u2514${"\u2500".repeat(size)}\u2518`,
550
- threshold: false
551
- });
552
- return lines;
553
- }
554
-
555
444
  // src/tui/transport.ts
556
445
  class SnapshotClient {
557
446
  transport;
@@ -800,30 +689,407 @@ class SnapshotClient {
800
689
  });
801
690
  }
802
691
  }
803
- stop() {
804
- this.generation++;
805
- this.controller?.abort();
806
- this.controller = undefined;
807
- clearInterval(this.refreshTimer);
808
- clearTimeout(this.retryTimer);
809
- this.reading = undefined;
810
- this.buffered = [];
811
- this.overflow = false;
812
- this.refreshAgain = false;
692
+ stop() {
693
+ this.generation++;
694
+ this.controller?.abort();
695
+ this.controller = undefined;
696
+ clearInterval(this.refreshTimer);
697
+ clearTimeout(this.retryTimer);
698
+ this.reading = undefined;
699
+ this.buffered = [];
700
+ this.overflow = false;
701
+ this.refreshAgain = false;
702
+ }
703
+ }
704
+ function abortable(promise, signal) {
705
+ return new Promise((resolve, reject) => {
706
+ const abort = () => reject(new Error("Snapshot request cancelled"));
707
+ if (signal.aborted) {
708
+ abort();
709
+ return;
710
+ }
711
+ signal.addEventListener("abort", abort, { once: true });
712
+ promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
713
+ });
714
+ }
715
+ var init_transport = __esm(() => {
716
+ init_rpc();
717
+ });
718
+
719
+ // src/tui/format.ts
720
+ function quantity(n) {
721
+ 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);
722
+ }
723
+ function cells(value) {
724
+ return [...segmenter.segment(value)].reduce((n, { segment }) => n + graphemeWidth(segment), 0);
725
+ }
726
+ function graphemeWidth(s) {
727
+ const cp = s.codePointAt(0) ?? 0;
728
+ if (/^[\p{Mark}\u200d\ufe0f]+$/u.test(s))
729
+ return 0;
730
+ return /[\p{Extended_Pictographic}\p{Regional_Indicator}\u20e3]/u.test(s) || cp >= 4352 && (cp <= 4447 || cp >= 9001 && cp <= 9002 || cp >= 11904 && cp <= 42191 || cp >= 44032 && cp <= 55203 || cp >= 63744 && cp <= 64255 || cp >= 65040 && cp <= 65135 || cp >= 65281 && cp <= 65376 || cp >= 131072) ? 2 : 1;
731
+ }
732
+ function clip(value, width) {
733
+ const clean = sanitize(value);
734
+ if (cells(clean) <= width)
735
+ return clean;
736
+ let result = "", used = 0;
737
+ for (const { segment } of segmenter.segment(clean)) {
738
+ const size = graphemeWidth(segment);
739
+ if (used + size > Math.max(0, width - 3))
740
+ break;
741
+ result += segment;
742
+ used += size;
743
+ }
744
+ return width < 3 ? ".".repeat(Math.max(0, width)) : result + "...";
745
+ }
746
+ function rowLines(row2, width) {
747
+ const s = row2.snapshot, m = s?.measurement;
748
+ const prefix = row2.current ? "* " : row2.depth > 5 ? ".../" : " ".repeat(Math.min(row2.depth, 5)) + "|-";
749
+ const percent = row2.utilizationPercent === undefined ? "?" : `${row2.utilizationPercent.toFixed(1)}%`;
750
+ const warning = row2.freshness === "stale" ? " STALE" : row2.pressure === "crossed" ? " !! crossed" : row2.pressure === "near" ? " ! near" : "";
751
+ const suffix = ` ${statuses[row2.node.status]} ${m?.confidence === "approximate" ? "~" : ""}${percent}${warning}`;
752
+ const label = clip(`${prefix}${row2.node.agent ?? row2.node.sessionId}`, Math.max(1, width - cells(suffix)));
753
+ return [
754
+ clip(`${label}${suffix}`, width),
755
+ ...performanceLines(row2, width),
756
+ ...wrap(`${quantity(m?.tokens)}/${quantity(s?.capacityTokens)} input; to ${quantity(row2.triggerDeltaTokens)}`, width),
757
+ ...s && s.compaction.phase !== "idle" ? wrap(`compact: ${s.compaction.phase}`, width) : [],
758
+ ...row2.node.interrupted ? [clip("interrupted", width)] : [],
759
+ ...row2.hidden ? wrap(`+ ${row2.hidden} completed descendants`, width) : []
760
+ ];
761
+ }
762
+ function detailLines(row2, width, expanded = false, ageMs = 0) {
763
+ const s = row2?.snapshot, m = s?.measurement;
764
+ if (!row2)
765
+ return wrap("Loading session family...", width);
766
+ if (!s)
767
+ return [
768
+ ...wrap(`${row2.node.agent ?? row2.node.sessionId} / ${row2.node.model ?? "?"}`, width),
769
+ ...wrap("Guard: not monitored / unavailable", width)
770
+ ];
771
+ const threshold = s.policy.configured;
772
+ const headroom = row2.triggerDeltaTokens;
773
+ const lines = [
774
+ `${s.agent ?? "?"} / ${s.model ?? "?"}`,
775
+ ...performanceLines(row2, width),
776
+ `${m?.confidence === "approximate" ? "~" : ""}${quantity(m?.tokens)} / ${quantity(s.capacityTokens)} input`,
777
+ `${row2.utilizationPercent?.toFixed(1) ?? "?"}% ${row2.pressure === "crossed" ? "!! crossed" : row2.pressure === "near" ? "! near" : row2.freshness.toUpperCase()}`,
778
+ `Trigger ${threshold.type === "ratio" ? `${threshold.value * 100}%` : `${threshold.value} ${threshold.type}`} (${s.policy.comparison})`,
779
+ `Resolved trigger ${s.policy.triggerTokens ?? "?"}`,
780
+ `Until trigger ${quantity(headroom)}`,
781
+ `Compact: ${s.compaction.phase}`,
782
+ `${s.compaction.armed ? "armed" : "disarmed"}${s.compaction.blockedReason ? ` / ${s.compaction.blockedReason}` : ""}`,
783
+ m ? `${m.confidence} ${m.scope}` : "measurement unknown",
784
+ m ? `${Math.floor(Math.max(0, ageMs) / 1000)}s ago; ${row2.freshness}` : ""
785
+ ];
786
+ if (expanded)
787
+ 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)}`);
788
+ return lines.filter(Boolean).flatMap((line) => wrap(line, width));
789
+ }
790
+ function sanitize(value) {
791
+ return value.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "").replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\x00-\x1f\x7f-\x9f]/g, "");
792
+ }
793
+ function wrap(value, width) {
794
+ const result = [];
795
+ let part = "";
796
+ for (const word of sanitize(value).split(" ")) {
797
+ if (part && cells(part + " " + word) > width) {
798
+ result.push(part);
799
+ part = "";
800
+ }
801
+ for (const { segment } of segmenter.segment((part ? " " : "") + word)) {
802
+ if (part && cells(part + segment) > width) {
803
+ result.push(part);
804
+ part = "";
805
+ }
806
+ part += cells(segment) <= width ? segment : "?";
807
+ }
808
+ }
809
+ if (part)
810
+ result.push(part);
811
+ return result;
812
+ }
813
+ function performanceLines(row2, width) {
814
+ const p = row2.snapshot?.performance;
815
+ if (!p)
816
+ return [];
817
+ const value = (n) => n === undefined ? "?" : n.toFixed(1);
818
+ return [
819
+ ...wrap(`TPS ${p.status === "waiting" ? "waiting" : `${p.status === "streaming" ? "~" : ""}${value(p.liveTps)}`} \xB7 ${p.status}${p.partial ? " \xB7 partial" : ""}`, width),
820
+ ...wrap(`Avg model ${value(p.averageModelTps)} \xB7 Avg session ${value(p.averageSessionTps)}`, width),
821
+ ...wrap(`TTFT ${p.ttftMs === undefined ? "?" : `~${(p.ttftMs / 1000).toFixed(2)}s`}${p.latestRequestTps === undefined ? "" : ` \xB7 Last ${value(p.latestRequestTps)} t/s`}`, width)
822
+ ];
823
+ }
824
+ var segmenter, statuses;
825
+ var init_format = __esm(() => {
826
+ segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
827
+ statuses = {
828
+ running: "RUN",
829
+ idle: "IDLE",
830
+ completed: "DONE",
831
+ failed: "FAIL",
832
+ unknown: "?"
833
+ };
834
+ });
835
+
836
+ // src/tui/chartformat.ts
837
+ function columns2(points, from, to, width, gaps = []) {
838
+ const size = Math.max(1, Math.min(120, Math.floor(width))), values = Array.from({ length: size });
839
+ const column = (time) => Math.max(0, Math.min(size - 1, Math.floor((time - from) / Math.max(1, to - from) * (size - 1))));
840
+ let min = Infinity, max = -Infinity;
841
+ for (const point of points) {
842
+ if (point.time < from || point.time > to || point.value === undefined || !Number.isFinite(point.value) || point.value < 0)
843
+ continue;
844
+ min = Math.min(min, point.value);
845
+ max = Math.max(max, point.value);
846
+ const i = column(point.time);
847
+ values[i] = Math.max(values[i] ?? -Infinity, point.value);
848
+ }
849
+ for (const time of gaps)
850
+ if (time >= from && time <= to)
851
+ values[column(time)] = undefined;
852
+ return { values, column, min, max };
853
+ }
854
+ function sparkline(points, from, to, width, gaps = []) {
855
+ const { values, column, min, max } = columns2(points, from, to, width, gaps);
856
+ const bars = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
857
+ const chars = values.map((v) => v === undefined ? " " : bars[Math.min(7, Math.floor(v / Math.max(1, max) * 7))] ?? "\u2581");
858
+ for (const time of gaps)
859
+ if (time >= from && time <= to)
860
+ chars[column(time)] = "\u2506";
861
+ return { line: chars.join(""), ...min === Infinity ? {} : { min, max } };
862
+ }
863
+ function metricPlot(points, from, to, width, gaps = []) {
864
+ const label = (value) => value >= 1e6 ? `${(value / 1e6).toFixed(1)}M` : value >= 1000 ? `${(value / 1000).toFixed(1)}k` : value.toFixed(1);
865
+ const peak = Math.max(0, ...points.filter((p) => p.time >= from && p.time <= to && Number.isFinite(p.value)).map((p) => p.value ?? 0));
866
+ const scale = Math.max(1, peak);
867
+ const gutter = width >= 20 ? Math.max(label(scale).length, 3) : 0;
868
+ const { values, column } = columns2(points, from, to, Math.max(1, width - gutter - 2), gaps);
869
+ const gapColumns = new Set(gaps.filter((time) => time >= from && time <= to).map(column));
870
+ const height = 6;
871
+ const blocks = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
872
+ const lines = Array.from({ length: height }, (_, row2) => {
873
+ const axis = gutter ? (row2 === 0 ? label(scale) : row2 === height - 1 ? "0.0" : "").padStart(gutter) : "";
874
+ return `${axis}\u2502${values.map((value, i) => {
875
+ if (gapColumns.has(i))
876
+ return "\u2506";
877
+ if (value === undefined)
878
+ return " ";
879
+ const fill = Math.max(0, Math.min(8, Math.ceil((value / scale * height - (height - row2 - 1)) * 8)));
880
+ return value === 0 && row2 === height - 1 ? "\u2581" : blocks[fill];
881
+ }).join("")}\u2502`;
882
+ });
883
+ lines.push(`${" ".repeat(gutter)}\u2514${"\u2500".repeat(values.length)}\u2518`);
884
+ const start = new Date(from).toISOString().slice(11, 16), end = new Date(to).toISOString().slice(11, 16);
885
+ const axisWidth = values.length + 2;
886
+ if (axisWidth >= 11)
887
+ lines.push(`${" ".repeat(gutter)}${start}${" ".repeat(axisWidth - 10)}${end}`);
888
+ return lines;
889
+ }
890
+ function historyChartLines(result, width, from, to, metricIndex = 0) {
891
+ if (!result.enabled)
892
+ return wrap("History recording is disabled on this server.", width);
893
+ const series = result.data.series[0];
894
+ if (!series)
895
+ return wrap("No retained measurements in this window.", width);
896
+ const gaps = result.data.gaps.map((g) => g.time);
897
+ const observations = (key) => series.points.map((p) => ({
898
+ time: p.time,
899
+ ...p[key] === undefined ? {} : { value: p[key] }
900
+ }));
901
+ const requests = (key) => series.requests.map((p) => ({
902
+ time: p.time,
903
+ ...p[key] === undefined ? {} : { value: key === "ttftMs" ? p[key] / 1000 : p[key] }
904
+ }));
905
+ const metric2 = chartMetrics[metricIndex] ?? chartMetrics[0];
906
+ const points = metric2.source === "points" ? observations(metric2.key) : requests(metric2.key);
907
+ const plotted = sparkline(points, from, to, width - 2, gaps);
908
+ return [
909
+ ...wrap(`\u2039 ${metric2.label} \u203A \xB7 ${metricIndex + 1}/${chartMetrics.length}`, width),
910
+ ...wrap(plotted.min === undefined ? "No measurements for this metric." : `${plotted.min.toFixed(1)}\u2013${plotted.max?.toFixed(1)} ${metric2.unit} \xB7 observed range`, width),
911
+ "",
912
+ ...metricPlot(points, from, to, width, gaps),
913
+ "",
914
+ ...wrap("UTC time \u2192 \xB7 peaks per column", width),
915
+ ...wrap("blank = no sample \xB7 \u2506 = gap", width),
916
+ ...wrap(`${new Date(from).toISOString()} \u2192 ${new Date(to).toISOString()}`, width),
917
+ ...series.points.some((p) => p.partial) ? wrap("Partial timing coverage; averages include only matched model durations.", width) : [],
918
+ ...result.truncated ? wrap("Downsampled/bounded history; some older requests or gap markers may be omitted.", width) : [],
919
+ ...result.metadata.malformedRecords ? wrap(`${result.metadata.malformedRecords} malformed/partial records skipped.`, width) : []
920
+ ];
921
+ }
922
+ var chartMetrics;
923
+ var init_chartformat = __esm(() => {
924
+ init_format();
925
+ chartMetrics = [
926
+ { label: "Live TPS ~", unit: "t/s", key: "liveTps", source: "points" },
927
+ { label: "Avg model", unit: "t/s", key: "averageModelTps", source: "points" },
928
+ {
929
+ label: "Avg session",
930
+ unit: "t/s",
931
+ key: "averageSessionTps",
932
+ source: "points"
933
+ },
934
+ { label: "TTFT ~", unit: "s", key: "ttftMs", source: "requests" },
935
+ { label: "Request throughput", unit: "t/s", key: "tps", source: "requests" },
936
+ {
937
+ label: "Cumulative output",
938
+ unit: "tokens",
939
+ key: "sessionOutputTokens",
940
+ source: "points"
941
+ }
942
+ ];
943
+ });
944
+
945
+ // src/tui.tsx
946
+ import { effect as _$effect5 } from "@opentui/solid";
947
+ import { createTextNode as _$createTextNode3 } from "@opentui/solid";
948
+ import { insertNode as _$insertNode5 } from "@opentui/solid";
949
+ import { setProp as _$setProp5 } from "@opentui/solid";
950
+ import { createElement as _$createElement5 } from "@opentui/solid";
951
+ import { createComponent as _$createComponent5 } from "@opentui/solid";
952
+ import { Plugin } from "@opencode/plugin/tui";
953
+ import { Show as Show4 } from "solid-js";
954
+
955
+ // src/tui/state.ts
956
+ init_rpc();
957
+ import { createSignal } from "solid-js";
958
+
959
+ // src/tui/contextchart.ts
960
+ function updateContextTrace(previous, row2) {
961
+ const snapshot = row2?.snapshot;
962
+ const sessionId = row2?.node.sessionId ?? "";
963
+ const sameSession = previous?.sessionId === sessionId;
964
+ const model = snapshot?.model ?? row2?.node.model ?? (sameSession ? previous?.model : undefined);
965
+ const capacity = snapshot?.capacityTokens ?? (sameSession && model === previous?.model ? previous?.capacity : undefined);
966
+ const compatible = sameSession && previous?.model === model && previous.capacity === capacity;
967
+ const samples = compatible ? previous.samples : [];
968
+ const completed = snapshot?.compaction.lastCompleted ?? (compatible ? previous.lastCompleted : undefined);
969
+ let pending = compatible ? previous.pendingCompleted : undefined;
970
+ if (completed !== undefined && completed !== previous?.lastCompleted)
971
+ pending = completed;
972
+ const measurement2 = snapshot?.measurement;
973
+ const valid2 = (row2?.freshness === "fresh" || row2?.freshness === "stale") && measurement2 && Number.isFinite(measurement2.tokens) && measurement2.tokens >= 0;
974
+ const at = measurement2?.at ?? snapshot?.observedAt;
975
+ let next = samples;
976
+ if (at !== undefined && Number.isFinite(at)) {
977
+ const last = samples.at(-1);
978
+ if (!last || at >= last.at) {
979
+ const reset = valid2 && (at === last?.at && last.compacted === true || pending !== undefined && measurement2.at >= pending && measurement2.confidence === "reported" && measurement2.scope === "completed-request" && snapshot?.compaction.phase !== "running");
980
+ const waiting = pending !== undefined && !reset;
981
+ const tokens = valid2 && !waiting ? Math.max(reset ? 0 : last?.tokens ?? 0, measurement2.tokens) : last?.tokens;
982
+ const held = tokens !== undefined && (!valid2 || waiting || tokens !== measurement2.tokens);
983
+ const sample = {
984
+ at,
985
+ ...tokens === undefined ? {} : { tokens },
986
+ ...held ? { held: true } : {},
987
+ ...reset || at === last?.at && last.compacted ? { compacted: true } : {}
988
+ };
989
+ if (reset)
990
+ pending = undefined;
991
+ if (!last || at > last.at && sample.tokens !== last.tokens) {
992
+ next = [...samples, sample].slice(-96);
993
+ } else if (sample.at !== last.at || sample.tokens !== last.tokens || sample.held !== last.held || sample.compacted !== last.compacted) {
994
+ next = [...samples.slice(0, -1), sample];
995
+ }
996
+ }
997
+ }
998
+ return {
999
+ sessionId,
1000
+ model,
1001
+ capacity,
1002
+ samples: next,
1003
+ ...completed === undefined ? {} : { lastCompleted: completed },
1004
+ ...pending === undefined ? {} : { pendingCompleted: pending }
1005
+ };
1006
+ }
1007
+
1008
+ class ContextTraceStore {
1009
+ traces = new Map;
1010
+ update(row2) {
1011
+ if (!row2)
1012
+ return updateContextTrace(undefined, undefined);
1013
+ const id = row2.node.sessionId;
1014
+ const trace = updateContextTrace(this.traces.get(id), row2);
1015
+ this.traces.delete(id);
1016
+ this.traces.set(id, trace);
1017
+ if (this.traces.size > 128) {
1018
+ const oldest = this.traces.keys().next().value;
1019
+ if (oldest !== undefined)
1020
+ this.traces.delete(oldest);
1021
+ }
1022
+ return trace;
1023
+ }
1024
+ clear() {
1025
+ this.traces.clear();
813
1026
  }
814
1027
  }
815
- function abortable(promise, signal) {
816
- return new Promise((resolve, reject) => {
817
- const abort = () => reject(new Error("Snapshot request cancelled"));
818
- if (signal.aborted) {
819
- abort();
820
- return;
1028
+ function contextChart(samples, capacity, trigger, width, now) {
1029
+ if (capacity === undefined || !Number.isFinite(capacity) || capacity <= 0 || width < 4)
1030
+ return [];
1031
+ const height = 8;
1032
+ const gutter = width >= 16 ? 4 : 0;
1033
+ const size = Math.max(1, Math.min(96, width - gutter - 2));
1034
+ const last = samples.at(-1);
1035
+ const paused = now !== undefined && last?.tokens !== undefined && now - last.at > 2500;
1036
+ const values = samples.slice(-size).map((sample, index, visible) => paused && index === visible.length - 1 ? { ...sample, held: true } : sample);
1037
+ const offset = size - values.length;
1038
+ const thresholdRow = trigger !== undefined && Number.isFinite(trigger) && trigger >= 0 && trigger <= capacity ? Math.round((1 - trigger / capacity) * (height - 1)) : -1;
1039
+ const blocks = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
1040
+ const lines = Array.from({ length: height }, (_, row2) => {
1041
+ const threshold = row2 === thresholdRow;
1042
+ const axis = gutter ? (row2 === 0 ? "100%" : row2 === height - 1 ? "0%" : "").padStart(gutter) : "";
1043
+ const plot = Array.from({ length: size }, (_2, col) => {
1044
+ const sample = values[col - offset];
1045
+ const value = sample?.tokens;
1046
+ const fill = value === undefined ? 0 : Math.max(0, Math.min(8, Math.ceil((Math.min(value / capacity, 1) * height - (height - row2 - 1)) * 8)));
1047
+ const tone = sample?.held ? "held" : "value";
1048
+ if (fill > 0)
1049
+ return { text: blocks[fill] ?? " ", tone };
1050
+ if (threshold)
1051
+ return { text: "\u2504", tone: "threshold" };
1052
+ if (value === 0 && row2 === height - 1)
1053
+ return { text: "\u2581", tone };
1054
+ return { text: " ", tone: "axis" };
1055
+ });
1056
+ const line = `${axis}\u2502${plot.map((cell) => cell.text).join("")}\u2502`;
1057
+ const segments = [
1058
+ { text: `${axis}\u2502`, held: false, tone: "axis" }
1059
+ ];
1060
+ for (const cell of plot) {
1061
+ const { text: text2, tone } = cell;
1062
+ const held = tone === "held";
1063
+ const previous = segments.at(-1);
1064
+ if (previous?.tone === tone)
1065
+ segments[segments.length - 1] = {
1066
+ text: previous.text + text2,
1067
+ held,
1068
+ tone
1069
+ };
1070
+ else
1071
+ segments.push({ text: text2, held, tone });
821
1072
  }
822
- signal.addEventListener("abort", abort, { once: true });
823
- promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
1073
+ segments.push({ text: "\u2502", held: false, tone: "axis" });
1074
+ return { line, threshold, segments };
1075
+ });
1076
+ lines.push({
1077
+ line: `${" ".repeat(gutter)}\u2514${"\u2500".repeat(size)}\u2518`,
1078
+ threshold: false,
1079
+ segments: [
1080
+ {
1081
+ text: `${" ".repeat(gutter)}\u2514${"\u2500".repeat(size)}\u2518`,
1082
+ held: false,
1083
+ tone: "axis"
1084
+ }
1085
+ ]
824
1086
  });
1087
+ return lines;
825
1088
  }
826
1089
 
1090
+ // src/tui/state.ts
1091
+ init_transport();
1092
+
827
1093
  // src/tui/inventory.ts
828
1094
  async function discoverFamily(client, currentId, signal, cached, maxNodes = 1024, previous) {
829
1095
  const sessions = new Map(previous?.sessions);
@@ -1231,6 +1497,7 @@ function sameLocation(a, b) {
1231
1497
  }
1232
1498
 
1233
1499
  // src/tui/sidebar.tsx
1500
+ init_format();
1234
1501
  import { effect as _$effect2 } from "@opentui/solid";
1235
1502
  import { createComponent as _$createComponent2 } from "@opentui/solid";
1236
1503
  import { insert as _$insert2 } from "@opentui/solid";
@@ -1241,121 +1508,8 @@ import { setProp as _$setProp2 } from "@opentui/solid";
1241
1508
  import { createElement as _$createElement2 } from "@opentui/solid";
1242
1509
  import { For as For2, createEffect as createEffect2, createMemo as createMemo2, onCleanup, Show as Show2 } from "solid-js";
1243
1510
 
1244
- // src/tui/format.ts
1245
- function quantity(n) {
1246
- 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);
1247
- }
1248
- var segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
1249
- function cells(value) {
1250
- return [...segmenter.segment(value)].reduce((n, { segment }) => n + graphemeWidth(segment), 0);
1251
- }
1252
- function graphemeWidth(s) {
1253
- const cp = s.codePointAt(0) ?? 0;
1254
- if (/^[\p{Mark}\u200d\ufe0f]+$/u.test(s))
1255
- return 0;
1256
- return /[\p{Extended_Pictographic}\p{Regional_Indicator}\u20e3]/u.test(s) || cp >= 4352 && (cp <= 4447 || cp >= 9001 && cp <= 9002 || cp >= 11904 && cp <= 42191 || cp >= 44032 && cp <= 55203 || cp >= 63744 && cp <= 64255 || cp >= 65040 && cp <= 65135 || cp >= 65281 && cp <= 65376 || cp >= 131072) ? 2 : 1;
1257
- }
1258
- function clip(value, width) {
1259
- const clean = sanitize(value);
1260
- if (cells(clean) <= width)
1261
- return clean;
1262
- let result = "", used = 0;
1263
- for (const { segment } of segmenter.segment(clean)) {
1264
- const size = graphemeWidth(segment);
1265
- if (used + size > Math.max(0, width - 3))
1266
- break;
1267
- result += segment;
1268
- used += size;
1269
- }
1270
- return width < 3 ? ".".repeat(Math.max(0, width)) : result + "...";
1271
- }
1272
- var statuses = {
1273
- running: "RUN",
1274
- idle: "IDLE",
1275
- completed: "DONE",
1276
- failed: "FAIL",
1277
- unknown: "?"
1278
- };
1279
- function rowLines(row2, width) {
1280
- const s = row2.snapshot, m = s?.measurement;
1281
- const prefix = row2.current ? "* " : row2.depth > 5 ? ".../" : " ".repeat(Math.min(row2.depth, 5)) + "|-";
1282
- const percent = row2.utilizationPercent === undefined ? "?" : `${row2.utilizationPercent.toFixed(1)}%`;
1283
- const warning = row2.freshness === "stale" ? " STALE" : row2.pressure === "crossed" ? " !! crossed" : row2.pressure === "near" ? " ! near" : "";
1284
- const suffix = ` ${statuses[row2.node.status]} ${m?.confidence === "approximate" ? "~" : ""}${percent}${warning}`;
1285
- const label = clip(`${prefix}${row2.node.agent ?? row2.node.sessionId}`, Math.max(1, width - cells(suffix)));
1286
- return [
1287
- clip(`${label}${suffix}`, width),
1288
- ...performanceLines(row2, width),
1289
- ...wrap(`${quantity(m?.tokens)}/${quantity(s?.capacityTokens)} input; to ${quantity(row2.triggerDeltaTokens)}`, width),
1290
- ...s && s.compaction.phase !== "idle" ? wrap(`compact: ${s.compaction.phase}`, width) : [],
1291
- ...row2.node.interrupted ? [clip("interrupted", width)] : [],
1292
- ...row2.hidden ? wrap(`+ ${row2.hidden} completed descendants`, width) : []
1293
- ];
1294
- }
1295
- function detailLines(row2, width, expanded = false, ageMs = 0) {
1296
- const s = row2?.snapshot, m = s?.measurement;
1297
- if (!row2)
1298
- return wrap("Loading session family...", width);
1299
- if (!s)
1300
- return [
1301
- ...wrap(`${row2.node.agent ?? row2.node.sessionId} / ${row2.node.model ?? "?"}`, width),
1302
- ...wrap("Guard: not monitored / unavailable", width)
1303
- ];
1304
- const threshold = s.policy.configured;
1305
- const headroom = row2.triggerDeltaTokens;
1306
- const lines = [
1307
- `${s.agent ?? "?"} / ${s.model ?? "?"}`,
1308
- ...performanceLines(row2, width),
1309
- `${m?.confidence === "approximate" ? "~" : ""}${quantity(m?.tokens)} / ${quantity(s.capacityTokens)} input`,
1310
- `${row2.utilizationPercent?.toFixed(1) ?? "?"}% ${row2.pressure === "crossed" ? "!! crossed" : row2.pressure === "near" ? "! near" : row2.freshness.toUpperCase()}`,
1311
- `Trigger ${threshold.type === "ratio" ? `${threshold.value * 100}%` : `${threshold.value} ${threshold.type}`} (${s.policy.comparison})`,
1312
- `Resolved trigger ${s.policy.triggerTokens ?? "?"}`,
1313
- `Until trigger ${quantity(headroom)}`,
1314
- `Compact: ${s.compaction.phase}`,
1315
- `${s.compaction.armed ? "armed" : "disarmed"}${s.compaction.blockedReason ? ` / ${s.compaction.blockedReason}` : ""}`,
1316
- m ? `${m.confidence} ${m.scope}` : "measurement unknown",
1317
- m ? `${Math.floor(Math.max(0, ageMs) / 1000)}s ago; ${row2.freshness}` : ""
1318
- ];
1319
- if (expanded)
1320
- 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)}`);
1321
- return lines.filter(Boolean).flatMap((line) => wrap(line, width));
1322
- }
1323
- function sanitize(value) {
1324
- return value.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "").replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\x00-\x1f\x7f-\x9f]/g, "");
1325
- }
1326
- function wrap(value, width) {
1327
- const result = [];
1328
- let part = "";
1329
- for (const word of sanitize(value).split(" ")) {
1330
- if (part && cells(part + " " + word) > width) {
1331
- result.push(part);
1332
- part = "";
1333
- }
1334
- for (const { segment } of segmenter.segment((part ? " " : "") + word)) {
1335
- if (part && cells(part + segment) > width) {
1336
- result.push(part);
1337
- part = "";
1338
- }
1339
- part += cells(segment) <= width ? segment : "?";
1340
- }
1341
- }
1342
- if (part)
1343
- result.push(part);
1344
- return result;
1345
- }
1346
- function performanceLines(row2, width) {
1347
- const p = row2.snapshot?.performance;
1348
- if (!p)
1349
- return [];
1350
- const value = (n) => n === undefined ? "?" : n.toFixed(1);
1351
- return [
1352
- ...wrap(`TPS ${p.status === "waiting" ? "waiting" : `${p.status === "streaming" ? "~" : ""}${value(p.liveTps)}`} \xB7 ${p.status}${p.partial ? " \xB7 partial" : ""}`, width),
1353
- ...wrap(`Avg model ${value(p.averageModelTps)} \xB7 Avg session ${value(p.averageSessionTps)}`, width),
1354
- ...wrap(`TTFT ${p.ttftMs === undefined ? "?" : `~${(p.ttftMs / 1000).toFixed(2)}s`}${p.latestRequestTps === undefined ? "" : ` \xB7 Last ${value(p.latestRequestTps)} t/s`}`, width)
1355
- ];
1356
- }
1357
-
1358
1511
  // src/tui/compact.tsx
1512
+ init_format();
1359
1513
  import { createTextNode as _$createTextNode } from "@opentui/solid";
1360
1514
  import { insertNode as _$insertNode } from "@opentui/solid";
1361
1515
  import { setProp as _$setProp } from "@opentui/solid";
@@ -1367,6 +1521,7 @@ import { createComponent as _$createComponent } from "@opentui/solid";
1367
1521
  import { For, Index, Show, createEffect, createMemo, createSignal as createSignal2 } from "solid-js";
1368
1522
 
1369
1523
  // src/tui/compactformat.ts
1524
+ init_format();
1370
1525
  function tokens(value) {
1371
1526
  if (value === undefined || !Number.isFinite(value))
1372
1527
  return "?";
@@ -1418,7 +1573,7 @@ function mainSections(row2, width, age, samples, chartCapacity) {
1418
1573
  ...samples?.some((sample) => sample.held) || m && age > 2500 ? [
1419
1574
  {
1420
1575
  tone: "measurement",
1421
- lines: wrap("\u2508 held \xB7 last known context", width)
1576
+ lines: wrap("muted held \xB7 last known context", width)
1422
1577
  }
1423
1578
  ] : [],
1424
1579
  {
@@ -1668,7 +1823,7 @@ function CompactSidebar(props) {
1668
1823
  var _el$14 = _$createElement("span");
1669
1824
  _$insert(_el$14, () => part.text);
1670
1825
  _$effect((_$p) => _$setProp(_el$14, "style", {
1671
- fg: part.held ? colors().muted : section2().tone === "threshold" ? colors().feedback.warning.base : pressureColor(current())
1826
+ fg: part.tone === "axis" || part.tone === "held" ? colors().muted : part.tone === "threshold" ? colors().feedback.warning.base : current()?.freshness === "fresh" ? colors().base : colors().muted
1672
1827
  }, _$p));
1673
1828
  return _el$14;
1674
1829
  })()
@@ -1910,7 +2065,7 @@ function GuardView(props) {
1910
2065
  var _el$10 = _$createElement2("span");
1911
2066
  _$insert2(_el$10, () => part.text);
1912
2067
  _$effect2((_$p) => _$setProp2(_el$10, "style", {
1913
- fg: part.held ? props.context.theme.text.muted : item.threshold ? props.context.theme.text.feedback.warning.base : props.context.theme.text.base
2068
+ fg: part.tone === "axis" || part.tone === "held" ? props.context.theme.text.muted : part.tone === "threshold" ? props.context.theme.text.feedback.warning.base : current()?.freshness === "fresh" ? props.context.theme.text.base : props.context.theme.text.muted
1914
2069
  }, _$p));
1915
2070
  return _el$10;
1916
2071
  })()
@@ -1923,7 +2078,7 @@ function GuardView(props) {
1923
2078
  }), _el$6);
1924
2079
  _$insert2(_el$, _$createComponent2(For2, {
1925
2080
  get each() {
1926
- return wrap("Recent context samples \u2192 now \xB7 \u2504 trigger \xB7 \u2508 held", props.width);
2081
+ return wrap("Recent context samples \u2192 now \xB7 \u2504 trigger \xB7 muted held", props.width);
1927
2082
  },
1928
2083
  children: (line) => (() => {
1929
2084
  var _el$11 = _$createElement2("text");
@@ -2035,6 +2190,8 @@ import { createElement as _$createElement4 } from "@opentui/solid";
2035
2190
  import { createSignal as createSignal4, createMemo as createMemo3, createEffect as createEffect4, onCleanup as onCleanup3, Show as Show3, For as For4 } from "solid-js";
2036
2191
 
2037
2192
  // src/tui/charts.tsx
2193
+ init_chartformat();
2194
+ init_format();
2038
2195
  import { effect as _$effect3 } from "@opentui/solid";
2039
2196
  import { insertNode as _$insertNode3 } from "@opentui/solid";
2040
2197
  import { insert as _$insert3 } from "@opentui/solid";
@@ -2042,113 +2199,6 @@ import { createComponent as _$createComponent3 } from "@opentui/solid";
2042
2199
  import { setProp as _$setProp3 } from "@opentui/solid";
2043
2200
  import { createElement as _$createElement3 } from "@opentui/solid";
2044
2201
  import { createEffect as createEffect3, createSignal as createSignal3, onCleanup as onCleanup2, For as For3 } from "solid-js";
2045
-
2046
- // src/tui/chartformat.ts
2047
- function columns2(points, from, to, width, gaps = []) {
2048
- const size = Math.max(1, Math.min(120, Math.floor(width))), values = Array.from({ length: size });
2049
- const column = (time) => Math.max(0, Math.min(size - 1, Math.floor((time - from) / Math.max(1, to - from) * (size - 1))));
2050
- let min = Infinity, max = -Infinity;
2051
- for (const point of points) {
2052
- if (point.time < from || point.time > to || point.value === undefined || !Number.isFinite(point.value) || point.value < 0)
2053
- continue;
2054
- min = Math.min(min, point.value);
2055
- max = Math.max(max, point.value);
2056
- const i = column(point.time);
2057
- values[i] = Math.max(values[i] ?? -Infinity, point.value);
2058
- }
2059
- for (const time of gaps)
2060
- if (time >= from && time <= to)
2061
- values[column(time)] = undefined;
2062
- return { values, column, min, max };
2063
- }
2064
- function sparkline(points, from, to, width, gaps = []) {
2065
- const { values, column, min, max } = columns2(points, from, to, width, gaps);
2066
- const bars = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
2067
- const chars = values.map((v) => v === undefined ? " " : bars[Math.min(7, Math.floor(v / Math.max(1, max) * 7))] ?? "\u2581");
2068
- for (const time of gaps)
2069
- if (time >= from && time <= to)
2070
- chars[column(time)] = "\u2506";
2071
- return { line: chars.join(""), ...min === Infinity ? {} : { min, max } };
2072
- }
2073
- var chartMetrics = [
2074
- { label: "Live TPS ~", unit: "t/s", key: "liveTps", source: "points" },
2075
- { label: "Avg model", unit: "t/s", key: "averageModelTps", source: "points" },
2076
- {
2077
- label: "Avg session",
2078
- unit: "t/s",
2079
- key: "averageSessionTps",
2080
- source: "points"
2081
- },
2082
- { label: "TTFT ~", unit: "s", key: "ttftMs", source: "requests" },
2083
- { label: "Request throughput", unit: "t/s", key: "tps", source: "requests" },
2084
- {
2085
- label: "Cumulative output",
2086
- unit: "tokens",
2087
- key: "sessionOutputTokens",
2088
- source: "points"
2089
- }
2090
- ];
2091
- function metricPlot(points, from, to, width, gaps = []) {
2092
- const label = (value) => value >= 1e6 ? `${(value / 1e6).toFixed(1)}M` : value >= 1000 ? `${(value / 1000).toFixed(1)}k` : value.toFixed(1);
2093
- const peak = Math.max(0, ...points.filter((p) => p.time >= from && p.time <= to && Number.isFinite(p.value)).map((p) => p.value ?? 0));
2094
- const scale = Math.max(1, peak);
2095
- const gutter = width >= 20 ? Math.max(label(scale).length, 3) : 0;
2096
- const { values, column } = columns2(points, from, to, Math.max(1, width - gutter - 2), gaps);
2097
- const gapColumns = new Set(gaps.filter((time) => time >= from && time <= to).map(column));
2098
- const height = 6;
2099
- const blocks = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
2100
- const lines = Array.from({ length: height }, (_, row2) => {
2101
- const axis = gutter ? (row2 === 0 ? label(scale) : row2 === height - 1 ? "0.0" : "").padStart(gutter) : "";
2102
- return `${axis}\u2502${values.map((value, i) => {
2103
- if (gapColumns.has(i))
2104
- return "\u2506";
2105
- if (value === undefined)
2106
- return " ";
2107
- const fill = Math.max(0, Math.min(8, Math.ceil((value / scale * height - (height - row2 - 1)) * 8)));
2108
- return value === 0 && row2 === height - 1 ? "\u2581" : blocks[fill];
2109
- }).join("")}\u2502`;
2110
- });
2111
- lines.push(`${" ".repeat(gutter)}\u2514${"\u2500".repeat(values.length)}\u2518`);
2112
- const start = new Date(from).toISOString().slice(11, 16), end = new Date(to).toISOString().slice(11, 16);
2113
- const axisWidth = values.length + 2;
2114
- if (axisWidth >= 11)
2115
- lines.push(`${" ".repeat(gutter)}${start}${" ".repeat(axisWidth - 10)}${end}`);
2116
- return lines;
2117
- }
2118
- function historyChartLines(result, width, from, to, metricIndex = 0) {
2119
- if (!result.enabled)
2120
- return wrap("History recording is disabled on this server.", width);
2121
- const series = result.data.series[0];
2122
- if (!series)
2123
- return wrap("No retained measurements in this window.", width);
2124
- const gaps = result.data.gaps.map((g) => g.time);
2125
- const observations = (key) => series.points.map((p) => ({
2126
- time: p.time,
2127
- ...p[key] === undefined ? {} : { value: p[key] }
2128
- }));
2129
- const requests = (key) => series.requests.map((p) => ({
2130
- time: p.time,
2131
- ...p[key] === undefined ? {} : { value: key === "ttftMs" ? p[key] / 1000 : p[key] }
2132
- }));
2133
- const metric2 = chartMetrics[metricIndex] ?? chartMetrics[0];
2134
- const points = metric2.source === "points" ? observations(metric2.key) : requests(metric2.key);
2135
- const plotted = sparkline(points, from, to, width - 2, gaps);
2136
- return [
2137
- ...wrap(`\u2039 ${metric2.label} \u203A \xB7 ${metricIndex + 1}/${chartMetrics.length}`, width),
2138
- ...wrap(plotted.min === undefined ? "No measurements for this metric." : `${plotted.min.toFixed(1)}\u2013${plotted.max?.toFixed(1)} ${metric2.unit} \xB7 observed range`, width),
2139
- "",
2140
- ...metricPlot(points, from, to, width, gaps),
2141
- "",
2142
- ...wrap("UTC time \u2192 \xB7 peaks per column", width),
2143
- ...wrap("blank = no sample \xB7 \u2506 = gap", width),
2144
- ...wrap(`${new Date(from).toISOString()} \u2192 ${new Date(to).toISOString()}`, width),
2145
- ...series.points.some((p) => p.partial) ? wrap("Partial timing coverage; averages include only matched model durations.", width) : [],
2146
- ...result.truncated ? wrap("Downsampled/bounded history; some older requests or gap markers may be omitted.", width) : [],
2147
- ...result.metadata.malformedRecords ? wrap(`${result.metadata.malformedRecords} malformed/partial records skipped.`, width) : []
2148
- ];
2149
- }
2150
-
2151
- // src/tui/charts.tsx
2152
2202
  function HistoryCharts(props) {
2153
2203
  const [result, setResult] = createSignal3();
2154
2204
  const [status, setStatus] = createSignal3("Loading retained history...");
@@ -2243,6 +2293,8 @@ function HistoryCharts(props) {
2243
2293
  }
2244
2294
 
2245
2295
  // src/tui/panel.tsx
2296
+ init_chartformat();
2297
+ init_format();
2246
2298
  function GuardPanel(props) {
2247
2299
  const [showCharts, setShowCharts] = createSignal4(false);
2248
2300
  const [metricIndex, setMetricIndex] = createSignal4(0);