dsh-sidenote 0.3.4 → 0.4.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 +14 -16
- package/lib/client.js +940 -208
- package/lib/index.js +180 -2
- package/lib/types/client/annotate/send.d.ts +11 -0
- package/lib/types/client/chat/cards.d.ts +3 -3
- package/lib/types/client/host/contracts.d.ts +75 -2
- package/lib/types/client/host/labels.d.ts +13 -0
- package/lib/types/client/index.d.ts +6 -5
- package/lib/types/client/locales.d.ts +10 -0
- package/lib/types/client/reflow.d.ts +6 -0
- package/lib/types/client/sidechat/lifecycle.d.ts +10 -2
- package/lib/types/client/sidechat/metaStore.d.ts +73 -0
- package/lib/types/client/sidechat/native-tab.d.ts +32 -0
- package/lib/types/client/sidechat/native.d.ts +15 -0
- package/lib/types/client/sidechat/open.d.ts +17 -6
- package/lib/types/index.d.ts +36 -5
- package/lib/types/trust-fence.d.ts +24 -0
- package/package.json +28 -4
- package/src/client/annotate/send.ts +126 -27
- package/src/client/chat/ToolCard.tsx +8 -8
- package/src/client/chat/cards.ts +3 -3
- package/src/client/host/contracts.ts +81 -1
- package/src/client/host/labels.ts +16 -0
- package/src/client/index.tsx +12 -6
- package/src/client/locales.ts +20 -0
- package/src/client/reflow.ts +52 -0
- package/src/client/sidechat/SideChatPanel.tsx +18 -7
- package/src/client/sidechat/index.tsx +54 -35
- package/src/client/sidechat/lifecycle.ts +49 -7
- package/src/client/sidechat/metaStore.ts +197 -0
- package/src/client/sidechat/native-tab.tsx +249 -0
- package/src/client/sidechat/native.ts +39 -1
- package/src/client/sidechat/notify.ts +29 -8
- package/src/client/sidechat/open.ts +161 -24
- package/src/client/sidechat/referenceSource.ts +41 -7
- package/src/client/sidechat/sidechat.module.css +11 -0
- package/src/client/sidechat/slash.ts +18 -6
- package/src/index.ts +194 -6
- package/src/trust-fence.ts +84 -0
package/lib/client.js
CHANGED
|
@@ -21,13 +21,44 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
return root ?? fallback;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
+
* betterSidebar 服务的唯一安全读取面(对抗性审查 B-1):cordis 对「未
|
|
25
|
+
* provide 且未 inject」的服务**属性访问抛错**(`cannot get property without
|
|
26
|
+
* inject`),`?.` 也挡不住;`ctx.get` 返回 undefined 不抛。optional peer
|
|
27
|
+
* 后 betterSidebar 不在 inject 清单——一切消费点必须走这里。
|
|
28
|
+
*/
|
|
29
|
+
function betterSidebarOf(ctx) {
|
|
30
|
+
try {
|
|
31
|
+
const viaGet = ctx.get("betterSidebar");
|
|
32
|
+
if (viaGet !== void 0 && viaGet !== null) return viaGet;
|
|
33
|
+
} catch {}
|
|
34
|
+
try {
|
|
35
|
+
return ctx.betterSidebar;
|
|
36
|
+
} catch {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 直连腿判定(WI-05):tab 直连注册进原生右栏的条件。
|
|
42
|
+
* - betterSidebar ≥ 0.19 ⇒ 宿主必 ≥ 0.1.5(BS 0.19 只支持 0.1.5)⇒ 直连;
|
|
43
|
+
* - betterSidebar 整体缺席(optional peer 后的合法形态)⇒ 只能直连;
|
|
44
|
+
* 无 BS 且无原生面的非法环境(宿主 < 0.1.5)下注册静默不到、侧聊缺席,
|
|
45
|
+
* 其余功能(注释/回流搭车)存活——静默缺席优于崩。
|
|
46
|
+
*/
|
|
47
|
+
function directNativeLeg(ctx) {
|
|
48
|
+
const bs = betterSidebarOf(ctx);
|
|
49
|
+
if (bs === void 0 || bs === null) return true;
|
|
50
|
+
return nativeSidebarHost(ctx);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
24
53
|
* True when the host keeps sidebar tabs outside the legacy layout store
|
|
25
54
|
* (better-sidebar >= 0.19). Version parse is best-effort: an unparsable
|
|
26
55
|
* version reports false, which keeps the pre-0.19 behaviour.
|
|
27
56
|
*/
|
|
28
57
|
function nativeSidebarHost(ctx) {
|
|
29
58
|
try {
|
|
30
|
-
const
|
|
59
|
+
const version = betterSidebarOf(ctx)?.version;
|
|
60
|
+
if (version === void 0) return false;
|
|
61
|
+
const [major = 0, minor = 0] = version.split(".").map((part) => Number.parseInt(part, 10));
|
|
31
62
|
return major > 0 || minor >= NATIVE_SIDEBAR_MINOR;
|
|
32
63
|
} catch {
|
|
33
64
|
return false;
|
|
@@ -143,6 +174,16 @@ window.__ModuleLoader__.load({
|
|
|
143
174
|
tabBaseTitle: "Side",
|
|
144
175
|
codeCopy: "Copy",
|
|
145
176
|
codeCopied: "Copied",
|
|
177
|
+
jsonCopyValue: "Copy value",
|
|
178
|
+
jsonCopyJson: "Copy JSON",
|
|
179
|
+
jsonCopyPath: "Copy path",
|
|
180
|
+
jsonCopyPretty: "Copy pretty JSON",
|
|
181
|
+
jsonCopyCompact: "Copy compact JSON",
|
|
182
|
+
jsonCopyFailed: "Copy failed",
|
|
183
|
+
jsonCollapse: "Collapse node",
|
|
184
|
+
jsonExpand: "Expand node",
|
|
185
|
+
jsonTreeLabel: "JSON payload",
|
|
186
|
+
sideChatCrashed: "Side chat panel crashed: ",
|
|
146
187
|
forkErrorTitle: "Couldn't create the side chat",
|
|
147
188
|
forkErrorHint: "The main session needs at least one completed turn to fork from. Close this tab with the × on the tab.",
|
|
148
189
|
missingTitle: "Session no longer exists",
|
|
@@ -277,6 +318,16 @@ window.__ModuleLoader__.load({
|
|
|
277
318
|
tabBaseTitle: "侧边",
|
|
278
319
|
codeCopy: "复制",
|
|
279
320
|
codeCopied: "已复制",
|
|
321
|
+
jsonCopyValue: "复制值",
|
|
322
|
+
jsonCopyJson: "复制 JSON",
|
|
323
|
+
jsonCopyPath: "复制路径",
|
|
324
|
+
jsonCopyPretty: "复制格式化 JSON",
|
|
325
|
+
jsonCopyCompact: "复制紧凑 JSON",
|
|
326
|
+
jsonCopyFailed: "复制失败",
|
|
327
|
+
jsonCollapse: "折叠节点",
|
|
328
|
+
jsonExpand: "展开节点",
|
|
329
|
+
jsonTreeLabel: "JSON 数据",
|
|
330
|
+
sideChatCrashed: "侧边聊天面板崩溃了:",
|
|
280
331
|
forkErrorTitle: "无法创建侧边聊天",
|
|
281
332
|
forkErrorHint: "主会话需要至少一轮已完成的对话才能 fork。点击标签上的 × 可关闭此标签页。",
|
|
282
333
|
missingTitle: "会话已不存在",
|
|
@@ -781,28 +832,238 @@ window.__ModuleLoader__.load({
|
|
|
781
832
|
};
|
|
782
833
|
}
|
|
783
834
|
//#endregion
|
|
835
|
+
//#region src/client/sidechat/metaStore.ts
|
|
836
|
+
const KEY_PREFIX$1 = "dsh-sidenote:side-meta:v1:";
|
|
837
|
+
/**
|
|
838
|
+
* 本页面生命周期 id。**挂在 window 上**(审查 m3):模块级铸造会在插件
|
|
839
|
+
* HMR/重载时换模块实例 → 新 runId 触发孤键清扫误删本页活记录。window
|
|
840
|
+
* 级持有跨模块重载稳定;页面刷新(真正的清扫时机)window 重建。
|
|
841
|
+
*/
|
|
842
|
+
const SIDENOTE_RUN_ID = (() => {
|
|
843
|
+
if (typeof window !== "undefined") {
|
|
844
|
+
const w = window;
|
|
845
|
+
if (w.__dshSidenoteRunId === void 0) w.__dshSidenoteRunId = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `run-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
846
|
+
return w.__dshSidenoteRunId;
|
|
847
|
+
}
|
|
848
|
+
return `run-ssr-${Math.random().toString(36).slice(2)}`;
|
|
849
|
+
})();
|
|
850
|
+
function keyOf(sessionId, tabId) {
|
|
851
|
+
return `${KEY_PREFIX$1}${sessionId}:${tabId}`;
|
|
852
|
+
}
|
|
853
|
+
function revive$1(value) {
|
|
854
|
+
if (typeof value !== "object" || value === null) return null;
|
|
855
|
+
const r = value;
|
|
856
|
+
if (typeof r.sessionId !== "string" || r.sessionId === "") return null;
|
|
857
|
+
if (typeof r.tabId !== "string" || r.tabId === "") return null;
|
|
858
|
+
if (typeof r.number !== "number") return null;
|
|
859
|
+
return {
|
|
860
|
+
tabId: r.tabId,
|
|
861
|
+
sessionId: r.sessionId,
|
|
862
|
+
...typeof r.childId === "string" ? { childId: r.childId } : {},
|
|
863
|
+
...typeof r.parentSessionId === "string" ? { parentSessionId: r.parentSessionId } : {},
|
|
864
|
+
...typeof r.pendingDraft === "string" ? { pendingDraft: r.pendingDraft } : {},
|
|
865
|
+
...typeof r.boundarySeq === "number" && Number.isInteger(r.boundarySeq) ? { boundarySeq: r.boundarySeq } : {},
|
|
866
|
+
number: r.number,
|
|
867
|
+
createdAt: typeof r.createdAt === "number" ? r.createdAt : 0,
|
|
868
|
+
...typeof r.runId === "string" ? { runId: r.runId } : {}
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function storage() {
|
|
872
|
+
return typeof localStorage === "undefined" ? null : localStorage;
|
|
873
|
+
}
|
|
874
|
+
let version = 0;
|
|
875
|
+
const listeners$1 = /* @__PURE__ */ new Set();
|
|
876
|
+
function notify() {
|
|
877
|
+
version += 1;
|
|
878
|
+
for (const fn of [...listeners$1]) fn();
|
|
879
|
+
}
|
|
880
|
+
/** useSyncExternalStore 三件套。 */
|
|
881
|
+
const sideChatMetaStore = {
|
|
882
|
+
getSnapshot: () => version,
|
|
883
|
+
subscribe(fn) {
|
|
884
|
+
listeners$1.add(fn);
|
|
885
|
+
return () => {
|
|
886
|
+
listeners$1.delete(fn);
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
/** 渲染期静默写后的补通知(面板 reconcile 用——render 期写不能 notify)。 */
|
|
891
|
+
function notifySideChatMetaListeners() {
|
|
892
|
+
notify();
|
|
893
|
+
}
|
|
894
|
+
function readSideChatMeta(sessionId, tabId) {
|
|
895
|
+
const store = storage();
|
|
896
|
+
if (store === null) return void 0;
|
|
897
|
+
try {
|
|
898
|
+
const raw = store.getItem(keyOf(sessionId, tabId));
|
|
899
|
+
if (raw === null) return void 0;
|
|
900
|
+
return revive$1(JSON.parse(raw)) ?? void 0;
|
|
901
|
+
} catch {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
/** 写/合并一个 tab 的 meta(整体替换语义由调用方组合:先读再写)。 */
|
|
906
|
+
function writeSideChatMeta(record, options) {
|
|
907
|
+
const store = storage();
|
|
908
|
+
if (store === null) return;
|
|
909
|
+
try {
|
|
910
|
+
store.setItem(keyOf(record.sessionId, record.tabId), JSON.stringify(record));
|
|
911
|
+
if (options?.silent !== true) notify();
|
|
912
|
+
} catch {}
|
|
913
|
+
}
|
|
914
|
+
function dropSideChatMeta(sessionId, tabId) {
|
|
915
|
+
const store = storage();
|
|
916
|
+
if (store === null) return;
|
|
917
|
+
try {
|
|
918
|
+
store.removeItem(keyOf(sessionId, tabId));
|
|
919
|
+
notify();
|
|
920
|
+
} catch {}
|
|
921
|
+
}
|
|
922
|
+
/** 枚举一个主会话的全部 meta 记录(按创建序升序)。 */
|
|
923
|
+
function sideChatMetasOf(sessionId) {
|
|
924
|
+
return sideChatMetasAll().filter((r) => r.sessionId === sessionId).sort((a, b) => a.createdAt - b.createdAt);
|
|
925
|
+
}
|
|
926
|
+
/** 枚举全部存活记录(跨会话;完成通知等全局监听用)。 */
|
|
927
|
+
function sideChatMetasAll() {
|
|
928
|
+
const store = storage();
|
|
929
|
+
if (store === null) return [];
|
|
930
|
+
try {
|
|
931
|
+
const out = [];
|
|
932
|
+
for (let i = 0; i < store.length; i += 1) {
|
|
933
|
+
const key = store.key(i);
|
|
934
|
+
if (typeof key !== "string" || !key.startsWith(KEY_PREFIX$1)) continue;
|
|
935
|
+
const record = revive$1(JSON.parse(store.getItem(key) ?? "null"));
|
|
936
|
+
if (record !== null) out.push(record);
|
|
937
|
+
}
|
|
938
|
+
return out;
|
|
939
|
+
} catch {
|
|
940
|
+
return [];
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* 下一个实例编号:当前会话存活记录的最大编号 + 1。
|
|
945
|
+
* 单实例期调用方保证同会话同时至多一条存活记录(held 规则),
|
|
946
|
+
* 此函数为 Delivery_02 的多实例预留正确语义。
|
|
947
|
+
*/
|
|
948
|
+
function nextSideChatNumber(sessionId) {
|
|
949
|
+
const existing = sideChatMetasOf(sessionId);
|
|
950
|
+
return existing.length === 0 ? 1 : Math.max(...existing.map((r) => r.number)) + 1;
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* 孤键清扫:删掉 runId 与本页面生命周期不匹配的记录(上一页面周期的
|
|
954
|
+
* 残留——原生布局刷新即空,这些键指向的 tab 已不存在)。插件 apply 时
|
|
955
|
+
* 调用一次。返回清扫数。
|
|
956
|
+
*/
|
|
957
|
+
function sweepOrphanedSideChatMeta() {
|
|
958
|
+
const store = storage();
|
|
959
|
+
if (store === null) return 0;
|
|
960
|
+
try {
|
|
961
|
+
const staleKeys = [];
|
|
962
|
+
for (let i = 0; i < store.length; i += 1) {
|
|
963
|
+
const key = store.key(i);
|
|
964
|
+
if (typeof key !== "string" || !key.startsWith(KEY_PREFIX$1)) continue;
|
|
965
|
+
const record = revive$1(JSON.parse(store.getItem(key) ?? "null"));
|
|
966
|
+
if (record === null || record.runId !== SIDENOTE_RUN_ID) staleKeys.push(key);
|
|
967
|
+
}
|
|
968
|
+
for (const key of staleKeys) store.removeItem(key);
|
|
969
|
+
if (staleKeys.length > 0) notify();
|
|
970
|
+
return staleKeys.length;
|
|
971
|
+
} catch {
|
|
972
|
+
return 0;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
//#endregion
|
|
784
976
|
//#region src/client/sidechat/open.ts
|
|
977
|
+
/** 直连腿的原生右栏面(off-face 探测;无面 = 不在直连腿或面缺席降级)。 */
|
|
978
|
+
function sidebarRightOf(ctx) {
|
|
979
|
+
try {
|
|
980
|
+
const face = ctx.get("sidebarRight");
|
|
981
|
+
return typeof face?.openTab === "function" ? face : void 0;
|
|
982
|
+
} catch {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
/** 直连腿判定:directNativeLeg(BS ≥0.19 或 BS 缺席)+ 原生面已就位。 */
|
|
987
|
+
function directLeg(ctx) {
|
|
988
|
+
return directNativeLeg(ctx) && sidebarRightOf(ctx) !== void 0;
|
|
989
|
+
}
|
|
990
|
+
/** 直连腿:向既存 tab 追加待投递草稿(面板 pendingDraft effect 消费)。 */
|
|
991
|
+
function appendNativePendingDraft(sessionId, tabId, draftText) {
|
|
992
|
+
const meta = readSideChatMeta(sessionId, tabId);
|
|
993
|
+
if (meta === void 0) return;
|
|
994
|
+
writeSideChatMeta({
|
|
995
|
+
...meta,
|
|
996
|
+
pendingDraft: appendDraftText(meta.pendingDraft ?? "", draftText)
|
|
997
|
+
});
|
|
998
|
+
}
|
|
785
999
|
/**
|
|
786
1000
|
* 从最新快照读一个 Tab(meta 合并写入前的读取面;布局即注册表)。
|
|
787
|
-
*
|
|
788
|
-
* in the layout snapshot — fall back to the live-panel registry.
|
|
1001
|
+
* 直连腿:metaStore 是 meta 权威(原生布局无 meta 面)。
|
|
789
1002
|
*/
|
|
790
|
-
function readTab(ctx, tabId) {
|
|
791
|
-
|
|
1003
|
+
function readTab(ctx, sessionId, tabId) {
|
|
1004
|
+
const direct = readSideChatMeta(sessionId, tabId);
|
|
1005
|
+
if (direct !== void 0) {
|
|
1006
|
+
const live = liveSideChatsOf(sessionId).find((entry) => entry.tabId === tabId);
|
|
1007
|
+
return {
|
|
1008
|
+
id: tabId,
|
|
1009
|
+
type: SIDE_TAB_TYPE,
|
|
1010
|
+
title: live?.readTitle() ?? (direct.number <= 1 ? t("tabBaseTitle") : `${t("tabBaseTitle")} ${direct.number}`),
|
|
1011
|
+
meta: direct
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
const legacySnap = betterSidebarOf(ctx)?.getSnapshot();
|
|
1015
|
+
return collectTabs(legacySnap?.state).find((candidate) => candidate.id === tabId) ?? nativeTabShell(tabId, "dsh-sidenote:side");
|
|
792
1016
|
}
|
|
793
1017
|
/**
|
|
794
1018
|
* 为 sessionId 新建或聚焦一个侧边聊天 Tab;draftText 给出时写入其草稿。
|
|
795
1019
|
* @returns false = 未能打开(调用方保持自己的流程)。
|
|
796
1020
|
*/
|
|
797
1021
|
function openOrFocusSideChat(ctx, sessionId, draftText) {
|
|
1022
|
+
if (directLeg(ctx)) return openOrFocusDirect(ctx, sessionId, draftText);
|
|
1023
|
+
return openOrFocusLegacy(ctx, sessionId, draftText);
|
|
1024
|
+
}
|
|
1025
|
+
/** 直连腿:聚焦既有(三级数据源)或铸造新开。 */
|
|
1026
|
+
function openOrFocusDirect(ctx, sessionId, draftText) {
|
|
1027
|
+
try {
|
|
1028
|
+
if (ctx.sessions.list.getSnapshot().current !== sessionId) return false;
|
|
1029
|
+
const hasDraft = draftText !== void 0 && draftText !== "";
|
|
1030
|
+
const live = lastLiveSideChat(sessionId);
|
|
1031
|
+
if (live !== void 0) {
|
|
1032
|
+
if (hasDraft) live.seedDraft(draftText);
|
|
1033
|
+
if (!focusNativeTab(ctx, live.tabId)) sidebarRightOf(ctx)?.focus(live.tabId);
|
|
1034
|
+
return true;
|
|
1035
|
+
}
|
|
1036
|
+
const opening = sideChatOpening(sessionId);
|
|
1037
|
+
if (opening !== void 0) {
|
|
1038
|
+
if (hasDraft) opening.drafts.push(draftText);
|
|
1039
|
+
return true;
|
|
1040
|
+
}
|
|
1041
|
+
const metas = sideChatMetasOf(sessionId);
|
|
1042
|
+
const target = metas[metas.length - 1];
|
|
1043
|
+
if (target !== void 0 && hasDraft) appendNativePendingDraft(sessionId, target.tabId, draftText);
|
|
1044
|
+
sidebarRightOf(ctx).openTab(SIDE_TAB_TYPE, { params: {
|
|
1045
|
+
parentSessionId: sessionId,
|
|
1046
|
+
...hasDraft && target === void 0 ? { pendingDraft: draftText } : {}
|
|
1047
|
+
} });
|
|
1048
|
+
markSideChatOpening(sessionId);
|
|
1049
|
+
return true;
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
console.warn("[dsh-sidenote] 打开侧边聊天失败:", error);
|
|
1052
|
+
return false;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
/** legacy 腿:布局快照即注册表的原始路径(BS < 0.19)。 */
|
|
1056
|
+
function openOrFocusLegacy(ctx, sessionId, draftText) {
|
|
1057
|
+
const bs = betterSidebarOf(ctx);
|
|
1058
|
+
if (bs === void 0) return false;
|
|
798
1059
|
try {
|
|
799
|
-
const snapshot =
|
|
1060
|
+
const snapshot = bs.getSnapshot();
|
|
800
1061
|
if (snapshot.sessionId !== sessionId || snapshot.state === void 0) return false;
|
|
801
1062
|
const existing = collectSideTabs(snapshot.state);
|
|
802
1063
|
const live = lastLiveSideChat(sessionId);
|
|
803
1064
|
if (live !== void 0) {
|
|
804
1065
|
if (draftText !== void 0 && draftText !== "") live.seedDraft(draftText);
|
|
805
|
-
if (!focusNativeTab(ctx, live.tabId))
|
|
1066
|
+
if (!focusNativeTab(ctx, live.tabId)) bs.activateTab(live.tabId, { sessionId });
|
|
806
1067
|
return true;
|
|
807
1068
|
}
|
|
808
1069
|
if (existing.length > 0) {
|
|
@@ -811,12 +1072,12 @@ window.__ModuleLoader__.load({
|
|
|
811
1072
|
const meta = parseSideChatMeta(target.meta);
|
|
812
1073
|
const input = meta.childId === void 0 ? null : resolveSessionInput(ctx, meta.childId);
|
|
813
1074
|
if (input !== null) input.setDraft(appendDraftText(readInputDraft(input), draftText));
|
|
814
|
-
else
|
|
1075
|
+
else bs.updateTab(target.id, { meta: {
|
|
815
1076
|
...meta,
|
|
816
1077
|
pendingDraft: appendDraftText(meta.pendingDraft ?? "", draftText)
|
|
817
1078
|
} });
|
|
818
1079
|
}
|
|
819
|
-
|
|
1080
|
+
bs.activateTab(target.id, { sessionId });
|
|
820
1081
|
return true;
|
|
821
1082
|
}
|
|
822
1083
|
const opening = sideChatOpening(sessionId);
|
|
@@ -831,28 +1092,35 @@ window.__ModuleLoader__.load({
|
|
|
831
1092
|
}
|
|
832
1093
|
}
|
|
833
1094
|
/**
|
|
834
|
-
* 无条件新建一个侧边聊天 Tab(/side
|
|
835
|
-
*
|
|
1095
|
+
* 无条件新建一个侧边聊天 Tab(/side「新建侧边聊天」选项的语义)。
|
|
1096
|
+
* 直连腿(单实例期):折叠为「聚焦既有 + 草稿正确投递」(= openOrFocus;
|
|
1097
|
+
* 多实例随 Delivery_02 的 multiple 放开)。
|
|
836
1098
|
* @returns false = 未能创建(调用方保持自己的流程)。
|
|
837
1099
|
*/
|
|
838
1100
|
function createSideChat(ctx, sessionId, draftText) {
|
|
1101
|
+
if (directLeg(ctx)) return openOrFocusDirect(ctx, sessionId, draftText);
|
|
1102
|
+
return createSideChatLegacy(ctx, sessionId, draftText);
|
|
1103
|
+
}
|
|
1104
|
+
function createSideChatLegacy(ctx, sessionId, draftText) {
|
|
1105
|
+
const bs = betterSidebarOf(ctx);
|
|
1106
|
+
if (bs === void 0) return false;
|
|
839
1107
|
try {
|
|
840
|
-
const snapshot =
|
|
1108
|
+
const snapshot = bs.getSnapshot();
|
|
841
1109
|
if (snapshot.sessionId !== sessionId || snapshot.state === void 0) return false;
|
|
842
|
-
if (!
|
|
1110
|
+
if (!bs.isTabEnabled("dsh-sidenote:side")) return false;
|
|
843
1111
|
const before = new Set(collectTabs(snapshot.state).map((tab) => tab.id));
|
|
844
1112
|
const seed = draftText !== void 0 && draftText !== "" ? {
|
|
845
1113
|
type: SIDE_TAB_TYPE,
|
|
846
1114
|
meta: { pendingDraft: draftText }
|
|
847
1115
|
} : { type: SIDE_TAB_TYPE };
|
|
848
|
-
|
|
849
|
-
const created = collectSideTabs(
|
|
1116
|
+
bs.openTab(seed, { sessionId });
|
|
1117
|
+
const created = collectSideTabs(bs.getSnapshot().state).find((tab) => !before.has(tab.id));
|
|
850
1118
|
if (created === void 0) {
|
|
851
1119
|
if (!nativeSidebarHost(ctx)) return false;
|
|
852
1120
|
markSideChatOpening(sessionId);
|
|
853
1121
|
return true;
|
|
854
1122
|
}
|
|
855
|
-
if (draftText !== void 0 && draftText !== "")
|
|
1123
|
+
if (draftText !== void 0 && draftText !== "") bs.updateTab(created.id, { meta: { pendingDraft: draftText } });
|
|
856
1124
|
return true;
|
|
857
1125
|
} catch (error) {
|
|
858
1126
|
console.warn("[dsh-sidenote] 新建侧边聊天失败:", error);
|
|
@@ -866,8 +1134,17 @@ window.__ModuleLoader__.load({
|
|
|
866
1134
|
*/
|
|
867
1135
|
function sideChatTargetTitle(ctx, sessionId) {
|
|
868
1136
|
try {
|
|
869
|
-
|
|
870
|
-
|
|
1137
|
+
if (directLeg(ctx)) {
|
|
1138
|
+
if (ctx.sessions.list.getSnapshot().current !== sessionId) return void 0;
|
|
1139
|
+
const live = lastLiveSideChat(sessionId);
|
|
1140
|
+
if (live !== void 0) return live.readTitle();
|
|
1141
|
+
const metas = sideChatMetasOf(sessionId);
|
|
1142
|
+
const last = metas[metas.length - 1];
|
|
1143
|
+
if (last !== void 0) return last.number <= 1 ? t("tabBaseTitle") : `${t("tabBaseTitle")} ${last.number}`;
|
|
1144
|
+
return t("tabBaseTitle");
|
|
1145
|
+
}
|
|
1146
|
+
const snapshot = betterSidebarOf(ctx)?.getSnapshot();
|
|
1147
|
+
if (snapshot === void 0 || snapshot.sessionId !== sessionId || snapshot.state === void 0) return void 0;
|
|
871
1148
|
const existing = collectSideTabs(snapshot.state);
|
|
872
1149
|
if (existing.length > 0) return existing[existing.length - 1].title;
|
|
873
1150
|
const live = lastLiveSideChat(sessionId);
|
|
@@ -884,28 +1161,43 @@ window.__ModuleLoader__.load({
|
|
|
884
1161
|
* 有现成错误态兜着)。
|
|
885
1162
|
*/
|
|
886
1163
|
function reopenSideChat(ctx, sessionId, childId, title) {
|
|
1164
|
+
if (directLeg(ctx)) try {
|
|
1165
|
+
if (ctx.sessions.list.getSnapshot().current !== sessionId) return false;
|
|
1166
|
+
if (sideChatMetasOf(sessionId).length > 0) return false;
|
|
1167
|
+
sidebarRightOf(ctx).openTab(SIDE_TAB_TYPE, { params: {
|
|
1168
|
+
parentSessionId: sessionId,
|
|
1169
|
+
childId
|
|
1170
|
+
} });
|
|
1171
|
+
markSideChatOpening(sessionId);
|
|
1172
|
+
return true;
|
|
1173
|
+
} catch (error) {
|
|
1174
|
+
console.warn("[dsh-sidenote] 重开侧边聊天失败:", error);
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
const bs = betterSidebarOf(ctx);
|
|
1178
|
+
if (bs === void 0) return false;
|
|
887
1179
|
try {
|
|
888
|
-
const snapshot =
|
|
1180
|
+
const snapshot = bs.getSnapshot();
|
|
889
1181
|
if (snapshot.sessionId !== sessionId || snapshot.state === void 0) return false;
|
|
890
|
-
if (!
|
|
1182
|
+
if (!bs.isTabEnabled("dsh-sidenote:side")) return false;
|
|
891
1183
|
if (nativeSidebarHost(ctx) && liveSideChatsOf(sessionId).length > 0) return false;
|
|
892
1184
|
const before = new Set(collectTabs(snapshot.state).map((tab) => tab.id));
|
|
893
1185
|
const meta = {
|
|
894
1186
|
childId,
|
|
895
1187
|
parentSessionId: sessionId
|
|
896
1188
|
};
|
|
897
|
-
|
|
1189
|
+
bs.openTab({
|
|
898
1190
|
type: SIDE_TAB_TYPE,
|
|
899
1191
|
...title !== void 0 ? { title } : {},
|
|
900
1192
|
meta
|
|
901
1193
|
}, { sessionId });
|
|
902
|
-
const created = collectSideTabs(
|
|
1194
|
+
const created = collectSideTabs(bs.getSnapshot().state).find((tab) => !before.has(tab.id));
|
|
903
1195
|
if (created === void 0) {
|
|
904
1196
|
if (!nativeSidebarHost(ctx)) return false;
|
|
905
1197
|
markSideChatOpening(sessionId);
|
|
906
1198
|
return true;
|
|
907
1199
|
}
|
|
908
|
-
|
|
1200
|
+
bs.updateTab(created.id, {
|
|
909
1201
|
...title !== void 0 ? { title } : {},
|
|
910
1202
|
meta
|
|
911
1203
|
});
|
|
@@ -936,7 +1228,7 @@ window.__ModuleLoader__.load({
|
|
|
936
1228
|
} catch {}
|
|
937
1229
|
const forked = await ctx.sessions.fork({ sessionId: parentSessionId });
|
|
938
1230
|
const owner = rootContext(ctx);
|
|
939
|
-
updateTabMeta(ctx, tabId, (current) => ({
|
|
1231
|
+
updateTabMeta(ctx, parentSessionId, tabId, (current) => ({
|
|
940
1232
|
...current,
|
|
941
1233
|
childId: forked,
|
|
942
1234
|
parentSessionId,
|
|
@@ -956,10 +1248,49 @@ window.__ModuleLoader__.load({
|
|
|
956
1248
|
}
|
|
957
1249
|
return forked;
|
|
958
1250
|
}
|
|
959
|
-
/**
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1251
|
+
/**
|
|
1252
|
+
* Tab meta 读-改-写。双腿:直连原生腿的 meta 在自有 metaStore(原生无
|
|
1253
|
+
* updateTab 面,布局 memory-only);legacy 腿在布局快照 + betterSidebar.updateTab。
|
|
1254
|
+
* 分腿判据统一为 directNativeLeg(对抗性审查 m1:判据单点化——metaStore
|
|
1255
|
+
* 有无记录不能再当判据,否则记录缺失时 childId 登记会静默落到 no-op 的
|
|
1256
|
+
* legacy 面)。直连腿记录缺失 = 异常态(reconcile 应先已建):warn 并 no-op。
|
|
1257
|
+
*/
|
|
1258
|
+
function updateTabMeta(ctx, sessionId, tabId, mutate) {
|
|
1259
|
+
if (directNativeLeg(ctx)) {
|
|
1260
|
+
const direct = readSideChatMeta(sessionId, tabId);
|
|
1261
|
+
if (direct === void 0) {
|
|
1262
|
+
console.warn("[dsh-sidenote] meta 记录缺失(reconcile 应先已建),本次 meta 写入跳过:", tabId);
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
const next = mutate(parseSideChatMeta(direct));
|
|
1266
|
+
writeSideChatMeta({
|
|
1267
|
+
tabId,
|
|
1268
|
+
sessionId: direct.sessionId,
|
|
1269
|
+
...next.childId !== void 0 ? { childId: next.childId } : {},
|
|
1270
|
+
...next.parentSessionId !== void 0 ? { parentSessionId: next.parentSessionId } : {},
|
|
1271
|
+
...next.pendingDraft !== void 0 ? { pendingDraft: next.pendingDraft } : {},
|
|
1272
|
+
...next.boundarySeq !== void 0 ? { boundarySeq: next.boundarySeq } : {},
|
|
1273
|
+
number: direct.number,
|
|
1274
|
+
createdAt: direct.createdAt,
|
|
1275
|
+
...direct.runId !== void 0 ? { runId: direct.runId } : {}
|
|
1276
|
+
});
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
const bs = betterSidebarOf(ctx);
|
|
1280
|
+
if (bs === void 0) return;
|
|
1281
|
+
const current = parseSideChatMeta(readTab(ctx, sessionId, tabId)?.meta);
|
|
1282
|
+
bs.updateTab(tabId, { meta: mutate(current) });
|
|
1283
|
+
}
|
|
1284
|
+
/** 关闭侧聊 tab:直连腿走 ISidebarRight.close,legacy 走 betterSidebar.closeTab。 */
|
|
1285
|
+
function closeSideTab(ctx, tabId, sessionId) {
|
|
1286
|
+
if (directNativeLeg(ctx)) {
|
|
1287
|
+
const face = sidebarRightOf(ctx);
|
|
1288
|
+
if (face !== void 0) {
|
|
1289
|
+
face.close(tabId);
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
betterSidebarOf(ctx)?.closeTab(tabId, { sessionId });
|
|
963
1294
|
}
|
|
964
1295
|
/**
|
|
965
1296
|
* 程序化入口(/side、bridge 划选提问)打开 Tab 时面板可能处于折叠态——
|
|
@@ -1202,6 +1533,49 @@ window.__ModuleLoader__.load({
|
|
|
1202
1533
|
* 持久化:localStorage 按会话键(dsh-sidenote:reflow:v1:<sessionId>),
|
|
1203
1534
|
* 与注释 store 同款纪律(刷新不丢、容错 revive、空删键)。
|
|
1204
1535
|
*/
|
|
1536
|
+
/**
|
|
1537
|
+
* reflow 注入通道(Workitem_06):优先经宿主路由 /sidenote/reflow 以
|
|
1538
|
+
* agent.inject 落父会话日志(plugin-source 独立事件,context row 折叠);
|
|
1539
|
+
* 路由缺席/父会话无 live agent/超时 → 调用方回落搭车形态(发送拦截器
|
|
1540
|
+
* 序列化前缀)。逐个 item 投递;成功项由调用方从 store 移除(不等发送
|
|
1541
|
+
* 确认——注入已入 inbox,chip 消失表达「已注入」)。
|
|
1542
|
+
*
|
|
1543
|
+
* 有界等待:注入尝试绝不能拖住发送手势——300ms 超时即回落搭车。
|
|
1544
|
+
*/
|
|
1545
|
+
const REFLOW_ROUTE_TIMEOUT_MS = 300;
|
|
1546
|
+
/** 尝试经宿主路由注入一批回流项;任何失败都降级为「全未注入」。 */
|
|
1547
|
+
async function tryInjectReflows(parentSessionId, items) {
|
|
1548
|
+
if (items.length === 0) return { injectedIds: /* @__PURE__ */ new Set() };
|
|
1549
|
+
const empty = { injectedIds: /* @__PURE__ */ new Set() };
|
|
1550
|
+
try {
|
|
1551
|
+
const controller = new AbortController();
|
|
1552
|
+
const timer = setTimeout(() => {
|
|
1553
|
+
controller.abort();
|
|
1554
|
+
}, REFLOW_ROUTE_TIMEOUT_MS);
|
|
1555
|
+
let res;
|
|
1556
|
+
try {
|
|
1557
|
+
res = await fetch("/sidenote/reflow", {
|
|
1558
|
+
method: "POST",
|
|
1559
|
+
headers: { "content-type": "application/json" },
|
|
1560
|
+
body: JSON.stringify({
|
|
1561
|
+
parentSessionId,
|
|
1562
|
+
items: items.map((item) => ({
|
|
1563
|
+
text: `以下是用户从侧边对话带回的结论(参考上下文):\n\n${buildReflowBlock(item)}`,
|
|
1564
|
+
sideTitle: item.sideTitle
|
|
1565
|
+
}))
|
|
1566
|
+
}),
|
|
1567
|
+
signal: controller.signal
|
|
1568
|
+
});
|
|
1569
|
+
} finally {
|
|
1570
|
+
clearTimeout(timer);
|
|
1571
|
+
}
|
|
1572
|
+
if (!res.ok) return empty;
|
|
1573
|
+
if ((await res.json()).ok !== true) return empty;
|
|
1574
|
+
return { injectedIds: new Set(items.map((item) => item.id)) };
|
|
1575
|
+
} catch {
|
|
1576
|
+
return empty;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1205
1579
|
const STORAGE_PREFIX$1 = "dsh-sidenote:reflow:v1:";
|
|
1206
1580
|
/**
|
|
1207
1581
|
* 回流块序列化(XML 形态,与注释协议同族):
|
|
@@ -2169,9 +2543,24 @@ window.__ModuleLoader__.load({
|
|
|
2169
2543
|
markdown: markdownChrome()
|
|
2170
2544
|
};
|
|
2171
2545
|
}
|
|
2546
|
+
/** JsonTreeLabels(0.1.5 必填:label + labels 全套)。 */
|
|
2547
|
+
function jsonTreeLabels() {
|
|
2548
|
+
return {
|
|
2549
|
+
copyValue: t("jsonCopyValue"),
|
|
2550
|
+
copyJson: t("jsonCopyJson"),
|
|
2551
|
+
copyPath: t("jsonCopyPath"),
|
|
2552
|
+
copyPrettyJson: t("jsonCopyPretty"),
|
|
2553
|
+
copyCompactJson: t("jsonCopyCompact"),
|
|
2554
|
+
copied: t("codeCopied"),
|
|
2555
|
+
copyFailed: t("jsonCopyFailed"),
|
|
2556
|
+
collapseNode: t("jsonCollapse"),
|
|
2557
|
+
expandNode: t("jsonExpand"),
|
|
2558
|
+
copyButtonTitle: (action) => action
|
|
2559
|
+
};
|
|
2560
|
+
}
|
|
2172
2561
|
//#endregion
|
|
2173
2562
|
//#region \0dsh-css:/home/runner/work/dsh-sidenote/dsh-sidenote/src/client/sidechat/sidechat.module.css.mjs
|
|
2174
|
-
const css$1 = "._5KEEsG_root{height:100%;color:var(--dsw-alias-label-primary);flex-direction:column;font-size:13px;display:flex;position:relative}._5KEEsG_body{flex-direction:column;flex:1;padding:12px 10px;display:flex;overflow-y:auto}._5KEEsG_transcript{flex-direction:column;gap:10px;display:flex}._5KEEsG_empty,._5KEEsG_stateScreen{text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px 16px;display:flex}._5KEEsG_emptyIcon{color:var(--dsw-alias-label-tertiary)}._5KEEsG_emptyTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:600}._5KEEsG_emptyText{color:var(--dsw-alias-label-tertiary);max-width:240px;font-size:12px;line-height:1.6}._5KEEsG_stateDetail{color:var(--dsw-alias-state-error-primary);word-break:break-word;max-width:260px;font-size:12px;line-height:1.6}._5KEEsG_userRow{justify-content:flex-end;display:flex}._5KEEsG_userBubble{background:var(--dsw-specific-bubble,#edf3fe);max-width:88%;color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:16px;padding:8px 12px;font-size:13px;line-height:1.55}._5KEEsG_assistantRow{justify-content:flex-start;display:flex;position:relative}._5KEEsG_rowActions{opacity:0;z-index:2;transition:opacity .12s ease-out;position:absolute;top:-8px;right:0}._5KEEsG_assistantRow:hover ._5KEEsG_rowActions{opacity:1}._5KEEsG_reflowButton{border:1px solid var(--dsw-alias-border-l1,#0000001a);background:var(--dsw-alias-bg-layer-1,#fff);width:22px;height:22px;color:var(--dsw-alias-label-tertiary,#8f959e);cursor:pointer;border-radius:999px;place-items:center;padding:0;display:grid;box-shadow:0 2px 8px #00000014}._5KEEsG_reflowButton:hover{color:var(--dsw-alias-state-business-primary,#2f88ff);border-color:var(--dsw-alias-state-business-primary,#2f88ff)}._5KEEsG_assistantBody{word-break:break-word;max-width:100%;font-size:13px;line-height:1.6}._5KEEsG_reasoning{border-left:3px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);margin-bottom:6px;padding-left:8px;font-size:12px}._5KEEsG_reasoning>summary{cursor:pointer;user-select:none}._5KEEsG_reasoningBody{white-space:pre-wrap;word-break:break-word;color:var(--dsw-alias-label-tertiary);margin-top:2px;padding-bottom:2px;padding-left:22px}._5KEEsG_streamingHint{color:var(--dsw-alias-label-dimmed)}._5KEEsG_toolCard{font-size:12px}._5KEEsG_toolHead{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:12px;display:flex}._5KEEsG_toolError{color:var(--dsw-alias-state-error-primary)}._5KEEsG_toolRunning{color:var(--dsw-alias-label-tertiary)}._5KEEsG_toolBody{color:var(--dsw-alias-label-tertiary);white-space:pre-wrap;word-break:break-word;max-height:160px;padding:2px 0 2px 22px;font-size:12px;overflow-y:auto}._5KEEsG_errorRow{color:var(--dsw-alias-state-error-primary);white-space:pre-wrap;padding:4px 2px;font-size:12px}._5KEEsG_noticeRow{color:var(--dsw-alias-label-dimmed);text-align:center;padding:2px 0;font-size:12px}._5KEEsG_composer{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:6px;padding:8px 10px;display:flex;position:relative}._5KEEsG_composerCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:14px;flex-direction:column;gap:2px;padding:4px 6px 6px;transition:border-color .12s;display:flex}._5KEEsG_composerCard:focus-within{border-color:var(--dsw-alias-state-business-primary)}._5KEEsG_input{resize:none;width:100%;min-height:36px;max-height:160px;color:var(--dsw-alias-label-primary);font:inherit;box-sizing:border-box;background:0 0;border:none;padding:6px 6px 2px}._5KEEsG_input:focus{outline:none}._5KEEsG_composerFoot{justify-content:space-between;align-items:center;gap:8px;padding:0 2px;display:flex}._5KEEsG_modelLabel{color:var(--dsw-alias-label-dimmed);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}._5KEEsG_sendButton,._5KEEsG_stopButton{appearance:none;background:var(--dsw-alias-button-info-fill);color:#fff;cursor:pointer;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;width:28px;height:28px;padding:0;display:inline-flex}._5KEEsG_sendButton:disabled{opacity:.45;cursor:default}._5KEEsG_headerSide{border:1px solid var(--dsw-alias-border-l1,#0000001a);color:var(--dsw-alias-label-secondary,#3f454d);cursor:pointer;user-select:none;background:0 0;border-radius:999px;align-items:center;gap:5px;padding:3px 10px;font-size:12px;line-height:18px;display:inline-flex}._5KEEsG_headerSide:hover{background:var(--dsw-alias-interactive-bg-hover,#0000000d);color:var(--dsw-alias-label-primary,#1f2329)}._5KEEsG_sentChipRow{align-items:center;gap:6px;margin-right:8px;display:inline-flex}._5KEEsG_sentChip{border:1px solid var(--dsw-alias-border-l1,#0000001a);background:var(--dsw-alias-interactive-bg-hover,#0000000d);color:var(--dsw-alias-label-secondary,#3f454d);user-select:none;border-radius:999px;align-items:center;gap:4px;padding:1px 8px;font-size:11px;line-height:16px;display:inline-flex}._5KEEsG_flowRow{font-size:12px}._5KEEsG_rowPreview{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-dimmed);flex:1;margin-left:8px;font-size:12px;overflow:hidden}._5KEEsG_flowRowError{color:var(--dsw-alias-state-error-primary)}._5KEEsG_todoBody{flex-direction:column;gap:3px;padding:2px 0 4px 22px;display:flex}._5KEEsG_todoItem{align-items:baseline;gap:7px;min-width:0;font-size:12px;line-height:1.5;display:flex}._5KEEsG_todoDot{background:var(--dsw-alias-label-dimmed);border-radius:50%;flex:none;width:6px;height:6px;transform:translateY(-1px)}._5KEEsG_todoDot[data-status=completed]{background:var(--dsw-alias-state-success-primary,#34a853)}._5KEEsG_todoDot[data-status=in_progress]{background:var(--dsw-alias-state-business-primary)}._5KEEsG_todoText[data-status=completed]{color:var(--dsw-alias-label-dimmed)}._5KEEsG_toolGenericBody{flex-direction:column;gap:6px;padding:4px 0 4px 22px;display:flex}._5KEEsG_toolBodyText{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;word-break:break-word;font-size:12px;line-height:1.55;font-family:var(--dsw-alias-font-mono,ui-monospace, monospace);margin:0}._5KEEsG_toolLocations{color:var(--dsw-alias-label-tertiary);white-space:pre-wrap;word-break:break-all;font-size:11px}._5KEEsG_inheritedBody{border-top:1px dashed var(--dsw-alias-border-l2);opacity:.92;padding:6px 0 2px}._5KEEsG_densityRow{justify-content:flex-end;align-items:center;padding:2px 2px 4px;display:flex}._5KEEsG_densityToggle{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;padding:2px 6px;font-size:11px}._5KEEsG_densityToggle:hover{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}._5KEEsG_jumpBottom{z-index:5;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);cursor:pointer;border-radius:999px;padding:3px 10px;font-size:11px;position:absolute;bottom:96px;right:12px;box-shadow:0 2px 8px #0000001f}._5KEEsG_jumpBottom:hover{background:var(--dsw-alias-bg-layer-2)}._5KEEsG_modelSelect{color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:6px;align-items:center;gap:3px;max-width:180px;padding:3px 6px;font-size:12px;display:inline-flex;overflow:hidden}._5KEEsG_modelSelect>span:first-child{text-overflow:ellipsis;overflow:hidden}._5KEEsG_modelSelect>svg{color:var(--dsw-alias-label-dimmed);flex:none}._5KEEsG_modelSelect:hover{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}._5KEEsG_composerChips{align-items:center;gap:4px;min-width:0;display:inline-flex;overflow:hidden}._5KEEsG_slashMenu{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);z-index:20;border-radius:10px;max-height:260px;margin-bottom:6px;padding:4px;position:absolute;bottom:100%;left:8px;right:8px;overflow-y:auto;box-shadow:0 8px 24px #00000024}._5KEEsG_slashGroupTitle{color:var(--dsw-alias-label-tertiary);text-transform:none;padding:4px 8px 2px;font-size:11px}._5KEEsG_slashItem,._5KEEsG_slashItemActive{text-align:left;cursor:pointer;width:100%;color:var(--dsw-alias-label-primary);background:0 0;border:none;border-radius:6px;align-items:baseline;gap:8px;padding:6px 8px;font-size:13px;display:flex}._5KEEsG_slashItemActive,._5KEEsG_slashItem:hover{background:var(--dsw-alias-interactive-bg-hover)}._5KEEsG_slashItemName{flex:none;font-weight:500}._5KEEsG_slashItemDetail{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}._5KEEsG_attachRail{flex-wrap:wrap;gap:6px;padding:2px 0;display:flex}._5KEEsG_attachThumb{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;width:44px;height:44px;position:relative;overflow:hidden}._5KEEsG_attachImg{object-fit:cover;width:100%;height:100%;display:block}._5KEEsG_attachRemove{color:#fff;cursor:pointer;background:#0000008c;border:none;border-radius:999px;place-items:center;width:16px;height:16px;padding:0;font-size:11px;line-height:1;display:grid;position:absolute;top:1px;right:1px}._5KEEsG_attachButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:4px;display:inline-flex}._5KEEsG_attachButton:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}._5KEEsG_pendingCard{border:1px solid var(--dsw-alias-border-l2);border-left:3px solid var(--dsw-alias-state-warning-primary,#e8a13a);background:var(--dsw-alias-bg-layer-2);border-radius:10px;flex-direction:column;gap:6px;margin:0 10px 6px;padding:10px 12px;font-size:12px;display:flex}._5KEEsG_pendingHead{color:var(--dsw-alias-state-warning-primary,#e8a13a);align-items:center;gap:6px;display:flex}._5KEEsG_pendingTitle{color:var(--dsw-alias-label-primary);font-weight:600}._5KEEsG_pendingDesc{color:var(--dsw-alias-label-secondary)}._5KEEsG_pendingReason{color:var(--dsw-alias-label-tertiary);white-space:pre-wrap;word-break:break-word}._5KEEsG_pendingQuestion{flex-direction:column;gap:4px;padding:4px 0;display:flex}._5KEEsG_pendingQHeader{color:var(--dsw-alias-label-primary);font-weight:600}._5KEEsG_pendingQText{color:var(--dsw-alias-label-secondary)}._5KEEsG_pendingOption{text-align:left;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:6px;flex-direction:column;align-items:flex-start;gap:2px;padding:5px 8px;font-size:12px;display:flex}._5KEEsG_pendingOption:hover{background:var(--dsw-alias-interactive-bg-hover,#0000000d)}._5KEEsG_pendingOptionActive{text-align:left;border:1px solid var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover,#0000000d);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;flex-direction:column;align-items:flex-start;gap:2px;padding:5px 8px;font-size:12px;display:flex}._5KEEsG_pendingOptionDesc{color:var(--dsw-alias-label-dimmed);font-size:11px}._5KEEsG_pendingCustom{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);font-size:12px;font:inherit;background:0 0;border-radius:6px;padding:5px 8px}._5KEEsG_pendingCustom:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}._5KEEsG_pendingActions{justify-content:flex-end;gap:8px;margin-top:2px;display:flex}._5KEEsG_pendingBtnGhost{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:6px;padding:4px 12px;font-size:12px}._5KEEsG_pendingBtnPrimary{background:var(--dsw-alias-button-info-fill);color:#fff;cursor:pointer;border:none;border-radius:6px;padding:4px 12px;font-size:12px}._5KEEsG_pendingBtnGhost:disabled,._5KEEsG_pendingBtnPrimary:disabled{opacity:.5;cursor:default}._5KEEsG_pendingBar{border:1px solid var(--dsw-alias-state-warning-primary,#d4a017);background:var(--dsw-alias-bg-layer-2);width:calc(100% - 16px);color:var(--dsw-alias-state-warning-primary,#d4a017);text-align:left;cursor:pointer;border-radius:8px;margin:0 8px 6px;padding:6px 10px;font-size:12px;display:block}._5KEEsG_pendingBar:hover{background:var(--dsw-alias-bg-layer-3)}._5KEEsG_writeNotice{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);border-radius:8px;align-items:center;gap:8px;margin:0 8px 6px;padding:6px 10px;font-size:12px;display:flex}._5KEEsG_writeNoticeClose{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;margin-left:auto;padding:0 4px;font-size:13px}._5KEEsG_parentStrip{border:none;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;align-items:center;gap:6px;padding:5px 12px;font-size:11px;display:flex}._5KEEsG_parentStrip:hover{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary)}._5KEEsG_dotRunning,._5KEEsG_dotPending,._5KEEsG_dotIdle{border-radius:999px;flex:none;width:7px;height:7px}._5KEEsG_dotRunning{background:var(--dsw-alias-state-business-primary,#2f88ff);animation:1.2s ease-in-out infinite _5KEEsG_sidechat-pulse}._5KEEsG_dotPending{background:var(--dsw-alias-state-warning-primary,#d4a017)}._5KEEsG_dotIdle{background:var(--dsw-alias-label-dimmed)}@keyframes _5KEEsG_sidechat-pulse{50%{opacity:.45}}._5KEEsG_actionGroup{gap:2px;margin-right:auto;display:inline-flex}";
|
|
2563
|
+
const css$1 = "._5KEEsG_nativeHost{flex-direction:column;height:100%;min-height:0;display:flex}._5KEEsG_root{height:100%;color:var(--dsw-alias-label-primary);flex-direction:column;font-size:13px;display:flex;position:relative}._5KEEsG_body{flex-direction:column;flex:1;padding:12px 10px;display:flex;overflow-y:auto}._5KEEsG_transcript{flex-direction:column;gap:10px;display:flex}._5KEEsG_empty,._5KEEsG_stateScreen{text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px 16px;display:flex}._5KEEsG_emptyIcon{color:var(--dsw-alias-label-tertiary)}._5KEEsG_emptyTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:600}._5KEEsG_emptyText{color:var(--dsw-alias-label-tertiary);max-width:240px;font-size:12px;line-height:1.6}._5KEEsG_stateDetail{color:var(--dsw-alias-state-error-primary);word-break:break-word;max-width:260px;font-size:12px;line-height:1.6}._5KEEsG_userRow{justify-content:flex-end;display:flex}._5KEEsG_userBubble{background:var(--dsw-specific-bubble,#edf3fe);max-width:88%;color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:16px;padding:8px 12px;font-size:13px;line-height:1.55}._5KEEsG_assistantRow{justify-content:flex-start;display:flex;position:relative}._5KEEsG_rowActions{opacity:0;z-index:2;transition:opacity .12s ease-out;position:absolute;top:-8px;right:0}._5KEEsG_assistantRow:hover ._5KEEsG_rowActions{opacity:1}._5KEEsG_reflowButton{border:1px solid var(--dsw-alias-border-l1,#0000001a);background:var(--dsw-alias-bg-layer-1,#fff);width:22px;height:22px;color:var(--dsw-alias-label-tertiary,#8f959e);cursor:pointer;border-radius:999px;place-items:center;padding:0;display:grid;box-shadow:0 2px 8px #00000014}._5KEEsG_reflowButton:hover{color:var(--dsw-alias-state-business-primary,#2f88ff);border-color:var(--dsw-alias-state-business-primary,#2f88ff)}._5KEEsG_assistantBody{word-break:break-word;max-width:100%;font-size:13px;line-height:1.6}._5KEEsG_reasoning{border-left:3px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);margin-bottom:6px;padding-left:8px;font-size:12px}._5KEEsG_reasoning>summary{cursor:pointer;user-select:none}._5KEEsG_reasoningBody{white-space:pre-wrap;word-break:break-word;color:var(--dsw-alias-label-tertiary);margin-top:2px;padding-bottom:2px;padding-left:22px}._5KEEsG_streamingHint{color:var(--dsw-alias-label-dimmed)}._5KEEsG_toolCard{font-size:12px}._5KEEsG_toolHead{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:12px;display:flex}._5KEEsG_toolError{color:var(--dsw-alias-state-error-primary)}._5KEEsG_toolRunning{color:var(--dsw-alias-label-tertiary)}._5KEEsG_toolBody{color:var(--dsw-alias-label-tertiary);white-space:pre-wrap;word-break:break-word;max-height:160px;padding:2px 0 2px 22px;font-size:12px;overflow-y:auto}._5KEEsG_errorRow{color:var(--dsw-alias-state-error-primary);white-space:pre-wrap;padding:4px 2px;font-size:12px}._5KEEsG_noticeRow{color:var(--dsw-alias-label-dimmed);text-align:center;padding:2px 0;font-size:12px}._5KEEsG_composer{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:6px;padding:8px 10px;display:flex;position:relative}._5KEEsG_composerCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:14px;flex-direction:column;gap:2px;padding:4px 6px 6px;transition:border-color .12s;display:flex}._5KEEsG_composerCard:focus-within{border-color:var(--dsw-alias-state-business-primary)}._5KEEsG_input{resize:none;width:100%;min-height:36px;max-height:160px;color:var(--dsw-alias-label-primary);font:inherit;box-sizing:border-box;background:0 0;border:none;padding:6px 6px 2px}._5KEEsG_input:focus{outline:none}._5KEEsG_composerFoot{justify-content:space-between;align-items:center;gap:8px;padding:0 2px;display:flex}._5KEEsG_modelLabel{color:var(--dsw-alias-label-dimmed);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}._5KEEsG_sendButton,._5KEEsG_stopButton{appearance:none;background:var(--dsw-alias-button-info-fill);color:#fff;cursor:pointer;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;width:28px;height:28px;padding:0;display:inline-flex}._5KEEsG_sendButton:disabled{opacity:.45;cursor:default}._5KEEsG_headerSide{border:1px solid var(--dsw-alias-border-l1,#0000001a);color:var(--dsw-alias-label-secondary,#3f454d);cursor:pointer;user-select:none;background:0 0;border-radius:999px;align-items:center;gap:5px;padding:3px 10px;font-size:12px;line-height:18px;display:inline-flex}._5KEEsG_headerSide:hover{background:var(--dsw-alias-interactive-bg-hover,#0000000d);color:var(--dsw-alias-label-primary,#1f2329)}._5KEEsG_sentChipRow{align-items:center;gap:6px;margin-right:8px;display:inline-flex}._5KEEsG_sentChip{border:1px solid var(--dsw-alias-border-l1,#0000001a);background:var(--dsw-alias-interactive-bg-hover,#0000000d);color:var(--dsw-alias-label-secondary,#3f454d);user-select:none;border-radius:999px;align-items:center;gap:4px;padding:1px 8px;font-size:11px;line-height:16px;display:inline-flex}._5KEEsG_flowRow{font-size:12px}._5KEEsG_rowPreview{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-dimmed);flex:1;margin-left:8px;font-size:12px;overflow:hidden}._5KEEsG_flowRowError{color:var(--dsw-alias-state-error-primary)}._5KEEsG_todoBody{flex-direction:column;gap:3px;padding:2px 0 4px 22px;display:flex}._5KEEsG_todoItem{align-items:baseline;gap:7px;min-width:0;font-size:12px;line-height:1.5;display:flex}._5KEEsG_todoDot{background:var(--dsw-alias-label-dimmed);border-radius:50%;flex:none;width:6px;height:6px;transform:translateY(-1px)}._5KEEsG_todoDot[data-status=completed]{background:var(--dsw-alias-state-success-primary,#34a853)}._5KEEsG_todoDot[data-status=in_progress]{background:var(--dsw-alias-state-business-primary)}._5KEEsG_todoText[data-status=completed]{color:var(--dsw-alias-label-dimmed)}._5KEEsG_toolGenericBody{flex-direction:column;gap:6px;padding:4px 0 4px 22px;display:flex}._5KEEsG_toolBodyText{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;word-break:break-word;font-size:12px;line-height:1.55;font-family:var(--dsw-alias-font-mono,ui-monospace, monospace);margin:0}._5KEEsG_toolLocations{color:var(--dsw-alias-label-tertiary);white-space:pre-wrap;word-break:break-all;font-size:11px}._5KEEsG_inheritedBody{border-top:1px dashed var(--dsw-alias-border-l2);opacity:.92;padding:6px 0 2px}._5KEEsG_densityRow{justify-content:flex-end;align-items:center;padding:2px 2px 4px;display:flex}._5KEEsG_densityToggle{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;padding:2px 6px;font-size:11px}._5KEEsG_densityToggle:hover{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}._5KEEsG_jumpBottom{z-index:5;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);cursor:pointer;border-radius:999px;padding:3px 10px;font-size:11px;position:absolute;bottom:96px;right:12px;box-shadow:0 2px 8px #0000001f}._5KEEsG_jumpBottom:hover{background:var(--dsw-alias-bg-layer-2)}._5KEEsG_modelSelect{color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:6px;align-items:center;gap:3px;max-width:180px;padding:3px 6px;font-size:12px;display:inline-flex;overflow:hidden}._5KEEsG_modelSelect>span:first-child{text-overflow:ellipsis;overflow:hidden}._5KEEsG_modelSelect>svg{color:var(--dsw-alias-label-dimmed);flex:none}._5KEEsG_modelSelect:hover{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}._5KEEsG_composerChips{align-items:center;gap:4px;min-width:0;display:inline-flex;overflow:hidden}._5KEEsG_slashMenu{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);z-index:20;border-radius:10px;max-height:260px;margin-bottom:6px;padding:4px;position:absolute;bottom:100%;left:8px;right:8px;overflow-y:auto;box-shadow:0 8px 24px #00000024}._5KEEsG_slashGroupTitle{color:var(--dsw-alias-label-tertiary);text-transform:none;padding:4px 8px 2px;font-size:11px}._5KEEsG_slashItem,._5KEEsG_slashItemActive{text-align:left;cursor:pointer;width:100%;color:var(--dsw-alias-label-primary);background:0 0;border:none;border-radius:6px;align-items:baseline;gap:8px;padding:6px 8px;font-size:13px;display:flex}._5KEEsG_slashItemActive,._5KEEsG_slashItem:hover{background:var(--dsw-alias-interactive-bg-hover)}._5KEEsG_slashItemName{flex:none;font-weight:500}._5KEEsG_slashItemDetail{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}._5KEEsG_attachRail{flex-wrap:wrap;gap:6px;padding:2px 0;display:flex}._5KEEsG_attachThumb{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;width:44px;height:44px;position:relative;overflow:hidden}._5KEEsG_attachImg{object-fit:cover;width:100%;height:100%;display:block}._5KEEsG_attachRemove{color:#fff;cursor:pointer;background:#0000008c;border:none;border-radius:999px;place-items:center;width:16px;height:16px;padding:0;font-size:11px;line-height:1;display:grid;position:absolute;top:1px;right:1px}._5KEEsG_attachButton{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:4px;display:inline-flex}._5KEEsG_attachButton:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}._5KEEsG_pendingCard{border:1px solid var(--dsw-alias-border-l2);border-left:3px solid var(--dsw-alias-state-warning-primary,#e8a13a);background:var(--dsw-alias-bg-layer-2);border-radius:10px;flex-direction:column;gap:6px;margin:0 10px 6px;padding:10px 12px;font-size:12px;display:flex}._5KEEsG_pendingHead{color:var(--dsw-alias-state-warning-primary,#e8a13a);align-items:center;gap:6px;display:flex}._5KEEsG_pendingTitle{color:var(--dsw-alias-label-primary);font-weight:600}._5KEEsG_pendingDesc{color:var(--dsw-alias-label-secondary)}._5KEEsG_pendingReason{color:var(--dsw-alias-label-tertiary);white-space:pre-wrap;word-break:break-word}._5KEEsG_pendingQuestion{flex-direction:column;gap:4px;padding:4px 0;display:flex}._5KEEsG_pendingQHeader{color:var(--dsw-alias-label-primary);font-weight:600}._5KEEsG_pendingQText{color:var(--dsw-alias-label-secondary)}._5KEEsG_pendingOption{text-align:left;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:6px;flex-direction:column;align-items:flex-start;gap:2px;padding:5px 8px;font-size:12px;display:flex}._5KEEsG_pendingOption:hover{background:var(--dsw-alias-interactive-bg-hover,#0000000d)}._5KEEsG_pendingOptionActive{text-align:left;border:1px solid var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover,#0000000d);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;flex-direction:column;align-items:flex-start;gap:2px;padding:5px 8px;font-size:12px;display:flex}._5KEEsG_pendingOptionDesc{color:var(--dsw-alias-label-dimmed);font-size:11px}._5KEEsG_pendingCustom{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);font-size:12px;font:inherit;background:0 0;border-radius:6px;padding:5px 8px}._5KEEsG_pendingCustom:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}._5KEEsG_pendingActions{justify-content:flex-end;gap:8px;margin-top:2px;display:flex}._5KEEsG_pendingBtnGhost{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:6px;padding:4px 12px;font-size:12px}._5KEEsG_pendingBtnPrimary{background:var(--dsw-alias-button-info-fill);color:#fff;cursor:pointer;border:none;border-radius:6px;padding:4px 12px;font-size:12px}._5KEEsG_pendingBtnGhost:disabled,._5KEEsG_pendingBtnPrimary:disabled{opacity:.5;cursor:default}._5KEEsG_pendingBar{border:1px solid var(--dsw-alias-state-warning-primary,#d4a017);background:var(--dsw-alias-bg-layer-2);width:calc(100% - 16px);color:var(--dsw-alias-state-warning-primary,#d4a017);text-align:left;cursor:pointer;border-radius:8px;margin:0 8px 6px;padding:6px 10px;font-size:12px;display:block}._5KEEsG_pendingBar:hover{background:var(--dsw-alias-bg-layer-3)}._5KEEsG_writeNotice{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);border-radius:8px;align-items:center;gap:8px;margin:0 8px 6px;padding:6px 10px;font-size:12px;display:flex}._5KEEsG_writeNoticeClose{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;margin-left:auto;padding:0 4px;font-size:13px}._5KEEsG_parentStrip{border:none;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;align-items:center;gap:6px;padding:5px 12px;font-size:11px;display:flex}._5KEEsG_parentStrip:hover{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary)}._5KEEsG_dotRunning,._5KEEsG_dotPending,._5KEEsG_dotIdle{border-radius:999px;flex:none;width:7px;height:7px}._5KEEsG_dotRunning{background:var(--dsw-alias-state-business-primary,#2f88ff);animation:1.2s ease-in-out infinite _5KEEsG_sidechat-pulse}._5KEEsG_dotPending{background:var(--dsw-alias-state-warning-primary,#d4a017)}._5KEEsG_dotIdle{background:var(--dsw-alias-label-dimmed)}@keyframes _5KEEsG_sidechat-pulse{50%{opacity:.45}}._5KEEsG_actionGroup{gap:2px;margin-right:auto;display:inline-flex}";
|
|
2175
2564
|
const tagId$1 = "dsh-sidenote/sidechat.module.css";
|
|
2176
2565
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
2177
2566
|
const tag = document.createElement("style");
|
|
@@ -2181,92 +2570,93 @@ window.__ModuleLoader__.load({
|
|
|
2181
2570
|
document.head.appendChild(tag);
|
|
2182
2571
|
}
|
|
2183
2572
|
var sidechat_module_css_default = {
|
|
2184
|
-
"
|
|
2573
|
+
"slashItemName": "_5KEEsG_slashItemName",
|
|
2574
|
+
"slashGroupTitle": "_5KEEsG_slashGroupTitle",
|
|
2575
|
+
"toolCard": "_5KEEsG_toolCard",
|
|
2576
|
+
"pendingOptionDesc": "_5KEEsG_pendingOptionDesc",
|
|
2185
2577
|
"composerCard": "_5KEEsG_composerCard",
|
|
2186
|
-
"attachRail": "_5KEEsG_attachRail",
|
|
2187
|
-
"reasoningBody": "_5KEEsG_reasoningBody",
|
|
2188
2578
|
"empty": "_5KEEsG_empty",
|
|
2189
|
-
"
|
|
2190
|
-
"
|
|
2191
|
-
"
|
|
2192
|
-
"
|
|
2193
|
-
"
|
|
2194
|
-
"
|
|
2195
|
-
"
|
|
2579
|
+
"pendingBtnPrimary": "_5KEEsG_pendingBtnPrimary",
|
|
2580
|
+
"pendingCustom": "_5KEEsG_pendingCustom",
|
|
2581
|
+
"userRow": "_5KEEsG_userRow",
|
|
2582
|
+
"assistantRow": "_5KEEsG_assistantRow",
|
|
2583
|
+
"pendingBtnGhost": "_5KEEsG_pendingBtnGhost",
|
|
2584
|
+
"pendingHead": "_5KEEsG_pendingHead",
|
|
2585
|
+
"attachRail": "_5KEEsG_attachRail",
|
|
2586
|
+
"toolHead": "_5KEEsG_toolHead",
|
|
2587
|
+
"toolError": "_5KEEsG_toolError",
|
|
2588
|
+
"body": "_5KEEsG_body",
|
|
2589
|
+
"rowActions": "_5KEEsG_rowActions",
|
|
2196
2590
|
"rowPreview": "_5KEEsG_rowPreview",
|
|
2591
|
+
"flowRowError": "_5KEEsG_flowRowError",
|
|
2592
|
+
"attachRemove": "_5KEEsG_attachRemove",
|
|
2593
|
+
"pendingDesc": "_5KEEsG_pendingDesc",
|
|
2594
|
+
"pendingActions": "_5KEEsG_pendingActions",
|
|
2595
|
+
"pendingQHeader": "_5KEEsG_pendingQHeader",
|
|
2596
|
+
"parentStrip": "_5KEEsG_parentStrip",
|
|
2597
|
+
"pendingTitle": "_5KEEsG_pendingTitle",
|
|
2598
|
+
"toolBodyText": "_5KEEsG_toolBodyText",
|
|
2599
|
+
"errorRow": "_5KEEsG_errorRow",
|
|
2600
|
+
"todoItem": "_5KEEsG_todoItem",
|
|
2601
|
+
"userBubble": "_5KEEsG_userBubble",
|
|
2197
2602
|
"reflowButton": "_5KEEsG_reflowButton",
|
|
2198
|
-
"
|
|
2603
|
+
"toolBody": "_5KEEsG_toolBody",
|
|
2604
|
+
"attachButton": "_5KEEsG_attachButton",
|
|
2605
|
+
"toolRunning": "_5KEEsG_toolRunning",
|
|
2199
2606
|
"toolGenericBody": "_5KEEsG_toolGenericBody",
|
|
2200
|
-
"
|
|
2201
|
-
"
|
|
2202
|
-
"
|
|
2607
|
+
"emptyIcon": "_5KEEsG_emptyIcon",
|
|
2608
|
+
"attachThumb": "_5KEEsG_attachThumb",
|
|
2609
|
+
"assistantBody": "_5KEEsG_assistantBody",
|
|
2610
|
+
"pendingReason": "_5KEEsG_pendingReason",
|
|
2611
|
+
"pendingCard": "_5KEEsG_pendingCard",
|
|
2612
|
+
"slashItem": "_5KEEsG_slashItem",
|
|
2613
|
+
"dotPending": "_5KEEsG_dotPending",
|
|
2614
|
+
"toolLocations": "_5KEEsG_toolLocations",
|
|
2615
|
+
"todoDot": "_5KEEsG_todoDot",
|
|
2616
|
+
"pendingBar": "_5KEEsG_pendingBar",
|
|
2617
|
+
"dotIdle": "_5KEEsG_dotIdle",
|
|
2203
2618
|
"inheritedBody": "_5KEEsG_inheritedBody",
|
|
2204
|
-
"
|
|
2619
|
+
"slashItemActive": "_5KEEsG_slashItemActive",
|
|
2205
2620
|
"pendingOption": "_5KEEsG_pendingOption",
|
|
2206
2621
|
"pendingOptionActive": "_5KEEsG_pendingOptionActive",
|
|
2207
|
-
"rowActions": "_5KEEsG_rowActions",
|
|
2208
|
-
"stateScreen": "_5KEEsG_stateScreen",
|
|
2209
|
-
"pendingActions": "_5KEEsG_pendingActions",
|
|
2210
|
-
"pendingBtnGhost": "_5KEEsG_pendingBtnGhost",
|
|
2211
|
-
"actionGroup": "_5KEEsG_actionGroup",
|
|
2212
|
-
"toolHead": "_5KEEsG_toolHead",
|
|
2213
|
-
"toolBodyText": "_5KEEsG_toolBodyText",
|
|
2214
|
-
"sidechat-pulse": "_5KEEsG_sidechat-pulse",
|
|
2215
|
-
"assistantBody": "_5KEEsG_assistantBody",
|
|
2216
|
-
"todoDot": "_5KEEsG_todoDot",
|
|
2217
2622
|
"todoBody": "_5KEEsG_todoBody",
|
|
2218
|
-
"
|
|
2219
|
-
"
|
|
2220
|
-
"
|
|
2221
|
-
"attachButton": "_5KEEsG_attachButton",
|
|
2222
|
-
"densityToggle": "_5KEEsG_densityToggle",
|
|
2223
|
-
"composerFoot": "_5KEEsG_composerFoot",
|
|
2224
|
-
"stopButton": "_5KEEsG_stopButton",
|
|
2225
|
-
"slashItemActive": "_5KEEsG_slashItemActive",
|
|
2226
|
-
"slashMenu": "_5KEEsG_slashMenu",
|
|
2227
|
-
"writeNotice": "_5KEEsG_writeNotice",
|
|
2623
|
+
"attachImg": "_5KEEsG_attachImg",
|
|
2624
|
+
"stateScreen": "_5KEEsG_stateScreen",
|
|
2625
|
+
"emptyText": "_5KEEsG_emptyText",
|
|
2228
2626
|
"input": "_5KEEsG_input",
|
|
2627
|
+
"reasoningBody": "_5KEEsG_reasoningBody",
|
|
2628
|
+
"modelLabel": "_5KEEsG_modelLabel",
|
|
2229
2629
|
"densityRow": "_5KEEsG_densityRow",
|
|
2230
|
-
"
|
|
2231
|
-
"
|
|
2232
|
-
"pendingQuestion": "_5KEEsG_pendingQuestion",
|
|
2233
|
-
"todoText": "_5KEEsG_todoText",
|
|
2234
|
-
"pendingReason": "_5KEEsG_pendingReason",
|
|
2235
|
-
"pendingBtnPrimary": "_5KEEsG_pendingBtnPrimary",
|
|
2236
|
-
"dotIdle": "_5KEEsG_dotIdle",
|
|
2237
|
-
"assistantRow": "_5KEEsG_assistantRow",
|
|
2238
|
-
"flowRow": "_5KEEsG_flowRow",
|
|
2239
|
-
"userRow": "_5KEEsG_userRow",
|
|
2240
|
-
"toolCard": "_5KEEsG_toolCard",
|
|
2241
|
-
"errorRow": "_5KEEsG_errorRow",
|
|
2630
|
+
"densityToggle": "_5KEEsG_densityToggle",
|
|
2631
|
+
"transcript": "_5KEEsG_transcript",
|
|
2242
2632
|
"noticeRow": "_5KEEsG_noticeRow",
|
|
2633
|
+
"slashMenu": "_5KEEsG_slashMenu",
|
|
2634
|
+
"pendingQText": "_5KEEsG_pendingQText",
|
|
2243
2635
|
"slashItemDetail": "_5KEEsG_slashItemDetail",
|
|
2244
|
-
"
|
|
2245
|
-
"
|
|
2246
|
-
"
|
|
2247
|
-
"
|
|
2248
|
-
"
|
|
2249
|
-
"parentStrip": "_5KEEsG_parentStrip",
|
|
2636
|
+
"dotRunning": "_5KEEsG_dotRunning",
|
|
2637
|
+
"sidechat-pulse": "_5KEEsG_sidechat-pulse",
|
|
2638
|
+
"composer": "_5KEEsG_composer",
|
|
2639
|
+
"sentChip": "_5KEEsG_sentChip",
|
|
2640
|
+
"reasoning": "_5KEEsG_reasoning",
|
|
2250
2641
|
"modelSelect": "_5KEEsG_modelSelect",
|
|
2251
|
-
"
|
|
2252
|
-
"
|
|
2253
|
-
"
|
|
2642
|
+
"stateDetail": "_5KEEsG_stateDetail",
|
|
2643
|
+
"stopButton": "_5KEEsG_stopButton",
|
|
2644
|
+
"nativeHost": "_5KEEsG_nativeHost",
|
|
2645
|
+
"writeNotice": "_5KEEsG_writeNotice",
|
|
2254
2646
|
"writeNoticeClose": "_5KEEsG_writeNoticeClose",
|
|
2255
|
-
"
|
|
2256
|
-
"
|
|
2257
|
-
"
|
|
2258
|
-
"
|
|
2259
|
-
"
|
|
2260
|
-
"composer": "_5KEEsG_composer",
|
|
2647
|
+
"headerSide": "_5KEEsG_headerSide",
|
|
2648
|
+
"flowRow": "_5KEEsG_flowRow",
|
|
2649
|
+
"actionGroup": "_5KEEsG_actionGroup",
|
|
2650
|
+
"todoText": "_5KEEsG_todoText",
|
|
2651
|
+
"root": "_5KEEsG_root",
|
|
2261
2652
|
"emptyTitle": "_5KEEsG_emptyTitle",
|
|
2262
|
-
"
|
|
2263
|
-
"
|
|
2264
|
-
"
|
|
2265
|
-
"
|
|
2266
|
-
"
|
|
2267
|
-
"
|
|
2268
|
-
"
|
|
2269
|
-
"pendingCard": "_5KEEsG_pendingCard"
|
|
2653
|
+
"streamingHint": "_5KEEsG_streamingHint",
|
|
2654
|
+
"composerFoot": "_5KEEsG_composerFoot",
|
|
2655
|
+
"sentChipRow": "_5KEEsG_sentChipRow",
|
|
2656
|
+
"jumpBottom": "_5KEEsG_jumpBottom",
|
|
2657
|
+
"pendingQuestion": "_5KEEsG_pendingQuestion",
|
|
2658
|
+
"composerChips": "_5KEEsG_composerChips",
|
|
2659
|
+
"sendButton": "_5KEEsG_sendButton"
|
|
2270
2660
|
};
|
|
2271
2661
|
//#endregion
|
|
2272
2662
|
//#region src/client/chat/ToolCard.tsx
|
|
@@ -2403,7 +2793,11 @@ window.__ModuleLoader__.load({
|
|
|
2403
2793
|
m.rawInput !== void 0 && (typeof m.rawInput === "string" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
2404
2794
|
className: sidechat_module_css_default.toolBodyText,
|
|
2405
2795
|
children: m.rawInput
|
|
2406
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.JsonTree, {
|
|
2796
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.JsonTree, {
|
|
2797
|
+
label: t("jsonTreeLabel"),
|
|
2798
|
+
labels: jsonTreeLabels(),
|
|
2799
|
+
data: m.rawInput
|
|
2800
|
+
})),
|
|
2407
2801
|
m.locations !== void 0 && m.locations.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2408
2802
|
className: sidechat_module_css_default.toolLocations,
|
|
2409
2803
|
children: m.locations.map((l) => `${l.path}${l.line !== void 0 ? `:${l.line}` : ""}`).join("\n")
|
|
@@ -3647,6 +4041,11 @@ window.__ModuleLoader__.load({
|
|
|
3647
4041
|
const childId = meta.childId;
|
|
3648
4042
|
const [forkError, setForkError] = (0, react.useState)(null);
|
|
3649
4043
|
const forkStarted = (0, react.useRef)(false);
|
|
4044
|
+
const prevChildId = (0, react.useRef)(childId);
|
|
4045
|
+
(0, react.useEffect)(() => {
|
|
4046
|
+
if (prevChildId.current !== void 0 && childId === void 0) forkStarted.current = false;
|
|
4047
|
+
prevChildId.current = childId;
|
|
4048
|
+
}, [childId]);
|
|
3650
4049
|
const { store } = props;
|
|
3651
4050
|
(0, react.useEffect)(() => {
|
|
3652
4051
|
ensurePanelOpen(store);
|
|
@@ -3719,7 +4118,7 @@ window.__ModuleLoader__.load({
|
|
|
3719
4118
|
(0, react.useEffect)(() => {
|
|
3720
4119
|
if (pendingDraft === void 0 || pendingDraft === "" || phase !== "chat") return;
|
|
3721
4120
|
composer.appendDraft(pendingDraft);
|
|
3722
|
-
updateTabMeta(ctx, tab.id, clearPendingDraft);
|
|
4121
|
+
updateTabMeta(ctx, scope.sessionId, tab.id, clearPendingDraft);
|
|
3723
4122
|
requestAnimationFrame(() => {
|
|
3724
4123
|
rootRef.current?.querySelector("textarea")?.focus();
|
|
3725
4124
|
});
|
|
@@ -3739,10 +4138,10 @@ window.__ModuleLoader__.load({
|
|
|
3739
4138
|
titleRef.current = tab.title;
|
|
3740
4139
|
(0, react.useEffect)(() => {
|
|
3741
4140
|
const metaNow = parseSideChatMeta(metaRef.current);
|
|
3742
|
-
if (
|
|
4141
|
+
if (directNativeLeg(ctx) && metaNow.childId !== void 0) dropClosedSideChat(scope.sessionId, metaNow.childId);
|
|
3743
4142
|
const dispose = registerLiveSideChat(scope.sessionId, tab.id, (text) => {
|
|
3744
4143
|
if (phaseRef.current !== "chat") {
|
|
3745
|
-
updateTabMeta(ctx, tab.id, (m) => ({
|
|
4144
|
+
updateTabMeta(ctx, scope.sessionId, tab.id, (m) => ({
|
|
3746
4145
|
...m,
|
|
3747
4146
|
pendingDraft: appendDraftText(m.pendingDraft ?? "", text)
|
|
3748
4147
|
}));
|
|
@@ -3755,7 +4154,7 @@ window.__ModuleLoader__.load({
|
|
|
3755
4154
|
}, () => metaRef.current, () => titleRef.current);
|
|
3756
4155
|
return () => {
|
|
3757
4156
|
dispose();
|
|
3758
|
-
if (
|
|
4157
|
+
if (directNativeLeg(ctx)) {
|
|
3759
4158
|
const m = parseSideChatMeta(metaRef.current);
|
|
3760
4159
|
if (m.childId !== void 0 && m.parentSessionId !== void 0) recordClosedSideChat(m.parentSessionId, {
|
|
3761
4160
|
childId: m.childId,
|
|
@@ -3779,7 +4178,7 @@ window.__ModuleLoader__.load({
|
|
|
3779
4178
|
increaseTitle: true
|
|
3780
4179
|
});
|
|
3781
4180
|
ctx.sessions.open(promoted);
|
|
3782
|
-
ctx
|
|
4181
|
+
closeSideTab(ctx, tab.id, scope.sessionId);
|
|
3783
4182
|
showToast(t("promoteDone"));
|
|
3784
4183
|
} catch (error) {
|
|
3785
4184
|
console.warn("[dsh-sidenote] 保存为正式会话失败:", error);
|
|
@@ -3940,6 +4339,216 @@ window.__ModuleLoader__.load({
|
|
|
3940
4339
|
});
|
|
3941
4340
|
}
|
|
3942
4341
|
//#endregion
|
|
4342
|
+
//#region src/client/sidechat/native-tab.tsx
|
|
4343
|
+
/**
|
|
4344
|
+
* 直连注册层(Workitem_02):侧聊 tab 类型直连 DSH 原生右栏(≥ 0.1.5-rc.1)。
|
|
4345
|
+
*
|
|
4346
|
+
* better-sidebar 0.19+ 把右栏让渡给原生 sidebarRight 后只剩纯转发——本模块
|
|
4347
|
+
* 绕开转发层,把侧聊类型直接注册进原生面:
|
|
4348
|
+
*
|
|
4349
|
+
* - 类型注册必须**等服务**(ctx.inject(['sidebarRightTabs']))而非等槽声明:
|
|
4350
|
+
* 原生栏先声明 sidebar.right.pane.tab 槽、约 3 秒后才 provide 注册表服务,
|
|
4351
|
+
* 等槽触发会永久静默不注册(better-sidebar native/index.ts 的真机教训)。
|
|
4352
|
+
* - 面板体挂 sidebar.right.pane.tab keyed 槽(key = 注册实现 id);
|
|
4353
|
+
* 芯片活标题挂 sidebar.right.pane.tab.title 槽(编号读 metaStore)。
|
|
4354
|
+
* - meta 无原生面(原生布局 memory-only):全部走自有 metaStore;
|
|
4355
|
+
* openTab → 面板挂载的窗口期内,初始值(parentSessionId/pendingDraft/恢复
|
|
4356
|
+
* 用的 childId)经 openTab params 随宿主管道投递,面板挂载时落进 store。
|
|
4357
|
+
*
|
|
4358
|
+
* 单实例语义(Delivery_01):held 规则下同 pane 同 kind 去重,「新建」由
|
|
4359
|
+
* 编排层折叠为聚焦既有(open.ts),注册层不感知;多实例等 Delivery_02
|
|
4360
|
+
* 的 multiple(0.1.6+)放开。
|
|
4361
|
+
*/
|
|
4362
|
+
/** 原生注册表里的实现 id(槽 key;kind 沿用 SIDE_TAB_TYPE 保持自文档化)。 */
|
|
4363
|
+
const NATIVE_IMPL_ID = "dsh-sidenote:side-chat";
|
|
4364
|
+
function parseOpenParams(params) {
|
|
4365
|
+
if (typeof params !== "object" || params === null) return void 0;
|
|
4366
|
+
const p = params;
|
|
4367
|
+
if (typeof p.parentSessionId !== "string" || p.parentSessionId === "") return void 0;
|
|
4368
|
+
return {
|
|
4369
|
+
parentSessionId: p.parentSessionId,
|
|
4370
|
+
...typeof p.pendingDraft === "string" && p.pendingDraft !== "" ? { pendingDraft: p.pendingDraft } : {},
|
|
4371
|
+
...typeof p.childId === "string" && p.childId !== "" ? { childId: p.childId } : {}
|
|
4372
|
+
};
|
|
4373
|
+
}
|
|
4374
|
+
/**
|
|
4375
|
+
* 渲染期把 params 的初始值幂等落进 metaStore(静默写,不 notify——渲染期
|
|
4376
|
+
* notify 会让订阅者(title 槽)触发 React「渲染中更新」警告;由调用方在
|
|
4377
|
+
* effect 里补 notify)。必须在渲染期完成:子组件 SideChatPanel 的 fork
|
|
4378
|
+
* effect 先于本组件的 effect 执行(React effect 自底向上),reopen 场景
|
|
4379
|
+
* 若在 effect 里登记,子面板会先按「无 childId」错误地重新 fork 出孤儿会话。
|
|
4380
|
+
* @returns true = 本次新建了记录(调用方 effect 里补 notify)。
|
|
4381
|
+
*/
|
|
4382
|
+
function reconcileMeta(record, sessionId) {
|
|
4383
|
+
const existing = readSideChatMeta(sessionId, record.id);
|
|
4384
|
+
if (existing !== void 0) return {
|
|
4385
|
+
created: false,
|
|
4386
|
+
meta: existing
|
|
4387
|
+
};
|
|
4388
|
+
const params = parseOpenParams(record.navigation.params);
|
|
4389
|
+
const meta = {
|
|
4390
|
+
tabId: record.id,
|
|
4391
|
+
sessionId,
|
|
4392
|
+
...params?.childId !== void 0 ? { childId: params.childId } : {},
|
|
4393
|
+
parentSessionId: params?.parentSessionId ?? sessionId,
|
|
4394
|
+
...params?.pendingDraft !== void 0 ? { pendingDraft: params.pendingDraft } : {},
|
|
4395
|
+
number: nextSideChatNumber(sessionId),
|
|
4396
|
+
createdAt: Date.now(),
|
|
4397
|
+
runId: SIDENOTE_RUN_ID
|
|
4398
|
+
};
|
|
4399
|
+
writeSideChatMeta(meta, { silent: true });
|
|
4400
|
+
return {
|
|
4401
|
+
created: true,
|
|
4402
|
+
meta
|
|
4403
|
+
};
|
|
4404
|
+
}
|
|
4405
|
+
/** 芯片标题:metaStore 的编号兑现(「侧边」/「侧边 N」)。 */
|
|
4406
|
+
function titleOf(sessionId, tabId) {
|
|
4407
|
+
const meta = readSideChatMeta(sessionId, tabId);
|
|
4408
|
+
if (meta === void 0 || meta.number <= 1) return t("tabBaseTitle");
|
|
4409
|
+
return `${t("tabBaseTitle")} ${meta.number}`;
|
|
4410
|
+
}
|
|
4411
|
+
/** 面板体外壳:把 useTabInfo(可能对未提交 record throw)也包进错误边界。 */
|
|
4412
|
+
function NativeSideChatBody(props) {
|
|
4413
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NativeTabBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NativeSideChatBodyInner, { ...props }) });
|
|
4414
|
+
}
|
|
4415
|
+
/** 面板体:原生 tab → SideChatPanel 的 TabComponentProps 合成适配。 */
|
|
4416
|
+
function NativeSideChatBodyInner(props) {
|
|
4417
|
+
const { ctx, sessionId, reflow, useTabInfo } = props;
|
|
4418
|
+
const nativeTab = useTabInfo().tab;
|
|
4419
|
+
const { created, meta: reconciledMeta } = reconcileMeta(nativeTab, sessionId);
|
|
4420
|
+
const createdRef = (0, react.useRef)(false);
|
|
4421
|
+
if (created) createdRef.current = true;
|
|
4422
|
+
(0, react.useEffect)(() => {
|
|
4423
|
+
if (createdRef.current) {
|
|
4424
|
+
createdRef.current = false;
|
|
4425
|
+
notifySideChatMetaListeners();
|
|
4426
|
+
}
|
|
4427
|
+
}, []);
|
|
4428
|
+
const cwd = useSessionCwd(ctx, sessionId);
|
|
4429
|
+
const scope = (0, react.useMemo)(() => ({
|
|
4430
|
+
sessionId,
|
|
4431
|
+
...cwd !== void 0 ? { cwd } : {}
|
|
4432
|
+
}), [sessionId, cwd]);
|
|
4433
|
+
(0, react.useSyncExternalStore)(sideChatMetaStore.subscribe, sideChatMetaStore.getSnapshot);
|
|
4434
|
+
const meta = readSideChatMeta(sessionId, nativeTab.id) ?? reconciledMeta;
|
|
4435
|
+
const tabSignal = nativeTab.signal;
|
|
4436
|
+
(0, react.useEffect)(() => {
|
|
4437
|
+
const onAbort = () => {
|
|
4438
|
+
dropSideChatMeta(sessionId, nativeTab.id);
|
|
4439
|
+
};
|
|
4440
|
+
if (tabSignal.aborted) {
|
|
4441
|
+
onAbort();
|
|
4442
|
+
return;
|
|
4443
|
+
}
|
|
4444
|
+
tabSignal.addEventListener("abort", onAbort, { once: true });
|
|
4445
|
+
return () => {
|
|
4446
|
+
tabSignal.removeEventListener("abort", onAbort);
|
|
4447
|
+
};
|
|
4448
|
+
}, [
|
|
4449
|
+
nativeTab.id,
|
|
4450
|
+
tabSignal,
|
|
4451
|
+
sessionId
|
|
4452
|
+
]);
|
|
4453
|
+
const tab = {
|
|
4454
|
+
id: nativeTab.id,
|
|
4455
|
+
type: SIDE_TAB_TYPE,
|
|
4456
|
+
title: titleOf(sessionId, nativeTab.id),
|
|
4457
|
+
...meta === void 0 ? {} : { meta }
|
|
4458
|
+
};
|
|
4459
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4460
|
+
className: sidechat_module_css_default.nativeHost,
|
|
4461
|
+
"data-dsh-sidenote-native-host": "",
|
|
4462
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideChatPanel, {
|
|
4463
|
+
ctx,
|
|
4464
|
+
store: void 0,
|
|
4465
|
+
scope,
|
|
4466
|
+
tab,
|
|
4467
|
+
visible: nativeTab.visible,
|
|
4468
|
+
reflow
|
|
4469
|
+
})
|
|
4470
|
+
});
|
|
4471
|
+
}
|
|
4472
|
+
/** 极简错误边界:渲染期 throw 兜成错误态,不逃到原生 seat(直连后不再有
|
|
4473
|
+
* better-sidebar 的 RenderBoundary 包裹)。 */
|
|
4474
|
+
var NativeTabBoundary = class extends react.Component {
|
|
4475
|
+
state = { error: null };
|
|
4476
|
+
static getDerivedStateFromError(error) {
|
|
4477
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
4478
|
+
}
|
|
4479
|
+
componentDidCatch(error) {
|
|
4480
|
+
console.warn("[dsh-sidenote] 侧聊面板渲染崩溃:", error);
|
|
4481
|
+
}
|
|
4482
|
+
render() {
|
|
4483
|
+
if (this.state.error !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4484
|
+
style: {
|
|
4485
|
+
padding: 16,
|
|
4486
|
+
fontSize: 13
|
|
4487
|
+
},
|
|
4488
|
+
children: [t("sideChatCrashed"), this.state.error]
|
|
4489
|
+
});
|
|
4490
|
+
return this.props.children;
|
|
4491
|
+
}
|
|
4492
|
+
};
|
|
4493
|
+
/** 芯片活标题:metaStore 订阅 + 编号标题。 */
|
|
4494
|
+
function NativeSideChatTitle(props) {
|
|
4495
|
+
const { useTabInfo } = props;
|
|
4496
|
+
const info = useTabInfo();
|
|
4497
|
+
(0, react.useSyncExternalStore)(sideChatMetaStore.subscribe, sideChatMetaStore.getSnapshot);
|
|
4498
|
+
return titleOf(props.sessionId, info.tab.id);
|
|
4499
|
+
}
|
|
4500
|
+
/** 会话工作区根(better-sidebar useSessionCwd 同款)。 */
|
|
4501
|
+
function useSessionCwd(ctx, sessionId) {
|
|
4502
|
+
return (0, react.useSyncExternalStore)((0, react.useMemo)(() => (listener) => ctx.sessions.list.subscribe(listener), [ctx]), () => {
|
|
4503
|
+
return (ctx.sessions.list.getSnapshot().byId?.[sessionId])?.cwd;
|
|
4504
|
+
});
|
|
4505
|
+
}
|
|
4506
|
+
/**
|
|
4507
|
+
* 直连注册:类型 + body/title 槽。返回 disposer(插件 fiber 撤销时清场)。
|
|
4508
|
+
* 探测与分腿在调用方(sidechat/index.tsx);本函数只在 sidebarRightTabs
|
|
4509
|
+
* 存在时被调用。
|
|
4510
|
+
*/
|
|
4511
|
+
function registerNativeSideChatTab(ctx, reflow) {
|
|
4512
|
+
ctx.inject(["sidebarRightTabs"], (injected) => {
|
|
4513
|
+
const tabs = injected.get("sidebarRightTabs");
|
|
4514
|
+
if (tabs === void 0) return;
|
|
4515
|
+
const disposeType = tabs.register({
|
|
4516
|
+
id: NATIVE_IMPL_ID,
|
|
4517
|
+
kind: SIDE_TAB_TYPE,
|
|
4518
|
+
priority: "extension",
|
|
4519
|
+
title: () => t("tabBaseTitle"),
|
|
4520
|
+
guide: [{
|
|
4521
|
+
order: 60,
|
|
4522
|
+
title: () => t("menuTitle"),
|
|
4523
|
+
icon: (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconNewChatOutline16, { size: props.size ?? 16 })
|
|
4524
|
+
}]
|
|
4525
|
+
});
|
|
4526
|
+
const disposeBody = ctx.slots.inject("sidebar.right.pane.tab", () => ctx.slots.register({
|
|
4527
|
+
name: "sidebar.right.pane.tab",
|
|
4528
|
+
key: NATIVE_IMPL_ID,
|
|
4529
|
+
inject: (sessionId) => ({
|
|
4530
|
+
ctx,
|
|
4531
|
+
sessionId,
|
|
4532
|
+
reflow
|
|
4533
|
+
})
|
|
4534
|
+
}, NativeSideChatBody));
|
|
4535
|
+
const disposeTitle = ctx.slots.inject("sidebar.right.pane.tab.title", () => ctx.slots.register({
|
|
4536
|
+
name: "sidebar.right.pane.tab.title",
|
|
4537
|
+
key: NATIVE_IMPL_ID,
|
|
4538
|
+
inject: (sessionId) => ({
|
|
4539
|
+
ctx,
|
|
4540
|
+
sessionId,
|
|
4541
|
+
reflow
|
|
4542
|
+
})
|
|
4543
|
+
}, NativeSideChatTitle));
|
|
4544
|
+
return () => {
|
|
4545
|
+
disposeBody();
|
|
4546
|
+
disposeTitle();
|
|
4547
|
+
disposeType();
|
|
4548
|
+
};
|
|
4549
|
+
});
|
|
4550
|
+
}
|
|
4551
|
+
//#endregion
|
|
3943
4552
|
//#region src/client/sidechat/header.tsx
|
|
3944
4553
|
/**
|
|
3945
4554
|
* 顶栏「侧边」入口(Delivery_02 Workitem_02 发现性):注册进宿主的
|
|
@@ -3996,21 +4605,32 @@ window.__ModuleLoader__.load({
|
|
|
3996
4605
|
kind: "popupSelect",
|
|
3997
4606
|
options: (session) => {
|
|
3998
4607
|
const options = [];
|
|
3999
|
-
const native =
|
|
4608
|
+
const native = directNativeLeg(ctx);
|
|
4000
4609
|
const lives = native ? liveSideChatsOf(session.sessionId) : [];
|
|
4610
|
+
const liveIds = new Set(lives.map((live) => live.tabId));
|
|
4611
|
+
const unloaded = native ? sideChatMetasOf(session.sessionId).filter((meta) => !liveIds.has(meta.tabId)) : [];
|
|
4001
4612
|
if (!native || lives.length === 0) options.push({
|
|
4002
4613
|
id: "new",
|
|
4003
4614
|
label: t("cmdNew"),
|
|
4004
4615
|
detail: t("cmdNewDetail")
|
|
4005
4616
|
});
|
|
4006
|
-
if (native)
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
const
|
|
4013
|
-
|
|
4617
|
+
if (native) {
|
|
4618
|
+
for (const live of lives) options.push({
|
|
4619
|
+
id: `focus:${live.tabId}`,
|
|
4620
|
+
label: t("cmdFocus", { title: live.readTitle() }),
|
|
4621
|
+
detail: t("cmdFocusDetail")
|
|
4622
|
+
});
|
|
4623
|
+
for (const meta of unloaded) {
|
|
4624
|
+
const title = meta.number <= 1 ? t("tabBaseTitle") : `${t("tabBaseTitle")} ${meta.number}`;
|
|
4625
|
+
options.push({
|
|
4626
|
+
id: `focus:${meta.tabId}`,
|
|
4627
|
+
label: t("cmdFocus", { title }),
|
|
4628
|
+
detail: t("cmdFocusDetail")
|
|
4629
|
+
});
|
|
4630
|
+
}
|
|
4631
|
+
} else {
|
|
4632
|
+
const snapshot = betterSidebarOf(ctx)?.getSnapshot();
|
|
4633
|
+
if (snapshot !== void 0 && snapshot.sessionId === session.sessionId && snapshot.state !== void 0) for (const tab of collectSideTabs(snapshot.state)) options.push({
|
|
4014
4634
|
id: `focus:${tab.id}`,
|
|
4015
4635
|
label: t("cmdFocus", { title: tab.title }),
|
|
4016
4636
|
detail: t("cmdFocusDetail")
|
|
@@ -4030,7 +4650,7 @@ window.__ModuleLoader__.load({
|
|
|
4030
4650
|
}
|
|
4031
4651
|
if (option.id.startsWith("focus:")) {
|
|
4032
4652
|
const tabId = option.id.slice(6);
|
|
4033
|
-
if (!focusNativeTab(ctx, tabId)) ctx
|
|
4653
|
+
if (!focusNativeTab(ctx, tabId)) betterSidebarOf(ctx)?.activateTab(tabId, { sessionId: session.sessionId });
|
|
4034
4654
|
return;
|
|
4035
4655
|
}
|
|
4036
4656
|
if (option.id.startsWith("reopen:")) {
|
|
@@ -4074,7 +4694,11 @@ window.__ModuleLoader__.load({
|
|
|
4074
4694
|
}
|
|
4075
4695
|
return `<side-chat-reference source="${(() => {
|
|
4076
4696
|
try {
|
|
4077
|
-
|
|
4697
|
+
if (directNativeLeg(ctx)) {
|
|
4698
|
+
const meta = sideChatMetasAll().find((m) => m.childId === childId);
|
|
4699
|
+
if (meta !== void 0) return meta.number <= 1 ? t("tabBaseTitle") : `${t("tabBaseTitle")} ${meta.number}`;
|
|
4700
|
+
}
|
|
4701
|
+
for (const tab of collectSideTabs(betterSidebarOf(ctx)?.getSnapshot().state)) if (parseSideChatMeta(tab.meta).childId === childId) return tab.title;
|
|
4078
4702
|
} catch {}
|
|
4079
4703
|
return childId;
|
|
4080
4704
|
})()}" note="用户 @ 引用的侧边聊天内容(问答成对)">\n${parts.join("\n")}\n</side-chat-reference>`;
|
|
@@ -4095,9 +4719,14 @@ window.__ModuleLoader__.load({
|
|
|
4095
4719
|
order: 50,
|
|
4096
4720
|
candidates: (session) => {
|
|
4097
4721
|
try {
|
|
4098
|
-
const snapshot = ctx.betterSidebar.getSnapshot();
|
|
4099
4722
|
if (session?.sessionId === void 0) return Promise.resolve([]);
|
|
4100
|
-
if (
|
|
4723
|
+
if (directNativeLeg(ctx)) return Promise.resolve(sideChatMetasOf(session.sessionId).filter((meta) => meta.childId !== void 0).map((meta) => ({
|
|
4724
|
+
name: meta.number <= 1 ? t("tabBaseTitle") : `${t("tabBaseTitle")} ${meta.number}`,
|
|
4725
|
+
description: "侧边聊天",
|
|
4726
|
+
icon: "💬"
|
|
4727
|
+
})));
|
|
4728
|
+
const snapshot = betterSidebarOf(ctx)?.getSnapshot();
|
|
4729
|
+
if (snapshot === void 0 || snapshot.sessionId !== session.sessionId || snapshot.state === void 0) return Promise.resolve([]);
|
|
4101
4730
|
return Promise.resolve(collectSideTabs(snapshot.state).map((tab) => ({
|
|
4102
4731
|
name: tab.title,
|
|
4103
4732
|
description: "侧边聊天",
|
|
@@ -4108,10 +4737,20 @@ window.__ModuleLoader__.load({
|
|
|
4108
4737
|
}
|
|
4109
4738
|
},
|
|
4110
4739
|
onPick: (pick, session) => {
|
|
4111
|
-
const snapshot = ctx.betterSidebar.getSnapshot();
|
|
4112
4740
|
if (session?.sessionId === void 0) return void 0;
|
|
4113
|
-
if (
|
|
4114
|
-
|
|
4741
|
+
if (directNativeLeg(ctx)) {
|
|
4742
|
+
const meta = sideChatMetasOf(session.sessionId).filter((m) => m.childId !== void 0).find((m) => (m.number <= 1 ? t("tabBaseTitle") : `${t("tabBaseTitle")} ${m.number}`) === pick.candidate.name);
|
|
4743
|
+
if (meta?.childId === void 0) return void 0;
|
|
4744
|
+
return { insert: {
|
|
4745
|
+
source: SOURCE,
|
|
4746
|
+
ref: meta.childId,
|
|
4747
|
+
label: pick.candidate.name,
|
|
4748
|
+
clipboardText: `@${pick.candidate.name}`
|
|
4749
|
+
} };
|
|
4750
|
+
}
|
|
4751
|
+
const snapshot = betterSidebarOf(ctx)?.getSnapshot();
|
|
4752
|
+
if (snapshot === void 0 || snapshot.sessionId !== session.sessionId || snapshot.state === void 0) return void 0;
|
|
4753
|
+
const tab = collectSideTabs(snapshot.state).find((tab) => tab.title === pick.candidate.name);
|
|
4115
4754
|
const childId = tab === void 0 ? void 0 : parseSideChatMeta(tab.meta).childId;
|
|
4116
4755
|
if (childId === void 0) return void 0;
|
|
4117
4756
|
return { insert: {
|
|
@@ -4144,24 +4783,40 @@ window.__ModuleLoader__.load({
|
|
|
4144
4783
|
function registerCompletionNotify(ctx) {
|
|
4145
4784
|
ctx.effect(() => {
|
|
4146
4785
|
const watchers = /* @__PURE__ */ new Map();
|
|
4786
|
+
const collectAlive = () => {
|
|
4787
|
+
if (directNativeLeg(ctx)) return sideChatMetasAll().flatMap((meta) => {
|
|
4788
|
+
if (meta.childId === void 0) return [];
|
|
4789
|
+
const title = meta.number <= 1 ? t("tabBaseTitle") : `${t("tabBaseTitle")} ${meta.number}`;
|
|
4790
|
+
return [{
|
|
4791
|
+
childId: meta.childId,
|
|
4792
|
+
title
|
|
4793
|
+
}];
|
|
4794
|
+
});
|
|
4795
|
+
const snapshot = betterSidebarOf(ctx)?.getSnapshot();
|
|
4796
|
+
if (snapshot?.state === void 0) return [];
|
|
4797
|
+
return collectSideTabs(snapshot.state).flatMap((tab) => {
|
|
4798
|
+
const childId = parseSideChatMeta(tab.meta).childId;
|
|
4799
|
+
return childId === void 0 ? [] : [{
|
|
4800
|
+
childId,
|
|
4801
|
+
title: tab.title
|
|
4802
|
+
}];
|
|
4803
|
+
});
|
|
4804
|
+
};
|
|
4147
4805
|
const rescan = () => {
|
|
4148
4806
|
let tabs = [];
|
|
4149
4807
|
try {
|
|
4150
|
-
tabs =
|
|
4808
|
+
tabs = collectAlive();
|
|
4151
4809
|
} catch {
|
|
4152
4810
|
return;
|
|
4153
4811
|
}
|
|
4154
4812
|
const alive = /* @__PURE__ */ new Set();
|
|
4155
|
-
for (const
|
|
4156
|
-
const childId = parseSideChatMeta(tab.meta).childId;
|
|
4157
|
-
if (childId === void 0) continue;
|
|
4813
|
+
for (const { childId, title } of tabs) {
|
|
4158
4814
|
alive.add(childId);
|
|
4159
4815
|
if (watchers.has(childId)) continue;
|
|
4160
4816
|
try {
|
|
4161
4817
|
const session = ctx.sessions.binding(childId)?.session;
|
|
4162
4818
|
if (session === void 0) continue;
|
|
4163
4819
|
openSessionWindow(session);
|
|
4164
|
-
const title = tab.title;
|
|
4165
4820
|
const watcher = {
|
|
4166
4821
|
unsub: () => {},
|
|
4167
4822
|
wasRunning: false,
|
|
@@ -4181,7 +4836,7 @@ window.__ModuleLoader__.load({
|
|
|
4181
4836
|
watchers.delete(id);
|
|
4182
4837
|
}
|
|
4183
4838
|
};
|
|
4184
|
-
const offState = ctx.
|
|
4839
|
+
const offState = directNativeLeg(ctx) ? sideChatMetaStore.subscribe(rescan) : betterSidebarOf(ctx)?.subscribeState(rescan) ?? (() => {});
|
|
4185
4840
|
rescan();
|
|
4186
4841
|
return () => {
|
|
4187
4842
|
offState();
|
|
@@ -4210,38 +4865,47 @@ window.__ModuleLoader__.load({
|
|
|
4210
4865
|
* 斜杠命令(spike,popupSelect 形态,不可行时降级为只有 Tab 入口)。
|
|
4211
4866
|
*/
|
|
4212
4867
|
function registerSideChat(ctx, reflow) {
|
|
4213
|
-
ctx
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
}
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
}
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4868
|
+
registerNativeSideChatTab(ctx, reflow);
|
|
4869
|
+
ctx.inject(["betterSidebar"], (injected) => {
|
|
4870
|
+
const bs = injected.get("betterSidebar");
|
|
4871
|
+
if (bs === void 0) return;
|
|
4872
|
+
try {
|
|
4873
|
+
const [major = 0, minor = 0] = bs.version.split(".").map((part) => Number.parseInt(part, 10));
|
|
4874
|
+
if (major > 0 || minor >= 19) return;
|
|
4875
|
+
} catch {}
|
|
4876
|
+
ctx.effect(() => bs.registerTab({
|
|
4877
|
+
id: SIDE_TAB_TYPE,
|
|
4878
|
+
title: () => t("menuTitle"),
|
|
4879
|
+
icon: (size) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconNewChatOutline16, { size }),
|
|
4880
|
+
order: 60,
|
|
4881
|
+
available: (availableCtx, scope) => canForkFrom(availableCtx, scope.sessionId),
|
|
4882
|
+
createTab: (state) => {
|
|
4883
|
+
const titles = collectSideTabs(state).map((tab) => tab.title);
|
|
4884
|
+
if (nativeSidebarHost(ctx)) {
|
|
4885
|
+
const current = ctx.sessions.list.getSnapshot().current;
|
|
4886
|
+
if (current !== void 0) for (const live of liveSideChatsOf(current)) titles.push(live.readTitle());
|
|
4887
|
+
}
|
|
4888
|
+
return { tab: {
|
|
4889
|
+
id: mintSideTabId(),
|
|
4890
|
+
type: SIDE_TAB_TYPE,
|
|
4891
|
+
title: sideTabTitle(titles)
|
|
4892
|
+
} };
|
|
4893
|
+
},
|
|
4894
|
+
onClose: (closedTab) => {
|
|
4895
|
+
const meta = parseSideChatMeta(closedTab.meta);
|
|
4896
|
+
if (meta.childId !== void 0 && meta.parentSessionId !== void 0) recordClosedSideChat(meta.parentSessionId, {
|
|
4897
|
+
childId: meta.childId,
|
|
4898
|
+
parentSessionId: meta.parentSessionId,
|
|
4899
|
+
title: closedTab.title,
|
|
4900
|
+
closedAt: Date.now()
|
|
4901
|
+
});
|
|
4902
|
+
},
|
|
4903
|
+
component: (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideChatPanel, {
|
|
4904
|
+
...props,
|
|
4905
|
+
reflow
|
|
4906
|
+
})
|
|
4907
|
+
}), "dsh-sidenote: side chat tab");
|
|
4908
|
+
});
|
|
4245
4909
|
ctx.effect(() => {
|
|
4246
4910
|
const impl = {
|
|
4247
4911
|
askInSideChat: (sessionId, draftText) => openOrFocusSideChat(ctx, sessionId, draftText),
|
|
@@ -4709,42 +5373,42 @@ window.__ModuleLoader__.load({
|
|
|
4709
5373
|
document.head.appendChild(tag);
|
|
4710
5374
|
}
|
|
4711
5375
|
var annotate_module_css_default = {
|
|
4712
|
-
"
|
|
4713
|
-
"
|
|
5376
|
+
"editorTarget": "_SVViG_editorTarget",
|
|
5377
|
+
"badge": "_SVViG_badge",
|
|
4714
5378
|
"highlight": "_SVViG_highlight",
|
|
4715
|
-
"chipRemove": "_SVViG_chipRemove",
|
|
4716
|
-
"dshSidenoteHintIn": "_SVViG_dshSidenoteHintIn",
|
|
4717
|
-
"editorNew": "_SVViG_editorNew",
|
|
4718
|
-
"chipRow": "_SVViG_chipRow",
|
|
4719
5379
|
"editorTextarea": "_SVViG_editorTextarea",
|
|
4720
|
-
"
|
|
4721
|
-
"chipNote": "_SVViG_chipNote",
|
|
4722
|
-
"chip": "_SVViG_chip",
|
|
4723
|
-
"chipText": "_SVViG_chipText",
|
|
5380
|
+
"deleteButton": "_SVViG_deleteButton",
|
|
4724
5381
|
"chipPanel": "_SVViG_chipPanel",
|
|
4725
|
-
"
|
|
4726
|
-
"
|
|
5382
|
+
"chipText": "_SVViG_chipText",
|
|
5383
|
+
"sentChip": "_SVViG_sentChip",
|
|
5384
|
+
"chip": "_SVViG_chip",
|
|
5385
|
+
"chipNumber": "_SVViG_chipNumber",
|
|
4727
5386
|
"sentCardQuote": "_SVViG_sentCardQuote",
|
|
4728
|
-
"
|
|
5387
|
+
"editorAsk": "_SVViG_editorAsk",
|
|
5388
|
+
"saveButton": "_SVViG_saveButton",
|
|
4729
5389
|
"sentChipRow": "_SVViG_sentChipRow",
|
|
4730
|
-
"
|
|
5390
|
+
"hint": "_SVViG_hint",
|
|
5391
|
+
"editorSpacer": "_SVViG_editorSpacer",
|
|
5392
|
+
"editorAskRow": "_SVViG_editorAskRow",
|
|
5393
|
+
"chipClearAll": "_SVViG_chipClearAll",
|
|
5394
|
+
"chipWrap": "_SVViG_chipWrap",
|
|
5395
|
+
"chipRow": "_SVViG_chipRow",
|
|
5396
|
+
"sentCardTitle": "_SVViG_sentCardTitle",
|
|
5397
|
+
"toolbarBelow": "_SVViG_toolbarBelow",
|
|
4731
5398
|
"sentCardNote": "_SVViG_sentCardNote",
|
|
4732
|
-
"
|
|
5399
|
+
"editorInput": "_SVViG_editorInput",
|
|
4733
5400
|
"cancelButton": "_SVViG_cancelButton",
|
|
5401
|
+
"badgeSent": "_SVViG_badgeSent",
|
|
5402
|
+
"editorEdit": "_SVViG_editorEdit",
|
|
5403
|
+
"editorNew": "_SVViG_editorNew",
|
|
5404
|
+
"chipRemove": "_SVViG_chipRemove",
|
|
4734
5405
|
"editorFooter": "_SVViG_editorFooter",
|
|
4735
|
-
"sentCardTitle": "_SVViG_sentCardTitle",
|
|
4736
|
-
"badge": "_SVViG_badge",
|
|
4737
|
-
"editorTarget": "_SVViG_editorTarget",
|
|
4738
|
-
"chipNumber": "_SVViG_chipNumber",
|
|
4739
|
-
"editorAskRow": "_SVViG_editorAskRow",
|
|
4740
|
-
"editorSpacer": "_SVViG_editorSpacer",
|
|
4741
5406
|
"hintClose": "_SVViG_hintClose",
|
|
4742
|
-
"
|
|
4743
|
-
"
|
|
5407
|
+
"chipNote": "_SVViG_chipNote",
|
|
5408
|
+
"confirmButton": "_SVViG_confirmButton",
|
|
5409
|
+
"dshSidenoteHintIn": "_SVViG_dshSidenoteHintIn",
|
|
4744
5410
|
"toolbarButton": "_SVViG_toolbarButton",
|
|
4745
|
-
"
|
|
4746
|
-
"chipWrap": "_SVViG_chipWrap",
|
|
4747
|
-
"sentChip": "_SVViG_sentChip",
|
|
5411
|
+
"editorError": "_SVViG_editorError",
|
|
4748
5412
|
"toolbar": "_SVViG_toolbar"
|
|
4749
5413
|
};
|
|
4750
5414
|
//#endregion
|
|
@@ -5584,6 +6248,23 @@ window.__ModuleLoader__.load({
|
|
|
5584
6248
|
function installSendInterceptor(ctx, store, reflow) {
|
|
5585
6249
|
/** 重入/连按护栏:事务进行中吞掉命中识别面的 Enter/点击(不重复驱动)。 */
|
|
5586
6250
|
let committing = false;
|
|
6251
|
+
/**
|
|
6252
|
+
* 手势尾随 click 的一次性吞并。pointerdown 提交后,同一次点击的 click 仍会
|
|
6253
|
+
* 到达,而此时宿主主按钮已按 `primaryStops = running && empty` 变身「停止」
|
|
6254
|
+
* ——放行它会立刻 `stop()` 掉刚发起的这一轮(表现:assistant/attempt 空流、
|
|
6255
|
+
* 缺 turn/end、且没有任何错误提示)。只吞这一发,并带兜底超时。
|
|
6256
|
+
*/
|
|
6257
|
+
let swallowNextClick = false;
|
|
6258
|
+
let swallowTimer = 0;
|
|
6259
|
+
const clearSwallow = () => {
|
|
6260
|
+
swallowNextClick = false;
|
|
6261
|
+
window.clearTimeout(swallowTimer);
|
|
6262
|
+
};
|
|
6263
|
+
const armSwallow = () => {
|
|
6264
|
+
swallowNextClick = true;
|
|
6265
|
+
window.clearTimeout(swallowTimer);
|
|
6266
|
+
swallowTimer = window.setTimeout(clearSwallow, 2e3);
|
|
6267
|
+
};
|
|
5587
6268
|
const currentSessionId = () => {
|
|
5588
6269
|
try {
|
|
5589
6270
|
return ctx.sessions.list.getSnapshot().current ?? "";
|
|
@@ -5591,37 +6272,36 @@ window.__ModuleLoader__.load({
|
|
|
5591
6272
|
return "";
|
|
5592
6273
|
}
|
|
5593
6274
|
};
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
const
|
|
5603
|
-
const
|
|
5604
|
-
|
|
5605
|
-
if (snap.phase !== "plain") return false;
|
|
5606
|
-
const seat = composerSeat();
|
|
5607
|
-
if (seat === null) return false;
|
|
5608
|
-
if (seat.querySelector("[role=\"listbox\"]") !== null) return false;
|
|
5609
|
-
if (seat.querySelector("[aria-expanded=\"true\"]") !== null) return false;
|
|
6275
|
+
/**
|
|
6276
|
+
* 异步提交(Workitem_06):inject 尝试(有界等待,见 tryInjectReflows)
|
|
6277
|
+
* 在拼稿前——成功项以 plugin-source 事件进父会话日志(不进消息前缀),
|
|
6278
|
+
* 且立即从 reflow store 移除(chip 消失表达「已注入」);失败/超时项
|
|
6279
|
+
* 照常搭车(拼进前缀)。正文取提交瞬间的最新草稿(注入等待窗口内的
|
|
6280
|
+
* 用户输入不丢)。
|
|
6281
|
+
*/
|
|
6282
|
+
const commitAsync = async (sessionId, input, draftAtHijack, reflows, active) => {
|
|
6283
|
+
const { injectedIds } = await tryInjectReflows(sessionId, reflows);
|
|
6284
|
+
for (const id of injectedIds) reflow.remove(id);
|
|
6285
|
+
const hitchhikers = reflows.filter((item) => !injectedIds.has(item.id));
|
|
5610
6286
|
const parts = [];
|
|
5611
|
-
for (const item of
|
|
6287
|
+
for (const item of hitchhikers) parts.push(buildReflowBlock(item));
|
|
5612
6288
|
if (active.length > 0) parts.push(buildProtocolBlock(active));
|
|
5613
|
-
const
|
|
6289
|
+
const draftBeforeCompose = input.state.getSnapshot().draft;
|
|
6290
|
+
const body = draftBeforeCompose.trim();
|
|
5614
6291
|
const full = [...parts, ...body === "" ? [] : [body]].join("\n\n");
|
|
5615
6292
|
const sentIds = active.map((a) => a.id);
|
|
6293
|
+
if (full === "") {
|
|
6294
|
+
committing = false;
|
|
6295
|
+
return;
|
|
6296
|
+
}
|
|
5616
6297
|
input.setDraft(full);
|
|
5617
|
-
committing = true;
|
|
5618
6298
|
try {
|
|
5619
6299
|
input.submit("queue");
|
|
5620
6300
|
} catch (error) {
|
|
5621
6301
|
console.warn("[dsh-sidenote] 提交失败,回滚草稿:", error);
|
|
5622
|
-
if (input.state.getSnapshot().draft.startsWith(full)) input.setDraft(
|
|
6302
|
+
if (input.state.getSnapshot().draft.startsWith(full)) input.setDraft(draftAtHijack);
|
|
5623
6303
|
committing = false;
|
|
5624
|
-
return
|
|
6304
|
+
return;
|
|
5625
6305
|
}
|
|
5626
6306
|
const off = input.state.subscribe(() => {
|
|
5627
6307
|
const state = input.state.getSnapshot();
|
|
@@ -5634,12 +6314,34 @@ window.__ModuleLoader__.load({
|
|
|
5634
6314
|
reflow.clearSession(sessionId);
|
|
5635
6315
|
return;
|
|
5636
6316
|
}
|
|
5637
|
-
if (state.draft.startsWith(full)) input.setDraft(
|
|
6317
|
+
if (state.draft.startsWith(full)) input.setDraft(draftBeforeCompose);
|
|
5638
6318
|
});
|
|
5639
6319
|
const watchdog = window.setTimeout(() => {
|
|
5640
6320
|
off();
|
|
5641
6321
|
committing = false;
|
|
5642
6322
|
}, 15e3);
|
|
6323
|
+
};
|
|
6324
|
+
const hijack = () => {
|
|
6325
|
+
const sessionId = currentSessionId();
|
|
6326
|
+
if (sessionId === "") return false;
|
|
6327
|
+
const active = store.listActive(sessionId);
|
|
6328
|
+
const reflows = reflow.list(sessionId);
|
|
6329
|
+
if (active.length === 0 && reflows.length === 0) return false;
|
|
6330
|
+
const input = resolveInput(ctx, sessionId);
|
|
6331
|
+
if (input === void 0) return false;
|
|
6332
|
+
const snap = input.state.getSnapshot();
|
|
6333
|
+
const draft = snap.draft;
|
|
6334
|
+
if (draft.trimStart().startsWith("/")) return false;
|
|
6335
|
+
if (snap.phase !== "plain") return false;
|
|
6336
|
+
const seat = composerSeat();
|
|
6337
|
+
if (seat === null) return false;
|
|
6338
|
+
if (seat.querySelector("[role=\"listbox\"]") !== null) return false;
|
|
6339
|
+
if (seat.querySelector("[aria-expanded=\"true\"]") !== null) return false;
|
|
6340
|
+
committing = true;
|
|
6341
|
+
commitAsync(sessionId, input, draft, reflows, active).catch((error) => {
|
|
6342
|
+
console.warn("[dsh-sidenote] 提交编排失败:", error);
|
|
6343
|
+
committing = false;
|
|
6344
|
+
});
|
|
5643
6345
|
return true;
|
|
5644
6346
|
};
|
|
5645
6347
|
const onKeyDown = (event) => {
|
|
@@ -5663,6 +6365,12 @@ window.__ModuleLoader__.load({
|
|
|
5663
6365
|
const target = event.target;
|
|
5664
6366
|
if (!(target instanceof Element)) return;
|
|
5665
6367
|
if (target.closest("[data-composer-seat]") === null) return;
|
|
6368
|
+
if (swallowNextClick) {
|
|
6369
|
+
clearSwallow();
|
|
6370
|
+
event.preventDefault();
|
|
6371
|
+
event.stopImmediatePropagation();
|
|
6372
|
+
return;
|
|
6373
|
+
}
|
|
5666
6374
|
const button = target.closest("button");
|
|
5667
6375
|
if (button === null) return;
|
|
5668
6376
|
if (committing) {
|
|
@@ -5675,11 +6383,35 @@ window.__ModuleLoader__.load({
|
|
|
5675
6383
|
event.preventDefault();
|
|
5676
6384
|
event.stopImmediatePropagation();
|
|
5677
6385
|
};
|
|
6386
|
+
/**
|
|
6387
|
+
* 空草稿补位:只接管「因空草稿而 disabled」的主按钮。enabled 时立即放行,
|
|
6388
|
+
* 正常路径仍由上面的 click 拦截负责 —— 二者以 button.disabled 互斥。
|
|
6389
|
+
*/
|
|
6390
|
+
const onPointerDown = (event) => {
|
|
6391
|
+
if (event.button !== 0) return;
|
|
6392
|
+
const target = event.target;
|
|
6393
|
+
if (!(target instanceof Element)) return;
|
|
6394
|
+
const button = target.closest("button");
|
|
6395
|
+
if (!(button instanceof HTMLButtonElement)) return;
|
|
6396
|
+
if (!button.disabled) return;
|
|
6397
|
+
if (button !== findSendButtonInCard()) return;
|
|
6398
|
+
if (committing) return;
|
|
6399
|
+
const sessionId = currentSessionId();
|
|
6400
|
+
if (sessionId === "") return;
|
|
6401
|
+
const input = resolveInput(ctx, sessionId);
|
|
6402
|
+
if (input === void 0 || input.state.getSnapshot().draft.trim() !== "") return;
|
|
6403
|
+
if (!hijack()) return;
|
|
6404
|
+
armSwallow();
|
|
6405
|
+
event.preventDefault();
|
|
6406
|
+
event.stopImmediatePropagation();
|
|
6407
|
+
};
|
|
5678
6408
|
document.addEventListener("keydown", onKeyDown, true);
|
|
5679
6409
|
document.addEventListener("click", onClick, true);
|
|
6410
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
5680
6411
|
return () => {
|
|
5681
6412
|
document.removeEventListener("keydown", onKeyDown, true);
|
|
5682
6413
|
document.removeEventListener("click", onClick, true);
|
|
6414
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
5683
6415
|
};
|
|
5684
6416
|
}
|
|
5685
6417
|
//#endregion
|
|
@@ -5849,7 +6581,6 @@ window.__ModuleLoader__.load({
|
|
|
5849
6581
|
//#endregion
|
|
5850
6582
|
//#region src/client/index.tsx
|
|
5851
6583
|
const inject = [
|
|
5852
|
-
"betterSidebar",
|
|
5853
6584
|
"sessions",
|
|
5854
6585
|
"workspaces",
|
|
5855
6586
|
"slots",
|
|
@@ -5865,6 +6596,7 @@ window.__ModuleLoader__.load({
|
|
|
5865
6596
|
}, "dsh-sidenote: native bridge");
|
|
5866
6597
|
attachLocale(ctx.locale);
|
|
5867
6598
|
probeHost(ctx);
|
|
6599
|
+
sweepOrphanedSideChatMeta();
|
|
5868
6600
|
const reflow = createReflowStore();
|
|
5869
6601
|
registerSideChat(ctx, reflow);
|
|
5870
6602
|
registerAnnotations(ctx, reflow);
|