opencode-subagent-magazine 1.4.2 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js CHANGED
@@ -11,95 +11,340 @@ 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.4.2";
14
+ var PLUGIN_VERSION = "1.5.1";
15
15
 
16
- // src/index.tsx
17
- var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["task", "delegate", "call_omo_agent"]);
18
- var I18N = {
19
- zh: {
20
- "panel.title": "\u5B50\u4EE3\u7406",
21
- "status.none": "\u6682\u65E0\u5B50\u4EE3\u7406",
22
- "agent.label": "\u4EE3\u7406",
23
- "status.label": "\u72B6\u6001",
24
- "time.label": "\u8017\u65F6",
25
- "tokens.label": "\u4E0A\u4E0B\u6587",
26
- "error.label": "\u9519\u8BEF",
27
- "model.label": "\u6A21\u578B",
28
- "todo.label": "\u8FDB\u5EA6",
29
- "session.label": "\u4F1A\u8BDD ID",
30
- "session.toast.copy": "\u53EF\u624B\u52A8\u590D\u5236\u4E0A\u65B9 ID",
31
- "open.label": "\u8FDB\u5165\u4F1A\u8BDD",
32
- "cost.label": "\u8D39\u7528",
33
- "scroll.more": "\u66F4\u591A",
34
- "scroll.top": "\u56DE\u9876",
35
- "scroll.bottom": "\u56DE\u5E95",
36
- "dismiss.label": "\u6807\u8BB0\u5B8C\u6210",
37
- "status.running": "\u8FD0\u884C\u4E2D",
38
- "status.done": "\u5DF2\u5B8C\u6210",
39
- "status.error": "\u9519\u8BEF",
40
- "order.desc": "\u964D\u5E8F\uFF08\u6700\u65B0\u5728\u524D\uFF09",
41
- "order.asc": "\u5347\u5E8F\uFF08\u6700\u65E9\u5728\u524D\uFF09",
42
- "scroll.wheel": "\u6EDA\u8F6E\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"
57
- },
58
- en: {
59
- "panel.title": "SubAgent",
60
- "status.none": "No sub-agents yet",
61
- "agent.label": "agent",
62
- "status.label": "status",
63
- "time.label": "time",
64
- "tokens.label": "tokens",
65
- "error.label": "error",
66
- "model.label": "model",
67
- "todo.label": "todo",
68
- "session.label": "session ID",
69
- "session.toast.copy": "Copy the ID above manually",
70
- "open.label": "Open session",
71
- "cost.label": "cost",
72
- "scroll.more": "more",
73
- "scroll.top": "Top",
74
- "scroll.bottom": "Bottom",
75
- "dismiss.label": "dismiss",
76
- "status.running": "running",
77
- "status.done": "done",
78
- "status.error": "error",
79
- "order.desc": "Desc (newest first)",
80
- "order.asc": "Asc (oldest first)",
81
- "scroll.wheel": "Wheel 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"
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
+ );
96
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
+ }
111
+
112
+ // src/i18n.ts
113
+ var ZH_T = {
114
+ "panel.title": "\u5B50\u4EE3\u7406",
115
+ "status.none": "\u6682\u65E0\u5B50\u4EE3\u7406",
116
+ "agent.label": "\u4EE3\u7406",
117
+ "status.label": "\u72B6\u6001",
118
+ "time.label": "\u8017\u65F6",
119
+ "tokens.label": "\u4E0A\u4E0B\u6587",
120
+ "error.label": "\u9519\u8BEF",
121
+ "model.label": "\u6A21\u578B",
122
+ "todo.label": "\u8FDB\u5EA6",
123
+ "session.label": "\u4F1A\u8BDD ID",
124
+ "session.toast.copy": "\u53EF\u624B\u52A8\u590D\u5236\u4E0A\u65B9 ID",
125
+ "session.toast.copied": "\u4F1A\u8BDD ID \u5DF2\u590D\u5236",
126
+ "session.toast.copy_failed": "\u65E0\u6CD5\u8BBF\u95EE\u7CFB\u7EDF\u526A\u8D34\u677F\uFF0C\u8BF7\u624B\u52A8\u590D\u5236\u4E0A\u65B9 ID",
127
+ "open.label": "\u8FDB\u5165\u4F1A\u8BDD",
128
+ "cost.label": "\u8D39\u7528",
129
+ "scroll.more": "\u66F4\u591A",
130
+ "scroll.top": "\u56DE\u9876",
131
+ "scroll.bottom": "\u56DE\u5E95",
132
+ "dismiss.label": "\u6807\u8BB0\u5B8C\u6210",
133
+ "cancel.label": "\u53D6\u6D88",
134
+ "status.running": "\u8FD0\u884C\u4E2D",
135
+ "status.done": "\u5DF2\u5B8C\u6210",
136
+ "status.cancelled": "\u5DF2\u53D6\u6D88",
137
+ "status.error": "\u9519\u8BEF",
138
+ "order.desc": "\u964D\u5E8F\uFF08\u6700\u65B0\u5728\u524D\uFF09",
139
+ "order.asc": "\u5347\u5E8F\uFF08\u6700\u65E9\u5728\u524D\uFF09",
140
+ "scroll.wheel": "\u6EDA\u8F6E\u7FFB\u9875",
141
+ "scroll.click": "\u70B9\u51FB\u7FFB\u9875",
142
+ "ttl.label": "\u6E05\u7406\u5468\u671F",
143
+ "ttl.3d": "3 \u5929",
144
+ "ttl.7d": "7 \u5929",
145
+ "ttl.14d": "14 \u5929",
146
+ "ttl.30d": "30 \u5929",
147
+ "ttl.unlimited": "\u65E0\u671F\u9650",
148
+ "ttl.toast": "\u6E05\u7406\u5468\u671F\u5DF2\u8BBE\u4E3A {n} \u5929",
149
+ "ttl.toast_unlimited": "\u6E05\u7406\u5468\u671F\u5DF2\u8BBE\u4E3A\u65E0\u671F\u9650",
150
+ "clear.title": "\u786E\u8BA4\u6E05\u9664",
151
+ "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",
152
+ "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",
153
+ "clear.done": "\u5DF2\u6E05\u9664 {n} \u6761\u5B50\u4EE3\u7406\u8BB0\u5F55",
154
+ "clear.empty": "\u5F53\u524D\u4F1A\u8BDD\u65E0\u5B50\u4EE3\u7406\u8BB0\u5F55",
155
+ "cancel.no_session": "\u5B50\u4F1A\u8BDD ID \u4E0D\u53EF\u7528",
156
+ "cancel.not_child": "\u76EE\u6807\u4E0D\u662F\u5B50\u4F1A\u8BDD",
157
+ "cancel.read_error": "\u65E0\u6CD5\u8BFB\u53D6\u4F1A\u8BDD\u4FE1\u606F",
158
+ "cancel.outside_tree": "\u76EE\u6807\u4E0D\u5728\u5F53\u524D\u76D1\u63A7\u4F1A\u8BDD\u6811\u4E2D",
159
+ "cancel.already_ended": "\u4F1A\u8BDD\u5DF2\u7ED3\u675F\uFF0C\u65E0\u9700\u53D6\u6D88",
160
+ "cancel.status_error": "\u65E0\u6CD5\u67E5\u8BE2\u4F1A\u8BDD\u72B6\u6001",
161
+ "cancel.sent": "\u5DF2\u53D1\u9001\u53D6\u6D88\u6307\u4EE4",
162
+ "cancel.failed": "\u53D6\u6D88\u5931\u8D25"
163
+ };
164
+ var EN_T = {
165
+ "panel.title": "SubAgent",
166
+ "status.none": "No sub-agents yet",
167
+ "agent.label": "agent",
168
+ "status.label": "status",
169
+ "time.label": "time",
170
+ "tokens.label": "tokens",
171
+ "error.label": "error",
172
+ "model.label": "model",
173
+ "todo.label": "todo",
174
+ "session.label": "session ID",
175
+ "session.toast.copy": "Copy the ID above manually",
176
+ "session.toast.copied": "Session ID copied",
177
+ "session.toast.copy_failed": "Cannot access the system clipboard; copy the ID above manually",
178
+ "open.label": "Open session",
179
+ "cost.label": "cost",
180
+ "scroll.more": "more",
181
+ "scroll.top": "Top",
182
+ "scroll.bottom": "Bottom",
183
+ "dismiss.label": "dismiss",
184
+ "cancel.label": "Cancel",
185
+ "status.running": "running",
186
+ "status.done": "done",
187
+ "status.cancelled": "cancelled",
188
+ "status.error": "error",
189
+ "order.desc": "Desc (newest first)",
190
+ "order.asc": "Asc (oldest first)",
191
+ "scroll.wheel": "Wheel Scroll",
192
+ "scroll.click": "Click Scroll",
193
+ "ttl.label": "TTL (Time to Live)",
194
+ "ttl.3d": "3 days",
195
+ "ttl.7d": "7 days",
196
+ "ttl.14d": "14 days",
197
+ "ttl.30d": "30 days",
198
+ "ttl.unlimited": "Never",
199
+ "ttl.toast": "TTL set to {n} days",
200
+ "ttl.toast_unlimited": "TTL set to Never",
201
+ "clear.title": "Confirm",
202
+ "clear.prompt": "Clear all sub-agent records for this session? This cannot be undone.",
203
+ "clear.prompt_running": "{n} sub-agent(s) are still running. Clearing will discard them permanently. Continue?",
204
+ "clear.done": "Cleared {n} sub-agent record(s)",
205
+ "clear.empty": "No sub-agent records in this session",
206
+ "cancel.no_session": "Child session ID is unavailable",
207
+ "cancel.not_child": "Target is not a child session",
208
+ "cancel.read_error": "Cannot read session info",
209
+ "cancel.outside_tree": "Target is outside the monitored session tree",
210
+ "cancel.already_ended": "Session already ended, no need to cancel",
211
+ "cancel.status_error": "Cannot query session status",
212
+ "cancel.sent": "Cancel instruction sent",
213
+ "cancel.failed": "Cancellation failed"
214
+ };
215
+ var JA_T = {
216
+ "panel.title": "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
217
+ "status.none": "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u306A\u3057",
218
+ "agent.label": "\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
219
+ "status.label": "\u72B6\u614B",
220
+ "time.label": "\u6642\u9593",
221
+ "tokens.label": "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8",
222
+ "error.label": "\u30A8\u30E9\u30FC",
223
+ "model.label": "\u30E2\u30C7\u30EB",
224
+ "todo.label": "\u9032\u6357",
225
+ "session.label": "\u30BB\u30C3\u30B7\u30E7\u30F3 ID",
226
+ "session.toast.copy": "\u4E0A\u306E ID \u3092\u624B\u52D5\u3067\u30B3\u30D4\u30FC\u3057\u3066\u304F\u3060\u3055\u3044",
227
+ "session.toast.copied": "\u30BB\u30C3\u30B7\u30E7\u30F3 ID \u3092\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F",
228
+ "session.toast.copy_failed": "\u30B7\u30B9\u30C6\u30E0\u306E\u30AF\u30EA\u30C3\u30D7\u30DC\u30FC\u30C9\u306B\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u306A\u3044\u305F\u3081\u3001\u4E0A\u306E ID \u3092\u624B\u52D5\u3067\u30B3\u30D4\u30FC\u3057\u3066\u304F\u3060\u3055\u3044",
229
+ "open.label": "\u30BB\u30C3\u30B7\u30E7\u30F3\u3092\u958B\u304F",
230
+ "cost.label": "\u8CBB\u7528",
231
+ "scroll.more": "\u3082\u3063\u3068",
232
+ "scroll.top": "\u5148\u982D\u3078",
233
+ "scroll.bottom": "\u672B\u5C3E\u3078",
234
+ "dismiss.label": "\u5B8C\u4E86\u306B\u3059\u308B",
235
+ "cancel.label": "\u30AD\u30E3\u30F3\u30BB\u30EB",
236
+ "status.running": "\u5B9F\u884C\u4E2D",
237
+ "status.done": "\u5B8C\u4E86",
238
+ "status.cancelled": "\u30AD\u30E3\u30F3\u30BB\u30EB\u6E08\u307F",
239
+ "status.error": "\u30A8\u30E9\u30FC",
240
+ "order.desc": "\u964D\u9806\uFF08\u65B0\u3057\u3044\u9806\uFF09",
241
+ "order.asc": "\u6607\u9806\uFF08\u53E4\u3044\u9806\uFF09",
242
+ "scroll.wheel": "\u30DB\u30A4\u30FC\u30EB\u30B9\u30AF\u30ED\u30FC\u30EB",
243
+ "scroll.click": "\u30AF\u30EA\u30C3\u30AF\u30B9\u30AF\u30ED\u30FC\u30EB",
244
+ "ttl.label": "\u4FDD\u6301\u671F\u9593",
245
+ "ttl.3d": "3 \u65E5",
246
+ "ttl.7d": "7 \u65E5",
247
+ "ttl.14d": "14 \u65E5",
248
+ "ttl.30d": "30 \u65E5",
249
+ "ttl.unlimited": "\u7121\u671F\u9650",
250
+ "ttl.toast": "\u4FDD\u6301\u671F\u9593\u3092 {n} \u65E5\u306B\u8A2D\u5B9A\u3057\u307E\u3057\u305F",
251
+ "ttl.toast_unlimited": "\u4FDD\u6301\u671F\u9593\u3092\u7121\u671F\u9650\u306B\u8A2D\u5B9A\u3057\u307E\u3057\u305F",
252
+ "clear.title": "\u524A\u9664\u306E\u78BA\u8A8D",
253
+ "clear.prompt": "\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u5168\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u8A18\u9332\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F\u3053\u306E\u64CD\u4F5C\u306F\u5143\u306B\u623B\u305B\u307E\u305B\u3093\u3002",
254
+ "clear.prompt_running": "\u5B9F\u884C\u4E2D\u306E\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u304C {n} \u500B\u3042\u308A\u307E\u3059\u3002\u524A\u9664\u3059\u308B\u3068\u5FA9\u5143\u3067\u304D\u307E\u305B\u3093\u3002\u7D9A\u884C\u3057\u307E\u3059\u304B\uFF1F",
255
+ "clear.done": "{n} \u4EF6\u306E\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u8A18\u9332\u3092\u524A\u9664\u3057\u307E\u3057\u305F",
256
+ "clear.empty": "\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306B\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u8A18\u9332\u306F\u3042\u308A\u307E\u305B\u3093",
257
+ "cancel.no_session": "\u5B50\u30BB\u30C3\u30B7\u30E7\u30F3 ID \u304C\u5229\u7528\u3067\u304D\u307E\u305B\u3093",
258
+ "cancel.not_child": "\u5BFE\u8C61\u306F\u5B50\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u306F\u3042\u308A\u307E\u305B\u3093",
259
+ "cancel.read_error": "\u30BB\u30C3\u30B7\u30E7\u30F3\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093",
260
+ "cancel.outside_tree": "\u5BFE\u8C61\u306F\u76E3\u8996\u5BFE\u8C61\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u30C4\u30EA\u30FC\u5916\u3067\u3059",
261
+ "cancel.already_ended": "\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u65E2\u306B\u7D42\u4E86\u3057\u3066\u3044\u307E\u3059",
262
+ "cancel.status_error": "\u30BB\u30C3\u30B7\u30E7\u30F3\u72B6\u614B\u3092\u7167\u4F1A\u3067\u304D\u307E\u305B\u3093",
263
+ "cancel.sent": "\u30AD\u30E3\u30F3\u30BB\u30EB\u6307\u793A\u3092\u9001\u4FE1\u3057\u307E\u3057\u305F",
264
+ "cancel.failed": "\u30AD\u30E3\u30F3\u30BB\u30EB\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
265
+ };
266
+ var KO_T = {
267
+ "panel.title": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8",
268
+ "status.none": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uC5C6\uC74C",
269
+ "agent.label": "\uC5D0\uC774\uC804\uD2B8",
270
+ "status.label": "\uC0C1\uD0DC",
271
+ "time.label": "\uC2DC\uAC04",
272
+ "tokens.label": "\uCEE8\uD14D\uC2A4\uD2B8",
273
+ "error.label": "\uC624\uB958",
274
+ "model.label": "\uBAA8\uB378",
275
+ "todo.label": "\uC9C4\uD589\uB3C4",
276
+ "session.label": "\uC138\uC158 ID",
277
+ "session.toast.copy": "\uC704 ID\uB97C \uC218\uB3D9\uC73C\uB85C \uBCF5\uC0AC\uD558\uC138\uC694",
278
+ "session.toast.copied": "\uC138\uC158 ID\uAC00 \uBCF5\uC0AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
279
+ "session.toast.copy_failed": "\uC2DC\uC2A4\uD15C \uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uC811\uADFC\uD560 \uC218 \uC5C6\uC5B4 \uC704 ID\uB97C \uC218\uB3D9\uC73C\uB85C \uBCF5\uC0AC\uD558\uC138\uC694",
280
+ "open.label": "\uC138\uC158 \uC5F4\uAE30",
281
+ "cost.label": "\uBE44\uC6A9",
282
+ "scroll.more": "\uB354 \uBCF4\uAE30",
283
+ "scroll.top": "\uB9E8 \uC704\uB85C",
284
+ "scroll.bottom": "\uB9E8 \uC544\uB798\uB85C",
285
+ "dismiss.label": "\uC644\uB8CC \uD45C\uC2DC",
286
+ "cancel.label": "\uCDE8\uC18C",
287
+ "status.running": "\uC2E4\uD589 \uC911",
288
+ "status.done": "\uC644\uB8CC",
289
+ "status.cancelled": "\uCDE8\uC18C\uB428",
290
+ "status.error": "\uC624\uB958",
291
+ "order.desc": "\uB0B4\uB9BC\uCC28\uC21C(\uCD5C\uC2E0\uC21C)",
292
+ "order.asc": "\uC624\uB984\uCC28\uC21C(\uC624\uB798\uB41C\uC21C)",
293
+ "scroll.wheel": "\uD720 \uC2A4\uD06C\uB864",
294
+ "scroll.click": "\uD074\uB9AD \uC2A4\uD06C\uB864",
295
+ "ttl.label": "\uBCF4\uC874 \uAE30\uAC04",
296
+ "ttl.3d": "3\uC77C",
297
+ "ttl.7d": "7\uC77C",
298
+ "ttl.14d": "14\uC77C",
299
+ "ttl.30d": "30\uC77C",
300
+ "ttl.unlimited": "\uBB34\uAE30\uD55C",
301
+ "ttl.toast": "\uBCF4\uC874 \uAE30\uAC04\uC744 {n}\uC77C\uB85C \uC124\uC815\uD588\uC2B5\uB2C8\uB2E4",
302
+ "ttl.toast_unlimited": "\uBCF4\uC874 \uAE30\uAC04\uC744 \uBB34\uAE30\uD55C\uC73C\uB85C \uC124\uC815\uD588\uC2B5\uB2C8\uB2E4",
303
+ "clear.title": "\uC0AD\uC81C \uD655\uC778",
304
+ "clear.prompt": "\uC774 \uC138\uC158\uC758 \uBAA8\uB4E0 \uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uAE30\uB85D\uC744 \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C? \uC774 \uC791\uC5C5\uC740 \uB418\uB3CC\uB9B4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
305
+ "clear.prompt_running": "\uC2E4\uD589 \uC911\uC778 \uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8\uAC00 {n}\uAC1C \uC788\uC2B5\uB2C8\uB2E4. \uC0AD\uC81C\uD558\uBA74 \uBCF5\uAD6C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uACC4\uC18D\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
306
+ "clear.done": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uAE30\uB85D {n}\uAC1C\uB97C \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4",
307
+ "clear.empty": "\uC774 \uC138\uC158\uC5D0 \uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4",
308
+ "cancel.no_session": "\uD558\uC704 \uC138\uC158 ID\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
309
+ "cancel.not_child": "\uB300\uC0C1\uC774 \uD558\uC704 \uC138\uC158\uC774 \uC544\uB2D9\uB2C8\uB2E4",
310
+ "cancel.read_error": "\uC138\uC158 \uC815\uBCF4\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
311
+ "cancel.outside_tree": "\uB300\uC0C1\uC774 \uBAA8\uB2C8\uD130\uB9C1 \uC138\uC158 \uD2B8\uB9AC \uBC16\uC5D0 \uC788\uC2B5\uB2C8\uB2E4",
312
+ "cancel.already_ended": "\uC138\uC158\uC774 \uC774\uBBF8 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
313
+ "cancel.status_error": "\uC138\uC158 \uC0C1\uD0DC\uB97C \uC870\uD68C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
314
+ "cancel.sent": "\uCDE8\uC18C \uC9C0\uC2DC\uB97C \uBCF4\uB0C8\uC2B5\uB2C8\uB2E4",
315
+ "cancel.failed": "\uCDE8\uC18C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4"
97
316
  };
