@cesarus777/opencode-cgp 0.2.3 → 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/CHANGELOG.md +14 -0
- package/README.md +36 -8
- package/dist/cli.js +3363 -1028
- package/dist/core.js +311 -102
- package/dist/index.js +873 -836
- package/dist/rpc.js +275 -246
- package/dist/tui.js +1004 -820
- package/dist/types/core.d.ts +1 -0
- package/dist/types/dashboard/command.d.ts +5 -0
- package/dist/types/dashboard/connection.d.ts +36 -0
- package/dist/types/dashboard/controller.d.ts +57 -0
- package/dist/types/dashboard/inventory.d.ts +17 -0
- package/dist/types/dashboard/port.d.ts +41 -0
- package/dist/types/dashboard/terminal.d.ts +36 -0
- package/dist/types/dashboard/terminalview.d.ts +15 -0
- package/dist/types/dashboard/view.d.ts +83 -0
- package/dist/types/modelanalytics.d.ts +60 -0
- package/dist/types/modelcli.d.ts +1 -0
- package/dist/types/tui/compactformat.d.ts +3 -2
- package/dist/types/tui/contextchart.d.ts +20 -3
- package/dist/types/tui/state.d.ts +4 -2
- package/package.json +5 -2
package/dist/tui.js
CHANGED
|
@@ -1,174 +1,33 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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) {
|
|
@@ -698,112 +712,490 @@ function abortable(promise, signal) {
|
|
|
698
712
|
promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
699
713
|
});
|
|
700
714
|
}
|
|
715
|
+
var init_transport = __esm(() => {
|
|
716
|
+
init_rpc();
|
|
717
|
+
});
|
|
701
718
|
|
|
702
|
-
// src/tui/
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
}
|
|
724
|
-
try {
|
|
725
|
-
current = await get(current.parentID);
|
|
726
|
-
} catch {
|
|
727
|
-
if (signal.aborted)
|
|
728
|
-
throw signal.reason;
|
|
729
|
-
damaged = true;
|
|
730
|
-
break;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
const queue = previous ? [...previous.pending] : [{ id: rootId, depth: 0, cursors: [] }];
|
|
735
|
-
const scanned = new Set(previous?.scanned);
|
|
736
|
-
while (queue.length && pages < 100) {
|
|
737
|
-
const next = queue.shift();
|
|
738
|
-
if (!next)
|
|
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))
|
|
739
740
|
break;
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
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 = "";
|
|
743
800
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
const response = await client.session.list({
|
|
749
|
-
parentID: next.id,
|
|
750
|
-
limit: 100,
|
|
751
|
-
order: "desc",
|
|
752
|
-
...next.cursor ? { cursor: next.cursor } : {}
|
|
753
|
-
}, { signal });
|
|
754
|
-
let capped = false;
|
|
755
|
-
for (const child of response.data) {
|
|
756
|
-
if (child.parentID !== next.id || child.id === next.id) {
|
|
757
|
-
damaged = true;
|
|
758
|
-
continue;
|
|
759
|
-
}
|
|
760
|
-
if (!sessions.has(child.id) && sessions.size >= maxNodes) {
|
|
761
|
-
capped = true;
|
|
762
|
-
break;
|
|
763
|
-
}
|
|
764
|
-
sessions.set(child.id, child);
|
|
765
|
-
if (!scanned.has(child.id) && !queue.some((branch) => branch.id === child.id)) {
|
|
766
|
-
if (next.depth < 64)
|
|
767
|
-
queue.push({ id: child.id, depth: next.depth + 1, cursors: [] });
|
|
768
|
-
else
|
|
769
|
-
damaged = true;
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
if (capped) {
|
|
773
|
-
queue.unshift(next);
|
|
774
|
-
break;
|
|
801
|
+
for (const { segment } of segmenter.segment((part ? " " : "") + word)) {
|
|
802
|
+
if (part && cells(part + segment) > width) {
|
|
803
|
+
result.push(part);
|
|
804
|
+
part = "";
|
|
775
805
|
}
|
|
776
|
-
|
|
777
|
-
if (cursor) {
|
|
778
|
-
if (next.cursors.includes(cursor) || cursor === next.cursor)
|
|
779
|
-
damaged = true;
|
|
780
|
-
else
|
|
781
|
-
queue.unshift({
|
|
782
|
-
...next,
|
|
783
|
-
cursor,
|
|
784
|
-
cursors: [...next.cursors, cursor]
|
|
785
|
-
});
|
|
786
|
-
} else
|
|
787
|
-
scanned.add(next.id);
|
|
788
|
-
} catch {
|
|
789
|
-
if (signal.aborted)
|
|
790
|
-
throw signal.reason;
|
|
791
|
-
damaged = true;
|
|
806
|
+
part += cells(segment) <= width ? segment : "?";
|
|
792
807
|
}
|
|
793
808
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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();
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
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 });
|
|
1072
|
+
}
|
|
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
|
+
]
|
|
1086
|
+
});
|
|
1087
|
+
return lines;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
// src/tui/state.ts
|
|
1091
|
+
init_transport();
|
|
1092
|
+
|
|
1093
|
+
// src/tui/inventory.ts
|
|
1094
|
+
async function discoverFamily(client, currentId, signal, cached, maxNodes = 1024, previous) {
|
|
1095
|
+
const sessions = new Map(previous?.sessions);
|
|
1096
|
+
let damaged = previous?.damaged ?? false, pages = 0, rootId = previous?.rootId ?? currentId;
|
|
1097
|
+
const get = async (id) => cached(id) ?? client.session.get({ sessionID: id }, { signal });
|
|
1098
|
+
if (!previous) {
|
|
1099
|
+
let current = await get(currentId);
|
|
1100
|
+
for (let depth = 0;depth <= 64; depth++) {
|
|
1101
|
+
if (signal.aborted)
|
|
1102
|
+
throw signal.reason;
|
|
1103
|
+
if (sessions.has(current.id) || sessions.size >= maxNodes) {
|
|
1104
|
+
damaged = true;
|
|
1105
|
+
break;
|
|
1106
|
+
}
|
|
1107
|
+
sessions.set(current.id, current);
|
|
1108
|
+
rootId = current.id;
|
|
1109
|
+
if (!current.parentID)
|
|
1110
|
+
break;
|
|
1111
|
+
if (depth === 64) {
|
|
1112
|
+
damaged = true;
|
|
1113
|
+
break;
|
|
1114
|
+
}
|
|
1115
|
+
try {
|
|
1116
|
+
current = await get(current.parentID);
|
|
1117
|
+
} catch {
|
|
1118
|
+
if (signal.aborted)
|
|
1119
|
+
throw signal.reason;
|
|
1120
|
+
damaged = true;
|
|
1121
|
+
break;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
const queue = previous ? [...previous.pending] : [{ id: rootId, depth: 0, cursors: [] }];
|
|
1126
|
+
const scanned = new Set(previous?.scanned);
|
|
1127
|
+
while (queue.length && pages < 100) {
|
|
1128
|
+
const next = queue.shift();
|
|
1129
|
+
if (!next)
|
|
1130
|
+
break;
|
|
1131
|
+
if (!next.cursor && scanned.has(next.id)) {
|
|
1132
|
+
damaged = true;
|
|
1133
|
+
continue;
|
|
1134
|
+
}
|
|
1135
|
+
if (signal.aborted)
|
|
1136
|
+
throw signal.reason;
|
|
1137
|
+
try {
|
|
1138
|
+
pages++;
|
|
1139
|
+
const response = await client.session.list({
|
|
1140
|
+
parentID: next.id,
|
|
1141
|
+
limit: 100,
|
|
1142
|
+
order: "desc",
|
|
1143
|
+
...next.cursor ? { cursor: next.cursor } : {}
|
|
1144
|
+
}, { signal });
|
|
1145
|
+
let capped = false;
|
|
1146
|
+
for (const child of response.data) {
|
|
1147
|
+
if (child.parentID !== next.id || child.id === next.id) {
|
|
1148
|
+
damaged = true;
|
|
1149
|
+
continue;
|
|
1150
|
+
}
|
|
1151
|
+
if (!sessions.has(child.id) && sessions.size >= maxNodes) {
|
|
1152
|
+
capped = true;
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1155
|
+
sessions.set(child.id, child);
|
|
1156
|
+
if (!scanned.has(child.id) && !queue.some((branch) => branch.id === child.id)) {
|
|
1157
|
+
if (next.depth < 64)
|
|
1158
|
+
queue.push({ id: child.id, depth: next.depth + 1, cursors: [] });
|
|
1159
|
+
else
|
|
1160
|
+
damaged = true;
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
if (capped) {
|
|
1164
|
+
queue.unshift(next);
|
|
1165
|
+
break;
|
|
1166
|
+
}
|
|
1167
|
+
const cursor = response.cursor?.next;
|
|
1168
|
+
if (cursor) {
|
|
1169
|
+
if (next.cursors.includes(cursor) || cursor === next.cursor)
|
|
1170
|
+
damaged = true;
|
|
1171
|
+
else
|
|
1172
|
+
queue.unshift({
|
|
1173
|
+
...next,
|
|
1174
|
+
cursor,
|
|
1175
|
+
cursors: [...next.cursors, cursor]
|
|
1176
|
+
});
|
|
1177
|
+
} else
|
|
1178
|
+
scanned.add(next.id);
|
|
1179
|
+
} catch {
|
|
1180
|
+
if (signal.aborted)
|
|
1181
|
+
throw signal.reason;
|
|
1182
|
+
damaged = true;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
return {
|
|
1186
|
+
sessions,
|
|
1187
|
+
complete: !damaged && !queue.length,
|
|
1188
|
+
rootId,
|
|
1189
|
+
pages: (previous?.pages ?? 0) + pages,
|
|
1190
|
+
pending: queue,
|
|
1191
|
+
scanned,
|
|
801
1192
|
damaged
|
|
802
1193
|
};
|
|
803
1194
|
}
|
|
804
1195
|
|
|
805
1196
|
// src/tui/state.ts
|
|
806
1197
|
function createGuardState(context) {
|
|
1198
|
+
const contextTraces = new ContextTraceStore;
|
|
807
1199
|
const [version, setVersion] = createSignal(0);
|
|
808
1200
|
const notify = () => {
|
|
809
1201
|
setVersion((n) => n + 1);
|
|
@@ -986,301 +1378,138 @@ function createGuardState(context) {
|
|
|
986
1378
|
},
|
|
987
1379
|
release() {
|
|
988
1380
|
consumers.delete(token);
|
|
989
|
-
if (consumers.size)
|
|
990
|
-
select();
|
|
991
|
-
else
|
|
992
|
-
stop();
|
|
993
|
-
}
|
|
994
|
-
};
|
|
995
|
-
}
|
|
996
|
-
function stop() {
|
|
997
|
-
controller?.abort();
|
|
998
|
-
scanGeneration++;
|
|
999
|
-
scanning = false;
|
|
1000
|
-
for (const c of clients.values())
|
|
1001
|
-
c.stop();
|
|
1002
|
-
clients.clear();
|
|
1003
|
-
clearTimeout(expiryTimer);
|
|
1004
|
-
clearInterval(ageTimer);
|
|
1005
|
-
clearInterval(scanTimer);
|
|
1006
|
-
clearTimeout(eventTimer);
|
|
1007
|
-
unlisten?.();
|
|
1008
|
-
unlisten = undefined;
|
|
1009
|
-
inventory = undefined;
|
|
1010
|
-
evidence.clear();
|
|
1011
|
-
currentId = "";
|
|
1012
|
-
}
|
|
1013
|
-
function rows(stableOrder = [], allDescendants = false) {
|
|
1014
|
-
version();
|
|
1015
|
-
const snapshots = new Map([...clients.values()].flatMap((c2) => [...c2.rows]));
|
|
1016
|
-
const nodes = [...inventory?.sessions.values() ?? []].map((original) => {
|
|
1017
|
-
const s = context.data.session.get(original.id) ?? original;
|
|
1018
|
-
const observed = evidence.get(s.id) ?? {};
|
|
1019
|
-
const metadataAt = s.time.idle ?? 0;
|
|
1020
|
-
const e = s.outcome && metadataAt >= (observed.terminalAt ?? 0) ? { ...observed, outcome: s.outcome, terminalAt: metadataAt } : observed;
|
|
1021
|
-
return {
|
|
1022
|
-
sessionId: s.id,
|
|
1023
|
-
...s.parentID ? { parentId: s.parentID } : {},
|
|
1024
|
-
...s.agent ? { agent: s.agent } : {},
|
|
1025
|
-
...s.model ? { model: `${s.model.providerID}/${s.model.id}` } : {},
|
|
1026
|
-
...e.outcome === "interrupted" ? { interrupted: true } : {},
|
|
1027
|
-
status: executionStatus(true, context.data.session.status(s.id) === "running", e)
|
|
1028
|
-
};
|
|
1029
|
-
});
|
|
1030
|
-
const c = [...clients.values()].find((c2) => c2.rows.has(currentId)) ?? clients.values().next().value;
|
|
1031
|
-
return familyRows(nodes, snapshots, currentId, c?.now() ?? Date.now(), c?.health?.staleMs ?? 300000, allDescendants ? new Set(nodes.map((node) => node.sessionId)) : expanded, maxNodes, (id) => {
|
|
1032
|
-
const session = inventory?.sessions.get(id);
|
|
1033
|
-
const client = session ? clients.get(locationKey(session.location)) : undefined;
|
|
1034
|
-
return {
|
|
1035
|
-
now: client?.now() ?? Date.now(),
|
|
1036
|
-
staleMs: client?.health?.staleMs ?? 300000
|
|
1037
|
-
};
|
|
1038
|
-
}, stableOrder);
|
|
1039
|
-
}
|
|
1040
|
-
return {
|
|
1041
|
-
version,
|
|
1042
|
-
acquire,
|
|
1043
|
-
async history(id, from, to, signal) {
|
|
1044
|
-
const info = inventory?.sessions.get(id);
|
|
1045
|
-
if (!info)
|
|
1046
|
-
throw new Error("Session location unavailable");
|
|
1047
|
-
const result = await context.client.rpc(historyRpc).read({ schemaVersion: 1, sessionId: id, from, to, maxPoints: 240 }, { location: info.location, signal });
|
|
1048
|
-
if (!isHistoryResult(result))
|
|
1049
|
-
throw new Error("Incompatible history service");
|
|
1050
|
-
return result;
|
|
1051
|
-
},
|
|
1052
|
-
rows,
|
|
1053
|
-
dispose: stop,
|
|
1054
|
-
age(id) {
|
|
1055
|
-
version();
|
|
1056
|
-
const c = [...clients.values()].find((c2) => c2.rows.has(id));
|
|
1057
|
-
const m = c?.rows.get(id)?.measurement;
|
|
1058
|
-
return c && m ? c.now() - m.at : 0;
|
|
1059
|
-
},
|
|
1060
|
-
health() {
|
|
1061
|
-
version();
|
|
1062
|
-
return [...clients.values()].find((c) => c.rows.has(currentId))?.health ?? clients.values().next().value?.health;
|
|
1063
|
-
},
|
|
1064
|
-
connection() {
|
|
1065
|
-
version();
|
|
1066
|
-
return clients.size ? [...clients.values()].map((c) => c.connection).find((c) => c !== "live") ?? "live" : scanFailed ? "unavailable" : "loading";
|
|
1067
|
-
},
|
|
1068
|
-
complete() {
|
|
1069
|
-
version();
|
|
1070
|
-
return inventory?.complete ?? false;
|
|
1071
|
-
},
|
|
1072
|
-
refresh() {
|
|
1073
|
-
scan();
|
|
1074
|
-
for (const c of clients.values())
|
|
1075
|
-
c.refresh();
|
|
1076
|
-
},
|
|
1077
|
-
loadMore() {
|
|
1078
|
-
maxNodes = Math.min(2048, maxNodes + 1024);
|
|
1079
|
-
scan(true);
|
|
1080
|
-
},
|
|
1081
|
-
expand(id) {
|
|
1082
|
-
if (expanded.has(id))
|
|
1083
|
-
expanded.delete(id);
|
|
1084
|
-
else if (expanded.size < 1024)
|
|
1085
|
-
expanded.add(id);
|
|
1086
|
-
savePreferences((draft) => {
|
|
1087
|
-
draft.expanded = [...expanded];
|
|
1088
|
-
}).catch(() => {
|
|
1089
|
-
});
|
|
1090
|
-
notify();
|
|
1091
|
-
}
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1094
|
-
function locationKey(location) {
|
|
1095
|
-
return JSON.stringify([location.directory, location.workspaceID ?? null]);
|
|
1096
|
-
}
|
|
1097
|
-
function sameLocation(a, b) {
|
|
1098
|
-
if (a.workspaceID && b.workspaceID)
|
|
1099
|
-
return a.workspaceID === b.workspaceID;
|
|
1100
|
-
return a.directory === b.directory;
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
// src/tui/sidebar.tsx
|
|
1104
|
-
import { effect as _$effect2 } from "@opentui/solid";
|
|
1105
|
-
import { createComponent as _$createComponent2 } from "@opentui/solid";
|
|
1106
|
-
import { insert as _$insert2 } from "@opentui/solid";
|
|
1107
|
-
import { createTextNode as _$createTextNode2 } from "@opentui/solid";
|
|
1108
|
-
import { insertNode as _$insertNode2 } from "@opentui/solid";
|
|
1109
|
-
import { memo as _$memo2 } from "@opentui/solid";
|
|
1110
|
-
import { setProp as _$setProp2 } from "@opentui/solid";
|
|
1111
|
-
import { createElement as _$createElement2 } from "@opentui/solid";
|
|
1112
|
-
import { For as For2, createEffect as createEffect2, createMemo as createMemo2, onCleanup, Show as Show2 } from "solid-js";
|
|
1113
|
-
|
|
1114
|
-
// src/tui/format.ts
|
|
1115
|
-
function quantity(n) {
|
|
1116
|
-
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);
|
|
1117
|
-
}
|
|
1118
|
-
var segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
1119
|
-
function cells(value) {
|
|
1120
|
-
return [...segmenter.segment(value)].reduce((n, { segment }) => n + graphemeWidth(segment), 0);
|
|
1121
|
-
}
|
|
1122
|
-
function graphemeWidth(s) {
|
|
1123
|
-
const cp = s.codePointAt(0) ?? 0;
|
|
1124
|
-
if (/^[\p{Mark}\u200d\ufe0f]+$/u.test(s))
|
|
1125
|
-
return 0;
|
|
1126
|
-
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;
|
|
1127
|
-
}
|
|
1128
|
-
function clip(value, width) {
|
|
1129
|
-
const clean = sanitize(value);
|
|
1130
|
-
if (cells(clean) <= width)
|
|
1131
|
-
return clean;
|
|
1132
|
-
let result = "", used = 0;
|
|
1133
|
-
for (const { segment } of segmenter.segment(clean)) {
|
|
1134
|
-
const size = graphemeWidth(segment);
|
|
1135
|
-
if (used + size > Math.max(0, width - 3))
|
|
1136
|
-
break;
|
|
1137
|
-
result += segment;
|
|
1138
|
-
used += size;
|
|
1139
|
-
}
|
|
1140
|
-
return width < 3 ? ".".repeat(Math.max(0, width)) : result + "...";
|
|
1141
|
-
}
|
|
1142
|
-
var statuses = {
|
|
1143
|
-
running: "RUN",
|
|
1144
|
-
idle: "IDLE",
|
|
1145
|
-
completed: "DONE",
|
|
1146
|
-
failed: "FAIL",
|
|
1147
|
-
unknown: "?"
|
|
1148
|
-
};
|
|
1149
|
-
function rowLines(row2, width) {
|
|
1150
|
-
const s = row2.snapshot, m = s?.measurement;
|
|
1151
|
-
const prefix = row2.current ? "* " : row2.depth > 5 ? ".../" : " ".repeat(Math.min(row2.depth, 5)) + "|-";
|
|
1152
|
-
const percent = row2.utilizationPercent === undefined ? "?" : `${row2.utilizationPercent.toFixed(1)}%`;
|
|
1153
|
-
const warning = row2.freshness === "stale" ? " STALE" : row2.pressure === "crossed" ? " !! crossed" : row2.pressure === "near" ? " ! near" : "";
|
|
1154
|
-
const suffix = ` ${statuses[row2.node.status]} ${m?.confidence === "approximate" ? "~" : ""}${percent}${warning}`;
|
|
1155
|
-
const label = clip(`${prefix}${row2.node.agent ?? row2.node.sessionId}`, Math.max(1, width - cells(suffix)));
|
|
1156
|
-
return [
|
|
1157
|
-
clip(`${label}${suffix}`, width),
|
|
1158
|
-
...performanceLines(row2, width),
|
|
1159
|
-
...wrap(`${quantity(m?.tokens)}/${quantity(s?.capacityTokens)} input; to ${quantity(row2.triggerDeltaTokens)}`, width),
|
|
1160
|
-
...s && s.compaction.phase !== "idle" ? wrap(`compact: ${s.compaction.phase}`, width) : [],
|
|
1161
|
-
...row2.node.interrupted ? [clip("interrupted", width)] : [],
|
|
1162
|
-
...row2.hidden ? wrap(`+ ${row2.hidden} completed descendants`, width) : []
|
|
1163
|
-
];
|
|
1164
|
-
}
|
|
1165
|
-
function detailLines(row2, width, expanded = false, ageMs = 0) {
|
|
1166
|
-
const s = row2?.snapshot, m = s?.measurement;
|
|
1167
|
-
if (!row2)
|
|
1168
|
-
return wrap("Loading session family...", width);
|
|
1169
|
-
if (!s)
|
|
1170
|
-
return [
|
|
1171
|
-
...wrap(`${row2.node.agent ?? row2.node.sessionId} / ${row2.node.model ?? "?"}`, width),
|
|
1172
|
-
...wrap("Guard: not monitored / unavailable", width)
|
|
1173
|
-
];
|
|
1174
|
-
const threshold = s.policy.configured;
|
|
1175
|
-
const headroom = row2.triggerDeltaTokens;
|
|
1176
|
-
const lines = [
|
|
1177
|
-
`${s.agent ?? "?"} / ${s.model ?? "?"}`,
|
|
1178
|
-
...performanceLines(row2, width),
|
|
1179
|
-
`${m?.confidence === "approximate" ? "~" : ""}${quantity(m?.tokens)} / ${quantity(s.capacityTokens)} input`,
|
|
1180
|
-
`${row2.utilizationPercent?.toFixed(1) ?? "?"}% ${row2.pressure === "crossed" ? "!! crossed" : row2.pressure === "near" ? "! near" : row2.freshness.toUpperCase()}`,
|
|
1181
|
-
`Trigger ${threshold.type === "ratio" ? `${threshold.value * 100}%` : `${threshold.value} ${threshold.type}`} (${s.policy.comparison})`,
|
|
1182
|
-
`Resolved trigger ${s.policy.triggerTokens ?? "?"}`,
|
|
1183
|
-
`Until trigger ${quantity(headroom)}`,
|
|
1184
|
-
`Compact: ${s.compaction.phase}`,
|
|
1185
|
-
`${s.compaction.armed ? "armed" : "disarmed"}${s.compaction.blockedReason ? ` / ${s.compaction.blockedReason}` : ""}`,
|
|
1186
|
-
m ? `${m.confidence} ${m.scope}` : "measurement unknown",
|
|
1187
|
-
m ? `${Math.floor(Math.max(0, ageMs) / 1000)}s ago; ${row2.freshness}` : ""
|
|
1188
|
-
];
|
|
1189
|
-
if (expanded)
|
|
1190
|
-
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)}`);
|
|
1191
|
-
return lines.filter(Boolean).flatMap((line) => wrap(line, width));
|
|
1192
|
-
}
|
|
1193
|
-
function sanitize(value) {
|
|
1194
|
-
return value.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "").replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\x00-\x1f\x7f-\x9f]/g, "");
|
|
1195
|
-
}
|
|
1196
|
-
function wrap(value, width) {
|
|
1197
|
-
const result = [];
|
|
1198
|
-
let part = "";
|
|
1199
|
-
for (const word of sanitize(value).split(" ")) {
|
|
1200
|
-
if (part && cells(part + " " + word) > width) {
|
|
1201
|
-
result.push(part);
|
|
1202
|
-
part = "";
|
|
1203
|
-
}
|
|
1204
|
-
for (const { segment } of segmenter.segment((part ? " " : "") + word)) {
|
|
1205
|
-
if (part && cells(part + segment) > width) {
|
|
1206
|
-
result.push(part);
|
|
1207
|
-
part = "";
|
|
1208
|
-
}
|
|
1209
|
-
part += cells(segment) <= width ? segment : "?";
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
if (part)
|
|
1213
|
-
result.push(part);
|
|
1214
|
-
return result;
|
|
1215
|
-
}
|
|
1216
|
-
function performanceLines(row2, width) {
|
|
1217
|
-
const p = row2.snapshot?.performance;
|
|
1218
|
-
if (!p)
|
|
1219
|
-
return [];
|
|
1220
|
-
const value = (n) => n === undefined ? "?" : n.toFixed(1);
|
|
1221
|
-
return [
|
|
1222
|
-
...wrap(`TPS ${p.status === "waiting" ? "waiting" : `${p.status === "streaming" ? "~" : ""}${value(p.liveTps)}`} \xB7 ${p.status}${p.partial ? " \xB7 partial" : ""}`, width),
|
|
1223
|
-
...wrap(`Avg model ${value(p.averageModelTps)} \xB7 Avg session ${value(p.averageSessionTps)}`, width),
|
|
1224
|
-
...wrap(`TTFT ${p.ttftMs === undefined ? "?" : `~${(p.ttftMs / 1000).toFixed(2)}s`}${p.latestRequestTps === undefined ? "" : ` \xB7 Last ${value(p.latestRequestTps)} t/s`}`, width)
|
|
1225
|
-
];
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
// src/tui/contextchart.ts
|
|
1229
|
-
function updateContextTrace(previous, row2) {
|
|
1230
|
-
const snapshot = row2?.snapshot;
|
|
1231
|
-
const model = snapshot?.model ?? row2?.node.model;
|
|
1232
|
-
const capacity = snapshot?.capacityTokens;
|
|
1233
|
-
const sessionId = row2?.node.sessionId ?? "";
|
|
1234
|
-
const samples = previous?.sessionId === sessionId && previous.model === model && previous.capacity === capacity ? previous.samples : [];
|
|
1235
|
-
const measurement2 = snapshot?.measurement;
|
|
1236
|
-
const valid2 = (row2?.freshness === "fresh" || row2?.freshness === "stale") && measurement2 && Number.isFinite(measurement2.tokens) && measurement2.tokens >= 0;
|
|
1237
|
-
const at = measurement2?.at ?? snapshot?.observedAt;
|
|
1238
|
-
let next = samples;
|
|
1239
|
-
if (at !== undefined && Number.isFinite(at)) {
|
|
1240
|
-
const sample = {
|
|
1241
|
-
at,
|
|
1242
|
-
...valid2 ? { tokens: measurement2.tokens } : {}
|
|
1381
|
+
if (consumers.size)
|
|
1382
|
+
select();
|
|
1383
|
+
else
|
|
1384
|
+
stop();
|
|
1385
|
+
}
|
|
1243
1386
|
};
|
|
1244
|
-
const last = samples.at(-1);
|
|
1245
|
-
if (!last || at > last.at)
|
|
1246
|
-
next = [...samples, sample].slice(-96);
|
|
1247
|
-
else if (at === last.at && sample.tokens !== last.tokens)
|
|
1248
|
-
next = [...samples.slice(0, -1), sample];
|
|
1249
1387
|
}
|
|
1250
|
-
|
|
1388
|
+
function stop() {
|
|
1389
|
+
controller?.abort();
|
|
1390
|
+
scanGeneration++;
|
|
1391
|
+
scanning = false;
|
|
1392
|
+
for (const c of clients.values())
|
|
1393
|
+
c.stop();
|
|
1394
|
+
clients.clear();
|
|
1395
|
+
clearTimeout(expiryTimer);
|
|
1396
|
+
clearInterval(ageTimer);
|
|
1397
|
+
clearInterval(scanTimer);
|
|
1398
|
+
clearTimeout(eventTimer);
|
|
1399
|
+
unlisten?.();
|
|
1400
|
+
unlisten = undefined;
|
|
1401
|
+
inventory = undefined;
|
|
1402
|
+
evidence.clear();
|
|
1403
|
+
currentId = "";
|
|
1404
|
+
}
|
|
1405
|
+
function rows(stableOrder = [], allDescendants = false) {
|
|
1406
|
+
version();
|
|
1407
|
+
const snapshots = new Map([...clients.values()].flatMap((c2) => [...c2.rows]));
|
|
1408
|
+
const nodes = [...inventory?.sessions.values() ?? []].map((original) => {
|
|
1409
|
+
const s = context.data.session.get(original.id) ?? original;
|
|
1410
|
+
const observed = evidence.get(s.id) ?? {};
|
|
1411
|
+
const metadataAt = s.time.idle ?? 0;
|
|
1412
|
+
const e = s.outcome && metadataAt >= (observed.terminalAt ?? 0) ? { ...observed, outcome: s.outcome, terminalAt: metadataAt } : observed;
|
|
1413
|
+
return {
|
|
1414
|
+
sessionId: s.id,
|
|
1415
|
+
...s.parentID ? { parentId: s.parentID } : {},
|
|
1416
|
+
...s.agent ? { agent: s.agent } : {},
|
|
1417
|
+
...s.model ? { model: `${s.model.providerID}/${s.model.id}` } : {},
|
|
1418
|
+
...e.outcome === "interrupted" ? { interrupted: true } : {},
|
|
1419
|
+
status: executionStatus(true, context.data.session.status(s.id) === "running", e)
|
|
1420
|
+
};
|
|
1421
|
+
});
|
|
1422
|
+
const c = [...clients.values()].find((c2) => c2.rows.has(currentId)) ?? clients.values().next().value;
|
|
1423
|
+
return familyRows(nodes, snapshots, currentId, c?.now() ?? Date.now(), c?.health?.staleMs ?? 300000, allDescendants ? new Set(nodes.map((node) => node.sessionId)) : expanded, maxNodes, (id) => {
|
|
1424
|
+
const session = inventory?.sessions.get(id);
|
|
1425
|
+
const client = session ? clients.get(locationKey(session.location)) : undefined;
|
|
1426
|
+
return {
|
|
1427
|
+
now: client?.now() ?? Date.now(),
|
|
1428
|
+
staleMs: client?.health?.staleMs ?? 300000
|
|
1429
|
+
};
|
|
1430
|
+
}, stableOrder);
|
|
1431
|
+
}
|
|
1432
|
+
return {
|
|
1433
|
+
version,
|
|
1434
|
+
acquire,
|
|
1435
|
+
async history(id, from, to, signal) {
|
|
1436
|
+
const info = inventory?.sessions.get(id);
|
|
1437
|
+
if (!info)
|
|
1438
|
+
throw new Error("Session location unavailable");
|
|
1439
|
+
const result = await context.client.rpc(historyRpc).read({ schemaVersion: 1, sessionId: id, from, to, maxPoints: 240 }, { location: info.location, signal });
|
|
1440
|
+
if (!isHistoryResult(result))
|
|
1441
|
+
throw new Error("Incompatible history service");
|
|
1442
|
+
return result;
|
|
1443
|
+
},
|
|
1444
|
+
rows,
|
|
1445
|
+
contextTrace: (row2) => contextTraces.update(row2),
|
|
1446
|
+
dispose() {
|
|
1447
|
+
stop();
|
|
1448
|
+
contextTraces.clear();
|
|
1449
|
+
},
|
|
1450
|
+
age(id) {
|
|
1451
|
+
version();
|
|
1452
|
+
const c = [...clients.values()].find((c2) => c2.rows.has(id));
|
|
1453
|
+
const m = c?.rows.get(id)?.measurement;
|
|
1454
|
+
return c && m ? c.now() - m.at : 0;
|
|
1455
|
+
},
|
|
1456
|
+
health() {
|
|
1457
|
+
version();
|
|
1458
|
+
return [...clients.values()].find((c) => c.rows.has(currentId))?.health ?? clients.values().next().value?.health;
|
|
1459
|
+
},
|
|
1460
|
+
connection() {
|
|
1461
|
+
version();
|
|
1462
|
+
return clients.size ? [...clients.values()].map((c) => c.connection).find((c) => c !== "live") ?? "live" : scanFailed ? "unavailable" : "loading";
|
|
1463
|
+
},
|
|
1464
|
+
complete() {
|
|
1465
|
+
version();
|
|
1466
|
+
return inventory?.complete ?? false;
|
|
1467
|
+
},
|
|
1468
|
+
refresh() {
|
|
1469
|
+
scan();
|
|
1470
|
+
for (const c of clients.values())
|
|
1471
|
+
c.refresh();
|
|
1472
|
+
},
|
|
1473
|
+
loadMore() {
|
|
1474
|
+
maxNodes = Math.min(2048, maxNodes + 1024);
|
|
1475
|
+
scan(true);
|
|
1476
|
+
},
|
|
1477
|
+
expand(id) {
|
|
1478
|
+
if (expanded.has(id))
|
|
1479
|
+
expanded.delete(id);
|
|
1480
|
+
else if (expanded.size < 1024)
|
|
1481
|
+
expanded.add(id);
|
|
1482
|
+
savePreferences((draft) => {
|
|
1483
|
+
draft.expanded = [...expanded];
|
|
1484
|
+
}).catch(() => {
|
|
1485
|
+
});
|
|
1486
|
+
notify();
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1251
1489
|
}
|
|
1252
|
-
function
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
const offset = size - values.length;
|
|
1260
|
-
const thresholdRow = trigger !== undefined && Number.isFinite(trigger) && trigger >= 0 && trigger <= capacity ? Math.round((1 - trigger / capacity) * (height - 1)) : -1;
|
|
1261
|
-
const blocks = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
1262
|
-
const lines = Array.from({ length: height }, (_, row2) => {
|
|
1263
|
-
const threshold = row2 === thresholdRow;
|
|
1264
|
-
const axis = gutter ? (row2 === 0 ? "100%" : row2 === height - 1 ? "0%" : "").padStart(gutter) : "";
|
|
1265
|
-
const plot = Array.from({ length: size }, (_2, col) => {
|
|
1266
|
-
const value = values[col - offset]?.tokens;
|
|
1267
|
-
const fill = value === undefined ? 0 : Math.max(0, Math.min(8, Math.ceil((Math.min(value / capacity, 1) * height - (height - row2 - 1)) * 8)));
|
|
1268
|
-
if (threshold)
|
|
1269
|
-
return fill > 0 ? "\u2542" : "\u2504";
|
|
1270
|
-
if (value === 0 && row2 === height - 1)
|
|
1271
|
-
return "\u2581";
|
|
1272
|
-
return blocks[fill] ?? " ";
|
|
1273
|
-
}).join("");
|
|
1274
|
-
return { line: `${axis}\u2502${plot}\u2502`, threshold };
|
|
1275
|
-
});
|
|
1276
|
-
lines.push({
|
|
1277
|
-
line: `${" ".repeat(gutter)}\u2514${"\u2500".repeat(size)}\u2518`,
|
|
1278
|
-
threshold: false
|
|
1279
|
-
});
|
|
1280
|
-
return lines;
|
|
1490
|
+
function locationKey(location) {
|
|
1491
|
+
return JSON.stringify([location.directory, location.workspaceID ?? null]);
|
|
1492
|
+
}
|
|
1493
|
+
function sameLocation(a, b) {
|
|
1494
|
+
if (a.workspaceID && b.workspaceID)
|
|
1495
|
+
return a.workspaceID === b.workspaceID;
|
|
1496
|
+
return a.directory === b.directory;
|
|
1281
1497
|
}
|
|
1282
1498
|
|
|
1499
|
+
// src/tui/sidebar.tsx
|
|
1500
|
+
init_format();
|
|
1501
|
+
import { effect as _$effect2 } from "@opentui/solid";
|
|
1502
|
+
import { createComponent as _$createComponent2 } from "@opentui/solid";
|
|
1503
|
+
import { insert as _$insert2 } from "@opentui/solid";
|
|
1504
|
+
import { createTextNode as _$createTextNode2 } from "@opentui/solid";
|
|
1505
|
+
import { insertNode as _$insertNode2 } from "@opentui/solid";
|
|
1506
|
+
import { memo as _$memo2 } from "@opentui/solid";
|
|
1507
|
+
import { setProp as _$setProp2 } from "@opentui/solid";
|
|
1508
|
+
import { createElement as _$createElement2 } from "@opentui/solid";
|
|
1509
|
+
import { For as For2, createEffect as createEffect2, createMemo as createMemo2, onCleanup, Show as Show2 } from "solid-js";
|
|
1510
|
+
|
|
1283
1511
|
// src/tui/compact.tsx
|
|
1512
|
+
init_format();
|
|
1284
1513
|
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
1285
1514
|
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
1286
1515
|
import { setProp as _$setProp } from "@opentui/solid";
|
|
@@ -1292,6 +1521,7 @@ import { createComponent as _$createComponent } from "@opentui/solid";
|
|
|
1292
1521
|
import { For, Index, Show, createEffect, createMemo, createSignal as createSignal2 } from "solid-js";
|
|
1293
1522
|
|
|
1294
1523
|
// src/tui/compactformat.ts
|
|
1524
|
+
init_format();
|
|
1295
1525
|
function tokens(value) {
|
|
1296
1526
|
if (value === undefined || !Number.isFinite(value))
|
|
1297
1527
|
return "?";
|
|
@@ -1314,7 +1544,7 @@ function progress(ratio, width) {
|
|
|
1314
1544
|
const filled = valid2 ? Math.round(Math.min(1, ratio) * size) : 0;
|
|
1315
1545
|
return clip("\u2588".repeat(filled) + "\u2591".repeat(size - filled) + " " + label, width);
|
|
1316
1546
|
}
|
|
1317
|
-
function mainSections(row2, width, age, samples) {
|
|
1547
|
+
function mainSections(row2, width, age, samples, chartCapacity) {
|
|
1318
1548
|
if (!row2)
|
|
1319
1549
|
return [{ tone: "base", lines: wrap("Loading session family...", width) }];
|
|
1320
1550
|
const s = row2.snapshot, m = s?.measurement;
|
|
@@ -1335,10 +1565,17 @@ function mainSections(row2, width, age, samples) {
|
|
|
1335
1565
|
...columns("Context", `${tokens(measured)} / ${tokens(s?.capacityTokens)}`, width)
|
|
1336
1566
|
]
|
|
1337
1567
|
},
|
|
1338
|
-
...contextChart(samples ?? (m && valid2 ? [{ at: m.at, tokens: m.tokens }] : []), s?.capacityTokens, s?.policy.triggerTokens, width).map(({ line, threshold }) => ({
|
|
1568
|
+
...contextChart(samples ?? (m && valid2 ? [{ at: m.at, tokens: m.tokens }] : []), s?.capacityTokens ?? chartCapacity, s?.policy.triggerTokens, width, m ? m.at + age : s?.observedAt === undefined ? undefined : s.observedAt + age).map(({ line, threshold, segments }) => ({
|
|
1339
1569
|
tone: threshold ? "threshold" : "pressure",
|
|
1340
|
-
lines: [line]
|
|
1570
|
+
lines: [line],
|
|
1571
|
+
...segments ? { segments } : {}
|
|
1341
1572
|
})),
|
|
1573
|
+
...samples?.some((sample) => sample.held) || m && age > 2500 ? [
|
|
1574
|
+
{
|
|
1575
|
+
tone: "measurement",
|
|
1576
|
+
lines: wrap("muted held \xB7 last known context", width)
|
|
1577
|
+
}
|
|
1578
|
+
] : [],
|
|
1342
1579
|
{
|
|
1343
1580
|
tone: "base",
|
|
1344
1581
|
lines: wrap(`${ratio(s?.capacityTokens) === undefined ? "?" : Math.round((ratio(s?.capacityTokens) ?? 0) * 100)}% used \xB7 recent samples \u2192 now`, width)
|
|
@@ -1472,7 +1709,7 @@ function CompactSidebar(props) {
|
|
|
1472
1709
|
setCollapsed(new Set);
|
|
1473
1710
|
});
|
|
1474
1711
|
const current = createMemo(() => props.rows.find((r) => r.node.sessionId === props.sessionID));
|
|
1475
|
-
const trace = createMemo((
|
|
1712
|
+
const trace = createMemo(() => props.state.contextTrace(current()));
|
|
1476
1713
|
const tree = createMemo(() => subagentTree(props.rows, props.sessionID, collapsed(), hideCompleted(), byPressure()));
|
|
1477
1714
|
const entries = createMemo(() => new Map(tree().visible.map((entry) => [entry.row.node.sessionId, entry])));
|
|
1478
1715
|
const toggle = (id) => setCollapsed((previous) => {
|
|
@@ -1538,7 +1775,7 @@ function CompactSidebar(props) {
|
|
|
1538
1775
|
const head = cells(`\u2500\u2500 ${title} `) > width() ? title : `\u2500\u2500 ${title} `;
|
|
1539
1776
|
return clip(head, width()) + "\u2500".repeat(Math.max(0, width() - cells(head)));
|
|
1540
1777
|
};
|
|
1541
|
-
const notices = createMemo(() => [
|
|
1778
|
+
const notices = createMemo(() => [...!["2.0.29", "2.1.2"].includes(props.context.app.version) ? wrap(`Runtime ${props.context.app.version}: unverified`, width()) : [], ...props.state.connection() !== "live" ? wrap(`Connection: ${props.state.connection()}`, width()) : [], ...props.state.health()?.mode === "observe" ? ["Observe mode"] : [], ...props.state.health()?.enforcement === "disabled" || props.state.health()?.enforcement === "suspended" ? wrap(`Guard: ${props.state.health()?.enforcement}`, width()) : [], ...(props.state.health()?.reasons ?? []).flatMap((reason) => wrap(reason, width()))]);
|
|
1542
1779
|
return (() => {
|
|
1543
1780
|
var _el$2 = _$createElement("box"), _el$3 = _$createElement("text"), _el$5 = _$createElement("text"), _el$6 = _$createElement("text"), _el$8 = _$createElement("text"), _el$9 = _$createElement("text"), _el$0 = _$createElement("text"), _el$1 = _$createElement("text"), _el$11 = _$createElement("text"), _el$12 = _$createElement("text");
|
|
1544
1781
|
_$insertNode(_el$2, _el$3);
|
|
@@ -1562,7 +1799,7 @@ function CompactSidebar(props) {
|
|
|
1562
1799
|
});
|
|
1563
1800
|
_$insert(_el$2, _$createComponent(Index, {
|
|
1564
1801
|
get each() {
|
|
1565
|
-
return mainSections(current(), width(), props.state.age(props.sessionID), trace().samples);
|
|
1802
|
+
return mainSections(current(), width(), props.state.age(props.sessionID), trace().samples, trace().capacity);
|
|
1566
1803
|
},
|
|
1567
1804
|
children: (section2) => _$createComponent(Index, {
|
|
1568
1805
|
get each() {
|
|
@@ -1570,7 +1807,29 @@ function CompactSidebar(props) {
|
|
|
1570
1807
|
},
|
|
1571
1808
|
children: (line) => (() => {
|
|
1572
1809
|
var _el$13 = _$createElement("text");
|
|
1573
|
-
_$insert(_el$13, (
|
|
1810
|
+
_$insert(_el$13, _$createComponent(Show, {
|
|
1811
|
+
get when() {
|
|
1812
|
+
return section2().segments;
|
|
1813
|
+
},
|
|
1814
|
+
get fallback() {
|
|
1815
|
+
return line() || " ";
|
|
1816
|
+
},
|
|
1817
|
+
get children() {
|
|
1818
|
+
return _$createComponent(For, {
|
|
1819
|
+
get each() {
|
|
1820
|
+
return section2().segments;
|
|
1821
|
+
},
|
|
1822
|
+
children: (part) => (() => {
|
|
1823
|
+
var _el$14 = _$createElement("span");
|
|
1824
|
+
_$insert(_el$14, () => part.text);
|
|
1825
|
+
_$effect((_$p) => _$setProp(_el$14, "style", {
|
|
1826
|
+
fg: part.tone === "axis" || part.tone === "held" ? colors().muted : part.tone === "threshold" ? colors().feedback.warning.base : current()?.freshness === "fresh" ? colors().base : colors().muted
|
|
1827
|
+
}, _$p));
|
|
1828
|
+
return _el$14;
|
|
1829
|
+
})()
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
}));
|
|
1574
1833
|
_$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));
|
|
1575
1834
|
return _el$13;
|
|
1576
1835
|
})()
|
|
@@ -1581,10 +1840,10 @@ function CompactSidebar(props) {
|
|
|
1581
1840
|
return notices();
|
|
1582
1841
|
},
|
|
1583
1842
|
children: (line) => (() => {
|
|
1584
|
-
var _el$
|
|
1585
|
-
_$insert(_el$
|
|
1586
|
-
_$effect((_$p) => _$setProp(_el$
|
|
1587
|
-
return _el$
|
|
1843
|
+
var _el$15 = _$createElement("text");
|
|
1844
|
+
_$insert(_el$15, line);
|
|
1845
|
+
_$effect((_$p) => _$setProp(_el$15, "fg", colors().feedback.warning.base, _$p));
|
|
1846
|
+
return _el$15;
|
|
1588
1847
|
})()
|
|
1589
1848
|
}), _el$3);
|
|
1590
1849
|
_$insertNode(_el$3, _$createTextNode(` `));
|
|
@@ -1610,60 +1869,60 @@ function CompactSidebar(props) {
|
|
|
1610
1869
|
return row2();
|
|
1611
1870
|
},
|
|
1612
1871
|
children: (item) => (() => {
|
|
1613
|
-
var _el$
|
|
1614
|
-
_$insertNode(_el$
|
|
1615
|
-
_$insertNode(_el$
|
|
1616
|
-
_$setProp(_el$
|
|
1617
|
-
_$setProp(_el$15, "flexShrink", 0);
|
|
1618
|
-
_$insertNode(_el$16, _el$18);
|
|
1619
|
-
_$setProp(_el$16, "flexDirection", "row");
|
|
1872
|
+
var _el$16 = _$createElement("box"), _el$17 = _$createElement("box"), _el$19 = _$createElement("text"), _el$20 = _$createElement("span"), _el$21 = _$createElement("span"), _el$22 = _$createElement("text");
|
|
1873
|
+
_$insertNode(_el$16, _el$17);
|
|
1874
|
+
_$insertNode(_el$16, _el$22);
|
|
1875
|
+
_$setProp(_el$16, "flexDirection", "column");
|
|
1620
1876
|
_$setProp(_el$16, "flexShrink", 0);
|
|
1621
|
-
_$
|
|
1877
|
+
_$insertNode(_el$17, _el$19);
|
|
1878
|
+
_$setProp(_el$17, "flexDirection", "row");
|
|
1879
|
+
_$setProp(_el$17, "flexShrink", 0);
|
|
1880
|
+
_$insert(_el$17, _$createComponent(Show, {
|
|
1622
1881
|
get when() {
|
|
1623
1882
|
return prefix();
|
|
1624
1883
|
},
|
|
1625
1884
|
get children() {
|
|
1626
|
-
var _el$
|
|
1627
|
-
_$setProp(_el$
|
|
1628
|
-
_$insert(_el$
|
|
1629
|
-
_$effect((_$p) => _$setProp(_el$
|
|
1630
|
-
return _el$
|
|
1885
|
+
var _el$18 = _$createElement("text");
|
|
1886
|
+
_$setProp(_el$18, "onMouseDown", () => toggle(id));
|
|
1887
|
+
_$insert(_el$18, prefix);
|
|
1888
|
+
_$effect((_$p) => _$setProp(_el$18, "fg", colors().muted, _$p));
|
|
1889
|
+
return _el$18;
|
|
1631
1890
|
}
|
|
1632
|
-
}), _el$
|
|
1633
|
-
_$insertNode(_el$
|
|
1634
|
-
_$insertNode(_el$
|
|
1635
|
-
_$setProp(_el$
|
|
1891
|
+
}), _el$19);
|
|
1892
|
+
_$insertNode(_el$19, _el$20);
|
|
1893
|
+
_$insertNode(_el$19, _el$21);
|
|
1894
|
+
_$setProp(_el$19, "onMouseDown", () => props.context.ui.router.navigate({
|
|
1636
1895
|
type: "session",
|
|
1637
1896
|
sessionID: id
|
|
1638
1897
|
}));
|
|
1639
|
-
_$insert(_el$
|
|
1640
|
-
_$insert(_el$
|
|
1641
|
-
_$insert(_el$
|
|
1898
|
+
_$insert(_el$20, () => agentHeading(item(), nameWidth()).slice(0, 1));
|
|
1899
|
+
_$insert(_el$21, () => agentHeading(item(), nameWidth()).slice(1));
|
|
1900
|
+
_$insert(_el$16, _$createComponent(Index, {
|
|
1642
1901
|
get each() {
|
|
1643
1902
|
return agentLines(item(), Math.max(1, width() - cells(indent()) - 2));
|
|
1644
1903
|
},
|
|
1645
1904
|
children: (line) => (() => {
|
|
1646
|
-
var _el$
|
|
1647
|
-
_$insertNode(_el$
|
|
1648
|
-
_$insert(_el$
|
|
1649
|
-
_$insert(_el$
|
|
1650
|
-
_$effect((_$p) => _$setProp(_el$
|
|
1651
|
-
return _el$
|
|
1905
|
+
var _el$24 = _$createElement("text"), _el$25 = _$createTextNode(` `);
|
|
1906
|
+
_$insertNode(_el$24, _el$25);
|
|
1907
|
+
_$insert(_el$24, indent, _el$25);
|
|
1908
|
+
_$insert(_el$24, line, null);
|
|
1909
|
+
_$effect((_$p) => _$setProp(_el$24, "fg", rowColor(item()), _$p));
|
|
1910
|
+
return _el$24;
|
|
1652
1911
|
})()
|
|
1653
|
-
}), _el$
|
|
1654
|
-
_$insertNode(_el$
|
|
1912
|
+
}), _el$22);
|
|
1913
|
+
_$insertNode(_el$22, _$createTextNode(` `));
|
|
1655
1914
|
_$effect((_p$) => {
|
|
1656
1915
|
var _v$0 = rowColor(item()), _v$1 = {
|
|
1657
1916
|
fg: executionColor(item())
|
|
1658
1917
|
};
|
|
1659
|
-
_v$0 !== _p$.e && (_p$.e = _$setProp(_el$
|
|
1660
|
-
_v$1 !== _p$.t && (_p$.t = _$setProp(_el$
|
|
1918
|
+
_v$0 !== _p$.e && (_p$.e = _$setProp(_el$19, "fg", _v$0, _p$.e));
|
|
1919
|
+
_v$1 !== _p$.t && (_p$.t = _$setProp(_el$20, "style", _v$1, _p$.t));
|
|
1661
1920
|
return _p$;
|
|
1662
1921
|
}, {
|
|
1663
1922
|
e: undefined,
|
|
1664
1923
|
t: undefined
|
|
1665
1924
|
});
|
|
1666
|
-
return _el$
|
|
1925
|
+
return _el$16;
|
|
1667
1926
|
})()
|
|
1668
1927
|
});
|
|
1669
1928
|
}
|
|
@@ -1717,8 +1976,8 @@ function GuardView(props) {
|
|
|
1717
1976
|
onCleanup(() => consumer.release());
|
|
1718
1977
|
const rows = createMemo2(() => props.family ?? props.state.rows([], !props.expanded));
|
|
1719
1978
|
const current = createMemo2(() => rows().find((row2) => row2.node.sessionId === props.sessionID));
|
|
1720
|
-
const trace = createMemo2((
|
|
1721
|
-
const chart = createMemo2(() => contextChart(trace().samples, current()?.snapshot?.capacityTokens, current()?.snapshot?.policy.triggerTokens, props.width));
|
|
1979
|
+
const trace = createMemo2(() => props.state.contextTrace(props.expanded ? current() : undefined));
|
|
1980
|
+
const chart = createMemo2(() => contextChart(trace().samples, current()?.snapshot?.capacityTokens ?? trace().capacity, current()?.snapshot?.policy.triggerTokens, props.width, current()?.snapshot?.measurement ? (current()?.snapshot?.measurement?.at ?? 0) + props.state.age(props.sessionID) : undefined));
|
|
1722
1981
|
const detail = createMemo2(() => {
|
|
1723
1982
|
const lines = detailLines(current(), props.width, props.expanded, props.state.age(props.sessionID));
|
|
1724
1983
|
if (props.expanded) {
|
|
@@ -1780,8 +2039,8 @@ function GuardView(props) {
|
|
|
1780
2039
|
_$insertNode2(_el$2, _el$3);
|
|
1781
2040
|
_$insert2(_el$2, () => props.state.health()?.mode ?? "?", null);
|
|
1782
2041
|
_$insert2(_el$4, (() => {
|
|
1783
|
-
var _c$ = _$memo2(() =>
|
|
1784
|
-
return () => _c$() ? "" : clip(`Runtime ${props.context.app.version}: unverified (2.0.29
|
|
2042
|
+
var _c$ = _$memo2(() => !!["2.0.29", "2.1.2"].includes(props.context.app.version));
|
|
2043
|
+
return () => _c$() ? "" : clip(`Runtime ${props.context.app.version}: unverified (tested: 2.0.29, 2.1.2)`, props.width);
|
|
1785
2044
|
})());
|
|
1786
2045
|
_$insert2(_el$5, () => clip(`${props.state.connection()} / ${props.state.health()?.enforcement ?? "?"}`, props.width));
|
|
1787
2046
|
_$insert2(_el$, _$createComponent2(For2, {
|
|
@@ -1790,20 +2049,42 @@ function GuardView(props) {
|
|
|
1790
2049
|
},
|
|
1791
2050
|
children: (item) => (() => {
|
|
1792
2051
|
var _el$1 = _$createElement2("text");
|
|
1793
|
-
_$insert2(_el$1, (
|
|
2052
|
+
_$insert2(_el$1, _$createComponent2(Show2, {
|
|
2053
|
+
get when() {
|
|
2054
|
+
return item.segments;
|
|
2055
|
+
},
|
|
2056
|
+
get fallback() {
|
|
2057
|
+
return item.line;
|
|
2058
|
+
},
|
|
2059
|
+
get children() {
|
|
2060
|
+
return _$createComponent2(For2, {
|
|
2061
|
+
get each() {
|
|
2062
|
+
return item.segments;
|
|
2063
|
+
},
|
|
2064
|
+
children: (part) => (() => {
|
|
2065
|
+
var _el$10 = _$createElement2("span");
|
|
2066
|
+
_$insert2(_el$10, () => part.text);
|
|
2067
|
+
_$effect2((_$p) => _$setProp2(_el$10, "style", {
|
|
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
|
|
2069
|
+
}, _$p));
|
|
2070
|
+
return _el$10;
|
|
2071
|
+
})()
|
|
2072
|
+
});
|
|
2073
|
+
}
|
|
2074
|
+
}));
|
|
1794
2075
|
_$effect2((_$p) => _$setProp2(_el$1, "fg", item.threshold ? props.context.theme.text.feedback.warning.base : props.context.theme.text.muted, _$p));
|
|
1795
2076
|
return _el$1;
|
|
1796
2077
|
})()
|
|
1797
2078
|
}), _el$6);
|
|
1798
2079
|
_$insert2(_el$, _$createComponent2(For2, {
|
|
1799
2080
|
get each() {
|
|
1800
|
-
return wrap("Recent context samples \u2192 now \xB7 \u2504 trigger", props.width);
|
|
2081
|
+
return wrap("Recent context samples \u2192 now \xB7 \u2504 trigger \xB7 muted held", props.width);
|
|
1801
2082
|
},
|
|
1802
2083
|
children: (line) => (() => {
|
|
1803
|
-
var _el$
|
|
1804
|
-
_$insert2(_el$
|
|
1805
|
-
_$effect2((_$p) => _$setProp2(_el$
|
|
1806
|
-
return _el$
|
|
2084
|
+
var _el$11 = _$createElement2("text");
|
|
2085
|
+
_$insert2(_el$11, line);
|
|
2086
|
+
_$effect2((_$p) => _$setProp2(_el$11, "fg", props.context.theme.text.muted, _$p));
|
|
2087
|
+
return _el$11;
|
|
1807
2088
|
})()
|
|
1808
2089
|
}), _el$6);
|
|
1809
2090
|
_$insert2(_el$, _$createComponent2(For2, {
|
|
@@ -1811,10 +2092,10 @@ function GuardView(props) {
|
|
|
1811
2092
|
return detail();
|
|
1812
2093
|
},
|
|
1813
2094
|
children: (line) => (() => {
|
|
1814
|
-
var _el$
|
|
1815
|
-
_$insert2(_el$
|
|
1816
|
-
_$effect2((_$p) => _$setProp2(_el$
|
|
1817
|
-
return _el$
|
|
2095
|
+
var _el$12 = _$createElement2("text");
|
|
2096
|
+
_$insert2(_el$12, line);
|
|
2097
|
+
_$effect2((_$p) => _$setProp2(_el$12, "fg", props.context.theme.text.base, _$p));
|
|
2098
|
+
return _el$12;
|
|
1818
2099
|
})()
|
|
1819
2100
|
}), _el$6);
|
|
1820
2101
|
_$insert2(_el$, _$createComponent2(For2, {
|
|
@@ -1822,10 +2103,10 @@ function GuardView(props) {
|
|
|
1822
2103
|
return props.state.health()?.reasons ?? [];
|
|
1823
2104
|
},
|
|
1824
2105
|
children: (reason) => (() => {
|
|
1825
|
-
var _el$
|
|
1826
|
-
_$insert2(_el$
|
|
1827
|
-
_$effect2((_$p) => _$setProp2(_el$
|
|
1828
|
-
return _el$
|
|
2106
|
+
var _el$13 = _$createElement2("text");
|
|
2107
|
+
_$insert2(_el$13, () => clip(reason, props.width));
|
|
2108
|
+
_$effect2((_$p) => _$setProp2(_el$13, "fg", props.context.theme.text.feedback.warning.base, _$p));
|
|
2109
|
+
return _el$13;
|
|
1829
2110
|
})()
|
|
1830
2111
|
}), _el$6);
|
|
1831
2112
|
_$insert2(_el$6, (() => {
|
|
@@ -1841,9 +2122,9 @@ function GuardView(props) {
|
|
|
1841
2122
|
return visible();
|
|
1842
2123
|
},
|
|
1843
2124
|
children: (row2) => (() => {
|
|
1844
|
-
var _el$
|
|
1845
|
-
_$setProp2(_el$
|
|
1846
|
-
_$setProp2(_el$
|
|
2125
|
+
var _el$14 = _$createElement2("box");
|
|
2126
|
+
_$setProp2(_el$14, "flexDirection", "column");
|
|
2127
|
+
_$setProp2(_el$14, "onMouseDown", () => {
|
|
1847
2128
|
if (row2.hidden)
|
|
1848
2129
|
props.state.expand(row2.node.sessionId);
|
|
1849
2130
|
else {
|
|
@@ -1855,19 +2136,19 @@ function GuardView(props) {
|
|
|
1855
2136
|
});
|
|
1856
2137
|
}
|
|
1857
2138
|
});
|
|
1858
|
-
_$insert2(_el$
|
|
2139
|
+
_$insert2(_el$14, _$createComponent2(For2, {
|
|
1859
2140
|
get each() {
|
|
1860
2141
|
return rowLines(row2, Math.max(1, props.width - (props.expanded ? 2 : 0))).map((line) => props.expanded ? `${row2.node.sessionId === props.selectedId ? ">" : " "} ${line}` : line);
|
|
1861
2142
|
},
|
|
1862
2143
|
children: (line) => (() => {
|
|
1863
|
-
var _el$
|
|
1864
|
-
_$insert2(_el$
|
|
1865
|
-
_$effect2((_$p) => _$setProp2(_el$
|
|
1866
|
-
return _el$
|
|
2144
|
+
var _el$15 = _$createElement2("text");
|
|
2145
|
+
_$insert2(_el$15, line);
|
|
2146
|
+
_$effect2((_$p) => _$setProp2(_el$15, "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));
|
|
2147
|
+
return _el$15;
|
|
1867
2148
|
})()
|
|
1868
2149
|
}));
|
|
1869
|
-
_$effect2((_$p) => _$setProp2(_el$
|
|
1870
|
-
return _el$
|
|
2150
|
+
_$effect2((_$p) => _$setProp2(_el$14, "id", `context-guard.row.${row2.node.sessionId}`, _$p));
|
|
2151
|
+
return _el$14;
|
|
1871
2152
|
})()
|
|
1872
2153
|
}), _el$0);
|
|
1873
2154
|
_$setProp2(_el$0, "onMouseDown", () => props.context.ui.panel.open("context-guard.monitor"));
|
|
@@ -1909,6 +2190,8 @@ import { createElement as _$createElement4 } from "@opentui/solid";
|
|
|
1909
2190
|
import { createSignal as createSignal4, createMemo as createMemo3, createEffect as createEffect4, onCleanup as onCleanup3, Show as Show3, For as For4 } from "solid-js";
|
|
1910
2191
|
|
|
1911
2192
|
// src/tui/charts.tsx
|
|
2193
|
+
init_chartformat();
|
|
2194
|
+
init_format();
|
|
1912
2195
|
import { effect as _$effect3 } from "@opentui/solid";
|
|
1913
2196
|
import { insertNode as _$insertNode3 } from "@opentui/solid";
|
|
1914
2197
|
import { insert as _$insert3 } from "@opentui/solid";
|
|
@@ -1916,113 +2199,6 @@ import { createComponent as _$createComponent3 } from "@opentui/solid";
|
|
|
1916
2199
|
import { setProp as _$setProp3 } from "@opentui/solid";
|
|
1917
2200
|
import { createElement as _$createElement3 } from "@opentui/solid";
|
|
1918
2201
|
import { createEffect as createEffect3, createSignal as createSignal3, onCleanup as onCleanup2, For as For3 } from "solid-js";
|
|
1919
|
-
|
|
1920
|
-
// src/tui/chartformat.ts
|
|
1921
|
-
function columns2(points, from, to, width, gaps = []) {
|
|
1922
|
-
const size = Math.max(1, Math.min(120, Math.floor(width))), values = Array.from({ length: size });
|
|
1923
|
-
const column = (time) => Math.max(0, Math.min(size - 1, Math.floor((time - from) / Math.max(1, to - from) * (size - 1))));
|
|
1924
|
-
let min = Infinity, max = -Infinity;
|
|
1925
|
-
for (const point of points) {
|
|
1926
|
-
if (point.time < from || point.time > to || point.value === undefined || !Number.isFinite(point.value) || point.value < 0)
|
|
1927
|
-
continue;
|
|
1928
|
-
min = Math.min(min, point.value);
|
|
1929
|
-
max = Math.max(max, point.value);
|
|
1930
|
-
const i = column(point.time);
|
|
1931
|
-
values[i] = Math.max(values[i] ?? -Infinity, point.value);
|
|
1932
|
-
}
|
|
1933
|
-
for (const time of gaps)
|
|
1934
|
-
if (time >= from && time <= to)
|
|
1935
|
-
values[column(time)] = undefined;
|
|
1936
|
-
return { values, column, min, max };
|
|
1937
|
-
}
|
|
1938
|
-
function sparkline(points, from, to, width, gaps = []) {
|
|
1939
|
-
const { values, column, min, max } = columns2(points, from, to, width, gaps);
|
|
1940
|
-
const bars = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
1941
|
-
const chars = values.map((v) => v === undefined ? " " : bars[Math.min(7, Math.floor(v / Math.max(1, max) * 7))] ?? "\u2581");
|
|
1942
|
-
for (const time of gaps)
|
|
1943
|
-
if (time >= from && time <= to)
|
|
1944
|
-
chars[column(time)] = "\u2506";
|
|
1945
|
-
return { line: chars.join(""), ...min === Infinity ? {} : { min, max } };
|
|
1946
|
-
}
|
|
1947
|
-
var chartMetrics = [
|
|
1948
|
-
{ label: "Live TPS ~", unit: "t/s", key: "liveTps", source: "points" },
|
|
1949
|
-
{ label: "Avg model", unit: "t/s", key: "averageModelTps", source: "points" },
|
|
1950
|
-
{
|
|
1951
|
-
label: "Avg session",
|
|
1952
|
-
unit: "t/s",
|
|
1953
|
-
key: "averageSessionTps",
|
|
1954
|
-
source: "points"
|
|
1955
|
-
},
|
|
1956
|
-
{ label: "TTFT ~", unit: "s", key: "ttftMs", source: "requests" },
|
|
1957
|
-
{ label: "Request throughput", unit: "t/s", key: "tps", source: "requests" },
|
|
1958
|
-
{
|
|
1959
|
-
label: "Cumulative output",
|
|
1960
|
-
unit: "tokens",
|
|
1961
|
-
key: "sessionOutputTokens",
|
|
1962
|
-
source: "points"
|
|
1963
|
-
}
|
|
1964
|
-
];
|
|
1965
|
-
function metricPlot(points, from, to, width, gaps = []) {
|
|
1966
|
-
const label = (value) => value >= 1e6 ? `${(value / 1e6).toFixed(1)}M` : value >= 1000 ? `${(value / 1000).toFixed(1)}k` : value.toFixed(1);
|
|
1967
|
-
const peak = Math.max(0, ...points.filter((p) => p.time >= from && p.time <= to && Number.isFinite(p.value)).map((p) => p.value ?? 0));
|
|
1968
|
-
const scale = Math.max(1, peak);
|
|
1969
|
-
const gutter = width >= 20 ? Math.max(label(scale).length, 3) : 0;
|
|
1970
|
-
const { values, column } = columns2(points, from, to, Math.max(1, width - gutter - 2), gaps);
|
|
1971
|
-
const gapColumns = new Set(gaps.filter((time) => time >= from && time <= to).map(column));
|
|
1972
|
-
const height = 6;
|
|
1973
|
-
const blocks = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
1974
|
-
const lines = Array.from({ length: height }, (_, row2) => {
|
|
1975
|
-
const axis = gutter ? (row2 === 0 ? label(scale) : row2 === height - 1 ? "0.0" : "").padStart(gutter) : "";
|
|
1976
|
-
return `${axis}\u2502${values.map((value, i) => {
|
|
1977
|
-
if (gapColumns.has(i))
|
|
1978
|
-
return "\u2506";
|
|
1979
|
-
if (value === undefined)
|
|
1980
|
-
return " ";
|
|
1981
|
-
const fill = Math.max(0, Math.min(8, Math.ceil((value / scale * height - (height - row2 - 1)) * 8)));
|
|
1982
|
-
return value === 0 && row2 === height - 1 ? "\u2581" : blocks[fill];
|
|
1983
|
-
}).join("")}\u2502`;
|
|
1984
|
-
});
|
|
1985
|
-
lines.push(`${" ".repeat(gutter)}\u2514${"\u2500".repeat(values.length)}\u2518`);
|
|
1986
|
-
const start = new Date(from).toISOString().slice(11, 16), end = new Date(to).toISOString().slice(11, 16);
|
|
1987
|
-
const axisWidth = values.length + 2;
|
|
1988
|
-
if (axisWidth >= 11)
|
|
1989
|
-
lines.push(`${" ".repeat(gutter)}${start}${" ".repeat(axisWidth - 10)}${end}`);
|
|
1990
|
-
return lines;
|
|
1991
|
-
}
|
|
1992
|
-
function historyChartLines(result, width, from, to, metricIndex = 0) {
|
|
1993
|
-
if (!result.enabled)
|
|
1994
|
-
return wrap("History recording is disabled on this server.", width);
|
|
1995
|
-
const series = result.data.series[0];
|
|
1996
|
-
if (!series)
|
|
1997
|
-
return wrap("No retained measurements in this window.", width);
|
|
1998
|
-
const gaps = result.data.gaps.map((g) => g.time);
|
|
1999
|
-
const observations = (key) => series.points.map((p) => ({
|
|
2000
|
-
time: p.time,
|
|
2001
|
-
...p[key] === undefined ? {} : { value: p[key] }
|
|
2002
|
-
}));
|
|
2003
|
-
const requests = (key) => series.requests.map((p) => ({
|
|
2004
|
-
time: p.time,
|
|
2005
|
-
...p[key] === undefined ? {} : { value: key === "ttftMs" ? p[key] / 1000 : p[key] }
|
|
2006
|
-
}));
|
|
2007
|
-
const metric2 = chartMetrics[metricIndex] ?? chartMetrics[0];
|
|
2008
|
-
const points = metric2.source === "points" ? observations(metric2.key) : requests(metric2.key);
|
|
2009
|
-
const plotted = sparkline(points, from, to, width - 2, gaps);
|
|
2010
|
-
return [
|
|
2011
|
-
...wrap(`\u2039 ${metric2.label} \u203A \xB7 ${metricIndex + 1}/${chartMetrics.length}`, width),
|
|
2012
|
-
...wrap(plotted.min === undefined ? "No measurements for this metric." : `${plotted.min.toFixed(1)}\u2013${plotted.max?.toFixed(1)} ${metric2.unit} \xB7 observed range`, width),
|
|
2013
|
-
"",
|
|
2014
|
-
...metricPlot(points, from, to, width, gaps),
|
|
2015
|
-
"",
|
|
2016
|
-
...wrap("UTC time \u2192 \xB7 peaks per column", width),
|
|
2017
|
-
...wrap("blank = no sample \xB7 \u2506 = gap", width),
|
|
2018
|
-
...wrap(`${new Date(from).toISOString()} \u2192 ${new Date(to).toISOString()}`, width),
|
|
2019
|
-
...series.points.some((p) => p.partial) ? wrap("Partial timing coverage; averages include only matched model durations.", width) : [],
|
|
2020
|
-
...result.truncated ? wrap("Downsampled/bounded history; some older requests or gap markers may be omitted.", width) : [],
|
|
2021
|
-
...result.metadata.malformedRecords ? wrap(`${result.metadata.malformedRecords} malformed/partial records skipped.`, width) : []
|
|
2022
|
-
];
|
|
2023
|
-
}
|
|
2024
|
-
|
|
2025
|
-
// src/tui/charts.tsx
|
|
2026
2202
|
function HistoryCharts(props) {
|
|
2027
2203
|
const [result, setResult] = createSignal3();
|
|
2028
2204
|
const [status, setStatus] = createSignal3("Loading retained history...");
|
|
@@ -2117,10 +2293,13 @@ function HistoryCharts(props) {
|
|
|
2117
2293
|
}
|
|
2118
2294
|
|
|
2119
2295
|
// src/tui/panel.tsx
|
|
2296
|
+
init_chartformat();
|
|
2297
|
+
init_format();
|
|
2120
2298
|
function GuardPanel(props) {
|
|
2121
2299
|
const [showCharts, setShowCharts] = createSignal4(false);
|
|
2122
2300
|
const [metricIndex, setMetricIndex] = createSignal4(0);
|
|
2123
|
-
const
|
|
2301
|
+
const [viewportWidth, setViewportWidth] = createSignal4();
|
|
2302
|
+
const width = () => Math.max(4, Math.min(props.input.width - 4, viewportWidth() ?? Infinity));
|
|
2124
2303
|
const windows = [300000, 3600000, 86400000, 7 * 86400000];
|
|
2125
2304
|
const [windowIndex, setWindowIndex] = createSignal4(1);
|
|
2126
2305
|
const [chartRefresh, setChartRefresh] = createSignal4(0);
|
|
@@ -2276,6 +2455,11 @@ function GuardPanel(props) {
|
|
|
2276
2455
|
_$use((value) => {
|
|
2277
2456
|
scroll = value;
|
|
2278
2457
|
}, _el$2);
|
|
2458
|
+
_$setProp4(_el$2, "viewportOptions", {
|
|
2459
|
+
onSizeChange: function() {
|
|
2460
|
+
setViewportWidth(this.width);
|
|
2461
|
+
}
|
|
2462
|
+
});
|
|
2279
2463
|
_$setProp4(_el$2, "flexGrow", 1);
|
|
2280
2464
|
_$setProp4(_el$2, "minHeight", 0);
|
|
2281
2465
|
_$insertNode4(_el$3, _el$4);
|