opencode-subagent-magazine 1.7.1 → 1.7.3
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/_version.d.ts +1 -1
- package/dist/panel/entry-map.d.ts +29 -0
- package/dist/tui.js +166 -19
- package/dist/v2.js +145 -22
- package/package.json +17 -4
- package/dist/_version.js +0 -2
- package/dist/clipboard.js +0 -85
- package/dist/core/color.js +0 -68
- package/dist/core/format.js +0 -113
- package/dist/core/index.js +0 -6
- package/dist/core/kv.js +0 -64
- package/dist/core/state-machine.js +0 -27
- package/dist/core/types.js +0 -9
- package/dist/core/usage.js +0 -1
- package/dist/i18n.js +0 -353
- package/dist/index.js +0 -528
- package/dist/panel/SubAgentPanel.js +0 -1644
- package/dist/panel/entry-map.js +0 -99
- package/dist/panel/panel-api.js +0 -1
- package/dist/panel/session-routing.js +0 -4
- package/dist/panel/store.js +0 -5
- package/dist/server.js +0 -14
- package/dist/v2/commands.js +0 -434
- package/dist/v2/db.js +0 -341
- package/dist/v2/index.js +0 -85
- package/dist/v2/settings-menu.js +0 -242
- package/dist/v2/theme.js +0 -12
- package/dist/v2/types.js +0 -6
- package/dist/v2/v2-panel-api.js +0 -623
- package/src/_version.ts +0 -2
- package/src/clipboard.ts +0 -134
- package/src/core/color.ts +0 -70
- package/src/core/format.ts +0 -105
- package/src/core/index.ts +0 -6
- package/src/core/kv.ts +0 -78
- package/src/core/state-machine.ts +0 -46
- package/src/core/types.ts +0 -85
- package/src/core/usage.ts +0 -16
- package/src/i18n.ts +0 -365
- package/src/index.tsx +0 -584
- package/src/panel/SubAgentPanel.tsx +0 -1877
- package/src/panel/entry-map.ts +0 -116
- package/src/panel/panel-api.ts +0 -100
- package/src/panel/session-routing.ts +0 -10
- package/src/panel/store.ts +0 -8
- package/src/server.ts +0 -19
- package/src/v2/commands.ts +0 -422
- package/src/v2/db.ts +0 -346
- package/src/v2/index.tsx +0 -149
- package/src/v2/settings-menu.ts +0 -259
- package/src/v2/theme.ts +0 -14
- package/src/v2/types.ts +0 -167
- package/src/v2/v2-panel-api.ts +0 -520
package/dist/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PLUGIN_VERSION = "1.7.
|
|
1
|
+
export declare const PLUGIN_VERSION = "1.7.3";
|
|
@@ -21,3 +21,32 @@ export declare function mergeSubEntry(base: SubEntry, incoming: SubEntry): SubEn
|
|
|
21
21
|
* 互相丢弃对方的条目。
|
|
22
22
|
*/
|
|
23
23
|
export declare function mergeSubEntries(base: Iterable<SubEntry>, incoming: Iterable<SubEntry>): Map<string, SubEntry>;
|
|
24
|
+
/** 持久化保留的 prompt 前缀长度。prompt 只用于生成 title,不参与渲染;
|
|
25
|
+
* 写入前截断,避免单条 10KB+ 的提示词把 KV 撑大(实测存量 prompt 占 2.9MB/4.4MB)。 */
|
|
26
|
+
export declare const PERSISTED_PROMPT_MAX = 128;
|
|
27
|
+
/** 压缩条目载荷(当前仅截断 prompt)。已达标时原样返回,避免无谓复制。 */
|
|
28
|
+
export declare function compactSubEntry(entry: SubEntry): SubEntry;
|
|
29
|
+
/**
|
|
30
|
+
* 持久化合并——所有 KV 写入路径的唯一入口:
|
|
31
|
+
* 1. 剔除 id 已进入 `clearedIds` 的条目(手动清除名单是持久化层权威,
|
|
32
|
+
* 过期快照/debounce 写入都不得把它们合并回去);
|
|
33
|
+
* 2. 压缩载荷(prompt 截断),base 里的存量胖数据也顺带清理。
|
|
34
|
+
*/
|
|
35
|
+
export declare function mergeSubEntriesForPersist(base: Iterable<SubEntry>, incoming: Iterable<SubEntry>, clearedIds: readonly string[] | undefined): Map<string, SubEntry>;
|
|
36
|
+
/**
|
|
37
|
+
* 从清除名单中筛出可安全移除的 id——它们不会再被扫描/轮询重建:
|
|
38
|
+
* - `tool:`:对应 part 已确认状态为 error(扫描从不为 error part 建条目);
|
|
39
|
+
* - `sub:`:子会话已不在权威存活列表里(轮询只重建存活子会话)。
|
|
40
|
+
* `liveChildIds` 未提供(本地库不可用)时不碰 `sub:` id。
|
|
41
|
+
*/
|
|
42
|
+
export declare function prunableClearedIds(input: {
|
|
43
|
+
clearedIds: Iterable<string>;
|
|
44
|
+
errorToolIds?: ReadonlySet<string>;
|
|
45
|
+
liveChildIds?: ReadonlySet<string>;
|
|
46
|
+
}): string[];
|
|
47
|
+
/**
|
|
48
|
+
* 从条目集合中移除 id 已清除的条目(保留原有 Map 键)。
|
|
49
|
+
* 扫描入口调用:防止 `globalEntryCache` / KV 中残留的已清除
|
|
50
|
+
* 条目在 replace=false 的合并扫描中继续存活。
|
|
51
|
+
*/
|
|
52
|
+
export declare function withoutClearedEntries(entries: ReadonlyMap<string, SubEntry>, clearedIds: ReadonlySet<string> | undefined): Map<string, SubEntry>;
|
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.7.
|
|
9
|
+
var PLUGIN_VERSION = "1.7.3";
|
|
10
10
|
|
|
11
11
|
// src/i18n.ts
|
|
12
12
|
var ZH_T = {
|
|
@@ -749,6 +749,39 @@ function mergeSubEntries(base, incoming) {
|
|
|
749
749
|
}
|
|
750
750
|
return out;
|
|
751
751
|
}
|
|
752
|
+
var PERSISTED_PROMPT_MAX = 128;
|
|
753
|
+
function compactSubEntry(entry) {
|
|
754
|
+
const prompt = entry.prompt ?? "";
|
|
755
|
+
if (prompt.length <= PERSISTED_PROMPT_MAX) return entry;
|
|
756
|
+
return { ...entry, prompt: prompt.slice(0, PERSISTED_PROMPT_MAX) };
|
|
757
|
+
}
|
|
758
|
+
function mergeSubEntriesForPersist(base, incoming, clearedIds) {
|
|
759
|
+
const cleared = new Set(clearedIds ?? []);
|
|
760
|
+
const keep = (entry) => !cleared.has(entry.id);
|
|
761
|
+
return mergeSubEntries(
|
|
762
|
+
[...base].filter(keep).map(compactSubEntry),
|
|
763
|
+
[...incoming].filter(keep).map(compactSubEntry)
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
function prunableClearedIds(input) {
|
|
767
|
+
const out = [];
|
|
768
|
+
for (const id of input.clearedIds) {
|
|
769
|
+
if (id.startsWith("tool:")) {
|
|
770
|
+
if (input.errorToolIds?.has(id)) out.push(id);
|
|
771
|
+
} else if (id.startsWith("sub:")) {
|
|
772
|
+
if (input.liveChildIds !== void 0 && !input.liveChildIds.has(id.slice(4))) out.push(id);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return out;
|
|
776
|
+
}
|
|
777
|
+
function withoutClearedEntries(entries, clearedIds) {
|
|
778
|
+
const next = new Map(entries);
|
|
779
|
+
if (!clearedIds || clearedIds.size === 0) return next;
|
|
780
|
+
for (const [key, entry] of next) {
|
|
781
|
+
if (clearedIds.has(entry.id)) next.delete(key);
|
|
782
|
+
}
|
|
783
|
+
return next;
|
|
784
|
+
}
|
|
752
785
|
|
|
753
786
|
// src/panel/SubAgentPanel.tsx
|
|
754
787
|
var LEFT_PAD = 4;
|
|
@@ -853,12 +886,12 @@ function SubAgentPanel(props) {
|
|
|
853
886
|
if (isChild) {
|
|
854
887
|
const parent = ensureRootRecord(data, parentSid);
|
|
855
888
|
const child = ensureChildRecord(data, parentSid, sid);
|
|
856
|
-
child.entries = [...
|
|
889
|
+
child.entries = [...mergeSubEntriesForPersist(child.entries ?? [], entries2.values(), child.clearedIds).values()];
|
|
857
890
|
parent.ts = Date.now();
|
|
858
891
|
} else {
|
|
859
892
|
const rec = ensureRootRecord(data, sid);
|
|
860
893
|
rec.ts = Date.now();
|
|
861
|
-
rec.entries = [...
|
|
894
|
+
rec.entries = [...mergeSubEntriesForPersist(rec.entries ?? [], entries2.values(), rec.clearedIds).values()];
|
|
862
895
|
}
|
|
863
896
|
});
|
|
864
897
|
} catch {
|
|
@@ -913,7 +946,62 @@ function SubAgentPanel(props) {
|
|
|
913
946
|
} catch {
|
|
914
947
|
}
|
|
915
948
|
};
|
|
949
|
+
const recordNeedsCompaction = (rec) => {
|
|
950
|
+
const cleared = new Set(rec.clearedIds ?? []);
|
|
951
|
+
for (const entry of rec.entries ?? []) {
|
|
952
|
+
if ((entry.prompt ?? "").length > PERSISTED_PROMPT_MAX) return true;
|
|
953
|
+
if (cleared.has(entry.id)) return true;
|
|
954
|
+
}
|
|
955
|
+
return false;
|
|
956
|
+
};
|
|
957
|
+
const compactStoredPayloads = () => {
|
|
958
|
+
try {
|
|
959
|
+
const data = loadSessionData2();
|
|
960
|
+
let needed = false;
|
|
961
|
+
for (const rec of Object.values(data)) {
|
|
962
|
+
if (recordNeedsCompaction(rec)) {
|
|
963
|
+
needed = true;
|
|
964
|
+
break;
|
|
965
|
+
}
|
|
966
|
+
for (const child of Object.values(rec.children ?? {})) {
|
|
967
|
+
if (recordNeedsCompaction(child)) {
|
|
968
|
+
needed = true;
|
|
969
|
+
break;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
if (needed) break;
|
|
973
|
+
}
|
|
974
|
+
if (!needed) return;
|
|
975
|
+
mutateSessionData((latest) => {
|
|
976
|
+
for (const rec of Object.values(latest)) {
|
|
977
|
+
rec.entries = [...mergeSubEntriesForPersist(rec.entries ?? [], [], rec.clearedIds).values()];
|
|
978
|
+
for (const child of Object.values(rec.children ?? {})) {
|
|
979
|
+
child.entries = [...mergeSubEntriesForPersist(child.entries ?? [], [], child.clearedIds).values()];
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
} catch {
|
|
984
|
+
}
|
|
985
|
+
};
|
|
916
986
|
cleanupOldSessions();
|
|
987
|
+
compactStoredPayloads();
|
|
988
|
+
const pruneClearedIds = (sid, ids) => {
|
|
989
|
+
if (ids.length === 0) return;
|
|
990
|
+
const remove = new Set(ids);
|
|
991
|
+
try {
|
|
992
|
+
mutateSessionData((data) => {
|
|
993
|
+
const {
|
|
994
|
+
parentSid,
|
|
995
|
+
isChild
|
|
996
|
+
} = resolveParent(sid);
|
|
997
|
+
const rec = isChild ? data[parentSid]?.children?.[sid] : data[parentSid];
|
|
998
|
+
if (!rec?.clearedIds?.length) return;
|
|
999
|
+
const next = rec.clearedIds.filter((id) => !remove.has(id));
|
|
1000
|
+
if (next.length !== rec.clearedIds.length) rec.clearedIds = next;
|
|
1001
|
+
});
|
|
1002
|
+
} catch {
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
917
1005
|
const [entryMap, setEntryMapRaw] = createSignal2(loadEntries(props.sessionId));
|
|
918
1006
|
const setEntryMap = (arg) => {
|
|
919
1007
|
setEntryMapRaw((prev) => {
|
|
@@ -937,12 +1025,12 @@ function SubAgentPanel(props) {
|
|
|
937
1025
|
if (isChild) {
|
|
938
1026
|
const parent = ensureRootRecord(data, parentSid);
|
|
939
1027
|
const child = ensureChildRecord(data, parentSid, props.sessionId);
|
|
940
|
-
child.entries = [...
|
|
1028
|
+
child.entries = [...mergeSubEntriesForPersist(child.entries ?? [], next.values(), child.clearedIds).values()];
|
|
941
1029
|
parent.ts = Date.now();
|
|
942
1030
|
} else {
|
|
943
1031
|
const rec = ensureRootRecord(data, props.sessionId);
|
|
944
1032
|
rec.ts = Date.now();
|
|
945
|
-
rec.entries = [...
|
|
1033
|
+
rec.entries = [...mergeSubEntriesForPersist(rec.entries ?? [], next.values(), rec.clearedIds).values()];
|
|
946
1034
|
}
|
|
947
1035
|
});
|
|
948
1036
|
} catch {
|
|
@@ -1377,7 +1465,7 @@ function SubAgentPanel(props) {
|
|
|
1377
1465
|
latest[parentSid] = {
|
|
1378
1466
|
...latestRec ?? rec,
|
|
1379
1467
|
ts: nowTs,
|
|
1380
|
-
entries: [...
|
|
1468
|
+
entries: [...mergeSubEntriesForPersist(latestRec?.entries ?? [], fallbackMap.values(), latestRec?.clearedIds).values()]
|
|
1381
1469
|
};
|
|
1382
1470
|
});
|
|
1383
1471
|
}
|
|
@@ -1395,7 +1483,7 @@ function SubAgentPanel(props) {
|
|
|
1395
1483
|
ts: nowTs
|
|
1396
1484
|
},
|
|
1397
1485
|
ts: nowTs,
|
|
1398
|
-
entries: [...
|
|
1486
|
+
entries: [...mergeSubEntriesForPersist(rec?.entries ?? [], parentCache.values(), rec?.clearedIds).values()]
|
|
1399
1487
|
};
|
|
1400
1488
|
});
|
|
1401
1489
|
}
|
|
@@ -1495,14 +1583,17 @@ function SubAgentPanel(props) {
|
|
|
1495
1583
|
} catch {
|
|
1496
1584
|
}
|
|
1497
1585
|
if (!msgs || msgs.length === 0) return false;
|
|
1586
|
+
const seenErrorIds = /* @__PURE__ */ new Set();
|
|
1587
|
+
let scanClearedIds = /* @__PURE__ */ new Set();
|
|
1498
1588
|
setEntryMapRaw((prev) => {
|
|
1499
|
-
const next = replace ? new Map(globalEntryCache.get(sid) ?? loadEntries(sid)) : new Map(prev);
|
|
1500
1589
|
const {
|
|
1501
1590
|
parentSid: scanPSid,
|
|
1502
1591
|
isChild: scanChild
|
|
1503
1592
|
} = resolveParent(sid);
|
|
1504
1593
|
const scanRec = loadSessionData2()[scanPSid];
|
|
1505
1594
|
const clearedIds = new Set(scanChild ? scanRec?.children?.[sid]?.clearedIds : scanRec?.clearedIds);
|
|
1595
|
+
scanClearedIds = clearedIds;
|
|
1596
|
+
const next = withoutClearedEntries(replace ? new Map(globalEntryCache.get(sid) ?? loadEntries(sid)) : new Map(prev), clearedIds);
|
|
1506
1597
|
try {
|
|
1507
1598
|
for (const msg of msgs) {
|
|
1508
1599
|
const parts = props.api.session.part(msg.id) ?? [];
|
|
@@ -1529,7 +1620,10 @@ function SubAgentPanel(props) {
|
|
|
1529
1620
|
}
|
|
1530
1621
|
const existingKey = findSubEntryKey(next, id, scanSubSid);
|
|
1531
1622
|
const exists = existingKey ? next.get(existingKey) : void 0;
|
|
1532
|
-
if (!exists && clearedIds.has(id))
|
|
1623
|
+
if (!exists && clearedIds.has(id)) {
|
|
1624
|
+
if (rawStatus === "error") seenErrorIds.add(id);
|
|
1625
|
+
continue;
|
|
1626
|
+
}
|
|
1533
1627
|
if ((rawStatus === "pending" || rawStatus === "") && !exists) continue;
|
|
1534
1628
|
if (rawStatus === "error") {
|
|
1535
1629
|
if (exists && exists.status === "running") {
|
|
@@ -1612,6 +1706,22 @@ function SubAgentPanel(props) {
|
|
|
1612
1706
|
if (snapshot.size > 0) {
|
|
1613
1707
|
globalEntryCache.set(sid, new Map(snapshot));
|
|
1614
1708
|
persistEntries(sid, snapshot);
|
|
1709
|
+
} else if (globalEntryCache.has(sid)) {
|
|
1710
|
+
globalEntryCache.set(sid, new Map(snapshot));
|
|
1711
|
+
}
|
|
1712
|
+
if (scanClearedIds.size > 0) {
|
|
1713
|
+
let liveChildIds;
|
|
1714
|
+
try {
|
|
1715
|
+
const children = props.api.session.listChildren?.(sid);
|
|
1716
|
+
if (children) liveChildIds = new Set(children.map((c) => c.id).filter((id) => Boolean(id)));
|
|
1717
|
+
} catch {
|
|
1718
|
+
}
|
|
1719
|
+
const prunable = prunableClearedIds({
|
|
1720
|
+
clearedIds: scanClearedIds,
|
|
1721
|
+
errorToolIds: seenErrorIds,
|
|
1722
|
+
liveChildIds
|
|
1723
|
+
});
|
|
1724
|
+
if (prunable.length > 0) pruneClearedIds(sid, prunable);
|
|
1615
1725
|
}
|
|
1616
1726
|
return true;
|
|
1617
1727
|
};
|
|
@@ -1882,6 +1992,7 @@ function SubAgentPanel(props) {
|
|
|
1882
1992
|
const tick = clearTick();
|
|
1883
1993
|
const forceReload = tick !== lastTick && !switched;
|
|
1884
1994
|
lastTick = tick;
|
|
1995
|
+
if (forceReload) clearTimeout(persistTimer);
|
|
1885
1996
|
let attempts = 0;
|
|
1886
1997
|
let retryTimer;
|
|
1887
1998
|
const run = () => {
|
|
@@ -2039,7 +2150,15 @@ function SubAgentPanel(props) {
|
|
|
2039
2150
|
const expandedPad = (label) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "));
|
|
2040
2151
|
const expandedValAvail = () => Math.max(6, panelWidth() - gutter() - INDENT - expandedMaxLabelW());
|
|
2041
2152
|
const summaryParts = createMemo(() => {
|
|
2042
|
-
if (!anyEntry())
|
|
2153
|
+
if (!anyEntry()) {
|
|
2154
|
+
return {
|
|
2155
|
+
done: "",
|
|
2156
|
+
running: null,
|
|
2157
|
+
err: null,
|
|
2158
|
+
duration: "",
|
|
2159
|
+
cost: ""
|
|
2160
|
+
};
|
|
2161
|
+
}
|
|
2043
2162
|
const dot = "\u25CF";
|
|
2044
2163
|
const cost = totalCost();
|
|
2045
2164
|
return {
|
|
@@ -2052,7 +2171,6 @@ function SubAgentPanel(props) {
|
|
|
2052
2171
|
});
|
|
2053
2172
|
const summaryCols = createMemo(() => {
|
|
2054
2173
|
const p = summaryParts();
|
|
2055
|
-
if (!p) return 0;
|
|
2056
2174
|
let w = visualWidth(p.done);
|
|
2057
2175
|
if (p.running) w += 1 + visualWidth(p.running);
|
|
2058
2176
|
if (p.err) w += 1 + visualWidth(p.err);
|
|
@@ -3380,14 +3498,16 @@ var tui = async (api) => {
|
|
|
3380
3498
|
expanded: "",
|
|
3381
3499
|
entries: []
|
|
3382
3500
|
};
|
|
3501
|
+
const child = data[parentID].children[sid];
|
|
3383
3502
|
data[parentID].children[sid] = {
|
|
3384
|
-
...
|
|
3385
|
-
entries: [...entries.values()]
|
|
3503
|
+
...child,
|
|
3504
|
+
entries: [...mergeSubEntriesForPersist(child.entries ?? [], entries.values(), child.clearedIds).values()]
|
|
3386
3505
|
};
|
|
3387
3506
|
} else {
|
|
3388
3507
|
data[sid] = {
|
|
3508
|
+
...data[sid] ?? {},
|
|
3389
3509
|
ts: Date.now(),
|
|
3390
|
-
entries: [...entries.values()],
|
|
3510
|
+
entries: [...mergeSubEntriesForPersist(data[sid]?.entries ?? [], entries.values(), data[sid]?.clearedIds).values()],
|
|
3391
3511
|
scroll: data[sid]?.scroll ?? 0,
|
|
3392
3512
|
expanded: data[sid]?.expanded ?? "",
|
|
3393
3513
|
children: data[sid]?.children ?? {}
|
|
@@ -3485,11 +3605,29 @@ var tui = async (api) => {
|
|
|
3485
3605
|
onConfirm: () => {
|
|
3486
3606
|
try {
|
|
3487
3607
|
const data = JSON.parse(String(api.kv.get(`${KV_PREFIX}.session_data`, "{}")));
|
|
3608
|
+
const cachedIds = [...globalEntryCache.get(sid)?.values() ?? []].map((e) => e.id);
|
|
3488
3609
|
let count = 0;
|
|
3489
3610
|
if (parentID) {
|
|
3490
|
-
if (data[parentID]?.children?.[sid]) {
|
|
3611
|
+
if (data[parentID]?.children?.[sid] || cachedIds.length > 0) {
|
|
3612
|
+
if (!data[parentID]) {
|
|
3613
|
+
data[parentID] = {
|
|
3614
|
+
ts: Date.now(),
|
|
3615
|
+
entries: [],
|
|
3616
|
+
scroll: 0,
|
|
3617
|
+
expanded: "",
|
|
3618
|
+
children: {}
|
|
3619
|
+
};
|
|
3620
|
+
}
|
|
3621
|
+
if (!data[parentID].children) data[parentID].children = {};
|
|
3622
|
+
if (!data[parentID].children[sid]) {
|
|
3623
|
+
data[parentID].children[sid] = {
|
|
3624
|
+
scroll: 0,
|
|
3625
|
+
expanded: "",
|
|
3626
|
+
entries: []
|
|
3627
|
+
};
|
|
3628
|
+
}
|
|
3491
3629
|
const child = data[parentID].children[sid];
|
|
3492
|
-
const ids = child.entries?.map((e) => e.id) ?? [];
|
|
3630
|
+
const ids = [.../* @__PURE__ */ new Set([...child.entries?.map((e) => e.id) ?? [], ...cachedIds])];
|
|
3493
3631
|
count = ids.length;
|
|
3494
3632
|
child.entries = [];
|
|
3495
3633
|
child.scroll = 0;
|
|
@@ -3497,9 +3635,18 @@ var tui = async (api) => {
|
|
|
3497
3635
|
child.clearedIds = [.../* @__PURE__ */ new Set([...child.clearedIds ?? [], ...ids])];
|
|
3498
3636
|
}
|
|
3499
3637
|
} else {
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3638
|
+
if (data[sid] || cachedIds.length > 0) {
|
|
3639
|
+
if (!data[sid]) {
|
|
3640
|
+
data[sid] = {
|
|
3641
|
+
ts: Date.now(),
|
|
3642
|
+
entries: [],
|
|
3643
|
+
scroll: 0,
|
|
3644
|
+
expanded: "",
|
|
3645
|
+
children: {}
|
|
3646
|
+
};
|
|
3647
|
+
}
|
|
3648
|
+
const ids = [.../* @__PURE__ */ new Set([...data[sid].entries?.map((e) => e.id) ?? [], ...cachedIds])];
|
|
3649
|
+
count = ids.length;
|
|
3503
3650
|
data[sid].entries = [];
|
|
3504
3651
|
data[sid].scroll = 0;
|
|
3505
3652
|
data[sid].expanded = "";
|
package/dist/v2.js
CHANGED
|
@@ -933,7 +933,7 @@ function safeErrorMsg(err) {
|
|
|
933
933
|
}
|
|
934
934
|
|
|
935
935
|
// src/_version.ts
|
|
936
|
-
var PLUGIN_VERSION = "1.7.
|
|
936
|
+
var PLUGIN_VERSION = "1.7.3";
|
|
937
937
|
|
|
938
938
|
// src/i18n.ts
|
|
939
939
|
var ZH_T = {
|
|
@@ -1354,6 +1354,39 @@ function mergeSubEntries(base, incoming) {
|
|
|
1354
1354
|
}
|
|
1355
1355
|
return out;
|
|
1356
1356
|
}
|
|
1357
|
+
var PERSISTED_PROMPT_MAX = 128;
|
|
1358
|
+
function compactSubEntry(entry) {
|
|
1359
|
+
const prompt = entry.prompt ?? "";
|
|
1360
|
+
if (prompt.length <= PERSISTED_PROMPT_MAX) return entry;
|
|
1361
|
+
return { ...entry, prompt: prompt.slice(0, PERSISTED_PROMPT_MAX) };
|
|
1362
|
+
}
|
|
1363
|
+
function mergeSubEntriesForPersist(base, incoming, clearedIds) {
|
|
1364
|
+
const cleared = new Set(clearedIds ?? []);
|
|
1365
|
+
const keep = (entry) => !cleared.has(entry.id);
|
|
1366
|
+
return mergeSubEntries(
|
|
1367
|
+
[...base].filter(keep).map(compactSubEntry),
|
|
1368
|
+
[...incoming].filter(keep).map(compactSubEntry)
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1371
|
+
function prunableClearedIds(input) {
|
|
1372
|
+
const out = [];
|
|
1373
|
+
for (const id of input.clearedIds) {
|
|
1374
|
+
if (id.startsWith("tool:")) {
|
|
1375
|
+
if (input.errorToolIds?.has(id)) out.push(id);
|
|
1376
|
+
} else if (id.startsWith("sub:")) {
|
|
1377
|
+
if (input.liveChildIds !== void 0 && !input.liveChildIds.has(id.slice(4))) out.push(id);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
return out;
|
|
1381
|
+
}
|
|
1382
|
+
function withoutClearedEntries(entries, clearedIds) {
|
|
1383
|
+
const next = new Map(entries);
|
|
1384
|
+
if (!clearedIds || clearedIds.size === 0) return next;
|
|
1385
|
+
for (const [key, entry] of next) {
|
|
1386
|
+
if (clearedIds.has(entry.id)) next.delete(key);
|
|
1387
|
+
}
|
|
1388
|
+
return next;
|
|
1389
|
+
}
|
|
1357
1390
|
|
|
1358
1391
|
// src/v2/settings-menu.ts
|
|
1359
1392
|
var TTL_VALUES = [3, 7, 14, 30, 0];
|
|
@@ -1841,7 +1874,7 @@ function makeCommands(context, api, signals) {
|
|
|
1841
1874
|
if (!data[parentSid]) data[parentSid] = { ts: Date.now(), entries: [], scroll: 0, expanded: "", children: {} };
|
|
1842
1875
|
if (!data[parentSid].children) data[parentSid].children = {};
|
|
1843
1876
|
const prev = data[parentSid].children[sid]?.entries ?? [];
|
|
1844
|
-
const merged = [...
|
|
1877
|
+
const merged = [...mergeSubEntriesForPersist(prev, entries.values(), data[parentSid].children[sid]?.clearedIds).values()].map(
|
|
1845
1878
|
(e) => e.status === "running" || e.status === "cancel_requested" ? { ...e, status: "done", endedAt: e.endedAt ?? Date.now() } : e
|
|
1846
1879
|
);
|
|
1847
1880
|
data[parentSid].children[sid] = {
|
|
@@ -1850,7 +1883,7 @@ function makeCommands(context, api, signals) {
|
|
|
1850
1883
|
};
|
|
1851
1884
|
} else {
|
|
1852
1885
|
const rec = data[parentSid] ?? { ts: Date.now(), entries: [], scroll: 0, expanded: "", children: {} };
|
|
1853
|
-
const merged = [...
|
|
1886
|
+
const merged = [...mergeSubEntriesForPersist(rec.entries ?? [], entries.values(), rec.clearedIds).values()].map(
|
|
1854
1887
|
(e) => e.status === "running" || e.status === "cancel_requested" ? { ...e, status: "done", endedAt: e.endedAt ?? Date.now() } : e
|
|
1855
1888
|
);
|
|
1856
1889
|
data[parentSid] = { ...rec, ts: Date.now(), entries: merged, children: rec.children ?? {} };
|
|
@@ -1919,6 +1952,7 @@ function makeCommands(context, api, signals) {
|
|
|
1919
1952
|
]
|
|
1920
1953
|
});
|
|
1921
1954
|
if (choice !== "yes") return;
|
|
1955
|
+
const cachedIds = [...globalEntryCache.get(sid)?.values() ?? []].map((e) => e.id);
|
|
1922
1956
|
try {
|
|
1923
1957
|
let count = 0;
|
|
1924
1958
|
const finish = () => {
|
|
@@ -1928,9 +1962,12 @@ function makeCommands(context, api, signals) {
|
|
|
1928
1962
|
};
|
|
1929
1963
|
const done = updateSessionData(kv, (data) => {
|
|
1930
1964
|
if (parentID) {
|
|
1931
|
-
const
|
|
1932
|
-
if (
|
|
1933
|
-
const
|
|
1965
|
+
const parent = data[parentID];
|
|
1966
|
+
if (parent?.children?.[sid] || cachedIds.length > 0) {
|
|
1967
|
+
const parentRec = parent ?? (data[parentID] = { ts: Date.now(), entries: [], scroll: 0, expanded: "", children: {} });
|
|
1968
|
+
if (!parentRec.children) parentRec.children = {};
|
|
1969
|
+
const child = parentRec.children[sid] ?? (parentRec.children[sid] = { scroll: 0, expanded: "", entries: [] });
|
|
1970
|
+
const ids = [.../* @__PURE__ */ new Set([...(child.entries ?? []).map((e) => e.id), ...cachedIds])];
|
|
1934
1971
|
count = ids.length;
|
|
1935
1972
|
child.entries = [];
|
|
1936
1973
|
child.scroll = 0;
|
|
@@ -1939,13 +1976,14 @@ function makeCommands(context, api, signals) {
|
|
|
1939
1976
|
}
|
|
1940
1977
|
} else {
|
|
1941
1978
|
const rec = data[sid];
|
|
1942
|
-
if (rec) {
|
|
1943
|
-
const
|
|
1979
|
+
if (rec || cachedIds.length > 0) {
|
|
1980
|
+
const target = rec ?? (data[sid] = { ts: Date.now(), entries: [], scroll: 0, expanded: "", children: {} });
|
|
1981
|
+
const ids = [.../* @__PURE__ */ new Set([...(target.entries ?? []).map((e) => e.id), ...cachedIds])];
|
|
1944
1982
|
count = ids.length;
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1983
|
+
target.entries = [];
|
|
1984
|
+
target.scroll = 0;
|
|
1985
|
+
target.expanded = "";
|
|
1986
|
+
target.clearedIds = [.../* @__PURE__ */ new Set([...target.clearedIds ?? [], ...ids])];
|
|
1949
1987
|
}
|
|
1950
1988
|
}
|
|
1951
1989
|
});
|
|
@@ -2286,12 +2324,12 @@ function SubAgentPanel(props) {
|
|
|
2286
2324
|
if (isChild) {
|
|
2287
2325
|
const parent = ensureRootRecord(data, parentSid);
|
|
2288
2326
|
const child = ensureChildRecord(data, parentSid, sid);
|
|
2289
|
-
child.entries = [...
|
|
2327
|
+
child.entries = [...mergeSubEntriesForPersist(child.entries ?? [], entries2.values(), child.clearedIds).values()];
|
|
2290
2328
|
parent.ts = Date.now();
|
|
2291
2329
|
} else {
|
|
2292
2330
|
const rec = ensureRootRecord(data, sid);
|
|
2293
2331
|
rec.ts = Date.now();
|
|
2294
|
-
rec.entries = [...
|
|
2332
|
+
rec.entries = [...mergeSubEntriesForPersist(rec.entries ?? [], entries2.values(), rec.clearedIds).values()];
|
|
2295
2333
|
}
|
|
2296
2334
|
});
|
|
2297
2335
|
} catch {
|
|
@@ -2346,7 +2384,62 @@ function SubAgentPanel(props) {
|
|
|
2346
2384
|
} catch {
|
|
2347
2385
|
}
|
|
2348
2386
|
};
|
|
2387
|
+
const recordNeedsCompaction = (rec) => {
|
|
2388
|
+
const cleared = new Set(rec.clearedIds ?? []);
|
|
2389
|
+
for (const entry of rec.entries ?? []) {
|
|
2390
|
+
if ((entry.prompt ?? "").length > PERSISTED_PROMPT_MAX) return true;
|
|
2391
|
+
if (cleared.has(entry.id)) return true;
|
|
2392
|
+
}
|
|
2393
|
+
return false;
|
|
2394
|
+
};
|
|
2395
|
+
const compactStoredPayloads = () => {
|
|
2396
|
+
try {
|
|
2397
|
+
const data = loadSessionData2();
|
|
2398
|
+
let needed = false;
|
|
2399
|
+
for (const rec of Object.values(data)) {
|
|
2400
|
+
if (recordNeedsCompaction(rec)) {
|
|
2401
|
+
needed = true;
|
|
2402
|
+
break;
|
|
2403
|
+
}
|
|
2404
|
+
for (const child of Object.values(rec.children ?? {})) {
|
|
2405
|
+
if (recordNeedsCompaction(child)) {
|
|
2406
|
+
needed = true;
|
|
2407
|
+
break;
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
if (needed) break;
|
|
2411
|
+
}
|
|
2412
|
+
if (!needed) return;
|
|
2413
|
+
mutateSessionData((latest) => {
|
|
2414
|
+
for (const rec of Object.values(latest)) {
|
|
2415
|
+
rec.entries = [...mergeSubEntriesForPersist(rec.entries ?? [], [], rec.clearedIds).values()];
|
|
2416
|
+
for (const child of Object.values(rec.children ?? {})) {
|
|
2417
|
+
child.entries = [...mergeSubEntriesForPersist(child.entries ?? [], [], child.clearedIds).values()];
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
});
|
|
2421
|
+
} catch {
|
|
2422
|
+
}
|
|
2423
|
+
};
|
|
2349
2424
|
cleanupOldSessions();
|
|
2425
|
+
compactStoredPayloads();
|
|
2426
|
+
const pruneClearedIds = (sid, ids) => {
|
|
2427
|
+
if (ids.length === 0) return;
|
|
2428
|
+
const remove = new Set(ids);
|
|
2429
|
+
try {
|
|
2430
|
+
mutateSessionData((data) => {
|
|
2431
|
+
const {
|
|
2432
|
+
parentSid,
|
|
2433
|
+
isChild
|
|
2434
|
+
} = resolveParent(sid);
|
|
2435
|
+
const rec = isChild ? data[parentSid]?.children?.[sid] : data[parentSid];
|
|
2436
|
+
if (!rec?.clearedIds?.length) return;
|
|
2437
|
+
const next = rec.clearedIds.filter((id) => !remove.has(id));
|
|
2438
|
+
if (next.length !== rec.clearedIds.length) rec.clearedIds = next;
|
|
2439
|
+
});
|
|
2440
|
+
} catch {
|
|
2441
|
+
}
|
|
2442
|
+
};
|
|
2350
2443
|
const [entryMap, setEntryMapRaw] = createSignal2(loadEntries(props.sessionId));
|
|
2351
2444
|
const setEntryMap = (arg) => {
|
|
2352
2445
|
setEntryMapRaw((prev) => {
|
|
@@ -2370,12 +2463,12 @@ function SubAgentPanel(props) {
|
|
|
2370
2463
|
if (isChild) {
|
|
2371
2464
|
const parent = ensureRootRecord(data, parentSid);
|
|
2372
2465
|
const child = ensureChildRecord(data, parentSid, props.sessionId);
|
|
2373
|
-
child.entries = [...
|
|
2466
|
+
child.entries = [...mergeSubEntriesForPersist(child.entries ?? [], next.values(), child.clearedIds).values()];
|
|
2374
2467
|
parent.ts = Date.now();
|
|
2375
2468
|
} else {
|
|
2376
2469
|
const rec = ensureRootRecord(data, props.sessionId);
|
|
2377
2470
|
rec.ts = Date.now();
|
|
2378
|
-
rec.entries = [...
|
|
2471
|
+
rec.entries = [...mergeSubEntriesForPersist(rec.entries ?? [], next.values(), rec.clearedIds).values()];
|
|
2379
2472
|
}
|
|
2380
2473
|
});
|
|
2381
2474
|
} catch {
|
|
@@ -2810,7 +2903,7 @@ function SubAgentPanel(props) {
|
|
|
2810
2903
|
latest[parentSid] = {
|
|
2811
2904
|
...latestRec ?? rec,
|
|
2812
2905
|
ts: nowTs,
|
|
2813
|
-
entries: [...
|
|
2906
|
+
entries: [...mergeSubEntriesForPersist(latestRec?.entries ?? [], fallbackMap.values(), latestRec?.clearedIds).values()]
|
|
2814
2907
|
};
|
|
2815
2908
|
});
|
|
2816
2909
|
}
|
|
@@ -2828,7 +2921,7 @@ function SubAgentPanel(props) {
|
|
|
2828
2921
|
ts: nowTs
|
|
2829
2922
|
},
|
|
2830
2923
|
ts: nowTs,
|
|
2831
|
-
entries: [...
|
|
2924
|
+
entries: [...mergeSubEntriesForPersist(rec?.entries ?? [], parentCache.values(), rec?.clearedIds).values()]
|
|
2832
2925
|
};
|
|
2833
2926
|
});
|
|
2834
2927
|
}
|
|
@@ -2928,14 +3021,17 @@ function SubAgentPanel(props) {
|
|
|
2928
3021
|
} catch {
|
|
2929
3022
|
}
|
|
2930
3023
|
if (!msgs || msgs.length === 0) return false;
|
|
3024
|
+
const seenErrorIds = /* @__PURE__ */ new Set();
|
|
3025
|
+
let scanClearedIds = /* @__PURE__ */ new Set();
|
|
2931
3026
|
setEntryMapRaw((prev) => {
|
|
2932
|
-
const next = replace ? new Map(globalEntryCache.get(sid) ?? loadEntries(sid)) : new Map(prev);
|
|
2933
3027
|
const {
|
|
2934
3028
|
parentSid: scanPSid,
|
|
2935
3029
|
isChild: scanChild
|
|
2936
3030
|
} = resolveParent(sid);
|
|
2937
3031
|
const scanRec = loadSessionData2()[scanPSid];
|
|
2938
3032
|
const clearedIds = new Set(scanChild ? scanRec?.children?.[sid]?.clearedIds : scanRec?.clearedIds);
|
|
3033
|
+
scanClearedIds = clearedIds;
|
|
3034
|
+
const next = withoutClearedEntries(replace ? new Map(globalEntryCache.get(sid) ?? loadEntries(sid)) : new Map(prev), clearedIds);
|
|
2939
3035
|
try {
|
|
2940
3036
|
for (const msg of msgs) {
|
|
2941
3037
|
const parts = props.api.session.part(msg.id) ?? [];
|
|
@@ -2962,7 +3058,10 @@ function SubAgentPanel(props) {
|
|
|
2962
3058
|
}
|
|
2963
3059
|
const existingKey = findSubEntryKey(next, id, scanSubSid);
|
|
2964
3060
|
const exists = existingKey ? next.get(existingKey) : void 0;
|
|
2965
|
-
if (!exists && clearedIds.has(id))
|
|
3061
|
+
if (!exists && clearedIds.has(id)) {
|
|
3062
|
+
if (rawStatus === "error") seenErrorIds.add(id);
|
|
3063
|
+
continue;
|
|
3064
|
+
}
|
|
2966
3065
|
if ((rawStatus === "pending" || rawStatus === "") && !exists) continue;
|
|
2967
3066
|
if (rawStatus === "error") {
|
|
2968
3067
|
if (exists && exists.status === "running") {
|
|
@@ -3045,6 +3144,22 @@ function SubAgentPanel(props) {
|
|
|
3045
3144
|
if (snapshot.size > 0) {
|
|
3046
3145
|
globalEntryCache.set(sid, new Map(snapshot));
|
|
3047
3146
|
persistEntries(sid, snapshot);
|
|
3147
|
+
} else if (globalEntryCache.has(sid)) {
|
|
3148
|
+
globalEntryCache.set(sid, new Map(snapshot));
|
|
3149
|
+
}
|
|
3150
|
+
if (scanClearedIds.size > 0) {
|
|
3151
|
+
let liveChildIds;
|
|
3152
|
+
try {
|
|
3153
|
+
const children = props.api.session.listChildren?.(sid);
|
|
3154
|
+
if (children) liveChildIds = new Set(children.map((c) => c.id).filter((id) => Boolean(id)));
|
|
3155
|
+
} catch {
|
|
3156
|
+
}
|
|
3157
|
+
const prunable = prunableClearedIds({
|
|
3158
|
+
clearedIds: scanClearedIds,
|
|
3159
|
+
errorToolIds: seenErrorIds,
|
|
3160
|
+
liveChildIds
|
|
3161
|
+
});
|
|
3162
|
+
if (prunable.length > 0) pruneClearedIds(sid, prunable);
|
|
3048
3163
|
}
|
|
3049
3164
|
return true;
|
|
3050
3165
|
};
|
|
@@ -3315,6 +3430,7 @@ function SubAgentPanel(props) {
|
|
|
3315
3430
|
const tick = clearTick();
|
|
3316
3431
|
const forceReload = tick !== lastTick && !switched;
|
|
3317
3432
|
lastTick = tick;
|
|
3433
|
+
if (forceReload) clearTimeout(persistTimer);
|
|
3318
3434
|
let attempts = 0;
|
|
3319
3435
|
let retryTimer;
|
|
3320
3436
|
const run = () => {
|
|
@@ -3472,7 +3588,15 @@ function SubAgentPanel(props) {
|
|
|
3472
3588
|
const expandedPad = (label) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "));
|
|
3473
3589
|
const expandedValAvail = () => Math.max(6, panelWidth() - gutter() - INDENT - expandedMaxLabelW());
|
|
3474
3590
|
const summaryParts = createMemo(() => {
|
|
3475
|
-
if (!anyEntry())
|
|
3591
|
+
if (!anyEntry()) {
|
|
3592
|
+
return {
|
|
3593
|
+
done: "",
|
|
3594
|
+
running: null,
|
|
3595
|
+
err: null,
|
|
3596
|
+
duration: "",
|
|
3597
|
+
cost: ""
|
|
3598
|
+
};
|
|
3599
|
+
}
|
|
3476
3600
|
const dot = "\u25CF";
|
|
3477
3601
|
const cost = totalCost();
|
|
3478
3602
|
return {
|
|
@@ -3485,7 +3609,6 @@ function SubAgentPanel(props) {
|
|
|
3485
3609
|
});
|
|
3486
3610
|
const summaryCols = createMemo(() => {
|
|
3487
3611
|
const p = summaryParts();
|
|
3488
|
-
if (!p) return 0;
|
|
3489
3612
|
let w = visualWidth(p.done);
|
|
3490
3613
|
if (p.running) w += 1 + visualWidth(p.running);
|
|
3491
3614
|
if (p.err) w += 1 + visualWidth(p.err);
|