317
+ var LANGS = { zh: ZH_T, en: EN_T, ja: JA_T, ko: KO_T };
318
+ var LANG_META = [
319
+ { code: "zh", label: "\u4E2D\u6587" },
320
+ { code: "en", label: "English" },
321
+ { code: "ja", label: "\u65E5\u672C\u8A9E" },
322
+ { code: "ko", label: "\uD55C\uAD6D\uC5B4" }
323
+ ];
324
+ function applyParams(tpl, params) {
325
+ if (!params) return tpl;
326
+ return tpl.replace(
327
+ /\{(\w+)\}/g,
328
+ (m, k) => k in params ? String(params[k]) : m
329
+ );
330
+ }
331
+ function createT(getCode) {
332
+ return (key, params) => applyParams(LANGS[getCode()][key] ?? key, params);
333
+ }
98
334
  function detectLang() {
99
- const env = process?.env?.OPENCODE_LANG ?? process?.env?.LANG ?? "";
100
- if (env.startsWith("zh")) return "zh";
101
- return "en";
335
+ try {
336
+ const loc = Intl.DateTimeFormat().resolvedOptions().locale.toLowerCase();
337
+ if (loc.startsWith("zh")) return "zh";
338
+ if (loc.startsWith("ja")) return "ja";
339
+ if (loc.startsWith("ko")) return "ko";
340
+ return "en";
341
+ } catch {
342
+ return "en";
343
+ }
102
344
  }
