opencode-subagent-magazine 1.5.2 → 1.6.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +192 -192
  3. package/dist/_version.d.ts +1 -1
  4. package/dist/_version.js +1 -1
  5. package/dist/core/color.d.ts +20 -0
  6. package/dist/core/color.js +68 -0
  7. package/dist/core/format.d.ts +5 -0
  8. package/dist/core/format.js +68 -0
  9. package/dist/core/index.d.ts +6 -0
  10. package/dist/core/index.js +6 -0
  11. package/dist/core/kv.d.ts +20 -0
  12. package/dist/core/kv.js +30 -0
  13. package/dist/core/state-machine.d.ts +17 -0
  14. package/dist/core/state-machine.js +27 -0
  15. package/dist/core/types.d.ts +51 -0
  16. package/dist/core/types.js +2 -0
  17. package/dist/core/usage.d.ts +15 -0
  18. package/dist/core/usage.js +1 -0
  19. package/dist/index.js +148 -1484
  20. package/dist/panel/SubAgentPanel.d.ts +13 -0
  21. package/dist/panel/SubAgentPanel.js +1237 -0
  22. package/dist/panel/panel-api.d.ts +67 -0
  23. package/dist/panel/panel-api.js +1 -0
  24. package/dist/panel/store.d.ts +5 -0
  25. package/dist/panel/store.js +5 -0
  26. package/dist/tui.js +388 -292
  27. package/dist/v2/commands.d.ts +7 -0
  28. package/dist/v2/commands.js +263 -0
  29. package/dist/v2/index.d.ts +8 -0
  30. package/dist/v2/index.js +62 -0
  31. package/dist/v2/theme.d.ts +3 -0
  32. package/dist/v2/theme.js +12 -0
  33. package/dist/v2/types.d.ts +231 -0
  34. package/dist/v2/types.js +6 -0
  35. package/dist/v2/v2-panel-api.d.ts +12 -0
  36. package/dist/v2/v2-panel-api.js +350 -0
  37. package/dist/v2.js +3008 -0
  38. package/install.mjs +103 -103
  39. package/package.json +64 -63
  40. package/src/_version.ts +1 -1
  41. package/src/clipboard.ts +134 -134
  42. package/src/core/color.ts +70 -0
  43. package/src/core/format.ts +61 -0
  44. package/src/core/index.ts +6 -0
  45. package/src/core/kv.ts +36 -0
  46. package/src/core/state-machine.ts +46 -0
  47. package/src/core/types.ts +58 -0
  48. package/src/core/usage.ts +16 -0
  49. package/src/i18n.ts +261 -261
  50. package/src/index.tsx +124 -1750
  51. package/src/panel/SubAgentPanel.tsx +1465 -0
  52. package/src/panel/panel-api.ts +72 -0
  53. package/src/panel/store.ts +8 -0
  54. package/src/server.ts +10 -10
  55. package/src/v2/commands.ts +251 -0
  56. package/src/v2/index.tsx +98 -0
  57. package/src/v2/theme.ts +14 -0
  58. package/src/v2/types.ts +165 -0
  59. package/src/v2/v2-panel-api.ts +306 -0
  60. package/tui/index.js +11 -0
