opencode-subagent-magazine 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js ADDED
@@ -0,0 +1,1859 @@
1
+ // src/index.tsx
2
+ import { createTextNode as _$createTextNode } from "@opentui/solid";
3
+ import { insertNode as _$insertNode } from "@opentui/solid";
4
+ import { createComponent as _$createComponent } from "@opentui/solid";
5
+ import { effect as _$effect } from "@opentui/solid";
6
+ import { insert as _$insert } from "@opentui/solid";
7
+ import { memo as _$memo } from "@opentui/solid";
8
+ import { use as _$use } from "@opentui/solid";
9
+ import { setProp as _$setProp } from "@opentui/solid";
10
+ import { createElement as _$createElement } from "@opentui/solid";
11
+ import { createMemo, createSignal, createEffect, onMount, onCleanup, untrack, Show, For } from "solid-js";
12
+
13
+ // src/_version.ts
14
+ var PLUGIN_VERSION = "1.1.3";
15
+
16
+ // src/index.tsx
17
+ var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["task", "delegate", "call_omo_agent"]);
18
+ var I18N = {
19
+ zh: {
20
+ "panel.title": "\u5B50\u4EE3\u7406",
21
+ "status.none": "\u6682\u65E0\u5B50\u4EE3\u7406",
22
+ "agent.label": "\u4EE3\u7406",
23
+ "status.label": "\u72B6\u6001",
24
+ "time.label": "\u8017\u65F6",
25
+ "tokens.label": "\u4E0A\u4E0B\u6587",
26
+ "error.label": "\u9519\u8BEF",
27
+ "model.label": "\u6A21\u578B",
28
+ "todo.label": "\u8FDB\u5EA6",
29
+ "open.label": "\u8FDB\u5165\u4F1A\u8BDD",
30
+ "cost.label": "\u8D39\u7528",
31
+ "scroll.more": "\u66F4\u591A",
32
+ "scroll.top": "\u56DE\u9876",
33
+ "dismiss.label": "\u6807\u8BB0\u5B8C\u6210",
34
+ "status.running": "\u8FD0\u884C\u4E2D",
35
+ "status.done": "\u5DF2\u5B8C\u6210",
36
+ "status.error": "\u9519\u8BEF"
37
+ },
38
+ en: {
39
+ "panel.title": "SubAgent",
40
+ "status.none": "No sub-agents yet",
41
+ "agent.label": "agent",
42
+ "status.label": "status",
43
+ "time.label": "time",
44
+ "tokens.label": "tokens",
45
+ "error.label": "error",
46
+ "model.label": "model",
47
+ "todo.label": "todo",
48
+ "open.label": "Open session",
49
+ "cost.label": "cost",
50
+ "scroll.more": "more",
51
+ "scroll.top": "Top",
52
+ "dismiss.label": "dismiss",
53
+ "status.running": "running",
54
+ "status.done": "done",
55
+ "status.error": "error"
56
+ }
57
+ };
58
+ function detectLang() {
59
+ const env = process?.env?.OPENCODE_LANG ?? process?.env?.LANG ?? "";
60
+ if (env.startsWith("zh")) return "zh";
61
+ return "en";
62
+ }
63
+ function charColumns(c) {
64
+ const code = c.codePointAt(0) ?? 0;
65
+ if (code < 32) return 0;
66
+ if (code < 127) return 1;
67
+ if (code < 160) return 0;
68
+ if (code >= 4352 && code <= 4447 || code >= 11904 && code <= 42191 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65040 && code <= 65135 || code >= 65281 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 127744 && code <= 128591 || code >= 131072 && code <= 262141) return 2;
69
+ return 1;
70
+ }
71
+ function visualWidth(s) {
72
+ let w = 0;
73
+ for (const c of s) w += charColumns(c);
74
+ return w;
75
+ }
76
+ function truncate(text, maxCols) {
77
+ if (visualWidth(text) <= maxCols) return text;
78
+ let cols = 0;
79
+ let i = 0;
80
+ for (const c of text) {
81
+ const w = charColumns(c);
82
+ if (cols + w > maxCols - 1) break;
83
+ cols += w;
84
+ i += c.length;
85
+ }
86
+ return text.slice(0, i) + "\u2026";
87
+ }
88
+ function fmtDurationShort(ms, running) {
89
+ if (running && ms < 2e3) return "";
90
+ if (ms < 1e3) return (ms / 1e3).toFixed(2) + "s";
91
+ if (ms < 6e4) return (ms / 1e3).toFixed(2) + "s";
92
+ const m = Math.floor(ms / 6e4);
93
+ const s = Math.round(ms % 6e4 / 1e3);
94
+ return `${m}m${s}s`;
95
+ }
96
+ function fmtTokens(n) {
97
+ if (n < 1e3) return `${n}`;
98
+ if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
99
+ return `${(n / 1e6).toFixed(1)}M`;
100
+ }
101
+ function rgb(raw) {
102
+ if (typeof raw === "string" && raw.startsWith("#")) {
103
+ const h = raw.slice(1);
104
+ return {
105
+ r: parseInt(h.slice(0, 2), 16),
106
+ g: parseInt(h.slice(2, 4), 16),
107
+ b: parseInt(h.slice(4, 6), 16)
108
+ };
109
+ }
110
+ if (raw && typeof raw === "object") {
111
+ const o = raw;
112
+ if (typeof o.r === "number" && typeof o.g === "number" && typeof o.b === "number") {
113
+ const scale = o.r > 1 || o.g > 1 || o.b > 1 ? 1 : 255;
114
+ return {
115
+ r: Math.round(o.r * scale),
116
+ g: Math.round(o.g * scale),
117
+ b: Math.round(o.b * scale)
118
+ };
119
+ }
120
+ }
121
+ return null;
122
+ }
123
+ function saturation(r, g, b) {
124
+ const max = Math.max(r, g, b) / 255;
125
+ const min = Math.min(r, g, b) / 255;
126
+ const delta = max - min;
127
+ if (delta === 0) return 0;
128
+ const L = (max + min) / 2;
129
+ return L <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
130
+ }
131
+ function desaturateTo(raw, maxSat, fallback) {
132
+ const c = rgb(raw);
133
+ if (!c) return fallback;
134
+ const sat = saturation(c.r, c.g, c.b);
135
+ if (sat <= maxSat) {
136
+ return "#" + [c.r, c.g, c.b].map((v) => v.toString(16).padStart(2, "0")).join("");
137
+ }
138
+ const luma = c.r * 0.299 + c.g * 0.587 + c.b * 0.114;
139
+ let lo = 0, hi = 1;
140
+ for (let i = 0; i < 12; i++) {
141
+ const mid = (lo + hi) / 2;
142
+ const nr2 = Math.round(c.r + (luma - c.r) * mid);
143
+ const ng2 = Math.round(c.g + (luma - c.g) * mid);
144
+ const nb2 = Math.round(c.b + (luma - c.b) * mid);
145
+ if (saturation(nr2, ng2, nb2) > maxSat) lo = mid;
146
+ else hi = mid;
147
+ }
148
+ const nr = Math.round(c.r + (luma - c.r) * hi);
149
+ const ng = Math.round(c.g + (luma - c.g) * hi);
150
+ const nb = Math.round(c.b + (luma - c.b) * hi);
151
+ return "#" + [nr, ng, nb].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
152
+ }
153
+ function dimColor(hex, factor = 0.5) {
154
+ const c = rgb(hex);
155
+ if (!c) return hex;
156
+ const r = Math.round(c.r * factor);
157
+ const g = Math.round(c.g * factor);
158
+ const b = Math.round(c.b * factor);
159
+ return "#" + [r, g, b].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
160
+ }
161
+ var FALLBACK = {
162
+ primary: "#8B9DAF",
163
+ text: "#C5C5BB",
164
+ muted: "#7A7A72",
165
+ success: "#9CAF8B",
166
+ warning: "#C5B88D",
167
+ error: "#B08A8A",
168
+ border: "#6B6B63"
169
+ };
170
+ var MAX_SAT = 0.28;
171
+ var LEFT_PAD = 4;
172
+ var INDENT = 2;
173
+ function safeErrorMsg(err) {
174
+ if (!err) return "";
175
+ if (typeof err === "string") return err;
176
+ if (typeof err === "object") return String(err.message || err.code || "");
177
+ return "";
178
+ }
179
+ var globalEntryCache = /* @__PURE__ */ new Map();
180
+ function SubAgentPanel(props) {
181
+ const t = (key) => I18N[props.lang()][key] ?? key;
182
+ const SESSION_DATA_KEY = `${KV_PREFIX}.session_data`;
183
+ const TTL_MS = 3 * 24 * 60 * 60 * 1e3;
184
+ const loadSessionData = () => {
185
+ try {
186
+ const raw = props.api.kv.get(SESSION_DATA_KEY, "{}");
187
+ return JSON.parse(String(raw));
188
+ } catch {
189
+ return {};
190
+ }
191
+ };
192
+ const saveSessionData = (data) => {
193
+ try {
194
+ props.api.kv.set(SESSION_DATA_KEY, JSON.stringify(data));
195
+ } catch {
196
+ }
197
+ };
198
+ const loadEntries = (sid) => {
199
+ const m = /* @__PURE__ */ new Map();
200
+ try {
201
+ const rec = loadSessionData()[sid];
202
+ if (rec?.entries) {
203
+ for (const e of rec.entries) m.set(e.id, e);
204
+ }
205
+ } catch {
206
+ }
207
+ return m;
208
+ };
209
+ let persistTimer;
210
+ const persistEntries = (sid, entries2) => {
211
+ clearTimeout(persistTimer);
212
+ persistTimer = setTimeout(() => {
213
+ try {
214
+ const data = loadSessionData();
215
+ data[sid] = {
216
+ ...data[sid],
217
+ ts: Date.now(),
218
+ entries: [...entries2.values()]
219
+ };
220
+ saveSessionData(data);
221
+ } catch {
222
+ }
223
+ }, 200);
224
+ };
225
+ const persistScroll = (sid, scroll) => {
226
+ try {
227
+ const data = loadSessionData();
228
+ data[sid] = {
229
+ ...data[sid],
230
+ ts: Date.now(),
231
+ scroll
232
+ };
233
+ saveSessionData(data);
234
+ } catch {
235
+ }
236
+ };
237
+ const persistExpanded = (sid, expanded2) => {
238
+ try {
239
+ const data = loadSessionData();
240
+ data[sid] = {
241
+ ...data[sid],
242
+ ts: Date.now(),
243
+ expanded: expanded2
244
+ };
245
+ saveSessionData(data);
246
+ } catch {
247
+ }
248
+ };
249
+ const cleanupOldSessions = () => {
250
+ try {
251
+ const data = loadSessionData();
252
+ const cutoff = Date.now() - TTL_MS;
253
+ let changed = false;
254
+ for (const sid of Object.keys(data)) {
255
+ if (data[sid].ts < cutoff) {
256
+ delete data[sid];
257
+ changed = true;
258
+ }
259
+ }
260
+ if (changed) saveSessionData(data);
261
+ } catch {
262
+ }
263
+ };
264
+ cleanupOldSessions();
265
+ const [entryMap, setEntryMapRaw] = createSignal(loadEntries(props.sessionId));
266
+ const setEntryMap = (arg) => {
267
+ setEntryMapRaw((prev) => {
268
+ const next = typeof arg === "function" ? arg(prev) : arg;
269
+ let needsImmediateFlush = false;
270
+ for (const [id, entry] of next) {
271
+ const prevEntry = prev.get(id);
272
+ if (prevEntry?.status === "running" && (entry.status === "done" || entry.status === "error")) {
273
+ needsImmediateFlush = true;
274
+ break;
275
+ }
276
+ }
277
+ if (needsImmediateFlush) {
278
+ clearTimeout(persistTimer);
279
+ try {
280
+ const data = loadSessionData();
281
+ data[props.sessionId] = {
282
+ ...data[props.sessionId],
283
+ ts: Date.now(),
284
+ entries: [...next.values()]
285
+ };
286
+ saveSessionData(data);
287
+ } catch {
288
+ }
289
+ } else {
290
+ persistEntries(props.sessionId, next);
291
+ }
292
+ globalEntryCache.set(props.sessionId, new Map(next));
293
+ return next;
294
+ });
295
+ };
296
+ const [panelWidth, setPanelWidth] = createSignal(28);
297
+ const [open, setOpen] = createSignal((() => {
298
+ try {
299
+ return props.api.kv.get(`${KV_PREFIX}.open`, true);
300
+ } catch {
301
+ return true;
302
+ }
303
+ })());
304
+ const [expanded, setExpanded] = createSignal((() => {
305
+ try {
306
+ return loadSessionData()[props.sessionId]?.expanded || void 0;
307
+ } catch {
308
+ return void 0;
309
+ }
310
+ })());
311
+ const [hoveredOpen, setHoveredOpen] = createSignal(void 0);
312
+ const [hoveredDismiss, setHoveredDismiss] = createSignal(void 0);
313
+ const [hoveredTop, setHoveredTop] = createSignal(false);
314
+ const [scrollOffset, setScrollOffset] = createSignal((() => {
315
+ try {
316
+ return loadSessionData()[props.sessionId]?.scroll ?? 0;
317
+ } catch {
318
+ return 0;
319
+ }
320
+ })());
321
+ const [now, setNow] = createSignal(Date.now());
322
+ const [renderTick, setRenderTick] = createSignal(0);
323
+ let boxEl;
324
+ let disposed = false;
325
+ const readSessionTokens = (sid) => {
326
+ if (!sid) return void 0;
327
+ try {
328
+ const msgs = props.api.state.session.messages(sid);
329
+ if (msgs) {
330
+ for (let i = msgs.length - 1; i >= 0; i--) {
331
+ const m = msgs[i];
332
+ if (m.role !== "assistant") continue;
333
+ const t2 = m.tokens;
334
+ if (!t2) continue;
335
+ const cache = t2.cache;
336
+ const ctx = (Number(t2.input) || 0) + (cache?.read ?? 0);
337
+ if (ctx > 0) return ctx;
338
+ }
339
+ }
340
+ return void 0;
341
+ } catch {
342
+ return void 0;
343
+ }
344
+ };
345
+ const readSessionCost = (sid) => {
346
+ if (!sid) return void 0;
347
+ try {
348
+ const session = props.api.state.session.get(sid);
349
+ if (session?.cost != null && session.cost > 0) return session.cost;
350
+ const msgs = props.api.state.session.messages(sid);
351
+ if (!msgs) return void 0;
352
+ let total = 0;
353
+ for (const m of msgs) {
354
+ if (m.role === "assistant" && typeof m.cost === "number") total += m.cost;
355
+ }
356
+ return total > 0 ? total : void 0;
357
+ } catch {
358
+ return void 0;
359
+ }
360
+ };
361
+ const readSessionModel = (sid) => {
362
+ if (!sid) return void 0;
363
+ try {
364
+ const msgs = props.api.state.session.messages(sid);
365
+ if (msgs) {
366
+ for (let i = msgs.length - 1; i >= 0; i--) {
367
+ const m = msgs[i];
368
+ if (m.role === "assistant" && m.modelID) return String(m.modelID);
369
+ }
370
+ }
371
+ return void 0;
372
+ } catch {
373
+ return void 0;
374
+ }
375
+ };
376
+ const readSessionTodo = (sid) => {
377
+ if (!sid) return void 0;
378
+ try {
379
+ const todos = props.api.state.session.todo(sid);
380
+ if (!todos || todos.length === 0) return void 0;
381
+ let done = 0;
382
+ for (const t2 of todos) {
383
+ if (t2.status === "completed" || t2.status === "cancelled") done++;
384
+ }
385
+ return {
386
+ total: todos.length,
387
+ done
388
+ };
389
+ } catch {
390
+ return void 0;
391
+ }
392
+ };
393
+ const upsertEntry = (partial) => {
394
+ setEntryMap((prev) => {
395
+ const existing = prev.get(partial.id);
396
+ const next = new Map(prev);
397
+ const nowTs = Date.now();
398
+ const e = partial.status;
399
+ const ended = e === "done" || e === "error";
400
+ next.set(partial.id, {
401
+ ...existing ?? {
402
+ startedAt: nowTs
403
+ },
404
+ ...partial,
405
+ startedAt: existing?.startedAt || partial.startedAt || nowTs,
406
+ endedAt: ended ? existing?.endedAt || nowTs : void 0
407
+ });
408
+ return next;
409
+ });
410
+ };
411
+ const handlePartUpdated = (event) => {
412
+ const e = event;
413
+ const props_ = e.properties;
414
+ const part = props_?.part;
415
+ if (!part) return;
416
+ if (part.type === "subtask") {
417
+ const agent = String(part.agent ?? "?");
418
+ const prompt = String(part.prompt ?? "");
419
+ const desc = String(part.description ?? "");
420
+ const title = desc || truncate(prompt.replace(/\n/g, " ").replace(/\s+/g, " ").trim(), 40);
421
+ const id = `sub:${String(part.id ?? crypto.randomUUID())}`;
422
+ const subSid = part.sessionID !== void 0 ? String(part.sessionID) : void 0;
423
+ const partModel = part.model;
424
+ const modelId = partModel?.modelID ? String(partModel.modelID) : void 0;
425
+ upsertEntry({
426
+ id,
427
+ title,
428
+ agent,
429
+ prompt,
430
+ sessionId: subSid,
431
+ status: "running",
432
+ model: modelId
433
+ });
434
+ }
435
+ if (part.type === "tool") {
436
+ const tool = String(part.tool ?? "");
437
+ if (!SUBAGENT_TOOLS.has(tool)) return;
438
+ const st = part.state;
439
+ const rawStatus = String(st?.status ?? "");
440
+ if (rawStatus === "pending" || rawStatus === "") return;
441
+ if (rawStatus === "error") {
442
+ const id2 = `tool:${String(part.id ?? "")}`;
443
+ if (!part.id) return;
444
+ const existing = entryMap().get(id2);
445
+ if (existing) {
446
+ upsertEntry({
447
+ id: id2,
448
+ title: existing.title,
449
+ agent: existing.agent,
450
+ prompt: existing.prompt,
451
+ status: "error"
452
+ });
453
+ }
454
+ return;
455
+ }
456
+ const input = st?.input;
457
+ let status = "running";
458
+ if (rawStatus === "completed") status = "done";
459
+ if (input?.run_in_background === true && status === "done") {
460
+ const stMetaCheck = st?.metadata;
461
+ const hasChild = stMetaCheck?.session_id !== void 0 || stMetaCheck?.sessionId !== void 0;
462
+ if (hasChild) status = "running";
463
+ }
464
+ const agent = String(part.subagent_type ?? input?.subagent_type ?? input?.category ?? tool);
465
+ const prompt = String(input?.prompt ?? part.description ?? "");
466
+ const desc = input?.description !== void 0 ? String(input.description) : "";
467
+ const title = desc || truncate(prompt.replace(/\n/g, " ").replace(/\s+/g, " ").trim(), 40);
468
+ const id = `tool:${String(part.id ?? crypto.randomUUID())}`;
469
+ const stMeta = st?.metadata;
470
+ const subSid = stMeta?.session_id !== void 0 ? String(stMeta.session_id) : stMeta?.sessionId !== void 0 ? String(stMeta.sessionId) : void 0;
471
+ upsertEntry({
472
+ id,
473
+ title,
474
+ agent,
475
+ prompt,
476
+ sessionId: subSid,
477
+ status
478
+ });
479
+ }
480
+ };
481
+ const handleSessionEnd = (event, status) => {
482
+ const e = event;
483
+ const props_ = e.properties;
484
+ const sid = String(props_?.sessionID ?? "");
485
+ if (!sid) return;
486
+ const sessionTokens = readSessionTokens(sid);
487
+ const sessionCost = readSessionCost(sid);
488
+ const sessionModel = readSessionModel(sid);
489
+ const sessionTodo = readSessionTodo(sid);
490
+ let sessionAgent;
491
+ let errorMsg;
492
+ try {
493
+ const s = props.api.state.session.get(sid);
494
+ sessionAgent = s?.agent;
495
+ if (status === "error") {
496
+ const evtErr = props_?.error;
497
+ errorMsg = safeErrorMsg(evtErr) || safeErrorMsg(props_?.message);
498
+ if (!errorMsg) {
499
+ const msgs = props.api.state.session.messages(sid);
500
+ if (msgs) {
501
+ for (let i = msgs.length - 1; i >= 0; i--) {
502
+ const m = msgs[i];
503
+ if (m.role === "assistant" && m.error) {
504
+ errorMsg = safeErrorMsg(m.error);
505
+ break;
506
+ }
507
+ }
508
+ }
509
+ }
510
+ }
511
+ } catch {
512
+ }
513
+ const tryMatchAndUpdate = (entriesMap, targetSid, targetStatus, nowTs) => {
514
+ for (const [, entry] of entriesMap) {
515
+ if (entry.sessionId === targetSid && entry.status === "running") {
516
+ entry.status = targetStatus;
517
+ entry.endedAt = nowTs;
518
+ entry.tokens = entry.tokens ?? sessionTokens;
519
+ entry.cost = entry.cost ?? sessionCost;
520
+ entry.model = entry.model ?? sessionModel;
521
+ entry.todoTotal = entry.todoTotal ?? sessionTodo?.total;
522
+ entry.todoDone = entry.todoDone ?? sessionTodo?.done;
523
+ entry.error = errorMsg || entry.error;
524
+ return true;
525
+ }
526
+ }
527
+ if (sessionAgent) {
528
+ const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9-]/g, "");
529
+ const saNorm = normalize(sessionAgent);
530
+ let best = null;
531
+ for (const [, entry] of entriesMap) {
532
+ if (entry.status !== "running") continue;
533
+ const eaNorm = normalize(entry.agent);
534
+ if (!eaNorm || !saNorm) continue;
535
+ if (!eaNorm.includes(saNorm) && !saNorm.includes(eaNorm)) continue;
536
+ const gap = nowTs - (entry.startedAt || 0);
537
+ if (!best || gap > best.gap) best = {
538
+ entry,
539
+ gap
540
+ };
541
+ }
542
+ if (!best) {
543
+ for (const [, entry] of entriesMap) {
544
+ if (entry.status !== "running") continue;
545
+ if (entry.sessionId) continue;
546
+ const gap = nowTs - (entry.startedAt || 0);
547
+ if (!best || gap > best.gap) best = {
548
+ entry,
549
+ gap
550
+ };
551
+ }
552
+ }
553
+ if (best) {
554
+ best.entry.status = targetStatus;
555
+ best.entry.endedAt = nowTs;
556
+ best.entry.tokens = best.entry.tokens ?? sessionTokens;
557
+ best.entry.cost = best.entry.cost ?? sessionCost;
558
+ best.entry.model = best.entry.model ?? sessionModel;
559
+ best.entry.todoTotal = best.entry.todoTotal ?? sessionTodo?.total;
560
+ best.entry.todoDone = best.entry.todoDone ?? sessionTodo?.done;
561
+ best.entry.sessionId = targetSid;
562
+ best.entry.error = errorMsg || best.entry.error;
563
+ return true;
564
+ }
565
+ }
566
+ return false;
567
+ };
568
+ setEntryMap((prev) => {
569
+ let changed = false;
570
+ const next = new Map(prev);
571
+ for (const [id, entry] of next) {
572
+ if (entry.sessionId !== sid) continue;
573
+ if (entry.status !== "running" && entry.status !== "done") continue;
574
+ if (sid === props.sessionId) continue;
575
+ const alreadySettled = entry.status !== "running";
576
+ next.set(id, {
577
+ ...entry,
578
+ ...alreadySettled ? {} : {
579
+ status,
580
+ endedAt: Date.now()
581
+ },
582
+ tokens: entry.tokens ?? sessionTokens,
583
+ cost: entry.cost ?? sessionCost,
584
+ model: entry.model ?? sessionModel,
585
+ todoTotal: entry.todoTotal ?? sessionTodo?.total,
586
+ todoDone: entry.todoDone ?? sessionTodo?.done,
587
+ error: errorMsg || entry.error
588
+ });
589
+ changed = true;
590
+ }
591
+ if (!changed && sessionAgent) {
592
+ const nowTs = Date.now();
593
+ const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9-]/g, "");
594
+ const saNorm = normalize(sessionAgent);
595
+ let best = null;
596
+ for (const [id, entry] of next) {
597
+ if (entry.status !== "running") continue;
598
+ const eaNorm = normalize(entry.agent);
599
+ if (!eaNorm || !saNorm) continue;
600
+ if (!eaNorm.includes(saNorm) && !saNorm.includes(eaNorm)) continue;
601
+ const gap = nowTs - (entry.startedAt || 0);
602
+ if (!best || gap > best.gap) best = {
603
+ id,
604
+ gap
605
+ };
606
+ }
607
+ if (!best) {
608
+ for (const [id, entry] of next) {
609
+ if (entry.status !== "running") continue;
610
+ if (entry.sessionId) continue;
611
+ const gap = nowTs - (entry.startedAt || 0);
612
+ if (!best || gap > best.gap) best = {
613
+ id,
614
+ gap
615
+ };
616
+ }
617
+ }
618
+ if (best) {
619
+ const entry = next.get(best.id);
620
+ next.set(best.id, {
621
+ ...entry,
622
+ status,
623
+ endedAt: nowTs,
624
+ tokens: sessionTokens || entry.tokens,
625
+ cost: sessionCost || entry.cost,
626
+ sessionId: sid,
627
+ error: errorMsg || entry.error
628
+ });
629
+ changed = true;
630
+ }
631
+ }
632
+ return changed ? next : prev;
633
+ });
634
+ try {
635
+ const sessionObj = props.api.state.session.get(sid);
636
+ const parentSid = sessionObj?.parentID;
637
+ if (parentSid && parentSid !== props.sessionId) {
638
+ const parentCache = globalEntryCache.get(parentSid);
639
+ const nowTs = Date.now();
640
+ let found = false;
641
+ if (parentCache) {
642
+ found = tryMatchAndUpdate(parentCache, sid, status, nowTs);
643
+ }
644
+ if (!found) {
645
+ const data = loadSessionData();
646
+ const rec = data[parentSid];
647
+ if (rec?.entries) {
648
+ const fallbackMap = new Map(rec.entries.map((e2) => [e2.id, e2]));
649
+ found = tryMatchAndUpdate(fallbackMap, sid, status, nowTs);
650
+ if (found) {
651
+ data[parentSid] = {
652
+ ...rec,
653
+ ts: nowTs,
654
+ entries: [...fallbackMap.values()]
655
+ };
656
+ saveSessionData(data);
657
+ globalEntryCache.set(parentSid, fallbackMap);
658
+ }
659
+ }
660
+ }
661
+ if (found && parentCache) {
662
+ const data = loadSessionData();
663
+ data[parentSid] = {
664
+ ...data[parentSid],
665
+ ts: nowTs,
666
+ entries: [...parentCache.values()]
667
+ };
668
+ saveSessionData(data);
669
+ }
670
+ }
671
+ } catch {
672
+ }
673
+ setTimeout(() => {
674
+ if (disposed) return;
675
+ const finalTokens = readSessionTokens(sid);
676
+ const finalCost = readSessionCost(sid);
677
+ const finalModel = readSessionModel(sid);
678
+ const finalTodo = readSessionTodo(sid);
679
+ setEntryMap((prev) => {
680
+ let changed = false;
681
+ const next = new Map(prev);
682
+ for (const [id, entry] of next) {
683
+ if (entry.sessionId !== sid) continue;
684
+ const t2 = finalTokens ?? entry.tokens;
685
+ const c = finalCost ?? entry.cost;
686
+ const m = finalModel ?? entry.model;
687
+ const tt = finalTodo?.total ?? entry.todoTotal;
688
+ const td = finalTodo?.done ?? entry.todoDone;
689
+ if (t2 !== entry.tokens || c !== entry.cost || m !== entry.model || tt !== entry.todoTotal || td !== entry.todoDone) {
690
+ next.set(id, {
691
+ ...entry,
692
+ tokens: t2,
693
+ cost: c,
694
+ model: m,
695
+ todoTotal: tt,
696
+ todoDone: td
697
+ });
698
+ changed = true;
699
+ }
700
+ }
701
+ return changed ? next : prev;
702
+ });
703
+ bump();
704
+ }, 150);
705
+ };
706
+ const bump = () => setRenderTick((v) => v + 1);
707
+ onMount(() => {
708
+ const clock = setInterval(() => {
709
+ setNow(Date.now());
710
+ bump();
711
+ }, 100);
712
+ const tokenTimer = setInterval(() => {
713
+ untrack(() => {
714
+ setEntryMapRaw((prev) => {
715
+ let changed = false;
716
+ const next = new Map(prev);
717
+ for (const [id, entry] of next) {
718
+ if (entry.status === "running" && entry.sessionId) {
719
+ let isChild = false;
720
+ try {
721
+ const s = props.api.state.session.get(entry.sessionId);
722
+ isChild = s?.parentID === props.sessionId;
723
+ } catch {
724
+ }
725
+ if (!isChild) continue;
726
+ const total = readSessionTokens(entry.sessionId);
727
+ const todo = readSessionTodo(entry.sessionId);
728
+ const model = entry.model ?? readSessionModel(entry.sessionId);
729
+ const nextEntry = {
730
+ ...entry
731
+ };
732
+ if (total !== void 0 && total !== entry.tokens) {
733
+ nextEntry.tokens = total;
734
+ changed = true;
735
+ }
736
+ if (todo !== void 0) {
737
+ if (todo.total !== entry.todoTotal || todo.done !== entry.todoDone) {
738
+ nextEntry.todoTotal = todo.total;
739
+ nextEntry.todoDone = todo.done;
740
+ changed = true;
741
+ }
742
+ }
743
+ if (model && !entry.model) {
744
+ nextEntry.model = model;
745
+ changed = true;
746
+ }
747
+ if (changed) next.set(id, nextEntry);
748
+ }
749
+ }
750
+ return changed ? next : prev;
751
+ });
752
+ });
753
+ bump();
754
+ }, 500);
755
+ bump();
756
+ const unsubPart = props.api.event.on("message.part.updated", (e) => {
757
+ handlePartUpdated(e);
758
+ bump();
759
+ });
760
+ const unsubMsg = props.api.event.on("message.updated", () => bump());
761
+ const unsubIdle = props.api.event.on("session.idle", (e) => {
762
+ handleSessionEnd(e, "done");
763
+ bump();
764
+ });
765
+ const unsubError = props.api.event.on("session.error", (e) => {
766
+ handleSessionEnd(e, "error");
767
+ bump();
768
+ });
769
+ onCleanup(() => {
770
+ disposed = true;
771
+ clearInterval(clock);
772
+ clearInterval(tokenTimer);
773
+ unsubPart();
774
+ unsubMsg();
775
+ unsubIdle();
776
+ unsubError();
777
+ });
778
+ });
779
+ let lastSid = props.sessionId;
780
+ createEffect(() => {
781
+ const sid = props.sessionId;
782
+ const switched = sid !== lastSid;
783
+ lastSid = sid;
784
+ const t2 = setTimeout(() => {
785
+ untrack(() => {
786
+ if (switched) {
787
+ const saved = loadSessionData()[sid]?.scroll ?? 0;
788
+ setScrollOffset(saved);
789
+ }
790
+ setEntryMapRaw((prev) => {
791
+ const next = switched ? new Map(globalEntryCache.get(sid) ?? loadEntries(sid)) : new Map(prev);
792
+ try {
793
+ const msgs = props.api.state.session.messages(sid);
794
+ if (msgs && msgs.length) {
795
+ for (const msg of msgs) {
796
+ const parts = props.api.state.part(msg.id) ?? [];
797
+ for (const partRaw of parts) {
798
+ const part = partRaw;
799
+ if (part.type === "tool") {
800
+ const tool = String(part.tool ?? "");
801
+ if (!SUBAGENT_TOOLS.has(tool)) continue;
802
+ const id = `tool:${String(part.id ?? "")}`;
803
+ if (!part.id) continue;
804
+ const st = part.state;
805
+ const rawStatus = String(st?.status ?? "");
806
+ const exists = next.get(id);
807
+ if ((rawStatus === "pending" || rawStatus === "") && !exists) continue;
808
+ if (rawStatus === "error") {
809
+ if (exists && exists.status === "running") {
810
+ next.set(id, {
811
+ ...exists,
812
+ status: "error",
813
+ endedAt: Date.now()
814
+ });
815
+ }
816
+ continue;
817
+ }
818
+ let status = "running";
819
+ if (rawStatus === "completed") status = "done";
820
+ if (st?.input?.run_in_background === true && status === "done") {
821
+ const scanStMeta = st?.metadata;
822
+ const scanHasChild = scanStMeta?.session_id !== void 0 || scanStMeta?.sessionId !== void 0;
823
+ if (scanHasChild) status = "running";
824
+ }
825
+ if (exists && exists.status !== "running") continue;
826
+ if (exists && status === "running") {
827
+ if (!rawStatus) {
828
+ const msgTokens = msg?.tokens;
829
+ if (msgTokens && (Number(msgTokens.input) > 0 || Number(msgTokens.output) > 0)) {
830
+ status = "done";
831
+ } else if (Date.now() - exists.startedAt > 30 * 60 * 1e3) {
832
+ status = "done";
833
+ } else {
834
+ continue;
835
+ }
836
+ } else {
837
+ continue;
838
+ }
839
+ }
840
+ const input = st?.input;
841
+ const agent = String(part.subagent_type ?? input?.subagent_type ?? tool);
842
+ const prompt = String(input?.prompt ?? part.description ?? "");
843
+ const desc = input?.description !== void 0 ? String(input.description) : "";
844
+ const title = desc || truncate(prompt.replace(/\n/g, " ").trim(), 40);
845
+ let tokens;
846
+ const scanStMeta2 = st?.metadata;
847
+ const scanSubSid = scanStMeta2?.session_id !== void 0 ? String(scanStMeta2.session_id) : scanStMeta2?.sessionId !== void 0 ? String(scanStMeta2.sessionId) : void 0;
848
+ if (scanSubSid) tokens = readSessionTokens(scanSubSid);
849
+ const ended = status === "done";
850
+ next.set(id, {
851
+ id,
852
+ title,
853
+ agent,
854
+ prompt,
855
+ // Preserve existing values (from handleSessionEnd / KV) — scan must not overwrite
856
+ tokens: exists?.tokens ?? tokens,
857
+ sessionId: exists?.sessionId ?? scanSubSid,
858
+ status,
859
+ startedAt: exists?.startedAt || Date.now(),
860
+ endedAt: ended ? exists?.endedAt || Date.now() : void 0
861
+ });
862
+ }
863
+ }
864
+ }
865
+ }
866
+ } catch {
867
+ }
868
+ return next;
869
+ });
870
+ setEntryMapRaw((prev) => {
871
+ let changed = false;
872
+ const next = new Map(prev);
873
+ for (const [id, entry] of next) {
874
+ if (entry.status !== "running" || !entry.sessionId) continue;
875
+ try {
876
+ const st = props.api.state.session.status(entry.sessionId);
877
+ if (!st || st.type !== "idle") continue;
878
+ const tokens = readSessionTokens(entry.sessionId);
879
+ const cost = readSessionCost(entry.sessionId);
880
+ next.set(id, {
881
+ ...entry,
882
+ status: "done",
883
+ endedAt: Date.now(),
884
+ tokens: tokens ?? entry.tokens,
885
+ cost: cost ?? entry.cost
886
+ });
887
+ changed = true;
888
+ } catch {
889
+ }
890
+ }
891
+ return changed ? next : prev;
892
+ });
893
+ bump();
894
+ });
895
+ }, 150);
896
+ onCleanup(() => clearTimeout(t2));
897
+ });
898
+ const pal = createMemo(() => {
899
+ const th = props.theme;
900
+ const sat = (k, fb) => desaturateTo(th[k], MAX_SAT, fb);
901
+ return {
902
+ primary: sat("primary", FALLBACK.primary),
903
+ text: sat("text", FALLBACK.text),
904
+ muted: sat("textMuted", FALLBACK.muted),
905
+ success: sat("success", FALLBACK.success),
906
+ warning: sat("warning", FALLBACK.warning),
907
+ error: sat("error", FALLBACK.error),
908
+ border: sat("border", FALLBACK.border)
909
+ };
910
+ });
911
+ const entryList = createMemo(() => {
912
+ return [...entryMap().values()].sort((a, b) => b.startedAt - a.startedAt);
913
+ });
914
+ const max = props.maxEntries;
915
+ const clampedOffset = createMemo(() => {
916
+ const total = entryList().length;
917
+ const m = max();
918
+ if (total <= m) return 0;
919
+ return Math.min(scrollOffset(), total - m);
920
+ });
921
+ const visibleList = createMemo(() => entryList().slice(clampedOffset(), clampedOffset() + max()));
922
+ const hiddenAbove = createMemo(() => clampedOffset());
923
+ const hiddenBelow = createMemo(() => Math.max(0, entryList().length - clampedOffset() - max()));
924
+ const entries = createMemo(() => {
925
+ const nowVal = now();
926
+ return entryList().map((e) => ({
927
+ ...e,
928
+ elapsed: (e.endedAt ?? nowVal) - e.startedAt
929
+ }));
930
+ });
931
+ const doneCount = createMemo(() => entryList().filter((e) => e.status === "done").length);
932
+ const runningCount = createMemo(() => entryList().filter((e) => e.status === "running").length);
933
+ const errCount = createMemo(() => entryList().filter((e) => e.status === "error").length);
934
+ const anyEntry = () => entryList().length > 0;
935
+ const totalTokens = createMemo(() => {
936
+ let sum = 0;
937
+ for (const e of entryList()) {
938
+ if (e.tokens) sum += e.tokens;
939
+ }
940
+ return sum;
941
+ });
942
+ const totalCost = createMemo(() => {
943
+ let sum = 0;
944
+ for (const e of entryList()) {
945
+ if (e.cost) sum += e.cost;
946
+ }
947
+ return sum;
948
+ });
949
+ const toggleExpand = (id) => {
950
+ setExpanded((prev) => {
951
+ const next = prev === id ? void 0 : id;
952
+ try {
953
+ persistExpanded(props.sessionId, next ?? "");
954
+ } catch {
955
+ }
956
+ return next;
957
+ });
958
+ };
959
+ const sep = () => "\u2500".repeat(Math.max(1, panelWidth()));
960
+ const expandedMaxLabelW = createMemo(() => {
961
+ const labels = [t("agent.label"), t("status.label"), t("time.label"), t("tokens.label"), t("error.label"), t("cost.label"), t("model.label"), t("todo.label")];
962
+ return Math.max(...labels.map((l) => visualWidth(l + ": ")));
963
+ });
964
+ const expandedPad = (label) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "));
965
+ const expandedValAvail = () => Math.max(6, panelWidth() - INDENT - expandedMaxLabelW());
966
+ const summaryParts = createMemo(() => {
967
+ if (!anyEntry()) return null;
968
+ const dot = "\u25CF";
969
+ const cost = totalCost();
970
+ return {
971
+ done: `${dot}${doneCount()}`,
972
+ running: runningCount() > 0 ? `${dot}${runningCount()}` : null,
973
+ err: errCount() > 0 ? `${dot}${errCount()}` : null,
974
+ duration: totalTokens() > 0 ? fmtTokens(totalTokens()) : "",
975
+ cost: cost > 0 ? `$${cost.toFixed(2)}` : ""
976
+ };
977
+ });
978
+ const summaryCols = createMemo(() => {
979
+ const p = summaryParts();
980
+ if (!p) return 0;
981
+ let w = visualWidth(p.done);
982
+ if (p.running) w += 1 + visualWidth(p.running);
983
+ if (p.err) w += 1 + visualWidth(p.err);
984
+ w += p.duration ? 1 + visualWidth(p.duration) : 0;
985
+ w += p.cost ? 1 + visualWidth(p.cost) : 0;
986
+ return w;
987
+ });
988
+ const versionText = ` v${PLUGIN_VERSION}`;
989
+ const versionW = visualWidth(versionText);
990
+ const showVersion = createMemo(() => {
991
+ if (!open()) return false;
992
+ const icon = "\u25BC";
993
+ const need = visualWidth(icon) + 1 + visualWidth(t("panel.title")) + versionW + summaryCols();
994
+ return need <= panelWidth();
995
+ });
996
+ const leftCols = createMemo(() => {
997
+ const icon = open() ? "\u25BC" : "\u25B6";
998
+ let w = visualWidth(icon) + 1 + visualWidth(t("panel.title"));
999
+ if (showVersion()) w += versionW;
1000
+ return w;
1001
+ });
1002
+ const spacerCols = createMemo(() => {
1003
+ if (!anyEntry()) return 0;
1004
+ return Math.max(0, panelWidth() - leftCols() - summaryCols());
1005
+ });
1006
+ const valueCols = (label) => Math.max(4, panelWidth() - INDENT - visualWidth(label + ": "));
1007
+ return (() => {
1008
+ var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("span"), _el$4 = _$createElement("span");
1009
+ _$insertNode(_el$, _el$2);
1010
+ var _ref$ = boxEl;
1011
+ typeof _ref$ === "function" ? _$use(_ref$, _el$) : boxEl = _el$;
1012
+ _$setProp(_el$, "border", false);
1013
+ _$setProp(_el$, "paddingTop", 0);
1014
+ _$setProp(_el$, "paddingBottom", 0);
1015
+ _$setProp(_el$, "paddingLeft", 0);
1016
+ _$setProp(_el$, "paddingRight", 0);
1017
+ _$setProp(_el$, "flexDirection", "column");
1018
+ _$setProp(_el$, "gap", 0);
1019
+ _$setProp(_el$, "onSizeChange", () => {
1020
+ const w = boxEl ? Math.max(20, boxEl.width ?? 0) : 28;
1021
+ setPanelWidth((prev) => prev === w ? prev : w);
1022
+ });
1023
+ _$insertNode(_el$2, _el$3);
1024
+ _$insertNode(_el$2, _el$4);
1025
+ _$setProp(_el$2, "onMouseUp", () => {
1026
+ setOpen((o) => {
1027
+ const n = !o;
1028
+ try {
1029
+ props.api.kv.set(`${KV_PREFIX}.open`, n);
1030
+ } catch {
1031
+ }
1032
+ return n;
1033
+ });
1034
+ bump();
1035
+ });
1036
+ _$insert(_el$3, () => renderTick() >= 0 && open() ? "\u25BC " : "\u25B6 ");
1037
+ _$insert(_el$4, () => t("panel.title"));
1038
+ _$insert(_el$2, _$createComponent(Show, {
1039
+ get when() {
1040
+ return showVersion();
1041
+ },
1042
+ get children() {
1043
+ var _el$5 = _$createElement("span");
1044
+ _$insert(_el$5, versionText);
1045
+ _$effect((_$p) => _$setProp(_el$5, "style", {
1046
+ fg: dimColor(pal().muted, 0.75)
1047
+ }, _$p));
1048
+ return _el$5;
1049
+ }
1050
+ }), null);
1051
+ _$insert(_el$2, (() => {
1052
+ var _c$ = _$memo(() => !!anyEntry());
1053
+ return () => _c$() ? [(() => {
1054
+ var _el$10 = _$createElement("span");
1055
+ _$insert(_el$10, () => " ".repeat(spacerCols()));
1056
+ _$effect((_$p) => _$setProp(_el$10, "style", {
1057
+ fg: pal().muted
1058
+ }, _$p));
1059
+ return _el$10;
1060
+ })(), (() => {
1061
+ var _el$11 = _$createElement("span");
1062
+ _$insert(_el$11, () => summaryParts().done);
1063
+ _$effect((_$p) => _$setProp(_el$11, "style", {
1064
+ fg: pal().success
1065
+ }, _$p));
1066
+ return _el$11;
1067
+ })(), _$memo(() => _$memo(() => runningCount() > 0)() && (() => {
1068
+ var _el$12 = _$createElement("span"), _el$13 = _$createTextNode(` `);
1069
+ _$insertNode(_el$12, _el$13);
1070
+ _$insert(_el$12, () => summaryParts().running, null);
1071
+ _$effect((_$p) => _$setProp(_el$12, "style", {
1072
+ fg: pal().warning
1073
+ }, _$p));
1074
+ return _el$12;
1075
+ })()), _$memo(() => _$memo(() => errCount() > 0)() && (() => {
1076
+ var _el$14 = _$createElement("span"), _el$15 = _$createTextNode(` `);
1077
+ _$insertNode(_el$14, _el$15);
1078
+ _$insert(_el$14, () => summaryParts().err, null);
1079
+ _$effect((_$p) => _$setProp(_el$14, "style", {
1080
+ fg: pal().error
1081
+ }, _$p));
1082
+ return _el$14;
1083
+ })()), _$memo(() => _$memo(() => !!summaryParts().duration)() ? (() => {
1084
+ var _el$16 = _$createElement("span"), _el$17 = _$createTextNode(` `);
1085
+ _$insertNode(_el$16, _el$17);
1086
+ _$insert(_el$16, () => summaryParts().duration, null);
1087
+ _$effect((_$p) => _$setProp(_el$16, "style", {
1088
+ fg: pal().muted
1089
+ }, _$p));
1090
+ return _el$16;
1091
+ })() : null), _$memo(() => _$memo(() => !!summaryParts().cost)() ? (() => {
1092
+ var _el$18 = _$createElement("span"), _el$19 = _$createTextNode(` `);
1093
+ _$insertNode(_el$18, _el$19);
1094
+ _$insert(_el$18, () => summaryParts().cost, null);
1095
+ _$effect((_$p) => _$setProp(_el$18, "style", {
1096
+ fg: pal().warning
1097
+ }, _$p));
1098
+ return _el$18;
1099
+ })() : null)] : null;
1100
+ })(), null);
1101
+ _$insert(_el$, _$createComponent(Show, {
1102
+ get when() {
1103
+ return open();
1104
+ },
1105
+ get children() {
1106
+ return [(() => {
1107
+ var _el$6 = _$createElement("text");
1108
+ _$insert(_el$6, sep);
1109
+ _$effect((_$p) => _$setProp(_el$6, "fg", pal().muted, _$p));
1110
+ return _el$6;
1111
+ })(), _$createComponent(Show, {
1112
+ get when() {
1113
+ return anyEntry();
1114
+ },
1115
+ get fallback() {
1116
+ return (() => {
1117
+ var _el$20 = _$createElement("text"), _el$21 = _$createTextNode(` &gt; `), _el$23 = _$createTextNode(` `);
1118
+ _$insertNode(_el$20, _el$21);
1119
+ _$insertNode(_el$20, _el$23);
1120
+ _$insert(_el$20, () => t("status.none"), _el$23);
1121
+ _$effect((_$p) => _$setProp(_el$20, "style", {
1122
+ fg: pal().muted
1123
+ }, _$p));
1124
+ return _el$20;
1125
+ })();
1126
+ },
1127
+ get children() {
1128
+ var _el$7 = _$createElement("box");
1129
+ _$setProp(_el$7, "onMouseScroll", (e) => {
1130
+ const total = entryList().length;
1131
+ const m = max();
1132
+ if (total <= m) return;
1133
+ const dir = e.button === 0 ? 1 : -1;
1134
+ setScrollOffset((prev) => {
1135
+ const next = Math.max(0, Math.min(prev + dir, total - m));
1136
+ try {
1137
+ persistScroll(props.sessionId, next);
1138
+ } catch {
1139
+ }
1140
+ return next;
1141
+ });
1142
+ });
1143
+ _$insert(_el$7, _$createComponent(Show, {
1144
+ get when() {
1145
+ return hiddenAbove() > 0;
1146
+ },
1147
+ get children() {
1148
+ var _el$8 = _$createElement("text"), _el$9 = _$createTextNode(` &uarr; `), _el$1 = _$createTextNode(` `);
1149
+ _$insertNode(_el$8, _el$9);
1150
+ _$insertNode(_el$8, _el$1);
1151
+ _$insert(_el$8, hiddenAbove, _el$1);
1152
+ _$insert(_el$8, () => t("scroll.more"), null);
1153
+ _$effect((_$p) => _$setProp(_el$8, "style", {
1154
+ fg: pal().muted
1155
+ }, _$p));
1156
+ return _el$8;
1157
+ }
1158
+ }), null);
1159
+ _$insert(_el$7, _$createComponent(For, {
1160
+ get each() {
1161
+ return visibleList();
1162
+ },
1163
+ children: (entry) => {
1164
+ const isExpanded = () => expanded() === entry.id;
1165
+ const isRunning = entry.status === "running";
1166
+ const isError = entry.status === "error";
1167
+ const elapsed = () => (entry.endedAt ?? now()) - entry.startedAt;
1168
+ const statusDot = () => "\u25CF";
1169
+ const statusColor = () => {
1170
+ if (!isRunning) return isError ? pal().error : pal().success;
1171
+ const t2 = (Math.sin(now() % 2e3 / 2e3 * Math.PI * 2 - Math.PI / 2) + 1) / 2;
1172
+ const a = rgb(pal().muted), b = rgb(pal().warning);
1173
+ if (!a || !b) return pal().warning;
1174
+ const r = Math.round(a.r + (b.r - a.r) * t2);
1175
+ const g = Math.round(a.g + (b.g - a.g) * t2);
1176
+ const bl = Math.round(a.b + (b.b - a.b) * t2);
1177
+ return "#" + [r, g, bl].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
1178
+ };
1179
+ const timeColor = () => isRunning ? pal().warning : isError ? pal().error : pal().muted;
1180
+ const tokenText = () => !isExpanded() && entry.tokens !== void 0 && entry.tokens > 0 ? ` ${fmtTokens(entry.tokens)}` : "";
1181
+ const timeText = () => !isExpanded() && (elapsed() >= 2e3 || entry.endedAt !== void 0) ? fmtDurationShort(elapsed(), isRunning) : "";
1182
+ const suffixW = () => {
1183
+ let w = 0;
1184
+ const t2 = timeText();
1185
+ if (t2) w += 1 + visualWidth(t2);
1186
+ const tk = tokenText();
1187
+ if (tk) w += visualWidth(tk);
1188
+ return w;
1189
+ };
1190
+ const labelAvail = () => Math.max(6, panelWidth() - LEFT_PAD - suffixW());
1191
+ const labelText = () => {
1192
+ const max2 = labelAvail();
1193
+ const text = entry.title || entry.agent;
1194
+ const truncated = truncate(text, max2);
1195
+ const pad = Math.max(0, max2 - visualWidth(truncated));
1196
+ return truncated + " ".repeat(pad);
1197
+ };
1198
+ return [(() => {
1199
+ var _el$24 = _$createElement("text"), _el$25 = _$createElement("span"), _el$26 = _$createTextNode(` `), _el$27 = _$createElement("span"), _el$28 = _$createTextNode(` `), _el$29 = _$createElement("span");
1200
+ _$insertNode(_el$24, _el$25);
1201
+ _$insertNode(_el$24, _el$26);
1202
+ _$insertNode(_el$24, _el$27);
1203
+ _$insertNode(_el$24, _el$28);
1204
+ _$insertNode(_el$24, _el$29);
1205
+ _$setProp(_el$24, "onMouseUp", () => toggleExpand(entry.id));
1206
+ _$insert(_el$25, () => isExpanded() ? "\u25BC" : "\u25B6");
1207
+ _$insert(_el$27, statusDot);
1208
+ _$insert(_el$29, labelText);
1209
+ _$insert(_el$24, (() => {
1210
+ var _c$2 = _$memo(() => !!timeText());
1211
+ return () => _c$2() ? [" ", (() => {
1212
+ var _el$80 = _$createElement("span");
1213
+ _$insert(_el$80, timeText);
1214
+ _$effect((_$p) => _$setProp(_el$80, "style", {
1215
+ fg: timeColor()
1216
+ }, _$p));
1217
+ return _el$80;
1218
+ })()] : null;
1219
+ })(), null);
1220
+ _$insert(_el$24, (() => {
1221
+ var _c$3 = _$memo(() => !!tokenText());
1222
+ return () => _c$3() ? (() => {
1223
+ var _el$81 = _$createElement("span");
1224
+ _$insert(_el$81, tokenText);
1225
+ _$effect((_$p) => _$setProp(_el$81, "style", {
1226
+ fg: pal().muted
1227
+ }, _$p));
1228
+ return _el$81;
1229
+ })() : null;
1230
+ })(), null);
1231
+ _$effect((_p$) => {
1232
+ var _v$3 = {
1233
+ fg: pal().muted
1234
+ }, _v$4 = {
1235
+ fg: statusColor()
1236
+ }, _v$5 = {
1237
+ fg: pal().text
1238
+ };
1239
+ _v$3 !== _p$.e && (_p$.e = _$setProp(_el$25, "style", _v$3, _p$.e));
1240
+ _v$4 !== _p$.t && (_p$.t = _$setProp(_el$27, "style", _v$4, _p$.t));
1241
+ _v$5 !== _p$.a && (_p$.a = _$setProp(_el$29, "style", _v$5, _p$.a));
1242
+ return _p$;
1243
+ }, {
1244
+ e: void 0,
1245
+ t: void 0,
1246
+ a: void 0
1247
+ });
1248
+ return _el$24;
1249
+ })(), _$createComponent(Show, {
1250
+ get when() {
1251
+ return isExpanded();
1252
+ },
1253
+ get children() {
1254
+ return [(() => {
1255
+ var _el$30 = _$createElement("text"), _el$31 = _$createTextNode(` `), _el$32 = _$createElement("span"), _el$33 = _$createTextNode(`: `), _el$34 = _$createElement("span"), _el$35 = _$createElement("span");
1256
+ _$insertNode(_el$30, _el$31);
1257
+ _$insertNode(_el$30, _el$32);
1258
+ _$insertNode(_el$30, _el$34);
1259
+ _$insertNode(_el$30, _el$35);
1260
+ _$insertNode(_el$32, _el$33);
1261
+ _$insert(_el$32, () => t("agent.label"), _el$33);
1262
+ _$insert(_el$34, () => " ".repeat(expandedPad(t("agent.label"))));
1263
+ _$insert(_el$35, () => entry.agent);
1264
+ _$effect((_p$) => {
1265
+ var _v$6 = {
1266
+ fg: pal().primary
1267
+ }, _v$7 = {
1268
+ fg: pal().muted
1269
+ }, _v$8 = {
1270
+ fg: pal().muted
1271
+ };
1272
+ _v$6 !== _p$.e && (_p$.e = _$setProp(_el$32, "style", _v$6, _p$.e));
1273
+ _v$7 !== _p$.t && (_p$.t = _$setProp(_el$34, "style", _v$7, _p$.t));
1274
+ _v$8 !== _p$.a && (_p$.a = _$setProp(_el$35, "style", _v$8, _p$.a));
1275
+ return _p$;
1276
+ }, {
1277
+ e: void 0,
1278
+ t: void 0,
1279
+ a: void 0
1280
+ });
1281
+ return _el$30;
1282
+ })(), (() => {
1283
+ var _el$36 = _$createElement("text"), _el$37 = _$createTextNode(` `), _el$38 = _$createElement("span"), _el$39 = _$createTextNode(`: `), _el$40 = _$createElement("span"), _el$41 = _$createElement("span");
1284
+ _$insertNode(_el$36, _el$37);
1285
+ _$insertNode(_el$36, _el$38);
1286
+ _$insertNode(_el$36, _el$40);
1287
+ _$insertNode(_el$36, _el$41);
1288
+ _$insertNode(_el$38, _el$39);
1289
+ _$insert(_el$38, () => t("status.label"), _el$39);
1290
+ _$insert(_el$40, () => " ".repeat(expandedPad(t("status.label"))));
1291
+ _$insert(_el$41, () => isRunning ? t("status.running") : isError ? t("status.error") : t("status.done"));
1292
+ _$effect((_p$) => {
1293
+ var _v$9 = {
1294
+ fg: pal().primary
1295
+ }, _v$0 = {
1296
+ fg: pal().muted
1297
+ }, _v$1 = {
1298
+ fg: isRunning ? pal().warning : isError ? pal().error : pal().success
1299
+ };
1300
+ _v$9 !== _p$.e && (_p$.e = _$setProp(_el$38, "style", _v$9, _p$.e));
1301
+ _v$0 !== _p$.t && (_p$.t = _$setProp(_el$40, "style", _v$0, _p$.t));
1302
+ _v$1 !== _p$.a && (_p$.a = _$setProp(_el$41, "style", _v$1, _p$.a));
1303
+ return _p$;
1304
+ }, {
1305
+ e: void 0,
1306
+ t: void 0,
1307
+ a: void 0
1308
+ });
1309
+ return _el$36;
1310
+ })(), _$createComponent(Show, {
1311
+ get when() {
1312
+ return elapsed() >= 2e3 || entry.endedAt !== void 0;
1313
+ },
1314
+ get children() {
1315
+ var _el$42 = _$createElement("text"), _el$43 = _$createTextNode(` `), _el$44 = _$createElement("span"), _el$45 = _$createTextNode(`: `), _el$46 = _$createElement("span"), _el$47 = _$createElement("span");
1316
+ _$insertNode(_el$42, _el$43);
1317
+ _$insertNode(_el$42, _el$44);
1318
+ _$insertNode(_el$42, _el$46);
1319
+ _$insertNode(_el$42, _el$47);
1320
+ _$insertNode(_el$44, _el$45);
1321
+ _$insert(_el$44, () => t("time.label"), _el$45);
1322
+ _$insert(_el$46, () => " ".repeat(expandedPad(t("time.label"))));
1323
+ _$insert(_el$47, () => fmtDurationShort(elapsed(), isRunning));
1324
+ _$effect((_p$) => {
1325
+ var _v$10 = {
1326
+ fg: pal().primary
1327
+ }, _v$11 = {
1328
+ fg: pal().muted
1329
+ }, _v$12 = {
1330
+ fg: pal().muted
1331
+ };
1332
+ _v$10 !== _p$.e && (_p$.e = _$setProp(_el$44, "style", _v$10, _p$.e));
1333
+ _v$11 !== _p$.t && (_p$.t = _$setProp(_el$46, "style", _v$11, _p$.t));
1334
+ _v$12 !== _p$.a && (_p$.a = _$setProp(_el$47, "style", _v$12, _p$.a));
1335
+ return _p$;
1336
+ }, {
1337
+ e: void 0,
1338
+ t: void 0,
1339
+ a: void 0
1340
+ });
1341
+ return _el$42;
1342
+ }
1343
+ }), _$createComponent(Show, {
1344
+ get when() {
1345
+ return entry.tokens !== void 0;
1346
+ },
1347
+ get children() {
1348
+ var _el$48 = _$createElement("text"), _el$49 = _$createTextNode(` `), _el$50 = _$createElement("span"), _el$51 = _$createTextNode(`: `), _el$52 = _$createElement("span"), _el$53 = _$createElement("span");
1349
+ _$insertNode(_el$48, _el$49);
1350
+ _$insertNode(_el$48, _el$50);
1351
+ _$insertNode(_el$48, _el$52);
1352
+ _$insertNode(_el$48, _el$53);
1353
+ _$insertNode(_el$50, _el$51);
1354
+ _$insert(_el$50, () => t("tokens.label"), _el$51);
1355
+ _$insert(_el$52, () => " ".repeat(expandedPad(t("tokens.label"))));
1356
+ _$insert(_el$53, () => fmtTokens(entry.tokens));
1357
+ _$effect((_p$) => {
1358
+ var _v$13 = {
1359
+ fg: pal().primary
1360
+ }, _v$14 = {
1361
+ fg: pal().muted
1362
+ }, _v$15 = {
1363
+ fg: pal().muted
1364
+ };
1365
+ _v$13 !== _p$.e && (_p$.e = _$setProp(_el$50, "style", _v$13, _p$.e));
1366
+ _v$14 !== _p$.t && (_p$.t = _$setProp(_el$52, "style", _v$14, _p$.t));
1367
+ _v$15 !== _p$.a && (_p$.a = _$setProp(_el$53, "style", _v$15, _p$.a));
1368
+ return _p$;
1369
+ }, {
1370
+ e: void 0,
1371
+ t: void 0,
1372
+ a: void 0
1373
+ });
1374
+ return _el$48;
1375
+ }
1376
+ }), _$createComponent(Show, {
1377
+ get when() {
1378
+ return entry.error;
1379
+ },
1380
+ get children() {
1381
+ var _el$54 = _$createElement("text"), _el$55 = _$createTextNode(` `), _el$56 = _$createElement("span"), _el$57 = _$createTextNode(`: `), _el$58 = _$createElement("span"), _el$59 = _$createElement("span");
1382
+ _$insertNode(_el$54, _el$55);
1383
+ _$insertNode(_el$54, _el$56);
1384
+ _$insertNode(_el$54, _el$58);
1385
+ _$insertNode(_el$54, _el$59);
1386
+ _$insertNode(_el$56, _el$57);
1387
+ _$insert(_el$56, () => t("error.label"), _el$57);
1388
+ _$insert(_el$58, () => " ".repeat(expandedPad(t("error.label"))));
1389
+ _$insert(_el$59, () => truncate(String(entry.error), expandedValAvail()));
1390
+ _$effect((_p$) => {
1391
+ var _v$16 = {
1392
+ fg: pal().error
1393
+ }, _v$17 = {
1394
+ fg: pal().muted
1395
+ }, _v$18 = {
1396
+ fg: pal().error
1397
+ };
1398
+ _v$16 !== _p$.e && (_p$.e = _$setProp(_el$56, "style", _v$16, _p$.e));
1399
+ _v$17 !== _p$.t && (_p$.t = _$setProp(_el$58, "style", _v$17, _p$.t));
1400
+ _v$18 !== _p$.a && (_p$.a = _$setProp(_el$59, "style", _v$18, _p$.a));
1401
+ return _p$;
1402
+ }, {
1403
+ e: void 0,
1404
+ t: void 0,
1405
+ a: void 0
1406
+ });
1407
+ return _el$54;
1408
+ }
1409
+ }), _$createComponent(Show, {
1410
+ get when() {
1411
+ return entry.cost !== void 0;
1412
+ },
1413
+ get children() {
1414
+ var _el$60 = _$createElement("text"), _el$61 = _$createTextNode(` `), _el$62 = _$createElement("span"), _el$63 = _$createTextNode(`: `), _el$64 = _$createElement("span"), _el$65 = _$createElement("span"), _el$66 = _$createTextNode(`$`);
1415
+ _$insertNode(_el$60, _el$61);
1416
+ _$insertNode(_el$60, _el$62);
1417
+ _$insertNode(_el$60, _el$64);
1418
+ _$insertNode(_el$60, _el$65);
1419
+ _$insertNode(_el$62, _el$63);
1420
+ _$insert(_el$62, () => t("cost.label"), _el$63);
1421
+ _$insert(_el$64, () => " ".repeat(expandedPad(t("cost.label"))));
1422
+ _$insertNode(_el$65, _el$66);
1423
+ _$insert(_el$65, () => entry.cost.toFixed(4), null);
1424
+ _$effect((_p$) => {
1425
+ var _v$19 = {
1426
+ fg: pal().primary
1427
+ }, _v$20 = {
1428
+ fg: pal().muted
1429
+ }, _v$21 = {
1430
+ fg: pal().muted
1431
+ };
1432
+ _v$19 !== _p$.e && (_p$.e = _$setProp(_el$62, "style", _v$19, _p$.e));
1433
+ _v$20 !== _p$.t && (_p$.t = _$setProp(_el$64, "style", _v$20, _p$.t));
1434
+ _v$21 !== _p$.a && (_p$.a = _$setProp(_el$65, "style", _v$21, _p$.a));
1435
+ return _p$;
1436
+ }, {
1437
+ e: void 0,
1438
+ t: void 0,
1439
+ a: void 0
1440
+ });
1441
+ return _el$60;
1442
+ }
1443
+ }), _$createComponent(Show, {
1444
+ get when() {
1445
+ return entry.model;
1446
+ },
1447
+ get children() {
1448
+ var _el$67 = _$createElement("text"), _el$68 = _$createTextNode(` `), _el$69 = _$createElement("span"), _el$70 = _$createTextNode(`: `), _el$71 = _$createElement("span"), _el$72 = _$createElement("span");
1449
+ _$insertNode(_el$67, _el$68);
1450
+ _$insertNode(_el$67, _el$69);
1451
+ _$insertNode(_el$67, _el$71);
1452
+ _$insertNode(_el$67, _el$72);
1453
+ _$insertNode(_el$69, _el$70);
1454
+ _$insert(_el$69, () => t("model.label"), _el$70);
1455
+ _$insert(_el$71, () => " ".repeat(expandedPad(t("model.label"))));
1456
+ _$insert(_el$72, () => truncate(entry.model, expandedValAvail()));
1457
+ _$effect((_p$) => {
1458
+ var _v$22 = {
1459
+ fg: pal().primary
1460
+ }, _v$23 = {
1461
+ fg: pal().muted
1462
+ }, _v$24 = {
1463
+ fg: pal().muted
1464
+ };
1465
+ _v$22 !== _p$.e && (_p$.e = _$setProp(_el$69, "style", _v$22, _p$.e));
1466
+ _v$23 !== _p$.t && (_p$.t = _$setProp(_el$71, "style", _v$23, _p$.t));
1467
+ _v$24 !== _p$.a && (_p$.a = _$setProp(_el$72, "style", _v$24, _p$.a));
1468
+ return _p$;
1469
+ }, {
1470
+ e: void 0,
1471
+ t: void 0,
1472
+ a: void 0
1473
+ });
1474
+ return _el$67;
1475
+ }
1476
+ }), _$createComponent(Show, {
1477
+ get when() {
1478
+ return entry.todoTotal !== void 0;
1479
+ },
1480
+ get children() {
1481
+ var _el$73 = _$createElement("text"), _el$74 = _$createTextNode(` `), _el$75 = _$createElement("span"), _el$76 = _$createTextNode(`: `), _el$77 = _$createElement("span"), _el$78 = _$createElement("span"), _el$79 = _$createTextNode(`/`);
1482
+ _$insertNode(_el$73, _el$74);
1483
+ _$insertNode(_el$73, _el$75);
1484
+ _$insertNode(_el$73, _el$77);
1485
+ _$insertNode(_el$73, _el$78);
1486
+ _$insertNode(_el$75, _el$76);
1487
+ _$insert(_el$75, () => t("todo.label"), _el$76);
1488
+ _$insert(_el$77, () => " ".repeat(expandedPad(t("todo.label"))));
1489
+ _$insertNode(_el$78, _el$79);
1490
+ _$insert(_el$78, () => entry.todoDone, _el$79);
1491
+ _$insert(_el$78, () => entry.todoTotal, null);
1492
+ _$effect((_p$) => {
1493
+ var _v$25 = {
1494
+ fg: pal().primary
1495
+ }, _v$26 = {
1496
+ fg: pal().muted
1497
+ }, _v$27 = {
1498
+ fg: pal().muted
1499
+ };
1500
+ _v$25 !== _p$.e && (_p$.e = _$setProp(_el$75, "style", _v$25, _p$.e));
1501
+ _v$26 !== _p$.t && (_p$.t = _$setProp(_el$77, "style", _v$26, _p$.t));
1502
+ _v$27 !== _p$.a && (_p$.a = _$setProp(_el$78, "style", _v$27, _p$.a));
1503
+ return _p$;
1504
+ }, {
1505
+ e: void 0,
1506
+ t: void 0,
1507
+ a: void 0
1508
+ });
1509
+ return _el$73;
1510
+ }
1511
+ }), _$createComponent(Show, {
1512
+ get when() {
1513
+ return entry.sessionId || isRunning;
1514
+ },
1515
+ get children() {
1516
+ return (() => {
1517
+ const dismissLabel = () => `- ${t("dismiss.label")}`;
1518
+ const openPrefix = () => " \u2192 ";
1519
+ const openFull = () => entry.sessionId ? openPrefix() + t("open.label") : "";
1520
+ const openW = () => entry.sessionId ? visualWidth(openFull()) : 0;
1521
+ const spacerW = () => Math.max(
1522
+ 1,
1523
+ panelWidth() - openW() - visualWidth(dismissLabel()) - 2
1524
+ /* indent */
1525
+ );
1526
+ return (() => {
1527
+ var _el$82 = _$createElement("box");
1528
+ _$setProp(_el$82, "flexDirection", "row");
1529
+ _$insert(_el$82, _$createComponent(Show, {
1530
+ get when() {
1531
+ return entry.sessionId;
1532
+ },
1533
+ get fallback() {
1534
+ return (() => {
1535
+ var _el$89 = _$createElement("text");
1536
+ _$insertNode(_el$89, _$createTextNode(` `));
1537
+ return _el$89;
1538
+ })();
1539
+ },
1540
+ get children() {
1541
+ var _el$83 = _$createElement("text"), _el$84 = _$createElement("span"), _el$85 = _$createElement("span");
1542
+ _$insertNode(_el$83, _el$84);
1543
+ _$insertNode(_el$83, _el$85);
1544
+ _$setProp(_el$83, "onMouseOver", () => setHoveredOpen(entry.id));
1545
+ _$setProp(_el$83, "onMouseOut", () => setHoveredOpen(void 0));
1546
+ _$setProp(_el$83, "onMouseUp", () => {
1547
+ if (entry.sessionId) {
1548
+ props.api.route.navigate("session", {
1549
+ sessionID: entry.sessionId
1550
+ });
1551
+ }
1552
+ });
1553
+ _$insert(_el$84, openPrefix);
1554
+ _$insert(_el$85, () => t("open.label"));
1555
+ _$effect((_p$) => {
1556
+ var _v$28 = {
1557
+ fg: hoveredOpen() === entry.id ? pal().warning : pal().primary
1558
+ }, _v$29 = {
1559
+ fg: hoveredOpen() === entry.id ? pal().warning : pal().primary
1560
+ };
1561
+ _v$28 !== _p$.e && (_p$.e = _$setProp(_el$84, "style", _v$28, _p$.e));
1562
+ _v$29 !== _p$.t && (_p$.t = _$setProp(_el$85, "style", _v$29, _p$.t));
1563
+ return _p$;
1564
+ }, {
1565
+ e: void 0,
1566
+ t: void 0
1567
+ });
1568
+ return _el$83;
1569
+ }
1570
+ }), null);
1571
+ _$insert(_el$82, _$createComponent(Show, {
1572
+ when: isRunning,
1573
+ get children() {
1574
+ return [(() => {
1575
+ var _el$86 = _$createElement("text");
1576
+ _$insert(_el$86, () => " ".repeat(spacerW()));
1577
+ _$effect((_$p) => _$setProp(_el$86, "style", {
1578
+ fg: pal().muted
1579
+ }, _$p));
1580
+ return _el$86;
1581
+ })(), (() => {
1582
+ var _el$87 = _$createElement("text"), _el$88 = _$createElement("span");
1583
+ _$insertNode(_el$87, _el$88);
1584
+ _$setProp(_el$87, "onMouseOver", () => setHoveredDismiss(entry.id));
1585
+ _$setProp(_el$87, "onMouseOut", () => setHoveredDismiss(void 0));
1586
+ _$setProp(_el$87, "onMouseUp", () => {
1587
+ upsertEntry({
1588
+ id: entry.id,
1589
+ title: entry.title,
1590
+ agent: entry.agent,
1591
+ prompt: entry.prompt,
1592
+ status: "done"
1593
+ });
1594
+ });
1595
+ _$insert(_el$88, dismissLabel);
1596
+ _$effect((_$p) => _$setProp(_el$88, "style", {
1597
+ fg: hoveredDismiss() === entry.id ? pal().warning : pal().muted
1598
+ }, _$p));
1599
+ return _el$87;
1600
+ })()];
1601
+ }
1602
+ }), null);
1603
+ return _el$82;
1604
+ })();
1605
+ })();
1606
+ }
1607
+ })];
1608
+ }
1609
+ })];
1610
+ }
1611
+ }), null);
1612
+ _$insert(_el$7, _$createComponent(Show, {
1613
+ get when() {
1614
+ return hiddenBelow() > 0 || scrollOffset() > 0;
1615
+ },
1616
+ get children() {
1617
+ return (() => {
1618
+ const showMore = hiddenBelow() > 0;
1619
+ const showTop = scrollOffset() > 0;
1620
+ const left = showMore ? ` \u2193 ${hiddenBelow()} ${t("scroll.more")}` : " ";
1621
+ const right = `\u2191 ${t("scroll.top")}`;
1622
+ const pad = showTop ? Math.max(1, panelWidth() - visualWidth(left) - visualWidth(right)) : 0;
1623
+ return (() => {
1624
+ var _el$91 = _$createElement("box"), _el$92 = _$createElement("text");
1625
+ _$insertNode(_el$91, _el$92);
1626
+ _$setProp(_el$91, "flexDirection", "row");
1627
+ _$insert(_el$92, left);
1628
+ _$insert(_el$91, showTop ? [(() => {
1629
+ var _el$93 = _$createElement("text");
1630
+ _$insert(_el$93, () => " ".repeat(pad));
1631
+ _$effect((_$p) => _$setProp(_el$93, "style", {
1632
+ fg: pal().muted
1633
+ }, _$p));
1634
+ return _el$93;
1635
+ })(), (() => {
1636
+ var _el$94 = _$createElement("text"), _el$95 = _$createElement("span");
1637
+ _$insertNode(_el$94, _el$95);
1638
+ _$setProp(_el$94, "onMouseOver", () => setHoveredTop(true));
1639
+ _$setProp(_el$94, "onMouseOut", () => setHoveredTop(false));
1640
+ _$setProp(_el$94, "onMouseUp", () => {
1641
+ setScrollOffset(0);
1642
+ setHoveredTop(false);
1643
+ });
1644
+ _$insert(_el$95, right);
1645
+ _$effect((_$p) => _$setProp(_el$95, "style", {
1646
+ fg: hoveredTop() ? pal().warning : pal().muted
1647
+ }, _$p));
1648
+ return _el$94;
1649
+ })()] : null, null);
1650
+ _$effect((_$p) => _$setProp(_el$92, "style", {
1651
+ fg: pal().muted
1652
+ }, _$p));
1653
+ return _el$91;
1654
+ })();
1655
+ })();
1656
+ }
1657
+ }), null);
1658
+ return _el$7;
1659
+ }
1660
+ })];
1661
+ }
1662
+ }), null);
1663
+ _$effect((_p$) => {
1664
+ var _v$ = {
1665
+ fg: pal().muted
1666
+ }, _v$2 = {
1667
+ fg: pal().primary
1668
+ };
1669
+ _v$ !== _p$.e && (_p$.e = _$setProp(_el$3, "style", _v$, _p$.e));
1670
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$4, "style", _v$2, _p$.t));
1671
+ return _p$;
1672
+ }, {
1673
+ e: void 0,
1674
+ t: void 0
1675
+ });
1676
+ return _el$;
1677
+ })();
1678
+ }
1679
+ function createSidebarSlot(api, sig) {
1680
+ return {
1681
+ order: 60,
1682
+ slots: {
1683
+ sidebar_content(ctx, input) {
1684
+ sig.sessionId = input.session_id;
1685
+ return _$createComponent(SubAgentPanel, {
1686
+ get theme() {
1687
+ return ctx.theme.current;
1688
+ },
1689
+ api,
1690
+ get lang() {
1691
+ return sig.lang;
1692
+ },
1693
+ get maxEntries() {
1694
+ return sig.maxEntries;
1695
+ },
1696
+ get sessionId() {
1697
+ return input.session_id;
1698
+ }
1699
+ });
1700
+ }
1701
+ }
1702
+ };
1703
+ }
1704
+ var KV_PREFIX = "subagent_magazine";
1705
+ var tui = async (api) => {
1706
+ const stored = String(api.kv.get(`${KV_PREFIX}.lang`, ""));
1707
+ const initialLang = stored === "zh" || stored === "en" ? stored : detectLang();
1708
+ const [lang, setLang] = createSignal(initialLang);
1709
+ const [maxEntries, setMaxEntries] = createSignal(parseInt(String(api.kv.get(`${KV_PREFIX}.max_entries`, "10")), 10) || 10);
1710
+ const signals = {
1711
+ lang,
1712
+ setLang,
1713
+ maxEntries,
1714
+ setMaxEntries,
1715
+ sessionId: ""
1716
+ };
1717
+ api.slots.register(createSidebarSlot(api, signals));
1718
+ api.command?.register(() => [{
1719
+ title: "SubAgent Magazine: Language",
1720
+ value: "subagent-lang",
1721
+ description: "Switch display language (\u4E2D\u6587 / English)",
1722
+ slash: {
1723
+ name: "subagent-lang"
1724
+ },
1725
+ onSelect: (dialog) => {
1726
+ dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
1727
+ title: "Language / \u8BED\u8A00",
1728
+ options: [{
1729
+ title: "\u4E2D\u6587",
1730
+ value: "zh"
1731
+ }, {
1732
+ title: "English",
1733
+ value: "en"
1734
+ }],
1735
+ onSelect: (opt) => {
1736
+ const l = opt.value;
1737
+ setLang(l);
1738
+ api.kv.set(`${KV_PREFIX}.lang`, l);
1739
+ api.ui.toast({
1740
+ message: l === "zh" ? "\u8BED\u8A00: \u4E2D\u6587" : "Language: English"
1741
+ });
1742
+ dialog?.clear();
1743
+ }
1744
+ }));
1745
+ }
1746
+ }, {
1747
+ title: "SubAgent Magazine: Max Entries",
1748
+ value: "subagent-max",
1749
+ description: "Set max visible sub-agent entries in sidebar",
1750
+ slash: {
1751
+ name: "subagent-max"
1752
+ },
1753
+ onSelect: (dialog) => {
1754
+ dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
1755
+ title: "Max Visible Entries",
1756
+ description: () => (() => {
1757
+ var _el$96 = _$createElement("text");
1758
+ _$insertNode(_el$96, _$createTextNode(`Number of entries to show in the sidebar (1\u201350)`));
1759
+ return _el$96;
1760
+ })(),
1761
+ get value() {
1762
+ return String(maxEntries());
1763
+ },
1764
+ onConfirm: (val) => {
1765
+ const n = Math.max(1, Math.min(50, parseInt(val, 10) || 10));
1766
+ setMaxEntries(n);
1767
+ api.kv.set(`${KV_PREFIX}.max_entries`, n);
1768
+ api.ui.toast({
1769
+ message: `Max entries: ${n}`
1770
+ });
1771
+ dialog?.clear();
1772
+ }
1773
+ }));
1774
+ }
1775
+ }, {
1776
+ title: "SubAgent Magazine: Version",
1777
+ value: "subagent-version",
1778
+ description: "Show plugin version",
1779
+ slash: {
1780
+ name: "subagent-version"
1781
+ },
1782
+ onSelect: (dialog) => {
1783
+ api.ui.toast({
1784
+ message: `opencode-subagent-magazine v${PLUGIN_VERSION}`
1785
+ });
1786
+ dialog?.clear();
1787
+ }
1788
+ }, {
1789
+ title: "SubAgent Magazine: Session",
1790
+ value: "subagent-session",
1791
+ description: "Show current session ID",
1792
+ slash: {
1793
+ name: "subagent-session"
1794
+ },
1795
+ onSelect: (dialog) => {
1796
+ api.ui.toast({
1797
+ message: `Session: ${signals.sessionId}`
1798
+ });
1799
+ dialog?.clear();
1800
+ }
1801
+ }, {
1802
+ title: "SubAgent Magazine: Clear Running",
1803
+ value: "subagent-clear-running",
1804
+ description: "Mark all running sub-agent entries as done (for stuck/zombie entries)",
1805
+ slash: {
1806
+ name: "subagent-clear-running"
1807
+ },
1808
+ onSelect: (dialog) => {
1809
+ const entries = globalEntryCache.get(signals.sessionId);
1810
+ if (!entries || entries.size === 0) {
1811
+ const msg = signals.lang() === "zh" ? "\u6682\u65E0\u5B50\u4EE3\u7406\u6761\u76EE" : "No sub-agent entries found";
1812
+ api.ui.toast({
1813
+ message: msg
1814
+ });
1815
+ dialog?.clear();
1816
+ return;
1817
+ }
1818
+ let count = 0;
1819
+ for (const [, entry] of entries) {
1820
+ if (entry.status === "running") {
1821
+ entry.status = "done";
1822
+ entry.endedAt = Date.now();
1823
+ count++;
1824
+ }
1825
+ }
1826
+ if (count > 0) {
1827
+ try {
1828
+ const data = JSON.parse(String(api.kv.get(`${KV_PREFIX}.session_data`, "{}")));
1829
+ data[signals.sessionId] = {
1830
+ ts: Date.now(),
1831
+ entries: [...entries.values()],
1832
+ scroll: data[signals.sessionId]?.scroll ?? 0,
1833
+ expanded: data[signals.sessionId]?.expanded ?? ""
1834
+ };
1835
+ api.kv.set(`${KV_PREFIX}.session_data`, JSON.stringify(data));
1836
+ } catch {
1837
+ }
1838
+ const msg = signals.lang() === "zh" ? `\u5DF2\u6807\u8BB0 ${count} \u4E2A\u8FD0\u884C\u4E2D\u7684\u6761\u76EE\u4E3A\u5B8C\u6210` : `Marked ${count} running entries as done`;
1839
+ api.ui.toast({
1840
+ message: msg
1841
+ });
1842
+ } else {
1843
+ const msg = signals.lang() === "zh" ? "\u6CA1\u6709\u9700\u8981\u6E05\u7406\u7684\u8FD0\u884C\u4E2D\u6761\u76EE" : "No running entries to clear";
1844
+ api.ui.toast({
1845
+ message: msg
1846
+ });
1847
+ }
1848
+ dialog?.clear();
1849
+ }
1850
+ }]);
1851
+ };
1852
+ var mod = {
1853
+ id: "opencode-subagent-magazine",
1854
+ tui
1855
+ };
1856
+ var index_default = mod;
1857
+ export {
1858
+ index_default as default
1859
+ };