345
+
346
+ // src/index.tsx
347
+ var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["task", "delegate", "call_omo_agent"]);
103
348
  function charColumns(c) {
104
349
  const code = c.codePointAt(0) ?? 0;
105
350
  if (code < 32) return 0;
@@ -219,7 +464,7 @@ function safeErrorMsg(err) {
219
464
  var globalEntryCache = /* @__PURE__ */ new Map();
220
465
  var [clearTick, setClearTick] = createSignal(0);
221
466
  function SubAgentPanel(props) {
222
- const t = (key) => I18N[props.lang()][key] ?? key;
467
+ const t = createT(() => props.lang());
223
468
  const SESSION_DATA_KEY = `${KV_PREFIX}.session_data`;
224
469
  const ttlDaysRaw = parseInt(String(props.api.kv.get(`${KV_PREFIX}.ttl_days`, "3")), 10);
225
470
  const ttlDays = Number.isNaN(ttlDaysRaw) ? 3 : ttlDaysRaw;
@@ -410,7 +655,7 @@ function SubAgentPanel(props) {
410
655
  let needsImmediateFlush = false;
411
656
  for (const [id, entry] of next) {
412
657
  const prevEntry = prev.get(id);
413
- if (prevEntry?.status === "running" && (entry.status === "done" || entry.status === "error")) {
658
+ if (prevEntry?.status === "running" && (entry.status === "done" || entry.status === "error" || entry.status === "cancelled")) {
414
659
  needsImmediateFlush = true;
415
660
  break;
416
661
  }
@@ -481,6 +726,7 @@ function SubAgentPanel(props) {
481
726
  })());
482
727
  const [hoveredOpen, setHoveredOpen] = createSignal(void 0);
483
728
  const [hoveredDismiss, setHoveredDismiss] = createSignal(void 0);
729
+ const [hoveredCancel, setHoveredCancel] = createSignal(void 0);
484
730
  const [hoveredTop, setHoveredTop] = createSignal(false);
485
731
  const [hoveredMoreAbove, setHoveredMoreAbove] = createSignal(false);
486
732
  const [hoveredMoreBelow, setHoveredMoreBelow] = createSignal(false);
@@ -574,7 +820,7 @@ function SubAgentPanel(props) {
574
820
  const next = new Map(prev);
575
821
  const nowTs = Date.now();
576
822
  const e = partial.status;
577
- const ended = e === "done" || e === "error";
823
+ const ended = e === "done" || e === "error" || e === "cancelled";
578
824
  next.set(partial.id, {
579
825
  ...existing ?? {
580
826
  startedAt: nowTs
@@ -586,6 +832,123 @@ function SubAgentPanel(props) {
586
832
  return next;
587
833
  });
588
834
  };
835
+ const isDescendantOf = (childId, rootId) => {
836
+ const visited = /* @__PURE__ */ new Set();
837
+ try {
838
+ let current = props.api.state.session.get(childId);
839
+ while (current?.parentID) {
840
+ if (visited.has(current.id)) return false;
841
+ visited.add(current.id);
842
+ if (current.parentID === rootId) return true;
843
+ current = props.api.state.session.get(current.parentID);
844
+ }
845
+ } catch {
846
+ }
847
+ return false;
848
+ };
849
+ const settleOnIdle = (entry) => {
850
+ if (entry.status === "cancel_requested" && entry.abortAccepted) return "cancelled";
851
+ return "done";
852
+ };
853
+ const cancelEntry = async (entry) => {
854
+ const childId = entry.sessionId;
855
+ if (!childId) {
856
+ props.api.ui.toast({
857
+ title: entry.title || entry.agent,
858
+ message: t("cancel.label") + ": " + t("cancel.no_session")
859
+ });
860
+ return;
861
+ }
862
+ try {
863
+ const child = props.api.state.session.get(childId);
864
+ if (!child?.parentID) {
865
+ props.api.ui.toast({
866
+ title: entry.title || entry.agent,
867
+ message: t("cancel.label") + ": " + t("cancel.not_child")
868
+ });
869
+ return;
870
+ }
871
+ } catch {
872
+ props.api.ui.toast({
873
+ title: entry.title || entry.agent,
874
+ message: t("cancel.label") + ": " + t("cancel.read_error")
875
+ });
876
+ return;
877
+ }
878
+ 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")
882
+ });
883
+ return;
884
+ }
885
+ try {
886
+ const st = props.api.state.session.status(childId);
887
+ if (st?.type !== "busy") {
888
+ const tokens = readSessionTokens(childId);
889
+ const cost = readSessionCost(childId);
890
+ upsertEntry({
891
+ id: entry.id,
892
+ title: entry.title,
893
+ agent: entry.agent,
894
+ prompt: entry.prompt,
895
+ status: "done",
896
+ sessionId: entry.sessionId,
897
+ tokens,
898
+ cost
899
+ });
900
+ return;
901
+ }
902
+ } catch {
903
+ props.api.ui.toast({
904
+ title: entry.title || entry.agent,
905
+ message: t("cancel.label") + ": " + t("cancel.status_error")
906
+ });
907
+ return;
908
+ }
909
+ upsertEntry({
910
+ id: entry.id,
911
+ title: entry.title,
912
+ agent: entry.agent,
913
+ prompt: entry.prompt,
914
+ status: "cancel_requested",
915
+ sessionId: entry.sessionId,
916
+ cancelRequestedAt: Date.now(),
917
+ abortAccepted: false,
918
+ cancelReason: "manual"
919
+ });
920
+ try {
921
+ await props.api.client.session.abort({
922
+ sessionID: childId
923
+ });
924
+ upsertEntry({
925
+ id: entry.id,
926
+ title: entry.title,
927
+ agent: entry.agent,
928
+ prompt: entry.prompt,
929
+ status: "cancel_requested",
930
+ sessionId: entry.sessionId,
931
+ abortAccepted: true
932
+ });
933
+ props.api.ui.toast({
934
+ message: t("cancel.label") + ": " + t("cancel.sent")
935
+ });
936
+ } catch (err) {
937
+ upsertEntry({
938
+ id: entry.id,
939
+ title: entry.title,
940
+ agent: entry.agent,
941
+ prompt: entry.prompt,
942
+ status: "error",
943
+ sessionId: entry.sessionId,
944
+ error: String(err)
945
+ });
946
+ props.api.ui.toast({
947
+ title: entry.title || entry.agent,
948
+ message: t("cancel.label") + ": " + t("cancel.failed")
949
+ });
950
+ }
951
+ };
589
952
  const handlePartUpdated = (event) => {
590
953
  const e = event;
591
954
  const props_ = e.properties;
@@ -690,8 +1053,9 @@ function SubAgentPanel(props) {
690
1053
  }
691
1054
  const tryMatchAndUpdate = (entriesMap, targetSid, targetStatus, nowTs) => {
692
1055
  for (const [, entry] of entriesMap) {
693
- if (entry.sessionId === targetSid && entry.status === "running") {
694
- entry.status = targetStatus;
1056
+ if (entry.sessionId === targetSid && (entry.status === "running" || entry.status === "cancel_requested")) {
1057
+ const finalStatus = targetStatus === "error" ? "error" : settleOnIdle(entry);
1058
+ entry.status = finalStatus;
695
1059
  entry.endedAt = nowTs;
696
1060
  entry.tokens = entry.tokens ?? sessionTokens;
697
1061
  entry.cost = entry.cost ?? sessionCost;
@@ -707,7 +1071,7 @@ function SubAgentPanel(props) {
707
1071
  const saNorm = normalize(sessionAgent);
708
1072
  let best = null;
709
1073
  for (const [, entry] of entriesMap) {
710
- if (entry.status !== "running") continue;
1074
+ if (entry.status !== "running" && entry.status !== "cancel_requested") continue;
711
1075
  const eaNorm = normalize(entry.agent);
712
1076
  if (!eaNorm || !saNorm) continue;
713
1077
  if (!eaNorm.includes(saNorm) && !saNorm.includes(eaNorm)) continue;
@@ -719,7 +1083,7 @@ function SubAgentPanel(props) {
719
1083
  }
720
1084
  if (!best) {
721
1085
  for (const [, entry] of entriesMap) {
722
- if (entry.status !== "running") continue;
1086
+ if (entry.status !== "running" && entry.status !== "cancel_requested") continue;
723
1087
  if (entry.sessionId) continue;
724
1088
  const gap = nowTs - (entry.startedAt || 0);
725
1089
  if (!best || gap > best.gap) best = {
@@ -729,7 +1093,8 @@ function SubAgentPanel(props) {
729
1093
  }
730
1094
  }
731
1095
  if (best) {
732
- best.entry.status = targetStatus;
1096
+ const finalStatus = targetStatus === "error" ? "error" : settleOnIdle(best.entry);
1097
+ best.entry.status = finalStatus;
733
1098
  best.entry.endedAt = nowTs;
734
1099
  best.entry.tokens = best.entry.tokens ?? sessionTokens;
735
1100
  best.entry.cost = best.entry.cost ?? sessionCost;
@@ -748,13 +1113,14 @@ function SubAgentPanel(props) {
748
1113
  const next = new Map(prev);
749
1114
  for (const [id, entry] of next) {
750
1115
  if (entry.sessionId !== sid) continue;
751
- if (entry.status !== "running" && entry.status !== "done") continue;
1116
+ if (entry.status !== "running" && entry.status !== "done" && entry.status !== "cancel_requested") continue;
752
1117
  if (sid === props.sessionId) continue;
753
- const alreadySettled = entry.status !== "running";
1118
+ const alreadySettled = entry.status !== "running" && entry.status !== "cancel_requested";
1119
+ const finalStatus = status === "error" ? "error" : settleOnIdle(entry);
754
1120
  next.set(id, {
755
1121
  ...entry,
756
1122
  ...alreadySettled ? {} : {
757
- status,
1123
+ status: finalStatus,
758
1124
  endedAt: Date.now()
759
1125
  },
760
1126
  tokens: entry.tokens ?? sessionTokens,
@@ -772,7 +1138,7 @@ function SubAgentPanel(props) {
772
1138
  const saNorm = normalize(sessionAgent);
773
1139
  let best = null;
774
1140
  for (const [id, entry] of next) {
775
- if (entry.status !== "running") continue;
1141
+ if (entry.status !== "running" && entry.status !== "cancel_requested") continue;
776
1142
  const eaNorm = normalize(entry.agent);
777
1143
  if (!eaNorm || !saNorm) continue;
778
1144
  if (!eaNorm.includes(saNorm) && !saNorm.includes(eaNorm)) continue;
@@ -784,7 +1150,7 @@ function SubAgentPanel(props) {
784
1150
  }
785
1151
  if (!best) {
786
1152
  for (const [id, entry] of next) {
787
- if (entry.status !== "running") continue;
1153
+ if (entry.status !== "running" && entry.status !== "cancel_requested") continue;
788
1154
  if (entry.sessionId) continue;
789
1155
  const gap = nowTs - (entry.startedAt || 0);
790
1156
  if (!best || gap > best.gap) best = {
@@ -795,9 +1161,10 @@ function SubAgentPanel(props) {
795
1161
  }
796
1162
  if (best) {
797
1163
  const entry = next.get(best.id);
1164
+ const finalStatus = status === "error" ? "error" : settleOnIdle(entry);
798
1165
  next.set(best.id, {
799
1166
  ...entry,
800
- status,
1167
+ status: finalStatus,
801
1168
  endedAt: nowTs,
802
1169
  tokens: sessionTokens || entry.tokens,
803
1170
  cost: sessionCost || entry.cost,
@@ -1020,7 +1387,7 @@ function SubAgentPanel(props) {
1020
1387
  const scanHasChild = scanStMeta?.session_id !== void 0 || scanStMeta?.sessionId !== void 0;
1021
1388
  if (scanHasChild) status = "running";
1022
1389
  }
1023
- if (exists && exists.status !== "running") continue;
1390
+ if (exists && exists.status !== "running" && exists.status !== "cancel_requested") continue;
1024
1391
  if (exists && status === "running") {
1025
1392
  if (!rawStatus) {
1026
1393
  const msgTokens = msg?.tokens;
@@ -1069,15 +1436,16 @@ function SubAgentPanel(props) {
1069
1436
  let changed = false;
1070
1437
  const next = new Map(prev);
1071
1438
  for (const [id, entry] of next) {
1072
- if (entry.status !== "running" || !entry.sessionId) continue;
1439
+ if (entry.status !== "running" && entry.status !== "cancel_requested" || !entry.sessionId) continue;
1073
1440
  try {
1074
1441
  const st = props.api.state.session.status(entry.sessionId);
1075
1442
  if (!st || st.type !== "idle") continue;
1076
1443
  const tokens = readSessionTokens(entry.sessionId);
1077
1444
  const cost = readSessionCost(entry.sessionId);
1445
+ const finalStatus = entry.status === "cancel_requested" && entry.abortAccepted ? "cancelled" : "done";
1078
1446
  next.set(id, {
1079
1447
  ...entry,
1080
- status: "done",
1448
+ status: finalStatus,
1081
1449
  endedAt: Date.now(),
1082
1450
  tokens: tokens ?? entry.tokens,
1083
1451
  cost: cost ?? entry.cost
@@ -1173,8 +1541,8 @@ function SubAgentPanel(props) {
1173
1541
  elapsed: (e.endedAt ?? nowVal) - e.startedAt
1174
1542
  }));
1175
1543
  });
1176
- const doneCount = createMemo(() => entryList().filter((e) => e.status === "done").length);
1177
- const runningCount = createMemo(() => entryList().filter((e) => e.status === "running").length);
1544
+ const doneCount = createMemo(() => entryList().filter((e) => e.status === "done" || e.status === "cancelled").length);
1545
+ const runningCount = createMemo(() => entryList().filter((e) => e.status === "running" || e.status === "cancel_requested").length);
1178
1546
  const errCount = createMemo(() => entryList().filter((e) => e.status === "error").length);
1179
1547
  const anyEntry = () => entryList().length > 0;
1180
1548
  const totalTokens = createMemo(() => {
@@ -1433,11 +1801,15 @@ function SubAgentPanel(props) {
1433
1801
  children: (entry) => {
1434
1802
  const isExpanded = () => expanded() === entry.id;
1435
1803
  const isRunning = entry.status === "running";
1804
+ const isCancelRequested = entry.status === "cancel_requested";
1805
+ const isCancelled = entry.status === "cancelled";
1436
1806
  const isError = entry.status === "error";
1807
+ const isActiveRunning = isRunning || isCancelRequested;
1437
1808
  const elapsed = () => (entry.endedAt ?? now()) - entry.startedAt;
1438
1809
  const statusDot = () => "\u25CF";
1439
1810
  const statusColor = () => {
1440
- if (!isRunning) return isError ? pal().error : pal().success;
1811
+ if (isCancelled) return pal().muted;
1812
+ if (!isActiveRunning) return isError ? pal().error : pal().success;
1441
1813
  const t2 = (Math.sin(now() % 2e3 / 2e3 * Math.PI * 2 - Math.PI / 2) + 1) / 2;
1442
1814
  const a = rgb(pal().muted), b = rgb(pal().warning);
1443
1815
  if (!a || !b) return pal().warning;
@@ -1446,9 +1818,9 @@ function SubAgentPanel(props) {
1446
1818
  const bl = Math.round(a.b + (b.b - a.b) * t2);
1447
1819
  return "#" + [r, g, bl].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
1448
1820
  };
1449
- const timeColor = () => isRunning ? pal().warning : isError ? pal().error : pal().muted;
1821
+ const timeColor = () => isActiveRunning ? pal().warning : isError ? pal().error : pal().muted;
1450
1822
  const tokenText = () => !isExpanded() && entry.tokens !== void 0 && entry.tokens > 0 ? ` ${fmtTokens(entry.tokens)}` : "";
1451
- const timeText = () => !isExpanded() && (elapsed() >= 2e3 || entry.endedAt !== void 0) ? fmtDurationShort(elapsed(), isRunning) : "";
1823
+ const timeText = () => !isExpanded() && (elapsed() >= 2e3 || entry.endedAt !== void 0) ? fmtDurationShort(elapsed(), isActiveRunning) : "";
1452
1824
  const suffixW = () => {
1453
1825
  let w = 0;
1454
1826
  const t2 = timeText();
@@ -1558,14 +1930,14 @@ function SubAgentPanel(props) {
1558
1930
  _$insertNode(_el$39, _el$40);
1559
1931
  _$insert(_el$39, () => t("status.label"), _el$40);
1560
1932
  _$insert(_el$41, () => " ".repeat(expandedPad(t("status.label"))));
1561
- _$insert(_el$42, () => isRunning ? t("status.running") : isError ? t("status.error") : t("status.done"));
1933
+ _$insert(_el$42, () => isActiveRunning ? t("status.running") : isCancelled ? t("status.cancelled") : isError ? t("status.error") : t("status.done"));
1562
1934
  _$effect((_p$) => {
1563
1935
  var _v$9 = {
1564
1936
  fg: pal().primary
1565
1937
  }, _v$0 = {
1566
1938
  fg: pal().muted
1567
1939
  }, _v$1 = {
1568
- fg: isRunning ? pal().warning : isError ? pal().error : pal().success
1940
+ fg: isActiveRunning ? pal().warning : isCancelled ? pal().muted : isError ? pal().error : pal().success
1569
1941
  };
1570
1942
  _v$9 !== _p$.e && (_p$.e = _$setProp(_el$39, "style", _v$9, _p$.e));
1571
1943
  _v$0 !== _p$.t && (_p$.t = _$setProp(_el$41, "style", _v$0, _p$.t));
@@ -1590,7 +1962,7 @@ function SubAgentPanel(props) {
1590
1962
  _$insertNode(_el$45, _el$46);
1591
1963
  _$insert(_el$45, () => t("time.label"), _el$46);
1592
1964
  _$insert(_el$47, () => " ".repeat(expandedPad(t("time.label"))));
1593
- _$insert(_el$48, () => fmtDurationShort(elapsed(), isRunning));
1965
+ _$insert(_el$48, () => fmtDurationShort(elapsed(), isActiveRunning));
1594
1966
  _$effect((_p$) => {
1595
1967
  var _v$10 = {
1596
1968
  fg: pal().primary
@@ -1794,16 +2166,27 @@ function SubAgentPanel(props) {
1794
2166
  _$insertNode(_el$74, _el$78);
1795
2167
  _$insertNode(_el$74, _el$79);
1796
2168
  _$insertNode(_el$74, _el$80);
1797
- _$setProp(_el$74, "onMouseUp", () => {
1798
- if (entry.sessionId) {
2169
+ _$setProp(_el$74, "onMouseUp", async () => {
2170
+ const sessionId = entry.sessionId;
2171
+ if (!sessionId) return;
2172
+ const result = await copyText(sessionId);
2173
+ if (result.copied) {
1799
2174
  props.api.ui.toast({
2175
+ variant: "success",
1800
2176
  title: entry.title || entry.agent,
1801
- message: `${entry.sessionId}
1802
-
1803
- ${t("session.toast.copy")}`,
1804
- duration: 8e3
2177
+ message: t("session.toast.copied"),
2178
+ duration: 2500
1805
2179
  });
2180
+ return;
1806
2181
  }
2182
+ props.api.ui.toast({
2183
+ variant: "warning",
2184
+ title: entry.title || entry.agent,
2185
+ message: `${sessionId}
2186
+
2187
+ ${t("session.toast.copy_failed")}`,
2188
+ duration: 8e3
2189
+ });
1807
2190
  });
1808
2191
  _$insertNode(_el$76, _el$77);
1809
2192
  _$insert(_el$76, () => t("session.label"), _el$77);
@@ -1839,29 +2222,21 @@ ${t("session.toast.copy")}`,
1839
2222
  },
1840
2223
  get children() {
1841
2224
  return (() => {
1842
- const dismissLabel = () => `- ${t("dismiss.label")}`;
1843
2225
  const openPrefix = () => " \u2192 ";
1844
2226
  const openFull = () => entry.sessionId ? openPrefix() + t("open.label") : "";
1845
2227
  const openW = () => entry.sessionId ? visualWidth(openFull()) : 0;
1846
- const spacerW = () => Math.max(
1847
- 1,
1848
- panelWidth() - openW() - visualWidth(dismissLabel()) - 2
1849
- /* indent */
1850
- );
2228
+ const cancelLabel = () => ` ${t("cancel.label")}`;
2229
+ const dismissLabel = () => ` ${t("dismiss.label")}`;
2230
+ const rightW = (isRunning ? visualWidth(dismissLabel()) : 0) + (isRunning && entry.sessionId ? visualWidth(cancelLabel()) : 0);
2231
+ const spacerW = () => Math.max(1, panelWidth() - openW() - rightW - 2);
1851
2232
  return (() => {
1852
- var _el$91 = _$createElement("box");
2233
+ var _el$91 = _$createElement("box"), _el$95 = _$createElement("text");
2234
+ _$insertNode(_el$91, _el$95);
1853
2235
  _$setProp(_el$91, "flexDirection", "row");
1854
2236
  _$insert(_el$91, _$createComponent(Show, {
1855
2237
  get when() {
1856
2238
  return entry.sessionId;
1857
2239
  },
1858
- get fallback() {
1859
- return (() => {
1860
- var _el$98 = _$createElement("text");
1861
- _$insertNode(_el$98, _$createTextNode(` `));
1862
- return _el$98;
1863
- })();
1864
- },
1865
2240
  get children() {
1866
2241
  var _el$92 = _$createElement("text"), _el$93 = _$createElement("span"), _el$94 = _$createElement("span");
1867
2242
  _$insertNode(_el$92, _el$93);
@@ -1892,39 +2267,51 @@ ${t("session.toast.copy")}`,
1892
2267
  });
1893
2268
  return _el$92;
1894
2269
  }
2270
+ }), _el$95);
2271
+ _$insert(_el$95, () => " ".repeat(spacerW()));
2272
+ _$insert(_el$91, _$createComponent(Show, {
2273
+ get when() {
2274
+ return isRunning && entry.sessionId;
2275
+ },
2276
+ get children() {
2277
+ var _el$96 = _$createElement("text"), _el$97 = _$createElement("span");
2278
+ _$insertNode(_el$96, _el$97);
2279
+ _$setProp(_el$96, "onMouseOver", () => setHoveredCancel(entry.id));
2280
+ _$setProp(_el$96, "onMouseOut", () => setHoveredCancel(void 0));
2281
+ _$setProp(_el$96, "onMouseUp", () => cancelEntry(entry));
2282
+ _$insert(_el$97, cancelLabel);
2283
+ _$effect((_$p) => _$setProp(_el$97, "style", {
2284
+ fg: hoveredCancel() === entry.id ? pal().warning : pal().error
2285
+ }, _$p));
2286
+ return _el$96;
2287
+ }
1895
2288
  }), null);
1896
2289
  _$insert(_el$91, _$createComponent(Show, {
1897
2290
  when: isRunning,
1898
2291
  get children() {
1899
- return [(() => {
1900
- var _el$95 = _$createElement("text");
1901
- _$insert(_el$95, () => " ".repeat(spacerW()));
1902
- _$effect((_$p) => _$setProp(_el$95, "style", {
1903
- fg: pal().muted
1904
- }, _$p));
1905
- return _el$95;
1906
- })(), (() => {
1907
- var _el$96 = _$createElement("text"), _el$97 = _$createElement("span");
1908
- _$insertNode(_el$96, _el$97);
1909
- _$setProp(_el$96, "onMouseOver", () => setHoveredDismiss(entry.id));
1910
- _$setProp(_el$96, "onMouseOut", () => setHoveredDismiss(void 0));
1911
- _$setProp(_el$96, "onMouseUp", () => {
1912
- upsertEntry({
1913
- id: entry.id,
1914
- title: entry.title,
1915
- agent: entry.agent,
1916
- prompt: entry.prompt,
1917
- status: "done"
1918
- });
2292
+ var _el$98 = _$createElement("text"), _el$99 = _$createElement("span");
2293
+ _$insertNode(_el$98, _el$99);
2294
+ _$setProp(_el$98, "onMouseOver", () => setHoveredDismiss(entry.id));
2295
+ _$setProp(_el$98, "onMouseOut", () => setHoveredDismiss(void 0));
2296
+ _$setProp(_el$98, "onMouseUp", () => {
2297
+ upsertEntry({
2298
+ id: entry.id,
2299
+ title: entry.title,
2300
+ agent: entry.agent,
2301
+ prompt: entry.prompt,
2302
+ status: "done"
1919
2303
  });
1920
- _$insert(_el$97, dismissLabel);
1921
- _$effect((_$p) => _$setProp(_el$97, "style", {
1922
- fg: hoveredDismiss() === entry.id ? pal().warning : pal().muted
1923
- }, _$p));
1924
- return _el$96;
1925
- })()];
2304
+ });
2305
+ _$insert(_el$99, dismissLabel);
2306
+ _$effect((_$p) => _$setProp(_el$99, "style", {
2307
+ fg: hoveredDismiss() === entry.id ? pal().warning : pal().muted
2308
+ }, _$p));
2309
+ return _el$98;
1926
2310
  }
1927
2311
  }), null);
2312
+ _$effect((_$p) => _$setProp(_el$95, "style", {
2313
+ fg: pal().muted
2314
+ }, _$p));
1928
2315
  return _el$91;
1929
2316
  })();
1930
2317
  })();
@@ -2056,7 +2443,7 @@ function createSidebarSlot(api, sig) {
2056
2443
  var KV_PREFIX = "subagent_magazine";
2057
2444
  var tui = async (api) => {
2058
2445
  const stored = String(api.kv.get(`${KV_PREFIX}.lang`, ""));
2059
- const initialLang = stored === "zh" || stored === "en" ? stored : detectLang();
2446
+ const initialLang = LANG_META.some((m) => m.code === stored) ? stored : detectLang();
2060
2447
  const [lang, setLang] = createSignal(initialLang);
2061
2448
  const [maxEntries, setMaxEntries] = createSignal(parseInt(String(api.kv.get(`${KV_PREFIX}.max_entries`, "10")), 10) || 10);
2062
2449
  const [sortOrder, setSortOrder] = createSignal(String(api.kv.get(`${KV_PREFIX}.order`, "desc")) === "asc" ? "asc" : "desc");
@@ -2083,19 +2470,18 @@ var tui = async (api) => {
2083
2470
  onSelect: (dialog) => {
2084
2471
  dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2085
2472
  title: "Language / \u8BED\u8A00",
2086
- options: [{
2087
- title: "\u4E2D\u6587",
2088
- value: "zh"
2089
- }, {
2090
- title: "English",
2091
- value: "en"
2092
- }],
2473
+ get options() {
2474
+ return LANG_META.map((m) => ({
2475
+ title: m.label,
2476
+ value: m.code
2477
+ }));
2478
+ },
2093
2479
  onSelect: (opt) => {
2094
2480
  const l = opt.value;
2095
2481
  setLang(l);
2096
2482
  api.kv.set(`${KV_PREFIX}.lang`, l);
2097
2483
  api.ui.toast({
2098
- message: l === "zh" ? "\u8BED\u8A00: \u4E2D\u6587" : "Language: English"
2484
+ message: "Language: " + (LANG_META.find((m) => m.code === l)?.label ?? l)
2099
2485
  });
2100
2486
  dialog?.clear();
2101
2487
  }
@@ -2109,7 +2495,7 @@ var tui = async (api) => {
2109
2495
  name: "subagent-order"
2110
2496
  },
2111
2497
  onSelect: (dialog) => {
2112
- const t = (k) => I18N[lang()][k] ?? k;
2498
+ const t = createT(() => lang());
2113
2499
  dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2114
2500
  title: "Sort Order / \u6392\u5E8F\u65B9\u5F0F",
2115
2501
  get options() {
@@ -2140,7 +2526,7 @@ var tui = async (api) => {
2140
2526
  name: "subagent-scroll"
2141
2527
  },
2142
2528
  onSelect: (dialog) => {
2143
- const t = (k) => I18N[lang()][k] ?? k;
2529
+ const t = createT(() => lang());
2144
2530
  dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2145
2531
  title: "Scroll Mode / \u6EDA\u52A8\u6A21\u5F0F",
2146
2532
  get options() {
@@ -2238,7 +2624,7 @@ var tui = async (api) => {
2238
2624
  }
2239
2625
  let count = 0;
2240
2626
  for (const [, entry] of entries) {
2241
- if (entry.status === "running") {
2627
+ if (entry.status === "running" || entry.status === "cancel_requested") {
2242
2628
  entry.status = "done";
2243
2629
  entry.endedAt = Date.now();
2244
2630
  count++;
@@ -2299,7 +2685,7 @@ var tui = async (api) => {
2299
2685
  name: "subagent-ttl"
2300
2686
  },
2301
2687
  onSelect: (dialog) => {
2302
- const t = (k) => I18N[signals.lang()][k] ?? k;
2688
+ const t = createT(() => signals.lang());
2303
2689
  const curRaw = parseInt(String(api.kv.get(`${KV_PREFIX}.ttl_days`, "3")), 10);
2304
2690
  const curDays = Number.isNaN(curRaw) ? 3 : curRaw;
2305
2691
  const curLabel = curDays === 0 ? t("ttl.unlimited") : `${curDays}d`;
@@ -2328,7 +2714,9 @@ var tui = async (api) => {
2328
2714
  onSelect: (opt) => {
2329
2715
  const days = parseInt(opt.value, 10);
2330
2716
  api.kv.set(`${KV_PREFIX}.ttl_days`, String(days));
2331
- const msg = days === 0 ? t("ttl.toast_unlimited") : t("ttl.toast").replace("{n}", String(days));
2717
+ const msg = days === 0 ? t("ttl.toast_unlimited") : t("ttl.toast", {
2718
+ n: days
2719
+ });
2332
2720
  api.ui.toast({
2333
2721
  message: msg
2334
2722
  });
@@ -2344,7 +2732,7 @@ var tui = async (api) => {
2344
2732
  name: "subagent-clear-entries"
2345
2733
  },
2346
2734
  onSelect: (dialog) => {
2347
- const t = (k) => I18N[signals.lang()][k] ?? k;
2735
+ const t = createT(() => signals.lang());
2348
2736
  const sid = signals.sessionId;
2349
2737
  const sessionObj = api.state.session.get(sid);
2350
2738
  const parentID = sessionObj?.parentID;
@@ -2355,7 +2743,9 @@ var tui = async (api) => {
2355
2743
  if (e.status === "running") runningCount++;
2356
2744
  }
2357
2745
  }
2358
- const msg = runningCount > 0 ? t("clear.prompt_running").replace("{n}", String(runningCount)) : t("clear.prompt");
2746
+ const msg = runningCount > 0 ? t("clear.prompt_running", {
2747
+ n: runningCount
2748
+ }) : t("clear.prompt");
2359
2749
  dialog?.replace(() => _$createComponent(api.ui.DialogConfirm, {
2360
2750
  get title() {
2361
2751
  return t("clear.title");
@@ -2388,7 +2778,9 @@ var tui = async (api) => {
2388
2778
  api.kv.set(`${KV_PREFIX}.session_data`, JSON.stringify(data));
2389
2779
  globalEntryCache.delete(sid);
2390
2780
  setClearTick((v) => v + 1);
2391
- const msg2 = t("clear.done").replace("{n}", String(count));
2781
+ const msg2 = t("clear.done", {
2782
+ n: count
2783
+ });
2392
2784
  api.ui.toast({
2393
2785
  message: msg2
2394
2786
  });