dsh-more 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/README.zh-CN.md +11 -0
- package/dist/client.js +1103 -141
- package/dist/index.js +232 -12
- package/dist/types/generated/host-settings-schema.d.ts +4 -0
- package/dist/types/generated/patch-catalog.d.ts +16 -0
- package/dist/types/patches/conversation-quick-navigation/client/index.d.ts +22 -0
- package/dist/types/patches/conversation-quick-navigation/client/navigation.d.ts +26 -0
- package/dist/types/patches/conversation-quick-navigation/host/index.d.ts +2 -0
- package/dist/types/patches/conversation-quick-navigation/shared.d.ts +1 -0
- package/dist/types/patches/model-reasoning-efforts/client/index.d.ts +39 -0
- package/dist/types/patches/model-reasoning-efforts/host/index.d.ts +2 -0
- package/dist/types/patches/model-reasoning-efforts/host/validate.d.ts +13 -0
- package/dist/types/patches/model-reasoning-efforts/shared.d.ts +51 -0
- package/dist/types/platform/dsh/client/api.d.ts +2 -0
- package/dist/types/platform/dsh/client/message-targets.d.ts +13 -1
- package/dist/types/platform/dsh/host/wire.d.ts +6 -0
- package/dsh.plugin.json +1 -1
- package/package.json +2 -2
package/dist/client.js
CHANGED
|
@@ -25,21 +25,25 @@ __export(index_exports, {
|
|
|
25
25
|
inject: () => inject
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(index_exports);
|
|
28
|
-
var
|
|
29
|
-
var
|
|
28
|
+
var import_react9 = require("react");
|
|
29
|
+
var import_react_dom2 = require("react-dom");
|
|
30
30
|
|
|
31
31
|
// src/generated/patch-catalog.ts
|
|
32
32
|
var PATCH_CATALOG = [
|
|
33
33
|
{ "id": "message-edit", "name": "\u7F16\u8F91\u5E76\u91CD\u65B0\u5F00\u59CB", "description": "\u7F16\u8F91\u7528\u6237\u6D88\u606F\u5E76\u4E22\u5F03\u8BE5\u6D88\u606F\u4E4B\u540E\u7684\u5386\u53F2", "defaultEnabled": true, "order": 100, "clientKind": "message-action" },
|
|
34
34
|
{ "id": "message-delete", "name": "\u5355\u6761\u6D88\u606F\u5220\u9664", "description": "\u5220\u9664\u6307\u5B9A\u6D88\u606F\u5E76\u4FDD\u7559\u524D\u540E\u5386\u53F2\u8BB0\u5F55", "defaultEnabled": true, "order": 200, "clientKind": "message-action" },
|
|
35
35
|
{ "id": "session-delete", "name": "\u6C38\u4E45\u5220\u9664\u4F1A\u8BDD", "description": "\u505C\u6B62\u76EE\u6807\u4F1A\u8BDD\u5E76\u4ECE\u78C1\u76D8\u6C38\u4E45\u5220\u9664\uFF0C\u4E0D\u5F71\u54CD\u539F\u751F\u5F52\u6863", "defaultEnabled": true, "order": 300, "clientKind": "standalone" },
|
|
36
|
-
{ "id": "conversation-markdown-export", "name": "\u5BFC\u51FA\u5B8C\u6574\u804A\u5929\u8BB0\u5F55", "description": "\u5C06\u5F53\u524D\u4F1A\u8BDD\u7684\u5B8C\u6574\u804A\u5929\u8BB0\u5F55\u4E0B\u8F7D\u4E3A Markdown \u6587\u4EF6", "defaultEnabled": true, "order": 400, "clientKind": "standalone" }
|
|
36
|
+
{ "id": "conversation-markdown-export", "name": "\u5BFC\u51FA\u5B8C\u6574\u804A\u5929\u8BB0\u5F55", "description": "\u5C06\u5F53\u524D\u4F1A\u8BDD\u7684\u5B8C\u6574\u804A\u5929\u8BB0\u5F55\u4E0B\u8F7D\u4E3A Markdown \u6587\u4EF6", "defaultEnabled": true, "order": 400, "clientKind": "standalone" },
|
|
37
|
+
{ "id": "model-reasoning-efforts", "name": "\u6A21\u578B\u601D\u8003\u5F3A\u5EA6", "description": "\u5728\u6A21\u578B\u914D\u7F6E\u754C\u9762\u4E3A\u6BCF\u4E2A\u6A21\u578B\u914D\u7F6E\u652F\u6301\u7684\u601D\u8003\u5F3A\u5EA6\u5E76\u5199\u5165 settings.yaml \u7684 reasoningEfforts", "defaultEnabled": true, "order": 500, "clientKind": "standalone" },
|
|
38
|
+
{ "id": "conversation-quick-navigation", "name": "\u5BF9\u8BDD\u5FEB\u901F\u5BFC\u822A", "description": "\u81EA\u52A8\u52A0\u8F7D\u5B8C\u6574\u8BB0\u5F55\uFF0C\u5E76\u7528\u5E38\u9A7B\u76EE\u5F55\u5FEB\u901F\u5B9A\u4F4D\u5F53\u524D\u4F1A\u8BDD\u4E2D\u7684\u6BCF\u4E00\u8F6E\u63D0\u95EE", "defaultEnabled": true, "order": 600, "clientKind": "standalone" }
|
|
37
39
|
];
|
|
38
40
|
var DEFAULT_PATCH_SETTINGS = {
|
|
39
41
|
"message-edit": true,
|
|
40
42
|
"message-delete": true,
|
|
41
43
|
"session-delete": true,
|
|
42
|
-
"conversation-markdown-export": true
|
|
44
|
+
"conversation-markdown-export": true,
|
|
45
|
+
"model-reasoning-efforts": true,
|
|
46
|
+
"conversation-quick-navigation": true
|
|
43
47
|
};
|
|
44
48
|
function decodePatchSettings(value) {
|
|
45
49
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
@@ -72,7 +76,7 @@ var DshMoreApiError = class extends Error {
|
|
|
72
76
|
}
|
|
73
77
|
code;
|
|
74
78
|
};
|
|
75
|
-
async function
|
|
79
|
+
async function requestPatch(patchId, action, payload) {
|
|
76
80
|
let response;
|
|
77
81
|
try {
|
|
78
82
|
response = await fetch(`${PLUGIN_API_PREFIX}/${encodeURIComponent(patchId)}/${encodeURIComponent(action)}`, {
|
|
@@ -86,12 +90,28 @@ async function callPatchApi(patchId, action, payload) {
|
|
|
86
90
|
} catch (error) {
|
|
87
91
|
throw new DshMoreApiError("network", error instanceof Error ? error.message : String(error));
|
|
88
92
|
}
|
|
93
|
+
return response;
|
|
94
|
+
}
|
|
95
|
+
async function responseError(response) {
|
|
89
96
|
const body = await response.json().catch(() => null);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
return new DshMoreApiError(body?.error?.code ?? "http", body?.error?.message ?? `HTTP ${String(response.status)}`);
|
|
98
|
+
}
|
|
99
|
+
async function callPatchApi(patchId, action, payload) {
|
|
100
|
+
const response = await requestPatch(patchId, action, payload);
|
|
101
|
+
const body = await response.json().catch(() => null);
|
|
102
|
+
if (!response.ok || body?.ok !== true || body.value === void 0) throw await responseErrorFromBody(response, body);
|
|
93
103
|
return body.value;
|
|
94
104
|
}
|
|
105
|
+
function responseErrorFromBody(response, body) {
|
|
106
|
+
return new DshMoreApiError(body?.error?.code ?? "http", body?.error?.message ?? `HTTP ${String(response.status)}`);
|
|
107
|
+
}
|
|
108
|
+
async function callPatchBlobApi(patchId, action, payload) {
|
|
109
|
+
const response = await requestPatch(patchId, action, payload);
|
|
110
|
+
if (!response.ok) throw await responseError(response);
|
|
111
|
+
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
112
|
+
if (contentType !== "text/markdown") throw new DshMoreApiError("unexpected-response", "\u5BFC\u51FA\u63A5\u53E3\u8FD4\u56DE\u4E86\u672A\u77E5\u5185\u5BB9\u3002");
|
|
113
|
+
return response.blob();
|
|
114
|
+
}
|
|
95
115
|
function apiErrorText(error) {
|
|
96
116
|
if (error instanceof DshMoreApiError || error instanceof Error) return error.message;
|
|
97
117
|
return String(error);
|
|
@@ -176,10 +196,16 @@ async function settleSessionRemoval(sessions, workspaces, sessionId) {
|
|
|
176
196
|
function adjacentVisibleSession(sessions, workspaces, deletingSessionId) {
|
|
177
197
|
if (sessions.current !== deletingSessionId) return void 0;
|
|
178
198
|
const archived = new Set(workspaces.archivedSessionIds);
|
|
179
|
-
const visible = sessions.ids.filter((id) => id !== deletingSessionId && !archived.has(id));
|
|
180
|
-
if (visible.length === 0) return void 0;
|
|
181
199
|
const deletingIndex = sessions.ids.indexOf(deletingSessionId);
|
|
182
|
-
|
|
200
|
+
for (let index = deletingIndex + 1; index < sessions.ids.length; index += 1) {
|
|
201
|
+
const id = sessions.ids[index];
|
|
202
|
+
if (id !== void 0 && id !== deletingSessionId && !archived.has(id)) return id;
|
|
203
|
+
}
|
|
204
|
+
for (let index = deletingIndex - 1; index >= 0; index -= 1) {
|
|
205
|
+
const id = sessions.ids[index];
|
|
206
|
+
if (id !== void 0 && id !== deletingSessionId && !archived.has(id)) return id;
|
|
207
|
+
}
|
|
208
|
+
return void 0;
|
|
183
209
|
}
|
|
184
210
|
|
|
185
211
|
// src/patches/message-edit/shared.ts
|
|
@@ -439,44 +465,71 @@ function replaceExactText(root, before, after) {
|
|
|
439
465
|
}
|
|
440
466
|
function installSessionDeleteMenuItems(onDelete) {
|
|
441
467
|
let frame = null;
|
|
442
|
-
const deleteItems = /* @__PURE__ */ new
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
468
|
+
const deleteItems = /* @__PURE__ */ new Map();
|
|
469
|
+
const pendingButtons = /* @__PURE__ */ new Set();
|
|
470
|
+
const syncButton = (archiveButton) => {
|
|
471
|
+
if (!archiveButton.isConnected) return;
|
|
472
|
+
const text = archiveButton.textContent?.trim();
|
|
473
|
+
const deleteLabel = text === "\u5F52\u6863\u4F1A\u8BDD" ? "\u6C38\u4E45\u5220\u9664\u4F1A\u8BDD" : text === "Archive session" ? "Permanently delete session" : void 0;
|
|
474
|
+
if (deleteLabel === void 0) return;
|
|
475
|
+
const wrapper = archiveButton.parentElement;
|
|
476
|
+
if (wrapper === null) return;
|
|
477
|
+
if (archiveButton.hasAttribute(DELETE_SOURCE_ATTRIBUTE)) {
|
|
478
|
+
if (deleteItems.get(archiveButton)?.isConnected === true) return;
|
|
479
|
+
archiveButton.removeAttribute(DELETE_SOURCE_ATTRIBUTE);
|
|
480
|
+
}
|
|
481
|
+
const clone = wrapper.cloneNode(true);
|
|
482
|
+
const deleteButton = clone.querySelector('button[role="menuitem"]');
|
|
483
|
+
if (deleteButton === null) return;
|
|
484
|
+
archiveButton.setAttribute(DELETE_SOURCE_ATTRIBUTE, "");
|
|
485
|
+
clone.setAttribute(DELETE_MENU_ATTRIBUTE, "");
|
|
486
|
+
deleteItems.set(archiveButton, clone);
|
|
487
|
+
replaceExactText(deleteButton, text, deleteLabel);
|
|
488
|
+
deleteButton.setAttribute("aria-label", deleteLabel);
|
|
489
|
+
deleteButton.classList.add("dshmore-session-delete-menu-item");
|
|
490
|
+
deleteButton.addEventListener("click", (event) => {
|
|
491
|
+
event.preventDefault();
|
|
492
|
+
event.stopImmediatePropagation();
|
|
493
|
+
onDelete(archiveButton);
|
|
494
|
+
});
|
|
495
|
+
wrapper.after(clone);
|
|
496
|
+
};
|
|
497
|
+
const collectButtons = (node) => {
|
|
498
|
+
const element = node instanceof Element ? node : node.parentElement;
|
|
499
|
+
if (element === null) return;
|
|
500
|
+
const ancestor = element.closest('button[role="menuitem"]');
|
|
501
|
+
if (ancestor !== null) pendingButtons.add(ancestor);
|
|
502
|
+
if (element.matches('button[role="menuitem"]')) pendingButtons.add(element);
|
|
503
|
+
element.querySelectorAll('button[role="menuitem"]').forEach((button) => pendingButtons.add(button));
|
|
504
|
+
};
|
|
505
|
+
const flush = () => {
|
|
506
|
+
frame = null;
|
|
507
|
+
for (const [archiveButton, deleteItem] of deleteItems) {
|
|
508
|
+
if (!archiveButton.isConnected) {
|
|
509
|
+
deleteItems.delete(archiveButton);
|
|
510
|
+
} else if (!deleteItem.isConnected) {
|
|
452
511
|
archiveButton.removeAttribute(DELETE_SOURCE_ATTRIBUTE);
|
|
512
|
+
deleteItems.delete(archiveButton);
|
|
513
|
+
pendingButtons.add(archiveButton);
|
|
453
514
|
}
|
|
454
|
-
const clone = wrapper.cloneNode(true);
|
|
455
|
-
const deleteButton = clone.querySelector('button[role="menuitem"]');
|
|
456
|
-
if (deleteButton === null) continue;
|
|
457
|
-
archiveButton.setAttribute(DELETE_SOURCE_ATTRIBUTE, "");
|
|
458
|
-
clone.setAttribute(DELETE_MENU_ATTRIBUTE, "");
|
|
459
|
-
deleteItems.set(archiveButton, clone);
|
|
460
|
-
replaceExactText(deleteButton, text, deleteLabel);
|
|
461
|
-
deleteButton.setAttribute("aria-label", deleteLabel);
|
|
462
|
-
deleteButton.classList.add("dshmore-session-delete-menu-item");
|
|
463
|
-
deleteButton.addEventListener("click", (event) => {
|
|
464
|
-
event.preventDefault();
|
|
465
|
-
event.stopImmediatePropagation();
|
|
466
|
-
onDelete(archiveButton);
|
|
467
|
-
});
|
|
468
|
-
wrapper.after(clone);
|
|
469
515
|
}
|
|
516
|
+
for (const button of pendingButtons) syncButton(button);
|
|
517
|
+
pendingButtons.clear();
|
|
470
518
|
};
|
|
471
519
|
const schedule = () => {
|
|
472
520
|
if (frame !== null) return;
|
|
473
|
-
frame = window.requestAnimationFrame(
|
|
474
|
-
frame = null;
|
|
475
|
-
sync();
|
|
476
|
-
});
|
|
521
|
+
frame = window.requestAnimationFrame(flush);
|
|
477
522
|
};
|
|
478
|
-
|
|
479
|
-
|
|
523
|
+
document.querySelectorAll('button[role="menuitem"]').forEach((button) => pendingButtons.add(button));
|
|
524
|
+
flush();
|
|
525
|
+
const observer = new MutationObserver((records) => {
|
|
526
|
+
let removedKnownItem = false;
|
|
527
|
+
for (const record of records) {
|
|
528
|
+
record.addedNodes.forEach(collectButtons);
|
|
529
|
+
if (record.removedNodes.length > 0 && deleteItems.size > 0) removedKnownItem = true;
|
|
530
|
+
}
|
|
531
|
+
if (pendingButtons.size > 0 || removedKnownItem) schedule();
|
|
532
|
+
});
|
|
480
533
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
481
534
|
return () => {
|
|
482
535
|
observer.disconnect();
|
|
@@ -492,12 +545,6 @@ function installSessionDeleteMenuItems(onDelete) {
|
|
|
492
545
|
function SessionDeleteController(props) {
|
|
493
546
|
const settings = (0, import_react3.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
|
|
494
547
|
const enabled = settings[SESSION_DELETE_PATCH_ID];
|
|
495
|
-
const sessionList = props.useSessions((state) => state);
|
|
496
|
-
const sessionListRef = (0, import_react3.useRef)(sessionList);
|
|
497
|
-
sessionListRef.current = sessionList;
|
|
498
|
-
const workspaceList = props.useWorkspaces((state) => state);
|
|
499
|
-
const workspaceListRef = (0, import_react3.useRef)(workspaceList);
|
|
500
|
-
workspaceListRef.current = workspaceList;
|
|
501
548
|
const [pending, setPending] = (0, import_react3.useState)(null);
|
|
502
549
|
const pendingRef = (0, import_react3.useRef)(null);
|
|
503
550
|
const deleteIntentRef = (0, import_react3.useRef)(false);
|
|
@@ -506,13 +553,18 @@ function SessionDeleteController(props) {
|
|
|
506
553
|
(0, import_react3.useEffect)(() => {
|
|
507
554
|
if (!enabled) return;
|
|
508
555
|
const workspaces = props.ctx.workspaces;
|
|
556
|
+
const sessions = props.ctx.sessions;
|
|
509
557
|
const mutable = workspaces;
|
|
510
558
|
const original = mutable.archiveSession;
|
|
511
559
|
mutable.archiveSession = (sessionId) => {
|
|
512
560
|
if (!deleteIntentRef.current) return original.call(mutable, sessionId);
|
|
513
561
|
deleteIntentRef.current = false;
|
|
514
562
|
return new Promise((resolve) => {
|
|
515
|
-
const request = {
|
|
563
|
+
const request = {
|
|
564
|
+
sessionId,
|
|
565
|
+
title: sessions.list.getSnapshot().byId[sessionId]?.displayTitle ?? String(sessionId),
|
|
566
|
+
resolve
|
|
567
|
+
};
|
|
516
568
|
pendingRef.current?.resolve();
|
|
517
569
|
pendingRef.current = request;
|
|
518
570
|
setError(null);
|
|
@@ -548,8 +600,8 @@ function SessionDeleteController(props) {
|
|
|
548
600
|
const sessions = props.ctx.sessions;
|
|
549
601
|
const workspaces = props.ctx.workspaces;
|
|
550
602
|
const fallbackSessionId = adjacentVisibleSession(
|
|
551
|
-
|
|
552
|
-
|
|
603
|
+
sessions.list.getSnapshot(),
|
|
604
|
+
workspaces.list.getSnapshot(),
|
|
553
605
|
pending.sessionId
|
|
554
606
|
);
|
|
555
607
|
if (fallbackSessionId !== void 0) openSessionWithoutGap(sessions, fallbackSessionId);
|
|
@@ -568,7 +620,7 @@ function SessionDeleteController(props) {
|
|
|
568
620
|
setBusy(false);
|
|
569
621
|
}
|
|
570
622
|
};
|
|
571
|
-
const title = pending
|
|
623
|
+
const title = pending?.title ?? "";
|
|
572
624
|
if (!enabled) return null;
|
|
573
625
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
574
626
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: styles + sessionDeleteStyles }),
|
|
@@ -665,13 +717,13 @@ function ConversationMarkdownExportButton(props) {
|
|
|
665
717
|
setBusy(true);
|
|
666
718
|
setError(null);
|
|
667
719
|
try {
|
|
668
|
-
const
|
|
720
|
+
const markdown = await callPatchBlobApi(
|
|
669
721
|
CONVERSATION_MARKDOWN_EXPORT_PATCH_ID,
|
|
670
722
|
"render",
|
|
671
723
|
{ sessionId: props.sessionId, title }
|
|
672
724
|
);
|
|
673
725
|
if (generation.current !== requestGeneration || activeSession.current !== requestSessionId) return;
|
|
674
|
-
saveMarkdown(markdownFilename(title, String(props.sessionId)),
|
|
726
|
+
saveMarkdown(markdownFilename(title, String(props.sessionId)), markdown);
|
|
675
727
|
} catch (caught) {
|
|
676
728
|
if (generation.current === requestGeneration && activeSession.current === requestSessionId) setError(apiErrorText(caught));
|
|
677
729
|
} finally {
|
|
@@ -723,9 +775,807 @@ var clientPatch2 = {
|
|
|
723
775
|
}
|
|
724
776
|
};
|
|
725
777
|
|
|
778
|
+
// src/patches/model-reasoning-efforts/client/index.tsx
|
|
779
|
+
var import_react5 = require("react");
|
|
780
|
+
var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
781
|
+
|
|
782
|
+
// src/patches/model-reasoning-efforts/shared.ts
|
|
783
|
+
var MODEL_REASONING_EFFORTS_PATCH_ID = "model-reasoning-efforts";
|
|
784
|
+
var LLM_PI_AI_SETTINGS_NAMESPACE = "llm-pi-ai";
|
|
785
|
+
var THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
786
|
+
|
|
787
|
+
// src/patches/model-reasoning-efforts/client/index.tsx
|
|
788
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
789
|
+
var EFFORT_BUTTON_ATTR = "data-dshmore-effort";
|
|
790
|
+
var LEVEL_LABELS = {
|
|
791
|
+
off: "\u4E0D\u601D\u8003",
|
|
792
|
+
minimal: "\u6781\u7B80",
|
|
793
|
+
low: "\u4F4E",
|
|
794
|
+
medium: "\u4E2D",
|
|
795
|
+
high: "\u9AD8",
|
|
796
|
+
xhigh: "\u6781\u9AD8",
|
|
797
|
+
max: "\u6700\u9AD8"
|
|
798
|
+
};
|
|
799
|
+
function emptyDraft() {
|
|
800
|
+
return { nonReasoning: false, levels: {} };
|
|
801
|
+
}
|
|
802
|
+
function draftFromServer(efforts) {
|
|
803
|
+
if (efforts === false) return { nonReasoning: true, levels: {} };
|
|
804
|
+
if (efforts !== null && typeof efforts === "object") {
|
|
805
|
+
const levels = {};
|
|
806
|
+
for (const level of THINKING_LEVELS) {
|
|
807
|
+
const wire = efforts[level];
|
|
808
|
+
if (wire !== void 0) levels[level] = { enabled: true, wire: wire ?? "" };
|
|
809
|
+
}
|
|
810
|
+
return { nonReasoning: false, levels };
|
|
811
|
+
}
|
|
812
|
+
return emptyDraft();
|
|
813
|
+
}
|
|
814
|
+
function buildDict(draft) {
|
|
815
|
+
const dict = {};
|
|
816
|
+
for (const level of THINKING_LEVELS) {
|
|
817
|
+
const entry = draft.levels[level];
|
|
818
|
+
if (entry === void 0 || !entry.enabled) continue;
|
|
819
|
+
dict[level] = level === "off" ? null : entry.wire;
|
|
820
|
+
}
|
|
821
|
+
return dict;
|
|
822
|
+
}
|
|
823
|
+
function summaryLabel(efforts) {
|
|
824
|
+
if (efforts === false) return "\u4E0D\u652F\u6301\u601D\u8003";
|
|
825
|
+
if (efforts === null || typeof efforts !== "object") return "\u672A\u914D\u7F6E";
|
|
826
|
+
const parts = THINKING_LEVELS.filter((level) => level !== "off" && efforts[level] !== void 0).map((level) => LEVEL_LABELS[level]);
|
|
827
|
+
return parts.length === 0 ? "\u672A\u914D\u7F6E" : parts.join("\u3001");
|
|
828
|
+
}
|
|
829
|
+
function findModelEntries() {
|
|
830
|
+
const entries = [];
|
|
831
|
+
const catalogs = document.querySelectorAll('[class*="modelCatalog"]');
|
|
832
|
+
for (const catalog of catalogs) {
|
|
833
|
+
for (const entry of catalog.querySelectorAll('[class*="modelEntry"]')) entries.push(entry);
|
|
834
|
+
}
|
|
835
|
+
return entries;
|
|
836
|
+
}
|
|
837
|
+
function providerRouteOf(entry) {
|
|
838
|
+
const editor = entry.closest('[class*="editor"]');
|
|
839
|
+
if (editor === null) return null;
|
|
840
|
+
const routeSpan = editor.querySelector('[class*="editorRoute"]');
|
|
841
|
+
const route = routeSpan?.textContent?.trim();
|
|
842
|
+
if (route !== void 0 && route !== "") return route;
|
|
843
|
+
const rowCard = editor.closest('[class*="rowCard"]');
|
|
844
|
+
const name = rowCard?.querySelector('[class*="rowName"]')?.textContent?.trim();
|
|
845
|
+
return name !== void 0 && name !== "" ? name : null;
|
|
846
|
+
}
|
|
847
|
+
function modelIdOf(entry) {
|
|
848
|
+
const input = entry.querySelector('[class*="modelRow"] input[type="text"]');
|
|
849
|
+
const id = input?.value.trim();
|
|
850
|
+
return id !== void 0 && id !== "" ? id : null;
|
|
851
|
+
}
|
|
852
|
+
function EffortEditorBody({ draft, setDraft, writable, busy }) {
|
|
853
|
+
const toggleLevel = (level, enabled) => {
|
|
854
|
+
setDraft((current) => {
|
|
855
|
+
const existing = current.levels[level];
|
|
856
|
+
const levels = { ...current.levels };
|
|
857
|
+
levels[level] = existing === void 0 ? { enabled, wire: level === "off" ? "" : level } : { ...existing, enabled };
|
|
858
|
+
return { ...current, levels };
|
|
859
|
+
});
|
|
860
|
+
};
|
|
861
|
+
const setWire = (level, wire) => {
|
|
862
|
+
setDraft((current) => {
|
|
863
|
+
const existing = current.levels[level];
|
|
864
|
+
if (existing === void 0) return current;
|
|
865
|
+
return { ...current, levels: { ...current.levels, [level]: { ...existing, wire } } };
|
|
866
|
+
});
|
|
867
|
+
};
|
|
868
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-effort-editor", children: [
|
|
869
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-effort-switch", children: [
|
|
870
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
871
|
+
"input",
|
|
872
|
+
{
|
|
873
|
+
type: "checkbox",
|
|
874
|
+
role: "switch",
|
|
875
|
+
checked: draft.nonReasoning,
|
|
876
|
+
disabled: !writable || busy,
|
|
877
|
+
onChange: (event) => {
|
|
878
|
+
setDraft((current) => ({ ...current, nonReasoning: event.currentTarget.checked }));
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
),
|
|
882
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u8BE5\u6A21\u578B\u4E0D\u652F\u6301\u601D\u8003\uFF08reasoningEfforts: false\uFF09" })
|
|
883
|
+
] }),
|
|
884
|
+
!draft.nonReasoning && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dshmore-effort-levels", children: THINKING_LEVELS.map((level) => {
|
|
885
|
+
const entry = draft.levels[level];
|
|
886
|
+
const enabled = entry?.enabled === true;
|
|
887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-effort-level", children: [
|
|
888
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
889
|
+
"input",
|
|
890
|
+
{
|
|
891
|
+
type: "checkbox",
|
|
892
|
+
checked: enabled,
|
|
893
|
+
disabled: !writable || busy,
|
|
894
|
+
onChange: (event) => {
|
|
895
|
+
toggleLevel(level, event.currentTarget.checked);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
),
|
|
899
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dshmore-effort-level-label", children: LEVEL_LABELS[level] }),
|
|
900
|
+
enabled && level !== "off" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
901
|
+
"input",
|
|
902
|
+
{
|
|
903
|
+
className: "dshmore-effort-wire",
|
|
904
|
+
type: "text",
|
|
905
|
+
value: entry?.wire ?? "",
|
|
906
|
+
disabled: !writable || busy,
|
|
907
|
+
placeholder: "\u7EBF\u4E0A\u503C",
|
|
908
|
+
"aria-label": `${LEVEL_LABELS[level]} \u7684\u7EBF\u4E0A\u503C`,
|
|
909
|
+
onChange: (event) => {
|
|
910
|
+
setWire(level, event.currentTarget.value);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
)
|
|
914
|
+
] }, level);
|
|
915
|
+
}) })
|
|
916
|
+
] });
|
|
917
|
+
}
|
|
918
|
+
function EffortEditorModal({ provider, modelId, initial, writable, onClose }) {
|
|
919
|
+
const [draft, setDraft] = (0, import_react5.useState)(() => draftFromServer(initial ?? null));
|
|
920
|
+
const [busy, setBusy] = (0, import_react5.useState)(false);
|
|
921
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
922
|
+
(0, import_react5.useEffect)(() => {
|
|
923
|
+
setDraft(draftFromServer(initial ?? null));
|
|
924
|
+
}, [initial]);
|
|
925
|
+
const known = initial !== void 0;
|
|
926
|
+
const save = async () => {
|
|
927
|
+
if (!known) return;
|
|
928
|
+
const payload = draft.nonReasoning ? false : buildDict(draft);
|
|
929
|
+
if (payload !== false && !THINKING_LEVELS.some((level) => level !== "off" && payload[level] !== void 0)) {
|
|
930
|
+
setError("\u81F3\u5C11\u9700\u8981\u5F00\u542F\u4E00\u4E2A\u975E\u300C\u4E0D\u601D\u8003\u300D\u7684\u601D\u8003\u7EA7\u522B\uFF0C\u6216\u4F7F\u7528\u300C\u6E05\u9664\u914D\u7F6E\u300D\u3002");
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
setBusy(true);
|
|
934
|
+
setError(null);
|
|
935
|
+
try {
|
|
936
|
+
await callPatchApi(MODEL_REASONING_EFFORTS_PATCH_ID, "save", {
|
|
937
|
+
provider,
|
|
938
|
+
modelId,
|
|
939
|
+
reasoningEfforts: payload
|
|
940
|
+
});
|
|
941
|
+
onClose();
|
|
942
|
+
} catch (caught) {
|
|
943
|
+
setError(apiErrorText(caught));
|
|
944
|
+
} finally {
|
|
945
|
+
setBusy(false);
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
const clear = async () => {
|
|
949
|
+
if (!known) return;
|
|
950
|
+
setBusy(true);
|
|
951
|
+
setError(null);
|
|
952
|
+
try {
|
|
953
|
+
await callPatchApi(MODEL_REASONING_EFFORTS_PATCH_ID, "save", {
|
|
954
|
+
provider,
|
|
955
|
+
modelId,
|
|
956
|
+
reasoningEfforts: null
|
|
957
|
+
});
|
|
958
|
+
onClose();
|
|
959
|
+
} catch (caught) {
|
|
960
|
+
setError(apiErrorText(caught));
|
|
961
|
+
} finally {
|
|
962
|
+
setBusy(false);
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
966
|
+
import_dsh_client_ui_primitives5.Modal,
|
|
967
|
+
{
|
|
968
|
+
open: true,
|
|
969
|
+
onClose,
|
|
970
|
+
title: `\u601D\u8003\u5F3A\u5EA6 \xB7 ${modelId}`,
|
|
971
|
+
closeLabel: "\u5173\u95ED",
|
|
972
|
+
description: `\u63D0\u4F9B\u65B9 ${provider}`,
|
|
973
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
974
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: busy, onClick: onClose, children: "\u5173\u95ED" }),
|
|
975
|
+
known && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: !writable || busy, onClick: () => {
|
|
976
|
+
void clear();
|
|
977
|
+
}, children: "\u6E05\u9664\u914D\u7F6E" }),
|
|
978
|
+
known && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "primary", disabled: !writable || busy, onClick: () => {
|
|
979
|
+
void save();
|
|
980
|
+
}, children: busy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58" })
|
|
981
|
+
] }),
|
|
982
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-effort-dialog-body", children: [
|
|
983
|
+
!known && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dshmore-effort-note", children: "\u8BE5\u6A21\u578B\u5C1A\u672A\u4FDD\u5B58\u5230 settings.yaml\uFF0C\u8BF7\u5148\u5728\u4E0A\u65B9\u4FDD\u5B58\u63D0\u4F9B\u65B9\u914D\u7F6E\u3002" }),
|
|
984
|
+
known && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EffortEditorBody, { draft, setDraft, writable, busy }),
|
|
985
|
+
!writable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dshmore-effort-warn", children: "\u5F53\u524D Settings \u5B58\u50A8\u4E3A\u53EA\u8BFB\uFF0C\u65E0\u6CD5\u4FDD\u5B58\u4FEE\u6539\u3002" }),
|
|
986
|
+
error !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dshmore-effort-error", children: error })
|
|
987
|
+
] })
|
|
988
|
+
}
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
function ModelsPageEffortPortal(props) {
|
|
992
|
+
const settings = (0, import_react5.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot, props.activation.getSnapshot);
|
|
993
|
+
const enabled = settings[MODEL_REASONING_EFFORTS_PATCH_ID];
|
|
994
|
+
const scopeSnapshot = (0, import_react5.useSyncExternalStore)(props.scope.subscribe, props.scope.getSnapshot, props.scope.getSnapshot);
|
|
995
|
+
const [editing, setEditing] = (0, import_react5.useState)(null);
|
|
996
|
+
const [data, setData] = (0, import_react5.useState)(null);
|
|
997
|
+
const dataRef = (0, import_react5.useRef)(data);
|
|
998
|
+
dataRef.current = data;
|
|
999
|
+
const generation = (0, import_react5.useRef)(0);
|
|
1000
|
+
const fillingRef = (0, import_react5.useRef)(false);
|
|
1001
|
+
const reload = (0, import_react5.useCallback)(async () => {
|
|
1002
|
+
const current = ++generation.current;
|
|
1003
|
+
try {
|
|
1004
|
+
const snapshot = await callPatchApi(MODEL_REASONING_EFFORTS_PATCH_ID, "read", {});
|
|
1005
|
+
if (generation.current !== current) return;
|
|
1006
|
+
setData(snapshot);
|
|
1007
|
+
if (enabled && snapshot.writable && snapshot.rows.some((row) => row.reasoningEfforts === null) && !fillingRef.current) {
|
|
1008
|
+
fillingRef.current = true;
|
|
1009
|
+
void callPatchApi(MODEL_REASONING_EFFORTS_PATCH_ID, "fillDefaults", {}).catch(() => void 0).finally(() => {
|
|
1010
|
+
fillingRef.current = false;
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
} catch {
|
|
1014
|
+
}
|
|
1015
|
+
}, [enabled]);
|
|
1016
|
+
(0, import_react5.useEffect)(() => {
|
|
1017
|
+
if (enabled) void reload();
|
|
1018
|
+
}, [enabled, reload, scopeSnapshot]);
|
|
1019
|
+
const syncButtons = (0, import_react5.useCallback)(() => {
|
|
1020
|
+
if (!enabled) return;
|
|
1021
|
+
const active = /* @__PURE__ */ new Set();
|
|
1022
|
+
for (const entry of findModelEntries()) {
|
|
1023
|
+
const provider = providerRouteOf(entry);
|
|
1024
|
+
const modelId = modelIdOf(entry);
|
|
1025
|
+
if (provider === null || modelId === null) continue;
|
|
1026
|
+
active.add(entry);
|
|
1027
|
+
let button = entry.querySelector(`[${EFFORT_BUTTON_ATTR}]`);
|
|
1028
|
+
if (button === null) {
|
|
1029
|
+
button = document.createElement("button");
|
|
1030
|
+
button.type = "button";
|
|
1031
|
+
button.className = "dshmore-effort-row-button";
|
|
1032
|
+
button.setAttribute(EFFORT_BUTTON_ATTR, "");
|
|
1033
|
+
button.addEventListener("click", () => {
|
|
1034
|
+
const route = button?.dataset.provider;
|
|
1035
|
+
const model = button?.dataset.model;
|
|
1036
|
+
if (route !== void 0 && model !== void 0) setEditing({ provider: route, modelId: model });
|
|
1037
|
+
});
|
|
1038
|
+
const row = entry.querySelector('[class*="modelRow"]');
|
|
1039
|
+
if (row === null) continue;
|
|
1040
|
+
entry.insertBefore(button, row.nextSibling);
|
|
1041
|
+
}
|
|
1042
|
+
if (button.dataset.provider !== provider) button.dataset.provider = provider;
|
|
1043
|
+
if (button.dataset.model !== modelId) button.dataset.model = modelId;
|
|
1044
|
+
const rowData = dataRef.current?.rows.find((row) => row.provider === provider && row.modelId === modelId);
|
|
1045
|
+
const text = rowData === void 0 ? "\u601D\u8003\u5F3A\u5EA6" : `\u601D\u8003\u5F3A\u5EA6 \xB7 ${summaryLabel(rowData.reasoningEfforts)}`;
|
|
1046
|
+
if (button.textContent !== text) button.textContent = text;
|
|
1047
|
+
}
|
|
1048
|
+
document.querySelectorAll(`[${EFFORT_BUTTON_ATTR}]`).forEach((button) => {
|
|
1049
|
+
const host = button.parentElement;
|
|
1050
|
+
if (host === null || !active.has(host)) button.remove();
|
|
1051
|
+
});
|
|
1052
|
+
}, [enabled]);
|
|
1053
|
+
(0, import_react5.useEffect)(() => {
|
|
1054
|
+
if (!enabled) {
|
|
1055
|
+
document.querySelectorAll(`[${EFFORT_BUTTON_ATTR}]`).forEach((element) => element.remove());
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
let frame = null;
|
|
1059
|
+
const schedule = () => {
|
|
1060
|
+
if (frame !== null) return;
|
|
1061
|
+
frame = window.requestAnimationFrame(() => {
|
|
1062
|
+
frame = null;
|
|
1063
|
+
syncButtons();
|
|
1064
|
+
});
|
|
1065
|
+
};
|
|
1066
|
+
syncButtons();
|
|
1067
|
+
const observer = new MutationObserver(schedule);
|
|
1068
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
1069
|
+
return () => {
|
|
1070
|
+
observer.disconnect();
|
|
1071
|
+
if (frame !== null) window.cancelAnimationFrame(frame);
|
|
1072
|
+
};
|
|
1073
|
+
}, [enabled, syncButtons]);
|
|
1074
|
+
(0, import_react5.useEffect)(() => {
|
|
1075
|
+
if (enabled) syncButtons();
|
|
1076
|
+
}, [enabled, syncButtons, data]);
|
|
1077
|
+
const editingRow = editing === null ? void 0 : data?.rows.find((row) => row.provider === editing.provider && row.modelId === editing.modelId);
|
|
1078
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1079
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: effortStyles }),
|
|
1080
|
+
editing !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1081
|
+
EffortEditorModal,
|
|
1082
|
+
{
|
|
1083
|
+
provider: editing.provider,
|
|
1084
|
+
modelId: editing.modelId,
|
|
1085
|
+
initial: editingRow === void 0 ? void 0 : editingRow.reasoningEfforts,
|
|
1086
|
+
writable: data?.writable ?? true,
|
|
1087
|
+
onClose: () => {
|
|
1088
|
+
setEditing(null);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
)
|
|
1092
|
+
] });
|
|
1093
|
+
}
|
|
1094
|
+
var effortStyles = `
|
|
1095
|
+
.dshmore-effort-row-button { box-sizing: border-box; width: 100%; height: 28px; color: var(--dsw-alias-label-secondary); font: inherit; cursor: pointer; background: transparent; border: 1px dashed var(--dsw-alias-border-l3); border-radius: 6px; margin-top: 6px; padding: 0 10px; font-size: 12px; line-height: 18px; display: inline-flex; align-items: center; justify-content: flex-start; gap: 6px; }
|
|
1096
|
+
.dshmore-effort-row-button:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
|
|
1097
|
+
.dshmore-effort-dialog-body { box-sizing: border-box; display: flex; flex-direction: column; gap: 12px; width: 100%; min-width: 0; overflow: hidden; }
|
|
1098
|
+
.dshmore-effort-editor { display: flex; flex-direction: column; gap: 12px; }
|
|
1099
|
+
.dshmore-effort-switch, .dshmore-effort-level { display: flex; align-items: center; gap: 8px; color: var(--dsw-alias-label-secondary); font-size: 13px; line-height: 20px; cursor: pointer; }
|
|
1100
|
+
.dshmore-effort-switch input, .dshmore-effort-level input[type="checkbox"] { accent-color: var(--dsw-alias-state-business-primary); cursor: pointer; }
|
|
1101
|
+
.dshmore-effort-levels { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px 12px; }
|
|
1102
|
+
.dshmore-effort-level-label { flex: none; }
|
|
1103
|
+
.dshmore-effort-wire { box-sizing: border-box; height: 28px; min-width: 0; width: 100%; font: inherit; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; padding: 0 8px; font-size: 12px; line-height: 18px; }
|
|
1104
|
+
.dshmore-effort-wire:focus { border-color: var(--dsw-alias-brand-primary); outline: none; }
|
|
1105
|
+
.dshmore-effort-wire::placeholder { color: var(--dsw-alias-label-dimmed); }
|
|
1106
|
+
.dshmore-effort-note { color: var(--dsw-alias-label-tertiary); margin: 0; font-size: 12px; line-height: 18px; }
|
|
1107
|
+
.dshmore-effort-warn { color: var(--dsw-alias-state-warn-label); margin: 0; font-size: 12px; line-height: 18px; }
|
|
1108
|
+
.dshmore-effort-error { padding: 8px 10px; border-radius: 8px; background: rgba(208,58,58,.10); color: var(--dsw-alias-state-error-primary, rgb(220,90,90)); font-size: 12px; line-height: 18px; }
|
|
1109
|
+
`;
|
|
1110
|
+
var clientPatch3 = {
|
|
1111
|
+
id: MODEL_REASONING_EFFORTS_PATCH_ID,
|
|
1112
|
+
install: (ctx, activation) => {
|
|
1113
|
+
const scope = ctx.settingsScope.bind({ namespace: LLM_PI_AI_SETTINGS_NAMESPACE });
|
|
1114
|
+
const boundScope = {
|
|
1115
|
+
getSnapshot: scope.getSnapshot.bind(scope),
|
|
1116
|
+
subscribe: scope.subscribe.bind(scope),
|
|
1117
|
+
set: scope.set.bind(scope),
|
|
1118
|
+
unset: scope.unset.bind(scope)
|
|
1119
|
+
};
|
|
1120
|
+
ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
1121
|
+
name: "shell.overlay",
|
|
1122
|
+
id: `${PLUGIN_NAME}-${MODEL_REASONING_EFFORTS_PATCH_ID}`,
|
|
1123
|
+
order: 90,
|
|
1124
|
+
registrant: PLUGIN_NAME
|
|
1125
|
+
}, (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ModelsPageEffortPortal, { ...props, scope: boundScope, activation })));
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
// src/patches/conversation-quick-navigation/client/index.tsx
|
|
1130
|
+
var import_react6 = require("react");
|
|
1131
|
+
var import_react_dom = require("react-dom");
|
|
1132
|
+
var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
1133
|
+
|
|
1134
|
+
// src/kernel/message-visibility.ts
|
|
1135
|
+
var MESSAGE_VISIBILITY_PROJECTION_KEY = "dshMoreMessageDelete";
|
|
1136
|
+
|
|
1137
|
+
// src/patches/conversation-quick-navigation/shared.ts
|
|
1138
|
+
var CONVERSATION_QUICK_NAVIGATION_PATCH_ID = "conversation-quick-navigation";
|
|
1139
|
+
|
|
1140
|
+
// src/platform/dsh/client/message-content.ts
|
|
1141
|
+
function contentText(content) {
|
|
1142
|
+
return content.filter((block) => block.type === "text").map((block) => block.text).join(" ").replace(/\s+/g, " ").trim();
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// src/patches/conversation-quick-navigation/client/navigation.ts
|
|
1146
|
+
var MAX_LABEL_CODE_POINTS = 72;
|
|
1147
|
+
function conciseLabel(content, fallbackIndex) {
|
|
1148
|
+
const text = contentText(content);
|
|
1149
|
+
if (text === "") return `\u7B2C ${String(fallbackIndex)} \u8F6E \xB7 \u975E\u6587\u672C\u6D88\u606F`;
|
|
1150
|
+
const codePoints = [...text];
|
|
1151
|
+
if (codePoints.length <= MAX_LABEL_CODE_POINTS) return text;
|
|
1152
|
+
return `${codePoints.slice(0, MAX_LABEL_CODE_POINTS - 1).join("")}\u2026`;
|
|
1153
|
+
}
|
|
1154
|
+
function turnSummary(node, key, index) {
|
|
1155
|
+
const candidate = node;
|
|
1156
|
+
if (candidate?.kind !== "user" && candidate?.kind !== "steering") return null;
|
|
1157
|
+
if (!Number.isSafeInteger(candidate.data?.seq) || !Array.isArray(candidate.data?.content)) return null;
|
|
1158
|
+
return {
|
|
1159
|
+
key,
|
|
1160
|
+
seq: candidate.data.seq,
|
|
1161
|
+
label: conciseLabel(candidate.data.content, index)
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
function sameTurns(left, right) {
|
|
1165
|
+
return left.length === right.length && left.every((turn, index) => {
|
|
1166
|
+
const other = right[index];
|
|
1167
|
+
return other !== void 0 && turn.key === other.key && turn.seq === other.seq && turn.label === other.label;
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
function createConversationTurnSelector() {
|
|
1171
|
+
let previousOrder;
|
|
1172
|
+
let previous = [];
|
|
1173
|
+
return (snapshot) => {
|
|
1174
|
+
if (snapshot.chat.order === previousOrder) return previous;
|
|
1175
|
+
previousOrder = snapshot.chat.order;
|
|
1176
|
+
const next = [];
|
|
1177
|
+
for (const key of snapshot.chat.order) {
|
|
1178
|
+
const summary = turnSummary(snapshot.chat.nodes.get(key), key, next.length + 1);
|
|
1179
|
+
if (summary !== null) next.push(summary);
|
|
1180
|
+
}
|
|
1181
|
+
if (!sameTurns(previous, next)) previous = next;
|
|
1182
|
+
return previous;
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
function historyWindowSignature(snapshot) {
|
|
1186
|
+
const first = snapshot.chat.order[0] ?? "";
|
|
1187
|
+
const last = snapshot.chat.order.at(-1) ?? "";
|
|
1188
|
+
return `${first}\0${last}\0${String(snapshot.chat.order.length)}`;
|
|
1189
|
+
}
|
|
1190
|
+
function shouldAutoLoadOlder(state) {
|
|
1191
|
+
return state.enabled && state.surfaceAvailable && state.hasMore && !state.loadingOlder && !state.paused;
|
|
1192
|
+
}
|
|
1193
|
+
function activeTurnAt(positions, readingLine) {
|
|
1194
|
+
let active = positions[0]?.key ?? null;
|
|
1195
|
+
for (const position of positions) {
|
|
1196
|
+
if (position.top > readingLine) break;
|
|
1197
|
+
active = position.key;
|
|
1198
|
+
}
|
|
1199
|
+
return active;
|
|
1200
|
+
}
|
|
1201
|
+
function scrollOffsetForRow(currentScrollTop, scrollportTop, rowTop, topInset = 20) {
|
|
1202
|
+
return Math.max(0, currentScrollTop + rowTop - scrollportTop - topInset);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// src/patches/conversation-quick-navigation/client/index.tsx
|
|
1206
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1207
|
+
var MAX_NO_PROGRESS_ATTEMPTS = 3;
|
|
1208
|
+
var MENU_LIST_ID = "dshmore-conversation-nav-list";
|
|
1209
|
+
var navigationCollapsedPreference = false;
|
|
1210
|
+
function conversationRow(root, key) {
|
|
1211
|
+
for (const row of root.querySelectorAll("[data-chat-flow-key]")) {
|
|
1212
|
+
if (row.dataset.chatFlowKey === key) return row;
|
|
1213
|
+
}
|
|
1214
|
+
return null;
|
|
1215
|
+
}
|
|
1216
|
+
function sessionRoot(marker) {
|
|
1217
|
+
return marker?.closest("[data-phase]") ?? null;
|
|
1218
|
+
}
|
|
1219
|
+
function conversationScrollport(marker) {
|
|
1220
|
+
return sessionRoot(marker)?.querySelector("[data-conversation-scroll]") ?? null;
|
|
1221
|
+
}
|
|
1222
|
+
function nativeLoadOlderButton(scrollport) {
|
|
1223
|
+
const flow = scrollport.querySelector("[data-chat-flow]");
|
|
1224
|
+
if (flow === null) return null;
|
|
1225
|
+
for (const child of flow.children) {
|
|
1226
|
+
if (child instanceof HTMLElement && child.dataset.chatFlowKey !== void 0) break;
|
|
1227
|
+
const button = child.querySelector("button");
|
|
1228
|
+
if (button !== null) return button;
|
|
1229
|
+
}
|
|
1230
|
+
return null;
|
|
1231
|
+
}
|
|
1232
|
+
function ConversationNavigationMenu({
|
|
1233
|
+
turns,
|
|
1234
|
+
activeKey,
|
|
1235
|
+
hasMore,
|
|
1236
|
+
loadingOlder,
|
|
1237
|
+
autoLoadPaused,
|
|
1238
|
+
collapsed,
|
|
1239
|
+
onRetry,
|
|
1240
|
+
onToggleCollapsed,
|
|
1241
|
+
onJump,
|
|
1242
|
+
listRef
|
|
1243
|
+
}) {
|
|
1244
|
+
const loading = hasMore && !autoLoadPaused;
|
|
1245
|
+
const compactStatus = autoLoadPaused ? `${String(turns.length)} \u8F6E \xB7 \u5DF2\u6682\u505C` : loading ? `${String(turns.length)} \u8F6E \xB7 \u52A0\u8F7D\u4E2D` : `${String(turns.length)} \u8F6E`;
|
|
1246
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1247
|
+
"nav",
|
|
1248
|
+
{
|
|
1249
|
+
className: "dshmore-conversation-nav-menu",
|
|
1250
|
+
"data-collapsed": collapsed ? "true" : "false",
|
|
1251
|
+
"aria-label": "\u5F53\u524D\u4F1A\u8BDD\u7684\u5BF9\u8BDD\u76EE\u5F55",
|
|
1252
|
+
children: [
|
|
1253
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("header", { className: "dshmore-conversation-nav-header", children: [
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-heading", children: [
|
|
1255
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-title-row", children: [
|
|
1256
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dshmore-conversation-nav-title", children: "\u5BF9\u8BDD\u76EE\u5F55" }),
|
|
1257
|
+
collapsed && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-compact-status", role: "status", "aria-live": "polite", children: [
|
|
1258
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dshmore-conversation-nav-loading-dot", "aria-hidden": "true" }),
|
|
1259
|
+
compactStatus
|
|
1260
|
+
] })
|
|
1261
|
+
] }),
|
|
1262
|
+
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-count", role: "status", "aria-live": "polite", children: [
|
|
1263
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dshmore-conversation-nav-loading-dot", "aria-hidden": "true" }),
|
|
1264
|
+
autoLoadPaused ? `\u5DF2\u8F7D\u5165 ${String(turns.length)} \u8F6E\uFF0C\u81EA\u52A8\u52A0\u8F7D\u5DF2\u6682\u505C` : loading ? `\u6B63\u5728\u52A0\u8F7D\u5168\u90E8\u8BB0\u5F55 \xB7 \u5DF2\u8F7D\u5165 ${String(turns.length)} \u8F6E` : `\u5171 ${String(turns.length)} \u8F6E`
|
|
1265
|
+
] })
|
|
1266
|
+
] }),
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-actions", children: [
|
|
1268
|
+
!collapsed && autoLoadPaused && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "dshmore-conversation-nav-retry", onClick: onRetry, children: "\u7EE7\u7EED\u52A0\u8F7D" }),
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1270
|
+
"button",
|
|
1271
|
+
{
|
|
1272
|
+
type: "button",
|
|
1273
|
+
className: "dshmore-conversation-nav-toggle",
|
|
1274
|
+
"aria-label": collapsed ? "\u5C55\u5F00\u5BF9\u8BDD\u76EE\u5F55" : "\u6298\u53E0\u5BF9\u8BDD\u76EE\u5F55",
|
|
1275
|
+
"aria-controls": MENU_LIST_ID,
|
|
1276
|
+
"aria-expanded": !collapsed,
|
|
1277
|
+
onClick: onToggleCollapsed,
|
|
1278
|
+
children: collapsed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_dsh_client_ui_primitives6.IconChevronDownOutline14, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_dsh_client_ui_primitives6.IconChevronUpOutline14, { size: 14 })
|
|
1279
|
+
}
|
|
1280
|
+
)
|
|
1281
|
+
] })
|
|
1282
|
+
] }),
|
|
1283
|
+
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { id: MENU_LIST_ID, ref: listRef, className: "dshmore-conversation-nav-list", children: [
|
|
1284
|
+
turns.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dshmore-conversation-nav-empty", children: loadingOlder || hasMore ? "\u6B63\u5728\u8BFB\u53D6\u5386\u53F2\u8BB0\u5F55\u2026" : "\u5F53\u524D\u6CA1\u6709\u53EF\u5B9A\u4F4D\u7684\u5BF9\u8BDD" }),
|
|
1285
|
+
turns.map((turn, index) => {
|
|
1286
|
+
const active = turn.key === activeKey;
|
|
1287
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1288
|
+
"button",
|
|
1289
|
+
{
|
|
1290
|
+
type: "button",
|
|
1291
|
+
className: "dshmore-conversation-nav-item",
|
|
1292
|
+
"aria-current": active ? "location" : void 0,
|
|
1293
|
+
onClick: () => {
|
|
1294
|
+
onJump(turn.key);
|
|
1295
|
+
},
|
|
1296
|
+
children: [
|
|
1297
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dshmore-conversation-nav-index", children: String(index + 1).padStart(2, "0") }),
|
|
1298
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dshmore-conversation-nav-label", children: turn.label })
|
|
1299
|
+
]
|
|
1300
|
+
},
|
|
1301
|
+
turn.key
|
|
1302
|
+
);
|
|
1303
|
+
})
|
|
1304
|
+
] })
|
|
1305
|
+
]
|
|
1306
|
+
}
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
function ConversationQuickNavigation(props) {
|
|
1310
|
+
const settings = (0, import_react6.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot, props.activation.getSnapshot);
|
|
1311
|
+
const enabled = settings[CONVERSATION_QUICK_NAVIGATION_PATCH_ID];
|
|
1312
|
+
const selector = (0, import_react6.useMemo)(createConversationTurnSelector, [props.sessionId]);
|
|
1313
|
+
const allTurns = props.useSession(selector);
|
|
1314
|
+
const hasMore = props.useSession((snapshot) => snapshot.hasMore);
|
|
1315
|
+
const loadingOlder = props.useSession((snapshot) => snapshot.loadingOlder);
|
|
1316
|
+
const windowSignature = props.useSession(historyWindowSignature);
|
|
1317
|
+
const projected = props.useProjection(MESSAGE_VISIBILITY_PROJECTION_KEY);
|
|
1318
|
+
const hiddenSeqs = (0, import_react6.useMemo)(() => new Set(projected?.deletedSeqs ?? []), [projected]);
|
|
1319
|
+
const turns = (0, import_react6.useMemo)(
|
|
1320
|
+
() => allTurns.filter((turn) => !hiddenSeqs.has(turn.seq)),
|
|
1321
|
+
[allTurns, hiddenSeqs]
|
|
1322
|
+
);
|
|
1323
|
+
const markerRef = (0, import_react6.useRef)(null);
|
|
1324
|
+
const listRef = (0, import_react6.useRef)(null);
|
|
1325
|
+
const pendingLoadSignatureRef = (0, import_react6.useRef)(null);
|
|
1326
|
+
const noProgressAttemptsRef = (0, import_react6.useRef)(0);
|
|
1327
|
+
const [portalTarget, setPortalTarget] = (0, import_react6.useState)(null);
|
|
1328
|
+
const [activeKey, setActiveKey] = (0, import_react6.useState)(null);
|
|
1329
|
+
const [surfaceAvailable, setSurfaceAvailable] = (0, import_react6.useState)(false);
|
|
1330
|
+
const [composerInset, setComposerInset] = (0, import_react6.useState)(176);
|
|
1331
|
+
const [autoLoadPaused, setAutoLoadPaused] = (0, import_react6.useState)(false);
|
|
1332
|
+
const [loadTick, setLoadTick] = (0, import_react6.useState)(0);
|
|
1333
|
+
const [collapsed, setCollapsed] = (0, import_react6.useState)(() => navigationCollapsedPreference);
|
|
1334
|
+
(0, import_react6.useLayoutEffect)(() => {
|
|
1335
|
+
const root = sessionRoot(markerRef.current);
|
|
1336
|
+
setPortalTarget(root);
|
|
1337
|
+
if (root === null) return;
|
|
1338
|
+
const composer = root.querySelector("[data-composer-seat]");
|
|
1339
|
+
const updateInset = () => {
|
|
1340
|
+
setComposerInset(Math.max(96, (composer?.offsetHeight ?? 152) + 20));
|
|
1341
|
+
};
|
|
1342
|
+
updateInset();
|
|
1343
|
+
if (composer === null || typeof ResizeObserver === "undefined") return;
|
|
1344
|
+
const observer = new ResizeObserver(updateInset);
|
|
1345
|
+
observer.observe(composer);
|
|
1346
|
+
return () => {
|
|
1347
|
+
observer.disconnect();
|
|
1348
|
+
};
|
|
1349
|
+
}, [props.sessionId]);
|
|
1350
|
+
(0, import_react6.useEffect)(() => {
|
|
1351
|
+
pendingLoadSignatureRef.current = null;
|
|
1352
|
+
noProgressAttemptsRef.current = 0;
|
|
1353
|
+
setAutoLoadPaused(false);
|
|
1354
|
+
}, [enabled, props.sessionId]);
|
|
1355
|
+
(0, import_react6.useEffect)(() => {
|
|
1356
|
+
if (hasMore) return;
|
|
1357
|
+
pendingLoadSignatureRef.current = null;
|
|
1358
|
+
noProgressAttemptsRef.current = 0;
|
|
1359
|
+
setAutoLoadPaused(false);
|
|
1360
|
+
}, [hasMore]);
|
|
1361
|
+
(0, import_react6.useEffect)(() => {
|
|
1362
|
+
if (!enabled) {
|
|
1363
|
+
setActiveKey(null);
|
|
1364
|
+
setSurfaceAvailable(false);
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
let frame = null;
|
|
1368
|
+
let scrollport = null;
|
|
1369
|
+
const schedule = () => {
|
|
1370
|
+
if (frame !== null) return;
|
|
1371
|
+
frame = window.requestAnimationFrame(recompute);
|
|
1372
|
+
};
|
|
1373
|
+
const bindScrollport = (next) => {
|
|
1374
|
+
if (next === scrollport) return;
|
|
1375
|
+
scrollport?.removeEventListener("scroll", schedule);
|
|
1376
|
+
scrollport = next;
|
|
1377
|
+
scrollport?.addEventListener("scroll", schedule, { passive: true });
|
|
1378
|
+
};
|
|
1379
|
+
const recompute = () => {
|
|
1380
|
+
frame = null;
|
|
1381
|
+
const nextScrollport = conversationScrollport(markerRef.current);
|
|
1382
|
+
bindScrollport(nextScrollport);
|
|
1383
|
+
const flowAvailable = nextScrollport !== null && nextScrollport.querySelector("[data-chat-flow]") !== null;
|
|
1384
|
+
setSurfaceAvailable(flowAvailable);
|
|
1385
|
+
if (nextScrollport === null || !flowAvailable) {
|
|
1386
|
+
setActiveKey(null);
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
const viewport = nextScrollport.getBoundingClientRect();
|
|
1390
|
+
const readingLine = viewport.top + Math.min(120, nextScrollport.clientHeight * 0.24);
|
|
1391
|
+
const positions = [];
|
|
1392
|
+
for (const turn of turns) {
|
|
1393
|
+
const row = conversationRow(nextScrollport, turn.key);
|
|
1394
|
+
if (row !== null) positions.push({ key: turn.key, top: row.getBoundingClientRect().top });
|
|
1395
|
+
}
|
|
1396
|
+
setActiveKey(activeTurnAt(positions, readingLine));
|
|
1397
|
+
};
|
|
1398
|
+
const observer = new MutationObserver(schedule);
|
|
1399
|
+
const root = sessionRoot(markerRef.current);
|
|
1400
|
+
if (root !== null) observer.observe(root, { childList: true, subtree: true });
|
|
1401
|
+
window.addEventListener("resize", schedule);
|
|
1402
|
+
recompute();
|
|
1403
|
+
return () => {
|
|
1404
|
+
observer.disconnect();
|
|
1405
|
+
window.removeEventListener("resize", schedule);
|
|
1406
|
+
scrollport?.removeEventListener("scroll", schedule);
|
|
1407
|
+
if (frame !== null) window.cancelAnimationFrame(frame);
|
|
1408
|
+
};
|
|
1409
|
+
}, [enabled, turns]);
|
|
1410
|
+
(0, import_react6.useEffect)(() => {
|
|
1411
|
+
if (!shouldAutoLoadOlder({ enabled, surfaceAvailable, hasMore, loadingOlder, paused: autoLoadPaused })) return;
|
|
1412
|
+
const pendingSignature = pendingLoadSignatureRef.current;
|
|
1413
|
+
let delay2 = 0;
|
|
1414
|
+
if (pendingSignature !== null) {
|
|
1415
|
+
if (pendingSignature === windowSignature) {
|
|
1416
|
+
noProgressAttemptsRef.current += 1;
|
|
1417
|
+
if (noProgressAttemptsRef.current >= MAX_NO_PROGRESS_ATTEMPTS) {
|
|
1418
|
+
pendingLoadSignatureRef.current = null;
|
|
1419
|
+
setAutoLoadPaused(true);
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
delay2 = noProgressAttemptsRef.current * 350;
|
|
1423
|
+
} else {
|
|
1424
|
+
noProgressAttemptsRef.current = 0;
|
|
1425
|
+
}
|
|
1426
|
+
pendingLoadSignatureRef.current = null;
|
|
1427
|
+
}
|
|
1428
|
+
let frame = null;
|
|
1429
|
+
let retryTimer = null;
|
|
1430
|
+
let requestTimer = null;
|
|
1431
|
+
const request = () => {
|
|
1432
|
+
frame = window.requestAnimationFrame(() => {
|
|
1433
|
+
frame = null;
|
|
1434
|
+
const scrollport = conversationScrollport(markerRef.current);
|
|
1435
|
+
const button = scrollport === null ? null : nativeLoadOlderButton(scrollport);
|
|
1436
|
+
if (button === null || button.disabled) {
|
|
1437
|
+
retryTimer = window.setTimeout(() => {
|
|
1438
|
+
setLoadTick((current) => current + 1);
|
|
1439
|
+
}, 180);
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
pendingLoadSignatureRef.current = windowSignature;
|
|
1443
|
+
button.click();
|
|
1444
|
+
retryTimer = window.setTimeout(() => {
|
|
1445
|
+
setLoadTick((current) => current + 1);
|
|
1446
|
+
}, 1600);
|
|
1447
|
+
});
|
|
1448
|
+
};
|
|
1449
|
+
if (delay2 > 0) requestTimer = window.setTimeout(request, delay2);
|
|
1450
|
+
else request();
|
|
1451
|
+
return () => {
|
|
1452
|
+
if (frame !== null) window.cancelAnimationFrame(frame);
|
|
1453
|
+
if (retryTimer !== null) window.clearTimeout(retryTimer);
|
|
1454
|
+
if (requestTimer !== null) window.clearTimeout(requestTimer);
|
|
1455
|
+
};
|
|
1456
|
+
}, [autoLoadPaused, enabled, hasMore, loadTick, loadingOlder, surfaceAvailable, windowSignature]);
|
|
1457
|
+
(0, import_react6.useLayoutEffect)(() => {
|
|
1458
|
+
if (collapsed || activeKey === null) return;
|
|
1459
|
+
const list = listRef.current;
|
|
1460
|
+
const active = list?.querySelector('[aria-current="location"]');
|
|
1461
|
+
if (list === null || active === null || active === void 0) return;
|
|
1462
|
+
const top = active.offsetTop;
|
|
1463
|
+
const bottom = top + active.offsetHeight;
|
|
1464
|
+
if (top < list.scrollTop) list.scrollTop = top;
|
|
1465
|
+
else if (bottom > list.scrollTop + list.clientHeight) list.scrollTop = bottom - list.clientHeight;
|
|
1466
|
+
}, [activeKey, collapsed]);
|
|
1467
|
+
const retryAutoLoad = () => {
|
|
1468
|
+
pendingLoadSignatureRef.current = null;
|
|
1469
|
+
noProgressAttemptsRef.current = 0;
|
|
1470
|
+
setAutoLoadPaused(false);
|
|
1471
|
+
setLoadTick((current) => current + 1);
|
|
1472
|
+
};
|
|
1473
|
+
const toggleCollapsed = () => {
|
|
1474
|
+
setCollapsed((current) => {
|
|
1475
|
+
navigationCollapsedPreference = !current;
|
|
1476
|
+
return navigationCollapsedPreference;
|
|
1477
|
+
});
|
|
1478
|
+
};
|
|
1479
|
+
const jump = (key) => {
|
|
1480
|
+
const scrollport = conversationScrollport(markerRef.current);
|
|
1481
|
+
if (scrollport === null) return;
|
|
1482
|
+
const row = conversationRow(scrollport, key);
|
|
1483
|
+
if (row === null) return;
|
|
1484
|
+
const viewport = scrollport.getBoundingClientRect();
|
|
1485
|
+
const rowRect = row.getBoundingClientRect();
|
|
1486
|
+
const top = scrollOffsetForRow(scrollport.scrollTop, viewport.top, rowRect.top);
|
|
1487
|
+
const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1488
|
+
scrollport.scrollTo({ top, behavior: reducedMotion ? "auto" : "smooth" });
|
|
1489
|
+
setActiveKey(key);
|
|
1490
|
+
};
|
|
1491
|
+
const rootStyle = { "--dshmore-conversation-nav-bottom": `${String(composerInset)}px` };
|
|
1492
|
+
const surface = enabled && surfaceAvailable && portalTarget !== null ? (0, import_react_dom.createPortal)(
|
|
1493
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1494
|
+
"div",
|
|
1495
|
+
{
|
|
1496
|
+
className: "dshmore-conversation-nav-root",
|
|
1497
|
+
"data-collapsed": collapsed ? "true" : "false",
|
|
1498
|
+
style: rootStyle,
|
|
1499
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1500
|
+
ConversationNavigationMenu,
|
|
1501
|
+
{
|
|
1502
|
+
turns,
|
|
1503
|
+
activeKey,
|
|
1504
|
+
hasMore,
|
|
1505
|
+
loadingOlder,
|
|
1506
|
+
autoLoadPaused,
|
|
1507
|
+
collapsed,
|
|
1508
|
+
onRetry: retryAutoLoad,
|
|
1509
|
+
onToggleCollapsed: toggleCollapsed,
|
|
1510
|
+
onJump: jump,
|
|
1511
|
+
listRef
|
|
1512
|
+
}
|
|
1513
|
+
)
|
|
1514
|
+
}
|
|
1515
|
+
),
|
|
1516
|
+
portalTarget
|
|
1517
|
+
) : null;
|
|
1518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
1519
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { ref: markerRef, className: "dshmore-conversation-nav-marker", "aria-hidden": "true" }),
|
|
1520
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: navigationStyles }),
|
|
1521
|
+
surface
|
|
1522
|
+
] });
|
|
1523
|
+
}
|
|
1524
|
+
var navigationStyles = `
|
|
1525
|
+
.dshmore-conversation-nav-marker { display: none; }
|
|
1526
|
+
.dshmore-conversation-nav-root { position: absolute; z-index: 20; right: 14px; top: 78px; bottom: var(--dshmore-conversation-nav-bottom, 176px); width: min(286px, calc(100% - 40px)); pointer-events: none; display: flex; align-items: flex-start; font-family: var(--dsw-font-family); }
|
|
1527
|
+
.dshmore-conversation-nav-root[data-collapsed="true"] { bottom: auto; height: 58px; }
|
|
1528
|
+
.dshmore-conversation-nav-menu { box-sizing: border-box; width: 100%; max-height: min(620px, 100%); min-height: 0; overflow: hidden; pointer-events: auto; display: flex; flex-direction: column; border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-base); box-shadow: var(--dsw-shadow-lv1, var(--dsw-shadow-lv2)); animation: dshmore-conversation-nav-enter 150ms ease-out; }
|
|
1529
|
+
.dshmore-conversation-nav-menu[data-collapsed="true"] { height: 58px; max-height: 58px; }
|
|
1530
|
+
.dshmore-conversation-nav-header { box-sizing: border-box; flex: none; min-height: 58px; padding: 12px 12px 10px 14px; display: flex; align-items: center; justify-content: space-between; gap: 10px; border-bottom: 1px solid var(--dsw-alias-border-l3); }
|
|
1531
|
+
.dshmore-conversation-nav-menu[data-collapsed="true"] .dshmore-conversation-nav-header { height: 58px; min-height: 58px; padding: 0 12px 0 14px; border-bottom: 0; }
|
|
1532
|
+
.dshmore-conversation-nav-heading { min-width: 0; }
|
|
1533
|
+
.dshmore-conversation-nav-title-row { min-width: 0; display: flex; align-items: baseline; gap: 6px; }
|
|
1534
|
+
.dshmore-conversation-nav-title { font: var(--dsw-font-s-strong-14); }
|
|
1535
|
+
.dshmore-conversation-nav-compact-status { min-width: 0; overflow: hidden; color: var(--dsw-alias-label-caption); text-overflow: ellipsis; white-space: nowrap; font-size: 11px; line-height: 16px; }
|
|
1536
|
+
.dshmore-conversation-nav-count { margin-top: 2px; color: var(--dsw-alias-label-caption); font-size: 11px; line-height: 16px; text-wrap: pretty; }
|
|
1537
|
+
.dshmore-conversation-nav-loading-dot { width: 6px; height: 6px; margin-right: 6px; display: inline-block; border-radius: 999px; background: var(--dsw-alias-state-business-primary); vertical-align: 1px; animation: dshmore-conversation-nav-pulse 1.1s ease-in-out infinite; }
|
|
1538
|
+
.dshmore-conversation-nav-retry { flex: none; min-height: 28px; padding: 4px 9px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; color: var(--dsw-alias-label-secondary); background: transparent; cursor: pointer; font: inherit; font-size: 11px; }
|
|
1539
|
+
.dshmore-conversation-nav-retry:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover); }
|
|
1540
|
+
.dshmore-conversation-nav-actions { flex: none; display: flex; align-items: center; gap: 6px; }
|
|
1541
|
+
.dshmore-conversation-nav-toggle { box-sizing: border-box; width: 28px; height: 28px; flex: none; padding: 0; display: grid; place-items: center; border: 0; border-radius: 999px; color: var(--dsw-alias-label-secondary); background: transparent; cursor: pointer; }
|
|
1542
|
+
.dshmore-conversation-nav-toggle:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover); }
|
|
1543
|
+
.dshmore-conversation-nav-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 6px; scrollbar-width: thin; }
|
|
1544
|
+
.dshmore-conversation-nav-empty { padding: 18px 12px; color: var(--dsw-alias-label-caption); text-align: center; font-size: 12px; line-height: 18px; text-wrap: pretty; }
|
|
1545
|
+
.dshmore-conversation-nav-item { box-sizing: border-box; width: 100%; min-height: 46px; padding: 7px 9px; display: grid; grid-template-columns: 28px minmax(0, 1fr); align-items: start; gap: 2px; border: 0; border-radius: 9px; color: var(--dsw-alias-label-secondary); background: transparent; cursor: pointer; text-align: left; font-family: inherit; transition: background-color 120ms ease, color 120ms ease; }
|
|
1546
|
+
.dshmore-conversation-nav-item:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover); }
|
|
1547
|
+
.dshmore-conversation-nav-item:focus-visible, .dshmore-conversation-nav-retry:focus-visible, .dshmore-conversation-nav-toggle:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: -2px; }
|
|
1548
|
+
.dshmore-conversation-nav-item[aria-current="location"] { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover-solid); }
|
|
1549
|
+
.dshmore-conversation-nav-index { color: var(--dsw-alias-label-caption); font-size: 11px; line-height: 20px; font-variant-numeric: tabular-nums; }
|
|
1550
|
+
.dshmore-conversation-nav-item[aria-current="location"] .dshmore-conversation-nav-index { color: var(--dsw-alias-state-business-primary); font-weight: 600; }
|
|
1551
|
+
.dshmore-conversation-nav-label { min-width: 0; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; font-size: 13px; line-height: 20px; overflow-wrap: anywhere; text-wrap: pretty; }
|
|
1552
|
+
@keyframes dshmore-conversation-nav-enter { from { opacity: 0; transform: translateX(6px); } to { opacity: 1; transform: translateX(0); } }
|
|
1553
|
+
@keyframes dshmore-conversation-nav-pulse { 50% { opacity: .35; transform: scale(.82); } }
|
|
1554
|
+
@media (max-width: 720px) {
|
|
1555
|
+
.dshmore-conversation-nav-root { right: 8px; top: 74px; bottom: auto; width: calc(100% - 16px); height: min(220px, 32dvh); align-items: stretch; }
|
|
1556
|
+
.dshmore-conversation-nav-root[data-collapsed="true"] { height: 58px; }
|
|
1557
|
+
.dshmore-conversation-nav-menu { max-height: 100%; }
|
|
1558
|
+
}
|
|
1559
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1560
|
+
.dshmore-conversation-nav-menu, .dshmore-conversation-nav-loading-dot { animation: none; }
|
|
1561
|
+
.dshmore-conversation-nav-item { transition: none; }
|
|
1562
|
+
}
|
|
1563
|
+
`;
|
|
1564
|
+
var clientPatch4 = {
|
|
1565
|
+
id: CONVERSATION_QUICK_NAVIGATION_PATCH_ID,
|
|
1566
|
+
install: (ctx, activation) => {
|
|
1567
|
+
ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
|
|
1568
|
+
name: "conversation.session.header.utilities",
|
|
1569
|
+
id: `${PLUGIN_NAME}-${CONVERSATION_QUICK_NAVIGATION_PATCH_ID}`,
|
|
1570
|
+
order: 120,
|
|
1571
|
+
registrant: PLUGIN_NAME
|
|
1572
|
+
}, (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ConversationQuickNavigation, { ...props, activation })));
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
|
|
726
1576
|
// src/generated/client-registry.ts
|
|
727
1577
|
var MESSAGE_ACTION_PATCHES = [{ id: "message-edit", order: 100, useActions: useMessageActions }, { id: "message-delete", order: 200, useActions: useMessageActions2 }];
|
|
728
|
-
var CLIENT_PATCHES = [clientPatch, clientPatch2];
|
|
1578
|
+
var CLIENT_PATCHES = [clientPatch, clientPatch2, clientPatch3, clientPatch4];
|
|
729
1579
|
|
|
730
1580
|
// src/kernel/client/activation.ts
|
|
731
1581
|
var ClientPatchActivation = class {
|
|
@@ -748,19 +1598,19 @@ var ClientPatchActivation = class {
|
|
|
748
1598
|
};
|
|
749
1599
|
|
|
750
1600
|
// src/kernel/client/config-card.tsx
|
|
751
|
-
var
|
|
752
|
-
var
|
|
753
|
-
var
|
|
1601
|
+
var import_react7 = require("react");
|
|
1602
|
+
var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
1603
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
754
1604
|
function PatchConfigCard({ activation, initiallyOpen = false }) {
|
|
755
|
-
const scope = (0,
|
|
1605
|
+
const scope = (0, import_react7.useSyncExternalStore)(
|
|
756
1606
|
activation.subscribe,
|
|
757
1607
|
activation.getSettingsSnapshot,
|
|
758
1608
|
activation.getSettingsSnapshot
|
|
759
1609
|
);
|
|
760
1610
|
const settings = activation.getSnapshot();
|
|
761
|
-
const [open, setOpen] = (0,
|
|
762
|
-
const [busy, setBusy] = (0,
|
|
763
|
-
const [error, setError] = (0,
|
|
1611
|
+
const [open, setOpen] = (0, import_react7.useState)(initiallyOpen);
|
|
1612
|
+
const [busy, setBusy] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
1613
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
764
1614
|
if (scope.status === "unavailable") return null;
|
|
765
1615
|
const update = async (id, enabled) => {
|
|
766
1616
|
setBusy((current) => /* @__PURE__ */ new Set([...current, id]));
|
|
@@ -777,9 +1627,9 @@ function PatchConfigCard({ activation, initiallyOpen = false }) {
|
|
|
777
1627
|
});
|
|
778
1628
|
}
|
|
779
1629
|
};
|
|
780
|
-
return /* @__PURE__ */ (0,
|
|
781
|
-
/* @__PURE__ */ (0,
|
|
782
|
-
/* @__PURE__ */ (0,
|
|
1630
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { className: `dshmore-config-card${open ? " dshmore-config-card-open" : ""}`, children: [
|
|
1631
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: styles }),
|
|
1632
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
783
1633
|
"button",
|
|
784
1634
|
{
|
|
785
1635
|
type: "button",
|
|
@@ -790,23 +1640,23 @@ function PatchConfigCard({ activation, initiallyOpen = false }) {
|
|
|
790
1640
|
setOpen((current) => !current);
|
|
791
1641
|
},
|
|
792
1642
|
children: [
|
|
793
|
-
/* @__PURE__ */ (0,
|
|
794
|
-
/* @__PURE__ */ (0,
|
|
795
|
-
/* @__PURE__ */ (0,
|
|
1643
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dshmore-config-heading-copy", children: [
|
|
1644
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "DSH More" }),
|
|
1645
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "\u52A8\u6001\u5F00\u542F\u6216\u5173\u95ED\u72EC\u7ACB\u8865\u4E01\uFF0C\u9ED8\u8BA4\u5168\u90E8\u5F00\u542F\u3002" })
|
|
796
1646
|
] }),
|
|
797
|
-
/* @__PURE__ */ (0,
|
|
1647
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_dsh_client_ui_primitives7.IconChevronDownOutline14, { className: `dshmore-config-chevron${open ? " dshmore-config-chevron-open" : ""}` })
|
|
798
1648
|
]
|
|
799
1649
|
}
|
|
800
1650
|
),
|
|
801
|
-
open && /* @__PURE__ */ (0,
|
|
802
|
-
/* @__PURE__ */ (0,
|
|
1651
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dshmore-config-body", children: [
|
|
1652
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dshmore-config-list", children: PATCH_CATALOG.map((patch) => {
|
|
803
1653
|
const waiting = busy.has(patch.id);
|
|
804
|
-
return /* @__PURE__ */ (0,
|
|
805
|
-
/* @__PURE__ */ (0,
|
|
806
|
-
/* @__PURE__ */ (0,
|
|
807
|
-
/* @__PURE__ */ (0,
|
|
1654
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "dshmore-config-row", children: [
|
|
1655
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dshmore-config-copy", children: [
|
|
1656
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: patch.name }),
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: patch.description })
|
|
808
1658
|
] }),
|
|
809
|
-
/* @__PURE__ */ (0,
|
|
1659
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
810
1660
|
"input",
|
|
811
1661
|
{
|
|
812
1662
|
type: "checkbox",
|
|
@@ -821,9 +1671,9 @@ function PatchConfigCard({ activation, initiallyOpen = false }) {
|
|
|
821
1671
|
)
|
|
822
1672
|
] }, patch.id);
|
|
823
1673
|
}) }),
|
|
824
|
-
scope.status === "loading" && /* @__PURE__ */ (0,
|
|
825
|
-
scope.status === "ready" && !scope.writable && /* @__PURE__ */ (0,
|
|
826
|
-
error !== null && /* @__PURE__ */ (0,
|
|
1674
|
+
scope.status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "dshmore-config-note", children: "\u6B63\u5728\u8BFB\u53D6\u63D2\u4EF6\u914D\u7F6E\u2026" }),
|
|
1675
|
+
scope.status === "ready" && !scope.writable && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "dshmore-config-note", children: "\u5F53\u524D Settings \u5B58\u50A8\u4E3A\u53EA\u8BFB\u3002" }),
|
|
1676
|
+
error !== null && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "dshmore-config-error", children: error })
|
|
827
1677
|
] })
|
|
828
1678
|
] });
|
|
829
1679
|
}
|
|
@@ -833,21 +1683,15 @@ function installPatchConfigCard(ctx, activation) {
|
|
|
833
1683
|
key: PATCH_SETTINGS_NAMESPACE,
|
|
834
1684
|
priority: 90,
|
|
835
1685
|
registrant: PLUGIN_NAME
|
|
836
|
-
}, (props) => /* @__PURE__ */ (0,
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
// src/kernel/message-visibility.ts
|
|
840
|
-
var MESSAGE_VISIBILITY_PROJECTION_KEY = "dshMoreMessageDelete";
|
|
841
|
-
|
|
842
|
-
// src/platform/dsh/client/message-targets.tsx
|
|
843
|
-
var import_react6 = require("react");
|
|
844
|
-
|
|
845
|
-
// src/platform/dsh/client/message-content.ts
|
|
846
|
-
function contentText(content) {
|
|
847
|
-
return content.filter((block) => block.type === "text").map((block) => block.text).join(" ").replace(/\s+/g, " ").trim();
|
|
1686
|
+
}, (props) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PatchConfigCard, { ...props, activation })));
|
|
848
1687
|
}
|
|
849
1688
|
|
|
850
1689
|
// src/platform/dsh/client/message-targets.tsx
|
|
1690
|
+
var import_react8 = require("react");
|
|
1691
|
+
var EMPTY_MESSAGE_SURFACE = {
|
|
1692
|
+
rows: [],
|
|
1693
|
+
byKey: /* @__PURE__ */ new Map()
|
|
1694
|
+
};
|
|
851
1695
|
function messageNodeInfo(node) {
|
|
852
1696
|
const candidate = node;
|
|
853
1697
|
if (candidate?.kind === "user" && Number.isSafeInteger(candidate.data?.seq) && Array.isArray(candidate.data?.content)) {
|
|
@@ -876,6 +1720,38 @@ function presentationSeq(node) {
|
|
|
876
1720
|
if (Number.isSafeInteger(closing?.finalNode?.seq)) return closing?.finalNode?.seq;
|
|
877
1721
|
return void 0;
|
|
878
1722
|
}
|
|
1723
|
+
function sameSurfaceRow(left, right) {
|
|
1724
|
+
return left !== void 0 && left.key === right.key && left.presentationSeq === right.presentationSeq && left.action?.seq === right.action?.seq && left.action?.kind === right.action?.kind && left.action?.text === right.action?.text;
|
|
1725
|
+
}
|
|
1726
|
+
function createMessageSurfaceSelector(active = true) {
|
|
1727
|
+
if (!active) return () => EMPTY_MESSAGE_SURFACE;
|
|
1728
|
+
const nodeCache = /* @__PURE__ */ new WeakMap();
|
|
1729
|
+
let previous = EMPTY_MESSAGE_SURFACE;
|
|
1730
|
+
let previousOrder;
|
|
1731
|
+
return (snapshot) => {
|
|
1732
|
+
if (snapshot.chat.order === previousOrder) return previous;
|
|
1733
|
+
previousOrder = snapshot.chat.order;
|
|
1734
|
+
const rows = [];
|
|
1735
|
+
for (const key of snapshot.chat.order) {
|
|
1736
|
+
const node = snapshot.chat.nodes.get(key);
|
|
1737
|
+
if (node === void 0) continue;
|
|
1738
|
+
let row = nodeCache.get(node);
|
|
1739
|
+
if (row === void 0) {
|
|
1740
|
+
row = {
|
|
1741
|
+
key,
|
|
1742
|
+
presentationSeq: presentationSeq(node),
|
|
1743
|
+
action: messageNodeInfo(node)
|
|
1744
|
+
};
|
|
1745
|
+
nodeCache.set(node, row);
|
|
1746
|
+
}
|
|
1747
|
+
const retained = previous.byKey.get(key);
|
|
1748
|
+
rows.push(sameSurfaceRow(retained, row) ? retained : row);
|
|
1749
|
+
}
|
|
1750
|
+
if (rows.length === previous.rows.length && rows.every((row, index) => row === previous.rows[index])) return previous;
|
|
1751
|
+
previous = { rows, byKey: new Map(rows.map((row) => [row.key, row])) };
|
|
1752
|
+
return previous;
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
879
1755
|
function hostForRow(row, kind) {
|
|
880
1756
|
const existing = row.querySelector(":scope [data-dshmore-message-actions]");
|
|
881
1757
|
if (kind === "assistant") {
|
|
@@ -919,11 +1795,11 @@ function hostForRow(row, kind) {
|
|
|
919
1795
|
else row.appendChild(host);
|
|
920
1796
|
return host;
|
|
921
1797
|
}
|
|
1798
|
+
function sameTarget(left, right) {
|
|
1799
|
+
return right !== void 0 && left.key === right.key && left.seq === right.seq && left.host === right.host && left.text === right.text;
|
|
1800
|
+
}
|
|
922
1801
|
function sameTargets(left, right) {
|
|
923
|
-
return left.length === right.length && left.every((target, index) =>
|
|
924
|
-
const other = right[index];
|
|
925
|
-
return other !== void 0 && target.key === other.key && target.seq === other.seq && target.host === other.host && target.text === other.text;
|
|
926
|
-
});
|
|
1802
|
+
return left.length === right.length && left.every((target, index) => sameTarget(target, right[index]));
|
|
927
1803
|
}
|
|
928
1804
|
function trajectoryRecordKey(row) {
|
|
929
1805
|
const encoded = row.dataset.trajectoryRowKey;
|
|
@@ -944,68 +1820,153 @@ function trajectorySourceSeq(row) {
|
|
|
944
1820
|
const seq = Number(raw);
|
|
945
1821
|
return Number.isSafeInteger(seq) && seq >= 0 ? seq : void 0;
|
|
946
1822
|
}
|
|
947
|
-
function useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys) {
|
|
948
|
-
const
|
|
949
|
-
const
|
|
950
|
-
(0,
|
|
1823
|
+
function useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, active = true) {
|
|
1824
|
+
const selector = (0, import_react8.useMemo)(() => createMessageSurfaceSelector(active), [active, props.sessionId]);
|
|
1825
|
+
const surface = props.useSession(selector);
|
|
1826
|
+
const surfaceRef = (0, import_react8.useRef)(surface);
|
|
1827
|
+
const hiddenSeqsRef = (0, import_react8.useRef)(hiddenSeqs);
|
|
1828
|
+
const hiddenTrajectoryKeysRef = (0, import_react8.useRef)(hiddenTrajectoryKeys);
|
|
1829
|
+
surfaceRef.current = surface;
|
|
1830
|
+
hiddenSeqsRef.current = hiddenSeqs;
|
|
1831
|
+
hiddenTrajectoryKeysRef.current = hiddenTrajectoryKeys;
|
|
1832
|
+
const [targets, setTargets] = (0, import_react8.useState)([]);
|
|
1833
|
+
const requestFullScanRef = (0, import_react8.useRef)(null);
|
|
1834
|
+
(0, import_react8.useLayoutEffect)(() => {
|
|
1835
|
+
if (!active) {
|
|
1836
|
+
setTargets((current) => current.length === 0 ? current : []);
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
951
1839
|
let frame = null;
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
delete row.dataset.dshmoreHidden;
|
|
967
|
-
}
|
|
968
|
-
const info = messageNodeInfo(node);
|
|
969
|
-
if (info !== null) next.push({ key, ...info, host: hostForRow(row, info.kind) });
|
|
1840
|
+
let fullScanRequested = true;
|
|
1841
|
+
let pruneDisconnected = false;
|
|
1842
|
+
let targetsDirty = false;
|
|
1843
|
+
const pendingChatRows = /* @__PURE__ */ new Set();
|
|
1844
|
+
const pendingTrajectoryRows = /* @__PURE__ */ new Set();
|
|
1845
|
+
const mountedTargets = /* @__PURE__ */ new Map();
|
|
1846
|
+
const processChatRow = (row) => {
|
|
1847
|
+
const key = row.dataset.chatFlowKey;
|
|
1848
|
+
if (key === void 0) return;
|
|
1849
|
+
const descriptor = surfaceRef.current.byKey.get(key);
|
|
1850
|
+
if (descriptor === void 0) {
|
|
1851
|
+
if (mountedTargets.delete(key)) targetsDirty = true;
|
|
1852
|
+
row.querySelector("[data-dshmore-message-actions]")?.remove();
|
|
1853
|
+
return;
|
|
970
1854
|
}
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1855
|
+
if (descriptor.presentationSeq !== void 0 && hiddenSeqsRef.current.has(descriptor.presentationSeq)) {
|
|
1856
|
+
row.dataset.dshmoreHidden = "";
|
|
1857
|
+
if (mountedTargets.delete(key)) targetsDirty = true;
|
|
1858
|
+
row.querySelector("[data-dshmore-message-actions]")?.remove();
|
|
1859
|
+
return;
|
|
1860
|
+
}
|
|
1861
|
+
if (row.dataset.dshmoreHidden !== void 0) delete row.dataset.dshmoreHidden;
|
|
1862
|
+
if (descriptor.action === null) {
|
|
1863
|
+
if (mountedTargets.delete(key)) targetsDirty = true;
|
|
1864
|
+
row.querySelector("[data-dshmore-message-actions]")?.remove();
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
const next = {
|
|
1868
|
+
key,
|
|
1869
|
+
...descriptor.action,
|
|
1870
|
+
host: hostForRow(row, descriptor.action.kind)
|
|
1871
|
+
};
|
|
1872
|
+
const current = mountedTargets.get(key);
|
|
1873
|
+
if (current === void 0 || !sameTarget(current, next)) {
|
|
1874
|
+
mountedTargets.set(key, next);
|
|
1875
|
+
targetsDirty = true;
|
|
1876
|
+
}
|
|
1877
|
+
};
|
|
1878
|
+
const processTrajectoryRow = (row) => {
|
|
1879
|
+
const seq = trajectorySourceSeq(row);
|
|
1880
|
+
const key = trajectoryRecordKey(row);
|
|
1881
|
+
if (seq !== void 0 && hiddenSeqsRef.current.has(seq) || key !== void 0 && hiddenTrajectoryKeysRef.current.has(key)) {
|
|
1882
|
+
row.dataset.dshmoreHidden = "";
|
|
1883
|
+
} else if (row.dataset.dshmoreHidden !== void 0) {
|
|
1884
|
+
delete row.dataset.dshmoreHidden;
|
|
1885
|
+
}
|
|
1886
|
+
};
|
|
1887
|
+
const publishTargets = () => {
|
|
1888
|
+
for (const [key, target] of mountedTargets) {
|
|
1889
|
+
if (!target.host.isConnected && mountedTargets.delete(key)) targetsDirty = true;
|
|
979
1890
|
}
|
|
1891
|
+
const next = surfaceRef.current.rows.flatMap((row) => {
|
|
1892
|
+
const target = mountedTargets.get(row.key);
|
|
1893
|
+
return target === void 0 ? [] : [target];
|
|
1894
|
+
});
|
|
980
1895
|
setTargets((current) => sameTargets(current, next) ? current : next);
|
|
1896
|
+
targetsDirty = false;
|
|
1897
|
+
};
|
|
1898
|
+
const flush = () => {
|
|
1899
|
+
frame = null;
|
|
1900
|
+
if (fullScanRequested) {
|
|
1901
|
+
fullScanRequested = false;
|
|
1902
|
+
mountedTargets.clear();
|
|
1903
|
+
targetsDirty = true;
|
|
1904
|
+
for (const row of document.querySelectorAll("[data-chat-flow-key]")) processChatRow(row);
|
|
1905
|
+
for (const row of document.querySelectorAll("[data-trajectory-row-key]")) processTrajectoryRow(row);
|
|
1906
|
+
} else {
|
|
1907
|
+
for (const row of pendingChatRows) if (row.isConnected) processChatRow(row);
|
|
1908
|
+
for (const row of pendingTrajectoryRows) if (row.isConnected) processTrajectoryRow(row);
|
|
1909
|
+
}
|
|
1910
|
+
pendingChatRows.clear();
|
|
1911
|
+
pendingTrajectoryRows.clear();
|
|
1912
|
+
const shouldPrune = pruneDisconnected;
|
|
1913
|
+
pruneDisconnected = false;
|
|
1914
|
+
if (targetsDirty || shouldPrune) publishTargets();
|
|
981
1915
|
};
|
|
982
1916
|
const schedule = () => {
|
|
983
|
-
if (frame === null) frame = window.requestAnimationFrame(
|
|
1917
|
+
if (frame === null) frame = window.requestAnimationFrame(flush);
|
|
984
1918
|
};
|
|
985
|
-
|
|
986
|
-
|
|
1919
|
+
const requestFullScan = () => {
|
|
1920
|
+
fullScanRequested = true;
|
|
1921
|
+
schedule();
|
|
1922
|
+
};
|
|
1923
|
+
const collectRows = (node) => {
|
|
1924
|
+
const element = node instanceof Element ? node : node.parentElement;
|
|
1925
|
+
if (element === null) return;
|
|
1926
|
+
const chatAncestor = element.closest("[data-chat-flow-key]");
|
|
1927
|
+
if (chatAncestor !== null) pendingChatRows.add(chatAncestor);
|
|
1928
|
+
const trajectoryAncestor = element.closest("[data-trajectory-row-key]");
|
|
1929
|
+
if (trajectoryAncestor !== null) pendingTrajectoryRows.add(trajectoryAncestor);
|
|
1930
|
+
if (element.matches("[data-chat-flow-key]")) pendingChatRows.add(element);
|
|
1931
|
+
if (element.matches("[data-trajectory-row-key]")) pendingTrajectoryRows.add(element);
|
|
1932
|
+
element.querySelectorAll("[data-chat-flow-key]").forEach((row) => pendingChatRows.add(row));
|
|
1933
|
+
element.querySelectorAll("[data-trajectory-row-key]").forEach((row) => pendingTrajectoryRows.add(row));
|
|
1934
|
+
};
|
|
1935
|
+
requestFullScanRef.current = requestFullScan;
|
|
1936
|
+
const observer = new MutationObserver((records) => {
|
|
1937
|
+
for (const record of records) {
|
|
1938
|
+
if (record.removedNodes.length > 0) pruneDisconnected = true;
|
|
1939
|
+
record.addedNodes.forEach(collectRows);
|
|
1940
|
+
}
|
|
1941
|
+
if (pendingChatRows.size > 0 || pendingTrajectoryRows.size > 0 || pruneDisconnected) schedule();
|
|
1942
|
+
});
|
|
987
1943
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
1944
|
+
flush();
|
|
988
1945
|
return () => {
|
|
989
1946
|
observer.disconnect();
|
|
990
1947
|
if (frame !== null) window.cancelAnimationFrame(frame);
|
|
1948
|
+
requestFullScanRef.current = null;
|
|
991
1949
|
for (const row of document.querySelectorAll("[data-dshmore-hidden]")) {
|
|
992
1950
|
delete row.dataset.dshmoreHidden;
|
|
993
1951
|
}
|
|
994
1952
|
for (const host of document.querySelectorAll("[data-dshmore-message-actions]")) host.remove();
|
|
995
1953
|
};
|
|
996
|
-
}, [
|
|
1954
|
+
}, [active]);
|
|
1955
|
+
(0, import_react8.useLayoutEffect)(() => {
|
|
1956
|
+
requestFullScanRef.current?.();
|
|
1957
|
+
}, [surface, hiddenSeqs, hiddenTrajectoryKeys]);
|
|
997
1958
|
return targets;
|
|
998
1959
|
}
|
|
999
1960
|
|
|
1000
1961
|
// src/client/index.tsx
|
|
1001
|
-
var
|
|
1962
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1002
1963
|
var inject = ["slots", "sessions", "workspaces", "settingsScope"];
|
|
1003
1964
|
function MessageActionPatchController({ patch, props, targets, enabled }) {
|
|
1004
1965
|
const actions = patch.useActions(props, enabled);
|
|
1005
1966
|
const style = { "--dshmore-action-order": patch.order };
|
|
1006
|
-
return /* @__PURE__ */ (0,
|
|
1007
|
-
enabled && targets.map((target) => (0,
|
|
1008
|
-
/* @__PURE__ */ (0,
|
|
1967
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1968
|
+
enabled && targets.map((target) => (0, import_react_dom2.createPortal)(
|
|
1969
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dshmore-action-contribution", style, children: actions.renderAction(target) }),
|
|
1009
1970
|
target.host,
|
|
1010
1971
|
`${patch.id}:${target.key}`
|
|
1011
1972
|
)),
|
|
@@ -1013,14 +1974,15 @@ function MessageActionPatchController({ patch, props, targets, enabled }) {
|
|
|
1013
1974
|
] });
|
|
1014
1975
|
}
|
|
1015
1976
|
function MessageActionsController(props) {
|
|
1016
|
-
const settings = (0,
|
|
1977
|
+
const settings = (0, import_react9.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
|
|
1017
1978
|
const projected = props.useProjection(MESSAGE_VISIBILITY_PROJECTION_KEY);
|
|
1018
|
-
const hiddenSeqs = (0,
|
|
1019
|
-
const hiddenTrajectoryKeys = (0,
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1979
|
+
const hiddenSeqs = (0, import_react9.useMemo)(() => new Set(projected?.deletedSeqs ?? []), [projected]);
|
|
1980
|
+
const hiddenTrajectoryKeys = (0, import_react9.useMemo)(() => new Set(projected?.hiddenTrajectoryKeys ?? []), [projected]);
|
|
1981
|
+
const messageActionsEnabled = MESSAGE_ACTION_PATCHES.some((patch) => settings[patch.id]);
|
|
1982
|
+
const targets = useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, messageActionsEnabled);
|
|
1983
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1984
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: styles }),
|
|
1985
|
+
MESSAGE_ACTION_PATCHES.map((patch) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1024
1986
|
MessageActionPatchController,
|
|
1025
1987
|
{
|
|
1026
1988
|
patch,
|
|
@@ -1044,7 +2006,7 @@ function apply(ctx) {
|
|
|
1044
2006
|
id: `${PLUGIN_NAME}-message-actions`,
|
|
1045
2007
|
order: 90,
|
|
1046
2008
|
registrant: PLUGIN_NAME
|
|
1047
|
-
}, (props) => /* @__PURE__ */ (0,
|
|
2009
|
+
}, (props) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MessageActionsController, { ...props, ctx, activation })));
|
|
1048
2010
|
for (const patch of CLIENT_PATCHES) patch.install(ctx, activation);
|
|
1049
2011
|
}
|
|
1050
2012
|
return module.exports; } });
|