opencode-subagent-magazine 1.5.1 → 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 -1480
  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 -290
  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 -1745
  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.1";
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,78 +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) continue;
759
- const cache = t2.cache;
760
- const ctx = (Number(t2.input) || 0) + (cache?.read ?? 0);
761
- if (ctx > 0) return ctx;
762
- }
763
- }
764
- return void 0;
765
- } catch {
766
- return void 0;
767
- }
768
- };
769
- const readSessionCost = (sid) => {
770
- if (!sid) return void 0;
771
- try {
772
- const session = props.api.state.session.get(sid);
773
- if (session?.cost != null && session.cost > 0) return session.cost;
774
- const msgs = props.api.state.session.messages(sid);
775
- if (!msgs) return void 0;
776
- let total = 0;
777
- for (const m of msgs) {
778
- if (m.role === "assistant" && typeof m.cost === "number") total += m.cost;
779
- }
780
- return total > 0 ? total : void 0;
781
- } catch {
782
- return void 0;
783
- }
784
- };
785
- const readSessionModel = (sid) => {
786
- if (!sid) return void 0;
787
- try {
788
- const msgs = props.api.state.session.messages(sid);
789
- if (msgs) {
790
- for (let i = msgs.length - 1; i >= 0; i--) {
791
- const m = msgs[i];
792
- if (m.role === "assistant" && m.modelID) return String(m.modelID);
793
- }
794
- }
795
- return void 0;
796
- } catch {
797
- return void 0;
798
- }
799
- };
800
- const readSessionTodo = (sid) => {
801
- if (!sid) return void 0;
802
- try {
803
- const todos = props.api.state.session.todo(sid);
804
- if (!todos || todos.length === 0) return void 0;
805
- let done = 0;
806
- for (const t2 of todos) {
807
- if (t2.status === "completed" || t2.status === "cancelled") done++;
808
- }
809
- return {
810
- total: todos.length,
811
- done
812
- };
813
- } catch {
814
- return void 0;
815
- }
816
- };
817
774
  const upsertEntry = (partial) => {
818
775
  setEntryMap((prev) => {
819
776
  const existing = prev.get(partial.id);
@@ -835,12 +792,12 @@ function SubAgentPanel(props) {
835
792
  const isDescendantOf = (childId, rootId) => {
836
793
  const visited = /* @__PURE__ */ new Set();
837
794
  try {
838
- let current = props.api.state.session.get(childId);
795
+ let current = props.api.session.get(childId);
839
796
  while (current?.parentID) {
840
797
  if (visited.has(current.id)) return false;
841
798
  visited.add(current.id);
842
799
  if (current.parentID === rootId) return true;
843
- current = props.api.state.session.get(current.parentID);
800
+ current = props.api.session.get(current.parentID);
844
801
  }
845
802
  } catch {
846
803
  }
@@ -853,40 +810,36 @@ function SubAgentPanel(props) {
853
810
  const cancelEntry = async (entry) => {
854
811
  const childId = entry.sessionId;
855
812
  if (!childId) {
856
- props.api.ui.toast({
857
- title: entry.title || entry.agent,
858
- 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
859
815
  });
860
816
  return;
861
817
  }
862
818
  try {
863
- const child = props.api.state.session.get(childId);
819
+ const child = props.api.session.get(childId);
864
820
  if (!child?.parentID) {
865
- props.api.ui.toast({
866
- title: entry.title || entry.agent,
867
- 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
868
823
  });
869
824
  return;
870
825
  }
871
826
  } catch {
872
- props.api.ui.toast({
873
- title: entry.title || entry.agent,
874
- 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
875
829
  });
876
830
  return;
877
831
  }
878
832
  if (!isDescendantOf(childId, props.sessionId)) {
879
- props.api.ui.toast({
880
- title: entry.title || entry.agent,
881
- 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
882
835
  });
883
836
  return;
884
837
  }
885
838
  try {
886
- const st = props.api.state.session.status(childId);
839
+ const st = props.api.session.status(childId);
887
840
  if (st?.type !== "busy") {
888
- const tokens = readSessionTokens(childId);
889
- const cost = readSessionCost(childId);
841
+ const tokens = props.api.usage.readSessionTokens(childId);
842
+ const cost = props.api.usage.readSessionCost(childId);
890
843
  upsertEntry({
891
844
  id: entry.id,
892
845
  title: entry.title,
@@ -900,9 +853,8 @@ function SubAgentPanel(props) {
900
853
  return;
901
854
  }
902
855
  } catch {
903
- props.api.ui.toast({
904
- title: entry.title || entry.agent,
905
- 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
906
858
  });
907
859
  return;
908
860
  }
@@ -918,7 +870,7 @@ function SubAgentPanel(props) {
918
870
  cancelReason: "manual"
919
871
  });
920
872
  try {
921
- await props.api.client.session.abort({
873
+ await props.api.client.abort({
922
874
  sessionID: childId
923
875
  });
924
876
  upsertEntry({
@@ -930,9 +882,7 @@ function SubAgentPanel(props) {
930
882
  sessionId: entry.sessionId,
931
883
  abortAccepted: true
932
884
  });
933
- props.api.ui.toast({
934
- message: t("cancel.label") + ": " + t("cancel.sent")
935
- });
885
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.sent"));
936
886
  } catch (err) {
937
887
  upsertEntry({
938
888
  id: entry.id,
@@ -943,16 +893,13 @@ function SubAgentPanel(props) {
943
893
  sessionId: entry.sessionId,
944
894
  error: String(err)
945
895
  });
946
- props.api.ui.toast({
947
- title: entry.title || entry.agent,
948
- message: t("cancel.label") + ": " + t("cancel.failed")
896
+ props.api.ui.toast(t("cancel.label") + ": " + t("cancel.failed"), {
897
+ title: entry.title || entry.agent
949
898
  });
950
899
  }
951
900
  };
952
901
  const handlePartUpdated = (event) => {
953
- const e = event;
954
- const props_ = e.properties;
955
- const part = props_?.part;
902
+ const part = event.payload?.part;
956
903
  if (!part) return;
957
904
  if (part.type === "subtask") {
958
905
  const agent = String(part.agent ?? "?");
@@ -1020,24 +967,23 @@ function SubAgentPanel(props) {
1020
967
  }
1021
968
  };
1022
969
  const handleSessionEnd = (event, status) => {
1023
- const e = event;
1024
- const props_ = e.properties;
970
+ const props_ = event.payload;
1025
971
  const sid = String(props_?.sessionID ?? "");
1026
972
  if (!sid) return;
1027
- const sessionTokens = readSessionTokens(sid);
1028
- const sessionCost = readSessionCost(sid);
1029
- const sessionModel = readSessionModel(sid);
1030
- 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);
1031
977
  let sessionAgent;
1032
978
  let errorMsg;
1033
979
  try {
1034
- const s = props.api.state.session.get(sid);
980
+ const s = props.api.session.get(sid);
1035
981
  sessionAgent = s?.agent;
1036
982
  if (status === "error") {
1037
983
  const evtErr = props_?.error;
1038
984
  errorMsg = safeErrorMsg(evtErr) || safeErrorMsg(props_?.message);
1039
985
  if (!errorMsg) {
1040
- const msgs = props.api.state.session.messages(sid);
986
+ const msgs = props.api.session.messages(sid);
1041
987
  if (msgs) {
1042
988
  for (let i = msgs.length - 1; i >= 0; i--) {
1043
989
  const m = msgs[i];
@@ -1177,7 +1123,7 @@ function SubAgentPanel(props) {
1177
1123
  return changed ? next : prev;
1178
1124
  });
1179
1125
  try {
1180
- const sessionObj = props.api.state.session.get(sid);
1126
+ const sessionObj = props.api.session.get(sid);
1181
1127
  const parentSid = sessionObj?.parentID;
1182
1128
  if (parentSid && parentSid !== props.sessionId) {
1183
1129
  const parentCache = globalEntryCache.get(parentSid);
@@ -1190,7 +1136,7 @@ function SubAgentPanel(props) {
1190
1136
  const data = loadSessionData();
1191
1137
  const rec = data[parentSid];
1192
1138
  if (rec?.entries) {
1193
- const fallbackMap = new Map(rec.entries.map((e2) => [e2.id, e2]));
1139
+ const fallbackMap = new Map(rec.entries.map((e) => [e.id, e]));
1194
1140
  found = tryMatchAndUpdate(fallbackMap, sid, status, nowTs);
1195
1141
  if (found) {
1196
1142
  data[parentSid] = {
@@ -1217,10 +1163,10 @@ function SubAgentPanel(props) {
1217
1163
  }
1218
1164
  setTimeout(() => {
1219
1165
  if (disposed) return;
1220
- const finalTokens = readSessionTokens(sid);
1221
- const finalCost = readSessionCost(sid);
1222
- const finalModel = readSessionModel(sid);
1223
- 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);
1224
1170
  setEntryMap((prev) => {
1225
1171
  let changed = false;
1226
1172
  const next = new Map(prev);
@@ -1263,14 +1209,14 @@ function SubAgentPanel(props) {
1263
1209
  if (entry.status === "running" && entry.sessionId) {
1264
1210
  let isChild = false;
1265
1211
  try {
1266
- const s = props.api.state.session.get(entry.sessionId);
1212
+ const s = props.api.session.get(entry.sessionId);
1267
1213
  isChild = s?.parentID === props.sessionId;
1268
1214
  } catch {
1269
1215
  }
1270
1216
  if (!isChild) continue;
1271
- const total = readSessionTokens(entry.sessionId);
1272
- const todo = readSessionTodo(entry.sessionId);
1273
- 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);
1274
1220
  const nextEntry = {
1275
1221
  ...entry
1276
1222
  };
@@ -1298,7 +1244,7 @@ function SubAgentPanel(props) {
1298
1244
  bump();
1299
1245
  }, 500);
1300
1246
  bump();
1301
- const unsubPart = props.api.event.on("message.part.updated", (e) => {
1247
+ const unsubPart = props.api.event.on("part.updated", (e) => {
1302
1248
  handlePartUpdated(e);
1303
1249
  bump();
1304
1250
  });
@@ -1354,10 +1300,10 @@ function SubAgentPanel(props) {
1354
1300
  const scanRec = loadSessionData()[scanPSid];
1355
1301
  const clearedIds = new Set(scanChild ? scanRec?.children?.[sid]?.clearedIds : scanRec?.clearedIds);
1356
1302
  try {
1357
- const msgs = props.api.state.session.messages(sid);
1303
+ const msgs = props.api.session.messages(sid);
1358
1304
  if (msgs && msgs.length) {
1359
1305
  for (const msg of msgs) {
1360
- const parts = props.api.state.part(msg.id) ?? [];
1306
+ const parts = props.api.session.part(msg.id) ?? [];
1361
1307
  for (const partRaw of parts) {
1362
1308
  const part = partRaw;
1363
1309
  if (part.type === "tool") {
@@ -1410,7 +1356,7 @@ function SubAgentPanel(props) {
1410
1356
  let tokens;
1411
1357
  const scanStMeta2 = st?.metadata;
1412
1358
  const scanSubSid = scanStMeta2?.session_id !== void 0 ? String(scanStMeta2.session_id) : scanStMeta2?.sessionId !== void 0 ? String(scanStMeta2.sessionId) : void 0;
1413
- if (scanSubSid) tokens = readSessionTokens(scanSubSid);
1359
+ if (scanSubSid) tokens = props.api.usage.readSessionTokens(scanSubSid);
1414
1360
  const ended = status === "done";
1415
1361
  next.set(id, {
1416
1362
  id,
@@ -1438,10 +1384,10 @@ function SubAgentPanel(props) {
1438
1384
  for (const [id, entry] of next) {
1439
1385
  if (entry.status !== "running" && entry.status !== "cancel_requested" || !entry.sessionId) continue;
1440
1386
  try {
1441
- const st = props.api.state.session.status(entry.sessionId);
1387
+ const st = props.api.session.status(entry.sessionId);
1442
1388
  if (!st || st.type !== "idle") continue;
1443
- const tokens = readSessionTokens(entry.sessionId);
1444
- const cost = readSessionCost(entry.sessionId);
1389
+ const tokens = props.api.usage.readSessionTokens(entry.sessionId);
1390
+ const cost = props.api.usage.readSessionCost(entry.sessionId);
1445
1391
  const finalStatus = entry.status === "cancel_requested" && entry.abortAccepted ? "cancelled" : "done";
1446
1392
  next.set(id, {
1447
1393
  ...entry,
@@ -2171,20 +2117,18 @@ function SubAgentPanel(props) {
2171
2117
  if (!sessionId) return;
2172
2118
  const result = await copyText(sessionId);
2173
2119
  if (result.copied) {
2174
- props.api.ui.toast({
2120
+ props.api.ui.toast(t("session.toast.copied"), {
2175
2121
  variant: "success",
2176
2122
  title: entry.title || entry.agent,
2177
- message: t("session.toast.copied"),
2178
2123
  duration: 2500
2179
2124
  });
2180
2125
  return;
2181
2126
  }
2182
- props.api.ui.toast({
2127
+ props.api.ui.toast(`${sessionId}
2128
+
2129
+ ${t("session.toast.copy_failed")}`, {
2183
2130
  variant: "warning",
2184
2131
  title: entry.title || entry.agent,
2185
- message: `${sessionId}
2186
-
2187
- ${t("session.toast.copy_failed")}`,
2188
2132
  duration: 8e3
2189
2133
  });
2190
2134
  });
@@ -2245,9 +2189,7 @@ ${t("session.toast.copy_failed")}`,
2245
2189
  _$setProp(_el$92, "onMouseOut", () => setHoveredOpen(void 0));
2246
2190
  _$setProp(_el$92, "onMouseUp", () => {
2247
2191
  if (entry.sessionId) {
2248
- props.api.route.navigate("session", {
2249
- sessionID: entry.sessionId
2250
- });
2192
+ props.api.route.navigateSession(entry.sessionId);
2251
2193
  }
2252
2194
  });
2253
2195
  _$insert(_el$93, openPrefix);
@@ -2409,17 +2351,19 @@ ${t("session.toast.copy_failed")}`,
2409
2351
  return _el$;
2410
2352
  })();
2411
2353
  }
2412
- function createSidebarSlot(api, sig) {
2354
+
2355
+ // src/index.tsx
2356
+ function createSidebarSlot(api, panelApi, sig) {
2413
2357
  return {
2414
2358
  order: 60,
2415
2359
  slots: {
2416
2360
  sidebar_content(ctx, input) {
2417
2361
  sig.sessionId = input.session_id;
2418
- return _$createComponent(SubAgentPanel, {
2362
+ return _$createComponent2(SubAgentPanel, {
2363
+ api: panelApi,
2419
2364
  get theme() {
2420
2365
  return ctx.theme.current;
2421
2366
  },
2422
- api,
2423
2367
  get lang() {
2424
2368
  return sig.lang;
2425
2369
  },
@@ -2440,14 +2384,13 @@ function createSidebarSlot(api, sig) {
2440
2384
  }
2441
2385
  };
2442
2386
  }
2443
- var KV_PREFIX = "subagent_magazine";
2444
2387
  var tui = async (api) => {
2445
2388
  const stored = String(api.kv.get(`${KV_PREFIX}.lang`, ""));
2446
2389
  const initialLang = LANG_META.some((m) => m.code === stored) ? stored : detectLang();
2447
- const [lang, setLang] = createSignal(initialLang);
2448
- const [maxEntries, setMaxEntries] = createSignal(parseInt(String(api.kv.get(`${KV_PREFIX}.max_entries`, "10")), 10) || 10);
2449
- const [sortOrder, setSortOrder] = createSignal(String(api.kv.get(`${KV_PREFIX}.order`, "desc")) === "asc" ? "asc" : "desc");
2450
- 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");
2451
2394
  const signals = {
2452
2395
  lang,
2453
2396
  setLang,
@@ -2459,7 +2402,157 @@ var tui = async (api) => {
2459
2402
  setScrollMode,
2460
2403
  sessionId: ""
2461
2404
  };
2462
- 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));
2463
2556
  api.command?.register(() => [{
2464
2557
  title: "SubAgent Magazine: Language",
2465
2558
  value: "subagent-lang",
@@ -2468,7 +2561,7 @@ var tui = async (api) => {
2468
2561
  name: "subagent-lang"
2469
2562
  },
2470
2563
  onSelect: (dialog) => {
2471
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2564
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2472
2565
  title: "Language / \u8BED\u8A00",
2473
2566
  get options() {
2474
2567
  return LANG_META.map((m) => ({
@@ -2496,7 +2589,7 @@ var tui = async (api) => {
2496
2589
  },
2497
2590
  onSelect: (dialog) => {
2498
2591
  const t = createT(() => lang());
2499
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2592
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2500
2593
  title: "Sort Order / \u6392\u5E8F\u65B9\u5F0F",
2501
2594
  get options() {
2502
2595
  return [{
@@ -2527,7 +2620,7 @@ var tui = async (api) => {
2527
2620
  },
2528
2621
  onSelect: (dialog) => {
2529
2622
  const t = createT(() => lang());
2530
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2623
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2531
2624
  title: "Scroll Mode / \u6EDA\u52A8\u6A21\u5F0F",
2532
2625
  get options() {
2533
2626
  return [{
@@ -2557,12 +2650,12 @@ var tui = async (api) => {
2557
2650
  name: "subagent-max"
2558
2651
  },
2559
2652
  onSelect: (dialog) => {
2560
- dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
2653
+ dialog?.replace(() => _$createComponent2(api.ui.DialogPrompt, {
2561
2654
  title: "Max Visible Entries",
2562
2655
  description: () => (() => {
2563
- var _el$106 = _$createElement("text");
2564
- _$insertNode(_el$106, _$createTextNode(`Number of entries to show in the sidebar (1\u201350)`));
2565
- 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$;
2566
2659
  })(),
2567
2660
  get value() {
2568
2661
  return String(maxEntries());
@@ -2689,7 +2782,7 @@ var tui = async (api) => {
2689
2782
  const curRaw = parseInt(String(api.kv.get(`${KV_PREFIX}.ttl_days`, "3")), 10);
2690
2783
  const curDays = Number.isNaN(curRaw) ? 3 : curRaw;
2691
2784
  const curLabel = curDays === 0 ? t("ttl.unlimited") : `${curDays}d`;
2692
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2785
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2693
2786
  get title() {
2694
2787
  return `${t("ttl.label")} (${curLabel})`;
2695
2788
  },
@@ -2746,7 +2839,7 @@ var tui = async (api) => {
2746
2839
  const msg = runningCount > 0 ? t("clear.prompt_running", {
2747
2840
  n: runningCount
2748
2841
  }) : t("clear.prompt");
2749
- dialog?.replace(() => _$createComponent(api.ui.DialogConfirm, {
2842
+ dialog?.replace(() => _$createComponent2(api.ui.DialogConfirm, {
2750
2843
  get title() {
2751
2844
  return t("clear.title");
2752
2845
  },