opencode-subagent-magazine 1.2.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js CHANGED
@@ -11,7 +11,7 @@ import { createElement as _$createElement } from "@opentui/solid";
11
11
  import { createMemo, createSignal, createEffect, onMount, onCleanup, untrack, Show, For } from "solid-js";
12
12
 
13
13
  // src/_version.ts
14
- var PLUGIN_VERSION = "1.2.1";
14
+ var PLUGIN_VERSION = "1.4.0";
15
15
 
16
16
  // src/index.tsx
17
17
  var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["task", "delegate", "call_omo_agent"]);
@@ -26,6 +26,8 @@ var I18N = {
26
26
  "error.label": "\u9519\u8BEF",
27
27
  "model.label": "\u6A21\u578B",
28
28
  "todo.label": "\u8FDB\u5EA6",
29
+ "session.label": "\u4F1A\u8BDD ID",
30
+ "session.toast.copy": "\u53EF\u624B\u52A8\u590D\u5236\u4E0A\u65B9 ID",
29
31
  "open.label": "\u8FDB\u5165\u4F1A\u8BDD",
30
32
  "cost.label": "\u8D39\u7528",
31
33
  "scroll.more": "\u66F4\u591A",
@@ -38,7 +40,20 @@ var I18N = {
38
40
  "order.desc": "\u964D\u5E8F\uFF08\u6700\u65B0\u5728\u524D\uFF09",
39
41
  "order.asc": "\u5347\u5E8F\uFF08\u6700\u65E9\u5728\u524D\uFF09",
40
42
  "scroll.wheel": "\u6EDA\u8F6E\u7FFB\u9875",
41
- "scroll.click": "\u70B9\u51FB\u7FFB\u9875"
43
+ "scroll.click": "\u70B9\u51FB\u7FFB\u9875",
44
+ "ttl.label": "\u6E05\u7406\u5468\u671F",
45
+ "ttl.3d": "3 \u5929",
46
+ "ttl.7d": "7 \u5929",
47
+ "ttl.14d": "14 \u5929",
48
+ "ttl.30d": "30 \u5929",
49
+ "ttl.unlimited": "\u65E0\u671F\u9650",
50
+ "ttl.toast": "\u6E05\u7406\u5468\u671F\u5DF2\u8BBE\u4E3A {n} \u5929",
51
+ "ttl.toast_unlimited": "\u6E05\u7406\u5468\u671F\u5DF2\u8BBE\u4E3A\u65E0\u671F\u9650",
52
+ "clear.title": "\u786E\u8BA4\u6E05\u9664",
53
+ "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",
54
+ "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",
55
+ "clear.done": "\u5DF2\u6E05\u9664 {n} \u6761\u5B50\u4EE3\u7406\u8BB0\u5F55",
56
+ "clear.empty": "\u5F53\u524D\u4F1A\u8BDD\u65E0\u5B50\u4EE3\u7406\u8BB0\u5F55"
42
57
  },
43
58
  en: {
44
59
  "panel.title": "SubAgent",
@@ -50,6 +65,8 @@ var I18N = {
50
65
  "error.label": "error",
51
66
  "model.label": "model",
52
67
  "todo.label": "todo",
68
+ "session.label": "session ID",
69
+ "session.toast.copy": "Copy the ID above manually",
53
70
  "open.label": "Open session",
54
71
  "cost.label": "cost",
55
72
  "scroll.more": "more",
@@ -62,7 +79,20 @@ var I18N = {
62
79
  "order.desc": "Desc (newest first)",
63
80
  "order.asc": "Asc (oldest first)",
64
81
  "scroll.wheel": "Wheel Scroll",
65
- "scroll.click": "Click Scroll"
82
+ "scroll.click": "Click Scroll",
83
+ "ttl.label": "TTL (Time to Live)",
84
+ "ttl.3d": "3 days",
85
+ "ttl.7d": "7 days",
86
+ "ttl.14d": "14 days",
87
+ "ttl.30d": "30 days",
88
+ "ttl.unlimited": "Never",
89
+ "ttl.toast": "TTL set to {n} days",
90
+ "ttl.toast_unlimited": "TTL set to Never",
91
+ "clear.title": "Confirm",
92
+ "clear.prompt": "Clear all sub-agent records for this session? This cannot be undone.",
93
+ "clear.prompt_running": "{n} sub-agent(s) are still running. Clearing will discard them permanently. Continue?",
94
+ "clear.done": "Cleared {n} sub-agent record(s)",
95
+ "clear.empty": "No sub-agent records in this session"
66
96
  }
67
97
  };
68
98
  function detectLang() {
@@ -187,10 +217,13 @@ function safeErrorMsg(err) {
187
217
  return "";
188
218
  }
189
219
  var globalEntryCache = /* @__PURE__ */ new Map();
220
+ var [clearTick, setClearTick] = createSignal(0);
190
221
  function SubAgentPanel(props) {
191
222
  const t = (key) => I18N[props.lang()][key] ?? key;
192
223
  const SESSION_DATA_KEY = `${KV_PREFIX}.session_data`;
193
- const TTL_MS = 3 * 24 * 60 * 60 * 1e3;
224
+ const ttlDaysRaw = parseInt(String(props.api.kv.get(`${KV_PREFIX}.ttl_days`, "3")), 10);
225
+ const ttlDays = Number.isNaN(ttlDaysRaw) ? 3 : ttlDaysRaw;
226
+ const TTL_MS = ttlDays * 24 * 60 * 60 * 1e3;
194
227
  const loadSessionData = () => {
195
228
  try {
196
229
  const raw = props.api.kv.get(SESSION_DATA_KEY, "{}");
@@ -205,12 +238,34 @@ function SubAgentPanel(props) {
205
238
  } catch {
206
239
  }
207
240
  };
241
+ const resolveParent = (sid) => {
242
+ try {
243
+ const session = props.api.state.session.get(sid);
244
+ const parentID = session?.parentID;
245
+ if (parentID) return {
246
+ parentSid: parentID,
247
+ isChild: true
248
+ };
249
+ } catch {
250
+ }
251
+ return {
252
+ parentSid: sid,
253
+ isChild: false
254
+ };
255
+ };
208
256
  const loadEntries = (sid) => {
209
257
  const m = /* @__PURE__ */ new Map();
210
258
  try {
211
- const rec = loadSessionData()[sid];
212
- if (rec?.entries) {
213
- for (const e of rec.entries) m.set(e.id, e);
259
+ const {
260
+ parentSid,
261
+ isChild
262
+ } = resolveParent(sid);
263
+ const rec = loadSessionData()[parentSid];
264
+ if (rec) {
265
+ const source = isChild ? rec.children?.[sid]?.entries : rec.entries;
266
+ if (source) {
267
+ for (const e of source) m.set(e.id, e);
268
+ }
214
269
  }
215
270
  } catch {
216
271
  }
@@ -222,11 +277,36 @@ function SubAgentPanel(props) {
222
277
  persistTimer = setTimeout(() => {
223
278
  try {
224
279
  const data = loadSessionData();
225
- data[sid] = {
226
- ...data[sid],
227
- ts: Date.now(),
228
- entries: [...entries2.values()]
229
- };
280
+ const {
281
+ parentSid,
282
+ isChild
283
+ } = resolveParent(sid);
284
+ if (isChild) {
285
+ if (!data[parentSid]) data[parentSid] = {
286
+ ts: Date.now(),
287
+ entries: [],
288
+ scroll: 0,
289
+ expanded: "",
290
+ children: {}
291
+ };
292
+ if (!data[parentSid].children) data[parentSid].children = {};
293
+ if (!data[parentSid].children[sid]) data[parentSid].children[sid] = {
294
+ scroll: 0,
295
+ expanded: "",
296
+ entries: []
297
+ };
298
+ data[parentSid].children[sid] = {
299
+ ...data[parentSid].children[sid],
300
+ entries: [...entries2.values()]
301
+ };
302
+ } else {
303
+ data[sid] = {
304
+ ...data[sid],
305
+ ts: Date.now(),
306
+ entries: [...entries2.values()],
307
+ children: data[sid]?.children ?? {}
308
+ };
309
+ }
230
310
  saveSessionData(data);
231
311
  } catch {
232
312
  }
@@ -235,11 +315,36 @@ function SubAgentPanel(props) {
235
315
  const persistScroll = (sid, scroll) => {
236
316
  try {
237
317
  const data = loadSessionData();
238
- data[sid] = {
239
- ...data[sid],
240
- ts: Date.now(),
241
- scroll
242
- };
318
+ const {
319
+ parentSid,
320
+ isChild
321
+ } = resolveParent(sid);
322
+ if (isChild) {
323
+ if (!data[parentSid]) data[parentSid] = {
324
+ ts: Date.now(),
325
+ entries: [],
326
+ scroll: 0,
327
+ expanded: "",
328
+ children: {}
329
+ };
330
+ if (!data[parentSid].children) data[parentSid].children = {};
331
+ if (!data[parentSid].children[sid]) data[parentSid].children[sid] = {
332
+ scroll: 0,
333
+ expanded: "",
334
+ entries: []
335
+ };
336
+ data[parentSid].children[sid] = {
337
+ ...data[parentSid].children[sid],
338
+ scroll
339
+ };
340
+ } else {
341
+ data[sid] = {
342
+ ...data[sid],
343
+ ts: Date.now(),
344
+ scroll,
345
+ children: data[sid]?.children ?? {}
346
+ };
347
+ }
243
348
  saveSessionData(data);
244
349
  } catch {
245
350
  }
@@ -247,16 +352,42 @@ function SubAgentPanel(props) {
247
352
  const persistExpanded = (sid, expanded2) => {
248
353
  try {
249
354
  const data = loadSessionData();
250
- data[sid] = {
251
- ...data[sid],
252
- ts: Date.now(),
253
- expanded: expanded2
254
- };
355
+ const {
356
+ parentSid,
357
+ isChild
358
+ } = resolveParent(sid);
359
+ if (isChild) {
360
+ if (!data[parentSid]) data[parentSid] = {
361
+ ts: Date.now(),
362
+ entries: [],
363
+ scroll: 0,
364
+ expanded: "",
365
+ children: {}
366
+ };
367
+ if (!data[parentSid].children) data[parentSid].children = {};
368
+ if (!data[parentSid].children[sid]) data[parentSid].children[sid] = {
369
+ scroll: 0,
370
+ expanded: "",
371
+ entries: []
372
+ };
373
+ data[parentSid].children[sid] = {
374
+ ...data[parentSid].children[sid],
375
+ expanded: expanded2
376
+ };
377
+ } else {
378
+ data[sid] = {
379
+ ...data[sid],
380
+ ts: Date.now(),
381
+ expanded: expanded2,
382
+ children: data[sid]?.children ?? {}
383
+ };
384
+ }
255
385
  saveSessionData(data);
256
386
  } catch {
257
387
  }
258
388
  };
259
389
  const cleanupOldSessions = () => {
390
+ if (ttlDays <= 0) return;
260
391
  try {
261
392
  const data = loadSessionData();
262
393
  const cutoff = Date.now() - TTL_MS;
@@ -288,11 +419,36 @@ function SubAgentPanel(props) {
288
419
  clearTimeout(persistTimer);
289
420
  try {
290
421
  const data = loadSessionData();
291
- data[props.sessionId] = {
292
- ...data[props.sessionId],
293
- ts: Date.now(),
294
- entries: [...next.values()]
295
- };
422
+ const {
423
+ parentSid,
424
+ isChild
425
+ } = resolveParent(props.sessionId);
426
+ if (isChild) {
427
+ if (!data[parentSid]) data[parentSid] = {
428
+ ts: Date.now(),
429
+ entries: [],
430
+ scroll: 0,
431
+ expanded: "",
432
+ children: {}
433
+ };
434
+ if (!data[parentSid].children) data[parentSid].children = {};
435
+ if (!data[parentSid].children[props.sessionId]) data[parentSid].children[props.sessionId] = {
436
+ scroll: 0,
437
+ expanded: "",
438
+ entries: []
439
+ };
440
+ data[parentSid].children[props.sessionId] = {
441
+ ...data[parentSid].children[props.sessionId],
442
+ entries: [...next.values()]
443
+ };
444
+ } else {
445
+ data[props.sessionId] = {
446
+ ...data[props.sessionId],
447
+ ts: Date.now(),
448
+ entries: [...next.values()],
449
+ children: data[props.sessionId]?.children ?? {}
450
+ };
451
+ }
296
452
  saveSessionData(data);
297
453
  } catch {
298
454
  }
@@ -313,10 +469,15 @@ function SubAgentPanel(props) {
313
469
  })());
314
470
  const [expanded, setExpanded] = createSignal((() => {
315
471
  try {
316
- return loadSessionData()[props.sessionId]?.expanded || void 0;
472
+ const {
473
+ parentSid,
474
+ isChild
475
+ } = resolveParent(props.sessionId);
476
+ const rec = loadSessionData()[parentSid];
477
+ if (rec) return isChild ? rec.children?.[props.sessionId]?.expanded || void 0 : rec.expanded || void 0;
317
478
  } catch {
318
- return void 0;
319
479
  }
480
+ return void 0;
320
481
  })());
321
482
  const [hoveredOpen, setHoveredOpen] = createSignal(void 0);
322
483
  const [hoveredDismiss, setHoveredDismiss] = createSignal(void 0);
@@ -325,7 +486,12 @@ function SubAgentPanel(props) {
325
486
  const [hoveredMoreBelow, setHoveredMoreBelow] = createSignal(false);
326
487
  const [scrollOffset, setScrollOffset] = createSignal((() => {
327
488
  try {
328
- return loadSessionData()[props.sessionId]?.scroll ?? 0;
489
+ const {
490
+ parentSid,
491
+ isChild
492
+ } = resolveParent(props.sessionId);
493
+ const rec = loadSessionData()[parentSid];
494
+ return isChild ? rec?.children?.[props.sessionId]?.scroll ?? 0 : rec?.scroll ?? 0;
329
495
  } catch {
330
496
  return 0;
331
497
  }
@@ -789,18 +955,37 @@ function SubAgentPanel(props) {
789
955
  });
790
956
  });
791
957
  let lastSid = props.sessionId;
958
+ let lastTick = 0;
792
959
  createEffect(() => {
793
960
  const sid = props.sessionId;
794
961
  const switched = sid !== lastSid;
795
962
  lastSid = sid;
963
+ const tick = clearTick();
964
+ const forceReload = tick !== lastTick && !switched;
965
+ lastTick = tick;
796
966
  const t2 = setTimeout(() => {
797
967
  untrack(() => {
798
968
  if (switched) {
799
- const saved = loadSessionData()[sid]?.scroll ?? 0;
969
+ const {
970
+ parentSid,
971
+ isChild
972
+ } = resolveParent(sid);
973
+ const data = loadSessionData();
974
+ const saved = isChild ? data[parentSid]?.children?.[sid]?.scroll ?? 0 : data[sid]?.scroll ?? 0;
800
975
  setScrollOffset(saved);
976
+ if (!isChild && data[sid]?.entries?.length) {
977
+ data[sid].ts = Date.now();
978
+ saveSessionData(data);
979
+ }
801
980
  }
802
981
  setEntryMapRaw((prev) => {
803
- const next = switched ? new Map(globalEntryCache.get(sid) ?? loadEntries(sid)) : new Map(prev);
982
+ const next = switched || forceReload ? new Map(globalEntryCache.get(sid) ?? loadEntries(sid)) : new Map(prev);
983
+ const {
984
+ parentSid: scanPSid,
985
+ isChild: scanChild
986
+ } = resolveParent(sid);
987
+ const scanRec = loadSessionData()[scanPSid];
988
+ const clearedIds = new Set(scanChild ? scanRec?.children?.[sid]?.clearedIds : scanRec?.clearedIds);
804
989
  try {
805
990
  const msgs = props.api.state.session.messages(sid);
806
991
  if (msgs && msgs.length) {
@@ -816,6 +1001,7 @@ function SubAgentPanel(props) {
816
1001
  const st = part.state;
817
1002
  const rawStatus = String(st?.status ?? "");
818
1003
  const exists = next.get(id);
1004
+ if (!exists && clearedIds.has(id)) continue;
819
1005
  if ((rawStatus === "pending" || rawStatus === "") && !exists) continue;
820
1006
  if (rawStatus === "error") {
821
1007
  if (exists && exists.status === "running") {
@@ -1017,7 +1203,7 @@ function SubAgentPanel(props) {
1017
1203
  };
1018
1204
  const sep = () => "\u2500".repeat(Math.max(1, panelWidth()));
1019
1205
  const expandedMaxLabelW = createMemo(() => {
1020
- 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")];
1206
+ 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")];
1021
1207
  return Math.max(...labels.map((l) => visualWidth(l + ": ")));
1022
1208
  });
1023
1209
  const expandedPad = (label) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "));
@@ -1293,23 +1479,23 @@ function SubAgentPanel(props) {
1293
1479
  _$insert(_el$25, (() => {
1294
1480
  var _c$2 = _$memo(() => !!timeText());
1295
1481
  return () => _c$2() ? [" ", (() => {
1296
- var _el$81 = _$createElement("span");
1297
- _$insert(_el$81, timeText);
1298
- _$effect((_$p) => _$setProp(_el$81, "style", {
1482
+ var _el$89 = _$createElement("span");
1483
+ _$insert(_el$89, timeText);
1484
+ _$effect((_$p) => _$setProp(_el$89, "style", {
1299
1485
  fg: timeColor()
1300
1486
  }, _$p));
1301
- return _el$81;
1487
+ return _el$89;
1302
1488
  })()] : null;
1303
1489
  })(), null);
1304
1490
  _$insert(_el$25, (() => {
1305
1491
  var _c$3 = _$memo(() => !!tokenText());
1306
1492
  return () => _c$3() ? (() => {
1307
- var _el$82 = _$createElement("span");
1308
- _$insert(_el$82, tokenText);
1309
- _$effect((_$p) => _$setProp(_el$82, "style", {
1493
+ var _el$90 = _$createElement("span");
1494
+ _$insert(_el$90, tokenText);
1495
+ _$effect((_$p) => _$setProp(_el$90, "style", {
1310
1496
  fg: pal().muted
1311
1497
  }, _$p));
1312
- return _el$82;
1498
+ return _el$90;
1313
1499
  })() : null;
1314
1500
  })(), null);
1315
1501
  _$effect((_p$) => {
@@ -1592,6 +1778,56 @@ function SubAgentPanel(props) {
1592
1778
  });
1593
1779
  return _el$74;
1594
1780
  }
1781
+ }), _$createComponent(Show, {
1782
+ get when() {
1783
+ return entry.sessionId;
1784
+ },
1785
+ get children() {
1786
+ var _el$81 = _$createElement("text"), _el$82 = _$createTextNode(` `), _el$83 = _$createElement("span"), _el$84 = _$createTextNode(`: `), _el$85 = _$createElement("span"), _el$86 = _$createElement("span"), _el$87 = _$createElement("span");
1787
+ _$insertNode(_el$81, _el$82);
1788
+ _$insertNode(_el$81, _el$83);
1789
+ _$insertNode(_el$81, _el$85);
1790
+ _$insertNode(_el$81, _el$86);
1791
+ _$insertNode(_el$81, _el$87);
1792
+ _$setProp(_el$81, "onMouseUp", () => {
1793
+ if (entry.sessionId) {
1794
+ props.api.ui.toast({
1795
+ title: entry.title || entry.agent,
1796
+ message: `${entry.sessionId}
1797
+
1798
+ ${t("session.toast.copy")}`,
1799
+ duration: 8e3
1800
+ });
1801
+ }
1802
+ });
1803
+ _$insertNode(_el$83, _el$84);
1804
+ _$insert(_el$83, () => t("session.label"), _el$84);
1805
+ _$insert(_el$85, () => " ".repeat(expandedPad(t("session.label"))));
1806
+ _$insert(_el$86, () => truncate(entry.sessionId, expandedValAvail() - visualWidth(" \u2398")));
1807
+ _$insertNode(_el$87, _$createTextNode(` \u2398`));
1808
+ _$effect((_p$) => {
1809
+ var _v$28 = {
1810
+ fg: pal().primary
1811
+ }, _v$29 = {
1812
+ fg: pal().muted
1813
+ }, _v$30 = {
1814
+ fg: pal().muted
1815
+ }, _v$31 = {
1816
+ fg: pal().warning
1817
+ };
1818
+ _v$28 !== _p$.e && (_p$.e = _$setProp(_el$83, "style", _v$28, _p$.e));
1819
+ _v$29 !== _p$.t && (_p$.t = _$setProp(_el$85, "style", _v$29, _p$.t));
1820
+ _v$30 !== _p$.a && (_p$.a = _$setProp(_el$86, "style", _v$30, _p$.a));
1821
+ _v$31 !== _p$.o && (_p$.o = _$setProp(_el$87, "style", _v$31, _p$.o));
1822
+ return _p$;
1823
+ }, {
1824
+ e: void 0,
1825
+ t: void 0,
1826
+ a: void 0,
1827
+ o: void 0
1828
+ });
1829
+ return _el$81;
1830
+ }
1595
1831
  }), _$createComponent(Show, {
1596
1832
  get when() {
1597
1833
  return entry.sessionId || isRunning;
@@ -1608,66 +1844,66 @@ function SubAgentPanel(props) {
1608
1844
  /* indent */
1609
1845
  );
1610
1846
  return (() => {
1611
- var _el$83 = _$createElement("box");
1612
- _$setProp(_el$83, "flexDirection", "row");
1613
- _$insert(_el$83, _$createComponent(Show, {
1847
+ var _el$91 = _$createElement("box");
1848
+ _$setProp(_el$91, "flexDirection", "row");
1849
+ _$insert(_el$91, _$createComponent(Show, {
1614
1850
  get when() {
1615
1851
  return entry.sessionId;
1616
1852
  },
1617
1853
  get fallback() {
1618
1854
  return (() => {
1619
- var _el$90 = _$createElement("text");
1620
- _$insertNode(_el$90, _$createTextNode(` `));
1621
- return _el$90;
1855
+ var _el$98 = _$createElement("text");
1856
+ _$insertNode(_el$98, _$createTextNode(` `));
1857
+ return _el$98;
1622
1858
  })();
1623
1859
  },
1624
1860
  get children() {
1625
- var _el$84 = _$createElement("text"), _el$85 = _$createElement("span"), _el$86 = _$createElement("span");
1626
- _$insertNode(_el$84, _el$85);
1627
- _$insertNode(_el$84, _el$86);
1628
- _$setProp(_el$84, "onMouseOver", () => setHoveredOpen(entry.id));
1629
- _$setProp(_el$84, "onMouseOut", () => setHoveredOpen(void 0));
1630
- _$setProp(_el$84, "onMouseUp", () => {
1861
+ var _el$92 = _$createElement("text"), _el$93 = _$createElement("span"), _el$94 = _$createElement("span");
1862
+ _$insertNode(_el$92, _el$93);
1863
+ _$insertNode(_el$92, _el$94);
1864
+ _$setProp(_el$92, "onMouseOver", () => setHoveredOpen(entry.id));
1865
+ _$setProp(_el$92, "onMouseOut", () => setHoveredOpen(void 0));
1866
+ _$setProp(_el$92, "onMouseUp", () => {
1631
1867
  if (entry.sessionId) {
1632
1868
  props.api.route.navigate("session", {
1633
1869
  sessionID: entry.sessionId
1634
1870
  });
1635
1871
  }
1636
1872
  });
1637
- _$insert(_el$85, openPrefix);
1638
- _$insert(_el$86, () => t("open.label"));
1873
+ _$insert(_el$93, openPrefix);
1874
+ _$insert(_el$94, () => t("open.label"));
1639
1875
  _$effect((_p$) => {
1640
- var _v$28 = {
1876
+ var _v$32 = {
1641
1877
  fg: hoveredOpen() === entry.id ? pal().warning : pal().primary
1642
- }, _v$29 = {
1878
+ }, _v$33 = {
1643
1879
  fg: hoveredOpen() === entry.id ? pal().warning : pal().primary
1644
1880
  };
1645
- _v$28 !== _p$.e && (_p$.e = _$setProp(_el$85, "style", _v$28, _p$.e));
1646
- _v$29 !== _p$.t && (_p$.t = _$setProp(_el$86, "style", _v$29, _p$.t));
1881
+ _v$32 !== _p$.e && (_p$.e = _$setProp(_el$93, "style", _v$32, _p$.e));
1882
+ _v$33 !== _p$.t && (_p$.t = _$setProp(_el$94, "style", _v$33, _p$.t));
1647
1883
  return _p$;
1648
1884
  }, {
1649
1885
  e: void 0,
1650
1886
  t: void 0
1651
1887
  });
1652
- return _el$84;
1888
+ return _el$92;
1653
1889
  }
1654
1890
  }), null);
1655
- _$insert(_el$83, _$createComponent(Show, {
1891
+ _$insert(_el$91, _$createComponent(Show, {
1656
1892
  when: isRunning,
1657
1893
  get children() {
1658
1894
  return [(() => {
1659
- var _el$87 = _$createElement("text");
1660
- _$insert(_el$87, () => " ".repeat(spacerW()));
1661
- _$effect((_$p) => _$setProp(_el$87, "style", {
1895
+ var _el$95 = _$createElement("text");
1896
+ _$insert(_el$95, () => " ".repeat(spacerW()));
1897
+ _$effect((_$p) => _$setProp(_el$95, "style", {
1662
1898
  fg: pal().muted
1663
1899
  }, _$p));
1664
- return _el$87;
1900
+ return _el$95;
1665
1901
  })(), (() => {
1666
- var _el$88 = _$createElement("text"), _el$89 = _$createElement("span");
1667
- _$insertNode(_el$88, _el$89);
1668
- _$setProp(_el$88, "onMouseOver", () => setHoveredDismiss(entry.id));
1669
- _$setProp(_el$88, "onMouseOut", () => setHoveredDismiss(void 0));
1670
- _$setProp(_el$88, "onMouseUp", () => {
1902
+ var _el$96 = _$createElement("text"), _el$97 = _$createElement("span");
1903
+ _$insertNode(_el$96, _el$97);
1904
+ _$setProp(_el$96, "onMouseOver", () => setHoveredDismiss(entry.id));
1905
+ _$setProp(_el$96, "onMouseOut", () => setHoveredDismiss(void 0));
1906
+ _$setProp(_el$96, "onMouseUp", () => {
1671
1907
  upsertEntry({
1672
1908
  id: entry.id,
1673
1909
  title: entry.title,
@@ -1676,15 +1912,15 @@ function SubAgentPanel(props) {
1676
1912
  status: "done"
1677
1913
  });
1678
1914
  });
1679
- _$insert(_el$89, dismissLabel);
1680
- _$effect((_$p) => _$setProp(_el$89, "style", {
1915
+ _$insert(_el$97, dismissLabel);
1916
+ _$effect((_$p) => _$setProp(_el$97, "style", {
1681
1917
  fg: hoveredDismiss() === entry.id ? pal().warning : pal().muted
1682
1918
  }, _$p));
1683
- return _el$88;
1919
+ return _el$96;
1684
1920
  })()];
1685
1921
  }
1686
1922
  }), null);
1687
- return _el$83;
1923
+ return _el$91;
1688
1924
  })();
1689
1925
  })();
1690
1926
  }
@@ -1705,13 +1941,13 @@ function SubAgentPanel(props) {
1705
1941
  const right = props.sortOrder() === "desc" ? `\u2191 ${t("scroll.top")}` : `\u2193 ${t("scroll.bottom")}`;
1706
1942
  const pad = showTop ? Math.max(1, panelWidth() - visualWidth(left) - visualWidth(right)) : 0;
1707
1943
  return (() => {
1708
- var _el$92 = _$createElement("box"), _el$93 = _$createElement("text"), _el$94 = _$createElement("span");
1709
- _$insertNode(_el$92, _el$93);
1710
- _$setProp(_el$92, "flexDirection", "row");
1711
- _$insertNode(_el$93, _el$94);
1712
- _$setProp(_el$93, "onMouseOver", () => showMore && setHoveredMoreBelow(true));
1713
- _$setProp(_el$93, "onMouseOut", () => setHoveredMoreBelow(false));
1714
- _$setProp(_el$93, "onMouseUp", () => {
1944
+ var _el$100 = _$createElement("box"), _el$101 = _$createElement("text"), _el$102 = _$createElement("span");
1945
+ _$insertNode(_el$100, _el$101);
1946
+ _$setProp(_el$100, "flexDirection", "row");
1947
+ _$insertNode(_el$101, _el$102);
1948
+ _$setProp(_el$101, "onMouseOver", () => showMore && setHoveredMoreBelow(true));
1949
+ _$setProp(_el$101, "onMouseOut", () => setHoveredMoreBelow(false));
1950
+ _$setProp(_el$101, "onMouseUp", () => {
1715
1951
  if (!showMore) return;
1716
1952
  const total = entryList().length;
1717
1953
  const m = max();
@@ -1723,20 +1959,20 @@ function SubAgentPanel(props) {
1723
1959
  }
1724
1960
  setHoveredMoreBelow(false);
1725
1961
  });
1726
- _$insert(_el$94, left);
1727
- _$insert(_el$92, showTop ? [(() => {
1728
- var _el$95 = _$createElement("text");
1729
- _$insert(_el$95, () => " ".repeat(pad));
1730
- _$effect((_$p) => _$setProp(_el$95, "style", {
1962
+ _$insert(_el$102, left);
1963
+ _$insert(_el$100, showTop ? [(() => {
1964
+ var _el$103 = _$createElement("text");
1965
+ _$insert(_el$103, () => " ".repeat(pad));
1966
+ _$effect((_$p) => _$setProp(_el$103, "style", {
1731
1967
  fg: pal().muted
1732
1968
  }, _$p));
1733
- return _el$95;
1969
+ return _el$103;
1734
1970
  })(), (() => {
1735
- var _el$96 = _$createElement("text"), _el$97 = _$createElement("span");
1736
- _$insertNode(_el$96, _el$97);
1737
- _$setProp(_el$96, "onMouseOver", () => setHoveredTop(true));
1738
- _$setProp(_el$96, "onMouseOut", () => setHoveredTop(false));
1739
- _$setProp(_el$96, "onMouseUp", () => {
1971
+ var _el$104 = _$createElement("text"), _el$105 = _$createElement("span");
1972
+ _$insertNode(_el$104, _el$105);
1973
+ _$setProp(_el$104, "onMouseOver", () => setHoveredTop(true));
1974
+ _$setProp(_el$104, "onMouseOut", () => setHoveredTop(false));
1975
+ _$setProp(_el$104, "onMouseUp", () => {
1740
1976
  const total = entryList().length;
1741
1977
  const m = max();
1742
1978
  if (props.sortOrder() === "desc") {
@@ -1746,16 +1982,16 @@ function SubAgentPanel(props) {
1746
1982
  }
1747
1983
  setHoveredTop(false);
1748
1984
  });
1749
- _$insert(_el$97, right);
1750
- _$effect((_$p) => _$setProp(_el$97, "style", {
1985
+ _$insert(_el$105, right);
1986
+ _$effect((_$p) => _$setProp(_el$105, "style", {
1751
1987
  fg: hoveredTop() ? pal().warning : pal().muted
1752
1988
  }, _$p));
1753
- return _el$96;
1989
+ return _el$104;
1754
1990
  })()] : null, null);
1755
- _$effect((_$p) => _$setProp(_el$94, "style", {
1991
+ _$effect((_$p) => _$setProp(_el$102, "style", {
1756
1992
  fg: showMore && hoveredMoreBelow() ? pal().warning : pal().muted
1757
1993
  }, _$p));
1758
- return _el$92;
1994
+ return _el$100;
1759
1995
  })();
1760
1996
  })();
1761
1997
  }
@@ -1933,9 +2169,9 @@ var tui = async (api) => {
1933
2169
  dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
1934
2170
  title: "Max Visible Entries",
1935
2171
  description: () => (() => {
1936
- var _el$98 = _$createElement("text");
1937
- _$insertNode(_el$98, _$createTextNode(`Number of entries to show in the sidebar (1\u201350)`));
1938
- return _el$98;
2172
+ var _el$106 = _$createElement("text");
2173
+ _$insertNode(_el$106, _$createTextNode(`Number of entries to show in the sidebar (1\u201350)`));
2174
+ return _el$106;
1939
2175
  })(),
1940
2176
  get value() {
1941
2177
  return String(maxEntries());
@@ -1985,7 +2221,8 @@ var tui = async (api) => {
1985
2221
  name: "subagent-clear-running"
1986
2222
  },
1987
2223
  onSelect: (dialog) => {
1988
- const entries = globalEntryCache.get(signals.sessionId);
2224
+ const sid = signals.sessionId;
2225
+ const entries = globalEntryCache.get(sid);
1989
2226
  if (!entries || entries.size === 0) {
1990
2227
  const msg = signals.lang() === "zh" ? "\u6682\u65E0\u5B50\u4EE3\u7406\u6761\u76EE" : "No sub-agent entries found";
1991
2228
  api.ui.toast({
@@ -2005,12 +2242,35 @@ var tui = async (api) => {
2005
2242
  if (count > 0) {
2006
2243
  try {
2007
2244
  const data = JSON.parse(String(api.kv.get(`${KV_PREFIX}.session_data`, "{}")));
2008
- data[signals.sessionId] = {
2009
- ts: Date.now(),
2010
- entries: [...entries.values()],
2011
- scroll: data[signals.sessionId]?.scroll ?? 0,
2012
- expanded: data[signals.sessionId]?.expanded ?? ""
2013
- };
2245
+ const sessionObj = api.state.session.get(sid);
2246
+ const parentID = sessionObj?.parentID;
2247
+ if (parentID) {
2248
+ if (!data[parentID]) data[parentID] = {
2249
+ ts: Date.now(),
2250
+ entries: [],
2251
+ scroll: 0,
2252
+ expanded: "",
2253
+ children: {}
2254
+ };
2255
+ if (!data[parentID].children) data[parentID].children = {};
2256
+ if (!data[parentID].children[sid]) data[parentID].children[sid] = {
2257
+ scroll: 0,
2258
+ expanded: "",
2259
+ entries: []
2260
+ };
2261
+ data[parentID].children[sid] = {
2262
+ ...data[parentID].children[sid],
2263
+ entries: [...entries.values()]
2264
+ };
2265
+ } else {
2266
+ data[sid] = {
2267
+ ts: Date.now(),
2268
+ entries: [...entries.values()],
2269
+ scroll: data[sid]?.scroll ?? 0,
2270
+ expanded: data[sid]?.expanded ?? "",
2271
+ children: data[sid]?.children ?? {}
2272
+ };
2273
+ }
2014
2274
  api.kv.set(`${KV_PREFIX}.session_data`, JSON.stringify(data));
2015
2275
  } catch {
2016
2276
  }
@@ -2026,6 +2286,113 @@ var tui = async (api) => {
2026
2286
  }
2027
2287
  dialog?.clear();
2028
2288
  }
2289
+ }, {
2290
+ title: "SubAgent Magazine: TTL",
2291
+ value: "subagent-ttl",
2292
+ description: "Set session data retention period (days before auto-cleanup)",
2293
+ slash: {
2294
+ name: "subagent-ttl"
2295
+ },
2296
+ onSelect: (dialog) => {
2297
+ const t = (k) => I18N[signals.lang()][k] ?? k;
2298
+ const curRaw = parseInt(String(api.kv.get(`${KV_PREFIX}.ttl_days`, "3")), 10);
2299
+ const curDays = Number.isNaN(curRaw) ? 3 : curRaw;
2300
+ const curLabel = curDays === 0 ? t("ttl.unlimited") : `${curDays}d`;
2301
+ dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2302
+ get title() {
2303
+ return `${t("ttl.label")} (${curLabel})`;
2304
+ },
2305
+ get options() {
2306
+ return [{
2307
+ title: t("ttl.3d"),
2308
+ value: "3"
2309
+ }, {
2310
+ title: t("ttl.7d"),
2311
+ value: "7"
2312
+ }, {
2313
+ title: t("ttl.14d"),
2314
+ value: "14"
2315
+ }, {
2316
+ title: t("ttl.30d"),
2317
+ value: "30"
2318
+ }, {
2319
+ title: t("ttl.unlimited"),
2320
+ value: "0"
2321
+ }];
2322
+ },
2323
+ onSelect: (opt) => {
2324
+ const days = parseInt(opt.value, 10);
2325
+ api.kv.set(`${KV_PREFIX}.ttl_days`, String(days));
2326
+ const msg = days === 0 ? t("ttl.toast_unlimited") : t("ttl.toast").replace("{n}", String(days));
2327
+ api.ui.toast({
2328
+ message: msg
2329
+ });
2330
+ dialog?.clear();
2331
+ }
2332
+ }));
2333
+ }
2334
+ }, {
2335
+ title: "SubAgent Magazine: Clear Entries",
2336
+ value: "subagent-clear-entries",
2337
+ description: "Delete all sub-agent records for the current session (cannot be undone)",
2338
+ slash: {
2339
+ name: "subagent-clear-entries"
2340
+ },
2341
+ onSelect: (dialog) => {
2342
+ const t = (k) => I18N[signals.lang()][k] ?? k;
2343
+ const sid = signals.sessionId;
2344
+ const sessionObj = api.state.session.get(sid);
2345
+ const parentID = sessionObj?.parentID;
2346
+ const cached = globalEntryCache.get(sid);
2347
+ let runningCount = 0;
2348
+ if (cached) {
2349
+ for (const [, e] of cached) {
2350
+ if (e.status === "running") runningCount++;
2351
+ }
2352
+ }
2353
+ const msg = runningCount > 0 ? t("clear.prompt_running").replace("{n}", String(runningCount)) : t("clear.prompt");
2354
+ dialog?.replace(() => _$createComponent(api.ui.DialogConfirm, {
2355
+ get title() {
2356
+ return t("clear.title");
2357
+ },
2358
+ message: msg,
2359
+ onConfirm: () => {
2360
+ try {
2361
+ const data = JSON.parse(String(api.kv.get(`${KV_PREFIX}.session_data`, "{}")));
2362
+ let count = 0;
2363
+ if (parentID) {
2364
+ if (data[parentID]?.children?.[sid]) {
2365
+ const child = data[parentID].children[sid];
2366
+ const ids = child.entries?.map((e) => e.id) ?? [];
2367
+ count = ids.length;
2368
+ child.entries = [];
2369
+ child.scroll = 0;
2370
+ child.expanded = "";
2371
+ child.clearedIds = [.../* @__PURE__ */ new Set([...child.clearedIds ?? [], ...ids])];
2372
+ }
2373
+ } else {
2374
+ count = data[sid]?.entries?.length ?? 0;
2375
+ if (data[sid]) {
2376
+ const ids = data[sid].entries?.map((e) => e.id) ?? [];
2377
+ data[sid].entries = [];
2378
+ data[sid].scroll = 0;
2379
+ data[sid].expanded = "";
2380
+ data[sid].clearedIds = [.../* @__PURE__ */ new Set([...data[sid].clearedIds ?? [], ...ids])];
2381
+ }
2382
+ }
2383
+ api.kv.set(`${KV_PREFIX}.session_data`, JSON.stringify(data));
2384
+ globalEntryCache.delete(sid);
2385
+ setClearTick((v) => v + 1);
2386
+ const msg2 = t("clear.done").replace("{n}", String(count));
2387
+ api.ui.toast({
2388
+ message: msg2
2389
+ });
2390
+ } catch {
2391
+ }
2392
+ dialog?.clear();
2393
+ }
2394
+ }));
2395
+ }
2029
2396
  }]);
2030
2397
  };
2031
2398
  var mod = {