opencode-subagent-magazine 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/_version.d.ts +1 -1
- package/dist/_version.js +1 -1
- package/dist/core/format.d.ts +7 -0
- package/dist/core/format.js +45 -0
- package/dist/core/kv.d.ts +21 -1
- package/dist/core/kv.js +33 -1
- package/dist/core/types.d.ts +12 -0
- package/dist/i18n.d.ts +19 -0
- package/dist/i18n.js +76 -0
- package/dist/index.js +73 -2
- package/dist/panel/SubAgentPanel.d.ts +5 -1
- package/dist/panel/SubAgentPanel.js +568 -261
- package/dist/panel/entry-map.d.ts +16 -0
- package/dist/panel/entry-map.js +74 -0
- package/dist/panel/panel-api.d.ts +8 -0
- package/dist/server.d.ts +3 -1
- package/dist/server.js +8 -0
- package/dist/tui.js +927 -431
- package/dist/v2/commands.js +188 -44
- package/dist/v2/db.d.ts +47 -0
- package/dist/v2/db.js +267 -0
- package/dist/v2/index.js +26 -6
- package/dist/v2/settings-menu.d.ts +9 -0
- package/dist/v2/settings-menu.js +225 -0
- package/dist/v2/v2-panel-api.js +304 -44
- package/dist/v2.js +1741 -560
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/core/format.ts +44 -0
- package/src/core/kv.ts +42 -2
- package/src/core/types.ts +12 -0
- package/src/i18n.ts +76 -0
- package/src/index.tsx +93 -2
- package/src/panel/SubAgentPanel.tsx +541 -233
- package/src/panel/entry-map.ts +77 -1
- package/src/panel/panel-api.ts +8 -0
- package/src/server.ts +10 -1
- package/src/v2/commands.ts +187 -43
- package/src/v2/db.ts +274 -0
- package/src/v2/index.tsx +49 -7
- package/src/v2/settings-menu.ts +241 -0
- package/src/v2/types.ts +3 -1
- package/src/v2/v2-panel-api.ts +241 -33
package/dist/tui.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createComponent as _$createComponent2 } from "@opentui/solid";
|
|
|
6
6
|
import { createSignal as createSignal3 } from "solid-js";
|
|
7
7
|
|
|
8
8
|
// src/_version.ts
|
|
9
|
-
var PLUGIN_VERSION = "1.
|
|
9
|
+
var PLUGIN_VERSION = "1.7.0";
|
|
10
10
|
|
|
11
11
|
// src/i18n.ts
|
|
12
12
|
var ZH_T = {
|
|
@@ -50,6 +50,7 @@ var ZH_T = {
|
|
|
50
50
|
"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",
|
|
51
51
|
"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",
|
|
52
52
|
"clear.done": "\u5DF2\u6E05\u9664 {n} \u6761\u5B50\u4EE3\u7406\u8BB0\u5F55",
|
|
53
|
+
"clear.failed": "\u6E05\u9664\u5931\u8D25",
|
|
53
54
|
"clear.empty": "\u5F53\u524D\u4F1A\u8BDD\u65E0\u5B50\u4EE3\u7406\u8BB0\u5F55",
|
|
54
55
|
"cancel.no_session": "\u5B50\u4F1A\u8BDD ID \u4E0D\u53EF\u7528",
|
|
55
56
|
"cancel.not_child": "\u76EE\u6807\u4E0D\u662F\u5B50\u4F1A\u8BDD",
|
|
@@ -60,7 +61,25 @@ var ZH_T = {
|
|
|
60
61
|
"cancel.sent": "\u5DF2\u53D1\u9001\u53D6\u6D88\u6307\u4EE4",
|
|
61
62
|
"cancel.failed": "\u53D6\u6D88\u5931\u8D25",
|
|
62
63
|
"borderShown": "\u9762\u677F\u8FB9\u6846 \u5DF2\u663E\u793A",
|
|
63
|
-
"borderHidden": "\u9762\u677F\u8FB9\u6846 \u5DF2\u9690\u85CF"
|
|
64
|
+
"borderHidden": "\u9762\u677F\u8FB9\u6846 \u5DF2\u9690\u85CF",
|
|
65
|
+
"settings.title": "SubAgent Magazine \u2014 \u8BBE\u7F6E",
|
|
66
|
+
"settings.section.general": "\u901A\u7528",
|
|
67
|
+
"settings.lang": "\u8BED\u8A00",
|
|
68
|
+
"settings.max": "\u6700\u5927\u6761\u76EE\u6570",
|
|
69
|
+
"settings.order": "\u6392\u5E8F\u65B9\u5F0F",
|
|
70
|
+
"settings.scroll": "\u6EDA\u52A8\u6A21\u5F0F",
|
|
71
|
+
"settings.ttl": "\u4FDD\u7559\u671F\u9650",
|
|
72
|
+
"settings.border": "\u9762\u677F\u8FB9\u6846",
|
|
73
|
+
"settings.showEntryCost": "\u6BCF\u6761\u5B50\u4EE3\u7406\u663E\u793A\u8D39\u7528",
|
|
74
|
+
"settings.showEntryTime": "\u5217\u8868\u4E2D\u663E\u793A\u8017\u65F6",
|
|
75
|
+
"settings.showEntryTokens": "\u5217\u8868\u4E2D\u663E\u793A Token \u6570",
|
|
76
|
+
"settings.timeFormat": "\u65F6\u95F4\u683C\u5F0F",
|
|
77
|
+
"settings.dbSync": "\u672C\u5730\u6570\u636E\u5E93\u8865\u5168",
|
|
78
|
+
"settings.on": "\u5F00",
|
|
79
|
+
"settings.off": "\u5173",
|
|
80
|
+
"settings.saved": "\u5DF2\u4FDD\u5B58 {item}\uFF1A{value}",
|
|
81
|
+
"settings.invalid": "\u65E0\u6548\u7684\u6570\u503C",
|
|
82
|
+
"settings.close": "\u5173\u95ED"
|
|
64
83
|
};
|
|
65
84
|
var EN_T = {
|
|
66
85
|
"panel.title": "SubAgent",
|
|
@@ -103,6 +122,7 @@ var EN_T = {
|
|
|
103
122
|
"clear.prompt": "Clear all sub-agent records for this session? This cannot be undone.",
|
|
104
123
|
"clear.prompt_running": "{n} sub-agent(s) are still running. Clearing will discard them permanently. Continue?",
|
|
105
124
|
"clear.done": "Cleared {n} sub-agent record(s)",
|
|
125
|
+
"clear.failed": "Clear failed",
|
|
106
126
|
"clear.empty": "No sub-agent records in this session",
|
|
107
127
|
"cancel.no_session": "Child session ID is unavailable",
|
|
108
128
|
"cancel.not_child": "Target is not a child session",
|
|
@@ -113,7 +133,25 @@ var EN_T = {
|
|
|
113
133
|
"cancel.sent": "Cancel instruction sent",
|
|
114
134
|
"cancel.failed": "Cancellation failed",
|
|
115
135
|
"borderShown": "Panel border shown",
|
|
116
|
-
"borderHidden": "Panel border hidden"
|
|
136
|
+
"borderHidden": "Panel border hidden",
|
|
137
|
+
"settings.title": "SubAgent Magazine \u2014 Settings",
|
|
138
|
+
"settings.section.general": "General",
|
|
139
|
+
"settings.lang": "Language",
|
|
140
|
+
"settings.max": "Max entries",
|
|
141
|
+
"settings.order": "Sort order",
|
|
142
|
+
"settings.scroll": "Scroll mode",
|
|
143
|
+
"settings.ttl": "Retention",
|
|
144
|
+
"settings.border": "Panel border",
|
|
145
|
+
"settings.showEntryCost": "Cost per sub-agent",
|
|
146
|
+
"settings.showEntryTime": "Elapsed time in list",
|
|
147
|
+
"settings.showEntryTokens": "Token count in list",
|
|
148
|
+
"settings.timeFormat": "Time format",
|
|
149
|
+
"settings.dbSync": "Local database enrichment",
|
|
150
|
+
"settings.on": "on",
|
|
151
|
+
"settings.off": "off",
|
|
152
|
+
"settings.saved": "Saved {item}: {value}",
|
|
153
|
+
"settings.invalid": "Invalid value",
|
|
154
|
+
"settings.close": "Close"
|
|
117
155
|
};
|
|
118
156
|
var JA_T = {
|
|
119
157
|
"panel.title": "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
|
|
@@ -156,6 +194,7 @@ var JA_T = {
|
|
|
156
194
|
"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",
|
|
157
195
|
"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",
|
|
158
196
|
"clear.done": "{n} \u4EF6\u306E\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u8A18\u9332\u3092\u524A\u9664\u3057\u307E\u3057\u305F",
|
|
197
|
+
"clear.failed": "\u30AF\u30EA\u30A2\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
159
198
|
"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",
|
|
160
199
|
"cancel.no_session": "\u5B50\u30BB\u30C3\u30B7\u30E7\u30F3 ID \u304C\u5229\u7528\u3067\u304D\u307E\u305B\u3093",
|
|
161
200
|
"cancel.not_child": "\u5BFE\u8C61\u306F\u5B50\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u306F\u3042\u308A\u307E\u305B\u3093",
|
|
@@ -166,7 +205,25 @@ var JA_T = {
|
|
|
166
205
|
"cancel.sent": "\u30AD\u30E3\u30F3\u30BB\u30EB\u6307\u793A\u3092\u9001\u4FE1\u3057\u307E\u3057\u305F",
|
|
167
206
|
"cancel.failed": "\u30AD\u30E3\u30F3\u30BB\u30EB\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
168
207
|
"borderShown": "\u30D1\u30CD\u30EB\u67A0\u7DDA \u8868\u793A",
|
|
169
|
-
"borderHidden": "\u30D1\u30CD\u30EB\u67A0\u7DDA \u975E\u8868\u793A"
|
|
208
|
+
"borderHidden": "\u30D1\u30CD\u30EB\u67A0\u7DDA \u975E\u8868\u793A",
|
|
209
|
+
"settings.title": "SubAgent Magazine \u2014 \u8A2D\u5B9A",
|
|
210
|
+
"settings.section.general": "\u4E00\u822C",
|
|
211
|
+
"settings.lang": "\u8A00\u8A9E",
|
|
212
|
+
"settings.max": "\u6700\u5927\u8868\u793A\u6570",
|
|
213
|
+
"settings.order": "\u4E26\u3073\u9806",
|
|
214
|
+
"settings.scroll": "\u30B9\u30AF\u30ED\u30FC\u30EB",
|
|
215
|
+
"settings.ttl": "\u4FDD\u6301\u671F\u9593",
|
|
216
|
+
"settings.border": "\u30D1\u30CD\u30EB\u67A0",
|
|
217
|
+
"settings.showEntryCost": "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u6BCE\u306E\u8CBB\u7528",
|
|
218
|
+
"settings.showEntryTime": "\u4E00\u89A7\u306B\u6240\u8981\u6642\u9593\u3092\u8868\u793A",
|
|
219
|
+
"settings.showEntryTokens": "\u4E00\u89A7\u306B\u30C8\u30FC\u30AF\u30F3\u6570\u3092\u8868\u793A",
|
|
220
|
+
"settings.timeFormat": "\u6642\u9593\u5F62\u5F0F",
|
|
221
|
+
"settings.dbSync": "\u30ED\u30FC\u30AB\u30EBDB\u88DC\u5B8C",
|
|
222
|
+
"settings.on": "\u30AA\u30F3",
|
|
223
|
+
"settings.off": "\u30AA\u30D5",
|
|
224
|
+
"settings.saved": "\u4FDD\u5B58\u3057\u307E\u3057\u305F {item}\uFF1A{value}",
|
|
225
|
+
"settings.invalid": "\u7121\u52B9\u306A\u5024\u3067\u3059",
|
|
226
|
+
"settings.close": "\u9589\u3058\u308B"
|
|
170
227
|
};
|
|
171
228
|
var KO_T = {
|
|
172
229
|
"panel.title": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8",
|
|
@@ -209,6 +266,7 @@ var KO_T = {
|
|
|
209
266
|
"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.",
|
|
210
267
|
"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?",
|
|
211
268
|
"clear.done": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uAE30\uB85D {n}\uAC1C\uB97C \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4",
|
|
269
|
+
"clear.failed": "\uC9C0\uC6B0\uAE30\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
|
|
212
270
|
"clear.empty": "\uC774 \uC138\uC158\uC5D0 \uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
213
271
|
"cancel.no_session": "\uD558\uC704 \uC138\uC158 ID\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
214
272
|
"cancel.not_child": "\uB300\uC0C1\uC774 \uD558\uC704 \uC138\uC158\uC774 \uC544\uB2D9\uB2C8\uB2E4",
|
|
@@ -219,7 +277,25 @@ var KO_T = {
|
|
|
219
277
|
"cancel.sent": "\uCDE8\uC18C \uC9C0\uC2DC\uB97C \uBCF4\uB0C8\uC2B5\uB2C8\uB2E4",
|
|
220
278
|
"cancel.failed": "\uCDE8\uC18C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
|
|
221
279
|
"borderShown": "\uD328\uB110 \uD14C\uB450\uB9AC \uD45C\uC2DC",
|
|
222
|
-
"borderHidden": "\uD328\uB110 \uD14C\uB450\uB9AC \uC228\uAE40"
|
|
280
|
+
"borderHidden": "\uD328\uB110 \uD14C\uB450\uB9AC \uC228\uAE40",
|
|
281
|
+
"settings.title": "SubAgent Magazine \u2014 \uC124\uC815",
|
|
282
|
+
"settings.section.general": "\uC77C\uBC18",
|
|
283
|
+
"settings.lang": "\uC5B8\uC5B4",
|
|
284
|
+
"settings.max": "\uCD5C\uB300 \uD56D\uBAA9 \uC218",
|
|
285
|
+
"settings.order": "\uC815\uB82C \uC21C\uC11C",
|
|
286
|
+
"settings.scroll": "\uC2A4\uD06C\uB864 \uBAA8\uB4DC",
|
|
287
|
+
"settings.ttl": "\uBCF4\uC874 \uAE30\uAC04",
|
|
288
|
+
"settings.border": "\uD328\uB110 \uD14C\uB450\uB9AC",
|
|
289
|
+
"settings.showEntryCost": "\uD558\uC704 \uC5D0\uC774\uC804\uD2B8\uBCC4 \uBE44\uC6A9",
|
|
290
|
+
"settings.showEntryTime": "\uBAA9\uB85D\uC5D0 \uC18C\uC694 \uC2DC\uAC04 \uD45C\uC2DC",
|
|
291
|
+
"settings.showEntryTokens": "\uBAA9\uB85D\uC5D0 \uD1A0\uD070 \uC218 \uD45C\uC2DC",
|
|
292
|
+
"settings.timeFormat": "\uC2DC\uAC04 \uD615\uC2DD",
|
|
293
|
+
"settings.dbSync": "\uB85C\uCEEC DB \uBCF4\uC644",
|
|
294
|
+
"settings.on": "\uCF2C",
|
|
295
|
+
"settings.off": "\uB054",
|
|
296
|
+
"settings.saved": "\uC800\uC7A5\uB428 {item}: {value}",
|
|
297
|
+
"settings.invalid": "\uC798\uBABB\uB41C \uAC12",
|
|
298
|
+
"settings.close": "\uB2EB\uAE30"
|
|
223
299
|
};
|
|
224
300
|
var LANGS = { zh: ZH_T, en: EN_T, ja: JA_T, ko: KO_T };
|
|
225
301
|
var LANG_META = [
|
|
@@ -260,8 +336,125 @@ var SETTING_KEYS = {
|
|
|
260
336
|
scrollMode: `${KV_PREFIX}.scroll_mode`,
|
|
261
337
|
open: `${KV_PREFIX}.open`,
|
|
262
338
|
ttlDays: `${KV_PREFIX}.ttl_days`,
|
|
263
|
-
border: `${KV_PREFIX}.border
|
|
339
|
+
border: `${KV_PREFIX}.border`,
|
|
340
|
+
showEntryCost: `${KV_PREFIX}.show_entry_cost`,
|
|
341
|
+
showEntryTime: `${KV_PREFIX}.show_entry_time`,
|
|
342
|
+
showEntryTokens: `${KV_PREFIX}.show_entry_tokens`,
|
|
343
|
+
timeFormat: `${KV_PREFIX}.time_format`,
|
|
344
|
+
dbSync: `${KV_PREFIX}.db_sync`
|
|
264
345
|
};
|
|
346
|
+
function loadSessionData(kv) {
|
|
347
|
+
try {
|
|
348
|
+
const raw = kv.get(SESSION_DATA_KEY, "{}");
|
|
349
|
+
return JSON.parse(String(raw));
|
|
350
|
+
} catch {
|
|
351
|
+
return {};
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function updateSessionData(kv, mutator) {
|
|
355
|
+
try {
|
|
356
|
+
if (typeof kv.update === "function") {
|
|
357
|
+
return kv.update(SESSION_DATA_KEY, (raw) => {
|
|
358
|
+
const data2 = parseSessionData(raw);
|
|
359
|
+
mutator(data2);
|
|
360
|
+
return JSON.stringify(data2);
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
const data = loadSessionData(kv);
|
|
364
|
+
mutator(data);
|
|
365
|
+
kv.set(SESSION_DATA_KEY, JSON.stringify(data));
|
|
366
|
+
} catch {
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function parseSessionData(raw) {
|
|
370
|
+
try {
|
|
371
|
+
return JSON.parse(String(raw ?? "{}"));
|
|
372
|
+
} catch {
|
|
373
|
+
return {};
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/core/format.ts
|
|
378
|
+
function charColumns(c) {
|
|
379
|
+
const code = c.codePointAt(0) ?? 0;
|
|
380
|
+
if (code < 32) return 0;
|
|
381
|
+
if (code < 127) return 1;
|
|
382
|
+
if (code < 160) return 0;
|
|
383
|
+
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)
|
|
384
|
+
return 2;
|
|
385
|
+
return 1;
|
|
386
|
+
}
|
|
387
|
+
function visualWidth(s) {
|
|
388
|
+
let w = 0;
|
|
389
|
+
for (const c of s) w += charColumns(c);
|
|
390
|
+
return w;
|
|
391
|
+
}
|
|
392
|
+
function truncate(text, maxCols) {
|
|
393
|
+
if (visualWidth(text) <= maxCols) return text;
|
|
394
|
+
let cols = 0;
|
|
395
|
+
let i = 0;
|
|
396
|
+
for (const c of text) {
|
|
397
|
+
const w = charColumns(c);
|
|
398
|
+
if (cols + w > maxCols - 1) break;
|
|
399
|
+
cols += w;
|
|
400
|
+
i += c.length;
|
|
401
|
+
}
|
|
402
|
+
return text.slice(0, i) + "\u2026";
|
|
403
|
+
}
|
|
404
|
+
function fmtDurationShort(ms, running) {
|
|
405
|
+
if (running && ms < 2e3) return "";
|
|
406
|
+
if (ms < 1e3) return (ms / 1e3).toFixed(2) + "s";
|
|
407
|
+
if (ms < 6e4) return (ms / 1e3).toFixed(2) + "s";
|
|
408
|
+
const m = Math.floor(ms / 6e4);
|
|
409
|
+
const s = Math.round(ms % 6e4 / 1e3);
|
|
410
|
+
return `${m}m${s}s`;
|
|
411
|
+
}
|
|
412
|
+
var TIME_FORMATS = ["short", "decimal", "clock", "compact", "seconds"];
|
|
413
|
+
var TIME_FORMAT_SAMPLES = {
|
|
414
|
+
decimal: "45.3s \xB7 9.5m \xB7 1.9h",
|
|
415
|
+
short: "45.32s \xB7 112m35s",
|
|
416
|
+
clock: "0:45 \xB7 1:52:35",
|
|
417
|
+
compact: "45s \xB7 1h52m",
|
|
418
|
+
seconds: "45s \xB7 6755s"
|
|
419
|
+
};
|
|
420
|
+
function fmtDuration(ms, running, mode = "short") {
|
|
421
|
+
if (running && ms < 2e3) return "";
|
|
422
|
+
const t = Number.isFinite(ms) && ms > 0 ? ms : 0;
|
|
423
|
+
switch (mode) {
|
|
424
|
+
case "short":
|
|
425
|
+
return fmtDurationShort(t, false);
|
|
426
|
+
case "compact": {
|
|
427
|
+
if (t < 6e4) return `${Math.floor(t / 1e3)}s`;
|
|
428
|
+
if (t < 36e5) return `${Math.floor(t / 6e4)}m${Math.floor(t % 6e4 / 1e3)}s`;
|
|
429
|
+
return `${Math.floor(t / 36e5)}h${Math.floor(t % 36e5 / 6e4)}m`;
|
|
430
|
+
}
|
|
431
|
+
case "clock": {
|
|
432
|
+
const s = Math.floor(t % 6e4 / 1e3);
|
|
433
|
+
if (t < 36e5) return `${Math.floor(t / 6e4)}:${String(s).padStart(2, "0")}`;
|
|
434
|
+
const m = Math.floor(t % 36e5 / 6e4);
|
|
435
|
+
return `${Math.floor(t / 36e5)}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
436
|
+
}
|
|
437
|
+
case "seconds":
|
|
438
|
+
return `${Math.floor(t / 1e3)}s`;
|
|
439
|
+
case "decimal":
|
|
440
|
+
default: {
|
|
441
|
+
if (t < 59950) return `${(t / 1e3).toFixed(1)}s`;
|
|
442
|
+
if (t < 3597e3) return `${(t / 6e4).toFixed(1)}m`;
|
|
443
|
+
return `${(t / 36e5).toFixed(1)}h`;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function fmtTokens(n) {
|
|
448
|
+
if (n < 1e3) return `${n}`;
|
|
449
|
+
if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
|
|
450
|
+
return `${(n / 1e6).toFixed(1)}M`;
|
|
451
|
+
}
|
|
452
|
+
function safeErrorMsg(err) {
|
|
453
|
+
if (!err) return "";
|
|
454
|
+
if (typeof err === "string") return err;
|
|
455
|
+
if (typeof err === "object") return String(err.message || err.code || "");
|
|
456
|
+
return "";
|
|
457
|
+
}
|
|
265
458
|
|
|
266
459
|
// src/panel/SubAgentPanel.tsx
|
|
267
460
|
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
@@ -376,53 +569,6 @@ async function copyText(text) {
|
|
|
376
569
|
// src/core/types.ts
|
|
377
570
|
var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["task", "subagent", "delegate", "call_omo_agent"]);
|
|
378
571
|
|
|
379
|
-
// src/core/format.ts
|
|
380
|
-
function charColumns(c) {
|
|
381
|
-
const code = c.codePointAt(0) ?? 0;
|
|
382
|
-
if (code < 32) return 0;
|
|
383
|
-
if (code < 127) return 1;
|
|
384
|
-
if (code < 160) return 0;
|
|
385
|
-
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)
|
|
386
|
-
return 2;
|
|
387
|
-
return 1;
|
|
388
|
-
}
|
|
389
|
-
function visualWidth(s) {
|
|
390
|
-
let w = 0;
|
|
391
|
-
for (const c of s) w += charColumns(c);
|
|
392
|
-
return w;
|
|
393
|
-
}
|
|
394
|
-
function truncate(text, maxCols) {
|
|
395
|
-
if (visualWidth(text) <= maxCols) return text;
|
|
396
|
-
let cols = 0;
|
|
397
|
-
let i = 0;
|
|
398
|
-
for (const c of text) {
|
|
399
|
-
const w = charColumns(c);
|
|
400
|
-
if (cols + w > maxCols - 1) break;
|
|
401
|
-
cols += w;
|
|
402
|
-
i += c.length;
|
|
403
|
-
}
|
|
404
|
-
return text.slice(0, i) + "\u2026";
|
|
405
|
-
}
|
|
406
|
-
function fmtDurationShort(ms, running) {
|
|
407
|
-
if (running && ms < 2e3) return "";
|
|
408
|
-
if (ms < 1e3) return (ms / 1e3).toFixed(2) + "s";
|
|
409
|
-
if (ms < 6e4) return (ms / 1e3).toFixed(2) + "s";
|
|
410
|
-
const m = Math.floor(ms / 6e4);
|
|
411
|
-
const s = Math.round(ms % 6e4 / 1e3);
|
|
412
|
-
return `${m}m${s}s`;
|
|
413
|
-
}
|
|
414
|
-
function fmtTokens(n) {
|
|
415
|
-
if (n < 1e3) return `${n}`;
|
|
416
|
-
if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
|
|
417
|
-
return `${(n / 1e6).toFixed(1)}M`;
|
|
418
|
-
}
|
|
419
|
-
function safeErrorMsg(err) {
|
|
420
|
-
if (!err) return "";
|
|
421
|
-
if (typeof err === "string") return err;
|
|
422
|
-
if (typeof err === "object") return String(err.message || err.code || "");
|
|
423
|
-
return "";
|
|
424
|
-
}
|
|
425
|
-
|
|
426
572
|
// src/core/color.ts
|
|
427
573
|
function rgb(raw) {
|
|
428
574
|
if (typeof raw === "string" && raw.startsWith("#")) {
|
|
@@ -525,17 +671,80 @@ function upsertSubEntry(entries, partial, now = Date.now()) {
|
|
|
525
671
|
});
|
|
526
672
|
return next;
|
|
527
673
|
}
|
|
674
|
+
function statusRank(status) {
|
|
675
|
+
if (status === "running") return 0;
|
|
676
|
+
if (status === "cancel_requested") return 1;
|
|
677
|
+
return 2;
|
|
678
|
+
}
|
|
679
|
+
var isTerminalStatus = (status) => statusRank(status) === 2;
|
|
680
|
+
function minDefined(a, b) {
|
|
681
|
+
if (a === void 0) return b;
|
|
682
|
+
if (b === void 0) return a;
|
|
683
|
+
return Math.min(a, b);
|
|
684
|
+
}
|
|
685
|
+
function maxDefined(a, b) {
|
|
686
|
+
if (a === void 0) return b;
|
|
687
|
+
if (b === void 0) return a;
|
|
688
|
+
return Math.max(a, b);
|
|
689
|
+
}
|
|
690
|
+
function mergeSubEntry(base, incoming) {
|
|
691
|
+
const successor = statusRank(incoming.status) > statusRank(base.status) ? incoming : base;
|
|
692
|
+
const status = successor.status;
|
|
693
|
+
const ended = isTerminalStatus(status);
|
|
694
|
+
return {
|
|
695
|
+
...base,
|
|
696
|
+
...incoming,
|
|
697
|
+
id: base.id,
|
|
698
|
+
status,
|
|
699
|
+
sessionId: incoming.sessionId ?? base.sessionId,
|
|
700
|
+
startedAt: minDefined(base.startedAt, incoming.startedAt) ?? base.startedAt,
|
|
701
|
+
endedAt: ended ? base.endedAt ?? incoming.endedAt ?? Date.now() : void 0,
|
|
702
|
+
tokens: maxDefined(base.tokens, incoming.tokens),
|
|
703
|
+
cost: maxDefined(base.cost, incoming.cost),
|
|
704
|
+
model: incoming.model ?? base.model,
|
|
705
|
+
todoTotal: maxDefined(base.todoTotal, incoming.todoTotal),
|
|
706
|
+
todoDone: maxDefined(base.todoDone, incoming.todoDone),
|
|
707
|
+
error: incoming.error ?? base.error,
|
|
708
|
+
cancelRequestedAt: minDefined(base.cancelRequestedAt, incoming.cancelRequestedAt),
|
|
709
|
+
abortAccepted: base.abortAccepted || incoming.abortAccepted || void 0,
|
|
710
|
+
cancelReason: incoming.cancelReason ?? base.cancelReason
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
function mergeSubEntries(base, incoming) {
|
|
714
|
+
const out = /* @__PURE__ */ new Map();
|
|
715
|
+
for (const entry of base) out.set(entry.id, entry);
|
|
716
|
+
for (const entry of incoming) {
|
|
717
|
+
const key = findSubEntryKey(out, entry.id, entry.sessionId);
|
|
718
|
+
if (!key) {
|
|
719
|
+
out.set(entry.id, entry);
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
out.set(key, mergeSubEntry(out.get(key), entry));
|
|
723
|
+
}
|
|
724
|
+
return out;
|
|
725
|
+
}
|
|
528
726
|
|
|
529
727
|
// src/panel/SubAgentPanel.tsx
|
|
530
728
|
var LEFT_PAD = 4;
|
|
531
729
|
var INDENT = 2;
|
|
730
|
+
function partMetadata(part, st) {
|
|
731
|
+
const partMeta = part?.metadata;
|
|
732
|
+
if (partMeta && Object.keys(partMeta).length > 0) return partMeta;
|
|
733
|
+
const stateMeta = st?.metadata;
|
|
734
|
+
return stateMeta && Object.keys(stateMeta).length > 0 ? stateMeta : void 0;
|
|
735
|
+
}
|
|
736
|
+
function validModel(model) {
|
|
737
|
+
if (typeof model !== "string") return false;
|
|
738
|
+
const s = model.trim();
|
|
739
|
+
return s.length > 0 && s !== "[object Object]" && !s.startsWith("{");
|
|
740
|
+
}
|
|
532
741
|
function SubAgentPanel(props) {
|
|
533
742
|
const t = createT(() => props.lang());
|
|
534
743
|
const SESSION_DATA_KEY2 = `${KV_PREFIX}.session_data`;
|
|
535
744
|
const ttlDaysRaw = parseInt(String(props.api.kv.get(`${KV_PREFIX}.ttl_days`, "3")), 10);
|
|
536
745
|
const ttlDays = Number.isNaN(ttlDaysRaw) ? 3 : ttlDaysRaw;
|
|
537
746
|
const TTL_MS = ttlDays * 24 * 60 * 60 * 1e3;
|
|
538
|
-
const
|
|
747
|
+
const loadSessionData2 = () => {
|
|
539
748
|
try {
|
|
540
749
|
const raw = props.api.kv.get(SESSION_DATA_KEY2, "{}");
|
|
541
750
|
return JSON.parse(String(raw));
|
|
@@ -543,11 +752,32 @@ function SubAgentPanel(props) {
|
|
|
543
752
|
return {};
|
|
544
753
|
}
|
|
545
754
|
};
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
755
|
+
const mutateSessionData = (mutator) => {
|
|
756
|
+
void Promise.resolve(updateSessionData(props.api.kv, mutator)).catch(() => {
|
|
757
|
+
});
|
|
758
|
+
};
|
|
759
|
+
const ensureRootRecord = (data, sid) => {
|
|
760
|
+
const rec = data[sid];
|
|
761
|
+
if (rec) return rec;
|
|
762
|
+
const created = {
|
|
763
|
+
ts: Date.now(),
|
|
764
|
+
entries: [],
|
|
765
|
+
scroll: 0,
|
|
766
|
+
expanded: "",
|
|
767
|
+
children: {}
|
|
768
|
+
};
|
|
769
|
+
data[sid] = created;
|
|
770
|
+
return created;
|
|
771
|
+
};
|
|
772
|
+
const ensureChildRecord = (data, parentSid, sid) => {
|
|
773
|
+
const parent = ensureRootRecord(data, parentSid);
|
|
774
|
+
if (!parent.children) parent.children = {};
|
|
775
|
+
if (!parent.children[sid]) parent.children[sid] = {
|
|
776
|
+
scroll: 0,
|
|
777
|
+
expanded: "",
|
|
778
|
+
entries: []
|
|
779
|
+
};
|
|
780
|
+
return parent.children[sid];
|
|
551
781
|
};
|
|
552
782
|
const resolveParent = (sid) => {
|
|
553
783
|
try {
|
|
@@ -571,7 +801,7 @@ function SubAgentPanel(props) {
|
|
|
571
801
|
parentSid,
|
|
572
802
|
isChild
|
|
573
803
|
} = resolveParent(sid);
|
|
574
|
-
const rec =
|
|
804
|
+
const rec = loadSessionData2()[parentSid];
|
|
575
805
|
if (rec) {
|
|
576
806
|
const source = isChild ? rec.children?.[sid]?.entries : rec.entries;
|
|
577
807
|
if (source) {
|
|
@@ -589,129 +819,71 @@ function SubAgentPanel(props) {
|
|
|
589
819
|
clearTimeout(persistTimer);
|
|
590
820
|
persistTimer = setTimeout(() => {
|
|
591
821
|
try {
|
|
592
|
-
|
|
822
|
+
mutateSessionData((data) => {
|
|
823
|
+
const {
|
|
824
|
+
parentSid,
|
|
825
|
+
isChild
|
|
826
|
+
} = resolveParent(sid);
|
|
827
|
+
if (isChild) {
|
|
828
|
+
const parent = ensureRootRecord(data, parentSid);
|
|
829
|
+
const child = ensureChildRecord(data, parentSid, sid);
|
|
830
|
+
child.entries = [...mergeSubEntries(child.entries ?? [], entries2.values()).values()];
|
|
831
|
+
parent.ts = Date.now();
|
|
832
|
+
} else {
|
|
833
|
+
const rec = ensureRootRecord(data, sid);
|
|
834
|
+
rec.ts = Date.now();
|
|
835
|
+
rec.entries = [...mergeSubEntries(rec.entries ?? [], entries2.values()).values()];
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
} catch {
|
|
839
|
+
}
|
|
840
|
+
}, 200);
|
|
841
|
+
};
|
|
842
|
+
const persistScroll = (sid, scroll) => {
|
|
843
|
+
try {
|
|
844
|
+
mutateSessionData((data) => {
|
|
593
845
|
const {
|
|
594
846
|
parentSid,
|
|
595
847
|
isChild
|
|
596
848
|
} = resolveParent(sid);
|
|
597
849
|
if (isChild) {
|
|
598
|
-
|
|
599
|
-
ts: Date.now(),
|
|
600
|
-
entries: [],
|
|
601
|
-
scroll: 0,
|
|
602
|
-
expanded: "",
|
|
603
|
-
children: {}
|
|
604
|
-
};
|
|
605
|
-
if (!data[parentSid].children) data[parentSid].children = {};
|
|
606
|
-
if (!data[parentSid].children[sid]) data[parentSid].children[sid] = {
|
|
607
|
-
scroll: 0,
|
|
608
|
-
expanded: "",
|
|
609
|
-
entries: []
|
|
610
|
-
};
|
|
611
|
-
data[parentSid].children[sid] = {
|
|
612
|
-
...data[parentSid].children[sid],
|
|
613
|
-
entries: [...entries2.values()]
|
|
614
|
-
};
|
|
850
|
+
ensureChildRecord(data, parentSid, sid).scroll = scroll;
|
|
615
851
|
} else {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
entries: [...entries2.values()],
|
|
620
|
-
children: data[sid]?.children ?? {}
|
|
621
|
-
};
|
|
852
|
+
const rec = ensureRootRecord(data, sid);
|
|
853
|
+
rec.ts = Date.now();
|
|
854
|
+
rec.scroll = scroll;
|
|
622
855
|
}
|
|
623
|
-
|
|
624
|
-
} catch {
|
|
625
|
-
}
|
|
626
|
-
}, 200);
|
|
627
|
-
};
|
|
628
|
-
const persistScroll = (sid, scroll) => {
|
|
629
|
-
try {
|
|
630
|
-
const data = loadSessionData();
|
|
631
|
-
const {
|
|
632
|
-
parentSid,
|
|
633
|
-
isChild
|
|
634
|
-
} = resolveParent(sid);
|
|
635
|
-
if (isChild) {
|
|
636
|
-
if (!data[parentSid]) data[parentSid] = {
|
|
637
|
-
ts: Date.now(),
|
|
638
|
-
entries: [],
|
|
639
|
-
scroll: 0,
|
|
640
|
-
expanded: "",
|
|
641
|
-
children: {}
|
|
642
|
-
};
|
|
643
|
-
if (!data[parentSid].children) data[parentSid].children = {};
|
|
644
|
-
if (!data[parentSid].children[sid]) data[parentSid].children[sid] = {
|
|
645
|
-
scroll: 0,
|
|
646
|
-
expanded: "",
|
|
647
|
-
entries: []
|
|
648
|
-
};
|
|
649
|
-
data[parentSid].children[sid] = {
|
|
650
|
-
...data[parentSid].children[sid],
|
|
651
|
-
scroll
|
|
652
|
-
};
|
|
653
|
-
} else {
|
|
654
|
-
data[sid] = {
|
|
655
|
-
...data[sid],
|
|
656
|
-
ts: Date.now(),
|
|
657
|
-
scroll,
|
|
658
|
-
children: data[sid]?.children ?? {}
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
saveSessionData(data);
|
|
856
|
+
});
|
|
662
857
|
} catch {
|
|
663
858
|
}
|
|
664
859
|
};
|
|
665
860
|
const persistExpanded = (sid, expanded2) => {
|
|
666
861
|
try {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
expanded
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
if (!data[parentSid].children) data[parentSid].children = {};
|
|
681
|
-
if (!data[parentSid].children[sid]) data[parentSid].children[sid] = {
|
|
682
|
-
scroll: 0,
|
|
683
|
-
expanded: "",
|
|
684
|
-
entries: []
|
|
685
|
-
};
|
|
686
|
-
data[parentSid].children[sid] = {
|
|
687
|
-
...data[parentSid].children[sid],
|
|
688
|
-
expanded: expanded2
|
|
689
|
-
};
|
|
690
|
-
} else {
|
|
691
|
-
data[sid] = {
|
|
692
|
-
...data[sid],
|
|
693
|
-
ts: Date.now(),
|
|
694
|
-
expanded: expanded2,
|
|
695
|
-
children: data[sid]?.children ?? {}
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
saveSessionData(data);
|
|
862
|
+
mutateSessionData((data) => {
|
|
863
|
+
const {
|
|
864
|
+
parentSid,
|
|
865
|
+
isChild
|
|
866
|
+
} = resolveParent(sid);
|
|
867
|
+
if (isChild) {
|
|
868
|
+
ensureChildRecord(data, parentSid, sid).expanded = expanded2;
|
|
869
|
+
} else {
|
|
870
|
+
const rec = ensureRootRecord(data, sid);
|
|
871
|
+
rec.ts = Date.now();
|
|
872
|
+
rec.expanded = expanded2;
|
|
873
|
+
}
|
|
874
|
+
});
|
|
699
875
|
} catch {
|
|
700
876
|
}
|
|
701
877
|
};
|
|
702
878
|
const cleanupOldSessions = () => {
|
|
703
879
|
if (ttlDays <= 0) return;
|
|
704
880
|
try {
|
|
705
|
-
const data = loadSessionData();
|
|
706
881
|
const cutoff = Date.now() - TTL_MS;
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
delete data[sid];
|
|
711
|
-
changed = true;
|
|
882
|
+
mutateSessionData((data) => {
|
|
883
|
+
for (const sid of Object.keys(data)) {
|
|
884
|
+
if (data[sid].ts < cutoff) delete data[sid];
|
|
712
885
|
}
|
|
713
|
-
}
|
|
714
|
-
if (changed) saveSessionData(data);
|
|
886
|
+
});
|
|
715
887
|
} catch {
|
|
716
888
|
}
|
|
717
889
|
};
|
|
@@ -731,38 +903,22 @@ function SubAgentPanel(props) {
|
|
|
731
903
|
if (needsImmediateFlush) {
|
|
732
904
|
clearTimeout(persistTimer);
|
|
733
905
|
try {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
entries
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
expanded: "",
|
|
751
|
-
entries: []
|
|
752
|
-
};
|
|
753
|
-
data[parentSid].children[props.sessionId] = {
|
|
754
|
-
...data[parentSid].children[props.sessionId],
|
|
755
|
-
entries: [...next.values()]
|
|
756
|
-
};
|
|
757
|
-
} else {
|
|
758
|
-
data[props.sessionId] = {
|
|
759
|
-
...data[props.sessionId],
|
|
760
|
-
ts: Date.now(),
|
|
761
|
-
entries: [...next.values()],
|
|
762
|
-
children: data[props.sessionId]?.children ?? {}
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
saveSessionData(data);
|
|
906
|
+
mutateSessionData((data) => {
|
|
907
|
+
const {
|
|
908
|
+
parentSid,
|
|
909
|
+
isChild
|
|
910
|
+
} = resolveParent(props.sessionId);
|
|
911
|
+
if (isChild) {
|
|
912
|
+
const parent = ensureRootRecord(data, parentSid);
|
|
913
|
+
const child = ensureChildRecord(data, parentSid, props.sessionId);
|
|
914
|
+
child.entries = [...mergeSubEntries(child.entries ?? [], next.values()).values()];
|
|
915
|
+
parent.ts = Date.now();
|
|
916
|
+
} else {
|
|
917
|
+
const rec = ensureRootRecord(data, props.sessionId);
|
|
918
|
+
rec.ts = Date.now();
|
|
919
|
+
rec.entries = [...mergeSubEntries(rec.entries ?? [], next.values()).values()];
|
|
920
|
+
}
|
|
921
|
+
});
|
|
766
922
|
} catch {
|
|
767
923
|
}
|
|
768
924
|
} else {
|
|
@@ -786,7 +942,7 @@ function SubAgentPanel(props) {
|
|
|
786
942
|
parentSid,
|
|
787
943
|
isChild
|
|
788
944
|
} = resolveParent(props.sessionId);
|
|
789
|
-
const rec =
|
|
945
|
+
const rec = loadSessionData2()[parentSid];
|
|
790
946
|
if (rec) return isChild ? rec.children?.[props.sessionId]?.expanded || void 0 : rec.expanded || void 0;
|
|
791
947
|
} catch {
|
|
792
948
|
}
|
|
@@ -804,7 +960,7 @@ function SubAgentPanel(props) {
|
|
|
804
960
|
parentSid,
|
|
805
961
|
isChild
|
|
806
962
|
} = resolveParent(props.sessionId);
|
|
807
|
-
const rec =
|
|
963
|
+
const rec = loadSessionData2()[parentSid];
|
|
808
964
|
return isChild ? rec?.children?.[props.sessionId]?.scroll ?? 0 : rec?.scroll ?? 0;
|
|
809
965
|
} catch {
|
|
810
966
|
return 0;
|
|
@@ -930,7 +1086,9 @@ function SubAgentPanel(props) {
|
|
|
930
1086
|
const part = event.payload?.part;
|
|
931
1087
|
if (!part) return;
|
|
932
1088
|
const eventSid = event.payload?.sessionID !== void 0 ? String(event.payload.sessionID) : void 0;
|
|
933
|
-
if (event.scope === "global" && eventSid !== props.sessionId)
|
|
1089
|
+
if (event.scope === "global" && eventSid !== props.sessionId) {
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
934
1092
|
if (part.type === "subtask") {
|
|
935
1093
|
const agent = String(part.agent ?? "?");
|
|
936
1094
|
const prompt = String(part.prompt ?? "");
|
|
@@ -959,7 +1117,7 @@ function SubAgentPanel(props) {
|
|
|
959
1117
|
if (rawStatus === "error") {
|
|
960
1118
|
const id2 = `tool:${String(part.id ?? "")}`;
|
|
961
1119
|
if (!part.id) return;
|
|
962
|
-
const stMeta2 = st
|
|
1120
|
+
const stMeta2 = partMetadata(part, st);
|
|
963
1121
|
const errorSid = stMeta2?.session_id !== void 0 ? String(stMeta2.session_id) : stMeta2?.sessionId !== void 0 ? String(stMeta2.sessionId) : void 0;
|
|
964
1122
|
const key = findSubEntryKey(entryMap(), id2, errorSid);
|
|
965
1123
|
const existing = key ? entryMap().get(key) : void 0;
|
|
@@ -979,7 +1137,7 @@ function SubAgentPanel(props) {
|
|
|
979
1137
|
let status = "running";
|
|
980
1138
|
if (rawStatus === "completed") status = "done";
|
|
981
1139
|
if ((input?.run_in_background === true || input?.background === true) && status === "done") {
|
|
982
|
-
const stMetaCheck = st
|
|
1140
|
+
const stMetaCheck = partMetadata(part, st);
|
|
983
1141
|
const hasChild = stMetaCheck?.session_id !== void 0 || stMetaCheck?.sessionId !== void 0;
|
|
984
1142
|
if (hasChild) status = "running";
|
|
985
1143
|
}
|
|
@@ -988,7 +1146,7 @@ function SubAgentPanel(props) {
|
|
|
988
1146
|
const desc = input?.description !== void 0 ? String(input.description) : "";
|
|
989
1147
|
const title = desc || truncate(prompt.replace(/\n/g, " ").replace(/\s+/g, " ").trim(), 40);
|
|
990
1148
|
const id = `tool:${String(part.id ?? crypto.randomUUID())}`;
|
|
991
|
-
const stMeta = st
|
|
1149
|
+
const stMeta = partMetadata(part, st);
|
|
992
1150
|
const subSid = stMeta?.session_id !== void 0 ? String(stMeta.session_id) : stMeta?.sessionId !== void 0 ? String(stMeta.sessionId) : void 0;
|
|
993
1151
|
upsertEntry({
|
|
994
1152
|
id,
|
|
@@ -1176,30 +1334,39 @@ function SubAgentPanel(props) {
|
|
|
1176
1334
|
found = tryMatchAndUpdate(parentCache, sid, status, nowTs);
|
|
1177
1335
|
}
|
|
1178
1336
|
if (!found) {
|
|
1179
|
-
const data =
|
|
1337
|
+
const data = loadSessionData2();
|
|
1180
1338
|
const rec = data[parentSid];
|
|
1181
|
-
if (rec?.entries) {
|
|
1339
|
+
if (rec?.entries?.length) {
|
|
1182
1340
|
const fallbackMap = new Map(rec.entries.map((e) => [e.id, e]));
|
|
1183
1341
|
found = tryMatchAndUpdate(fallbackMap, sid, status, nowTs);
|
|
1184
1342
|
if (found) {
|
|
1185
|
-
data[parentSid] = {
|
|
1186
|
-
...rec,
|
|
1187
|
-
ts: nowTs,
|
|
1188
|
-
entries: [...fallbackMap.values()]
|
|
1189
|
-
};
|
|
1190
|
-
saveSessionData(data);
|
|
1191
1343
|
globalEntryCache.set(parentSid, fallbackMap);
|
|
1344
|
+
mutateSessionData((latest) => {
|
|
1345
|
+
const latestRec = latest[parentSid];
|
|
1346
|
+
latest[parentSid] = {
|
|
1347
|
+
...latestRec ?? rec,
|
|
1348
|
+
ts: nowTs,
|
|
1349
|
+
entries: [...mergeSubEntries(latestRec?.entries ?? [], fallbackMap.values()).values()]
|
|
1350
|
+
};
|
|
1351
|
+
});
|
|
1192
1352
|
}
|
|
1193
1353
|
}
|
|
1194
1354
|
}
|
|
1195
1355
|
if (found && parentCache) {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1356
|
+
mutateSessionData((data) => {
|
|
1357
|
+
const rec = data[parentSid];
|
|
1358
|
+
data[parentSid] = {
|
|
1359
|
+
...rec ?? {
|
|
1360
|
+
entries: [],
|
|
1361
|
+
scroll: 0,
|
|
1362
|
+
expanded: "",
|
|
1363
|
+
children: {},
|
|
1364
|
+
ts: nowTs
|
|
1365
|
+
},
|
|
1366
|
+
ts: nowTs,
|
|
1367
|
+
entries: [...mergeSubEntries(rec?.entries ?? [], parentCache.values()).values()]
|
|
1368
|
+
};
|
|
1369
|
+
});
|
|
1203
1370
|
}
|
|
1204
1371
|
}
|
|
1205
1372
|
} catch {
|
|
@@ -1238,52 +1405,357 @@ function SubAgentPanel(props) {
|
|
|
1238
1405
|
}, 150);
|
|
1239
1406
|
};
|
|
1240
1407
|
const bump = () => setRenderTick((v) => v + 1);
|
|
1408
|
+
const settleIdleEntries = (prev) => {
|
|
1409
|
+
let changed = false;
|
|
1410
|
+
const next = new Map(prev);
|
|
1411
|
+
for (const [id, entry] of next) {
|
|
1412
|
+
if (entry.status !== "running" && entry.status !== "cancel_requested") continue;
|
|
1413
|
+
let sid = entry.sessionId;
|
|
1414
|
+
if (!sid) {
|
|
1415
|
+
try {
|
|
1416
|
+
const callId = String(entry.id).replace(/^tool:/, "");
|
|
1417
|
+
sid = props.api.session.resolveChild?.({
|
|
1418
|
+
parentId: props.sessionId,
|
|
1419
|
+
callId,
|
|
1420
|
+
agent: entry.agent,
|
|
1421
|
+
startedAt: entry.startedAt
|
|
1422
|
+
});
|
|
1423
|
+
} catch {
|
|
1424
|
+
}
|
|
1425
|
+
if (!sid) continue;
|
|
1426
|
+
next.set(id, {
|
|
1427
|
+
...entry,
|
|
1428
|
+
sessionId: sid
|
|
1429
|
+
});
|
|
1430
|
+
changed = true;
|
|
1431
|
+
}
|
|
1432
|
+
try {
|
|
1433
|
+
const st = props.api.session.status(sid);
|
|
1434
|
+
if (!st || st.type !== "idle") continue;
|
|
1435
|
+
const tokens = props.api.usage.readSessionTokens(sid);
|
|
1436
|
+
const cost = props.api.usage.readSessionCost(sid);
|
|
1437
|
+
const finalStatus = entry.status === "cancel_requested" && entry.abortAccepted ? "cancelled" : "done";
|
|
1438
|
+
next.set(id, {
|
|
1439
|
+
...entry,
|
|
1440
|
+
sessionId: sid,
|
|
1441
|
+
status: finalStatus,
|
|
1442
|
+
endedAt: Date.now(),
|
|
1443
|
+
tokens: tokens ?? entry.tokens,
|
|
1444
|
+
cost: cost ?? entry.cost
|
|
1445
|
+
});
|
|
1446
|
+
changed = true;
|
|
1447
|
+
} catch {
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
return changed ? next : prev;
|
|
1451
|
+
};
|
|
1452
|
+
const reconcileIdleEntries = () => {
|
|
1453
|
+
try {
|
|
1454
|
+
const before = entryMap();
|
|
1455
|
+
const after = settleIdleEntries(before);
|
|
1456
|
+
if (after !== before) setEntryMap(after);
|
|
1457
|
+
} catch {
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
const runSessionScan = (sid, replace) => {
|
|
1461
|
+
let msgs;
|
|
1462
|
+
try {
|
|
1463
|
+
msgs = props.api.session.messages(sid);
|
|
1464
|
+
} catch {
|
|
1465
|
+
}
|
|
1466
|
+
if (!msgs || msgs.length === 0) return false;
|
|
1467
|
+
setEntryMapRaw((prev) => {
|
|
1468
|
+
const next = replace ? new Map(globalEntryCache.get(sid) ?? loadEntries(sid)) : new Map(prev);
|
|
1469
|
+
const {
|
|
1470
|
+
parentSid: scanPSid,
|
|
1471
|
+
isChild: scanChild
|
|
1472
|
+
} = resolveParent(sid);
|
|
1473
|
+
const scanRec = loadSessionData2()[scanPSid];
|
|
1474
|
+
const clearedIds = new Set(scanChild ? scanRec?.children?.[sid]?.clearedIds : scanRec?.clearedIds);
|
|
1475
|
+
try {
|
|
1476
|
+
for (const msg of msgs) {
|
|
1477
|
+
const parts = props.api.session.part(msg.id) ?? [];
|
|
1478
|
+
for (const partRaw of parts) {
|
|
1479
|
+
const part = partRaw;
|
|
1480
|
+
if (part.type === "tool") {
|
|
1481
|
+
const tool = String(part.tool ?? "");
|
|
1482
|
+
if (!SUBAGENT_TOOLS.has(tool)) continue;
|
|
1483
|
+
const id = `tool:${String(part.id ?? "")}`;
|
|
1484
|
+
if (!part.id) continue;
|
|
1485
|
+
const st = part.state;
|
|
1486
|
+
const rawStatus = String(st?.status ?? "");
|
|
1487
|
+
const scanInput = st?.input;
|
|
1488
|
+
const scanMeta = partMetadata(part, st);
|
|
1489
|
+
let scanSubSid = scanMeta?.session_id !== void 0 ? String(scanMeta.session_id) : scanMeta?.sessionId !== void 0 ? String(scanMeta.sessionId) : scanMeta?.sessionID !== void 0 ? String(scanMeta.sessionID) : void 0;
|
|
1490
|
+
if (!scanSubSid) {
|
|
1491
|
+
try {
|
|
1492
|
+
scanSubSid = props.api.session.resolveChild?.({
|
|
1493
|
+
parentId: sid,
|
|
1494
|
+
callId: String(part.id)
|
|
1495
|
+
});
|
|
1496
|
+
} catch {
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
const existingKey = findSubEntryKey(next, id, scanSubSid);
|
|
1500
|
+
const exists = existingKey ? next.get(existingKey) : void 0;
|
|
1501
|
+
if (!exists && clearedIds.has(id)) continue;
|
|
1502
|
+
if ((rawStatus === "pending" || rawStatus === "") && !exists) continue;
|
|
1503
|
+
if (rawStatus === "error") {
|
|
1504
|
+
if (exists && exists.status === "running") {
|
|
1505
|
+
next.set(existingKey ?? id, {
|
|
1506
|
+
...exists,
|
|
1507
|
+
status: "error",
|
|
1508
|
+
endedAt: Date.now()
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
1511
|
+
continue;
|
|
1512
|
+
}
|
|
1513
|
+
const settled = exists !== void 0 && exists.status !== "running" && exists.status !== "cancel_requested";
|
|
1514
|
+
const needsRepair = settled && (exists.sessionId === void 0 || exists.tokens === void 0 || exists.cost === void 0 || !validModel(exists.model));
|
|
1515
|
+
if (settled && !needsRepair) continue;
|
|
1516
|
+
let status = "running";
|
|
1517
|
+
if (rawStatus === "completed") status = "done";
|
|
1518
|
+
if ((scanInput?.run_in_background === true || scanInput?.background === true) && status === "done") {
|
|
1519
|
+
if (scanSubSid !== void 0) status = "running";
|
|
1520
|
+
}
|
|
1521
|
+
if (status === "done" && scanSubSid) {
|
|
1522
|
+
try {
|
|
1523
|
+
const childStatus = props.api.session.status(scanSubSid);
|
|
1524
|
+
if (childStatus && childStatus.type !== "idle") status = "running";
|
|
1525
|
+
} catch {
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
if (settled) {
|
|
1529
|
+
status = exists.status;
|
|
1530
|
+
} else if (exists && status === "running") {
|
|
1531
|
+
if (!rawStatus) {
|
|
1532
|
+
const msgTokens = msg?.tokens;
|
|
1533
|
+
if (msgTokens && (Number(msgTokens.input) > 0 || Number(msgTokens.output) > 0)) {
|
|
1534
|
+
status = "done";
|
|
1535
|
+
} else {
|
|
1536
|
+
continue;
|
|
1537
|
+
}
|
|
1538
|
+
} else {
|
|
1539
|
+
continue;
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
const agent = String(part.subagent_type ?? scanInput?.agent ?? scanInput?.subagent_type ?? tool);
|
|
1543
|
+
const prompt = String(scanInput?.prompt ?? part.description ?? "");
|
|
1544
|
+
const desc = scanInput?.description !== void 0 ? String(scanInput.description) : "";
|
|
1545
|
+
const title = desc || truncate(prompt.replace(/\n/g, " ").trim(), 40);
|
|
1546
|
+
let tokens;
|
|
1547
|
+
if (scanSubSid) tokens = props.api.usage.readSessionTokens(scanSubSid);
|
|
1548
|
+
let cost;
|
|
1549
|
+
if (scanSubSid) cost = props.api.usage.readSessionCost(scanSubSid);
|
|
1550
|
+
let model;
|
|
1551
|
+
if (scanSubSid) model = props.api.usage.readSessionModel(scanSubSid);
|
|
1552
|
+
const entryKey = existingKey ?? id;
|
|
1553
|
+
next.set(entryKey, {
|
|
1554
|
+
...exists ?? {
|
|
1555
|
+
id
|
|
1556
|
+
},
|
|
1557
|
+
title: title || exists?.title || "",
|
|
1558
|
+
agent: exists?.agent ?? agent,
|
|
1559
|
+
prompt: prompt || exists?.prompt || "",
|
|
1560
|
+
// Preserve existing values (from handleSessionEnd / KV) — scan must not overwrite
|
|
1561
|
+
tokens: exists?.tokens ?? tokens,
|
|
1562
|
+
cost: exists?.cost ?? cost,
|
|
1563
|
+
model: validModel(exists?.model) ? exists.model : model,
|
|
1564
|
+
sessionId: exists?.sessionId ?? scanSubSid,
|
|
1565
|
+
status,
|
|
1566
|
+
startedAt: exists?.startedAt || Date.now(),
|
|
1567
|
+
endedAt: exists?.endedAt ?? (status === "done" ? Date.now() : void 0)
|
|
1568
|
+
});
|
|
1569
|
+
if (entryKey !== id) next.delete(id);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
} catch {
|
|
1574
|
+
}
|
|
1575
|
+
return next;
|
|
1576
|
+
});
|
|
1577
|
+
setEntryMapRaw((prev) => settleIdleEntries(prev));
|
|
1578
|
+
const snapshot = entryMap();
|
|
1579
|
+
if (snapshot.size > 0) {
|
|
1580
|
+
globalEntryCache.set(sid, new Map(snapshot));
|
|
1581
|
+
persistEntries(sid, snapshot);
|
|
1582
|
+
}
|
|
1583
|
+
return true;
|
|
1584
|
+
};
|
|
1585
|
+
let rescanTimer;
|
|
1586
|
+
const missingNewestToolPart = () => {
|
|
1587
|
+
try {
|
|
1588
|
+
const msgs = props.api.session.messages(props.sessionId);
|
|
1589
|
+
if (!msgs || msgs.length === 0) return false;
|
|
1590
|
+
const map = entryMap();
|
|
1591
|
+
const from = Math.max(0, msgs.length - 6);
|
|
1592
|
+
for (let i = msgs.length - 1; i >= from; i--) {
|
|
1593
|
+
const parts = props.api.session.part(msgs[i]?.id) ?? [];
|
|
1594
|
+
for (const part of parts) {
|
|
1595
|
+
if (!part || part.type !== "tool") continue;
|
|
1596
|
+
if (!SUBAGENT_TOOLS.has(String(part.tool ?? ""))) continue;
|
|
1597
|
+
const partId = String(part.id ?? "");
|
|
1598
|
+
if (!partId) continue;
|
|
1599
|
+
const st = part.state;
|
|
1600
|
+
const rawStatus = String(st?.status ?? "");
|
|
1601
|
+
if (rawStatus !== "running" && rawStatus !== "completed") continue;
|
|
1602
|
+
const id = `tool:${partId}`;
|
|
1603
|
+
const meta = partMetadata(part, st);
|
|
1604
|
+
const subSid = meta?.session_id !== void 0 ? String(meta.session_id) : meta?.sessionId !== void 0 ? String(meta.sessionId) : void 0;
|
|
1605
|
+
const key = findSubEntryKey(map, id, subSid);
|
|
1606
|
+
const entry = key ? map.get(key) : void 0;
|
|
1607
|
+
if (!entry) return true;
|
|
1608
|
+
const input = st?.input;
|
|
1609
|
+
const isBackground = input?.background === true || input?.run_in_background === true;
|
|
1610
|
+
const stillRunning = entry.status === "running" || entry.status === "cancel_requested";
|
|
1611
|
+
if (rawStatus === "completed" && !isBackground && stillRunning) return true;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
} catch {
|
|
1615
|
+
}
|
|
1616
|
+
return false;
|
|
1617
|
+
};
|
|
1618
|
+
const scheduleRescan = () => {
|
|
1619
|
+
if (disposed) return;
|
|
1620
|
+
clearTimeout(rescanTimer);
|
|
1621
|
+
rescanTimer = setTimeout(() => {
|
|
1622
|
+
if (disposed) return;
|
|
1623
|
+
untrack(() => {
|
|
1624
|
+
if (!missingNewestToolPart()) return;
|
|
1625
|
+
runSessionScan(props.sessionId, false);
|
|
1626
|
+
bump();
|
|
1627
|
+
});
|
|
1628
|
+
}, 400);
|
|
1629
|
+
};
|
|
1630
|
+
let enrichCursor = 0;
|
|
1241
1631
|
onMount(() => {
|
|
1242
1632
|
const clock = setInterval(() => {
|
|
1243
1633
|
setNow(Date.now());
|
|
1244
1634
|
bump();
|
|
1245
1635
|
}, 100);
|
|
1636
|
+
let tick = 0;
|
|
1246
1637
|
const tokenTimer = setInterval(() => {
|
|
1638
|
+
tick++;
|
|
1247
1639
|
untrack(() => {
|
|
1640
|
+
let enriched;
|
|
1641
|
+
let attempted = 0;
|
|
1248
1642
|
setEntryMapRaw((prev) => {
|
|
1249
1643
|
let changed = false;
|
|
1250
1644
|
const next = new Map(prev);
|
|
1645
|
+
const candidates = [];
|
|
1251
1646
|
for (const [id, entry] of next) {
|
|
1252
|
-
|
|
1647
|
+
const running = entry.status === "running" || entry.status === "cancel_requested";
|
|
1648
|
+
const missing = entry.tokens === void 0 || entry.cost === void 0 || !validModel(entry.model);
|
|
1649
|
+
if (entry.sessionId && !running && !missing) continue;
|
|
1650
|
+
candidates.push(id);
|
|
1651
|
+
}
|
|
1652
|
+
if (candidates.length > 0) {
|
|
1653
|
+
const start = enrichCursor % candidates.length;
|
|
1654
|
+
let budget = 4;
|
|
1655
|
+
for (let k = 0; k < candidates.length && budget > 0; k++) {
|
|
1656
|
+
const id = candidates[(start + k) % candidates.length];
|
|
1657
|
+
let entry = next.get(id);
|
|
1658
|
+
if (!entry) continue;
|
|
1659
|
+
if (!entry.sessionId) {
|
|
1660
|
+
try {
|
|
1661
|
+
const callId = String(entry.id).replace(/^tool:/, "");
|
|
1662
|
+
const sid = props.api.session.resolveChild?.({
|
|
1663
|
+
parentId: props.sessionId,
|
|
1664
|
+
callId,
|
|
1665
|
+
agent: entry.agent,
|
|
1666
|
+
startedAt: entry.startedAt
|
|
1667
|
+
});
|
|
1668
|
+
if (sid) {
|
|
1669
|
+
entry = {
|
|
1670
|
+
...entry,
|
|
1671
|
+
sessionId: sid
|
|
1672
|
+
};
|
|
1673
|
+
next.set(id, entry);
|
|
1674
|
+
changed = true;
|
|
1675
|
+
}
|
|
1676
|
+
} catch {
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
if (!entry.sessionId) continue;
|
|
1680
|
+
const childSid = entry.sessionId;
|
|
1253
1681
|
let isChild = false;
|
|
1254
1682
|
try {
|
|
1255
|
-
const s = props.api.session.get(
|
|
1256
|
-
isChild = s
|
|
1683
|
+
const s = props.api.session.get(childSid);
|
|
1684
|
+
isChild = !s || s.parentID === props.sessionId;
|
|
1257
1685
|
} catch {
|
|
1686
|
+
isChild = true;
|
|
1258
1687
|
}
|
|
1259
1688
|
if (!isChild) continue;
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
const
|
|
1689
|
+
budget--;
|
|
1690
|
+
attempted++;
|
|
1691
|
+
const running = entry.status === "running" || entry.status === "cancel_requested";
|
|
1692
|
+
let entryChanged = false;
|
|
1263
1693
|
const nextEntry = {
|
|
1264
1694
|
...entry
|
|
1265
1695
|
};
|
|
1266
|
-
if (
|
|
1267
|
-
|
|
1268
|
-
|
|
1696
|
+
if (running || entry.tokens === void 0) {
|
|
1697
|
+
const total = props.api.usage.readSessionTokens(childSid);
|
|
1698
|
+
if (total !== void 0 && total !== entry.tokens) {
|
|
1699
|
+
nextEntry.tokens = total;
|
|
1700
|
+
entryChanged = true;
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
if (running || entry.cost === void 0) {
|
|
1704
|
+
const cost = props.api.usage.readSessionCost(childSid);
|
|
1705
|
+
if (cost !== void 0 && cost !== entry.cost) {
|
|
1706
|
+
nextEntry.cost = cost;
|
|
1707
|
+
entryChanged = true;
|
|
1708
|
+
}
|
|
1269
1709
|
}
|
|
1270
|
-
if (
|
|
1271
|
-
|
|
1710
|
+
if (running || !validModel(entry.model)) {
|
|
1711
|
+
const model = props.api.usage.readSessionModel(childSid);
|
|
1712
|
+
if (model && model !== entry.model) {
|
|
1713
|
+
nextEntry.model = model;
|
|
1714
|
+
entryChanged = true;
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
if (running) {
|
|
1718
|
+
const todo = props.api.usage.readSessionTodo(childSid);
|
|
1719
|
+
if (todo !== void 0 && (todo.total !== entry.todoTotal || todo.done !== entry.todoDone)) {
|
|
1272
1720
|
nextEntry.todoTotal = todo.total;
|
|
1273
1721
|
nextEntry.todoDone = todo.done;
|
|
1274
|
-
|
|
1722
|
+
entryChanged = true;
|
|
1275
1723
|
}
|
|
1276
1724
|
}
|
|
1277
|
-
if (
|
|
1278
|
-
|
|
1725
|
+
if (entryChanged) {
|
|
1726
|
+
next.set(id, nextEntry);
|
|
1279
1727
|
changed = true;
|
|
1280
1728
|
}
|
|
1281
|
-
if (changed) next.set(id, nextEntry);
|
|
1282
1729
|
}
|
|
1730
|
+
enrichCursor = (start + Math.max(1, attempted)) % candidates.length;
|
|
1283
1731
|
}
|
|
1284
|
-
|
|
1732
|
+
if (!changed) return prev;
|
|
1733
|
+
enriched = next;
|
|
1734
|
+
return next;
|
|
1285
1735
|
});
|
|
1736
|
+
if (enriched) {
|
|
1737
|
+
globalEntryCache.set(props.sessionId, new Map(enriched));
|
|
1738
|
+
persistEntries(props.sessionId, enriched);
|
|
1739
|
+
}
|
|
1286
1740
|
});
|
|
1741
|
+
reconcileIdleEntries();
|
|
1742
|
+
if (tick % 4 === 0) {
|
|
1743
|
+
untrack(() => {
|
|
1744
|
+
if (missingNewestToolPart()) {
|
|
1745
|
+
runSessionScan(props.sessionId, false);
|
|
1746
|
+
bump();
|
|
1747
|
+
}
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
if (tick % 60 === 0) {
|
|
1751
|
+
untrack(() => {
|
|
1752
|
+
const hasRunning = entryList().some((e) => e.status === "running" || e.status === "cancel_requested");
|
|
1753
|
+
if (hasRunning) {
|
|
1754
|
+
runSessionScan(props.sessionId, false);
|
|
1755
|
+
bump();
|
|
1756
|
+
}
|
|
1757
|
+
});
|
|
1758
|
+
}
|
|
1287
1759
|
bump();
|
|
1288
1760
|
}, 500);
|
|
1289
1761
|
bump();
|
|
@@ -1291,7 +1763,10 @@ function SubAgentPanel(props) {
|
|
|
1291
1763
|
handlePartUpdated(e);
|
|
1292
1764
|
bump();
|
|
1293
1765
|
});
|
|
1294
|
-
const unsubMsg = props.api.event.on("message.updated", () =>
|
|
1766
|
+
const unsubMsg = props.api.event.on("message.updated", () => {
|
|
1767
|
+
bump();
|
|
1768
|
+
scheduleRescan();
|
|
1769
|
+
});
|
|
1295
1770
|
const unsubIdle = props.api.event.on("session.idle", (e) => {
|
|
1296
1771
|
handleSessionEnd(e, "done");
|
|
1297
1772
|
bump();
|
|
@@ -1302,6 +1777,7 @@ function SubAgentPanel(props) {
|
|
|
1302
1777
|
});
|
|
1303
1778
|
onCleanup(() => {
|
|
1304
1779
|
disposed = true;
|
|
1780
|
+
clearTimeout(rescanTimer);
|
|
1305
1781
|
clearInterval(clock);
|
|
1306
1782
|
clearInterval(tokenTimer);
|
|
1307
1783
|
unsubPart();
|
|
@@ -1319,139 +1795,38 @@ function SubAgentPanel(props) {
|
|
|
1319
1795
|
const tick = clearTick();
|
|
1320
1796
|
const forceReload = tick !== lastTick && !switched;
|
|
1321
1797
|
lastTick = tick;
|
|
1322
|
-
|
|
1798
|
+
let attempts = 0;
|
|
1799
|
+
let retryTimer;
|
|
1800
|
+
const run = () => {
|
|
1323
1801
|
untrack(() => {
|
|
1324
1802
|
if (switched) {
|
|
1325
1803
|
const {
|
|
1326
1804
|
parentSid,
|
|
1327
1805
|
isChild
|
|
1328
1806
|
} = resolveParent(sid);
|
|
1329
|
-
const data =
|
|
1807
|
+
const data = loadSessionData2();
|
|
1330
1808
|
const saved = isChild ? data[parentSid]?.children?.[sid]?.scroll ?? 0 : data[sid]?.scroll ?? 0;
|
|
1331
1809
|
setScrollOffset(saved);
|
|
1332
1810
|
if (!isChild && data[sid]?.entries?.length) {
|
|
1333
|
-
|
|
1334
|
-
|
|
1811
|
+
void Promise.resolve(updateSessionData(props.api.kv, (latest) => {
|
|
1812
|
+
if (latest[sid]?.entries?.length) latest[sid].ts = Date.now();
|
|
1813
|
+
})).catch(() => {
|
|
1814
|
+
});
|
|
1335
1815
|
}
|
|
1336
1816
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
} = resolveParent(sid);
|
|
1343
|
-
const scanRec = loadSessionData()[scanPSid];
|
|
1344
|
-
const clearedIds = new Set(scanChild ? scanRec?.children?.[sid]?.clearedIds : scanRec?.clearedIds);
|
|
1345
|
-
try {
|
|
1346
|
-
const msgs = props.api.session.messages(sid);
|
|
1347
|
-
if (msgs && msgs.length) {
|
|
1348
|
-
for (const msg of msgs) {
|
|
1349
|
-
const parts = props.api.session.part(msg.id) ?? [];
|
|
1350
|
-
for (const partRaw of parts) {
|
|
1351
|
-
const part = partRaw;
|
|
1352
|
-
if (part.type === "tool") {
|
|
1353
|
-
const tool = String(part.tool ?? "");
|
|
1354
|
-
if (!SUBAGENT_TOOLS.has(tool)) continue;
|
|
1355
|
-
const id = `tool:${String(part.id ?? "")}`;
|
|
1356
|
-
if (!part.id) continue;
|
|
1357
|
-
const st = part.state;
|
|
1358
|
-
const rawStatus = String(st?.status ?? "");
|
|
1359
|
-
const scanStMeta = st?.metadata;
|
|
1360
|
-
const scanSubSid = scanStMeta?.session_id !== void 0 ? String(scanStMeta.session_id) : scanStMeta?.sessionId !== void 0 ? String(scanStMeta.sessionId) : void 0;
|
|
1361
|
-
const existingKey = findSubEntryKey(next, id, scanSubSid);
|
|
1362
|
-
const exists = existingKey ? next.get(existingKey) : void 0;
|
|
1363
|
-
if (!exists && clearedIds.has(id)) continue;
|
|
1364
|
-
if ((rawStatus === "pending" || rawStatus === "") && !exists) continue;
|
|
1365
|
-
if (rawStatus === "error") {
|
|
1366
|
-
if (exists && exists.status === "running") {
|
|
1367
|
-
next.set(existingKey ?? id, {
|
|
1368
|
-
...exists,
|
|
1369
|
-
status: "error",
|
|
1370
|
-
endedAt: Date.now()
|
|
1371
|
-
});
|
|
1372
|
-
}
|
|
1373
|
-
continue;
|
|
1374
|
-
}
|
|
1375
|
-
let status = "running";
|
|
1376
|
-
if (rawStatus === "completed") status = "done";
|
|
1377
|
-
if ((st?.input?.run_in_background === true || st?.input?.background === true) && status === "done") {
|
|
1378
|
-
const scanStMeta2 = st?.metadata;
|
|
1379
|
-
const scanHasChild = scanStMeta2?.session_id !== void 0 || scanStMeta2?.sessionId !== void 0;
|
|
1380
|
-
if (scanHasChild) status = "running";
|
|
1381
|
-
}
|
|
1382
|
-
if (exists && existingKey === id && exists.status !== "running" && exists.status !== "cancel_requested") continue;
|
|
1383
|
-
if (exists && status === "running") {
|
|
1384
|
-
if (!rawStatus) {
|
|
1385
|
-
const msgTokens = msg?.tokens;
|
|
1386
|
-
if (msgTokens && (Number(msgTokens.input) > 0 || Number(msgTokens.output) > 0)) {
|
|
1387
|
-
status = "done";
|
|
1388
|
-
} else if (Date.now() - exists.startedAt > 30 * 60 * 1e3) {
|
|
1389
|
-
status = "done";
|
|
1390
|
-
} else {
|
|
1391
|
-
continue;
|
|
1392
|
-
}
|
|
1393
|
-
} else {
|
|
1394
|
-
continue;
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
const input = st?.input;
|
|
1398
|
-
const agent = String(part.subagent_type ?? input?.agent ?? input?.subagent_type ?? tool);
|
|
1399
|
-
const prompt = String(input?.prompt ?? part.description ?? "");
|
|
1400
|
-
const desc = input?.description !== void 0 ? String(input.description) : "";
|
|
1401
|
-
const title = desc || truncate(prompt.replace(/\n/g, " ").trim(), 40);
|
|
1402
|
-
let tokens;
|
|
1403
|
-
if (scanSubSid) tokens = props.api.usage.readSessionTokens(scanSubSid);
|
|
1404
|
-
const ended = status === "done";
|
|
1405
|
-
const entryKey = existingKey ?? id;
|
|
1406
|
-
next.set(entryKey, {
|
|
1407
|
-
id: exists?.id ?? id,
|
|
1408
|
-
title,
|
|
1409
|
-
agent,
|
|
1410
|
-
prompt,
|
|
1411
|
-
// Preserve existing values (from handleSessionEnd / KV) — scan must not overwrite
|
|
1412
|
-
tokens: exists?.tokens ?? tokens,
|
|
1413
|
-
sessionId: exists?.sessionId ?? scanSubSid,
|
|
1414
|
-
status,
|
|
1415
|
-
startedAt: exists?.startedAt || Date.now(),
|
|
1416
|
-
endedAt: ended ? exists?.endedAt || Date.now() : void 0
|
|
1417
|
-
});
|
|
1418
|
-
if (entryKey !== id) next.delete(id);
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
} catch {
|
|
1424
|
-
}
|
|
1425
|
-
return next;
|
|
1426
|
-
});
|
|
1427
|
-
setEntryMapRaw((prev) => {
|
|
1428
|
-
let changed = false;
|
|
1429
|
-
const next = new Map(prev);
|
|
1430
|
-
for (const [id, entry] of next) {
|
|
1431
|
-
if (entry.status !== "running" && entry.status !== "cancel_requested" || !entry.sessionId) continue;
|
|
1432
|
-
try {
|
|
1433
|
-
const st = props.api.session.status(entry.sessionId);
|
|
1434
|
-
if (!st || st.type !== "idle") continue;
|
|
1435
|
-
const tokens = props.api.usage.readSessionTokens(entry.sessionId);
|
|
1436
|
-
const cost = props.api.usage.readSessionCost(entry.sessionId);
|
|
1437
|
-
const finalStatus = entry.status === "cancel_requested" && entry.abortAccepted ? "cancelled" : "done";
|
|
1438
|
-
next.set(id, {
|
|
1439
|
-
...entry,
|
|
1440
|
-
status: finalStatus,
|
|
1441
|
-
endedAt: Date.now(),
|
|
1442
|
-
tokens: tokens ?? entry.tokens,
|
|
1443
|
-
cost: cost ?? entry.cost
|
|
1444
|
-
});
|
|
1445
|
-
changed = true;
|
|
1446
|
-
} catch {
|
|
1447
|
-
}
|
|
1448
|
-
}
|
|
1449
|
-
return changed ? next : prev;
|
|
1450
|
-
});
|
|
1451
|
-
bump();
|
|
1817
|
+
const ok = runSessionScan(sid, switched || forceReload);
|
|
1818
|
+
if (!ok && attempts < 4) {
|
|
1819
|
+
attempts++;
|
|
1820
|
+
retryTimer = setTimeout(run, 400);
|
|
1821
|
+
}
|
|
1452
1822
|
});
|
|
1453
|
-
|
|
1454
|
-
|
|
1823
|
+
bump();
|
|
1824
|
+
};
|
|
1825
|
+
const t2 = setTimeout(run, 150);
|
|
1826
|
+
onCleanup(() => {
|
|
1827
|
+
clearTimeout(t2);
|
|
1828
|
+
if (retryTimer) clearTimeout(retryTimer);
|
|
1829
|
+
});
|
|
1455
1830
|
});
|
|
1456
1831
|
const pal = createMemo(() => {
|
|
1457
1832
|
const th = props.theme;
|
|
@@ -1830,14 +2205,17 @@ function SubAgentPanel(props) {
|
|
|
1830
2205
|
return "#" + [r, g, bl].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
|
|
1831
2206
|
};
|
|
1832
2207
|
const timeColor = () => isActiveRunning ? pal().warning : isError ? pal().error : pal().muted;
|
|
1833
|
-
const tokenText = () => !isExpanded() && entry.tokens !== void 0 && entry.tokens > 0 ? ` ${fmtTokens(entry.tokens)}` : "";
|
|
1834
|
-
const
|
|
2208
|
+
const tokenText = () => !isExpanded() && props.showEntryTokens() && entry.tokens !== void 0 && entry.tokens > 0 ? ` ${fmtTokens(entry.tokens)}` : "";
|
|
2209
|
+
const costText = () => !isExpanded() && props.showEntryCost() && entry.cost !== void 0 && entry.cost > 0 ? ` $${entry.cost.toFixed(4)}` : "";
|
|
2210
|
+
const timeText = () => !isExpanded() && props.showEntryTime() && (elapsed() >= 2e3 || entry.endedAt !== void 0) ? fmtDuration(elapsed(), isActiveRunning, props.timeFormat()) : "";
|
|
1835
2211
|
const suffixW = () => {
|
|
1836
2212
|
let w = 0;
|
|
1837
2213
|
const t2 = timeText();
|
|
1838
2214
|
if (t2) w += 1 + visualWidth(t2);
|
|
1839
2215
|
const tk = tokenText();
|
|
1840
2216
|
if (tk) w += visualWidth(tk);
|
|
2217
|
+
const c = costText();
|
|
2218
|
+
if (c) w += visualWidth(c);
|
|
1841
2219
|
return w;
|
|
1842
2220
|
};
|
|
1843
2221
|
const labelAvail = () => Math.max(6, panelWidth() - gutter() - LEFT_PAD - suffixW());
|
|
@@ -1881,6 +2259,17 @@ function SubAgentPanel(props) {
|
|
|
1881
2259
|
return _el$83;
|
|
1882
2260
|
})() : null;
|
|
1883
2261
|
})(), null);
|
|
2262
|
+
_$insert(_el$25, (() => {
|
|
2263
|
+
var _c$4 = _$memo(() => !!costText());
|
|
2264
|
+
return () => _c$4() ? (() => {
|
|
2265
|
+
var _el$84 = _$createElement("span");
|
|
2266
|
+
_$insert(_el$84, costText);
|
|
2267
|
+
_$effect((_$p) => _$setProp(_el$84, "style", {
|
|
2268
|
+
fg: pal().warning
|
|
2269
|
+
}, _$p));
|
|
2270
|
+
return _el$84;
|
|
2271
|
+
})() : null;
|
|
2272
|
+
})(), null);
|
|
1884
2273
|
_$effect((_p$) => {
|
|
1885
2274
|
var _v$3 = {
|
|
1886
2275
|
fg: pal().muted
|
|
@@ -1973,7 +2362,7 @@ function SubAgentPanel(props) {
|
|
|
1973
2362
|
_$insertNode(_el$45, _el$46);
|
|
1974
2363
|
_$insert(_el$45, () => t("time.label"), _el$46);
|
|
1975
2364
|
_$insert(_el$47, () => " ".repeat(expandedPad(t("time.label"))));
|
|
1976
|
-
_$insert(_el$48, () =>
|
|
2365
|
+
_$insert(_el$48, () => fmtDuration(elapsed(), isActiveRunning, props.timeFormat()));
|
|
1977
2366
|
_$effect((_p$) => {
|
|
1978
2367
|
var _v$10 = {
|
|
1979
2368
|
fg: pal().primary
|
|
@@ -2067,16 +2456,16 @@ function SubAgentPanel(props) {
|
|
|
2067
2456
|
return (() => {
|
|
2068
2457
|
const cost = entry.cost;
|
|
2069
2458
|
return (() => {
|
|
2070
|
-
var _el$
|
|
2071
|
-
_$insertNode(_el$
|
|
2072
|
-
_$insertNode(_el$
|
|
2073
|
-
_$insertNode(_el$
|
|
2074
|
-
_$insertNode(_el$
|
|
2075
|
-
_$insertNode(_el$
|
|
2076
|
-
_$insert(_el$
|
|
2077
|
-
_$insert(_el$
|
|
2078
|
-
_$insertNode(_el$
|
|
2079
|
-
_$insert(_el$
|
|
2459
|
+
var _el$85 = _$createElement("text"), _el$86 = _$createTextNode(` `), _el$87 = _$createElement("span"), _el$88 = _$createTextNode(`: `), _el$89 = _$createElement("span"), _el$90 = _$createElement("span"), _el$91 = _$createTextNode(`$`);
|
|
2460
|
+
_$insertNode(_el$85, _el$86);
|
|
2461
|
+
_$insertNode(_el$85, _el$87);
|
|
2462
|
+
_$insertNode(_el$85, _el$89);
|
|
2463
|
+
_$insertNode(_el$85, _el$90);
|
|
2464
|
+
_$insertNode(_el$87, _el$88);
|
|
2465
|
+
_$insert(_el$87, () => t("cost.label"), _el$88);
|
|
2466
|
+
_$insert(_el$89, () => " ".repeat(expandedPad(t("cost.label"))));
|
|
2467
|
+
_$insertNode(_el$90, _el$91);
|
|
2468
|
+
_$insert(_el$90, () => cost.toFixed(4), null);
|
|
2080
2469
|
_$effect((_p$) => {
|
|
2081
2470
|
var _v$29 = {
|
|
2082
2471
|
fg: pal().primary
|
|
@@ -2085,22 +2474,22 @@ function SubAgentPanel(props) {
|
|
|
2085
2474
|
}, _v$31 = {
|
|
2086
2475
|
fg: pal().muted
|
|
2087
2476
|
};
|
|
2088
|
-
_v$29 !== _p$.e && (_p$.e = _$setProp(_el$
|
|
2089
|
-
_v$30 !== _p$.t && (_p$.t = _$setProp(_el$
|
|
2090
|
-
_v$31 !== _p$.a && (_p$.a = _$setProp(_el$
|
|
2477
|
+
_v$29 !== _p$.e && (_p$.e = _$setProp(_el$87, "style", _v$29, _p$.e));
|
|
2478
|
+
_v$30 !== _p$.t && (_p$.t = _$setProp(_el$89, "style", _v$30, _p$.t));
|
|
2479
|
+
_v$31 !== _p$.a && (_p$.a = _$setProp(_el$90, "style", _v$31, _p$.a));
|
|
2091
2480
|
return _p$;
|
|
2092
2481
|
}, {
|
|
2093
2482
|
e: void 0,
|
|
2094
2483
|
t: void 0,
|
|
2095
2484
|
a: void 0
|
|
2096
2485
|
});
|
|
2097
|
-
return _el$
|
|
2486
|
+
return _el$85;
|
|
2098
2487
|
})();
|
|
2099
2488
|
})();
|
|
2100
2489
|
}
|
|
2101
2490
|
}), _$createComponent(Show, {
|
|
2102
2491
|
get when() {
|
|
2103
|
-
return entry.model;
|
|
2492
|
+
return _$memo(() => !!validModel(entry.model))() ? entry.model : void 0;
|
|
2104
2493
|
},
|
|
2105
2494
|
get children() {
|
|
2106
2495
|
var _el$61 = _$createElement("text"), _el$62 = _$createTextNode(` `), _el$63 = _$createElement("span"), _el$64 = _$createTextNode(`: `), _el$65 = _$createElement("span"), _el$66 = _$createElement("span");
|
|
@@ -2239,68 +2628,68 @@ ${t("session.toast.copy_failed")}`, {
|
|
|
2239
2628
|
const rightW = (isRunning ? visualWidth(dismissLabel()) : 0) + (isRunning && entry.sessionId ? visualWidth(cancelLabel()) : 0);
|
|
2240
2629
|
const spacerW = () => Math.max(1, panelWidth() - gutter() - openW() - rightW - 2);
|
|
2241
2630
|
return (() => {
|
|
2242
|
-
var _el$
|
|
2243
|
-
_$insertNode(_el$
|
|
2244
|
-
_$setProp(_el$
|
|
2245
|
-
_$insert(_el$
|
|
2631
|
+
var _el$92 = _$createElement("box"), _el$96 = _$createElement("text");
|
|
2632
|
+
_$insertNode(_el$92, _el$96);
|
|
2633
|
+
_$setProp(_el$92, "flexDirection", "row");
|
|
2634
|
+
_$insert(_el$92, _$createComponent(Show, {
|
|
2246
2635
|
get when() {
|
|
2247
2636
|
return entry.sessionId;
|
|
2248
2637
|
},
|
|
2249
2638
|
get children() {
|
|
2250
|
-
var _el$
|
|
2251
|
-
_$insertNode(_el$
|
|
2252
|
-
_$insertNode(_el$
|
|
2253
|
-
_$setProp(_el$
|
|
2254
|
-
_$setProp(_el$
|
|
2255
|
-
_$setProp(_el$
|
|
2639
|
+
var _el$93 = _$createElement("text"), _el$94 = _$createElement("span"), _el$95 = _$createElement("span");
|
|
2640
|
+
_$insertNode(_el$93, _el$94);
|
|
2641
|
+
_$insertNode(_el$93, _el$95);
|
|
2642
|
+
_$setProp(_el$93, "onMouseOver", () => setHoveredOpen(entry.id));
|
|
2643
|
+
_$setProp(_el$93, "onMouseOut", () => setHoveredOpen(void 0));
|
|
2644
|
+
_$setProp(_el$93, "onMouseUp", () => {
|
|
2256
2645
|
if (entry.sessionId) {
|
|
2257
2646
|
props.api.route.navigateSession(entry.sessionId);
|
|
2258
2647
|
}
|
|
2259
2648
|
});
|
|
2260
|
-
_$insert(_el$
|
|
2261
|
-
_$insert(_el$
|
|
2649
|
+
_$insert(_el$94, openPrefix);
|
|
2650
|
+
_$insert(_el$95, () => t("open.label"));
|
|
2262
2651
|
_$effect((_p$) => {
|
|
2263
2652
|
var _v$32 = {
|
|
2264
2653
|
fg: hoveredOpen() === entry.id ? pal().warning : pal().primary
|
|
2265
2654
|
}, _v$33 = {
|
|
2266
2655
|
fg: hoveredOpen() === entry.id ? pal().warning : pal().primary
|
|
2267
2656
|
};
|
|
2268
|
-
_v$32 !== _p$.e && (_p$.e = _$setProp(_el$
|
|
2269
|
-
_v$33 !== _p$.t && (_p$.t = _$setProp(_el$
|
|
2657
|
+
_v$32 !== _p$.e && (_p$.e = _$setProp(_el$94, "style", _v$32, _p$.e));
|
|
2658
|
+
_v$33 !== _p$.t && (_p$.t = _$setProp(_el$95, "style", _v$33, _p$.t));
|
|
2270
2659
|
return _p$;
|
|
2271
2660
|
}, {
|
|
2272
2661
|
e: void 0,
|
|
2273
2662
|
t: void 0
|
|
2274
2663
|
});
|
|
2275
|
-
return _el$
|
|
2664
|
+
return _el$93;
|
|
2276
2665
|
}
|
|
2277
|
-
}), _el$
|
|
2278
|
-
_$insert(_el$
|
|
2279
|
-
_$insert(_el$
|
|
2666
|
+
}), _el$96);
|
|
2667
|
+
_$insert(_el$96, () => " ".repeat(spacerW()));
|
|
2668
|
+
_$insert(_el$92, _$createComponent(Show, {
|
|
2280
2669
|
get when() {
|
|
2281
2670
|
return isRunning && entry.sessionId;
|
|
2282
2671
|
},
|
|
2283
2672
|
get children() {
|
|
2284
|
-
var _el$
|
|
2285
|
-
_$insertNode(_el$
|
|
2286
|
-
_$setProp(_el$
|
|
2287
|
-
_$setProp(_el$
|
|
2288
|
-
_$setProp(_el$
|
|
2289
|
-
_$insert(_el$
|
|
2290
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2673
|
+
var _el$97 = _$createElement("text"), _el$98 = _$createElement("span");
|
|
2674
|
+
_$insertNode(_el$97, _el$98);
|
|
2675
|
+
_$setProp(_el$97, "onMouseOver", () => setHoveredCancel(entry.id));
|
|
2676
|
+
_$setProp(_el$97, "onMouseOut", () => setHoveredCancel(void 0));
|
|
2677
|
+
_$setProp(_el$97, "onMouseUp", () => cancelEntry(entry));
|
|
2678
|
+
_$insert(_el$98, cancelLabel);
|
|
2679
|
+
_$effect((_$p) => _$setProp(_el$98, "style", {
|
|
2291
2680
|
fg: hoveredCancel() === entry.id ? pal().warning : pal().error
|
|
2292
2681
|
}, _$p));
|
|
2293
|
-
return _el$
|
|
2682
|
+
return _el$97;
|
|
2294
2683
|
}
|
|
2295
2684
|
}), null);
|
|
2296
|
-
_$insert(_el$
|
|
2685
|
+
_$insert(_el$92, _$createComponent(Show, {
|
|
2297
2686
|
when: isRunning,
|
|
2298
2687
|
get children() {
|
|
2299
|
-
var _el$
|
|
2300
|
-
_$insertNode(_el$
|
|
2301
|
-
_$setProp(_el$
|
|
2302
|
-
_$setProp(_el$
|
|
2303
|
-
_$setProp(_el$
|
|
2688
|
+
var _el$99 = _$createElement("text"), _el$100 = _$createElement("span");
|
|
2689
|
+
_$insertNode(_el$99, _el$100);
|
|
2690
|
+
_$setProp(_el$99, "onMouseOver", () => setHoveredDismiss(entry.id));
|
|
2691
|
+
_$setProp(_el$99, "onMouseOut", () => setHoveredDismiss(void 0));
|
|
2692
|
+
_$setProp(_el$99, "onMouseUp", () => {
|
|
2304
2693
|
upsertEntry({
|
|
2305
2694
|
id: entry.id,
|
|
2306
2695
|
title: entry.title,
|
|
@@ -2309,17 +2698,17 @@ ${t("session.toast.copy_failed")}`, {
|
|
|
2309
2698
|
status: "done"
|
|
2310
2699
|
});
|
|
2311
2700
|
});
|
|
2312
|
-
_$insert(_el$
|
|
2313
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2701
|
+
_$insert(_el$100, dismissLabel);
|
|
2702
|
+
_$effect((_$p) => _$setProp(_el$100, "style", {
|
|
2314
2703
|
fg: hoveredDismiss() === entry.id ? pal().warning : pal().muted
|
|
2315
2704
|
}, _$p));
|
|
2316
|
-
return _el$
|
|
2705
|
+
return _el$99;
|
|
2317
2706
|
}
|
|
2318
2707
|
}), null);
|
|
2319
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2708
|
+
_$effect((_$p) => _$setProp(_el$96, "style", {
|
|
2320
2709
|
fg: pal().muted
|
|
2321
2710
|
}, _$p));
|
|
2322
|
-
return _el$
|
|
2711
|
+
return _el$92;
|
|
2323
2712
|
})();
|
|
2324
2713
|
})();
|
|
2325
2714
|
}
|
|
@@ -2340,13 +2729,13 @@ ${t("session.toast.copy_failed")}`, {
|
|
|
2340
2729
|
const right = props.sortOrder() === "desc" ? `\u2191 ${t("scroll.top")}` : `\u2193 ${t("scroll.bottom")}`;
|
|
2341
2730
|
const pad = showTop ? Math.max(1, panelWidth() - gutter() - visualWidth(left) - visualWidth(right)) : 0;
|
|
2342
2731
|
return (() => {
|
|
2343
|
-
var _el$
|
|
2344
|
-
_$insertNode(_el$100, _el$101);
|
|
2345
|
-
_$setProp(_el$100, "flexDirection", "row");
|
|
2732
|
+
var _el$101 = _$createElement("box"), _el$102 = _$createElement("text"), _el$103 = _$createElement("span");
|
|
2346
2733
|
_$insertNode(_el$101, _el$102);
|
|
2347
|
-
_$setProp(_el$101, "
|
|
2348
|
-
_$
|
|
2349
|
-
_$setProp(_el$
|
|
2734
|
+
_$setProp(_el$101, "flexDirection", "row");
|
|
2735
|
+
_$insertNode(_el$102, _el$103);
|
|
2736
|
+
_$setProp(_el$102, "onMouseOver", () => showMore && setHoveredMoreBelow(true));
|
|
2737
|
+
_$setProp(_el$102, "onMouseOut", () => setHoveredMoreBelow(false));
|
|
2738
|
+
_$setProp(_el$102, "onMouseUp", () => {
|
|
2350
2739
|
if (!showMore) return;
|
|
2351
2740
|
const total = entryList().length;
|
|
2352
2741
|
const m = max();
|
|
@@ -2358,20 +2747,20 @@ ${t("session.toast.copy_failed")}`, {
|
|
|
2358
2747
|
}
|
|
2359
2748
|
setHoveredMoreBelow(false);
|
|
2360
2749
|
});
|
|
2361
|
-
_$insert(_el$
|
|
2362
|
-
_$insert(_el$
|
|
2363
|
-
var _el$
|
|
2364
|
-
_$insert(_el$
|
|
2365
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2750
|
+
_$insert(_el$103, left);
|
|
2751
|
+
_$insert(_el$101, showTop ? [(() => {
|
|
2752
|
+
var _el$104 = _$createElement("text");
|
|
2753
|
+
_$insert(_el$104, () => " ".repeat(pad));
|
|
2754
|
+
_$effect((_$p) => _$setProp(_el$104, "style", {
|
|
2366
2755
|
fg: pal().muted
|
|
2367
2756
|
}, _$p));
|
|
2368
|
-
return _el$
|
|
2757
|
+
return _el$104;
|
|
2369
2758
|
})(), (() => {
|
|
2370
|
-
var _el$
|
|
2371
|
-
_$insertNode(_el$
|
|
2372
|
-
_$setProp(_el$
|
|
2373
|
-
_$setProp(_el$
|
|
2374
|
-
_$setProp(_el$
|
|
2759
|
+
var _el$105 = _$createElement("text"), _el$106 = _$createElement("span");
|
|
2760
|
+
_$insertNode(_el$105, _el$106);
|
|
2761
|
+
_$setProp(_el$105, "onMouseOver", () => setHoveredTop(true));
|
|
2762
|
+
_$setProp(_el$105, "onMouseOut", () => setHoveredTop(false));
|
|
2763
|
+
_$setProp(_el$105, "onMouseUp", () => {
|
|
2375
2764
|
const total = entryList().length;
|
|
2376
2765
|
const m = max();
|
|
2377
2766
|
if (props.sortOrder() === "desc") {
|
|
@@ -2381,16 +2770,16 @@ ${t("session.toast.copy_failed")}`, {
|
|
|
2381
2770
|
}
|
|
2382
2771
|
setHoveredTop(false);
|
|
2383
2772
|
});
|
|
2384
|
-
_$insert(_el$
|
|
2385
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2773
|
+
_$insert(_el$106, right);
|
|
2774
|
+
_$effect((_$p) => _$setProp(_el$106, "style", {
|
|
2386
2775
|
fg: hoveredTop() ? pal().warning : pal().muted
|
|
2387
2776
|
}, _$p));
|
|
2388
|
-
return _el$
|
|
2777
|
+
return _el$105;
|
|
2389
2778
|
})()] : null, null);
|
|
2390
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2779
|
+
_$effect((_$p) => _$setProp(_el$103, "style", {
|
|
2391
2780
|
fg: showMore && hoveredMoreBelow() ? pal().warning : pal().muted
|
|
2392
2781
|
}, _$p));
|
|
2393
|
-
return _el$
|
|
2782
|
+
return _el$101;
|
|
2394
2783
|
})();
|
|
2395
2784
|
})();
|
|
2396
2785
|
}
|
|
@@ -2444,6 +2833,18 @@ function createSidebarSlot(api, panelApi, sig) {
|
|
|
2444
2833
|
get borderVisible() {
|
|
2445
2834
|
return sig.borderVisible;
|
|
2446
2835
|
},
|
|
2836
|
+
get showEntryCost() {
|
|
2837
|
+
return sig.showEntryCost;
|
|
2838
|
+
},
|
|
2839
|
+
get showEntryTime() {
|
|
2840
|
+
return sig.showEntryTime;
|
|
2841
|
+
},
|
|
2842
|
+
get showEntryTokens() {
|
|
2843
|
+
return sig.showEntryTokens;
|
|
2844
|
+
},
|
|
2845
|
+
get timeFormat() {
|
|
2846
|
+
return sig.timeFormat;
|
|
2847
|
+
},
|
|
2447
2848
|
get sessionId() {
|
|
2448
2849
|
return input.session_id;
|
|
2449
2850
|
}
|
|
@@ -2460,6 +2861,12 @@ var tui = async (api) => {
|
|
|
2460
2861
|
const [sortOrder, setSortOrder] = createSignal3(String(api.kv.get(`${KV_PREFIX}.order`, "desc")) === "asc" ? "asc" : "desc");
|
|
2461
2862
|
const [scrollMode, setScrollMode] = createSignal3(String(api.kv.get(`${KV_PREFIX}.scroll_mode`, "wheel")) === "click" ? "click" : "wheel");
|
|
2462
2863
|
const [borderVisible, setBorderVisible] = createSignal3(api.kv.get(`${KV_PREFIX}.border`, false) === true);
|
|
2864
|
+
const [showEntryCost, setShowEntryCost] = createSignal3(api.kv.get(`${KV_PREFIX}.show_entry_cost`, false) === true);
|
|
2865
|
+
const [showEntryTime, setShowEntryTime] = createSignal3(api.kv.get(`${KV_PREFIX}.show_entry_time`, true) !== false);
|
|
2866
|
+
const [showEntryTokens, setShowEntryTokens] = createSignal3(api.kv.get(`${KV_PREFIX}.show_entry_tokens`, true) !== false);
|
|
2867
|
+
const storedTimeFormat = String(api.kv.get(`${KV_PREFIX}.time_format`, "short"));
|
|
2868
|
+
const [timeFormat, setTimeFormat] = createSignal3(TIME_FORMATS.includes(storedTimeFormat) ? storedTimeFormat : "short");
|
|
2869
|
+
const [dbSync, setDbSync] = createSignal3(api.kv.get(`${KV_PREFIX}.db_sync`, true) !== false);
|
|
2463
2870
|
const signals = {
|
|
2464
2871
|
lang,
|
|
2465
2872
|
setLang,
|
|
@@ -2471,6 +2878,16 @@ var tui = async (api) => {
|
|
|
2471
2878
|
setScrollMode,
|
|
2472
2879
|
borderVisible,
|
|
2473
2880
|
setBorderVisible,
|
|
2881
|
+
showEntryCost,
|
|
2882
|
+
setShowEntryCost,
|
|
2883
|
+
showEntryTime,
|
|
2884
|
+
setShowEntryTime,
|
|
2885
|
+
showEntryTokens,
|
|
2886
|
+
setShowEntryTokens,
|
|
2887
|
+
timeFormat,
|
|
2888
|
+
setTimeFormat,
|
|
2889
|
+
dbSync,
|
|
2890
|
+
setDbSync,
|
|
2474
2891
|
sessionId: ""
|
|
2475
2892
|
};
|
|
2476
2893
|
const v1Api = {
|
|
@@ -2971,6 +3388,85 @@ var tui = async (api) => {
|
|
|
2971
3388
|
});
|
|
2972
3389
|
dialog?.clear();
|
|
2973
3390
|
}
|
|
3391
|
+
}, {
|
|
3392
|
+
title: "SubAgent Magazine: Entry Cost",
|
|
3393
|
+
value: "subagent-cost",
|
|
3394
|
+
description: "Show or hide the per-sub-agent cost in the sidebar",
|
|
3395
|
+
slash: {
|
|
3396
|
+
name: "subagent-cost"
|
|
3397
|
+
},
|
|
3398
|
+
onSelect: (dialog) => {
|
|
3399
|
+
const t = createT(() => signals.lang());
|
|
3400
|
+
const cur = Boolean(api.kv.get(`${KV_PREFIX}.show_entry_cost`, false));
|
|
3401
|
+
api.kv.set(`${KV_PREFIX}.show_entry_cost`, !cur);
|
|
3402
|
+
signals.setShowEntryCost(!cur);
|
|
3403
|
+
api.ui.toast({
|
|
3404
|
+
message: `${t("settings.showEntryCost")}: ${!cur ? t("settings.on") : t("settings.off")}`
|
|
3405
|
+
});
|
|
3406
|
+
dialog?.clear();
|
|
3407
|
+
}
|
|
3408
|
+
}, {
|
|
3409
|
+
title: "SubAgent Magazine: Entry Time",
|
|
3410
|
+
value: "subagent-time",
|
|
3411
|
+
description: "Show or hide the elapsed time in the sidebar list",
|
|
3412
|
+
slash: {
|
|
3413
|
+
name: "subagent-time"
|
|
3414
|
+
},
|
|
3415
|
+
onSelect: (dialog) => {
|
|
3416
|
+
const t = createT(() => signals.lang());
|
|
3417
|
+
const cur = Boolean(api.kv.get(`${KV_PREFIX}.show_entry_time`, true));
|
|
3418
|
+
api.kv.set(`${KV_PREFIX}.show_entry_time`, !cur);
|
|
3419
|
+
signals.setShowEntryTime(!cur);
|
|
3420
|
+
api.ui.toast({
|
|
3421
|
+
message: `${t("settings.showEntryTime")}: ${!cur ? t("settings.on") : t("settings.off")}`
|
|
3422
|
+
});
|
|
3423
|
+
dialog?.clear();
|
|
3424
|
+
}
|
|
3425
|
+
}, {
|
|
3426
|
+
title: "SubAgent Magazine: Entry Tokens",
|
|
3427
|
+
value: "subagent-tokens",
|
|
3428
|
+
description: "Show or hide the token count in the sidebar list",
|
|
3429
|
+
slash: {
|
|
3430
|
+
name: "subagent-tokens"
|
|
3431
|
+
},
|
|
3432
|
+
onSelect: (dialog) => {
|
|
3433
|
+
const t = createT(() => signals.lang());
|
|
3434
|
+
const cur = Boolean(api.kv.get(`${KV_PREFIX}.show_entry_tokens`, true));
|
|
3435
|
+
api.kv.set(`${KV_PREFIX}.show_entry_tokens`, !cur);
|
|
3436
|
+
signals.setShowEntryTokens(!cur);
|
|
3437
|
+
api.ui.toast({
|
|
3438
|
+
message: `${t("settings.showEntryTokens")}: ${!cur ? t("settings.on") : t("settings.off")}`
|
|
3439
|
+
});
|
|
3440
|
+
dialog?.clear();
|
|
3441
|
+
}
|
|
3442
|
+
}, {
|
|
3443
|
+
title: "SubAgent Magazine: Time Format",
|
|
3444
|
+
value: "subagent-time-format",
|
|
3445
|
+
description: "Set how elapsed time is displayed",
|
|
3446
|
+
slash: {
|
|
3447
|
+
name: "subagent-time-format"
|
|
3448
|
+
},
|
|
3449
|
+
onSelect: (dialog) => {
|
|
3450
|
+
dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
|
|
3451
|
+
title: "Time Format / \u65F6\u95F4\u683C\u5F0F",
|
|
3452
|
+
get options() {
|
|
3453
|
+
return TIME_FORMATS.map((f) => ({
|
|
3454
|
+
title: `${f} \u2014 ${TIME_FORMAT_SAMPLES[f]}`,
|
|
3455
|
+
value: f
|
|
3456
|
+
}));
|
|
3457
|
+
},
|
|
3458
|
+
onSelect: (opt) => {
|
|
3459
|
+
const f = opt.value;
|
|
3460
|
+
setTimeFormat(f);
|
|
3461
|
+
api.kv.set(`${KV_PREFIX}.time_format`, f);
|
|
3462
|
+
const t = createT(() => lang());
|
|
3463
|
+
api.ui.toast({
|
|
3464
|
+
message: `${t("settings.timeFormat")}: ${TIME_FORMAT_SAMPLES[f]}`
|
|
3465
|
+
});
|
|
3466
|
+
dialog?.clear();
|
|
3467
|
+
}
|
|
3468
|
+
}));
|
|
3469
|
+
}
|
|
2974
3470
|
}]);
|
|
2975
3471
|
};
|
|
2976
3472
|
var mod = {
|