@michengai/dsh-codex-ui 0.2.72 → 0.2.73
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/client.js +194 -53
- package/dist/index.mjs +127 -44
- package/package.json +3 -2
package/dist/client.js
CHANGED
|
@@ -18,6 +18,7 @@ window.__ModuleLoader__.load({
|
|
|
18
18
|
if (match !== void 0) return match;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
let cancelPendingNavigation;
|
|
21
22
|
function openSettingsSection(root, label, onMissing) {
|
|
22
23
|
const labels = typeof label === "string" ? [label] : label;
|
|
23
24
|
const trigger = root?.querySelector("[aria-haspopup=\"dialog\"]");
|
|
@@ -25,18 +26,48 @@ window.__ModuleLoader__.load({
|
|
|
25
26
|
onMissing?.();
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
const opening = cancelPendingNavigation !== void 0;
|
|
30
|
+
cancelPendingNavigation?.();
|
|
31
|
+
if (!opening && document.querySelector("[role=\"dialog\"]") === null) trigger.click();
|
|
32
|
+
let frame;
|
|
33
|
+
let finished = false;
|
|
34
|
+
const observer = new MutationObserver(() => {
|
|
35
|
+
schedule();
|
|
36
|
+
});
|
|
37
|
+
const cleanup = () => {
|
|
38
|
+
if (finished) return;
|
|
39
|
+
finished = true;
|
|
40
|
+
observer.disconnect();
|
|
41
|
+
window.clearTimeout(timeout);
|
|
42
|
+
if (frame !== void 0) window.cancelAnimationFrame(frame);
|
|
43
|
+
if (cancelPendingNavigation === cleanup) cancelPendingNavigation = void 0;
|
|
44
|
+
};
|
|
45
|
+
const select = () => {
|
|
46
|
+
const target = pickSettingsSectionButton([...document.querySelectorAll("[role=\"dialog\"] nav button")], labels);
|
|
47
|
+
if (target === void 0) return false;
|
|
48
|
+
cleanup();
|
|
49
|
+
target.click();
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
52
|
+
const schedule = () => {
|
|
53
|
+
if (finished || frame !== void 0) return;
|
|
54
|
+
frame = window.requestAnimationFrame(() => {
|
|
55
|
+
frame = void 0;
|
|
56
|
+
select();
|
|
38
57
|
});
|
|
58
|
+
};
|
|
59
|
+
const timeout = window.setTimeout(() => {
|
|
60
|
+
if (select()) return;
|
|
61
|
+
cleanup();
|
|
62
|
+
console.warn(`[michengai-codex-ui] 未找到设置分区:${labels.join(" / ")}`);
|
|
63
|
+
onMissing?.();
|
|
64
|
+
}, 1500);
|
|
65
|
+
observer.observe(document.body, {
|
|
66
|
+
childList: true,
|
|
67
|
+
subtree: true
|
|
39
68
|
});
|
|
69
|
+
cancelPendingNavigation = cleanup;
|
|
70
|
+
schedule();
|
|
40
71
|
}
|
|
41
72
|
//#endregion
|
|
42
73
|
//#region src/client/sidebar-search.ts
|
|
@@ -52,6 +83,7 @@ window.__ModuleLoader__.load({
|
|
|
52
83
|
channels: false,
|
|
53
84
|
schedule: false
|
|
54
85
|
};
|
|
86
|
+
const reportedSlotErrors = /* @__PURE__ */ new WeakSet();
|
|
55
87
|
/** 插槽声明本身不算占用;只有其他插件 register 后才视为已安装。 */
|
|
56
88
|
function readSlotEntries(slots, name) {
|
|
57
89
|
if (slots === void 0) return [];
|
|
@@ -59,7 +91,11 @@ window.__ModuleLoader__.load({
|
|
|
59
91
|
if (typeof read !== "function") return [];
|
|
60
92
|
try {
|
|
61
93
|
return read.call(slots, name) ?? [];
|
|
62
|
-
} catch {
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (!reportedSlotErrors.has(slots)) {
|
|
96
|
+
reportedSlotErrors.add(slots);
|
|
97
|
+
console.warn("[michengai-codex-ui] 无法读取配套插件插槽。", error);
|
|
98
|
+
}
|
|
63
99
|
return [];
|
|
64
100
|
}
|
|
65
101
|
}
|
|
@@ -251,11 +287,19 @@ window.__ModuleLoader__.load({
|
|
|
251
287
|
});
|
|
252
288
|
}
|
|
253
289
|
/** 读取 IM 频道分组;失败时交给界面显示空态或错误。 */
|
|
254
|
-
async function loadChannelGroups() {
|
|
255
|
-
const response = await fetch(CHANNELS_ENDPOINT, {
|
|
256
|
-
|
|
257
|
-
|
|
290
|
+
async function loadChannelGroups(signal) {
|
|
291
|
+
const response = await fetch(CHANNELS_ENDPOINT, {
|
|
292
|
+
cache: "no-store",
|
|
293
|
+
signal
|
|
294
|
+
});
|
|
295
|
+
let payload;
|
|
296
|
+
try {
|
|
297
|
+
payload = await response.json();
|
|
298
|
+
} catch {
|
|
299
|
+
throw new Error(response.ok ? "频道会话数据格式无效" : "无法读取频道会话");
|
|
300
|
+
}
|
|
258
301
|
const root = payload !== null && typeof payload === "object" ? payload : {};
|
|
302
|
+
if (!response.ok) throw new Error(text(root.error, "无法读取频道会话"));
|
|
259
303
|
if (root.ok === false) throw new Error(text(root.error, "无法读取频道会话"));
|
|
260
304
|
return parseChannelGroups(payload);
|
|
261
305
|
}
|
|
@@ -679,7 +723,6 @@ window.__ModuleLoader__.load({
|
|
|
679
723
|
card.append(sub);
|
|
680
724
|
}
|
|
681
725
|
card.dataset.dcuUserText = text;
|
|
682
|
-
card.title = text;
|
|
683
726
|
}
|
|
684
727
|
}
|
|
685
728
|
function ensureUserBubbleStyle(doc) {
|
|
@@ -790,19 +833,25 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
790
833
|
slider.style.transform = `translateX(${Math.max(0, tabBox.left - listBox.left)}px)`;
|
|
791
834
|
}
|
|
792
835
|
function watchTabSelection(tabs) {
|
|
793
|
-
if (tabs.dataset.dcuTabWatch === "") return;
|
|
794
836
|
tabs.dataset.dcuTabWatch = "";
|
|
795
837
|
const sync = () => {
|
|
796
838
|
syncTabSlider(tabs);
|
|
797
839
|
};
|
|
798
|
-
|
|
840
|
+
const onClick = () => {
|
|
841
|
+
window.requestAnimationFrame(sync);
|
|
842
|
+
};
|
|
843
|
+
const observer = new MutationObserver(sync);
|
|
844
|
+
observer.observe(tabs, {
|
|
799
845
|
attributes: true,
|
|
800
846
|
subtree: true,
|
|
801
847
|
attributeFilter: ["aria-selected", "data-state"]
|
|
802
848
|
});
|
|
803
|
-
tabs.addEventListener("click",
|
|
804
|
-
|
|
805
|
-
|
|
849
|
+
tabs.addEventListener("click", onClick);
|
|
850
|
+
return () => {
|
|
851
|
+
observer.disconnect();
|
|
852
|
+
tabs.removeEventListener("click", onClick);
|
|
853
|
+
delete tabs.dataset.dcuTabWatch;
|
|
854
|
+
};
|
|
806
855
|
}
|
|
807
856
|
function ensureStyle(doc) {
|
|
808
857
|
if (doc.getElementById("dcu-conversation-header-style") !== null) return;
|
|
@@ -818,6 +867,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
818
867
|
ensureUserBubbleStyle(doc);
|
|
819
868
|
let applying = false;
|
|
820
869
|
let frame;
|
|
870
|
+
let watchedTabs;
|
|
871
|
+
let stopWatchingTabs;
|
|
821
872
|
const run = () => {
|
|
822
873
|
frame = void 0;
|
|
823
874
|
if (applying) return;
|
|
@@ -825,7 +876,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
825
876
|
try {
|
|
826
877
|
placeConversationTabs(doc);
|
|
827
878
|
const tabs = findConversationTablist(doc);
|
|
828
|
-
if (tabs !==
|
|
879
|
+
if (tabs !== watchedTabs) {
|
|
880
|
+
stopWatchingTabs?.();
|
|
881
|
+
watchedTabs = tabs;
|
|
882
|
+
stopWatchingTabs = tabs === void 0 ? void 0 : watchTabSelection(tabs);
|
|
883
|
+
}
|
|
829
884
|
syncTabSlider(doc);
|
|
830
885
|
decorateConversationTitle(doc);
|
|
831
886
|
decorateUserBubbles(doc);
|
|
@@ -845,6 +900,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
845
900
|
});
|
|
846
901
|
return () => {
|
|
847
902
|
observer.disconnect();
|
|
903
|
+
stopWatchingTabs?.();
|
|
848
904
|
if (frame !== void 0) window.cancelAnimationFrame(frame);
|
|
849
905
|
};
|
|
850
906
|
}
|
|
@@ -903,6 +959,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
903
959
|
window.clearTimeout(showTipTimer.current);
|
|
904
960
|
showTipTimer.current = void 0;
|
|
905
961
|
}
|
|
962
|
+
if (hideTipTimer.current !== void 0) window.clearTimeout(hideTipTimer.current);
|
|
906
963
|
hideTipTimer.current = window.setTimeout(() => {
|
|
907
964
|
setHoverTip(void 0);
|
|
908
965
|
}, 120);
|
|
@@ -1229,6 +1286,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1229
1286
|
};
|
|
1230
1287
|
const [renameDraft, setRenameDraft] = (0, react.useState)("");
|
|
1231
1288
|
const [busy, setBusy] = (0, react.useState)();
|
|
1289
|
+
const busyRef = (0, react.useRef)();
|
|
1232
1290
|
const [error, setError] = (0, react.useState)();
|
|
1233
1291
|
const [workspaceDragId, setWorkspaceDragId] = (0, react.useState)();
|
|
1234
1292
|
const [workspaceDropId, setWorkspaceDropId] = (0, react.useState)();
|
|
@@ -1339,6 +1397,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1339
1397
|
const assignedIds = workspaces.items.flatMap((workspace) => workspace.sessionIds.map((id) => String(id)));
|
|
1340
1398
|
const recentIds = ungroupedSessionIds(sessions.ids ?? Object.keys(sessions.byId), sessions.byId, assignedIds, workspaces.archivedSessionIds).sort((left, right) => (sessions.byId[right]?.updatedAt ?? 0) - (sessions.byId[left]?.updatedAt ?? 0));
|
|
1341
1399
|
const run = async (key, action) => {
|
|
1400
|
+
if (busyRef.current !== void 0) return;
|
|
1401
|
+
busyRef.current = key;
|
|
1342
1402
|
setBusy(key);
|
|
1343
1403
|
setError(void 0);
|
|
1344
1404
|
try {
|
|
@@ -1347,6 +1407,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1347
1407
|
} catch (reason) {
|
|
1348
1408
|
setError(reason instanceof Error ? reason.message : String(reason));
|
|
1349
1409
|
} finally {
|
|
1410
|
+
busyRef.current = void 0;
|
|
1350
1411
|
setBusy(void 0);
|
|
1351
1412
|
}
|
|
1352
1413
|
};
|
|
@@ -2330,7 +2391,10 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2330
2391
|
function useBusyAction(onSuccess) {
|
|
2331
2392
|
const [busy, setBusy] = (0, react.useState)();
|
|
2332
2393
|
const [error, setError] = (0, react.useState)();
|
|
2394
|
+
const busyRef = (0, react.useRef)();
|
|
2333
2395
|
const run = async (key, action) => {
|
|
2396
|
+
if (busyRef.current !== void 0) return;
|
|
2397
|
+
busyRef.current = key;
|
|
2334
2398
|
setBusy(key);
|
|
2335
2399
|
setError(void 0);
|
|
2336
2400
|
try {
|
|
@@ -2339,6 +2403,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2339
2403
|
} catch (reason) {
|
|
2340
2404
|
setError(reason instanceof Error ? reason.message : String(reason));
|
|
2341
2405
|
} finally {
|
|
2406
|
+
busyRef.current = void 0;
|
|
2342
2407
|
setBusy(void 0);
|
|
2343
2408
|
}
|
|
2344
2409
|
};
|
|
@@ -2557,11 +2622,15 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2557
2622
|
});
|
|
2558
2623
|
(0, react.useEffect)(() => {
|
|
2559
2624
|
let disposed = false;
|
|
2560
|
-
let
|
|
2625
|
+
let active;
|
|
2561
2626
|
const load = () => {
|
|
2562
|
-
if (
|
|
2563
|
-
|
|
2564
|
-
|
|
2627
|
+
if (active !== void 0 || document.visibilityState === "hidden") return;
|
|
2628
|
+
const controller = new AbortController();
|
|
2629
|
+
active = controller;
|
|
2630
|
+
const timeout = window.setTimeout(() => {
|
|
2631
|
+
controller.abort();
|
|
2632
|
+
}, 8e3);
|
|
2633
|
+
loadChannelGroups(controller.signal).then((next) => {
|
|
2565
2634
|
if (!disposed) {
|
|
2566
2635
|
setGroups(next);
|
|
2567
2636
|
setPollError(void 0);
|
|
@@ -2569,16 +2638,23 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2569
2638
|
}).catch(() => {
|
|
2570
2639
|
if (!disposed) setPollError(t("channels.loadError"));
|
|
2571
2640
|
}).finally(() => {
|
|
2572
|
-
|
|
2641
|
+
window.clearTimeout(timeout);
|
|
2642
|
+
if (active === controller) active = void 0;
|
|
2573
2643
|
});
|
|
2574
2644
|
};
|
|
2575
2645
|
load();
|
|
2576
2646
|
const timer = window.setInterval(load, 4e3);
|
|
2647
|
+
const onVisibilityChange = () => {
|
|
2648
|
+
if (document.visibilityState === "visible") load();
|
|
2649
|
+
};
|
|
2650
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
2577
2651
|
return () => {
|
|
2578
2652
|
disposed = true;
|
|
2653
|
+
active?.abort();
|
|
2579
2654
|
window.clearInterval(timer);
|
|
2655
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
2580
2656
|
};
|
|
2581
|
-
}, []);
|
|
2657
|
+
}, [t]);
|
|
2582
2658
|
const banner = pollError ?? error;
|
|
2583
2659
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2584
2660
|
className: "dcu-wb",
|
|
@@ -2875,6 +2951,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2875
2951
|
}
|
|
2876
2952
|
//#endregion
|
|
2877
2953
|
//#region src/client/CodexSidebar.tsx
|
|
2954
|
+
const subscribeEmptyCompanionTabs = () => () => {};
|
|
2955
|
+
const getEmptyCompanionTabs = () => EMPTY_COMPANION_TABS;
|
|
2878
2956
|
const stylesheet$3 = `
|
|
2879
2957
|
.dcu-root{--dcu-font:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI","Microsoft YaHei UI",sans-serif;--dcu-sidebar-primary:#393d3e;--dcu-sidebar-secondary:#676b6c;--dcu-sidebar-tertiary:#9a9f9f;--dcu-sidebar-navigation:#4e5253;--dcu-sidebar-icon:#4e5253;--dcu-sidebar-hover:#dfe8e5;--dcu-sidebar-border:rgba(37,46,41,.10);--dcu-tip-bg:#ffffff;--dcu-tip-shadow:0 10px 32px rgba(31,39,36,.22);height:100%;min-width:0;box-sizing:border-box;display:flex;flex-direction:column;background:#eef7f5;color:var(--dcu-sidebar-primary);font:14px/20px var(--dcu-font)}body[data-ds-dark-theme] .dcu-root{background:#1d2120;--dcu-sidebar-primary:#b9bab9;--dcu-sidebar-secondary:#909191;--dcu-sidebar-tertiary:#666867;--dcu-sidebar-navigation:#b9bab9;--dcu-sidebar-icon:#afafaf;--dcu-sidebar-hover:#303432;--dcu-sidebar-border:rgba(255,255,255,.08);--dcu-tip-bg:#2a2e2c;--dcu-tip-shadow:0 10px 30px rgba(0,0,0,.28)}
|
|
2880
2958
|
.dcu-root *{box-sizing:border-box}.dcu-head{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:8px;height:60px;padding:8px 8px 8px 12px}.dcu-brand{border:0;background:transparent;color:inherit;padding:0;display:flex;align-items:center;min-width:0;overflow:hidden}.dcu-brand svg{display:block;width:auto;max-width:100%;height:24px;min-width:0}.dcu-head-actions{display:grid;grid-auto-flow:column;grid-auto-columns:28px;align-items:center;column-gap:8px;height:28px}
|
|
@@ -2932,7 +3010,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2932
3010
|
const [searchQuery, setSearchQuery] = (0, react.useState)("");
|
|
2933
3011
|
const [activeSearchIndex, setActiveSearchIndex] = (0, react.useState)(0);
|
|
2934
3012
|
const [imTab, setImTab] = (0, react.useState)("tasks");
|
|
2935
|
-
const companionTabs = (0, react.useSyncExternalStore)(companionSlots?.subscribe ??
|
|
3013
|
+
const companionTabs = (0, react.useSyncExternalStore)(companionSlots?.subscribe ?? subscribeEmptyCompanionTabs, companionSlots?.getSnapshot ?? getEmptyCompanionTabs, companionSlots?.getSnapshot ?? getEmptyCompanionTabs);
|
|
2936
3014
|
const showChannels = companionTabs.channels;
|
|
2937
3015
|
const showSchedule = companionTabs.schedule;
|
|
2938
3016
|
const showCompanionTabs = showChannels || showSchedule;
|
|
@@ -3126,14 +3204,17 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3126
3204
|
(0, react.useEffect)(() => {
|
|
3127
3205
|
let startX = 0;
|
|
3128
3206
|
let dragging = false;
|
|
3207
|
+
let pointerId;
|
|
3129
3208
|
const onDown = (event) => {
|
|
3130
|
-
if (!isSidebarDragHandle(event.target)) return;
|
|
3209
|
+
if (dragging || !isSidebarDragHandle(event.target)) return;
|
|
3131
3210
|
dragging = true;
|
|
3211
|
+
pointerId = event.pointerId;
|
|
3132
3212
|
startX = event.clientX;
|
|
3133
3213
|
};
|
|
3134
3214
|
const onUp = (event) => {
|
|
3135
|
-
if (!dragging) return;
|
|
3215
|
+
if (!dragging || event.pointerId !== pointerId) return;
|
|
3136
3216
|
dragging = false;
|
|
3217
|
+
pointerId = void 0;
|
|
3137
3218
|
if (!shouldCollapseOnSidebarDrag(startX, event.clientX)) return;
|
|
3138
3219
|
window.requestAnimationFrame(() => {
|
|
3139
3220
|
window.requestAnimationFrame(() => {
|
|
@@ -3141,11 +3222,18 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3141
3222
|
});
|
|
3142
3223
|
});
|
|
3143
3224
|
};
|
|
3225
|
+
const onCancel = (event) => {
|
|
3226
|
+
if (event.pointerId !== pointerId) return;
|
|
3227
|
+
dragging = false;
|
|
3228
|
+
pointerId = void 0;
|
|
3229
|
+
};
|
|
3144
3230
|
window.addEventListener("pointerdown", onDown, true);
|
|
3145
3231
|
window.addEventListener("pointerup", onUp, true);
|
|
3232
|
+
window.addEventListener("pointercancel", onCancel, true);
|
|
3146
3233
|
return () => {
|
|
3147
3234
|
window.removeEventListener("pointerdown", onDown, true);
|
|
3148
3235
|
window.removeEventListener("pointerup", onUp, true);
|
|
3236
|
+
window.removeEventListener("pointercancel", onCancel, true);
|
|
3149
3237
|
};
|
|
3150
3238
|
}, [toggleSidebar]);
|
|
3151
3239
|
if (collapsed || width < 80) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
|
|
@@ -3607,9 +3695,13 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3607
3695
|
const root = (0, react.useRef)(null);
|
|
3608
3696
|
const stateRef = (0, react.useRef)("loading");
|
|
3609
3697
|
const requestId = (0, react.useRef)(0);
|
|
3698
|
+
const installingRef = (0, react.useRef)();
|
|
3610
3699
|
stateRef.current = state;
|
|
3611
|
-
(0, react.useEffect)(() =>
|
|
3612
|
-
alive.current =
|
|
3700
|
+
(0, react.useEffect)(() => {
|
|
3701
|
+
alive.current = true;
|
|
3702
|
+
return () => {
|
|
3703
|
+
alive.current = false;
|
|
3704
|
+
};
|
|
3613
3705
|
}, []);
|
|
3614
3706
|
const load = (0, react.useCallback)(async (signal) => {
|
|
3615
3707
|
const currentRequest = ++requestId.current;
|
|
@@ -3639,8 +3731,17 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3639
3731
|
if (node === null || typeof IntersectionObserver === "undefined") return () => {
|
|
3640
3732
|
controller.abort();
|
|
3641
3733
|
};
|
|
3734
|
+
let initialized = false;
|
|
3735
|
+
let wasVisible = false;
|
|
3642
3736
|
const observer = new IntersectionObserver((entries) => {
|
|
3643
|
-
|
|
3737
|
+
const visible = entries.some((entry) => entry.isIntersecting);
|
|
3738
|
+
if (!initialized) {
|
|
3739
|
+
initialized = true;
|
|
3740
|
+
wasVisible = visible;
|
|
3741
|
+
return;
|
|
3742
|
+
}
|
|
3743
|
+
if (visible && !wasVisible) refresh();
|
|
3744
|
+
wasVisible = visible;
|
|
3644
3745
|
}, { threshold: .2 });
|
|
3645
3746
|
observer.observe(node);
|
|
3646
3747
|
return () => {
|
|
@@ -3649,6 +3750,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3649
3750
|
};
|
|
3650
3751
|
}, [load]);
|
|
3651
3752
|
const install = async (id) => {
|
|
3753
|
+
if (installingRef.current !== void 0) return;
|
|
3754
|
+
installingRef.current = id;
|
|
3652
3755
|
setInstalling(id);
|
|
3653
3756
|
setMessage(void 0);
|
|
3654
3757
|
try {
|
|
@@ -3669,6 +3772,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3669
3772
|
text: error instanceof Error ? error.message : t("about.installFailed")
|
|
3670
3773
|
});
|
|
3671
3774
|
} finally {
|
|
3775
|
+
installingRef.current = void 0;
|
|
3672
3776
|
if (alive.current) setInstalling(void 0);
|
|
3673
3777
|
}
|
|
3674
3778
|
};
|
|
@@ -3736,7 +3840,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3736
3840
|
(!dependency.installed || dependency.updateAvailable) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3737
3841
|
className: "dcu-about-install",
|
|
3738
3842
|
type: "button",
|
|
3739
|
-
disabled: installing
|
|
3843
|
+
disabled: installing !== void 0,
|
|
3740
3844
|
onClick: () => {
|
|
3741
3845
|
install(dependency.id);
|
|
3742
3846
|
},
|
|
@@ -4190,11 +4294,27 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4190
4294
|
let applying = false;
|
|
4191
4295
|
let frame;
|
|
4192
4296
|
let pending;
|
|
4297
|
+
let frameObserver;
|
|
4298
|
+
const watchFrame = (next) => {
|
|
4299
|
+
if (frame === next) return;
|
|
4300
|
+
frameObserver?.disconnect();
|
|
4301
|
+
frame = next;
|
|
4302
|
+
if (frame === void 0) return;
|
|
4303
|
+
frameObserver = new MutationObserver(schedule);
|
|
4304
|
+
frameObserver.observe(frame, {
|
|
4305
|
+
attributes: true,
|
|
4306
|
+
attributeFilter: [
|
|
4307
|
+
"style",
|
|
4308
|
+
"data-sidebar-collapsed",
|
|
4309
|
+
"data-dragging"
|
|
4310
|
+
]
|
|
4311
|
+
});
|
|
4312
|
+
};
|
|
4193
4313
|
const apply = () => {
|
|
4194
4314
|
if (applying) return;
|
|
4195
4315
|
applying = true;
|
|
4196
4316
|
try {
|
|
4197
|
-
if (frame === void 0 || !frame.isConnected)
|
|
4317
|
+
if (frame === void 0 || !frame.isConnected) watchFrame(findSidebarFrame(document));
|
|
4198
4318
|
if (frame !== void 0) applySlimSidebar(frame);
|
|
4199
4319
|
} finally {
|
|
4200
4320
|
applying = false;
|
|
@@ -4208,19 +4328,16 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4208
4328
|
});
|
|
4209
4329
|
};
|
|
4210
4330
|
apply();
|
|
4211
|
-
const observer = new MutationObserver(
|
|
4331
|
+
const observer = new MutationObserver(() => {
|
|
4332
|
+
if (frame === void 0 || !frame.isConnected) schedule();
|
|
4333
|
+
});
|
|
4212
4334
|
observer.observe(document.body, {
|
|
4213
|
-
attributes: true,
|
|
4214
|
-
attributeFilter: [
|
|
4215
|
-
"style",
|
|
4216
|
-
"data-sidebar-collapsed",
|
|
4217
|
-
"data-dragging"
|
|
4218
|
-
],
|
|
4219
4335
|
childList: true,
|
|
4220
4336
|
subtree: true
|
|
4221
4337
|
});
|
|
4222
4338
|
return () => {
|
|
4223
4339
|
observer.disconnect();
|
|
4340
|
+
frameObserver?.disconnect();
|
|
4224
4341
|
if (pending !== void 0) window.cancelAnimationFrame(pending);
|
|
4225
4342
|
};
|
|
4226
4343
|
}
|
|
@@ -4234,8 +4351,16 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4234
4351
|
return document.querySelector("[data-conversation-scroll]");
|
|
4235
4352
|
}
|
|
4236
4353
|
function conversationAnchor(root, key) {
|
|
4237
|
-
|
|
4238
|
-
|
|
4354
|
+
return conversationAnchors(root).get(key) ?? null;
|
|
4355
|
+
}
|
|
4356
|
+
/** 一次扫描生成锚点索引,滚动帧内不得为每个轮次重复遍历 DOM。 */
|
|
4357
|
+
function conversationAnchors(root) {
|
|
4358
|
+
const anchors = /* @__PURE__ */ new Map();
|
|
4359
|
+
for (const anchor of root.querySelectorAll("[data-chat-anchor-key]")) {
|
|
4360
|
+
const key = anchor.dataset.chatAnchorKey;
|
|
4361
|
+
if (key !== void 0 && !anchors.has(key)) anchors.set(key, anchor);
|
|
4362
|
+
}
|
|
4363
|
+
return anchors;
|
|
4239
4364
|
}
|
|
4240
4365
|
//#endregion
|
|
4241
4366
|
//#region src/client/TurnNavigator.tsx
|
|
@@ -4337,27 +4462,44 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4337
4462
|
};
|
|
4338
4463
|
}, []);
|
|
4339
4464
|
(0, react.useEffect)(() => {
|
|
4340
|
-
|
|
4341
|
-
|
|
4465
|
+
if (turns.length === 0) return;
|
|
4466
|
+
let host = null;
|
|
4342
4467
|
let frame = null;
|
|
4343
4468
|
const update = () => {
|
|
4344
4469
|
frame = null;
|
|
4470
|
+
if (host === null) return;
|
|
4345
4471
|
const threshold = host.getBoundingClientRect().top + Math.min(180, host.clientHeight * .35);
|
|
4472
|
+
const anchors = conversationAnchors(host);
|
|
4346
4473
|
let next = turns[0]?.key ?? null;
|
|
4347
4474
|
for (const turn of turns) {
|
|
4348
|
-
const anchor =
|
|
4349
|
-
if (anchor !==
|
|
4475
|
+
const anchor = anchors.get(turn.key);
|
|
4476
|
+
if (anchor !== void 0 && anchor.getBoundingClientRect().top <= threshold) next = turn.key;
|
|
4350
4477
|
}
|
|
4351
4478
|
setCurrent((previous) => previous === next ? previous : next);
|
|
4352
4479
|
};
|
|
4353
4480
|
const schedule = () => {
|
|
4354
4481
|
if (frame === null) frame = window.requestAnimationFrame(update);
|
|
4355
4482
|
};
|
|
4356
|
-
|
|
4483
|
+
const bindHost = () => {
|
|
4484
|
+
const next = conversationScrollRoot();
|
|
4485
|
+
if (next === host) return;
|
|
4486
|
+
host?.removeEventListener("scroll", schedule);
|
|
4487
|
+
host = next;
|
|
4488
|
+
host?.addEventListener("scroll", schedule, { passive: true });
|
|
4489
|
+
schedule();
|
|
4490
|
+
};
|
|
4491
|
+
const observer = new MutationObserver(() => {
|
|
4492
|
+
if (host === null || !host.isConnected) bindHost();
|
|
4493
|
+
});
|
|
4494
|
+
observer.observe(document.body, {
|
|
4495
|
+
childList: true,
|
|
4496
|
+
subtree: true
|
|
4497
|
+
});
|
|
4357
4498
|
window.addEventListener("resize", schedule);
|
|
4358
|
-
|
|
4499
|
+
bindHost();
|
|
4359
4500
|
return () => {
|
|
4360
|
-
|
|
4501
|
+
observer.disconnect();
|
|
4502
|
+
host?.removeEventListener("scroll", schedule);
|
|
4361
4503
|
window.removeEventListener("resize", schedule);
|
|
4362
4504
|
if (frame !== null) window.cancelAnimationFrame(frame);
|
|
4363
4505
|
};
|
|
@@ -4412,7 +4554,6 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4412
4554
|
index: index + 1,
|
|
4413
4555
|
summary: turn.summary
|
|
4414
4556
|
}),
|
|
4415
|
-
title: turn.summary,
|
|
4416
4557
|
style: tickStyle,
|
|
4417
4558
|
onFocus: () => {
|
|
4418
4559
|
setHoverAt(index);
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { resolve, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -54,6 +54,7 @@ function managedDependency(id) {
|
|
|
54
54
|
//#region src/dependency-manager.ts
|
|
55
55
|
const PROFILE_PENDING_UPDATES_FILE = ".dsh-pending-updates.json";
|
|
56
56
|
const APPLY_PLUGIN_UPDATES_IPC = "apply-plugin-updates";
|
|
57
|
+
const PLUGIN_INSTALL_TIMEOUT_MS = 6e5;
|
|
57
58
|
function profileDirectory() {
|
|
58
59
|
if (process.env.DSH_PROFILE_DIR !== void 0) return process.env.DSH_PROFILE_DIR;
|
|
59
60
|
return resolve(homedir(), ".dsh", "profiles", "web");
|
|
@@ -173,7 +174,7 @@ function applyReleaseExclude(source, packageName, version) {
|
|
|
173
174
|
}
|
|
174
175
|
/** 将用户本次确认的精确版本加入 Profile 的 pnpm 发布时间保护例外。 */
|
|
175
176
|
async function ensureLatestReleaseAllowed(packageName, version) {
|
|
176
|
-
if (
|
|
177
|
+
if (parseSemver(version) === void 0) throw new Error("npm 返回了无法识别的最新版本。");
|
|
177
178
|
const path = resolve(profileDirectory(), "pnpm-workspace.yaml");
|
|
178
179
|
let source;
|
|
179
180
|
try {
|
|
@@ -185,26 +186,40 @@ async function ensureLatestReleaseAllowed(packageName, version) {
|
|
|
185
186
|
const next = applyReleaseExclude(source, packageName, version);
|
|
186
187
|
if (next !== source) await writeFile(path, next, "utf8");
|
|
187
188
|
}
|
|
188
|
-
function
|
|
189
|
-
const match = /^v?(\d+)\.(\d+)\.(\d+)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
189
|
+
function parseSemver(version) {
|
|
190
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(version);
|
|
191
|
+
if (match === null) return void 0;
|
|
192
|
+
return {
|
|
193
|
+
core: [
|
|
194
|
+
Number(match[1]),
|
|
195
|
+
Number(match[2]),
|
|
196
|
+
Number(match[3])
|
|
197
|
+
],
|
|
198
|
+
prerelease: match[4] === void 0 ? [] : match[4].split(".")
|
|
199
|
+
};
|
|
195
200
|
}
|
|
196
|
-
function
|
|
197
|
-
|
|
198
|
-
|
|
201
|
+
function comparePrerelease(left, right) {
|
|
202
|
+
if (left.length === 0 || right.length === 0) return left.length === right.length ? 0 : left.length === 0 ? 1 : -1;
|
|
203
|
+
const length = Math.max(left.length, right.length);
|
|
204
|
+
for (let index = 0; index < length; index += 1) {
|
|
205
|
+
const a = left[index];
|
|
206
|
+
const b = right[index];
|
|
207
|
+
if (a === void 0 || b === void 0) return a === b ? 0 : a === void 0 ? -1 : 1;
|
|
208
|
+
if (a === b) continue;
|
|
209
|
+
const aNumeric = /^\d+$/.test(a);
|
|
210
|
+
const bNumeric = /^\d+$/.test(b);
|
|
211
|
+
if (aNumeric && bNumeric) return Number(a) > Number(b) ? 1 : -1;
|
|
212
|
+
if (aNumeric !== bNumeric) return aNumeric ? -1 : 1;
|
|
213
|
+
return a > b ? 1 : -1;
|
|
214
|
+
}
|
|
215
|
+
return 0;
|
|
199
216
|
}
|
|
200
217
|
function newerVersion(installed, latest) {
|
|
201
|
-
const current =
|
|
202
|
-
const candidate =
|
|
218
|
+
const current = parseSemver(installed);
|
|
219
|
+
const candidate = parseSemver(latest);
|
|
203
220
|
if (current === void 0 || candidate === void 0) return false;
|
|
204
|
-
if (candidate[
|
|
205
|
-
|
|
206
|
-
if (candidate[2] !== current[2]) return candidate[2] > current[2];
|
|
207
|
-
return prereleaseRank(latest) > prereleaseRank(installed);
|
|
221
|
+
for (let index = 0; index < current.core.length; index += 1) if (candidate.core[index] !== current.core[index]) return candidate.core[index] > current.core[index];
|
|
222
|
+
return comparePrerelease(candidate.prerelease, current.prerelease) > 0;
|
|
208
223
|
}
|
|
209
224
|
/** 返回 Web profile 中固定管理插件的实际安装版本与 npm latest 状态。 */
|
|
210
225
|
async function dependencyStatuses() {
|
|
@@ -272,9 +287,31 @@ async function recordPendingUpdate(packageName, version) {
|
|
|
272
287
|
});
|
|
273
288
|
await writeFile(pendingPath, `${JSON.stringify({ packages }, void 0, 2)}\n`, "utf8");
|
|
274
289
|
}
|
|
290
|
+
async function removePendingUpdate(packageName) {
|
|
291
|
+
const pendingPath = resolve(profileDirectory(), PROFILE_PENDING_UPDATES_FILE);
|
|
292
|
+
try {
|
|
293
|
+
const parsed = JSON.parse(await readFile(pendingPath, "utf8"));
|
|
294
|
+
if (!Array.isArray(parsed.packages)) return;
|
|
295
|
+
const packages = parsed.packages.filter((item) => item === null || typeof item !== "object" || item.packageName !== packageName);
|
|
296
|
+
if (packages.length === parsed.packages.length) return;
|
|
297
|
+
if (packages.length === 0) {
|
|
298
|
+
await unlink(pendingPath);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
await writeFile(pendingPath, `${JSON.stringify({ packages }, void 0, 2)}\n`, "utf8");
|
|
302
|
+
} catch (error) {
|
|
303
|
+
if (error.code !== "ENOENT") throw error;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
275
306
|
async function recordDeclaredVersion(packageName, version) {
|
|
276
307
|
const manifestPath = resolve(profileDirectory(), "package.json");
|
|
277
|
-
|
|
308
|
+
let manifest;
|
|
309
|
+
try {
|
|
310
|
+
manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
311
|
+
} catch (error) {
|
|
312
|
+
if (error.code !== "ENOENT") throw error;
|
|
313
|
+
manifest = {};
|
|
314
|
+
}
|
|
278
315
|
manifest.dependencies = {
|
|
279
316
|
...manifest.dependencies,
|
|
280
317
|
[packageName]: version
|
|
@@ -293,43 +330,87 @@ function pluginCommandError(stderr) {
|
|
|
293
330
|
* 复用启动当前服务的 DSH CLI:它会通过 pnpm 从 npm 安装或更新,并自动维护
|
|
294
331
|
* dsh.profile.bundles,避免浏览器端直接管理 profile 文件。
|
|
295
332
|
*/
|
|
296
|
-
function
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
"
|
|
305
|
-
|
|
333
|
+
function pluginExecArgv(args = process.execArgv) {
|
|
334
|
+
return args.filter((arg) => !/^--(?:inspect|inspect-brk|debug|debug-brk)(?:=|$)/.test(arg));
|
|
335
|
+
}
|
|
336
|
+
const activePluginChildren = /* @__PURE__ */ new Set();
|
|
337
|
+
function terminatePluginChild(child) {
|
|
338
|
+
if (child.exitCode !== null || child.killed) return;
|
|
339
|
+
if (process.platform === "win32" && child.pid !== void 0) {
|
|
340
|
+
const killer = spawn("taskkill", [
|
|
341
|
+
"/pid",
|
|
342
|
+
String(child.pid),
|
|
343
|
+
"/T",
|
|
344
|
+
"/F"
|
|
306
345
|
], {
|
|
307
|
-
cwd: process.cwd(),
|
|
308
|
-
env: {
|
|
309
|
-
...process.env,
|
|
310
|
-
CI: "true"
|
|
311
|
-
},
|
|
312
346
|
windowsHide: true,
|
|
313
|
-
stdio:
|
|
314
|
-
"ignore",
|
|
315
|
-
"pipe",
|
|
316
|
-
"pipe"
|
|
317
|
-
]
|
|
347
|
+
stdio: "ignore"
|
|
318
348
|
});
|
|
349
|
+
killer.once("error", () => {
|
|
350
|
+
child.kill("SIGTERM");
|
|
351
|
+
});
|
|
352
|
+
killer.unref();
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
child.kill("SIGTERM");
|
|
356
|
+
}
|
|
357
|
+
/** 插件停用时终止仍在运行的安装进程,避免热更新后遗留 pnpm。 */
|
|
358
|
+
function disposeDependencyInstaller() {
|
|
359
|
+
for (const child of activePluginChildren) terminatePluginChild(child);
|
|
360
|
+
}
|
|
361
|
+
function monitorPluginChild(child, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
362
|
+
return new Promise((resolvePromise, reject) => {
|
|
363
|
+
activePluginChildren.add(child);
|
|
319
364
|
let output = "";
|
|
365
|
+
let settled = false;
|
|
320
366
|
const collect = (chunk) => {
|
|
321
|
-
output
|
|
367
|
+
output = `${output}${String(chunk)}`.slice(-65536);
|
|
368
|
+
};
|
|
369
|
+
const finish = (error) => {
|
|
370
|
+
if (settled) return;
|
|
371
|
+
settled = true;
|
|
372
|
+
clearTimeout(timeout);
|
|
373
|
+
activePluginChildren.delete(child);
|
|
374
|
+
error === void 0 ? resolvePromise() : reject(error);
|
|
322
375
|
};
|
|
323
376
|
child.stdout?.on("data", collect);
|
|
324
377
|
child.stderr?.on("data", collect);
|
|
325
378
|
child.once("error", () => {
|
|
326
|
-
|
|
379
|
+
finish(/* @__PURE__ */ new Error("无法启动 DSH 插件安装命令。请确认 Node.js 与 pnpm 可用后重试。"));
|
|
327
380
|
});
|
|
328
381
|
child.once("exit", (code) => {
|
|
329
|
-
code === 0 ?
|
|
382
|
+
finish(code === 0 ? void 0 : pluginCommandError(output));
|
|
330
383
|
});
|
|
384
|
+
const timeout = setTimeout(() => {
|
|
385
|
+
terminatePluginChild(child);
|
|
386
|
+
finish(/* @__PURE__ */ new Error("插件安装超时,已终止安装进程。请检查网络后重试。"));
|
|
387
|
+
}, timeoutMs);
|
|
388
|
+
timeout.unref?.();
|
|
331
389
|
});
|
|
332
390
|
}
|
|
391
|
+
function runDshPlugin(args, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
392
|
+
const entry = resolveDshCliEntry();
|
|
393
|
+
return monitorPluginChild(spawn(process.execPath, [
|
|
394
|
+
...pluginExecArgv(),
|
|
395
|
+
entry,
|
|
396
|
+
"plugin",
|
|
397
|
+
"--profile",
|
|
398
|
+
"web",
|
|
399
|
+
...args
|
|
400
|
+
], {
|
|
401
|
+
cwd: process.cwd(),
|
|
402
|
+
env: {
|
|
403
|
+
...process.env,
|
|
404
|
+
CI: "true"
|
|
405
|
+
},
|
|
406
|
+
windowsHide: true,
|
|
407
|
+
stdio: [
|
|
408
|
+
"ignore",
|
|
409
|
+
"pipe",
|
|
410
|
+
"pipe"
|
|
411
|
+
]
|
|
412
|
+
}), timeoutMs);
|
|
413
|
+
}
|
|
333
414
|
/** 并发安装互斥:pnpm 锁文件竞争会触发 EPERM/EBUSY,同一时间只允许一个安装进程。 */
|
|
334
415
|
let installing = false;
|
|
335
416
|
/** 仅允许安装固定依赖,避免把浏览器输入转成任意命令。 */
|
|
@@ -352,10 +433,10 @@ async function installDependencyLocked(id, requestHotUpdate) {
|
|
|
352
433
|
const targetVersion = target === dependency.packageName ? latestVersion : await npmLatestVersion(target);
|
|
353
434
|
if (targetVersion === void 0) throw new Error("无法获取 npm 最新版本,请检查网络或 npm registry 后重试。");
|
|
354
435
|
const remove = pluginsToRemoveBeforeInstall(declared, target);
|
|
355
|
-
if (remove.length > 0) await runDshPlugin(["remove", ...remove]);
|
|
356
436
|
await ensureLatestReleaseAllowed(target, targetVersion);
|
|
357
437
|
if (!isOfficialRuntimePackage(target)) await recordDeclaredVersion(target, targetVersion);
|
|
358
438
|
await recordPendingUpdate(target, targetVersion);
|
|
439
|
+
if (remove.length > 0) await runDshPlugin(["remove", ...remove]);
|
|
359
440
|
if (requestHotUpdate()) return dependencyStatuses();
|
|
360
441
|
try {
|
|
361
442
|
await runDshPlugin([
|
|
@@ -368,6 +449,7 @@ async function installDependencyLocked(id, requestHotUpdate) {
|
|
|
368
449
|
throw error;
|
|
369
450
|
}
|
|
370
451
|
if (await installedPackageVersion(target) !== targetVersion) return dependencyStatuses();
|
|
452
|
+
await removePendingUpdate(target);
|
|
371
453
|
return dependencyStatuses();
|
|
372
454
|
}
|
|
373
455
|
//#endregion
|
|
@@ -419,7 +501,7 @@ function crossSiteRequest(request) {
|
|
|
419
501
|
/** 把安装错误收成可给浏览器看的文案:我们自己的中文说明保留,带本地路径的底层错误脱敏。 */
|
|
420
502
|
function publicDependencyError(error) {
|
|
421
503
|
const message = error instanceof Error ? error.message : "依赖管理暂不可用。";
|
|
422
|
-
if (/[A-Za-z]:[\\/]|\/(?:home|Users|var|tmp)\//.test(message)) return "依赖管理暂不可用,请查看服务端日志。";
|
|
504
|
+
if (/[A-Za-z]:[\\/]|\/(?:home|root|Users|var|tmp)\//.test(message)) return "依赖管理暂不可用,请查看服务端日志。";
|
|
423
505
|
return message;
|
|
424
506
|
}
|
|
425
507
|
const inject = [
|
|
@@ -528,6 +610,7 @@ function apply(ctx) {
|
|
|
528
610
|
}
|
|
529
611
|
});
|
|
530
612
|
return () => {
|
|
613
|
+
disposeDependencyInstaller();
|
|
531
614
|
disposeConnectors();
|
|
532
615
|
disposeDependencies();
|
|
533
616
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@michengai/dsh-codex-ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.73",
|
|
4
4
|
"description": "以 Codex 风格重构 DSH Web 侧栏的独立客户端插件",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -53,7 +53,8 @@
|
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"build": "tsc --noEmit && tsdown",
|
|
56
|
-
"
|
|
56
|
+
"typecheck": "tsc --noEmit",
|
|
57
|
+
"test": "pnpm run typecheck && vitest run tests/client-runtime.integration.spec.ts && tsdown && node tests/run-assertions.mjs"
|
|
57
58
|
},
|
|
58
59
|
"peerDependencies": {
|
|
59
60
|
"@deepseek-ai/cordis": ">=4.0.1 <5.0.0",
|