opencode-subagent-magazine 1.5.2 → 1.6.0-beta.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.
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 +1232 -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 +383 -289
  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 +345 -0
  37. package/dist/v2.js +3003 -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 +1460 -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 +301 -0
  60. package/tui/index.js +11 -0
package/dist/tui.js CHANGED
@@ -1,113 +1,12 @@
1
1
  // src/index.tsx
2
- import { createTextNode as _$createTextNode } from "@opentui/solid";
3
- import { insertNode as _$insertNode } from "@opentui/solid";
4
- import { createComponent as _$createComponent } from "@opentui/solid";
5
- import { effect as _$effect } from "@opentui/solid";
6
- import { insert as _$insert } from "@opentui/solid";
7
- import { memo as _$memo } from "@opentui/solid";
8
- import { use as _$use } from "@opentui/solid";
9
- import { setProp as _$setProp } from "@opentui/solid";
10
- import { createElement as _$createElement } from "@opentui/solid";
11
- import { createMemo, createSignal, createEffect, onMount, onCleanup, untrack, Show, For } from "solid-js";
2
+ import { createTextNode as _$createTextNode2 } from "@opentui/solid";
3
+ import { insertNode as _$insertNode2 } from "@opentui/solid";
4
+ import { createElement as _$createElement2 } from "@opentui/solid";
5
+ import { createComponent as _$createComponent2 } from "@opentui/solid";
6
+ import { createSignal as createSignal3 } from "solid-js";
12
7
 
13
8
  // src/_version.ts
14
- var PLUGIN_VERSION = "1.5.2";
15
-
16
- // src/clipboard.ts
17
- import { spawn } from "node:child_process";
18
- import { platform, release } from "node:os";
19
- function runWithInput(command, args, input) {
20
- return new Promise((resolve, reject) => {
21
- const child = spawn(command, args, {
22
- stdio: ["pipe", "ignore", "ignore"],
23
- windowsHide: true
24
- });
25
- child.once("error", reject);
26
- child.once("close", (code) => {
27
- if (code === 0) resolve();
28
- else reject(new Error(`${command} exited with code ${code}`));
29
- });
30
- child.stdin?.end(input);
31
- });
32
- }
33
- function writeOsc52(text) {
34
- if (!process.stdout.isTTY) return false;
35
- const payload = Buffer.from(text, "utf8").toString("base64");
36
- const sequence = `\x1B]52;c;${payload}\x07`;
37
- const wrapped = process.env.TMUX || process.env.STY ? `\x1BPtmux;\x1B${sequence}\x1B\\` : sequence;
38
- process.stdout.write(wrapped);
39
- return true;
40
- }
41
- async function tryCommand(method, command, args, text) {
42
- try {
43
- await runWithInput(command, args, text);
44
- return { copied: true, method };
45
- } catch {
46
- return void 0;
47
- }
48
- }
49
- async function copyText(text) {
50
- if (!text) return { copied: false, method: "none", error: "empty_text" };
51
- const os = platform();
52
- const isWsl = release().toLowerCase().includes("microsoft");
53
- const attempts = [];
54
- if (os === "darwin") {
55
- attempts.push(() => tryCommand("pbcopy", "pbcopy", [], text));
56
- attempts.push(
57
- () => tryCommand(
58
- "osascript",
59
- "osascript",
60
- ["-e", 'set the clipboard to (read (POSIX file "/dev/stdin") as text)'],
61
- text
62
- )
63
- );
64
- }
65
- if (os === "linux" && isWsl) {
66
- attempts.push(
67
- () => tryCommand(
68
- "powershell",
69
- "powershell.exe",
70
- [
71
- "-NonInteractive",
72
- "-NoProfile",
73
- "-Command",
74
- "[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())"
75
- ],
76
- text
77
- )
78
- );
79
- } else if (os === "linux") {
80
- if (process.env.WAYLAND_DISPLAY) {
81
- attempts.push(() => tryCommand("wl-copy", "wl-copy", [], text));
82
- }
83
- attempts.push(() => tryCommand("xclip", "xclip", ["-selection", "clipboard"], text));
84
- attempts.push(() => tryCommand("xsel", "xsel", ["--clipboard", "--input"], text));
85
- }
86
- if (os === "win32") {
87
- attempts.push(
88
- () => tryCommand(
89
- "powershell",
90
- "powershell.exe",
91
- [
92
- "-NonInteractive",
93
- "-NoProfile",
94
- "-Command",
95
- "[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())"
96
- ],
97
- text
98
- )
99
- );
100
- }
101
- for (const attempt of attempts) {
102
- const result = await attempt();
103
- if (result) return result;
104
- }
105
- try {
106
- if (writeOsc52(text)) return { copied: true, method: "osc52" };
107
- } catch {
108
- }
109
- return { copied: false, method: "none", error: "clipboard_unavailable" };
110
- }
9
+ var PLUGIN_VERSION = "1.6.0-beta.0";
111
10
 
112
11
  // src/i18n.ts
113
12
  var ZH_T = {
@@ -343,14 +242,137 @@ function detectLang() {
343
242
  }
344
243
  }
345
244
 