package/dist/v2.js ADDED
@@ -0,0 +1,3008 @@
1
+ // src/v2/index.tsx
2
+ import { createComponent as _$createComponent2 } from "@opentui/solid";
3
+ import { createSignal as createSignal3 } from "solid-js";
4
+
5
+ // src/v2/v2-panel-api.ts
6
+ var SUBAGENT_TOOL_V2 = "subagent";
7
+ function normalizeMeta(meta) {
8
+ const m = meta && typeof meta === "object" ? { ...meta } : {};
9
+ if (m.sessionID !== void 0) {
10
+ if (m.session_id === void 0) m.session_id = m.sessionID;
11
+ if (m.sessionId === void 0) m.sessionId = m.sessionID;
12
+ }
13
+ return m;
14
+ }
15
+ function toV1Part(p) {
16
+ if (p.type === "tool") {
17
+ const st = { ...p.state ?? {} };
18
+ if (st.output === void 0 && Array.isArray(st.content)) {
19
+ st.output = st.content.map((c) => c.type === "text" ? c.text : c.type === "file" ? String(c.path ?? c.filename ?? "") : JSON.stringify(c)).filter((t) => typeof t === "string" && t.length > 0).join("\n");
20
+ }
21
+ return { type: "tool", tool: p.tool ?? p.name, state: st, subagent_type: p.subagent_type, metadata: normalizeMeta(p.metadata) };
22
+ }
23
+ if (p.type === "text") return { type: "text", text: String(p.text ?? "") };
24
+ if (p.type === "file") return { type: "file", source: p.source ?? {} };
25
+ if (p.type === "reasoning") return { type: "reasoning", text: String(p.text ?? "") };
26
+ return p;
27
+ }
28
+ function createPanelApi(context, settings) {
29
+ const kvStore = /* @__PURE__ */ new Map();
30
+ const messageIndex = /* @__PURE__ */ new Map();
31
+ const toolInfo = /* @__PURE__ */ new Map();
32
+ const kvGet = (key, fallback) => {
33
+ let entry = kvStore.get(key);
34
+ if (!entry) {
35
+ const created = context.storage.store(`subagent_magazine.${key}`, {
36
+ initial: { value: fallback }
37
+ });
38
+ entry = created;
39
+ kvStore.set(key, entry);
40
+ }
41
+ const v = entry[0].value;
42
+ return v === void 0 ? fallback : v;
43
+ };
44
+ const kvSet = (key, value) => {
45
+ let entry = kvStore.get(key);
46
+ if (!entry) {
47
+ const created = context.storage.store(`subagent_magazine.${key}`, {
48
+ initial: { value }
49
+ });
50
+ entry = created;
51
+ kvStore.set(key, entry);
52
+ }
53
+ const [, mutate] = entry;
54
+ return mutate((d) => {
55
+ d.value = value;
56
+ });
57
+ };
58
+ const isSubagentTool = (name) => name === SUBAGENT_TOOL_V2 || name === "task" || name === "delegate" || name === "call_omo_agent";
59
+ const toolEventToPart = (event) => {
60
+ const type = event.type;
61
+ const data = event.data;
62
+ if (!data) return void 0;
63
+ const key = data.assistantMessageID !== void 0 ? `${String(data.assistantMessageID)}\0${String(data.id)}` : void 0;
64
+ const info = key ? toolInfo.get(key) : void 0;
65
+ const normName = (n) => n === SUBAGENT_TOOL_V2 ? "task" : n;
66
+ const agentOf = (input) => {
67
+ const i = input && typeof input === "object" ? input : {};
68
+ return typeof i.agent === "string" ? i.agent : void 0;
69
+ };
70
+ if (type === "session.tool.input.started") {
71
+ if (!isSubagentTool(data.name)) return void 0;
72
+ if (key) toolInfo.set(key, { name: String(data.name), input: {} });
73
+ return { type: "tool", tool: normName(String(data.name)), id: String(data.id), state: { status: "pending", input: {} } };
74
+ }
75
+ if (type === "session.tool.called") {
76
+ const name = data.name ?? info?.name;
77
+ if (name && !isSubagentTool(name)) return void 0;
78
+ if (!name) return void 0;
79
+ if (key) toolInfo.set(key, { name: String(name), input: data.input ?? {} });
80
+ return {
81
+ type: "tool",
82
+ tool: normName(String(name)),
83
+ id: String(data.id),
84
+ subagent_type: agentOf(data.input),
85
+ state: { status: "running", input: data.input ?? {}, metadata: {} }
86
+ };
87
+ }
88
+ if (type === "session.tool.progress") {
89
+ const name = data.name ?? info?.name;
90
+ if (name && !isSubagentTool(name)) return void 0;
91
+ if (!name) return void 0;
92
+ return {
93
+ type: "tool",
94
+ tool: normName(String(name)),
95
+ id: String(data.id),
96
+ subagent_type: agentOf(info?.input),
97
+ state: { status: "running", input: info?.input ?? {}, metadata: normalizeMeta(data.metadata) }
98
+ };
99
+ }
100
+ if (type === "session.tool.success" || type === "session.tool.failed") {
101
+ const meta = normalizeMeta(data.metadata);
102
+ if (meta.sessionID === void 0) return void 0;
103
+ if (type === "session.tool.failed" && meta.status === "running") return void 0;
104
+ const name = data.name ?? info?.name;
105
+ if (name && !isSubagentTool(name)) return void 0;
106
+ const input = info?.input ?? data.input ?? {};
107
+ return {
108
+ type: "tool",
109
+ tool: normName(String(name ?? "task")),
110
+ id: String(data.id),
111
+ subagent_type: agentOf(input),
112
+ state: {
113
+ status: type === "session.tool.failed" ? "error" : "completed",
114
+ input,
115
+ metadata: meta
116
+ }
117
+ };
118
+ }
119
+ return void 0;
120
+ };
121
+ const normalizeMessages = (sid) => {
122
+ const raw = context.data.session.message.list(sid) ?? [];
123
+ const out = [];
124
+ for (const m of raw) {
125
+ const record = m;
126
+ messageIndex.set(String(m.id), record);
127
+ const model = m.model ?? (typeof m.model === "string" ? { id: m.model } : void 0);
128
+ out.push({
129
+ ...m,
130
+ role: m.type === "assistant" ? "assistant" : m.type === "user" ? "user" : m.type,
131
+ modelID: model?.id
132
+ });
133
+ }
134
+ return out;
135
+ };
136
+ return {
137
+ kv: {
138
+ get: kvGet,
139
+ set: kvSet
140
+ },
141
+ usage: {
142
+ readSessionTokens: (sid) => {
143
+ if (!sid) return void 0;
144
+ try {
145
+ const msgs = context.data.session.message.list(sid);
146
+ if (msgs) {
147
+ for (let i = msgs.length - 1; i >= 0; i--) {
148
+ const m = msgs[i];
149
+ if (m.type !== "assistant") continue;
150
+ const t = m.tokens;
151
+ if (!t || !(Number(t.output) > 0)) continue;
152
+ const ctx = (Number(t.input) || 0) + (Number(t.output) || 0) + (Number(t.reasoning) || 0) + (Number(t.cache?.read) || 0) + (Number(t.cache?.write) || 0);
153
+ if (ctx > 0) return ctx;
154
+ }
155
+ }
156
+ return void 0;
157
+ } catch {
158
+ return void 0;
159
+ }
160
+ },
161
+ readSessionCost: (sid) => {
162
+ if (!sid) return void 0;
163
+ try {
164
+ const session = context.data.session.get(sid);
165
+ if (session?.cost != null && session.cost > 0) return session.cost;
166
+ const msgs = context.data.session.message.list(sid);
167
+ if (!msgs) return void 0;
168
+ let total = 0;
169
+ for (const m of msgs) {
170
+ if (m.type === "assistant" && typeof m.cost === "number") total += m.cost;
171
+ }
172
+ return total > 0 ? total : void 0;
173
+ } catch {
174
+ return void 0;
175
+ }
176
+ },
177
+ readSessionModel: (sid) => {
178
+ if (!sid) return void 0;
179
+ try {
180
+ const msgs = context.data.session.message.list(sid);
181
+ if (msgs) {
182
+ for (let i = msgs.length - 1; i >= 0; i--) {
183
+ const m = msgs[i];
184
+ if (m.type !== "assistant") continue;
185
+ const model = m.model;
186
+ if (typeof model === "string") return model;
187
+ if (model?.id) return String(model.id);
188
+ }
189
+ }
190
+ return void 0;
191
+ } catch {
192
+ return void 0;
193
+ }
194
+ },
195
+ readSessionTodo: () => void 0
196
+ // V2 无 todo 数据源
197
+ },
198
+ session: {
199
+ get: (sid) => {
200
+ try {
201
+ return context.data.session.get(sid);
202
+ } catch {
203
+ return void 0;
204
+ }
205
+ },
206
+ status: (sid) => {
207
+ try {
208
+ const st = context.data.session.status(sid);
209
+ const type = st === "running" ? "busy" : st ?? "";
210
+ return { type };
211
+ } catch {
212
+ return void 0;
213
+ }
214
+ },
215
+ messages: (sid) => {
216
+ try {
217
+ return normalizeMessages(sid);
218
+ } catch {
219
+ return void 0;
220
+ }
221
+ },
222
+ part: (messageID) => {
223
+ const msg = messageIndex.get(String(messageID));
224
+ if (!msg) return void 0;
225
+ if (!Array.isArray(msg.content) || msg.content.length === 0) {
226
+ if (typeof msg.text === "string" && msg.text.length > 0) {
227
+ return [{ type: "text", text: msg.text }];
228
+ }
229
+ return [];
230
+ }
231
+ return msg.content.map((p) => toV1Part(p));
232
+ }
233
+ },
234
+ event: {
235
+ on: (type, cb) => {
236
+ switch (type) {
237
+ case "part.updated": {
238
+ const unsubs = [];
239
+ for (const evt of ["session.tool.input.started", "session.tool.called", "session.tool.progress", "session.tool.success", "session.tool.failed"]) {
240
+ unsubs.push(context.data.on(evt, (e) => {
241
+ const part = toolEventToPart(e);
242
+ if (!part) return;
243
+ const evt2 = e.data;
244
+ const sid = evt2?.sessionID !== void 0 ? String(evt2.sessionID) : void 0;
245
+ cb({ type, payload: { part, sessionID: sid } });
246
+ }));
247
+ }
248
+ return () => {
249
+ for (const u of unsubs) u();
250
+ };
251
+ }
252
+ case "message.updated": {
253
+ const unsubs = [];
254
+ for (const evt of ["session.step.started", "session.step.ended", "session.step.failed"]) {
255
+ unsubs.push(context.data.on(evt, () => cb({ type })));
256
+ }
257
+ return () => {
258
+ for (const u of unsubs) u();
259
+ };
260
+ }
261
+ case "session.idle": {
262
+ const unsubs = [];
263
+ for (const evt of ["session.execution.succeeded", "session.execution.interrupted"]) {
264
+ unsubs.push(context.data.on(evt, (e) => {
265
+ const sid = String(e.data?.sessionID ?? "");
266
+ if (sid) cb({ type, payload: { sessionID: sid } });
267
+ }));
268
+ }
269
+ return () => {
270
+ for (const u of unsubs) u();
271
+ };
272
+ }
273
+ case "session.error":
274
+ return context.data.on("session.execution.failed", (e) => {
275
+ const evt = e.data;
276
+ const sid = String(evt?.sessionID ?? "");
277
+ if (sid) cb({ type, payload: { sessionID: sid, error: evt?.error } });
278
+ });
279
+ default:
280
+ return () => {
281
+ };
282
+ }
283
+ }
284
+ },
285
+ client: {
286
+ // V2 官方取消途径:context.client.session.interrupt(data.session 无 interrupt)
287
+ abort: ({ sessionID }) => context.client.session.interrupt({ sessionID }).then(() => {
288
+ })
289
+ },
290
+ route: {
291
+ navigateSession: (sessionID) => context.ui.router.navigate({ type: "session", sessionID })
292
+ },
293
+ ui: {
294
+ toast: (message, opts) => context.ui.toast.show({ message, title: opts?.title, variant: opts?.variant })
295
+ },
296
+ settings
297
+ };
298
+ }
299
+
300
+ // src/core/kv.ts
301
+ var KV_PREFIX = "subagent_magazine";
302
+ var SESSION_DATA_KEY = `${KV_PREFIX}.session_data`;
303
+ var SETTING_KEYS = {
304
+ lang: `${KV_PREFIX}.lang`,
305
+ maxEntries: `${KV_PREFIX}.max_entries`,
306
+ order: `${KV_PREFIX}.order`,
307
+ scrollMode: `${KV_PREFIX}.scroll_mode`,
308
+ open: `${KV_PREFIX}.open`,
309
+ ttlDays: `${KV_PREFIX}.ttl_days`
310
+ };
311
+ function loadSessionData(kv) {
312
+ try {
313
+ const raw = kv.get(SESSION_DATA_KEY, "{}");
314
+ return JSON.parse(String(raw));
315
+ } catch {
316
+ return {};
317
+ }
318
+ }
319
+ function saveSessionData(kv, data) {
320
+ try {
321
+ kv.set(SESSION_DATA_KEY, JSON.stringify(data));
322
+ } catch {
323
+ }
324
+ }
325
+ function readTTLDays(kv) {
326
+ const ttlDaysRaw = parseInt(String(kv.get(SETTING_KEYS.ttlDays, "3")), 10);
327
+ return Number.isNaN(ttlDaysRaw) ? 3 : ttlDaysRaw;
328
+ }
329
+
330
+ // src/_version.ts
331
+ var PLUGIN_VERSION = "1.6.0-beta.1";
332
+
333
+ // src/i18n.ts
334
+ var ZH_T = {
335
+ "panel.title": "\u5B50\u4EE3\u7406",
336
+ "status.none": "\u6682\u65E0\u5B50\u4EE3\u7406",
337
+ "agent.label": "\u4EE3\u7406",
338
+ "status.label": "\u72B6\u6001",
339
+ "time.label": "\u8017\u65F6",
340
+ "tokens.label": "\u4E0A\u4E0B\u6587",
341
+ "error.label": "\u9519\u8BEF",
342
+ "model.label": "\u6A21\u578B",
343
+ "todo.label": "\u8FDB\u5EA6",
344
+ "session.label": "\u4F1A\u8BDD ID",
345
+ "session.toast.copy": "\u53EF\u624B\u52A8\u590D\u5236\u4E0A\u65B9 ID",
346
+ "session.toast.copied": "\u4F1A\u8BDD ID \u5DF2\u590D\u5236",
347
+ "session.toast.copy_failed": "\u65E0\u6CD5\u8BBF\u95EE\u7CFB\u7EDF\u526A\u8D34\u677F\uFF0C\u8BF7\u624B\u52A8\u590D\u5236\u4E0A\u65B9 ID",
348
+ "open.label": "\u8FDB\u5165\u4F1A\u8BDD",
349
+ "cost.label": "\u8D39\u7528",
350
+ "scroll.more": "\u66F4\u591A",
351
+ "scroll.top": "\u56DE\u9876",
352
+ "scroll.bottom": "\u56DE\u5E95",
353
+ "dismiss.label": "\u6807\u8BB0\u5B8C\u6210",
354
+ "cancel.label": "\u53D6\u6D88",
355
+ "status.running": "\u8FD0\u884C\u4E2D",
356
+ "status.done": "\u5DF2\u5B8C\u6210",
357
+ "status.cancelled": "\u5DF2\u53D6\u6D88",
358
+ "status.error": "\u9519\u8BEF",
359
+ "order.desc": "\u964D\u5E8F\uFF08\u6700\u65B0\u5728\u524D\uFF09",
360
+ "order.asc": "\u5347\u5E8F\uFF08\u6700\u65E9\u5728\u524D\uFF09",
361
+ "scroll.wheel": "\u6EDA\u8F6E\u7FFB\u9875",
362
+ "scroll.click": "\u70B9\u51FB\u7FFB\u9875",
363
+ "ttl.label": "\u6E05\u7406\u5468\u671F",
364
+ "ttl.3d": "3 \u5929",
365
+ "ttl.7d": "7 \u5929",
366
+ "ttl.14d": "14 \u5929",
367
+ "ttl.30d": "30 \u5929",
368
+ "ttl.unlimited": "\u65E0\u671F\u9650",
369
+ "ttl.toast": "\u6E05\u7406\u5468\u671F\u5DF2\u8BBE\u4E3A {n} \u5929",
370
+ "ttl.toast_unlimited": "\u6E05\u7406\u5468\u671F\u5DF2\u8BBE\u4E3A\u65E0\u671F\u9650",
371
+ "clear.title": "\u786E\u8BA4\u6E05\u9664",
372
+ "clear.prompt": "\u786E\u5B9A\u6E05\u9664\u5F53\u524D\u4F1A\u8BDD\u6240\u6709\u5B50\u4EE3\u7406\u8BB0\u5F55\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u64A4\u9500\u3002",
373
+ "clear.prompt_running": "\u5F53\u524D\u6709 {n} \u4E2A\u8FD0\u884C\u4E2D\u7684\u5B50\u4EE3\u7406\uFF0C\u6E05\u9664\u540E\u5C06\u4E0D\u53EF\u6062\u590D\u3002\u786E\u5B9A\u7EE7\u7EED\uFF1F",
374
+ "clear.done": "\u5DF2\u6E05\u9664 {n} \u6761\u5B50\u4EE3\u7406\u8BB0\u5F55",
375
+ "clear.empty": "\u5F53\u524D\u4F1A\u8BDD\u65E0\u5B50\u4EE3\u7406\u8BB0\u5F55",
376
+ "cancel.no_session": "\u5B50\u4F1A\u8BDD ID \u4E0D\u53EF\u7528",
377
+ "cancel.not_child": "\u76EE\u6807\u4E0D\u662F\u5B50\u4F1A\u8BDD",
378
+ "cancel.read_error": "\u65E0\u6CD5\u8BFB\u53D6\u4F1A\u8BDD\u4FE1\u606F",
379
+ "cancel.outside_tree": "\u76EE\u6807\u4E0D\u5728\u5F53\u524D\u76D1\u63A7\u4F1A\u8BDD\u6811\u4E2D",
380
+ "cancel.already_ended": "\u4F1A\u8BDD\u5DF2\u7ED3\u675F\uFF0C\u65E0\u9700\u53D6\u6D88",
381
+ "cancel.status_error": "\u65E0\u6CD5\u67E5\u8BE2\u4F1A\u8BDD\u72B6\u6001",
382
+ "cancel.sent": "\u5DF2\u53D1\u9001\u53D6\u6D88\u6307\u4EE4",
383
+ "cancel.failed": "\u53D6\u6D88\u5931\u8D25"
384
+ };
385
+ var EN_T = {
386
+ "panel.title": "SubAgent",
387
+ "status.none": "No sub-agents yet",
388
+ "agent.label": "agent",
389
+ "status.label": "status",
390
+ "time.label": "time",
391
+ "tokens.label": "tokens",
392
+ "error.label": "error",
393
+ "model.label": "model",
394
+ "todo.label": "todo",
395
+ "session.label": "session ID",
396
+ "session.toast.copy": "Copy the ID above manually",
397
+ "session.toast.copied": "Session ID copied",
398
+ "session.toast.copy_failed": "Cannot access the system clipboard; copy the ID above manually",
399
+ "open.label": "Open session",
400
+ "cost.label": "cost",
401
+ "scroll.more": "more",
402
+ "scroll.top": "Top",
403
+ "scroll.bottom": "Bottom",
404
+ "dismiss.label": "dismiss",
405
+ "cancel.label": "Cancel",
406
+ "status.running": "running",
407
+ "status.done": "done",
408
+ "status.cancelled": "cancelled",
409
+ "status.error": "error",
410
+ "order.desc": "Desc (newest first)",
411
+ "order.asc": "Asc (oldest first)",
412
+ "scroll.wheel": "Wheel Scroll",
413
+ "scroll.click": "Click Scroll",
414
+ "ttl.label": "TTL (Time to Live)",
415
+ "ttl.3d": "3 days",
416
+ "ttl.7d": "7 days",
417
+ "ttl.14d": "14 days",
418
+ "ttl.30d": "30 days",
419
+ "ttl.unlimited": "Never",
420
+ "ttl.toast": "TTL set to {n} days",
421
+ "ttl.toast_unlimited": "TTL set to Never",
422
+ "clear.title": "Confirm",
423
+ "clear.prompt": "Clear all sub-agent records for this session? This cannot be undone.",
424
+ "clear.prompt_running": "{n} sub-agent(s) are still running. Clearing will discard them permanently. Continue?",
425
+ "clear.done": "Cleared {n} sub-agent record(s)",
426
+ "clear.empty": "No sub-agent records in this session",
427
+ "cancel.no_session": "Child session ID is unavailable",
428
+ "cancel.not_child": "Target is not a child session",
429
+ "cancel.read_error": "Cannot read session info",
430
+ "cancel.outside_tree": "Target is outside the monitored session tree",
431
+ "cancel.already_ended": "Session already ended, no need to cancel",
432
+ "cancel.status_error": "Cannot query session status",
433
+ "cancel.sent": "Cancel instruction sent",
434
+ "cancel.failed": "Cancellation failed"
435
+ };
436
+ var JA_T = {
437
+ "panel.title": "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
438
+ "status.none": "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u306A\u3057",
439
+ "agent.label": "\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
440
+ "status.label": "\u72B6\u614B",
441
+ "time.label": "\u6642\u9593",
442
+ "tokens.label": "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8",
443
+ "error.label": "\u30A8\u30E9\u30FC",
444
+ "model.label": "\u30E2\u30C7\u30EB",
445
+ "todo.label": "\u9032\u6357",
446
+ "session.label": "\u30BB\u30C3\u30B7\u30E7\u30F3 ID",
447
+ "session.toast.copy": "\u4E0A\u306E ID \u3092\u624B\u52D5\u3067\u30B3\u30D4\u30FC\u3057\u3066\u304F\u3060\u3055\u3044",
448
+ "session.toast.copied": "\u30BB\u30C3\u30B7\u30E7\u30F3 ID \u3092\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F",
449
+ "session.toast.copy_failed": "\u30B7\u30B9\u30C6\u30E0\u306E\u30AF\u30EA\u30C3\u30D7\u30DC\u30FC\u30C9\u306B\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u306A\u3044\u305F\u3081\u3001\u4E0A\u306E ID \u3092\u624B\u52D5\u3067\u30B3\u30D4\u30FC\u3057\u3066\u304F\u3060\u3055\u3044",
450
+ "open.label": "\u30BB\u30C3\u30B7\u30E7\u30F3\u3092\u958B\u304F",
451
+ "cost.label": "\u8CBB\u7528",
452
+ "scroll.more": "\u3082\u3063\u3068",
453
+ "scroll.top": "\u5148\u982D\u3078",
454
+ "scroll.bottom": "\u672B\u5C3E\u3078",
455
+ "dismiss.label": "\u5B8C\u4E86\u306B\u3059\u308B",
456
+ "cancel.label": "\u30AD\u30E3\u30F3\u30BB\u30EB",
457
+ "status.running": "\u5B9F\u884C\u4E2D",
458
+ "status.done": "\u5B8C\u4E86",
459
+ "status.cancelled": "\u30AD\u30E3\u30F3\u30BB\u30EB\u6E08\u307F",
460
+ "status.error": "\u30A8\u30E9\u30FC",
461
+ "order.desc": "\u964D\u9806\uFF08\u65B0\u3057\u3044\u9806\uFF09",
462
+ "order.asc": "\u6607\u9806\uFF08\u53E4\u3044\u9806\uFF09",
463
+ "scroll.wheel": "\u30DB\u30A4\u30FC\u30EB\u30B9\u30AF\u30ED\u30FC\u30EB",
464
+ "scroll.click": "\u30AF\u30EA\u30C3\u30AF\u30B9\u30AF\u30ED\u30FC\u30EB",
465
+ "ttl.label": "\u4FDD\u6301\u671F\u9593",
466
+ "ttl.3d": "3 \u65E5",
467
+ "ttl.7d": "7 \u65E5",
468
+ "ttl.14d": "14 \u65E5",
469
+ "ttl.30d": "30 \u65E5",
470
+ "ttl.unlimited": "\u7121\u671F\u9650",
471
+ "ttl.toast": "\u4FDD\u6301\u671F\u9593\u3092 {n} \u65E5\u306B\u8A2D\u5B9A\u3057\u307E\u3057\u305F",
472
+ "ttl.toast_unlimited": "\u4FDD\u6301\u671F\u9593\u3092\u7121\u671F\u9650\u306B\u8A2D\u5B9A\u3057\u307E\u3057\u305F",
473
+ "clear.title": "\u524A\u9664\u306E\u78BA\u8A8D",
474
+ "clear.prompt": "\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u5168\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u8A18\u9332\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F\u3053\u306E\u64CD\u4F5C\u306F\u5143\u306B\u623B\u305B\u307E\u305B\u3093\u3002",
475
+ "clear.prompt_running": "\u5B9F\u884C\u4E2D\u306E\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u304C {n} \u500B\u3042\u308A\u307E\u3059\u3002\u524A\u9664\u3059\u308B\u3068\u5FA9\u5143\u3067\u304D\u307E\u305B\u3093\u3002\u7D9A\u884C\u3057\u307E\u3059\u304B\uFF1F",
476
+ "clear.done": "{n} \u4EF6\u306E\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u8A18\u9332\u3092\u524A\u9664\u3057\u307E\u3057\u305F",
477
+ "clear.empty": "\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306B\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u8A18\u9332\u306F\u3042\u308A\u307E\u305B\u3093",
478
+ "cancel.no_session": "\u5B50\u30BB\u30C3\u30B7\u30E7\u30F3 ID \u304C\u5229\u7528\u3067\u304D\u307E\u305B\u3093",
479
+ "cancel.not_child": "\u5BFE\u8C61\u306F\u5B50\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u306F\u3042\u308A\u307E\u305B\u3093",
480
+ "cancel.read_error": "\u30BB\u30C3\u30B7\u30E7\u30F3\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093",
481
+ "cancel.outside_tree": "\u5BFE\u8C61\u306F\u76E3\u8996\u5BFE\u8C61\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u30C4\u30EA\u30FC\u5916\u3067\u3059",
482
+ "cancel.already_ended": "\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u65E2\u306B\u7D42\u4E86\u3057\u3066\u3044\u307E\u3059",
483
+ "cancel.status_error": "\u30BB\u30C3\u30B7\u30E7\u30F3\u72B6\u614B\u3092\u7167\u4F1A\u3067\u304D\u307E\u305B\u3093",
484
+ "cancel.sent": "\u30AD\u30E3\u30F3\u30BB\u30EB\u6307\u793A\u3092\u9001\u4FE1\u3057\u307E\u3057\u305F",
485
+ "cancel.failed": "\u30AD\u30E3\u30F3\u30BB\u30EB\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
486
+ };
487
+ var KO_T = {
488
+ "panel.title": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8",
489
+ "status.none": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uC5C6\uC74C",
490
+ "agent.label": "\uC5D0\uC774\uC804\uD2B8",
491
+ "status.label": "\uC0C1\uD0DC",
492
+ "time.label": "\uC2DC\uAC04",
493
+ "tokens.label": "\uCEE8\uD14D\uC2A4\uD2B8",
494
+ "error.label": "\uC624\uB958",
495
+ "model.label": "\uBAA8\uB378",
496
+ "todo.label": "\uC9C4\uD589\uB3C4",
497
+ "session.label": "\uC138\uC158 ID",
498
+ "session.toast.copy": "\uC704 ID\uB97C \uC218\uB3D9\uC73C\uB85C \uBCF5\uC0AC\uD558\uC138\uC694",
499
+ "session.toast.copied": "\uC138\uC158 ID\uAC00 \uBCF5\uC0AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
500
+ "session.toast.copy_failed": "\uC2DC\uC2A4\uD15C \uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uC811\uADFC\uD560 \uC218 \uC5C6\uC5B4 \uC704 ID\uB97C \uC218\uB3D9\uC73C\uB85C \uBCF5\uC0AC\uD558\uC138\uC694",
501
+ "open.label": "\uC138\uC158 \uC5F4\uAE30",
502
+ "cost.label": "\uBE44\uC6A9",
503
+ "scroll.more": "\uB354 \uBCF4\uAE30",
504
+ "scroll.top": "\uB9E8 \uC704\uB85C",
505
+ "scroll.bottom": "\uB9E8 \uC544\uB798\uB85C",
506
+ "dismiss.label": "\uC644\uB8CC \uD45C\uC2DC",
507
+ "cancel.label": "\uCDE8\uC18C",
508
+ "status.running": "\uC2E4\uD589 \uC911",
509
+ "status.done": "\uC644\uB8CC",
510
+ "status.cancelled": "\uCDE8\uC18C\uB428",
511
+ "status.error": "\uC624\uB958",
512
+ "order.desc": "\uB0B4\uB9BC\uCC28\uC21C(\uCD5C\uC2E0\uC21C)",
513
+ "order.asc": "\uC624\uB984\uCC28\uC21C(\uC624\uB798\uB41C\uC21C)",
514
+ "scroll.wheel": "\uD720 \uC2A4\uD06C\uB864",
515
+ "scroll.click": "\uD074\uB9AD \uC2A4\uD06C\uB864",
516
+ "ttl.label": "\uBCF4\uC874 \uAE30\uAC04",
517
+ "ttl.3d": "3\uC77C",
518
+ "ttl.7d": "7\uC77C",
519
+ "ttl.14d": "14\uC77C",
520
+ "ttl.30d": "30\uC77C",
521
+ "ttl.unlimited": "\uBB34\uAE30\uD55C",
522
+ "ttl.toast": "\uBCF4\uC874 \uAE30\uAC04\uC744 {n}\uC77C\uB85C \uC124\uC815\uD588\uC2B5\uB2C8\uB2E4",
523
+ "ttl.toast_unlimited": "\uBCF4\uC874 \uAE30\uAC04\uC744 \uBB34\uAE30\uD55C\uC73C\uB85C \uC124\uC815\uD588\uC2B5\uB2C8\uB2E4",
524
+ "clear.title": "\uC0AD\uC81C \uD655\uC778",
525
+ "clear.prompt": "\uC774 \uC138\uC158\uC758 \uBAA8\uB4E0 \uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uAE30\uB85D\uC744 \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C? \uC774 \uC791\uC5C5\uC740 \uB418\uB3CC\uB9B4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
526
+ "clear.prompt_running": "\uC2E4\uD589 \uC911\uC778 \uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8\uAC00 {n}\uAC1C \uC788\uC2B5\uB2C8\uB2E4. \uC0AD\uC81C\uD558\uBA74 \uBCF5\uAD6C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uACC4\uC18D\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
527
+ "clear.done": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uAE30\uB85D {n}\uAC1C\uB97C \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4",
528
+ "clear.empty": "\uC774 \uC138\uC158\uC5D0 \uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4",
529
+ "cancel.no_session": "\uD558\uC704 \uC138\uC158 ID\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
530
+ "cancel.not_child": "\uB300\uC0C1\uC774 \uD558\uC704 \uC138\uC158\uC774 \uC544\uB2D9\uB2C8\uB2E4",
531
+ "cancel.read_error": "\uC138\uC158 \uC815\uBCF4\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
532
+ "cancel.outside_tree": "\uB300\uC0C1\uC774 \uBAA8\uB2C8\uD130\uB9C1 \uC138\uC158 \uD2B8\uB9AC \uBC16\uC5D0 \uC788\uC2B5\uB2C8\uB2E4",
533
+ "cancel.already_ended": "\uC138\uC158\uC774 \uC774\uBBF8 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
534
+ "cancel.status_error": "\uC138\uC158 \uC0C1\uD0DC\uB97C \uC870\uD68C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
535
+ "cancel.sent": "\uCDE8\uC18C \uC9C0\uC2DC\uB97C \uBCF4\uB0C8\uC2B5\uB2C8\uB2E4",
536
+ "cancel.failed": "\uCDE8\uC18C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4"
537
+ };
538
+ var LANGS = { zh: ZH_T, en: EN_T, ja: JA_T, ko: KO_T };
539
+ var LANG_META = [
540
+ { code: "zh", label: "\u4E2D\u6587" },
541
+ { code: "en", label: "English" },
542
+ { code: "ja", label: "\u65E5\u672C\u8A9E" },
543
+ { code: "ko", label: "\uD55C\uAD6D\uC5B4" }
544
+ ];
545
+ function applyParams(tpl, params) {
546
+ if (!params) return tpl;
547
+ return tpl.replace(
548
+ /\{(\w+)\}/g,
549
+ (m, k) => k in params ? String(params[k]) : m
550
+ );
551
+ }
552
+ function createT(getCode) {
553
+ return (key, params) => applyParams(LANGS[getCode()][key] ?? key, params);
554
+ }
555
+ function detectLang() {
556
+ try {
557
+ const loc = Intl.DateTimeFormat().resolvedOptions().locale.toLowerCase();
558
+ if (loc.startsWith("zh")) return "zh";
559
+ if (loc.startsWith("ja")) return "ja";
560
+ if (loc.startsWith("ko")) return "ko";
561
+ return "en";
562
+ } catch {
563
+ return "en";
564
+ }
565
+ }
566
+
567
+ // src/panel/store.ts
568
+ import { createSignal } from "solid-js";
569
+ var globalEntryCache = /* @__PURE__ */ new Map();
570
+ var [clearTick, setClearTick] = createSignal(0);
571
+
572
+ // src/v2/commands.ts
573
+ function makeCommands(context, api, signals) {
574
+ const t = createT(() => signals.lang());
575
+ const kv = api.kv;
576
+ const clampMax = (n) => Math.max(1, Math.min(50, n));
577
+ const resolveParent = (sid) => {
578
+ try {
579
+ const session = api.session.get(sid);
580
+ const parentID = session?.parentID;
581
+ if (parentID) return { parentSid: parentID, isChild: true };
582
+ } catch {
583
+ }
584
+ return { parentSid: sid, isChild: false };
585
+ };
586
+ return [
587
+ {
588
+ id: "opencode-subagent-magazine.subagent.lang",
589
+ title: "SubAgent Magazine: Language",
590
+ description: "Switch display language (\u4E2D\u6587 / English / \u65E5\u672C\u8A9E / \uD55C\uAD6D\uC5B4)",
591
+ slash: { name: "subagent-lang" },
592
+ palette: true,
593
+ run: async () => {
594
+ const lang = await context.ui.dialog.select({
595
+ title: "Language / \u8BED\u8A00",
596
+ options: LANG_META.map((m) => ({ title: m.label, value: m.code }))
597
+ });
598
+ if (!lang) return;
599
+ signals.setLang(lang);
600
+ kv.set(SETTING_KEYS.lang, lang);
601
+ api.ui.toast("Language: " + (LANG_META.find((m) => m.code === lang)?.label ?? lang));
602
+ }
603
+ },
604
+ {
605
+ id: "opencode-subagent-magazine.subagent.order",
606
+ title: "SubAgent Magazine: Sort Order",
607
+ description: "Set sub-agent entry sort order (desc / asc)",
608
+ slash: { name: "subagent-order" },
609
+ palette: true,
610
+ run: async () => {
611
+ const order = await context.ui.dialog.select({
612
+ title: "Sort Order / \u6392\u5E8F\u65B9\u5F0F",
613
+ options: [
614
+ { title: t("order.desc"), value: "desc" },
615
+ { title: t("order.asc"), value: "asc" }
616
+ ]
617
+ });
618
+ if (!order) return;
619
+ signals.setSortOrder(order);
620
+ kv.set(SETTING_KEYS.order, order);
621
+ api.ui.toast(order === "desc" ? t("order.desc") : t("order.asc"));
622
+ }
623
+ },
624
+ {
625
+ id: "opencode-subagent-magazine.subagent.scroll",
626
+ title: "SubAgent Magazine: Scroll Mode",
627
+ description: "Set scroll mode (wheel / click)",
628
+ slash: { name: "subagent-scroll" },
629
+ palette: true,
630
+ run: async () => {
631
+ const mode = await context.ui.dialog.select({
632
+ title: "Scroll Mode / \u6EDA\u52A8\u6A21\u5F0F",
633
+ options: [
634
+ { title: t("scroll.wheel"), value: "wheel" },
635
+ { title: t("scroll.click"), value: "click" }
636
+ ]
637
+ });
638
+ if (!mode) return;
639
+ signals.setScrollMode(mode);
640
+ kv.set(SETTING_KEYS.scrollMode, mode);
641
+ api.ui.toast(mode === "wheel" ? t("scroll.wheel") : t("scroll.click"));
642
+ }
643
+ },
644
+ {
645
+ id: "opencode-subagent-magazine.subagent.max",
646
+ title: "SubAgent Magazine: Max Entries",
647
+ description: "Set max visible sub-agent entries in sidebar",
648
+ slash: { name: "subagent-max" },
649
+ palette: true,
650
+ run: async () => {
651
+ const val = await context.ui.dialog.prompt({
652
+ title: "Max Visible Entries",
653
+ message: "Number of entries to show in the sidebar (1\u201350)",
654
+ placeholder: String(signals.maxEntries())
655
+ });
656
+ if (val === void 0) return;
657
+ const n = clampMax(parseInt(val, 10) || 10);
658
+ signals.setMaxEntries(n);
659
+ kv.set(SETTING_KEYS.maxEntries, n);
660
+ api.ui.toast(`Max entries: ${n}`);
661
+ }
662
+ },
663
+ {
664
+ id: "opencode-subagent-magazine.subagent.version",
665
+ title: "SubAgent Magazine: Version",
666
+ description: "Show plugin version",
667
+ slash: { name: "subagent-version" },
668
+ palette: true,
669
+ run: () => {
670
+ api.ui.toast(`opencode-subagent-magazine v${PLUGIN_VERSION}`);
671
+ }
672
+ },
673
+ {
674
+ id: "opencode-subagent-magazine.subagent.session",
675
+ title: "SubAgent Magazine: Session",
676
+ description: "Show current session ID",
677
+ slash: { name: "subagent-session" },
678
+ palette: true,
679
+ run: () => {
680
+ api.ui.toast(`Session: ${signals.sessionId}`);
681
+ }
682
+ },
683
+ {
684
+ id: "opencode-subagent-magazine.subagent.clear-running",
685
+ title: "SubAgent Magazine: Clear Running",
686
+ description: "Mark all running sub-agent entries as done (for stuck/zombie entries)",
687
+ slash: { name: "subagent-clear-running" },
688
+ palette: true,
689
+ run: () => {
690
+ const sid = signals.sessionId;
691
+ const entries = globalEntryCache.get(sid);
692
+ if (!entries || entries.size === 0) {
693
+ api.ui.toast(signals.lang() === "zh" ? "\u6682\u65E0\u5B50\u4EE3\u7406\u6761\u76EE" : "No sub-agent entries found");
694
+ return;
695
+ }
696
+ let count = 0;
697
+ for (const [, entry] of entries) {
698
+ if (entry.status === "running" || entry.status === "cancel_requested") {
699
+ entry.status = "done";
700
+ entry.endedAt = Date.now();
701
+ count++;
702
+ }
703
+ }
704
+ if (count > 0) {
705
+ try {
706
+ const data = loadSessionData(kv);
707
+ const { parentSid, isChild } = resolveParent(sid);
708
+ if (isChild) {
709
+ if (!data[parentSid]) data[parentSid] = { ts: Date.now(), entries: [], scroll: 0, expanded: "", children: {} };
710
+ if (!data[parentSid].children) data[parentSid].children = {};
711
+ if (!data[parentSid].children[sid]) data[parentSid].children[sid] = { scroll: 0, expanded: "", entries: [] };
712
+ data[parentSid].children[sid] = { ...data[parentSid].children[sid], entries: [...entries.values()] };
713
+ } else {
714
+ data[sid] = {
715
+ ts: Date.now(),
716
+ entries: [...entries.values()],
717
+ scroll: data[sid]?.scroll ?? 0,
718
+ expanded: data[sid]?.expanded ?? "",
719
+ children: data[sid]?.children ?? {}
720
+ };
721
+ }
722
+ saveSessionData(kv, data);
723
+ } catch {
724
+ }
725
+ api.ui.toast(signals.lang() === "zh" ? `\u5DF2\u6807\u8BB0 ${count} \u4E2A\u8FD0\u884C\u4E2D\u7684\u6761\u76EE\u4E3A\u5B8C\u6210` : `Marked ${count} running entries as done`);
726
+ } else {
727
+ api.ui.toast(signals.lang() === "zh" ? "\u6CA1\u6709\u9700\u8981\u6E05\u7406\u7684\u8FD0\u884C\u4E2D\u6761\u76EE" : "No running entries to clear");
728
+ }
729
+ }
730
+ },
731
+ {
732
+ id: "opencode-subagent-magazine.subagent.ttl",
733
+ title: "SubAgent Magazine: TTL",
734
+ description: "Set session data retention period (days before auto-cleanup)",
735
+ slash: { name: "subagent-ttl" },
736
+ palette: true,
737
+ run: async () => {
738
+ const curDays = readTTLDays(kv);
739
+ const curLabel = curDays === 0 ? t("ttl.unlimited") : `${curDays}d`;
740
+ const days = await context.ui.dialog.select({
741
+ title: `${t("ttl.label")} (${curLabel})`,
742
+ options: [
743
+ { title: t("ttl.3d"), value: 3 },
744
+ { title: t("ttl.7d"), value: 7 },
745
+ { title: t("ttl.14d"), value: 14 },
746
+ { title: t("ttl.30d"), value: 30 },
747
+ { title: t("ttl.unlimited"), value: 0 }
748
+ ]
749
+ });
750
+ if (days === void 0) return;
751
+ kv.set(SETTING_KEYS.ttlDays, String(days));
752
+ api.ui.toast(days === 0 ? t("ttl.toast_unlimited") : t("ttl.toast", { n: days }));
753
+ }
754
+ },
755
+ {
756
+ id: "opencode-subagent-magazine.subagent.clear-entries",
757
+ title: "SubAgent Magazine: Clear Entries",
758
+ description: "Delete all sub-agent records for the current session (cannot be undone)",
759
+ slash: { name: "subagent-clear-entries" },
760
+ palette: true,
761
+ run: async () => {
762
+ const sid = signals.sessionId;
763
+ const sessionObj = api.session.get(sid);
764
+ const parentID = sessionObj?.parentID;
765
+ const cached = globalEntryCache.get(sid);
766
+ let runningCount = 0;
767
+ if (cached) {
768
+ for (const [, e] of cached) {
769
+ if (e.status === "running") runningCount++;
770
+ }
771
+ }
772
+ const msg = runningCount > 0 ? t("clear.prompt_running", { n: runningCount }) : t("clear.prompt");
773
+ const choice = await context.ui.dialog.select({
774
+ title: t("clear.title"),
775
+ options: [
776
+ { title: t("clear.title"), value: "yes" },
777
+ { title: t("cancel.label"), value: "no" }
778
+ ]
779
+ });
780
+ if (choice !== "yes") return;
781
+ try {
782
+ const data = loadSessionData(kv);
783
+ let count = 0;
784
+ if (parentID) {
785
+ if (data[parentID]?.children?.[sid]) {
786
+ const child = data[parentID].children[sid];
787
+ const ids = child.entries?.map((e) => e.id) ?? [];
788
+ count = ids.length;
789
+ child.entries = [];
790
+ child.scroll = 0;
791
+ child.expanded = "";
792
+ child.clearedIds = [.../* @__PURE__ */ new Set([...child.clearedIds ?? [], ...ids])];
793
+ }
794
+ } else {
795
+ count = data[sid]?.entries?.length ?? 0;
796
+ if (data[sid]) {
797
+ const ids = data[sid].entries?.map((e) => e.id) ?? [];
798
+ data[sid].entries = [];
799
+ data[sid].scroll = 0;
800
+ data[sid].expanded = "";
801
+ data[sid].clearedIds = [.../* @__PURE__ */ new Set([...data[sid].clearedIds ?? [], ...ids])];
802
+ }
803
+ }
804
+ saveSessionData(kv, data);
805
+ globalEntryCache.delete(sid);
806
+ setClearTick((v) => v + 1);
807
+ api.ui.toast(t("clear.done", { n: count }));
808
+ } catch {
809
+ }
810
+ }
811
+ }
812
+ ];
813
+ }
814
+
815
+ // src/v2/theme.ts
816
+ function mapTheme(theme) {
817
+ return {
818
+ primary: theme.hue.interactive[300],
819
+ text: theme.text.default,
820
+ textMuted: theme.text.subdued,
821
+ success: theme.text.feedback.success.default,
822
+ warning: theme.text.feedback.warning.default,
823
+ error: theme.text.feedback.error.default,
824
+ border: theme.text.subdued
825
+ };
826
+ }
827
+
828
+ // src/panel/SubAgentPanel.tsx
829
+ import { createTextNode as _$createTextNode } from "@opentui/solid";
830
+ import { insertNode as _$insertNode } from "@opentui/solid";
831
+ import { createComponent as _$createComponent } from "@opentui/solid";
832
+ import { effect as _$effect } from "@opentui/solid";
833
+ import { insert as _$insert } from "@opentui/solid";
834
+ import { memo as _$memo } from "@opentui/solid";
835
+ import { use as _$use } from "@opentui/solid";
836
+ import { setProp as _$setProp } from "@opentui/solid";
837
+ import { createElement as _$createElement } from "@opentui/solid";
838
+ import { createMemo, createSignal as createSignal2, createEffect, onMount, onCleanup, untrack, Show, For } from "solid-js";
839
+
840
+ // src/clipboard.ts
841
+ import { spawn } from "node:child_process";
842
+ import { platform, release } from "node:os";
843
+ function runWithInput(command, args, input) {
844
+ return new Promise((resolve, reject) => {
845
+ const child = spawn(command, args, {
846
+ stdio: ["pipe", "ignore", "ignore"],
847
+ windowsHide: true
848
+ });
849
+ child.once("error", reject);
850
+ child.once("close", (code) => {
851
+ if (code === 0) resolve();
852
+ else reject(new Error(`${command} exited with code ${code}`));
853
+ });
854
+ child.stdin?.end(input);
855
+ });
856
+ }
857
+ function writeOsc52(text) {
858
+ if (!process.stdout.isTTY) return false;
859
+ const payload = Buffer.from(text, "utf8").toString("base64");
860
+ const sequence = `\x1B]52;c;${payload}\x07`;
861
+ const wrapped = process.env.TMUX || process.env.STY ? `\x1BPtmux;\x1B${sequence}\x1B\\` : sequence;
862
+ process.stdout.write(wrapped);
863
+ return true;
864
+ }
865
+ async function tryCommand(method, command, args, text) {
866
+ try {
867
+ await runWithInput(command, args, text);
868
+ return { copied: true, method };
869
+ } catch {
870
+ return void 0;
871
+ }
872
+ }
873
+ async function copyText(text) {
874
+ if (!text) return { copied: false, method: "none", error: "empty_text" };
875
+ const os = platform();
876
+ const isWsl = release().toLowerCase().includes("microsoft");
877
+ const attempts = [];
878
+ if (os === "darwin") {
879
+ attempts.push(() => tryCommand("pbcopy", "pbcopy", [], text));
880
+ attempts.push(
881
+ () => tryCommand(
882
+ "osascript",
883
+ "osascript",
884
+ ["-e", 'set the clipboard to (read (POSIX file "/dev/stdin") as text)'],
885
+ text
886
+ )
887
+ );
888
+ }
889
+ if (os === "linux" && isWsl) {
890
+ attempts.push(
891
+ () => tryCommand(
892
+ "powershell",
893
+ "powershell.exe",
894
+ [
895
+ "-NonInteractive",
896
+ "-NoProfile",
897
+ "-Command",
898
+ "[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())"
899
+ ],
900
+ text
901
+ )
902
+ );
903
+ } else if (os === "linux") {
904
+ if (process.env.WAYLAND_DISPLAY) {
905
+ attempts.push(() => tryCommand("wl-copy", "wl-copy", [], text));
906
+ }
907
+ attempts.push(() => tryCommand("xclip", "xclip", ["-selection", "clipboard"], text));
908
+ attempts.push(() => tryCommand("xsel", "xsel", ["--clipboard", "--input"], text));
909
+ }
910
+ if (os === "win32") {
911
+ attempts.push(
912
+ () => tryCommand(
913
+ "powershell",
914
+ "powershell.exe",
915
+ [
916
+ "-NonInteractive",
917
+ "-NoProfile",
918
+ "-Command",
919
+ "[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())"
920
+ ],
921
+ text
922
+ )
923
+ );
924
+ }
925
+ for (const attempt of attempts) {
926
+ const result = await attempt();
927
+ if (result) return result;
928
+ }
929
+ try {
930
+ if (writeOsc52(text)) return { copied: true, method: "osc52" };
931
+ } catch {
932
+ }
933
+ return { copied: false, method: "none", error: "clipboard_unavailable" };
934
+ }
935
+
936
+ // src/core/types.ts
937
+ var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["task", "subagent", "delegate", "call_omo_agent"]);
938
+
939
+ // src/core/format.ts
940
+ function charColumns(c) {
941
+ const code = c.codePointAt(0) ?? 0;
942
+ if (code < 32) return 0;
943
+ if (code < 127) return 1;
944
+ if (code < 160) return 0;
945
+ 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)
946
+ return 2;
947
+ return 1;
948
+ }
949
+ function visualWidth(s) {
950
+ let w = 0;
951
+ for (const c of s) w += charColumns(c);
952
+ return w;
953
+ }
954
+ function truncate(text, maxCols) {
955
+ if (visualWidth(text) <= maxCols) return text;
956
+ let cols = 0;
957
+ let i = 0;
958
+ for (const c of text) {
959
+ const w = charColumns(c);
960
+ if (cols + w > maxCols - 1) break;
961
+ cols += w;
962
+ i += c.length;
963
+ }
964
+ return text.slice(0, i) + "\u2026";
965
+ }
966
+ function fmtDurationShort(ms, running) {
967
+ if (running && ms < 2e3) return "";
968
+ if (ms < 1e3) return (ms / 1e3).toFixed(2) + "s";
969
+ if (ms < 6e4) return (ms / 1e3).toFixed(2) + "s";
970
+ const m = Math.floor(ms / 6e4);
971
+ const s = Math.round(ms % 6e4 / 1e3);
972
+ return `${m}m${s}s`;
973
+ }
974
+ function fmtTokens(n) {
975
+ if (n < 1e3) return `${n}`;
976
+ if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
977
+ return `${(n / 1e6).toFixed(1)}M`;
978
+ }
979
+ function safeErrorMsg(err) {
980
+ if (!err) return "";
981
+ if (typeof err === "string") return err;
982
+ if (typeof err === "object") return String(err.message || err.code || "");
983
+ return "";
984
+ }
985
+
986
+ // src/core/color.ts
987
+ function rgb(raw) {
988
+ if (typeof raw === "string" && raw.startsWith("#")) {
989
+ const h = raw.slice(1);
990
+ return {
991
+ r: parseInt(h.slice(0, 2), 16),
992
+ g: parseInt(h.slice(2, 4), 16),
993
+ b: parseInt(h.slice(4, 6), 16)
994
+ };
995
+ }
996
+ if (raw && typeof raw === "object") {
997
+ const o = raw;
998
+ if (typeof o.r === "number" && typeof o.g === "number" && typeof o.b === "number") {
999
+ const scale = o.r > 1 || o.g > 1 || o.b > 1 ? 1 : 255;
1000
+ return { r: Math.round(o.r * scale), g: Math.round(o.g * scale), b: Math.round(o.b * scale) };
1001
+ }
1002
+ }
1003
+ return null;
1004
+ }
1005
+ function saturation(r, g, b) {
1006
+ const max = Math.max(r, g, b) / 255;
1007
+ const min = Math.min(r, g, b) / 255;
1008
+ const delta = max - min;
1009
+ if (delta === 0) return 0;
1010
+ const L = (max + min) / 2;
1011
+ return L <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
1012
+ }
1013
+ function desaturateTo(raw, maxSat, fallback) {
1014
+ const c = rgb(raw);
1015
+ if (!c) return fallback;
1016
+ const sat = saturation(c.r, c.g, c.b);
1017
+ if (sat <= maxSat) {
1018
+ return "#" + [c.r, c.g, c.b].map((v) => v.toString(16).padStart(2, "0")).join("");
1019
+ }
1020
+ const luma = c.r * 0.299 + c.g * 0.587 + c.b * 0.114;
1021
+ let lo = 0, hi = 1;
1022
+ for (let i = 0; i < 12; i++) {
1023
+ const mid = (lo + hi) / 2;
1024
+ const nr2 = Math.round(c.r + (luma - c.r) * mid);
1025
+ const ng2 = Math.round(c.g + (luma - c.g) * mid);
1026
+ const nb2 = Math.round(c.b + (luma - c.b) * mid);
1027
+ if (saturation(nr2, ng2, nb2) > maxSat) lo = mid;
1028
+ else hi = mid;
1029
+ }
1030
+ const nr = Math.round(c.r + (luma - c.r) * hi);
1031
+ const ng = Math.round(c.g + (luma - c.g) * hi);
1032
+ const nb = Math.round(c.b + (luma - c.b) * hi);
1033
+ return "#" + [nr, ng, nb].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
1034
+ }
1035
+ function dimColor(hex, factor = 0.5) {
1036
+ const c = rgb(hex);
1037
+ if (!c) return hex;
1038
+ const r = Math.round(c.r * factor);
1039
+ const g = Math.round(c.g * factor);
1040
+ const b = Math.round(c.b * factor);
1041
+ return "#" + [r, g, b].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
1042
+ }
1043
+ var FALLBACK = {
1044
+ primary: "#8B9DAF",
1045
+ text: "#C5C5BB",
1046
+ muted: "#7A7A72",
1047
+ success: "#9CAF8B",
1048
+ warning: "#C5B88D",
1049
+ error: "#B08A8A",
1050
+ border: "#6B6B63"
1051
+ };
1052
+ var MAX_SAT = 0.28;
1053
+
1054
+ // src/panel/SubAgentPanel.tsx
1055
+ var LEFT_PAD = 4;
1056
+ var INDENT = 2;
1057
+ function SubAgentPanel(props) {
1058
+ const t = createT(() => props.lang());
1059
+ const SESSION_DATA_KEY2 = `${KV_PREFIX}.session_data`;
1060
+ const ttlDaysRaw = parseInt(String(props.api.kv.get(`${KV_PREFIX}.ttl_days`, "3")), 10);
1061
+ const ttlDays = Number.isNaN(ttlDaysRaw) ? 3 : ttlDaysRaw;
1062
+ const TTL_MS = ttlDays * 24 * 60 * 60 * 1e3;
1063
+ const loadSessionData2 = () => {
1064
+ try {
1065
+ const raw = props.api.kv.get(SESSION_DATA_KEY2, "{}");
1066
+ return JSON.parse(String(raw));
1067
+ } catch {
1068
+ return {};
1069
+ }
1070
+ };
1071
+ const saveSessionData2 = (data) => {
1072
+ try {
1073
+ props.api.kv.set(SESSION_DATA_KEY2, JSON.stringify(data));
1074
+ } catch {
1075
+ }
1076
+ };
1077
+ const resolveParent = (sid) => {
1078
+ try {
1079
+ const session = props.api.session.get(sid);
1080
+ const parentID = session?.parentID;
1081
+ if (parentID) return {
1082
+ parentSid: parentID,
1083
+ isChild: true
1084
+ };
1085
+ } catch {
1086
+ }
1087
+ return {
1088
+ parentSid: sid,
1089
+ isChild: false
1090
+ };
1091
+ };
1092
+ const loadEntries = (sid) => {
1093
+ const m = /* @__PURE__ */ new Map();
1094
+ try {
1095
+ const {
1096
+ parentSid,
1097
+ isChild
1098
+ } = resolveParent(sid);
1099
+ const rec = loadSessionData2()[parentSid];
1100
+ if (rec) {
1101
+ const source = isChild ? rec.children?.[sid]?.entries : rec.entries;
1102
+ if (source) {
1103
+ for (const e of source) m.set(e.id, e);
1104
+ }
1105
+ }
1106
+ } catch {
1107
+ }
1108
+ return m;
1109
+ };
1110
+ let persistTimer;
1111
+ const persistEntries = (sid, entries2) => {
1112
+ clearTimeout(persistTimer);
1113
+ persistTimer = setTimeout(() => {
1114
+ try {
1115
+ const data = loadSessionData2();
1116
+ const {
1117
+ parentSid,
1118
+ isChild
1119
+ } = resolveParent(sid);
1120
+ if (isChild) {
1121
+ if (!data[parentSid]) data[parentSid] = {
1122
+ ts: Date.now(),
1123
+ entries: [],
1124
+ scroll: 0,
1125
+ expanded: "",
1126
+ children: {}
1127
+ };
1128
+ if (!data[parentSid].children) data[parentSid].children = {};
1129
+ if (!data[parentSid].children[sid]) data[parentSid].children[sid] = {
1130
+ scroll: 0,
1131
+ expanded: "",
1132
+ entries: []
1133
+ };
1134
+ data[parentSid].children[sid] = {
1135
+ ...data[parentSid].children[sid],
1136
+ entries: [...entries2.values()]
1137
+ };
1138
+ } else {
1139
+ data[sid] = {
1140
+ ...data[sid],
1141
+ ts: Date.now(),
1142
+ entries: [...entries2.values()],
1143
+ children: data[sid]?.children ?? {}
1144
+ };
1145
+ }
1146
+ saveSessionData2(data);
1147
+ } catch {
1148
+ }
1149
+ }, 200);
1150
+ };
1151
+ const persistScroll = (sid, scroll) => {
1152
+ try {
1153
+ const data = loadSessionData2();
1154
+ const {
1155
+ parentSid,
1156
+ isChild
1157
+ } = resolveParent(sid);
1158
+ if (isChild) {
1159
+ if (!data[parentSid]) data[parentSid] = {
1160
+ ts: Date.now(),
1161
+ entries: [],
1162
+ scroll: 0,
1163
+ expanded: "",
1164
+ children: {}
1165
+ };
1166
+ if (!data[parentSid].children) data[parentSid].children = {};
1167
+ if (!data[parentSid].children[sid]) data[parentSid].children[sid] = {
1168
+ scroll: 0,
1169
+ expanded: "",
1170
+ entries: []
1171
+ };
1172
+ data[parentSid].children[sid] = {
1173
+ ...data[parentSid].children[sid],
1174
+ scroll
1175
+ };
1176
+ } else {
1177
+ data[sid] = {
1178
+ ...data[sid],
1179
+ ts: Date.now(),
1180
+ scroll,
1181
+ children: data[sid]?.children ?? {}
1182
+ };
1183
+ }
1184
+ saveSessionData2(data);
1185
+ } catch {
1186
+ }
1187
+ };
1188
+ const persistExpanded = (sid, expanded2) => {
1189
+ try {
1190
+ const data = loadSessionData2();
1191
+ const {
1192
+ parentSid,
1193
+ isChild
1194
+ } = resolveParent(sid);
1195
+ if (isChild) {
1196
+ if (!data[parentSid]) data[parentSid] = {
1197
+ ts: Date.now(),
1198
+ entries: [],
1199
+ scroll: 0,
1200
+ expanded: "",
1201
+ children: {}
1202
+ };
1203
+ if (!data[parentSid].children) data[parentSid].children = {};
1204
+ if (!data[parentSid].children[sid]) data[parentSid].children[sid] = {
1205
+ scroll: 0,
1206
+ expanded: "",
1207
+ entries: []
1208
+ };
1209
+ data[parentSid].children[sid] = {
1210
+ ...data[parentSid].children[sid],
1211
+ expanded: expanded2
1212
+ };
1213
+ } else {
1214
+ data[sid] = {
1215
+ ...data[sid],
1216
+ ts: Date.now(),
1217
+ expanded: expanded2,
1218
+ children: data[sid]?.children ?? {}
1219
+ };
1220
+ }
1221
+ saveSessionData2(data);
1222
+ } catch {
1223
+ }
1224
+ };
1225
+ const cleanupOldSessions = () => {
1226
+ if (ttlDays <= 0) return;
1227
+ try {
1228
+ const data = loadSessionData2();
1229
+ const cutoff = Date.now() - TTL_MS;
1230
+ let changed = false;
1231
+ for (const sid of Object.keys(data)) {
1232
+ if (data[sid].ts < cutoff) {
1233
+ delete data[sid];
1234
+ changed = true;
1235
+ }
1236
+ }
1237
+ if (changed) saveSessionData2(data);
1238
+ } catch {
1239
+ }
1240
+ };
1241
+ cleanupOldSessions();
1242
+ const [entryMap, setEntryMapRaw] = createSignal2(loadEntries(props.sessionId));
1243
+ const setEntryMap = (arg) => {
1244
+ setEntryMapRaw((prev) => {
1245
+ const next = typeof arg === "function" ? arg(prev) : arg;
1246
+ let needsImmediateFlush = false;
1247
+ for (const [id, entry] of next) {
1248
+ const prevEntry = prev.get(id);
1249
+ if (prevEntry?.status === "running" && (entry.status === "done" || entry.status === "error" || entry.status === "cancelled")) {
1250
+ needsImmediateFlush = true;
1251
+ break;
1252
+ }
1253
+ }
1254
+ if (needsImmediateFlush) {
1255
+ clearTimeout(persistTimer);
1256
+ try {
1257
+ const data = loadSessionData2();
1258
+ const {
1259
+ parentSid,
1260
+ isChild
1261
+ } = resolveParent(props.sessionId);
1262
+ if (isChild) {
1263
+ if (!data[parentSid]) data[parentSid] = {
1264
+ ts: Date.now(),
1265
+ entries: [],
1266
+ scroll: 0,
1267
+ expanded: "",
1268
+ children: {}
1269
+ };
1270
+ if (!data[parentSid].children) data[parentSid].children = {};
1271
+ if (!data[parentSid].children[props.sessionId]) data[parentSid].children[props.sessionId] = {
1272
+ scroll: 0,
1273
+ expanded: "",
1274
+ entries: []
1275
+ };
1276
+ data[parentSid].children[props.sessionId] = {
1277
+ ...data[parentSid].children[props.sessionId],
1278
+ entries: [...next.values()]
1279
+ };
1280
+ } else {
1281
+ data[props.sessionId] = {
1282
+ ...data[props.sessionId],
1283
+ ts: Date.now(),
1284
+ entries: [...next.values()],
1285
+ children: data[props.sessionId]?.children ?? {}
1286
+ };
1287
+ }
1288
+ saveSessionData2(data);
1289
+ } catch {
1290
+ }
1291
+ } else {
1292
+ persistEntries(props.sessionId, next);
1293
+ }
1294
+ globalEntryCache.set(props.sessionId, new Map(next));
1295
+ return next;
1296
+ });
1297
+ };
1298
+ const [panelWidth, setPanelWidth] = createSignal2(28);
1299
+ const [open, setOpen] = createSignal2((() => {
1300
+ try {
1301
+ return props.api.kv.get(`${KV_PREFIX}.open`, true);
1302
+ } catch {
1303
+ return true;
1304
+ }
1305
+ })());
1306
+ const [expanded, setExpanded] = createSignal2((() => {
1307
+ try {
1308
+ const {
1309
+ parentSid,
1310
+ isChild
1311
+ } = resolveParent(props.sessionId);
1312
+ const rec = loadSessionData2()[parentSid];
1313
+ if (rec) return isChild ? rec.children?.[props.sessionId]?.expanded || void 0 : rec.expanded || void 0;
1314
+ } catch {
1315
+ }
1316
+ return void 0;
1317
+ })());
1318
+ const [hoveredOpen, setHoveredOpen] = createSignal2(void 0);
1319
+ const [hoveredDismiss, setHoveredDismiss] = createSignal2(void 0);
1320
+ const [hoveredCancel, setHoveredCancel] = createSignal2(void 0);
1321
+ const [hoveredTop, setHoveredTop] = createSignal2(false);
1322
+ const [hoveredMoreAbove, setHoveredMoreAbove] = createSignal2(false);
1323
+ const [hoveredMoreBelow, setHoveredMoreBelow] = createSignal2(false);
1324
+ const [scrollOffset, setScrollOffset] = createSignal2((() => {
1325
+ try {
1326
+ const {
1327
+ parentSid,
1328
+ isChild
1329
+ } = resolveParent(props.sessionId);
1330
+ const rec = loadSessionData2()[parentSid];
1331
+ return isChild ? rec?.children?.[props.sessionId]?.scroll ?? 0 : rec?.scroll ?? 0;
1332
+ } catch {
1333
+ return 0;
1334
+ }
1335
+ })());
1336
+ const [now, setNow] = createSignal2(Date.now());
1337
+ const [renderTick, setRenderTick] = createSignal2(0);
1338
+ let boxEl;
1339
+ let disposed = false;
1340
+ const upsertEntry = (partial) => {
1341
+ setEntryMap((prev) => {
1342
+ const existing = prev.get(partial.id);
1343
+ const next = new Map(prev);
1344
+ const nowTs = Date.now();
1345
+ const e = partial.status;
1346
+ const ended = e === "done" || e === "error" || e === "cancelled";
1347
+ next.set(partial.id, {
1348
+ ...existing ?? {
1349
+ startedAt: nowTs
1350
+ },
1351
+ ...partial,
1352
+ startedAt: existing?.startedAt || partial.startedAt || nowTs,
1353
+ endedAt: ended ? existing?.endedAt || nowTs : void 0
1354
+ });
1355
+ return next;
1356
+ });
1357
+ };
1358
+ const isDescendantOf = (childId, rootId) => {
1359
+ const visited = /* @__PURE__ */ new Set();
1360
+ try {
1361
+ let current = props.api.session.get(childId);
1362
+ while (current?.parentID) {
1363
+ if (visited.has(current.id)) return false;
1364
+ visited.add(current.id);
1365
+ if (current.parentID === rootId) return true;
1366
+ current = props.api.session.get(current.parentID);
1367
+ }
1368
+ } catch {
1369
+ }
1370
+ return false;
1371
+ };
1372
+ const settleOnIdle = (entry) => {
1373
+ if (entry.status === "cancel_requested" && entry.abortAccepted) return "cancelled";
1374
+ return "done";
1375
+ };
1376
+ const cancelEntry = async (entry) => {
1377
+ const childId = entry.sessionId;
1378
+ if (!childId) {
1379
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.no_session"), {
1380
+ title: entry.title || entry.agent
1381
+ });
1382
+ return;
1383
+ }
1384
+ try {
1385
+ const child = props.api.session.get(childId);
1386
+ if (!child?.parentID) {
1387
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.not_child"), {
1388
+ title: entry.title || entry.agent
1389
+ });
1390
+ return;
1391
+ }
1392
+ } catch {
1393
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.read_error"), {
1394
+ title: entry.title || entry.agent
1395
+ });
1396
+ return;
1397
+ }
1398
+ if (!isDescendantOf(childId, props.sessionId)) {
1399
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.outside_tree"), {
1400
+ title: entry.title || entry.agent
1401
+ });
1402
+ return;
1403
+ }
1404
+ try {
1405
+ const st = props.api.session.status(childId);
1406
+ if (st?.type !== "busy") {
1407
+ const tokens = props.api.usage.readSessionTokens(childId);
1408
+ const cost = props.api.usage.readSessionCost(childId);
1409
+ upsertEntry({
1410
+ id: entry.id,
1411
+ title: entry.title,
1412
+ agent: entry.agent,
1413
+ prompt: entry.prompt,
1414
+ status: "done",
1415
+ sessionId: entry.sessionId,
1416
+ tokens,
1417
+ cost
1418
+ });
1419
+ return;
1420
+ }
1421
+ } catch {
1422
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.status_error"), {
1423
+ title: entry.title || entry.agent
1424
+ });
1425
+ return;
1426
+ }
1427
+ upsertEntry({
1428
+ id: entry.id,
1429
+ title: entry.title,
1430
+ agent: entry.agent,
1431
+ prompt: entry.prompt,
1432
+ status: "cancel_requested",
1433
+ sessionId: entry.sessionId,
1434
+ cancelRequestedAt: Date.now(),
1435
+ abortAccepted: false,
1436
+ cancelReason: "manual"
1437
+ });
1438
+ try {
1439
+ await props.api.client.abort({
1440
+ sessionID: childId
1441
+ });
1442
+ upsertEntry({
1443
+ id: entry.id,
1444
+ title: entry.title,
1445
+ agent: entry.agent,
1446
+ prompt: entry.prompt,
1447
+ status: "cancel_requested",
1448
+ sessionId: entry.sessionId,
1449
+ abortAccepted: true
1450
+ });
1451
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.sent"));
1452
+ } catch (err) {
1453
+ upsertEntry({
1454
+ id: entry.id,
1455
+ title: entry.title,
1456
+ agent: entry.agent,
1457
+ prompt: entry.prompt,
1458
+ status: "error",
1459
+ sessionId: entry.sessionId,
1460
+ error: String(err)
1461
+ });
1462
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.failed"), {
1463
+ title: entry.title || entry.agent
1464
+ });
1465
+ }
1466
+ };
1467
+ const handlePartUpdated = (event) => {
1468
+ const part = event.payload?.part;
1469
+ if (!part) return;
1470
+ const eventSid = event.payload?.sessionID !== void 0 ? String(event.payload.sessionID) : void 0;
1471
+ if (eventSid !== void 0 && eventSid !== props.sessionId) return;
1472
+ if (part.type === "subtask") {
1473
+ const agent = String(part.agent ?? "?");
1474
+ const prompt = String(part.prompt ?? "");
1475
+ const desc = String(part.description ?? "");
1476
+ const title = desc || truncate(prompt.replace(/\n/g, " ").replace(/\s+/g, " ").trim(), 40);
1477
+ const id = `sub:${String(part.id ?? crypto.randomUUID())}`;
1478
+ const subSid = part.sessionID !== void 0 ? String(part.sessionID) : void 0;
1479
+ const partModel = part.model;
1480
+ const modelId = partModel?.modelID ? String(partModel.modelID) : void 0;
1481
+ upsertEntry({
1482
+ id,
1483
+ title,
1484
+ agent,
1485
+ prompt,
1486
+ sessionId: subSid,
1487
+ status: "running",
1488
+ model: modelId
1489
+ });
1490
+ }
1491
+ if (part.type === "tool") {
1492
+ const tool = String(part.tool ?? "");
1493
+ if (!SUBAGENT_TOOLS.has(tool)) return;
1494
+ const st = part.state;
1495
+ const rawStatus = String(st?.status ?? "");
1496
+ if (rawStatus === "pending" || rawStatus === "") return;
1497
+ if (rawStatus === "error") {
1498
+ const id2 = `tool:${String(part.id ?? "")}`;
1499
+ if (!part.id) return;
1500
+ const existing = entryMap().get(id2);
1501
+ if (existing) {
1502
+ upsertEntry({
1503
+ id: id2,
1504
+ title: existing.title,
1505
+ agent: existing.agent,
1506
+ prompt: existing.prompt,
1507
+ status: "error"
1508
+ });
1509
+ }
1510
+ return;
1511
+ }
1512
+ const input = st?.input;
1513
+ let status = "running";
1514
+ if (rawStatus === "completed") status = "done";
1515
+ if ((input?.run_in_background === true || input?.background === true) && status === "done") {
1516
+ const stMetaCheck = st?.metadata;
1517
+ const hasChild = stMetaCheck?.session_id !== void 0 || stMetaCheck?.sessionId !== void 0;
1518
+ if (hasChild) status = "running";
1519
+ }
1520
+ const agent = String(part.subagent_type ?? input?.agent ?? input?.subagent_type ?? input?.category ?? tool);
1521
+ const prompt = String(input?.prompt ?? part.description ?? "");
1522
+ const desc = input?.description !== void 0 ? String(input.description) : "";
1523
+ const title = desc || truncate(prompt.replace(/\n/g, " ").replace(/\s+/g, " ").trim(), 40);
1524
+ const id = `tool:${String(part.id ?? crypto.randomUUID())}`;
1525
+ const stMeta = st?.metadata;
1526
+ const subSid = stMeta?.session_id !== void 0 ? String(stMeta.session_id) : stMeta?.sessionId !== void 0 ? String(stMeta.sessionId) : void 0;
1527
+ upsertEntry({
1528
+ id,
1529
+ title,
1530
+ agent,
1531
+ prompt,
1532
+ sessionId: subSid,
1533
+ status
1534
+ });
1535
+ }
1536
+ };
1537
+ const handleSessionEnd = (event, status) => {
1538
+ const props_ = event.payload;
1539
+ const sid = String(props_?.sessionID ?? "");
1540
+ if (!sid) return;
1541
+ const sessionTokens = props.api.usage.readSessionTokens(sid);
1542
+ const sessionCost = props.api.usage.readSessionCost(sid);
1543
+ const sessionModel = props.api.usage.readSessionModel(sid);
1544
+ const sessionTodo = props.api.usage.readSessionTodo(sid);
1545
+ let sessionAgent;
1546
+ let errorMsg;
1547
+ try {
1548
+ const s = props.api.session.get(sid);
1549
+ sessionAgent = s?.agent;
1550
+ if (status === "error") {
1551
+ const evtErr = props_?.error;
1552
+ errorMsg = safeErrorMsg(evtErr) || safeErrorMsg(props_?.message);
1553
+ if (!errorMsg) {
1554
+ const msgs = props.api.session.messages(sid);
1555
+ if (msgs) {
1556
+ for (let i = msgs.length - 1; i >= 0; i--) {
1557
+ const m = msgs[i];
1558
+ if (m.role === "assistant" && m.error) {
1559
+ errorMsg = safeErrorMsg(m.error);
1560
+ break;
1561
+ }
1562
+ }
1563
+ }
1564
+ }
1565
+ }
1566
+ } catch {
1567
+ }
1568
+ const tryMatchAndUpdate = (entriesMap, targetSid, targetStatus, nowTs) => {
1569
+ for (const [, entry] of entriesMap) {
1570
+ if (entry.sessionId === targetSid && (entry.status === "running" || entry.status === "cancel_requested")) {
1571
+ const finalStatus = targetStatus === "error" ? "error" : settleOnIdle(entry);
1572
+ entry.status = finalStatus;
1573
+ entry.endedAt = nowTs;
1574
+ entry.tokens = entry.tokens ?? sessionTokens;
1575
+ entry.cost = entry.cost ?? sessionCost;
1576
+ entry.model = entry.model ?? sessionModel;
1577
+ entry.todoTotal = entry.todoTotal ?? sessionTodo?.total;
1578
+ entry.todoDone = entry.todoDone ?? sessionTodo?.done;
1579
+ entry.error = errorMsg || entry.error;
1580
+ return true;
1581
+ }
1582
+ }
1583
+ if (sessionAgent) {
1584
+ const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9-]/g, "");
1585
+ const saNorm = normalize(sessionAgent);
1586
+ let best = null;
1587
+ for (const [, entry] of entriesMap) {
1588
+ if (entry.status !== "running" && entry.status !== "cancel_requested") continue;
1589
+ const eaNorm = normalize(entry.agent);
1590
+ if (!eaNorm || !saNorm) continue;
1591
+ if (!eaNorm.includes(saNorm) && !saNorm.includes(eaNorm)) continue;
1592
+ const gap = nowTs - (entry.startedAt || 0);
1593
+ if (!best || gap > best.gap) best = {
1594
+ entry,
1595
+ gap
1596
+ };
1597
+ }
1598
+ if (!best) {
1599
+ for (const [, entry] of entriesMap) {
1600
+ if (entry.status !== "running" && entry.status !== "cancel_requested") continue;
1601
+ if (entry.sessionId) continue;
1602
+ const gap = nowTs - (entry.startedAt || 0);
1603
+ if (!best || gap > best.gap) best = {
1604
+ entry,
1605
+ gap
1606
+ };
1607
+ }
1608
+ }
1609
+ if (best) {
1610
+ const finalStatus = targetStatus === "error" ? "error" : settleOnIdle(best.entry);
1611
+ best.entry.status = finalStatus;
1612
+ best.entry.endedAt = nowTs;
1613
+ best.entry.tokens = best.entry.tokens ?? sessionTokens;
1614
+ best.entry.cost = best.entry.cost ?? sessionCost;
1615
+ best.entry.model = best.entry.model ?? sessionModel;
1616
+ best.entry.todoTotal = best.entry.todoTotal ?? sessionTodo?.total;
1617
+ best.entry.todoDone = best.entry.todoDone ?? sessionTodo?.done;
1618
+ best.entry.sessionId = targetSid;
1619
+ best.entry.error = errorMsg || best.entry.error;
1620
+ return true;
1621
+ }
1622
+ }
1623
+ return false;
1624
+ };
1625
+ setEntryMap((prev) => {
1626
+ let changed = false;
1627
+ const next = new Map(prev);
1628
+ for (const [id, entry] of next) {
1629
+ if (entry.sessionId !== sid) continue;
1630
+ if (entry.status !== "running" && entry.status !== "done" && entry.status !== "cancel_requested") continue;
1631
+ if (sid === props.sessionId) continue;
1632
+ const alreadySettled = entry.status !== "running" && entry.status !== "cancel_requested";
1633
+ const finalStatus = status === "error" ? "error" : settleOnIdle(entry);
1634
+ next.set(id, {
1635
+ ...entry,
1636
+ ...alreadySettled ? {} : {
1637
+ status: finalStatus,
1638
+ endedAt: Date.now()
1639
+ },
1640
+ tokens: entry.tokens ?? sessionTokens,
1641
+ cost: entry.cost ?? sessionCost,
1642
+ model: entry.model ?? sessionModel,
1643
+ todoTotal: entry.todoTotal ?? sessionTodo?.total,
1644
+ todoDone: entry.todoDone ?? sessionTodo?.done,
1645
+ error: errorMsg || entry.error
1646
+ });
1647
+ changed = true;
1648
+ }
1649
+ if (!changed && sessionAgent) {
1650
+ const nowTs = Date.now();
1651
+ const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9-]/g, "");
1652
+ const saNorm = normalize(sessionAgent);
1653
+ let best = null;
1654
+ for (const [id, entry] of next) {
1655
+ if (entry.status !== "running" && entry.status !== "cancel_requested") continue;
1656
+ const eaNorm = normalize(entry.agent);
1657
+ if (!eaNorm || !saNorm) continue;
1658
+ if (!eaNorm.includes(saNorm) && !saNorm.includes(eaNorm)) continue;
1659
+ const gap = nowTs - (entry.startedAt || 0);
1660
+ if (!best || gap > best.gap) best = {
1661
+ id,
1662
+ gap
1663
+ };
1664
+ }
1665
+ if (!best) {
1666
+ for (const [id, entry] of next) {
1667
+ if (entry.status !== "running" && entry.status !== "cancel_requested") continue;
1668
+ if (entry.sessionId) continue;
1669
+ const gap = nowTs - (entry.startedAt || 0);
1670
+ if (!best || gap > best.gap) best = {
1671
+ id,
1672
+ gap
1673
+ };
1674
+ }
1675
+ }
1676
+ if (best) {
1677
+ const entry = next.get(best.id);
1678
+ const finalStatus = status === "error" ? "error" : settleOnIdle(entry);
1679
+ next.set(best.id, {
1680
+ ...entry,
1681
+ status: finalStatus,
1682
+ endedAt: nowTs,
1683
+ tokens: sessionTokens || entry.tokens,
1684
+ cost: sessionCost || entry.cost,
1685
+ sessionId: sid,
1686
+ error: errorMsg || entry.error
1687
+ });
1688
+ changed = true;
1689
+ }
1690
+ }
1691
+ return changed ? next : prev;
1692
+ });
1693
+ try {
1694
+ const sessionObj = props.api.session.get(sid);
1695
+ const parentSid = sessionObj?.parentID;
1696
+ if (parentSid && parentSid !== props.sessionId) {
1697
+ const parentCache = globalEntryCache.get(parentSid);
1698
+ const nowTs = Date.now();
1699
+ let found = false;
1700
+ if (parentCache) {
1701
+ found = tryMatchAndUpdate(parentCache, sid, status, nowTs);
1702
+ }
1703
+ if (!found) {
1704
+ const data = loadSessionData2();
1705
+ const rec = data[parentSid];
1706
+ if (rec?.entries) {
1707
+ const fallbackMap = new Map(rec.entries.map((e) => [e.id, e]));
1708
+ found = tryMatchAndUpdate(fallbackMap, sid, status, nowTs);
1709
+ if (found) {
1710
+ data[parentSid] = {
1711
+ ...rec,
1712
+ ts: nowTs,
1713
+ entries: [...fallbackMap.values()]
1714
+ };
1715
+ saveSessionData2(data);
1716
+ globalEntryCache.set(parentSid, fallbackMap);
1717
+ }
1718
+ }
1719
+ }
1720
+ if (found && parentCache) {
1721
+ const data = loadSessionData2();
1722
+ data[parentSid] = {
1723
+ ...data[parentSid],
1724
+ ts: nowTs,
1725
+ entries: [...parentCache.values()]
1726
+ };
1727
+ saveSessionData2(data);
1728
+ }
1729
+ }
1730
+ } catch {
1731
+ }
1732
+ setTimeout(() => {
1733
+ if (disposed) return;
1734
+ const finalTokens = props.api.usage.readSessionTokens(sid);
1735
+ const finalCost = props.api.usage.readSessionCost(sid);
1736
+ const finalModel = props.api.usage.readSessionModel(sid);
1737
+ const finalTodo = props.api.usage.readSessionTodo(sid);
1738
+ setEntryMap((prev) => {
1739
+ let changed = false;
1740
+ const next = new Map(prev);
1741
+ for (const [id, entry] of next) {
1742
+ if (entry.sessionId !== sid) continue;
1743
+ const t2 = finalTokens ?? entry.tokens;
1744
+ const c = finalCost ?? entry.cost;
1745
+ const m = finalModel ?? entry.model;
1746
+ const tt = finalTodo?.total ?? entry.todoTotal;
1747
+ const td = finalTodo?.done ?? entry.todoDone;
1748
+ if (t2 !== entry.tokens || c !== entry.cost || m !== entry.model || tt !== entry.todoTotal || td !== entry.todoDone) {
1749
+ next.set(id, {
1750
+ ...entry,
1751
+ tokens: t2,
1752
+ cost: c,
1753
+ model: m,
1754
+ todoTotal: tt,
1755
+ todoDone: td
1756
+ });
1757
+ changed = true;
1758
+ }
1759
+ }
1760
+ return changed ? next : prev;
1761
+ });
1762
+ bump();
1763
+ }, 150);
1764
+ };
1765
+ const bump = () => setRenderTick((v) => v + 1);
1766
+ onMount(() => {
1767
+ const clock = setInterval(() => {
1768
+ setNow(Date.now());
1769
+ bump();
1770
+ }, 100);
1771
+ const tokenTimer = setInterval(() => {
1772
+ untrack(() => {
1773
+ setEntryMapRaw((prev) => {
1774
+ let changed = false;
1775
+ const next = new Map(prev);
1776
+ for (const [id, entry] of next) {
1777
+ if (entry.status === "running" && entry.sessionId) {
1778
+ let isChild = false;
1779
+ try {
1780
+ const s = props.api.session.get(entry.sessionId);
1781
+ isChild = s?.parentID === props.sessionId;
1782
+ } catch {
1783
+ }
1784
+ if (!isChild) continue;
1785
+ const total = props.api.usage.readSessionTokens(entry.sessionId);
1786
+ const todo = props.api.usage.readSessionTodo(entry.sessionId);
1787
+ const model = entry.model ?? props.api.usage.readSessionModel(entry.sessionId);
1788
+ const nextEntry = {
1789
+ ...entry
1790
+ };
1791
+ if (total !== void 0 && total !== entry.tokens) {
1792
+ nextEntry.tokens = total;
1793
+ changed = true;
1794
+ }
1795
+ if (todo !== void 0) {
1796
+ if (todo.total !== entry.todoTotal || todo.done !== entry.todoDone) {
1797
+ nextEntry.todoTotal = todo.total;
1798
+ nextEntry.todoDone = todo.done;
1799
+ changed = true;
1800
+ }
1801
+ }
1802
+ if (model && !entry.model) {
1803
+ nextEntry.model = model;
1804
+ changed = true;
1805
+ }
1806
+ if (changed) next.set(id, nextEntry);
1807
+ }
1808
+ }
1809
+ return changed ? next : prev;
1810
+ });
1811
+ });
1812
+ bump();
1813
+ }, 500);
1814
+ bump();
1815
+ const unsubPart = props.api.event.on("part.updated", (e) => {
1816
+ handlePartUpdated(e);
1817
+ bump();
1818
+ });
1819
+ const unsubMsg = props.api.event.on("message.updated", () => bump());
1820
+ const unsubIdle = props.api.event.on("session.idle", (e) => {
1821
+ handleSessionEnd(e, "done");
1822
+ bump();
1823
+ });
1824
+ const unsubError = props.api.event.on("session.error", (e) => {
1825
+ handleSessionEnd(e, "error");
1826
+ bump();
1827
+ });
1828
+ onCleanup(() => {
1829
+ disposed = true;
1830
+ clearInterval(clock);
1831
+ clearInterval(tokenTimer);
1832
+ unsubPart();
1833
+ unsubMsg();
1834
+ unsubIdle();
1835
+ unsubError();
1836
+ });
1837
+ });
1838
+ let lastSid = props.sessionId;
1839
+ let lastTick = 0;
1840
+ createEffect(() => {
1841
+ const sid = props.sessionId;
1842
+ const switched = sid !== lastSid;
1843
+ lastSid = sid;
1844
+ const tick = clearTick();
1845
+ const forceReload = tick !== lastTick && !switched;
1846
+ lastTick = tick;
1847
+ const t2 = setTimeout(() => {
1848
+ untrack(() => {
1849
+ if (switched) {
1850
+ const {
1851
+ parentSid,
1852
+ isChild
1853
+ } = resolveParent(sid);
1854
+ const data = loadSessionData2();
1855
+ const saved = isChild ? data[parentSid]?.children?.[sid]?.scroll ?? 0 : data[sid]?.scroll ?? 0;
1856
+ setScrollOffset(saved);
1857
+ if (!isChild && data[sid]?.entries?.length) {
1858
+ data[sid].ts = Date.now();
1859
+ saveSessionData2(data);
1860
+ }
1861
+ }
1862
+ setEntryMapRaw((prev) => {
1863
+ const next = switched || forceReload ? new Map(globalEntryCache.get(sid) ?? loadEntries(sid)) : new Map(prev);
1864
+ const {
1865
+ parentSid: scanPSid,
1866
+ isChild: scanChild
1867
+ } = resolveParent(sid);
1868
+ const scanRec = loadSessionData2()[scanPSid];
1869
+ const clearedIds = new Set(scanChild ? scanRec?.children?.[sid]?.clearedIds : scanRec?.clearedIds);
1870
+ try {
1871
+ const msgs = props.api.session.messages(sid);
1872
+ if (msgs && msgs.length) {
1873
+ for (const msg of msgs) {
1874
+ const parts = props.api.session.part(msg.id) ?? [];
1875
+ for (const partRaw of parts) {
1876
+ const part = partRaw;
1877
+ if (part.type === "tool") {
1878
+ const tool = String(part.tool ?? "");
1879
+ if (!SUBAGENT_TOOLS.has(tool)) continue;
1880
+ const id = `tool:${String(part.id ?? "")}`;
1881
+ if (!part.id) continue;
1882
+ const st = part.state;
1883
+ const rawStatus = String(st?.status ?? "");
1884
+ const exists = next.get(id);
1885
+ if (!exists && clearedIds.has(id)) continue;
1886
+ if ((rawStatus === "pending" || rawStatus === "") && !exists) continue;
1887
+ if (rawStatus === "error") {
1888
+ if (exists && exists.status === "running") {
1889
+ next.set(id, {
1890
+ ...exists,
1891
+ status: "error",
1892
+ endedAt: Date.now()
1893
+ });
1894
+ }
1895
+ continue;
1896
+ }
1897
+ let status = "running";
1898
+ if (rawStatus === "completed") status = "done";
1899
+ if ((st?.input?.run_in_background === true || st?.input?.background === true) && status === "done") {
1900
+ const scanStMeta = st?.metadata;
1901
+ const scanHasChild = scanStMeta?.session_id !== void 0 || scanStMeta?.sessionId !== void 0;
1902
+ if (scanHasChild) status = "running";
1903
+ }
1904
+ if (exists && exists.status !== "running" && exists.status !== "cancel_requested") continue;
1905
+ if (exists && status === "running") {
1906
+ if (!rawStatus) {
1907
+ const msgTokens = msg?.tokens;
1908
+ if (msgTokens && (Number(msgTokens.input) > 0 || Number(msgTokens.output) > 0)) {
1909
+ status = "done";
1910
+ } else if (Date.now() - exists.startedAt > 30 * 60 * 1e3) {
1911
+ status = "done";
1912
+ } else {
1913
+ continue;
1914
+ }
1915
+ } else {
1916
+ continue;
1917
+ }
1918
+ }
1919
+ const input = st?.input;
1920
+ const agent = String(part.subagent_type ?? input?.agent ?? input?.subagent_type ?? tool);
1921
+ const prompt = String(input?.prompt ?? part.description ?? "");
1922
+ const desc = input?.description !== void 0 ? String(input.description) : "";
1923
+ const title = desc || truncate(prompt.replace(/\n/g, " ").trim(), 40);
1924
+ let tokens;
1925
+ const scanStMeta2 = st?.metadata;
1926
+ const scanSubSid = scanStMeta2?.session_id !== void 0 ? String(scanStMeta2.session_id) : scanStMeta2?.sessionId !== void 0 ? String(scanStMeta2.sessionId) : void 0;
1927
+ if (scanSubSid) tokens = props.api.usage.readSessionTokens(scanSubSid);
1928
+ const ended = status === "done";
1929
+ next.set(id, {
1930
+ id,
1931
+ title,
1932
+ agent,
1933
+ prompt,
1934
+ // Preserve existing values (from handleSessionEnd / KV) — scan must not overwrite
1935
+ tokens: exists?.tokens ?? tokens,
1936
+ sessionId: exists?.sessionId ?? scanSubSid,
1937
+ status,
1938
+ startedAt: exists?.startedAt || Date.now(),
1939
+ endedAt: ended ? exists?.endedAt || Date.now() : void 0
1940
+ });
1941
+ }
1942
+ }
1943
+ }
1944
+ }
1945
+ } catch {
1946
+ }
1947
+ return next;
1948
+ });
1949
+ setEntryMapRaw((prev) => {
1950
+ let changed = false;
1951
+ const next = new Map(prev);
1952
+ for (const [id, entry] of next) {
1953
+ if (entry.status !== "running" && entry.status !== "cancel_requested" || !entry.sessionId) continue;
1954
+ try {
1955
+ const st = props.api.session.status(entry.sessionId);
1956
+ if (!st || st.type !== "idle") continue;
1957
+ const tokens = props.api.usage.readSessionTokens(entry.sessionId);
1958
+ const cost = props.api.usage.readSessionCost(entry.sessionId);
1959
+ const finalStatus = entry.status === "cancel_requested" && entry.abortAccepted ? "cancelled" : "done";
1960
+ next.set(id, {
1961
+ ...entry,
1962
+ status: finalStatus,
1963
+ endedAt: Date.now(),
1964
+ tokens: tokens ?? entry.tokens,
1965
+ cost: cost ?? entry.cost
1966
+ });
1967
+ changed = true;
1968
+ } catch {
1969
+ }
1970
+ }
1971
+ return changed ? next : prev;
1972
+ });
1973
+ bump();
1974
+ });
1975
+ }, 150);
1976
+ onCleanup(() => clearTimeout(t2));
1977
+ });
1978
+ const pal = createMemo(() => {
1979
+ const th = props.theme;
1980
+ const sat = (k, fb) => desaturateTo(th[k], MAX_SAT, fb);
1981
+ return {
1982
+ primary: sat("primary", FALLBACK.primary),
1983
+ text: sat("text", FALLBACK.text),
1984
+ muted: sat("textMuted", FALLBACK.muted),
1985
+ success: sat("success", FALLBACK.success),
1986
+ warning: sat("warning", FALLBACK.warning),
1987
+ error: sat("error", FALLBACK.error),
1988
+ border: sat("border", FALLBACK.border)
1989
+ };
1990
+ });
1991
+ const entryList = createMemo(() => {
1992
+ const entries2 = [...entryMap().values()];
1993
+ if (props.sortOrder() === "desc") {
1994
+ return entries2.sort((a, b) => b.startedAt - a.startedAt);
1995
+ }
1996
+ return entries2.sort((a, b) => a.startedAt - b.startedAt);
1997
+ });
1998
+ const max = props.maxEntries;
1999
+ const clampedOffset = createMemo(() => {
2000
+ const total = entryList().length;
2001
+ const m = max();
2002
+ if (total <= m) return 0;
2003
+ return Math.min(scrollOffset(), total - m);
2004
+ });
2005
+ const visibleList = createMemo(() => entryList().slice(clampedOffset(), clampedOffset() + max()));
2006
+ const hiddenAbove = createMemo(() => clampedOffset());
2007
+ const hiddenBelow = createMemo(() => Math.max(0, entryList().length - clampedOffset() - max()));
2008
+ createEffect(() => {
2009
+ if (hiddenAbove() === 0) setHoveredMoreAbove(false);
2010
+ });
2011
+ let sortInitialized = false;
2012
+ createEffect(() => {
2013
+ props.sortOrder();
2014
+ if (!sortInitialized) {
2015
+ sortInitialized = true;
2016
+ return;
2017
+ }
2018
+ const total = untrack(() => entryList().length);
2019
+ const m = untrack(() => max());
2020
+ const target = props.sortOrder() === "desc" ? 0 : Math.max(0, total - m);
2021
+ setScrollOffset(target);
2022
+ setTimeout(() => {
2023
+ try {
2024
+ persistScroll(props.sessionId, target);
2025
+ } catch {
2026
+ }
2027
+ }, 0);
2028
+ });
2029
+ let prevEntryCount = 0;
2030
+ createEffect(() => {
2031
+ const total = entryList().length;
2032
+ if (prevEntryCount === 0) {
2033
+ prevEntryCount = total;
2034
+ return;
2035
+ }
2036
+ if (total === prevEntryCount) return;
2037
+ const m = max();
2038
+ const wasAtNewest = props.sortOrder() === "desc" ? untrack(() => scrollOffset() === 0) : untrack(() => scrollOffset() >= prevEntryCount - m);
2039
+ prevEntryCount = total;
2040
+ if (wasAtNewest) {
2041
+ const target = props.sortOrder() === "desc" ? 0 : Math.max(0, total - m);
2042
+ setScrollOffset(target);
2043
+ setTimeout(() => {
2044
+ try {
2045
+ persistScroll(props.sessionId, target);
2046
+ } catch {
2047
+ }
2048
+ }, 0);
2049
+ }
2050
+ });
2051
+ const entries = createMemo(() => {
2052
+ const nowVal = now();
2053
+ return entryList().map((e) => ({
2054
+ ...e,
2055
+ elapsed: (e.endedAt ?? nowVal) - e.startedAt
2056
+ }));
2057
+ });
2058
+ const doneCount = createMemo(() => entryList().filter((e) => e.status === "done" || e.status === "cancelled").length);
2059
+ const runningCount = createMemo(() => entryList().filter((e) => e.status === "running" || e.status === "cancel_requested").length);
2060
+ const errCount = createMemo(() => entryList().filter((e) => e.status === "error").length);
2061
+ const anyEntry = () => entryList().length > 0;
2062
+ const totalTokens = createMemo(() => {
2063
+ let sum = 0;
2064
+ for (const e of entryList()) {
2065
+ if (e.tokens) sum += e.tokens;
2066
+ }
2067
+ return sum;
2068
+ });
2069
+ const totalCost = createMemo(() => {
2070
+ let sum = 0;
2071
+ for (const e of entryList()) {
2072
+ if (e.cost) sum += e.cost;
2073
+ }
2074
+ return sum;
2075
+ });
2076
+ const toggleExpand = (id) => {
2077
+ setExpanded((prev) => {
2078
+ const next = prev === id ? void 0 : id;
2079
+ try {
2080
+ persistExpanded(props.sessionId, next ?? "");
2081
+ } catch {
2082
+ }
2083
+ return next;
2084
+ });
2085
+ };
2086
+ const sep = () => "\u2500".repeat(Math.max(1, panelWidth()));
2087
+ const expandedMaxLabelW = createMemo(() => {
2088
+ 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"), t("session.label")];
2089
+ return Math.max(...labels.map((l) => visualWidth(l + ": ")));
2090
+ });
2091
+ const expandedPad = (label) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "));
2092
+ const expandedValAvail = () => Math.max(6, panelWidth() - INDENT - expandedMaxLabelW());
2093
+ const summaryParts = createMemo(() => {
2094
+ if (!anyEntry()) return null;
2095
+ const dot = "\u25CF";
2096
+ const cost = totalCost();
2097
+ return {
2098
+ done: `${dot}${doneCount()}`,
2099
+ running: runningCount() > 0 ? `${dot}${runningCount()}` : null,
2100
+ err: errCount() > 0 ? `${dot}${errCount()}` : null,
2101
+ duration: totalTokens() > 0 ? fmtTokens(totalTokens()) : "",
2102
+ cost: cost > 0 ? `$${cost.toFixed(2)}` : ""
2103
+ };
2104
+ });
2105
+ const summaryCols = createMemo(() => {
2106
+ const p = summaryParts();
2107
+ if (!p) return 0;
2108
+ let w = visualWidth(p.done);
2109
+ if (p.running) w += 1 + visualWidth(p.running);
2110
+ if (p.err) w += 1 + visualWidth(p.err);
2111
+ w += p.duration ? 1 + visualWidth(p.duration) : 0;
2112
+ w += p.cost ? 1 + visualWidth(p.cost) : 0;
2113
+ return w;
2114
+ });
2115
+ const versionText = ` v${PLUGIN_VERSION}`;
2116
+ const versionW = visualWidth(versionText);
2117
+ const showVersion = createMemo(() => {
2118
+ if (!open()) return false;
2119
+ const icon = "\u25BC";
2120
+ const need = visualWidth(icon) + 1 + visualWidth(t("panel.title")) + versionW + summaryCols();
2121
+ return need <= panelWidth();
2122
+ });
2123
+ const leftCols = createMemo(() => {
2124
+ const icon = open() ? "\u25BC" : "\u25B6";
2125
+ let w = visualWidth(icon) + 1 + visualWidth(t("panel.title"));
2126
+ if (showVersion()) w += versionW;
2127
+ return w;
2128
+ });
2129
+ const spacerCols = createMemo(() => {
2130
+ if (!anyEntry()) return 0;
2131
+ return Math.max(0, panelWidth() - leftCols() - summaryCols());
2132
+ });
2133
+ const valueCols = (label) => Math.max(4, panelWidth() - INDENT - visualWidth(label + ": "));
2134
+ return (() => {
2135
+ var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("span"), _el$4 = _$createElement("span");
2136
+ _$insertNode(_el$, _el$2);
2137
+ var _ref$ = boxEl;
2138
+ typeof _ref$ === "function" ? _$use(_ref$, _el$) : boxEl = _el$;
2139
+ _$setProp(_el$, "border", false);
2140
+ _$setProp(_el$, "paddingTop", 0);
2141
+ _$setProp(_el$, "paddingBottom", 0);
2142
+ _$setProp(_el$, "paddingLeft", 0);
2143
+ _$setProp(_el$, "paddingRight", 0);
2144
+ _$setProp(_el$, "flexDirection", "column");
2145
+ _$setProp(_el$, "gap", 0);
2146
+ _$setProp(_el$, "onSizeChange", () => {
2147
+ const w = boxEl ? Math.max(20, boxEl.width ?? 0) : 28;
2148
+ setPanelWidth((prev) => prev === w ? prev : w);
2149
+ });
2150
+ _$insertNode(_el$2, _el$3);
2151
+ _$insertNode(_el$2, _el$4);
2152
+ _$setProp(_el$2, "onMouseUp", () => {
2153
+ setOpen((o) => {
2154
+ const n = !o;
2155
+ try {
2156
+ props.api.kv.set(`${KV_PREFIX}.open`, n);
2157
+ } catch {
2158
+ }
2159
+ return n;
2160
+ });
2161
+ bump();
2162
+ });
2163
+ _$insert(_el$3, () => renderTick() >= 0 && open() ? "\u25BC " : "\u25B6 ");
2164
+ _$insert(_el$4, () => t("panel.title"));
2165
+ _$insert(_el$2, _$createComponent(Show, {
2166
+ get when() {
2167
+ return showVersion();
2168
+ },
2169
+ get children() {
2170
+ var _el$5 = _$createElement("span");
2171
+ _$insert(_el$5, versionText);
2172
+ _$effect((_$p) => _$setProp(_el$5, "style", {
2173
+ fg: dimColor(pal().muted, 0.75)
2174
+ }, _$p));
2175
+ return _el$5;
2176
+ }
2177
+ }), null);
2178
+ _$insert(_el$2, (() => {
2179
+ var _c$ = _$memo(() => !!anyEntry());
2180
+ return () => _c$() ? [(() => {
2181
+ var _el$11 = _$createElement("span");
2182
+ _$insert(_el$11, () => " ".repeat(spacerCols()));
2183
+ _$effect((_$p) => _$setProp(_el$11, "style", {
2184
+ fg: pal().muted
2185
+ }, _$p));
2186
+ return _el$11;
2187
+ })(), (() => {
2188
+ var _el$12 = _$createElement("span");
2189
+ _$insert(_el$12, () => summaryParts().done);
2190
+ _$effect((_$p) => _$setProp(_el$12, "style", {
2191
+ fg: pal().success
2192
+ }, _$p));
2193
+ return _el$12;
2194
+ })(), _$memo(() => _$memo(() => runningCount() > 0)() && (() => {
2195
+ var _el$13 = _$createElement("span"), _el$14 = _$createTextNode(` `);
2196
+ _$insertNode(_el$13, _el$14);
2197
+ _$insert(_el$13, () => summaryParts().running, null);
2198
+ _$effect((_$p) => _$setProp(_el$13, "style", {
2199
+ fg: pal().warning
2200
+ }, _$p));
2201
+ return _el$13;
2202
+ })()), _$memo(() => _$memo(() => errCount() > 0)() && (() => {
2203
+ var _el$15 = _$createElement("span"), _el$16 = _$createTextNode(` `);
2204
+ _$insertNode(_el$15, _el$16);
2205
+ _$insert(_el$15, () => summaryParts().err, null);
2206
+ _$effect((_$p) => _$setProp(_el$15, "style", {
2207
+ fg: pal().error
2208
+ }, _$p));
2209
+ return _el$15;
2210
+ })()), _$memo(() => _$memo(() => !!summaryParts().duration)() ? (() => {
2211
+ var _el$17 = _$createElement("span"), _el$18 = _$createTextNode(` `);
2212
+ _$insertNode(_el$17, _el$18);
2213
+ _$insert(_el$17, () => summaryParts().duration, null);
2214
+ _$effect((_$p) => _$setProp(_el$17, "style", {
2215
+ fg: pal().muted
2216
+ }, _$p));
2217
+ return _el$17;
2218
+ })() : null), _$memo(() => _$memo(() => !!summaryParts().cost)() ? (() => {
2219
+ var _el$19 = _$createElement("span"), _el$20 = _$createTextNode(` `);
2220
+ _$insertNode(_el$19, _el$20);
2221
+ _$insert(_el$19, () => summaryParts().cost, null);
2222
+ _$effect((_$p) => _$setProp(_el$19, "style", {
2223
+ fg: pal().warning
2224
+ }, _$p));
2225
+ return _el$19;
2226
+ })() : null)] : null;
2227
+ })(), null);
2228
+ _$insert(_el$, _$createComponent(Show, {
2229
+ get when() {
2230
+ return open();
2231
+ },
2232
+ get children() {
2233
+ return [(() => {
2234
+ var _el$6 = _$createElement("text");
2235
+ _$insert(_el$6, sep);
2236
+ _$effect((_$p) => _$setProp(_el$6, "fg", pal().muted, _$p));
2237
+ return _el$6;
2238
+ })(), _$createComponent(Show, {
2239
+ get when() {
2240
+ return anyEntry();
2241
+ },
2242
+ get fallback() {
2243
+ return (() => {
2244
+ var _el$21 = _$createElement("text"), _el$22 = _$createTextNode(` &gt; `), _el$24 = _$createTextNode(` `);
2245
+ _$insertNode(_el$21, _el$22);
2246
+ _$insertNode(_el$21, _el$24);
2247
+ _$insert(_el$21, () => t("status.none"), _el$24);
2248
+ _$effect((_$p) => _$setProp(_el$21, "style", {
2249
+ fg: pal().muted
2250
+ }, _$p));
2251
+ return _el$21;
2252
+ })();
2253
+ },
2254
+ get children() {
2255
+ var _el$7 = _$createElement("box");
2256
+ _$setProp(_el$7, "onMouseScroll", (e) => {
2257
+ if (props.scrollMode() === "click") return;
2258
+ const total = entryList().length;
2259
+ const m = max();
2260
+ if (total <= m) return;
2261
+ const dir = e.button === 0 ? 1 : -1;
2262
+ setScrollOffset((prev) => {
2263
+ const next = Math.max(0, Math.min(prev + dir, total - m));
2264
+ try {
2265
+ persistScroll(props.sessionId, next);
2266
+ } catch {
2267
+ }
2268
+ return next;
2269
+ });
2270
+ });
2271
+ _$insert(_el$7, _$createComponent(Show, {
2272
+ get when() {
2273
+ return hiddenAbove() > 0;
2274
+ },
2275
+ get children() {
2276
+ var _el$8 = _$createElement("text"), _el$9 = _$createElement("span"), _el$0 = _$createTextNode(` &uarr; `), _el$10 = _$createTextNode(` `);
2277
+ _$insertNode(_el$8, _el$9);
2278
+ _$setProp(_el$8, "onMouseOver", () => setHoveredMoreAbove(true));
2279
+ _$setProp(_el$8, "onMouseOut", () => setHoveredMoreAbove(false));
2280
+ _$setProp(_el$8, "onMouseUp", () => {
2281
+ const total = entryList().length;
2282
+ const m = max();
2283
+ if (total <= m) return;
2284
+ const next = Math.max(0, scrollOffset() - m);
2285
+ if (next === 0) {
2286
+ setTimeout(() => {
2287
+ setScrollOffset(next);
2288
+ try {
2289
+ persistScroll(props.sessionId, next);
2290
+ } catch {
2291
+ }
2292
+ }, 0);
2293
+ } else {
2294
+ setScrollOffset(next);
2295
+ try {
2296
+ persistScroll(props.sessionId, next);
2297
+ } catch {
2298
+ }
2299
+ }
2300
+ });
2301
+ _$insertNode(_el$9, _el$0);
2302
+ _$insertNode(_el$9, _el$10);
2303
+ _$insert(_el$9, hiddenAbove, _el$10);
2304
+ _$insert(_el$9, () => t("scroll.more"), null);
2305
+ _$effect((_$p) => _$setProp(_el$9, "style", {
2306
+ fg: hoveredMoreAbove() ? pal().warning : pal().muted
2307
+ }, _$p));
2308
+ return _el$8;
2309
+ }
2310
+ }), null);
2311
+ _$insert(_el$7, _$createComponent(For, {
2312
+ get each() {
2313
+ return visibleList();
2314
+ },
2315
+ children: (entry) => {
2316
+ const isExpanded = () => expanded() === entry.id;
2317
+ const isRunning = entry.status === "running";
2318
+ const isCancelRequested = entry.status === "cancel_requested";
2319
+ const isCancelled = entry.status === "cancelled";
2320
+ const isError = entry.status === "error";
2321
+ const isActiveRunning = isRunning || isCancelRequested;
2322
+ const elapsed = () => (entry.endedAt ?? now()) - entry.startedAt;
2323
+ const statusDot = () => "\u25CF";
2324
+ const statusColor = () => {
2325
+ if (isCancelled) return pal().muted;
2326
+ if (!isActiveRunning) return isError ? pal().error : pal().success;
2327
+ const t2 = (Math.sin(now() % 2e3 / 2e3 * Math.PI * 2 - Math.PI / 2) + 1) / 2;
2328
+ const a = rgb(pal().muted), b = rgb(pal().warning);
2329
+ if (!a || !b) return pal().warning;
2330
+ const r = Math.round(a.r + (b.r - a.r) * t2);
2331
+ const g = Math.round(a.g + (b.g - a.g) * t2);
2332
+ const bl = Math.round(a.b + (b.b - a.b) * t2);
2333
+ return "#" + [r, g, bl].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
2334
+ };
2335
+ const timeColor = () => isActiveRunning ? pal().warning : isError ? pal().error : pal().muted;
2336
+ const tokenText = () => !isExpanded() && entry.tokens !== void 0 && entry.tokens > 0 ? ` ${fmtTokens(entry.tokens)}` : "";
2337
+ const timeText = () => !isExpanded() && (elapsed() >= 2e3 || entry.endedAt !== void 0) ? fmtDurationShort(elapsed(), isActiveRunning) : "";
2338
+ const suffixW = () => {
2339
+ let w = 0;
2340
+ const t2 = timeText();
2341
+ if (t2) w += 1 + visualWidth(t2);
2342
+ const tk = tokenText();
2343
+ if (tk) w += visualWidth(tk);
2344
+ return w;
2345
+ };
2346
+ const labelAvail = () => Math.max(6, panelWidth() - LEFT_PAD - suffixW());
2347
+ const labelText = () => {
2348
+ const max2 = labelAvail();
2349
+ const text = entry.title || entry.agent;
2350
+ const truncated = truncate(text, max2);
2351
+ const pad = Math.max(0, max2 - visualWidth(truncated));
2352
+ return truncated + " ".repeat(pad);
2353
+ };
2354
+ return [(() => {
2355
+ var _el$25 = _$createElement("text"), _el$26 = _$createElement("span"), _el$27 = _$createTextNode(` `), _el$28 = _$createElement("span"), _el$29 = _$createTextNode(` `), _el$30 = _$createElement("span");
2356
+ _$insertNode(_el$25, _el$26);
2357
+ _$insertNode(_el$25, _el$27);
2358
+ _$insertNode(_el$25, _el$28);
2359
+ _$insertNode(_el$25, _el$29);
2360
+ _$insertNode(_el$25, _el$30);
2361
+ _$setProp(_el$25, "onMouseUp", () => toggleExpand(entry.id));
2362
+ _$insert(_el$26, () => isExpanded() ? "\u25BC" : "\u25B6");
2363
+ _$insert(_el$28, statusDot);
2364
+ _$insert(_el$30, labelText);
2365
+ _$insert(_el$25, (() => {
2366
+ var _c$2 = _$memo(() => !!timeText());
2367
+ return () => _c$2() ? [" ", (() => {
2368
+ var _el$82 = _$createElement("span");
2369
+ _$insert(_el$82, timeText);
2370
+ _$effect((_$p) => _$setProp(_el$82, "style", {
2371
+ fg: timeColor()
2372
+ }, _$p));
2373
+ return _el$82;
2374
+ })()] : null;
2375
+ })(), null);
2376
+ _$insert(_el$25, (() => {
2377
+ var _c$3 = _$memo(() => !!tokenText());
2378
+ return () => _c$3() ? (() => {
2379
+ var _el$83 = _$createElement("span");
2380
+ _$insert(_el$83, tokenText);
2381
+ _$effect((_$p) => _$setProp(_el$83, "style", {
2382
+ fg: pal().muted
2383
+ }, _$p));
2384
+ return _el$83;
2385
+ })() : null;
2386
+ })(), null);
2387
+ _$effect((_p$) => {
2388
+ var _v$3 = {
2389
+ fg: pal().muted
2390
+ }, _v$4 = {
2391
+ fg: statusColor()
2392
+ }, _v$5 = {
2393
+ fg: pal().text
2394
+ };
2395
+ _v$3 !== _p$.e && (_p$.e = _$setProp(_el$26, "style", _v$3, _p$.e));
2396
+ _v$4 !== _p$.t && (_p$.t = _$setProp(_el$28, "style", _v$4, _p$.t));
2397
+ _v$5 !== _p$.a && (_p$.a = _$setProp(_el$30, "style", _v$5, _p$.a));
2398
+ return _p$;
2399
+ }, {
2400
+ e: void 0,
2401
+ t: void 0,
2402
+ a: void 0
2403
+ });
2404
+ return _el$25;
2405
+ })(), _$createComponent(Show, {
2406
+ get when() {
2407
+ return isExpanded();
2408
+ },
2409
+ get children() {
2410
+ return [(() => {
2411
+ var _el$31 = _$createElement("text"), _el$32 = _$createTextNode(` `), _el$33 = _$createElement("span"), _el$34 = _$createTextNode(`: `), _el$35 = _$createElement("span"), _el$36 = _$createElement("span");
2412
+ _$insertNode(_el$31, _el$32);
2413
+ _$insertNode(_el$31, _el$33);
2414
+ _$insertNode(_el$31, _el$35);
2415
+ _$insertNode(_el$31, _el$36);
2416
+ _$insertNode(_el$33, _el$34);
2417
+ _$insert(_el$33, () => t("agent.label"), _el$34);
2418
+ _$insert(_el$35, () => " ".repeat(expandedPad(t("agent.label"))));
2419
+ _$insert(_el$36, () => entry.agent);
2420
+ _$effect((_p$) => {
2421
+ var _v$6 = {
2422
+ fg: pal().primary
2423
+ }, _v$7 = {
2424
+ fg: pal().muted
2425
+ }, _v$8 = {
2426
+ fg: pal().muted
2427
+ };
2428
+ _v$6 !== _p$.e && (_p$.e = _$setProp(_el$33, "style", _v$6, _p$.e));
2429
+ _v$7 !== _p$.t && (_p$.t = _$setProp(_el$35, "style", _v$7, _p$.t));
2430
+ _v$8 !== _p$.a && (_p$.a = _$setProp(_el$36, "style", _v$8, _p$.a));
2431
+ return _p$;
2432
+ }, {
2433
+ e: void 0,
2434
+ t: void 0,
2435
+ a: void 0
2436
+ });
2437
+ return _el$31;
2438
+ })(), (() => {
2439
+ var _el$37 = _$createElement("text"), _el$38 = _$createTextNode(` `), _el$39 = _$createElement("span"), _el$40 = _$createTextNode(`: `), _el$41 = _$createElement("span"), _el$42 = _$createElement("span");
2440
+ _$insertNode(_el$37, _el$38);
2441
+ _$insertNode(_el$37, _el$39);
2442
+ _$insertNode(_el$37, _el$41);
2443
+ _$insertNode(_el$37, _el$42);
2444
+ _$insertNode(_el$39, _el$40);
2445
+ _$insert(_el$39, () => t("status.label"), _el$40);
2446
+ _$insert(_el$41, () => " ".repeat(expandedPad(t("status.label"))));
2447
+ _$insert(_el$42, () => isActiveRunning ? t("status.running") : isCancelled ? t("status.cancelled") : isError ? t("status.error") : t("status.done"));
2448
+ _$effect((_p$) => {
2449
+ var _v$9 = {
2450
+ fg: pal().primary
2451
+ }, _v$0 = {
2452
+ fg: pal().muted
2453
+ }, _v$1 = {
2454
+ fg: isActiveRunning ? pal().warning : isCancelled ? pal().muted : isError ? pal().error : pal().success
2455
+ };
2456
+ _v$9 !== _p$.e && (_p$.e = _$setProp(_el$39, "style", _v$9, _p$.e));
2457
+ _v$0 !== _p$.t && (_p$.t = _$setProp(_el$41, "style", _v$0, _p$.t));
2458
+ _v$1 !== _p$.a && (_p$.a = _$setProp(_el$42, "style", _v$1, _p$.a));
2459
+ return _p$;
2460
+ }, {
2461
+ e: void 0,
2462
+ t: void 0,
2463
+ a: void 0
2464
+ });
2465
+ return _el$37;
2466
+ })(), _$createComponent(Show, {
2467
+ get when() {
2468
+ return elapsed() >= 2e3 || entry.endedAt !== void 0;
2469
+ },
2470
+ get children() {
2471
+ var _el$43 = _$createElement("text"), _el$44 = _$createTextNode(` `), _el$45 = _$createElement("span"), _el$46 = _$createTextNode(`: `), _el$47 = _$createElement("span"), _el$48 = _$createElement("span");
2472
+ _$insertNode(_el$43, _el$44);
2473
+ _$insertNode(_el$43, _el$45);
2474
+ _$insertNode(_el$43, _el$47);
2475
+ _$insertNode(_el$43, _el$48);
2476
+ _$insertNode(_el$45, _el$46);
2477
+ _$insert(_el$45, () => t("time.label"), _el$46);
2478
+ _$insert(_el$47, () => " ".repeat(expandedPad(t("time.label"))));
2479
+ _$insert(_el$48, () => fmtDurationShort(elapsed(), isActiveRunning));
2480
+ _$effect((_p$) => {
2481
+ var _v$10 = {
2482
+ fg: pal().primary
2483
+ }, _v$11 = {
2484
+ fg: pal().muted
2485
+ }, _v$12 = {
2486
+ fg: pal().muted
2487
+ };
2488
+ _v$10 !== _p$.e && (_p$.e = _$setProp(_el$45, "style", _v$10, _p$.e));
2489
+ _v$11 !== _p$.t && (_p$.t = _$setProp(_el$47, "style", _v$11, _p$.t));
2490
+ _v$12 !== _p$.a && (_p$.a = _$setProp(_el$48, "style", _v$12, _p$.a));
2491
+ return _p$;
2492
+ }, {
2493
+ e: void 0,
2494
+ t: void 0,
2495
+ a: void 0
2496
+ });
2497
+ return _el$43;
2498
+ }
2499
+ }), _$createComponent(Show, {
2500
+ get when() {
2501
+ return entry.tokens !== void 0;
2502
+ },
2503
+ get children() {
2504
+ var _el$49 = _$createElement("text"), _el$50 = _$createTextNode(` `), _el$51 = _$createElement("span"), _el$52 = _$createTextNode(`: `), _el$53 = _$createElement("span"), _el$54 = _$createElement("span");
2505
+ _$insertNode(_el$49, _el$50);
2506
+ _$insertNode(_el$49, _el$51);
2507
+ _$insertNode(_el$49, _el$53);
2508
+ _$insertNode(_el$49, _el$54);
2509
+ _$insertNode(_el$51, _el$52);
2510
+ _$insert(_el$51, () => t("tokens.label"), _el$52);
2511
+ _$insert(_el$53, () => " ".repeat(expandedPad(t("tokens.label"))));
2512
+ _$insert(_el$54, () => fmtTokens(entry.tokens));
2513
+ _$effect((_p$) => {
2514
+ var _v$13 = {
2515
+ fg: pal().primary
2516
+ }, _v$14 = {
2517
+ fg: pal().muted
2518
+ }, _v$15 = {
2519
+ fg: pal().muted
2520
+ };
2521
+ _v$13 !== _p$.e && (_p$.e = _$setProp(_el$51, "style", _v$13, _p$.e));
2522
+ _v$14 !== _p$.t && (_p$.t = _$setProp(_el$53, "style", _v$14, _p$.t));
2523
+ _v$15 !== _p$.a && (_p$.a = _$setProp(_el$54, "style", _v$15, _p$.a));
2524
+ return _p$;
2525
+ }, {
2526
+ e: void 0,
2527
+ t: void 0,
2528
+ a: void 0
2529
+ });
2530
+ return _el$49;
2531
+ }
2532
+ }), _$createComponent(Show, {
2533
+ get when() {
2534
+ return entry.error;
2535
+ },
2536
+ get children() {
2537
+ var _el$55 = _$createElement("text"), _el$56 = _$createTextNode(` `), _el$57 = _$createElement("span"), _el$58 = _$createTextNode(`: `), _el$59 = _$createElement("span"), _el$60 = _$createElement("span");
2538
+ _$insertNode(_el$55, _el$56);
2539
+ _$insertNode(_el$55, _el$57);
2540
+ _$insertNode(_el$55, _el$59);
2541
+ _$insertNode(_el$55, _el$60);
2542
+ _$insertNode(_el$57, _el$58);
2543
+ _$insert(_el$57, () => t("error.label"), _el$58);
2544
+ _$insert(_el$59, () => " ".repeat(expandedPad(t("error.label"))));
2545
+ _$insert(_el$60, () => truncate(String(entry.error), expandedValAvail()));
2546
+ _$effect((_p$) => {
2547
+ var _v$16 = {
2548
+ fg: pal().error
2549
+ }, _v$17 = {
2550
+ fg: pal().muted
2551
+ }, _v$18 = {
2552
+ fg: pal().error
2553
+ };
2554
+ _v$16 !== _p$.e && (_p$.e = _$setProp(_el$57, "style", _v$16, _p$.e));
2555
+ _v$17 !== _p$.t && (_p$.t = _$setProp(_el$59, "style", _v$17, _p$.t));
2556
+ _v$18 !== _p$.a && (_p$.a = _$setProp(_el$60, "style", _v$18, _p$.a));
2557
+ return _p$;
2558
+ }, {
2559
+ e: void 0,
2560
+ t: void 0,
2561
+ a: void 0
2562
+ });
2563
+ return _el$55;
2564
+ }
2565
+ }), _$createComponent(Show, {
2566
+ get when() {
2567
+ return entry.cost !== void 0;
2568
+ },
2569
+ get children() {
2570
+ return (() => {
2571
+ const cost = entry.cost;
2572
+ return (() => {
2573
+ var _el$84 = _$createElement("text"), _el$85 = _$createTextNode(` `), _el$86 = _$createElement("span"), _el$87 = _$createTextNode(`: `), _el$88 = _$createElement("span"), _el$89 = _$createElement("span"), _el$90 = _$createTextNode(`$`);
2574
+ _$insertNode(_el$84, _el$85);
2575
+ _$insertNode(_el$84, _el$86);
2576
+ _$insertNode(_el$84, _el$88);
2577
+ _$insertNode(_el$84, _el$89);
2578
+ _$insertNode(_el$86, _el$87);
2579
+ _$insert(_el$86, () => t("cost.label"), _el$87);
2580
+ _$insert(_el$88, () => " ".repeat(expandedPad(t("cost.label"))));
2581
+ _$insertNode(_el$89, _el$90);
2582
+ _$insert(_el$89, () => cost.toFixed(4), null);
2583
+ _$effect((_p$) => {
2584
+ var _v$29 = {
2585
+ fg: pal().primary
2586
+ }, _v$30 = {
2587
+ fg: pal().muted
2588
+ }, _v$31 = {
2589
+ fg: pal().muted
2590
+ };
2591
+ _v$29 !== _p$.e && (_p$.e = _$setProp(_el$86, "style", _v$29, _p$.e));
2592
+ _v$30 !== _p$.t && (_p$.t = _$setProp(_el$88, "style", _v$30, _p$.t));
2593
+ _v$31 !== _p$.a && (_p$.a = _$setProp(_el$89, "style", _v$31, _p$.a));
2594
+ return _p$;
2595
+ }, {
2596
+ e: void 0,
2597
+ t: void 0,
2598
+ a: void 0
2599
+ });
2600
+ return _el$84;
2601
+ })();
2602
+ })();
2603
+ }
2604
+ }), _$createComponent(Show, {
2605
+ get when() {
2606
+ return entry.model;
2607
+ },
2608
+ get children() {
2609
+ var _el$61 = _$createElement("text"), _el$62 = _$createTextNode(` `), _el$63 = _$createElement("span"), _el$64 = _$createTextNode(`: `), _el$65 = _$createElement("span"), _el$66 = _$createElement("span");
2610
+ _$insertNode(_el$61, _el$62);
2611
+ _$insertNode(_el$61, _el$63);
2612
+ _$insertNode(_el$61, _el$65);
2613
+ _$insertNode(_el$61, _el$66);
2614
+ _$insertNode(_el$63, _el$64);
2615
+ _$insert(_el$63, () => t("model.label"), _el$64);
2616
+ _$insert(_el$65, () => " ".repeat(expandedPad(t("model.label"))));
2617
+ _$insert(_el$66, () => truncate(entry.model, expandedValAvail()));
2618
+ _$effect((_p$) => {
2619
+ var _v$19 = {
2620
+ fg: pal().primary
2621
+ }, _v$20 = {
2622
+ fg: pal().muted
2623
+ }, _v$21 = {
2624
+ fg: pal().muted
2625
+ };
2626
+ _v$19 !== _p$.e && (_p$.e = _$setProp(_el$63, "style", _v$19, _p$.e));
2627
+ _v$20 !== _p$.t && (_p$.t = _$setProp(_el$65, "style", _v$20, _p$.t));
2628
+ _v$21 !== _p$.a && (_p$.a = _$setProp(_el$66, "style", _v$21, _p$.a));
2629
+ return _p$;
2630
+ }, {
2631
+ e: void 0,
2632
+ t: void 0,
2633
+ a: void 0
2634
+ });
2635
+ return _el$61;
2636
+ }
2637
+ }), _$createComponent(Show, {
2638
+ get when() {
2639
+ return entry.todoTotal !== void 0;
2640
+ },
2641
+ get children() {
2642
+ var _el$67 = _$createElement("text"), _el$68 = _$createTextNode(` `), _el$69 = _$createElement("span"), _el$70 = _$createTextNode(`: `), _el$71 = _$createElement("span"), _el$72 = _$createElement("span"), _el$73 = _$createTextNode(`/`);
2643
+ _$insertNode(_el$67, _el$68);
2644
+ _$insertNode(_el$67, _el$69);
2645
+ _$insertNode(_el$67, _el$71);
2646
+ _$insertNode(_el$67, _el$72);
2647
+ _$insertNode(_el$69, _el$70);
2648
+ _$insert(_el$69, () => t("todo.label"), _el$70);
2649
+ _$insert(_el$71, () => " ".repeat(expandedPad(t("todo.label"))));
2650
+ _$insertNode(_el$72, _el$73);
2651
+ _$insert(_el$72, () => entry.todoDone, _el$73);
2652
+ _$insert(_el$72, () => entry.todoTotal, null);
2653
+ _$effect((_p$) => {
2654
+ var _v$22 = {
2655
+ fg: pal().primary
2656
+ }, _v$23 = {
2657
+ fg: pal().muted
2658
+ }, _v$24 = {
2659
+ fg: pal().muted
2660
+ };
2661
+ _v$22 !== _p$.e && (_p$.e = _$setProp(_el$69, "style", _v$22, _p$.e));
2662
+ _v$23 !== _p$.t && (_p$.t = _$setProp(_el$71, "style", _v$23, _p$.t));
2663
+ _v$24 !== _p$.a && (_p$.a = _$setProp(_el$72, "style", _v$24, _p$.a));
2664
+ return _p$;
2665
+ }, {
2666
+ e: void 0,
2667
+ t: void 0,
2668
+ a: void 0
2669
+ });
2670
+ return _el$67;
2671
+ }
2672
+ }), _$createComponent(Show, {
2673
+ get when() {
2674
+ return entry.sessionId;
2675
+ },
2676
+ get children() {
2677
+ var _el$74 = _$createElement("text"), _el$75 = _$createTextNode(` `), _el$76 = _$createElement("span"), _el$77 = _$createTextNode(`: `), _el$78 = _$createElement("span"), _el$79 = _$createElement("span"), _el$80 = _$createElement("span");
2678
+ _$insertNode(_el$74, _el$75);
2679
+ _$insertNode(_el$74, _el$76);
2680
+ _$insertNode(_el$74, _el$78);
2681
+ _$insertNode(_el$74, _el$79);
2682
+ _$insertNode(_el$74, _el$80);
2683
+ _$setProp(_el$74, "onMouseUp", async () => {
2684
+ const sessionId = entry.sessionId;
2685
+ if (!sessionId) return;
2686
+ const result = await copyText(sessionId);
2687
+ if (result.copied) {
2688
+ props.api.ui.toast(t("session.toast.copied"), {
2689
+ variant: "success",
2690
+ title: entry.title || entry.agent,
2691
+ duration: 2500
2692
+ });
2693
+ return;
2694
+ }
2695
+ props.api.ui.toast(`${sessionId}
2696
+
2697
+ ${t("session.toast.copy_failed")}`, {
2698
+ variant: "warning",
2699
+ title: entry.title || entry.agent,
2700
+ duration: 8e3
2701
+ });
2702
+ });
2703
+ _$insertNode(_el$76, _el$77);
2704
+ _$insert(_el$76, () => t("session.label"), _el$77);
2705
+ _$insert(_el$78, () => " ".repeat(expandedPad(t("session.label"))));
2706
+ _$insert(_el$79, () => truncate(entry.sessionId, expandedValAvail() - visualWidth(" \u2398")));
2707
+ _$insertNode(_el$80, _$createTextNode(` \u2398`));
2708
+ _$effect((_p$) => {
2709
+ var _v$25 = {
2710
+ fg: pal().primary
2711
+ }, _v$26 = {
2712
+ fg: pal().muted
2713
+ }, _v$27 = {
2714
+ fg: pal().muted
2715
+ }, _v$28 = {
2716
+ fg: pal().warning
2717
+ };
2718
+ _v$25 !== _p$.e && (_p$.e = _$setProp(_el$76, "style", _v$25, _p$.e));
2719
+ _v$26 !== _p$.t && (_p$.t = _$setProp(_el$78, "style", _v$26, _p$.t));
2720
+ _v$27 !== _p$.a && (_p$.a = _$setProp(_el$79, "style", _v$27, _p$.a));
2721
+ _v$28 !== _p$.o && (_p$.o = _$setProp(_el$80, "style", _v$28, _p$.o));
2722
+ return _p$;
2723
+ }, {
2724
+ e: void 0,
2725
+ t: void 0,
2726
+ a: void 0,
2727
+ o: void 0
2728
+ });
2729
+ return _el$74;
2730
+ }
2731
+ }), _$createComponent(Show, {
2732
+ get when() {
2733
+ return entry.sessionId || isRunning;
2734
+ },
2735
+ get children() {
2736
+ return (() => {
2737
+ const openPrefix = () => " \u2192 ";
2738
+ const openFull = () => entry.sessionId ? openPrefix() + t("open.label") : "";
2739
+ const openW = () => entry.sessionId ? visualWidth(openFull()) : 0;
2740
+ const cancelLabel = () => ` ${t("cancel.label")}`;
2741
+ const dismissLabel = () => ` ${t("dismiss.label")}`;
2742
+ const rightW = (isRunning ? visualWidth(dismissLabel()) : 0) + (isRunning && entry.sessionId ? visualWidth(cancelLabel()) : 0);
2743
+ const spacerW = () => Math.max(1, panelWidth() - openW() - rightW - 2);
2744
+ return (() => {
2745
+ var _el$91 = _$createElement("box"), _el$95 = _$createElement("text");
2746
+ _$insertNode(_el$91, _el$95);
2747
+ _$setProp(_el$91, "flexDirection", "row");
2748
+ _$insert(_el$91, _$createComponent(Show, {
2749
+ get when() {
2750
+ return entry.sessionId;
2751
+ },
2752
+ get children() {
2753
+ var _el$92 = _$createElement("text"), _el$93 = _$createElement("span"), _el$94 = _$createElement("span");
2754
+ _$insertNode(_el$92, _el$93);
2755
+ _$insertNode(_el$92, _el$94);
2756
+ _$setProp(_el$92, "onMouseOver", () => setHoveredOpen(entry.id));
2757
+ _$setProp(_el$92, "onMouseOut", () => setHoveredOpen(void 0));
2758
+ _$setProp(_el$92, "onMouseUp", () => {
2759
+ if (entry.sessionId) {
2760
+ props.api.route.navigateSession(entry.sessionId);
2761
+ }
2762
+ });
2763
+ _$insert(_el$93, openPrefix);
2764
+ _$insert(_el$94, () => t("open.label"));
2765
+ _$effect((_p$) => {
2766
+ var _v$32 = {
2767
+ fg: hoveredOpen() === entry.id ? pal().warning : pal().primary
2768
+ }, _v$33 = {
2769
+ fg: hoveredOpen() === entry.id ? pal().warning : pal().primary
2770
+ };
2771
+ _v$32 !== _p$.e && (_p$.e = _$setProp(_el$93, "style", _v$32, _p$.e));
2772
+ _v$33 !== _p$.t && (_p$.t = _$setProp(_el$94, "style", _v$33, _p$.t));
2773
+ return _p$;
2774
+ }, {
2775
+ e: void 0,
2776
+ t: void 0
2777
+ });
2778
+ return _el$92;
2779
+ }
2780
+ }), _el$95);
2781
+ _$insert(_el$95, () => " ".repeat(spacerW()));
2782
+ _$insert(_el$91, _$createComponent(Show, {
2783
+ get when() {
2784
+ return isRunning && entry.sessionId;
2785
+ },
2786
+ get children() {
2787
+ var _el$96 = _$createElement("text"), _el$97 = _$createElement("span");
2788
+ _$insertNode(_el$96, _el$97);
2789
+ _$setProp(_el$96, "onMouseOver", () => setHoveredCancel(entry.id));
2790
+ _$setProp(_el$96, "onMouseOut", () => setHoveredCancel(void 0));
2791
+ _$setProp(_el$96, "onMouseUp", () => cancelEntry(entry));
2792
+ _$insert(_el$97, cancelLabel);
2793
+ _$effect((_$p) => _$setProp(_el$97, "style", {
2794
+ fg: hoveredCancel() === entry.id ? pal().warning : pal().error
2795
+ }, _$p));
2796
+ return _el$96;
2797
+ }
2798
+ }), null);
2799
+ _$insert(_el$91, _$createComponent(Show, {
2800
+ when: isRunning,
2801
+ get children() {
2802
+ var _el$98 = _$createElement("text"), _el$99 = _$createElement("span");
2803
+ _$insertNode(_el$98, _el$99);
2804
+ _$setProp(_el$98, "onMouseOver", () => setHoveredDismiss(entry.id));
2805
+ _$setProp(_el$98, "onMouseOut", () => setHoveredDismiss(void 0));
2806
+ _$setProp(_el$98, "onMouseUp", () => {
2807
+ upsertEntry({
2808
+ id: entry.id,
2809
+ title: entry.title,
2810
+ agent: entry.agent,
2811
+ prompt: entry.prompt,
2812
+ status: "done"
2813
+ });
2814
+ });
2815
+ _$insert(_el$99, dismissLabel);
2816
+ _$effect((_$p) => _$setProp(_el$99, "style", {
2817
+ fg: hoveredDismiss() === entry.id ? pal().warning : pal().muted
2818
+ }, _$p));
2819
+ return _el$98;
2820
+ }
2821
+ }), null);
2822
+ _$effect((_$p) => _$setProp(_el$95, "style", {
2823
+ fg: pal().muted
2824
+ }, _$p));
2825
+ return _el$91;
2826
+ })();
2827
+ })();
2828
+ }
2829
+ })];
2830
+ }
2831
+ })];
2832
+ }
2833
+ }), null);
2834
+ _$insert(_el$7, _$createComponent(Show, {
2835
+ get when() {
2836
+ return hiddenBelow() > 0 || (props.sortOrder() === "desc" ? scrollOffset() > 0 : entryList().length > max() && clampedOffset() < entryList().length - max());
2837
+ },
2838
+ get children() {
2839
+ return (() => {
2840
+ const showMore = hiddenBelow() > 0;
2841
+ const showTop = props.sortOrder() === "desc" ? scrollOffset() > 0 : entryList().length > max() && clampedOffset() < entryList().length - max();
2842
+ const left = showMore ? ` \u2193 ${hiddenBelow()} ${t("scroll.more")}` : " ";
2843
+ const right = props.sortOrder() === "desc" ? `\u2191 ${t("scroll.top")}` : `\u2193 ${t("scroll.bottom")}`;
2844
+ const pad = showTop ? Math.max(1, panelWidth() - visualWidth(left) - visualWidth(right)) : 0;
2845
+ return (() => {
2846
+ var _el$100 = _$createElement("box"), _el$101 = _$createElement("text"), _el$102 = _$createElement("span");
2847
+ _$insertNode(_el$100, _el$101);
2848
+ _$setProp(_el$100, "flexDirection", "row");
2849
+ _$insertNode(_el$101, _el$102);
2850
+ _$setProp(_el$101, "onMouseOver", () => showMore && setHoveredMoreBelow(true));
2851
+ _$setProp(_el$101, "onMouseOut", () => setHoveredMoreBelow(false));
2852
+ _$setProp(_el$101, "onMouseUp", () => {
2853
+ if (!showMore) return;
2854
+ const total = entryList().length;
2855
+ const m = max();
2856
+ if (total <= m) return;
2857
+ setScrollOffset((prev) => Math.min(total - m, prev + m));
2858
+ try {
2859
+ persistScroll(props.sessionId, scrollOffset());
2860
+ } catch {
2861
+ }
2862
+ setHoveredMoreBelow(false);
2863
+ });
2864
+ _$insert(_el$102, left);
2865
+ _$insert(_el$100, showTop ? [(() => {
2866
+ var _el$103 = _$createElement("text");
2867
+ _$insert(_el$103, () => " ".repeat(pad));
2868
+ _$effect((_$p) => _$setProp(_el$103, "style", {
2869
+ fg: pal().muted
2870
+ }, _$p));
2871
+ return _el$103;
2872
+ })(), (() => {
2873
+ var _el$104 = _$createElement("text"), _el$105 = _$createElement("span");
2874
+ _$insertNode(_el$104, _el$105);
2875
+ _$setProp(_el$104, "onMouseOver", () => setHoveredTop(true));
2876
+ _$setProp(_el$104, "onMouseOut", () => setHoveredTop(false));
2877
+ _$setProp(_el$104, "onMouseUp", () => {
2878
+ const total = entryList().length;
2879
+ const m = max();
2880
+ if (props.sortOrder() === "desc") {
2881
+ setScrollOffset(0);
2882
+ } else {
2883
+ setScrollOffset(Math.max(0, total - m));
2884
+ }
2885
+ setHoveredTop(false);
2886
+ });
2887
+ _$insert(_el$105, right);
2888
+ _$effect((_$p) => _$setProp(_el$105, "style", {
2889
+ fg: hoveredTop() ? pal().warning : pal().muted
2890
+ }, _$p));
2891
+ return _el$104;
2892
+ })()] : null, null);
2893
+ _$effect((_$p) => _$setProp(_el$102, "style", {
2894
+ fg: showMore && hoveredMoreBelow() ? pal().warning : pal().muted
2895
+ }, _$p));
2896
+ return _el$100;
2897
+ })();
2898
+ })();
2899
+ }
2900
+ }), null);
2901
+ return _el$7;
2902
+ }
2903
+ })];
2904
+ }
2905
+ }), null);
2906
+ _$effect((_p$) => {
2907
+ var _v$ = {
2908
+ fg: pal().muted
2909
+ }, _v$2 = {
2910
+ fg: pal().primary
2911
+ };
2912
+ _v$ !== _p$.e && (_p$.e = _$setProp(_el$3, "style", _v$, _p$.e));
2913
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$4, "style", _v$2, _p$.t));
2914
+ return _p$;
2915
+ }, {
2916
+ e: void 0,
2917
+ t: void 0
2918
+ });
2919
+ return _el$;
2920
+ })();
2921
+ }
2922
+
2923
+ // src/v2/index.tsx
2924
+ function PluginRoot(props) {
2925
+ props.context.keymap.layer(() => ({
2926
+ mode: "global",
2927
+ commands: makeCommands(props.context, props.api, props.signals)
2928
+ }));
2929
+ return _$createComponent2(SubAgentPanel, {
2930
+ get api() {
2931
+ return props.api;
2932
+ },
2933
+ get theme() {
2934
+ return mapTheme(props.context.theme);
2935
+ },
2936
+ get lang() {
2937
+ return props.signals.lang;
2938
+ },
2939
+ get maxEntries() {
2940
+ return props.signals.maxEntries;
2941
+ },
2942
+ get sortOrder() {
2943
+ return props.signals.sortOrder;
2944
+ },
2945
+ get scrollMode() {
2946
+ return props.signals.scrollMode;
2947
+ },
2948
+ get sessionId() {
2949
+ return props.sessionID;
2950
+ }
2951
+ });
2952
+ }
2953
+ var mod = {
2954
+ id: "opencode-subagent-magazine",
2955
+ setup(context) {
2956
+ let lang;
2957
+ let maxEntries;
2958
+ let sortOrder;
2959
+ let scrollMode;
2960
+ const api = createPanelApi(context, {
2961
+ lang: () => lang(),
2962
+ maxEntries: () => maxEntries(),
2963
+ sortOrder: () => sortOrder(),
2964
+ scrollMode: () => scrollMode()
2965
+ });
2966
+ const storedLang = String(api.kv.get(SETTING_KEYS.lang, ""));
2967
+ const initialLang = LANG_META.some((m) => m.code === storedLang) ? storedLang : detectLang();
2968
+ const [langSignal, setLang] = createSignal3(initialLang);
2969
+ const [maxSignal, setMaxEntries] = createSignal3(Number(api.kv.get(SETTING_KEYS.maxEntries, "10")) || 10);
2970
+ const [orderSignal, setSortOrder] = createSignal3(String(api.kv.get(SETTING_KEYS.order, "desc")) === "asc" ? "asc" : "desc");
2971
+ const [scrollSignal, setScrollMode] = createSignal3(String(api.kv.get(SETTING_KEYS.scrollMode, "wheel")) === "click" ? "click" : "wheel");
2972
+ lang = langSignal;
2973
+ maxEntries = maxSignal;
2974
+ sortOrder = orderSignal;
2975
+ scrollMode = scrollSignal;
2976
+ const signals = {
2977
+ lang,
2978
+ setLang,
2979
+ maxEntries,
2980
+ setMaxEntries,
2981
+ sortOrder,
2982
+ setSortOrder,
2983
+ scrollMode,
2984
+ setScrollMode,
2985
+ sessionId: ""
2986
+ };
2987
+ context.ui.slot({
2988
+ prepend: "sidebar.content",
2989
+ render: (props) => {
2990
+ signals.sessionId = String(props.sessionID ?? "");
2991
+ return _$createComponent2(PluginRoot, {
2992
+ context,
2993
+ api,
2994
+ signals,
2995
+ get sessionID() {
2996
+ return String(props.sessionID ?? "");
2997
+ }
2998
+ });
2999
+ }
3000
+ });
3001
+ },
3002
+ // V1 server 空实现(兼容标记):v2 加载 setup,V1 检测需要 server 字段识别为插件
3003
+ server: async () => ({})
3004
+ };
3005
+ var index_default = mod;
3006
+ export {
3007
+ index_default as default
3008
+ };