346
- // src/index.tsx
245
+ // src/core/kv.ts
246
+ var KV_PREFIX = "subagent_magazine";
247
+ var SESSION_DATA_KEY = `${KV_PREFIX}.session_data`;
248
+ var SETTING_KEYS = {
249
+ lang: `${KV_PREFIX}.lang`,
250
+ maxEntries: `${KV_PREFIX}.max_entries`,
251
+ order: `${KV_PREFIX}.order`,
252
+ scrollMode: `${KV_PREFIX}.scroll_mode`,
253
+ open: `${KV_PREFIX}.open`,
254
+ ttlDays: `${KV_PREFIX}.ttl_days`
255
+ };
256
+
257
+ // src/panel/SubAgentPanel.tsx
258
+ import { createTextNode as _$createTextNode } from "@opentui/solid";
259
+ import { insertNode as _$insertNode } from "@opentui/solid";
260
+ import { createComponent as _$createComponent } from "@opentui/solid";
261
+ import { effect as _$effect } from "@opentui/solid";
262
+ import { insert as _$insert } from "@opentui/solid";
263
+ import { memo as _$memo } from "@opentui/solid";
264
+ import { use as _$use } from "@opentui/solid";
265
+ import { setProp as _$setProp } from "@opentui/solid";
266
+ import { createElement as _$createElement } from "@opentui/solid";
267
+ import { createMemo, createSignal as createSignal2, createEffect, onMount, onCleanup, untrack, Show, For } from "solid-js";
268
+
269
+ // src/clipboard.ts
270
+ import { spawn } from "node:child_process";
271
+ import { platform, release } from "node:os";
272
+ function runWithInput(command, args, input) {
273
+ return new Promise((resolve, reject) => {
274
+ const child = spawn(command, args, {
275
+ stdio: ["pipe", "ignore", "ignore"],
276
+ windowsHide: true
277
+ });
278
+ child.once("error", reject);
279
+ child.once("close", (code) => {
280
+ if (code === 0) resolve();
281
+ else reject(new Error(`${command} exited with code ${code}`));
282
+ });
283
+ child.stdin?.end(input);
284
+ });
285
+ }
286
+ function writeOsc52(text) {
287
+ if (!process.stdout.isTTY) return false;
288
+ const payload = Buffer.from(text, "utf8").toString("base64");
289
+ const sequence = `\x1B]52;c;${payload}\x07`;
290
+ const wrapped = process.env.TMUX || process.env.STY ? `\x1BPtmux;\x1B${sequence}\x1B\\` : sequence;
291
+ process.stdout.write(wrapped);
292
+ return true;
293
+ }
294
+ async function tryCommand(method, command, args, text) {
295
+ try {
296
+ await runWithInput(command, args, text);
297
+ return { copied: true, method };
298
+ } catch {
299
+ return void 0;
300
+ }
301
+ }
302
+ async function copyText(text) {
303
+ if (!text) return { copied: false, method: "none", error: "empty_text" };
304
+ const os = platform();
305
+ const isWsl = release().toLowerCase().includes("microsoft");
306
+ const attempts = [];
307
+ if (os === "darwin") {
308
+ attempts.push(() => tryCommand("pbcopy", "pbcopy", [], text));
309
+ attempts.push(
310
+ () => tryCommand(
311
+ "osascript",
312
+ "osascript",
313
+ ["-e", 'set the clipboard to (read (POSIX file "/dev/stdin") as text)'],
314
+ text
315
+ )
316
+ );
317
+ }
318
+ if (os === "linux" && isWsl) {
319
+ attempts.push(
320
+ () => tryCommand(
321
+ "powershell",
322
+ "powershell.exe",
323
+ [
324
+ "-NonInteractive",
325
+ "-NoProfile",
326
+ "-Command",
327
+ "[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())"
328
+ ],
329
+ text
330
+ )
331
+ );
332
+ } else if (os === "linux") {
333
+ if (process.env.WAYLAND_DISPLAY) {
334
+ attempts.push(() => tryCommand("wl-copy", "wl-copy", [], text));
335
+ }
336
+ attempts.push(() => tryCommand("xclip", "xclip", ["-selection", "clipboard"], text));
337
+ attempts.push(() => tryCommand("xsel", "xsel", ["--clipboard", "--input"], text));
338
+ }
339
+ if (os === "win32") {
340
+ attempts.push(
341
+ () => tryCommand(
342
+ "powershell",
343
+ "powershell.exe",
344
+ [
345
+ "-NonInteractive",
346
+ "-NoProfile",
347
+ "-Command",
348
+ "[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())"
349
+ ],
350
+ text
351
+ )
352
+ );
353
+ }
354
+ for (const attempt of attempts) {
355
+ const result = await attempt();
356
+ if (result) return result;
357
+ }
358
+ try {
359
+ if (writeOsc52(text)) return { copied: true, method: "osc52" };
360
+ } catch {
361
+ }
362
+ return { copied: false, method: "none", error: "clipboard_unavailable" };
363
+ }
364
+
365
+ // src/core/types.ts
347
366
  var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["task", "delegate", "call_omo_agent"]);
367
+
368
+ // src/core/format.ts
348
369
  function charColumns(c) {
349
370
  const code = c.codePointAt(0) ?? 0;
350
371
  if (code < 32) return 0;
351
372
  if (code < 127) return 1;
352
373
  if (code < 160) return 0;
353
- if (code >= 4352 && code <= 4447 || code >= 11904 && code <= 42191 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65040 && code <= 65135 || code >= 65281 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 127744 && code <= 128591 || code >= 131072 && code <= 262141) return 2;
374
+ 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)
375
+ return 2;
354
376
  return 1;
355
377
  }
356
378
  function visualWidth(s) {
@@ -383,6 +405,14 @@ function fmtTokens(n) {
383
405
  if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
384
406
  return `${(n / 1e6).toFixed(1)}M`;
385
407
  }
408
+ function safeErrorMsg(err) {
409
+ if (!err) return "";
410
+ if (typeof err === "string") return err;
411
+ if (typeof err === "object") return String(err.message || err.code || "");
412
+ return "";
413
+ }
414
+
415
+ // src/core/color.ts
386
416
  function rgb(raw) {
387
417
  if (typeof raw === "string" && raw.startsWith("#")) {
388
418
  const h = raw.slice(1);
@@ -396,11 +426,7 @@ function rgb(raw) {
396
426
  const o = raw;
397
427
  if (typeof o.r === "number" && typeof o.g === "number" && typeof o.b === "number") {
398
428
  const scale = o.r > 1 || o.g > 1 || o.b > 1 ? 1 : 255;
399
- return {
400
- r: Math.round(o.r * scale),
401
- g: Math.round(o.g * scale),
402
- b: Math.round(o.b * scale)
403
- };
429
+ return { r: Math.round(o.r * scale), g: Math.round(o.g * scale), b: Math.round(o.b * scale) };
404
430
  }
405
431
  }
406
432
  return null;
@@ -453,25 +479,24 @@ var FALLBACK = {
453
479
  border: "#6B6B63"
454
480
  };
455
481
  var MAX_SAT = 0.28;
456
- var LEFT_PAD = 4;
457
- var INDENT = 2;
458
- function safeErrorMsg(err) {
459
- if (!err) return "";
460
- if (typeof err === "string") return err;
461
- if (typeof err === "object") return String(err.message || err.code || "");
462
- return "";
463
- }
482
+
483
+ // src/panel/store.ts
484
+ import { createSignal } from "solid-js";
464
485
  var globalEntryCache = /* @__PURE__ */ new Map();
465
486
  var [clearTick, setClearTick] = createSignal(0);
487
+
488
+ // src/panel/SubAgentPanel.tsx
489
+ var LEFT_PAD = 4;
490
+ var INDENT = 2;
466
491
  function SubAgentPanel(props) {
467
492
  const t = createT(() => props.lang());
468
- const SESSION_DATA_KEY = `${KV_PREFIX}.session_data`;
493
+ const SESSION_DATA_KEY2 = `${KV_PREFIX}.session_data`;
469
494
  const ttlDaysRaw = parseInt(String(props.api.kv.get(`${KV_PREFIX}.ttl_days`, "3")), 10);
470
495
  const ttlDays = Number.isNaN(ttlDaysRaw) ? 3 : ttlDaysRaw;
471
496
  const TTL_MS = ttlDays * 24 * 60 * 60 * 1e3;
472
497
  const loadSessionData = () => {
473
498
  try {
474
- const raw = props.api.kv.get(SESSION_DATA_KEY, "{}");
499
+ const raw = props.api.kv.get(SESSION_DATA_KEY2, "{}");
475
500
  return JSON.parse(String(raw));
476
501
  } catch {
477
502
  return {};
@@ -479,13 +504,13 @@ function SubAgentPanel(props) {
479
504
  };
480
505
  const saveSessionData = (data) => {
481
506
  try {
482
- props.api.kv.set(SESSION_DATA_KEY, JSON.stringify(data));
507
+ props.api.kv.set(SESSION_DATA_KEY2, JSON.stringify(data));
483
508
  } catch {
484
509
  }
485
510
  };
486
511
  const resolveParent = (sid) => {
487
512
  try {
488
- const session = props.api.state.session.get(sid);
513
+ const session = props.api.session.get(sid);
489
514
  const parentID = session?.parentID;
490
515
  if (parentID) return {
491
516
  parentSid: parentID,
@@ -648,7 +673,7 @@ function SubAgentPanel(props) {
648
673
  }
649
674
  };
650
675
  cleanupOldSessions();
651
- const [entryMap, setEntryMapRaw] = createSignal(loadEntries(props.sessionId));
676
+ const [entryMap, setEntryMapRaw] = createSignal2(loadEntries(props.sessionId));
652
677
  const setEntryMap = (arg) => {
653
678
  setEntryMapRaw((prev) => {
654
679
  const next = typeof arg === "function" ? arg(prev) : arg;
@@ -704,15 +729,15 @@ function SubAgentPanel(props) {
704
729
  return next;
705
730
  });
706
731
  };
707
- const [panelWidth, setPanelWidth] = createSignal(28);
708
- const [open, setOpen] = createSignal((() => {
732
+ const [panelWidth, setPanelWidth] = createSignal2(28);
733
+ const [open, setOpen] = createSignal2((() => {
709
734
  try {
710
735
  return props.api.kv.get(`${KV_PREFIX}.open`, true);
711
736
  } catch {
712
737
  return true;
713
738
  }
714
739
  })());
715
- const [expanded, setExpanded] = createSignal((() => {
740
+ const [expanded, setExpanded] = createSignal2((() => {
716
741
  try {
717
742
  const {
718
743
  parentSid,
@@ -724,13 +749,13 @@ function SubAgentPanel(props) {
724
749
  }
725
750
  return void 0;
726
751
  })());
727
- const [hoveredOpen, setHoveredOpen] = createSignal(void 0);
728
- const [hoveredDismiss, setHoveredDismiss] = createSignal(void 0);
729
- const [hoveredCancel, setHoveredCancel] = createSignal(void 0);
730
- const [hoveredTop, setHoveredTop] = createSignal(false);
731
- const [hoveredMoreAbove, setHoveredMoreAbove] = createSignal(false);
732
- const [hoveredMoreBelow, setHoveredMoreBelow] = createSignal(false);
733
- const [scrollOffset, setScrollOffset] = createSignal((() => {
752
+ const [hoveredOpen, setHoveredOpen] = createSignal2(void 0);
753
+ const [hoveredDismiss, setHoveredDismiss] = createSignal2(void 0);
754
+ const [hoveredCancel, setHoveredCancel] = createSignal2(void 0);
755
+ const [hoveredTop, setHoveredTop] = createSignal2(false);
756
+ const [hoveredMoreAbove, setHoveredMoreAbove] = createSignal2(false);
757
+ const [hoveredMoreBelow, setHoveredMoreBelow] = createSignal2(false);
758
+ const [scrollOffset, setScrollOffset] = createSignal2((() => {
734
759
  try {
735
760
  const {
736
761
  parentSid,
@@ -742,77 +767,10 @@ function SubAgentPanel(props) {
742
767
  return 0;
743
768
  }
744
769
  })());
745
- const [now, setNow] = createSignal(Date.now());
746
- const [renderTick, setRenderTick] = createSignal(0);
770
+ const [now, setNow] = createSignal2(Date.now());
771
+ const [renderTick, setRenderTick] = createSignal2(0);
747
772
  let boxEl;
748
773
  let disposed = false;
749
- const readSessionTokens = (sid) => {
750
- if (!sid) return void 0;
751
- try {
752
- const msgs = props.api.state.session.messages(sid);
753
- if (msgs) {
754
- for (let i = msgs.length - 1; i >= 0; i--) {
755
- const m = msgs[i];
756
- if (m.role !== "assistant") continue;
757
- const t2 = m.tokens;
758
- if (!t2 || !(Number(t2.output) > 0)) continue;
759
- const ctx = (Number(t2.input) || 0) + (Number(t2.output) || 0) + (Number(t2.reasoning) || 0) + (Number(t2.cache?.read) || 0) + (Number(t2.cache?.write) || 0);
760
- if (ctx > 0) return ctx;
761
- }
762
- }
763
- return void 0;
764
- } catch {
765
- return void 0;
766
- }
767
- };
768
- const readSessionCost = (sid) => {
769
- if (!sid) return void 0;
770
- try {
771
- const session = props.api.state.session.get(sid);
772
- if (session?.cost != null && session.cost > 0) return session.cost;
773
- const msgs = props.api.state.session.messages(sid);
774
- if (!msgs) return void 0;
775
- let total = 0;
776
- for (const m of msgs) {
777
- if (m.role === "assistant" && typeof m.cost === "number") total += m.cost;
778
- }
779
- return total > 0 ? total : void 0;
780
- } catch {
781
- return void 0;
782
- }
783
- };
784
- const readSessionModel = (sid) => {
785
- if (!sid) return void 0;
786
- try {
787
- const msgs = props.api.state.session.messages(sid);
788
- if (msgs) {
789
- for (let i = msgs.length - 1; i >= 0; i--) {
790
- const m = msgs[i];
791
- if (m.role === "assistant" && m.modelID) return String(m.modelID);
792
- }
793
- }
794
- return void 0;
795
- } catch {
796
- return void 0;
797
- }
798
- };
799
- const readSessionTodo = (sid) => {
800
- if (!sid) return void 0;
801
- try {
802
- const todos = props.api.state.session.todo(sid);
803
- if (!todos || todos.length === 0) return void 0;
804
- let done = 0;
805
- for (const t2 of todos) {
806
- if (t2.status === "completed" || t2.status === "cancelled") done++;
807
- }
808
- return {
809
- total: todos.length,
810
- done
811
- };
812
- } catch {
813
- return void 0;
814
- }
815
- };
816
774
  const upsertEntry = (partial) => {
817
775
  setEntryMap((prev) => {
818
776
  const existing = prev.get(partial.id);
@@ -834,12 +792,12 @@ function SubAgentPanel(props) {
834
792
  const isDescendantOf = (childId, rootId) => {
835
793
  const visited = /* @__PURE__ */ new Set();
836
794
  try {
837
- let current = props.api.state.session.get(childId);
795
+ let current = props.api.session.get(childId);
838
796
  while (current?.parentID) {
839
797
  if (visited.has(current.id)) return false;
840
798
  visited.add(current.id);
841
799
  if (current.parentID === rootId) return true;
842
- current = props.api.state.session.get(current.parentID);
800
+ current = props.api.session.get(current.parentID);
843
801
  }
844
802
  } catch {
845
803
  }
@@ -852,40 +810,36 @@ function SubAgentPanel(props) {
852
810
  const cancelEntry = async (entry) => {
853
811
  const childId = entry.sessionId;
854
812
  if (!childId) {
855
- props.api.ui.toast({
856
- title: entry.title || entry.agent,
857
- message: t("cancel.label") + ": " + t("cancel.no_session")
813
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.no_session"), {
814
+ title: entry.title || entry.agent
858
815
  });
859
816
  return;
860
817
  }
861
818
  try {
862
- const child = props.api.state.session.get(childId);
819
+ const child = props.api.session.get(childId);
863
820
  if (!child?.parentID) {
864
- props.api.ui.toast({
865
- title: entry.title || entry.agent,
866
- message: t("cancel.label") + ": " + t("cancel.not_child")
821
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.not_child"), {
822
+ title: entry.title || entry.agent
867
823
  });
868
824
  return;
869
825
  }
870
826
  } catch {
871
- props.api.ui.toast({
872
- title: entry.title || entry.agent,
873
- message: t("cancel.label") + ": " + t("cancel.read_error")
827
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.read_error"), {
828
+ title: entry.title || entry.agent
874
829
  });
875
830
  return;
876
831
  }
877
832
  if (!isDescendantOf(childId, props.sessionId)) {
878
- props.api.ui.toast({
879
- title: entry.title || entry.agent,
880
- message: t("cancel.label") + ": " + t("cancel.outside_tree")
833
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.outside_tree"), {
834
+ title: entry.title || entry.agent
881
835
  });
882
836
  return;
883
837
  }
884
838
  try {
885
- const st = props.api.state.session.status(childId);
839
+ const st = props.api.session.status(childId);
886
840
  if (st?.type !== "busy") {
887
- const tokens = readSessionTokens(childId);
888
- const cost = readSessionCost(childId);
841
+ const tokens = props.api.usage.readSessionTokens(childId);
842
+ const cost = props.api.usage.readSessionCost(childId);
889
843
  upsertEntry({
890
844
  id: entry.id,
891
845
  title: entry.title,
@@ -899,9 +853,8 @@ function SubAgentPanel(props) {
899
853
  return;
900
854
  }
901
855
  } catch {
902
- props.api.ui.toast({
903
- title: entry.title || entry.agent,
904
- message: t("cancel.label") + ": " + t("cancel.status_error")
856
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.status_error"), {
857
+ title: entry.title || entry.agent
905
858
  });
906
859
  return;
907
860
  }
@@ -917,7 +870,7 @@ function SubAgentPanel(props) {
917
870
  cancelReason: "manual"
918
871
  });
919
872
  try {
920
- await props.api.client.session.abort({
873
+ await props.api.client.abort({
921
874
  sessionID: childId
922
875
  });
923
876
  upsertEntry({
@@ -929,9 +882,7 @@ function SubAgentPanel(props) {
929
882
  sessionId: entry.sessionId,
930
883
  abortAccepted: true
931
884
  });
932
- props.api.ui.toast({
933
- message: t("cancel.label") + ": " + t("cancel.sent")
934
- });
885
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.sent"));
935
886
  } catch (err) {
936
887
  upsertEntry({
937
888
  id: entry.id,
@@ -942,16 +893,13 @@ function SubAgentPanel(props) {
942
893
  sessionId: entry.sessionId,
943
894
  error: String(err)
944
895
  });
945
- props.api.ui.toast({
946
- title: entry.title || entry.agent,
947
- message: t("cancel.label") + ": " + t("cancel.failed")
896
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.failed"), {
897
+ title: entry.title || entry.agent
948
898
  });
949
899
  }
950
900
  };
951
901
  const handlePartUpdated = (event) => {
952
- const e = event;
953
- const props_ = e.properties;
954
- const part = props_?.part;
902
+ const part = event.payload?.part;
955
903
  if (!part) return;
956
904
  if (part.type === "subtask") {
957
905
  const agent = String(part.agent ?? "?");
@@ -1019,24 +967,23 @@ function SubAgentPanel(props) {
1019
967
  }
1020
968
  };
1021
969
  const handleSessionEnd = (event, status) => {
1022
- const e = event;
1023
- const props_ = e.properties;
970
+ const props_ = event.payload;
1024
971
  const sid = String(props_?.sessionID ?? "");
1025
972
  if (!sid) return;
1026
- const sessionTokens = readSessionTokens(sid);
1027
- const sessionCost = readSessionCost(sid);
1028
- const sessionModel = readSessionModel(sid);
1029
- const sessionTodo = readSessionTodo(sid);
973
+ const sessionTokens = props.api.usage.readSessionTokens(sid);
974
+ const sessionCost = props.api.usage.readSessionCost(sid);
975
+ const sessionModel = props.api.usage.readSessionModel(sid);
976
+ const sessionTodo = props.api.usage.readSessionTodo(sid);
1030
977
  let sessionAgent;
1031
978
  let errorMsg;
1032
979
  try {
1033
- const s = props.api.state.session.get(sid);
980
+ const s = props.api.session.get(sid);
1034
981
  sessionAgent = s?.agent;
1035
982
  if (status === "error") {
1036
983
  const evtErr = props_?.error;
1037
984
  errorMsg = safeErrorMsg(evtErr) || safeErrorMsg(props_?.message);
1038
985
  if (!errorMsg) {
1039
- const msgs = props.api.state.session.messages(sid);
986
+ const msgs = props.api.session.messages(sid);
1040
987
  if (msgs) {
1041
988
  for (let i = msgs.length - 1; i >= 0; i--) {
1042
989
  const m = msgs[i];
@@ -1176,7 +1123,7 @@ function SubAgentPanel(props) {
1176
1123
  return changed ? next : prev;
1177
1124
  });
1178
1125
  try {
1179
- const sessionObj = props.api.state.session.get(sid);
1126
+ const sessionObj = props.api.session.get(sid);
1180
1127
  const parentSid = sessionObj?.parentID;
1181
1128
  if (parentSid && parentSid !== props.sessionId) {
1182
1129
  const parentCache = globalEntryCache.get(parentSid);
@@ -1189,7 +1136,7 @@ function SubAgentPanel(props) {
1189
1136
  const data = loadSessionData();
1190
1137
  const rec = data[parentSid];
1191
1138
  if (rec?.entries) {
1192
- const fallbackMap = new Map(rec.entries.map((e2) => [e2.id, e2]));
1139
+ const fallbackMap = new Map(rec.entries.map((e) => [e.id, e]));
1193
1140
  found = tryMatchAndUpdate(fallbackMap, sid, status, nowTs);
1194
1141
  if (found) {
1195
1142
  data[parentSid] = {
@@ -1216,10 +1163,10 @@ function SubAgentPanel(props) {
1216
1163
  }
1217
1164
  setTimeout(() => {
1218
1165
  if (disposed) return;
1219
- const finalTokens = readSessionTokens(sid);
1220
- const finalCost = readSessionCost(sid);
1221
- const finalModel = readSessionModel(sid);
1222
- const finalTodo = readSessionTodo(sid);
1166
+ const finalTokens = props.api.usage.readSessionTokens(sid);
1167
+ const finalCost = props.api.usage.readSessionCost(sid);
1168
+ const finalModel = props.api.usage.readSessionModel(sid);
1169
+ const finalTodo = props.api.usage.readSessionTodo(sid);
1223
1170
  setEntryMap((prev) => {
1224
1171
  let changed = false;
1225
1172
  const next = new Map(prev);
@@ -1262,14 +1209,14 @@ function SubAgentPanel(props) {
1262
1209
  if (entry.status === "running" && entry.sessionId) {
1263
1210
  let isChild = false;
1264
1211
  try {
1265
- const s = props.api.state.session.get(entry.sessionId);
1212
+ const s = props.api.session.get(entry.sessionId);
1266
1213
  isChild = s?.parentID === props.sessionId;
1267
1214
  } catch {
1268
1215
  }
1269
1216
  if (!isChild) continue;
1270
- const total = readSessionTokens(entry.sessionId);
1271
- const todo = readSessionTodo(entry.sessionId);
1272
- const model = entry.model ?? readSessionModel(entry.sessionId);
1217
+ const total = props.api.usage.readSessionTokens(entry.sessionId);
1218
+ const todo = props.api.usage.readSessionTodo(entry.sessionId);
1219
+ const model = entry.model ?? props.api.usage.readSessionModel(entry.sessionId);
1273
1220
  const nextEntry = {
1274
1221
  ...entry
1275
1222
  };
@@ -1297,7 +1244,7 @@ function SubAgentPanel(props) {
1297
1244
  bump();
1298
1245
  }, 500);
1299
1246
  bump();
1300
- const unsubPart = props.api.event.on("message.part.updated", (e) => {
1247
+ const unsubPart = props.api.event.on("part.updated", (e) => {
1301
1248
  handlePartUpdated(e);
1302
1249
  bump();
1303
1250
  });
@@ -1353,10 +1300,10 @@ function SubAgentPanel(props) {
1353
1300
  const scanRec = loadSessionData()[scanPSid];
1354
1301
  const clearedIds = new Set(scanChild ? scanRec?.children?.[sid]?.clearedIds : scanRec?.clearedIds);
1355
1302
  try {
1356
- const msgs = props.api.state.session.messages(sid);
1303
+ const msgs = props.api.session.messages(sid);
1357
1304
  if (msgs && msgs.length) {
1358
1305
  for (const msg of msgs) {
1359
- const parts = props.api.state.part(msg.id) ?? [];
1306
+ const parts = props.api.session.part(msg.id) ?? [];
1360
1307
  for (const partRaw of parts) {
1361
1308
  const part = partRaw;
1362
1309
  if (part.type === "tool") {
@@ -1409,7 +1356,7 @@ function SubAgentPanel(props) {
1409
1356
  let tokens;
1410
1357
  const scanStMeta2 = st?.metadata;
1411
1358
  const scanSubSid = scanStMeta2?.session_id !== void 0 ? String(scanStMeta2.session_id) : scanStMeta2?.sessionId !== void 0 ? String(scanStMeta2.sessionId) : void 0;
1412
- if (scanSubSid) tokens = readSessionTokens(scanSubSid);
1359
+ if (scanSubSid) tokens = props.api.usage.readSessionTokens(scanSubSid);
1413
1360
  const ended = status === "done";
1414
1361
  next.set(id, {
1415
1362
  id,
@@ -1437,10 +1384,10 @@ function SubAgentPanel(props) {
1437
1384
  for (const [id, entry] of next) {
1438
1385
  if (entry.status !== "running" && entry.status !== "cancel_requested" || !entry.sessionId) continue;
1439
1386
  try {
1440
- const st = props.api.state.session.status(entry.sessionId);
1387
+ const st = props.api.session.status(entry.sessionId);
1441
1388
  if (!st || st.type !== "idle") continue;
1442
- const tokens = readSessionTokens(entry.sessionId);
1443
- const cost = readSessionCost(entry.sessionId);
1389
+ const tokens = props.api.usage.readSessionTokens(entry.sessionId);
1390
+ const cost = props.api.usage.readSessionCost(entry.sessionId);
1444
1391
  const finalStatus = entry.status === "cancel_requested" && entry.abortAccepted ? "cancelled" : "done";
1445
1392
  next.set(id, {
1446
1393
  ...entry,
@@ -2170,20 +2117,18 @@ function SubAgentPanel(props) {
2170
2117
  if (!sessionId) return;
2171
2118
  const result = await copyText(sessionId);
2172
2119
  if (result.copied) {
2173
- props.api.ui.toast({
2120
+ props.api.ui.toast(t("session.toast.copied"), {
2174
2121
  variant: "success",
2175
2122
  title: entry.title || entry.agent,
2176
- message: t("session.toast.copied"),
2177
2123
  duration: 2500
2178
2124
  });
2179
2125
  return;
2180
2126
  }
2181
- props.api.ui.toast({
2127
+ props.api.ui.toast(`${sessionId}
2128
+
2129
+ ${t("session.toast.copy_failed")}`, {
2182
2130
  variant: "warning",
2183
2131
  title: entry.title || entry.agent,
2184
- message: `${sessionId}
2185
-
2186
- ${t("session.toast.copy_failed")}`,
2187
2132
  duration: 8e3
2188
2133
  });
2189
2134
  });
@@ -2244,9 +2189,7 @@ ${t("session.toast.copy_failed")}`,
2244
2189
  _$setProp(_el$92, "onMouseOut", () => setHoveredOpen(void 0));
2245
2190
  _$setProp(_el$92, "onMouseUp", () => {
2246
2191
  if (entry.sessionId) {
2247
- props.api.route.navigate("session", {
2248
- sessionID: entry.sessionId
2249
- });
2192
+ props.api.route.navigateSession(entry.sessionId);
2250
2193
  }
2251
2194
  });
2252
2195
  _$insert(_el$93, openPrefix);
@@ -2408,17 +2351,19 @@ ${t("session.toast.copy_failed")}`,
2408
2351
  return _el$;
2409
2352
  })();
2410
2353
  }
2411
- function createSidebarSlot(api, sig) {
2354
+
2355
+ // src/index.tsx
2356
+ function createSidebarSlot(api, panelApi, sig) {
2412
2357
  return {
2413
2358
  order: 60,
2414
2359
  slots: {
2415
2360
  sidebar_content(ctx, input) {
2416
2361
  sig.sessionId = input.session_id;
2417
- return _$createComponent(SubAgentPanel, {
2362
+ return _$createComponent2(SubAgentPanel, {
2363
+ api: panelApi,
2418
2364
  get theme() {
2419
2365
  return ctx.theme.current;
2420
2366
  },
2421
- api,
2422
2367
  get lang() {
2423
2368
  return sig.lang;
2424
2369
  },
@@ -2439,14 +2384,13 @@ function createSidebarSlot(api, sig) {
2439
2384
  }
2440
2385
  };
2441
2386
  }
2442
- var KV_PREFIX = "subagent_magazine";
2443
2387
  var tui = async (api) => {
2444
2388
  const stored = String(api.kv.get(`${KV_PREFIX}.lang`, ""));
2445
2389
  const initialLang = LANG_META.some((m) => m.code === stored) ? stored : detectLang();
2446
- const [lang, setLang] = createSignal(initialLang);
2447
- const [maxEntries, setMaxEntries] = createSignal(parseInt(String(api.kv.get(`${KV_PREFIX}.max_entries`, "10")), 10) || 10);
2448
- const [sortOrder, setSortOrder] = createSignal(String(api.kv.get(`${KV_PREFIX}.order`, "desc")) === "asc" ? "asc" : "desc");
2449
- const [scrollMode, setScrollMode] = createSignal(String(api.kv.get(`${KV_PREFIX}.scroll_mode`, "wheel")) === "click" ? "click" : "wheel");
2390
+ const [lang, setLang] = createSignal3(initialLang);
2391
+ const [maxEntries, setMaxEntries] = createSignal3(parseInt(String(api.kv.get(`${KV_PREFIX}.max_entries`, "10")), 10) || 10);
2392
+ const [sortOrder, setSortOrder] = createSignal3(String(api.kv.get(`${KV_PREFIX}.order`, "desc")) === "asc" ? "asc" : "desc");
2393
+ const [scrollMode, setScrollMode] = createSignal3(String(api.kv.get(`${KV_PREFIX}.scroll_mode`, "wheel")) === "click" ? "click" : "wheel");
2450
2394
  const signals = {
2451
2395
  lang,
2452
2396
  setLang,
@@ -2458,7 +2402,157 @@ var tui = async (api) => {
2458
2402
  setScrollMode,
2459
2403
  sessionId: ""
2460
2404
  };
2461
- api.slots.register(createSidebarSlot(api, signals));
2405
+ const v1Api = {
2406
+ kv: api.kv,
2407
+ usage: {
2408
+ readSessionTokens: (sid) => {
2409
+ if (!sid) return void 0;
2410
+ try {
2411
+ const msgs = api.state.session.messages(sid);
2412
+ if (msgs) {
2413
+ for (let i = msgs.length - 1; i >= 0; i--) {
2414
+ const m = msgs[i];
2415
+ if (m.role !== "assistant") continue;
2416
+ const t = m.tokens;
2417
+ if (!t || !(Number(t.output) > 0)) continue;
2418
+ const ctx = (Number(t.input) || 0) + (Number(t.output) || 0) + (Number(t.reasoning) || 0) + (Number(t.cache?.read) || 0) + (Number(t.cache?.write) || 0);
2419
+ if (ctx > 0) return ctx;
2420
+ }
2421
+ }
2422
+ return void 0;
2423
+ } catch {
2424
+ return void 0;
2425
+ }
2426
+ },
2427
+ readSessionCost: (sid) => {
2428
+ if (!sid) return void 0;
2429
+ try {
2430
+ const session = api.state.session.get(sid);
2431
+ if (session?.cost != null && session.cost > 0) return session.cost;
2432
+ const msgs = api.state.session.messages(sid);
2433
+ if (!msgs) return void 0;
2434
+ let total = 0;
2435
+ for (const m of msgs) {
2436
+ if (m.role === "assistant" && typeof m.cost === "number") total += m.cost;
2437
+ }
2438
+ return total > 0 ? total : void 0;
2439
+ } catch {
2440
+ return void 0;
2441
+ }
2442
+ },
2443
+ readSessionModel: (sid) => {
2444
+ if (!sid) return void 0;
2445
+ try {
2446
+ const msgs = api.state.session.messages(sid);
2447
+ if (msgs) {
2448
+ for (let i = msgs.length - 1; i >= 0; i--) {
2449
+ const m = msgs[i];
2450
+ if (m.role === "assistant" && m.modelID) return String(m.modelID);
2451
+ }
2452
+ }
2453
+ return void 0;
2454
+ } catch {
2455
+ return void 0;
2456
+ }
2457
+ },
2458
+ readSessionTodo: (sid) => {
2459
+ if (!sid) return void 0;
2460
+ try {
2461
+ const todos = api.state.session.todo(sid);
2462
+ if (!todos || todos.length === 0) return void 0;
2463
+ let done = 0;
2464
+ for (const t of todos) {
2465
+ if (t.status === "completed" || t.status === "cancelled") done++;
2466
+ }
2467
+ return {
2468
+ total: todos.length,
2469
+ done
2470
+ };
2471
+ } catch {
2472
+ return void 0;
2473
+ }
2474
+ }
2475
+ },
2476
+ session: {
2477
+ get: (sid) => {
2478
+ try {
2479
+ return api.state.session.get(sid);
2480
+ } catch {
2481
+ return void 0;
2482
+ }
2483
+ },
2484
+ status: (sid) => {
2485
+ try {
2486
+ return api.state.session.status(sid);
2487
+ } catch {
2488
+ return void 0;
2489
+ }
2490
+ },
2491
+ messages: (sid) => {
2492
+ try {
2493
+ return api.state.session.messages(sid);
2494
+ } catch {
2495
+ return void 0;
2496
+ }
2497
+ },
2498
+ part: (messageID) => {
2499
+ try {
2500
+ return api.state.part(messageID);
2501
+ } catch {
2502
+ return void 0;
2503
+ }
2504
+ }
2505
+ },
2506
+ event: {
2507
+ on: (type, cb) => {
2508
+ switch (type) {
2509
+ case "part.updated":
2510
+ return api.event.on("message.part.updated", (e) => cb({
2511
+ type,
2512
+ payload: {
2513
+ part: e.properties?.part
2514
+ }
2515
+ }));
2516
+ case "message.updated":
2517
+ return api.event.on("message.updated", () => cb({
2518
+ type
2519
+ }));
2520
+ case "session.idle":
2521
+ return api.event.on("session.idle", (e) => cb({
2522
+ type,
2523
+ payload: e.properties
2524
+ }));
2525
+ case "session.error":
2526
+ return api.event.on("session.error", (e) => cb({
2527
+ type,
2528
+ payload: e.properties
2529
+ }));
2530
+ }
2531
+ }
2532
+ },
2533
+ client: {
2534
+ abort: (input) => api.client.session.abort(input).then(() => {
2535
+ })
2536
+ },
2537
+ route: {
2538
+ navigateSession: (sessionID) => api.route.navigate("session", {
2539
+ sessionID
2540
+ })
2541
+ },
2542
+ ui: {
2543
+ toast: (message, opts) => api.ui.toast({
2544
+ ...opts,
2545
+ message
2546
+ })
2547
+ },
2548
+ settings: {
2549
+ lang: () => lang(),
2550
+ maxEntries: () => maxEntries(),
2551
+ sortOrder: () => sortOrder(),
2552
+ scrollMode: () => scrollMode()
2553
+ }
2554
+ };
2555
+ api.slots.register(createSidebarSlot(api, v1Api, signals));
2462
2556
  api.command?.register(() => [{
2463
2557
  title: "SubAgent Magazine: Language",
2464
2558
  value: "subagent-lang",
@@ -2467,7 +2561,7 @@ var tui = async (api) => {
2467
2561
  name: "subagent-lang"
2468
2562
  },
2469
2563
  onSelect: (dialog) => {
2470
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2564
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2471
2565
  title: "Language / \u8BED\u8A00",
2472
2566
  get options() {
2473
2567
  return LANG_META.map((m) => ({
@@ -2495,7 +2589,7 @@ var tui = async (api) => {
2495
2589
  },
2496
2590
  onSelect: (dialog) => {
2497
2591
  const t = createT(() => lang());
2498
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2592
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2499
2593
  title: "Sort Order / \u6392\u5E8F\u65B9\u5F0F",
2500
2594
  get options() {
2501
2595
  return [{
@@ -2526,7 +2620,7 @@ var tui = async (api) => {
2526
2620
  },
2527
2621
  onSelect: (dialog) => {
2528
2622
  const t = createT(() => lang());
2529
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2623
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2530
2624
  title: "Scroll Mode / \u6EDA\u52A8\u6A21\u5F0F",
2531
2625
  get options() {
2532
2626
  return [{
@@ -2556,12 +2650,12 @@ var tui = async (api) => {
2556
2650
  name: "subagent-max"
2557
2651
  },
2558
2652
  onSelect: (dialog) => {
2559
- dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
2653
+ dialog?.replace(() => _$createComponent2(api.ui.DialogPrompt, {
2560
2654
  title: "Max Visible Entries",
2561
2655
  description: () => (() => {
2562
- var _el$106 = _$createElement("text");
2563
- _$insertNode(_el$106, _$createTextNode(`Number of entries to show in the sidebar (1\u201350)`));
2564
- return _el$106;
2656
+ var _el$ = _$createElement2("text");
2657
+ _$insertNode2(_el$, _$createTextNode2(`Number of entries to show in the sidebar (1\u201350)`));
2658
+ return _el$;
2565
2659
  })(),
2566
2660
  get value() {
2567
2661
  return String(maxEntries());
@@ -2688,7 +2782,7 @@ var tui = async (api) => {
2688
2782
  const curRaw = parseInt(String(api.kv.get(`${KV_PREFIX}.ttl_days`, "3")), 10);
2689
2783
  const curDays = Number.isNaN(curRaw) ? 3 : curRaw;
2690
2784
  const curLabel = curDays === 0 ? t("ttl.unlimited") : `${curDays}d`;
2691
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2785
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2692
2786
  get title() {
2693
2787
  return `${t("ttl.label")} (${curLabel})`;
2694
2788
  },
@@ -2745,7 +2839,7 @@ var tui = async (api) => {
2745
2839
  const msg = runningCount > 0 ? t("clear.prompt_running", {
2746
2840
  n: runningCount
2747
2841
  }) : t("clear.prompt");
2748
- dialog?.replace(() => _$createComponent(api.ui.DialogConfirm, {
2842
+ dialog?.replace(() => _$createComponent2(api.ui.DialogConfirm, {
2749
2843
  get title() {
2750
2844
  return t("clear.title");
2751
2845
  },