dsh-more 0.0.4 → 0.0.6

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.
Files changed (34) hide show
  1. package/README.md +15 -7
  2. package/README.zh-CN.md +15 -7
  3. package/dist/client.js +794 -698
  4. package/dist/index.js +425 -135
  5. package/dist/types/generated/host-settings-schema.d.ts +6 -4
  6. package/dist/types/generated/patch-catalog.d.ts +16 -8
  7. package/dist/types/patches/model-capabilities/client/api.d.ts +4 -0
  8. package/dist/types/patches/model-capabilities/client/editor.d.ts +26 -0
  9. package/dist/types/patches/model-capabilities/client/index.d.ts +10 -0
  10. package/dist/types/patches/model-capabilities/client/model-entries.d.ts +15 -0
  11. package/dist/types/patches/model-capabilities/client/styles.d.ts +1 -0
  12. package/dist/types/patches/model-capabilities/host/deepseek.d.ts +11 -0
  13. package/dist/types/patches/{model-reasoning-efforts → model-capabilities}/host/validate.d.ts +3 -2
  14. package/dist/types/patches/model-capabilities/shared.d.ts +38 -0
  15. package/dist/types/patches/projectless-tasks/client/adapter.d.ts +15 -0
  16. package/dist/types/patches/projectless-tasks/client/create-task.d.ts +7 -0
  17. package/dist/types/patches/projectless-tasks/client/draft.d.ts +9 -0
  18. package/dist/types/patches/projectless-tasks/client/index.d.ts +2 -0
  19. package/dist/types/patches/projectless-tasks/client/new-session.d.ts +34 -0
  20. package/dist/types/patches/projectless-tasks/client/picker.d.ts +26 -0
  21. package/dist/types/patches/projectless-tasks/host/index.d.ts +5 -0
  22. package/dist/types/patches/projectless-tasks/shared.d.ts +6 -0
  23. package/dist/types/patches/session-auto-title/client/index.d.ts +2 -0
  24. package/dist/types/patches/session-auto-title/host/generate.d.ts +6 -0
  25. package/dist/types/patches/session-auto-title/shared.d.ts +2 -0
  26. package/dsh.plugin.json +1 -1
  27. package/package.json +5 -3
  28. package/dist/types/patches/conversation-quick-navigation/client/index.d.ts +0 -27
  29. package/dist/types/patches/conversation-quick-navigation/client/navigation.d.ts +0 -26
  30. package/dist/types/patches/conversation-quick-navigation/shared.d.ts +0 -1
  31. package/dist/types/patches/model-reasoning-efforts/client/index.d.ts +0 -54
  32. package/dist/types/patches/model-reasoning-efforts/shared.d.ts +0 -51
  33. /package/dist/types/patches/{conversation-quick-navigation → model-capabilities}/host/index.d.ts +0 -0
  34. /package/dist/types/patches/{model-reasoning-efforts → session-auto-title}/host/index.d.ts +0 -0
package/dist/client.js CHANGED
@@ -25,8 +25,8 @@ __export(index_exports, {
25
25
  inject: () => inject
26
26
  });
27
27
  module.exports = __toCommonJS(index_exports);
28
- var import_react9 = require("react");
29
- var import_react_dom2 = require("react-dom");
28
+ var import_react11 = require("react");
29
+ var import_react_dom = require("react-dom");
30
30
 
31
31
  // src/generated/patch-catalog.ts
32
32
  var PATCH_CATALOG = [
@@ -34,16 +34,18 @@ var PATCH_CATALOG = [
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
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
+ { "id": "model-capabilities", "name": "\u6A21\u578B\u80FD\u529B\u914D\u7F6E", "description": "\u5728\u6A21\u578B\u914D\u7F6E\u9875\u8BBE\u7F6E\u6BCF\u4E2A\u6A21\u578B\u7684\u8BC6\u56FE\u80FD\u529B\u3001\u53EF\u9009\u601D\u8003\u7C7B\u578B\u4E0E\u601D\u8003\u53C2\u6570\u683C\u5F0F", "defaultEnabled": true, "order": 500, "clientKind": "standalone" },
38
+ { "id": "session-auto-title", "name": "\u4F1A\u8BDD\u81EA\u52A8\u547D\u540D", "description": "\u65B0\u4F1A\u8BDD\u9996\u6761\u9700\u6C42\u540E\uFF0C\u4F7F\u7528\u5F53\u524D\u6A21\u578B\u751F\u6210\u300C\u7C7B\u578B \xB7 \u5177\u4F53\u4EFB\u52A1\u300D\u6807\u9898\uFF1B\u4FDD\u7559\u624B\u52A8\u547D\u540D\uFF0C\u5931\u8D25\u65F6\u4FDD\u7559\u539F\u6709\u6807\u9898", "defaultEnabled": true, "order": 600, "clientKind": "standalone" },
39
+ { "id": "projectless-tasks", "name": "\u72EC\u7ACB\u4EFB\u52A1", "description": "\u5728\u5DE5\u4F5C\u533A\u4E0B\u62C9\u6846\u9009\u62E9\u72EC\u7ACB\u4EFB\u52A1\uFF0C\u6216\u6E05\u9664\u5DF2\u9009\u76EE\u5F55\u5207\u6362\uFF0C\u4FDD\u7559\u8349\u7A3F\u5E76\u81EA\u52A8\u4F7F\u7528\u72EC\u7ACB\u76EE\u5F55", "defaultEnabled": true, "order": 700, "clientKind": "standalone" }
39
40
  ];
40
41
  var DEFAULT_PATCH_SETTINGS = {
41
42
  "message-edit": true,
42
43
  "message-delete": true,
43
44
  "session-delete": true,
44
45
  "conversation-markdown-export": true,
45
- "model-reasoning-efforts": true,
46
- "conversation-quick-navigation": true
46
+ "model-capabilities": true,
47
+ "session-auto-title": true,
48
+ "projectless-tasks": true
47
49
  };
48
50
  function decodePatchSettings(value) {
49
51
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -774,18 +776,53 @@ var clientPatch2 = {
774
776
  }
775
777
  };
776
778
 
777
- // src/patches/model-reasoning-efforts/client/index.tsx
778
- var import_react5 = require("react");
779
- var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
779
+ // src/patches/model-capabilities/client/index.tsx
780
+ var import_react6 = require("react");
780
781
 
781
- // src/patches/model-reasoning-efforts/shared.ts
782
- var MODEL_REASONING_EFFORTS_PATCH_ID = "model-reasoning-efforts";
782
+ // src/patches/model-capabilities/shared.ts
783
+ var MODEL_CAPABILITIES_PATCH_ID = "model-capabilities";
783
784
  var LLM_PI_AI_SETTINGS_NAMESPACE = "llm-pi-ai";
785
+ var LLM_DEEPSEEK_SETTINGS_NAMESPACE = "llm-deepseek";
786
+ var DEEPSEEK_PROVIDER = "deepseek-official";
787
+ var CAPABILITIES_PROTOCOL_VERSION = 2;
788
+ var DEEPSEEK_THINKING_LEVELS = ["off", "low", "high", "max"];
784
789
  var THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
790
+ var THINKING_FORMATS = [
791
+ "openai",
792
+ "deepseek",
793
+ "openrouter",
794
+ "together",
795
+ "baseten",
796
+ "zai",
797
+ "qwen",
798
+ "chat-template",
799
+ "qwen-chat-template",
800
+ "string-thinking",
801
+ "ant-ling"
802
+ ];
803
+
804
+ // src/patches/model-capabilities/client/api.ts
805
+ function decodeSnapshot(value) {
806
+ if (typeof value !== "object" || value === null) throw mismatch();
807
+ const snapshot = value;
808
+ if (snapshot.protocolVersion !== CAPABILITIES_PROTOCOL_VERSION || typeof snapshot.writable !== "boolean" || !Array.isArray(snapshot.rows) || !snapshot.rows.every((row) => {
809
+ if (typeof row !== "object" || row === null) return false;
810
+ const entry = row;
811
+ return (entry.namespace === "llm-deepseek" || entry.namespace === "llm-pi-ai") && Number.isSafeInteger(entry.revision) && Number(entry.revision) >= 0 && typeof entry.provider === "string" && typeof entry.modelId === "string" && (entry.vision === null || typeof entry.vision === "boolean") && Object.hasOwn(entry, "reasoningEfforts") && Object.hasOwn(entry, "thinkingFormat");
812
+ })) throw mismatch();
813
+ return snapshot;
814
+ }
815
+ function mismatch() {
816
+ return new Error("\u6A21\u578B\u80FD\u529B\u754C\u9762\u4E0E\u540E\u53F0\u7248\u672C\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u542F DSH \u670D\u52A1\u540E\u5237\u65B0\u9875\u9762\uFF0C\u518D\u4FDD\u5B58\u914D\u7F6E\u3002");
817
+ }
818
+ async function readCapabilities() {
819
+ return decodeSnapshot(await callPatchApi(MODEL_CAPABILITIES_PATCH_ID, "read", {}));
820
+ }
785
821
 
786
- // src/patches/model-reasoning-efforts/client/index.tsx
822
+ // src/patches/model-capabilities/client/editor.tsx
823
+ var import_react5 = require("react");
824
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
787
825
  var import_jsx_runtime5 = require("react/jsx-runtime");
788
- var EFFORT_BUTTON_ATTR = "data-dshmore-effort";
789
826
  var LEVEL_LABELS = {
790
827
  off: "\u4E0D\u601D\u8003",
791
828
  minimal: "\u6781\u7B80",
@@ -795,265 +832,355 @@ var LEVEL_LABELS = {
795
832
  xhigh: "\u6781\u9AD8",
796
833
  max: "\u6700\u9AD8"
797
834
  };
798
- function emptyDraft() {
799
- return { nonReasoning: false, levels: {} };
800
- }
801
- function draftFromServer(efforts) {
802
- if (efforts === false) return { nonReasoning: true, levels: {} };
803
- if (efforts !== null && typeof efforts === "object") {
804
- const levels = {};
835
+ function draftFromServer(capabilities) {
836
+ const efforts = capabilities.reasoningEfforts;
837
+ const levels = {};
838
+ if (efforts !== false && efforts !== null) {
805
839
  for (const level of THINKING_LEVELS) {
806
- const wire = efforts[level];
807
- if (wire !== void 0) levels[level] = { enabled: true, wire: wire ?? "" };
840
+ if (Object.hasOwn(efforts, level)) levels[level] = { enabled: true, wire: efforts[level] ?? "" };
808
841
  }
809
- return { nonReasoning: false, levels };
810
- }
811
- return emptyDraft();
812
- }
813
- function buildDict(draft) {
814
- const dict = {};
815
- for (const level of THINKING_LEVELS) {
816
- const entry = draft.levels[level];
817
- if (entry === void 0 || !entry.enabled) continue;
818
- dict[level] = level === "off" ? null : entry.wire;
819
842
  }
820
- return dict;
821
- }
822
- function summaryLabel(efforts) {
823
- if (efforts === false) return "\u4E0D\u652F\u6301\u601D\u8003";
824
- if (efforts === null || typeof efforts !== "object") return "\u672A\u914D\u7F6E";
825
- const parts = THINKING_LEVELS.filter((level) => level !== "off" && efforts[level] !== void 0).map((level) => LEVEL_LABELS[level]);
826
- return parts.length === 0 ? "\u672A\u914D\u7F6E" : parts.join("\u3001");
843
+ return {
844
+ vision: capabilities.vision === null ? "default" : capabilities.vision ? "yes" : "no",
845
+ thinking: efforts === null ? "default" : efforts === false ? "disabled" : "custom",
846
+ levels,
847
+ thinkingFormat: capabilities.thinkingFormat ?? "default"
848
+ };
827
849
  }
828
- function findModelEntries() {
829
- const entries = [];
830
- const catalogs = document.querySelectorAll('[class*="modelCatalog"]');
831
- for (const catalog of catalogs) {
832
- for (const entry of catalog.querySelectorAll('[class*="modelEntry"]')) entries.push(entry);
850
+ function capabilitiesFromDraft(draft) {
851
+ let reasoningEfforts = null;
852
+ if (draft.thinking === "disabled") reasoningEfforts = false;
853
+ if (draft.thinking === "custom") {
854
+ reasoningEfforts = {};
855
+ for (const level of THINKING_LEVELS) {
856
+ const entry = draft.levels[level];
857
+ if (!entry?.enabled) continue;
858
+ const wire = entry.wire.trim();
859
+ if (level !== "off" && wire === "") throw new Error(`\u8BF7\u586B\u5199\u300C${LEVEL_LABELS[level]}\u300D\u7684\u53C2\u6570\u503C\u3002`);
860
+ reasoningEfforts[level] = level === "off" && wire === "" ? null : wire;
861
+ }
862
+ if (!THINKING_LEVELS.some((level) => level !== "off" && draft.levels[level]?.enabled)) {
863
+ throw new Error("\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u79CD\u601D\u8003\u7B49\u7EA7\uFF1B\u4EC5\u9700\u4E0D\u601D\u8003\u65F6\uFF0C\u8BF7\u9009\u62E9\u300C\u4E0D\u652F\u6301\u601D\u8003\u300D\u3002");
864
+ }
833
865
  }
834
- return entries;
835
- }
836
- function providerRouteOf(entry) {
837
- const editor = entry.closest('[class*="editor"]');
838
- if (editor === null) return null;
839
- const routeSpan = editor.querySelector('[class*="editorRoute"]');
840
- const route = routeSpan?.textContent?.trim();
841
- if (route !== void 0 && route !== "") return route;
842
- const rowCard = editor.closest('[class*="rowCard"]');
843
- const name = rowCard?.querySelector('[class*="rowName"]')?.textContent?.trim();
844
- return name !== void 0 && name !== "" ? name : null;
845
- }
846
- function modelIdOf(entry) {
847
- const input = entry.querySelector('[class*="modelRow"] input[type="text"]');
848
- const id = input?.value.trim();
849
- return id !== void 0 && id !== "" ? id : null;
850
- }
851
- function EffortEditorBody({ draft, setDraft, writable, busy }) {
852
- const toggleLevel = (level, enabled) => {
853
- setDraft((current) => {
854
- const existing = current.levels[level];
855
- const levels = { ...current.levels };
856
- levels[level] = existing === void 0 ? { enabled, wire: level === "off" ? "" : level } : { ...existing, enabled };
857
- return { ...current, levels };
858
- });
859
- };
860
- const setWire = (level, wire) => {
861
- setDraft((current) => {
862
- const existing = current.levels[level];
863
- if (existing === void 0) return current;
864
- return { ...current, levels: { ...current.levels, [level]: { ...existing, wire } } };
865
- });
866
+ return {
867
+ vision: draft.vision === "default" ? null : draft.vision === "yes",
868
+ reasoningEfforts,
869
+ thinkingFormat: draft.thinkingFormat === "default" ? null : draft.thinkingFormat
866
870
  };
867
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-effort-editor", children: [
868
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-effort-switch", children: [
869
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
870
- "input",
871
- {
872
- type: "checkbox",
873
- role: "switch",
874
- checked: draft.nonReasoning,
875
- disabled: !writable || busy,
876
- onChange: (event) => {
877
- setDraft((current) => ({ ...current, nonReasoning: event.currentTarget.checked }));
878
- }
879
- }
880
- ),
881
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u8BE5\u6A21\u578B\u4E0D\u652F\u6301\u601D\u8003\uFF08reasoningEfforts: false\uFF09" })
871
+ }
872
+ function summaryLabel(capabilities) {
873
+ const vision = capabilities.vision === null ? "\u8BC6\u56FE\uFF1A\u9ED8\u8BA4" : capabilities.vision ? "\u652F\u6301\u8BC6\u56FE" : "\u4E0D\u652F\u6301\u8BC6\u56FE";
874
+ const efforts = capabilities.reasoningEfforts;
875
+ const thinking = efforts === null ? "\u601D\u8003\uFF1A\u9ED8\u8BA4" : efforts === false ? "\u4E0D\u652F\u6301\u601D\u8003" : THINKING_LEVELS.filter((level) => Object.hasOwn(efforts, level)).map((level) => LEVEL_LABELS[level]).join("\u3001");
876
+ return `${vision} \xB7 ${thinking}`;
877
+ }
878
+ function CapabilitiesEditorBody({ draft, setDraft, disabled, api: api3 }) {
879
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-capabilities-fields", children: [
880
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-capabilities-field", children: [
881
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u8BC6\u56FE\u80FD\u529B" }),
882
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { "aria-label": "\u8BC6\u56FE\u80FD\u529B", value: draft.vision, disabled, onChange: (event) => {
883
+ const vision = event.currentTarget.value;
884
+ setDraft((current) => ({ ...current, vision }));
885
+ }, children: [
886
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "default", children: "\u6CBF\u7528\u9ED8\u8BA4" }),
887
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "yes", children: "\u652F\u6301\u8BC6\u56FE" }),
888
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "no", children: "\u4E0D\u652F\u6301\u8BC6\u56FE\uFF08\u4EC5\u6587\u5B57\uFF09" })
889
+ ] })
882
890
  ] }),
883
- !draft.nonReasoning && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dshmore-effort-levels", children: THINKING_LEVELS.map((level) => {
884
- const entry = draft.levels[level];
885
- const enabled = entry?.enabled === true;
886
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-effort-level", children: [
887
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
888
- "input",
889
- {
890
- type: "checkbox",
891
- checked: enabled,
892
- disabled: !writable || busy,
893
- onChange: (event) => {
894
- toggleLevel(level, event.currentTarget.checked);
895
- }
896
- }
897
- ),
898
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dshmore-effort-level-label", children: LEVEL_LABELS[level] }),
899
- enabled && level !== "off" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
900
- "input",
901
- {
902
- className: "dshmore-effort-wire",
903
- type: "text",
904
- value: entry?.wire ?? "",
905
- disabled: !writable || busy,
906
- placeholder: "\u7EBF\u4E0A\u503C",
907
- "aria-label": `${LEVEL_LABELS[level]} \u7684\u7EBF\u4E0A\u503C`,
908
- onChange: (event) => {
909
- setWire(level, event.currentTarget.value);
891
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-capabilities-field", children: [
892
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u601D\u8003\u7C7B\u578B" }),
893
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { "aria-label": "\u601D\u8003\u7C7B\u578B", value: draft.thinking, disabled, onChange: (event) => {
894
+ const thinking = event.currentTarget.value;
895
+ setDraft((current) => ({ ...current, thinking }));
896
+ }, children: [
897
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "default", children: "\u6CBF\u7528\u9ED8\u8BA4" }),
898
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "disabled", children: "\u4E0D\u652F\u6301\u601D\u8003" }),
899
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "custom", children: "\u81EA\u5B9A\u4E49\u53EF\u9009\u7C7B\u578B" })
900
+ ] })
901
+ ] }),
902
+ draft.thinking === "custom" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("fieldset", { className: "dshmore-capabilities-levels", disabled, children: [
903
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("legend", { children: "\u6A21\u578B\u652F\u6301\u7684\u601D\u8003\u7B49\u7EA7" }),
904
+ (api3 === "deepseek-native" ? DEEPSEEK_THINKING_LEVELS : THINKING_LEVELS).map((level) => {
905
+ const entry = draft.levels[level];
906
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-capabilities-level", children: [
907
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { children: [
908
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", checked: entry?.enabled === true, onChange: (event) => {
909
+ const enabled = event.currentTarget.checked;
910
+ setDraft((current) => ({ ...current, levels: {
911
+ ...current.levels,
912
+ [level]: { wire: level === "off" ? "" : level, ...current.levels[level], enabled }
913
+ } }));
914
+ } }),
915
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
916
+ LEVEL_LABELS[level],
917
+ " ",
918
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { children: level })
919
+ ] })
920
+ ] }),
921
+ entry?.enabled && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
922
+ "input",
923
+ {
924
+ type: "text",
925
+ "aria-label": `${LEVEL_LABELS[level]}\u7684\u53C2\u6570\u503C`,
926
+ value: entry.wire,
927
+ readOnly: api3 === "deepseek-native",
928
+ placeholder: level === "off" ? "\u7559\u7A7A\uFF1A\u4E0D\u53D1\u9001\u53C2\u6570" : "\u53D1\u9001\u7ED9\u63A5\u53E3\u7684\u53C2\u6570\u503C",
929
+ onChange: (event) => {
930
+ const wire = event.currentTarget.value;
931
+ setDraft((current) => ({ ...current, levels: {
932
+ ...current.levels,
933
+ [level]: { enabled: true, wire }
934
+ } }));
935
+ }
910
936
  }
911
- }
912
- )
913
- ] }, level);
914
- }) })
937
+ )
938
+ ] }, level);
939
+ })
940
+ ] }),
941
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("details", { className: "dshmore-capabilities-advanced", children: [
942
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("summary", { children: [
943
+ "\u601D\u8003\u53C2\u6570\u683C\u5F0F",
944
+ draft.thinkingFormat === "default" ? "" : ` \xB7 ${draft.thinkingFormat}`
945
+ ] }),
946
+ api3 === null || api3 === "openai-completions" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-capabilities-field", children: [
947
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u63A5\u53E3\u63A5\u53D7\u7684\u683C\u5F0F" }),
948
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { "aria-label": "\u601D\u8003\u53C2\u6570\u683C\u5F0F", disabled, value: draft.thinkingFormat, onChange: (event) => {
949
+ const thinkingFormat = event.currentTarget.value;
950
+ setDraft((current) => ({ ...current, thinkingFormat }));
951
+ }, children: [
952
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "default", children: "\u6CBF\u7528\u9ED8\u8BA4\uFF08\u63D0\u4F9B\u65B9 / \u81EA\u52A8\u8BC6\u522B\uFF09" }),
953
+ THINKING_FORMATS.map((format) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: format, children: format }, format))
954
+ ] }),
955
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dshmore-capabilities-note", children: "\u7528\u4E8E OpenAI \u517C\u5BB9\u63A5\u53E3\uFF1B\u6309\u63A5\u53E3\u8981\u6C42\u9009\u62E9 OpenAI\u3001DeepSeek\u3001Qwen \u7B49\u683C\u5F0F\u3002" })
956
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dshmore-capabilities-note", children: "\u5F53\u524D\u63A5\u53E3\u4F7F\u7528\u539F\u751F\u601D\u8003\u534F\u8BAE\uFF0C\u65E0\u9700\u914D\u7F6E\u6B64\u9879\u3002" })
957
+ ] }),
958
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dshmore-capabilities-note", children: "\u6CBF\u7528\u9ED8\u8BA4\u4F1A\u79FB\u9664\u8BE5\u6A21\u578B\u7684\u5BF9\u5E94\u58F0\u660E\u3002\u8BF7\u6309\u6A21\u578B\u5B9E\u9645\u80FD\u529B\u914D\u7F6E\u3002" })
915
959
  ] });
916
960
  }
917
- function EffortEditorModal({ provider, modelId, initial, writable, onClose }) {
918
- const [draft, setDraft] = (0, import_react5.useState)(() => draftFromServer(initial ?? null));
919
- const [busy, setBusy] = (0, import_react5.useState)(false);
961
+ function CapabilitiesEditorModal({ provider, modelId, namespace, onClose, onSaved }) {
962
+ const [snapshot, setSnapshot] = (0, import_react5.useState)(null);
963
+ const [draft, setDraft] = (0, import_react5.useState)(null);
920
964
  const [error, setError] = (0, import_react5.useState)(null);
965
+ const [busy, setBusy] = (0, import_react5.useState)(false);
966
+ const [attempt, setAttempt] = (0, import_react5.useState)(0);
967
+ const saving = (0, import_react5.useRef)(false);
968
+ const mounted = (0, import_react5.useRef)(false);
921
969
  (0, import_react5.useEffect)(() => {
922
- setDraft(draftFromServer(initial ?? null));
923
- }, [initial]);
924
- const known = initial !== void 0;
970
+ mounted.current = true;
971
+ return () => {
972
+ mounted.current = false;
973
+ };
974
+ }, []);
975
+ (0, import_react5.useEffect)(() => {
976
+ let cancelled = false;
977
+ setError(null);
978
+ void readCapabilities().then((next) => {
979
+ if (cancelled) return;
980
+ setSnapshot(next);
981
+ const row2 = next.rows.find((entry) => entry.namespace === namespace && entry.provider === provider && entry.modelId === modelId);
982
+ setDraft(row2 === void 0 ? null : draftFromServer(row2));
983
+ }).catch((caught) => {
984
+ if (!cancelled) setError(apiErrorText(caught));
985
+ });
986
+ return () => {
987
+ cancelled = true;
988
+ };
989
+ }, [namespace, provider, modelId, attempt]);
990
+ const row = snapshot?.rows.find((entry) => entry.provider === provider && entry.modelId === modelId);
925
991
  const save = async () => {
926
- if (!known) return;
927
- const payload = draft.nonReasoning ? false : buildDict(draft);
928
- if (payload !== false && !THINKING_LEVELS.some((level) => level !== "off" && payload[level] !== void 0)) {
929
- 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");
992
+ if (saving.current) return;
993
+ if (draft === null || row === void 0 || !snapshot?.writable || !Number.isSafeInteger(row.revision)) {
994
+ setError("\u6A21\u578B\u914D\u7F6E\u5C1A\u672A\u5C31\u7EEA\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5F39\u7A97\u540E\u91CD\u8BD5\u3002");
930
995
  return;
931
996
  }
932
- setBusy(true);
933
- setError(null);
997
+ let capabilities;
934
998
  try {
935
- await callPatchApi(MODEL_REASONING_EFFORTS_PATCH_ID, "save", {
936
- provider,
937
- modelId,
938
- reasoningEfforts: payload
939
- });
940
- onClose();
999
+ capabilities = capabilitiesFromDraft(draft);
941
1000
  } catch (caught) {
942
1001
  setError(apiErrorText(caught));
943
- } finally {
944
- setBusy(false);
1002
+ return;
945
1003
  }
946
- };
947
- const clear = async () => {
948
- if (!known) return;
1004
+ saving.current = true;
949
1005
  setBusy(true);
950
1006
  setError(null);
951
1007
  try {
952
- await callPatchApi(MODEL_REASONING_EFFORTS_PATCH_ID, "save", {
1008
+ const next = decodeSnapshot(await callPatchApi(MODEL_CAPABILITIES_PATCH_ID, "save", {
1009
+ namespace,
953
1010
  provider,
954
1011
  modelId,
955
- reasoningEfforts: null
956
- });
957
- onClose();
1012
+ expectedRevision: row.revision,
1013
+ ...capabilities
1014
+ }));
1015
+ if (mounted.current) {
1016
+ onSaved(next);
1017
+ onClose();
1018
+ }
958
1019
  } catch (caught) {
959
- setError(apiErrorText(caught));
1020
+ if (mounted.current) setError(apiErrorText(caught));
960
1021
  } finally {
961
- setBusy(false);
1022
+ saving.current = false;
1023
+ if (mounted.current) setBusy(false);
962
1024
  }
963
1025
  };
964
1026
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
965
1027
  import_dsh_client_ui_primitives5.Modal,
966
1028
  {
967
1029
  open: true,
968
- onClose,
969
- title: `\u601D\u8003\u5F3A\u5EA6 \xB7 ${modelId}`,
1030
+ onClose: () => {
1031
+ if (!saving.current) onClose();
1032
+ },
1033
+ title: `\u6A21\u578B\u80FD\u529B \xB7 ${modelId}`,
970
1034
  closeLabel: "\u5173\u95ED",
971
1035
  description: `\u63D0\u4F9B\u65B9 ${provider}`,
972
1036
  footer: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
973
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: busy, onClick: onClose, children: "\u5173\u95ED" }),
974
- known && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: !writable || busy, onClick: () => {
975
- void clear();
976
- }, children: "\u6E05\u9664\u914D\u7F6E" }),
977
- known && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "primary", disabled: !writable || busy, onClick: () => {
978
- void save();
979
- }, children: busy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58" })
1037
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: busy, onClick: onClose, children: "\u53D6\u6D88" }),
1038
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1039
+ import_dsh_client_ui_primitives5.Button,
1040
+ {
1041
+ variant: "primary",
1042
+ disabled: busy || draft === null || row === void 0 || !snapshot?.writable,
1043
+ onClick: () => {
1044
+ void save();
1045
+ },
1046
+ children: busy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"
1047
+ }
1048
+ )
980
1049
  ] }),
981
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-effort-dialog-body", children: [
982
- !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" }),
983
- known && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EffortEditorBody, { draft, setDraft, writable, busy }),
984
- !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" }),
985
- error !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dshmore-effort-error", children: error })
1050
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-capabilities-dialog", children: [
1051
+ snapshot === null && error === null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dshmore-capabilities-note", children: "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u914D\u7F6E\u2026" }),
1052
+ snapshot !== null && row === void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dshmore-capabilities-note", children: "\u8BF7\u5148\u4FDD\u5B58\u63D0\u4F9B\u65B9\u914D\u7F6E\uFF0C\u518D\u6253\u5F00\u8BE5\u6A21\u578B\u7684\u80FD\u529B\u8BBE\u7F6E\u3002" }),
1053
+ draft !== null && row !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1054
+ CapabilitiesEditorBody,
1055
+ {
1056
+ draft,
1057
+ setDraft: (update) => {
1058
+ setDraft((current) => current === null ? null : update(current));
1059
+ },
1060
+ disabled: busy || !snapshot?.writable,
1061
+ api: row.api
1062
+ }
1063
+ ),
1064
+ snapshot !== null && !snapshot.writable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dshmore-capabilities-note", children: "\u5F53\u524D\u914D\u7F6E\u4E3A\u53EA\u8BFB\u3002" }),
1065
+ error !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { role: "alert", className: "dshmore-capabilities-error", children: error }),
1066
+ snapshot === null && error !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", onClick: () => {
1067
+ setAttempt((value) => value + 1);
1068
+ }, children: "\u91CD\u8BD5" })
986
1069
  ] })
987
1070
  }
988
1071
  );
989
1072
  }
990
- function ModelsPageEffortPortal(props) {
991
- const settings = (0, import_react5.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot, props.activation.getSnapshot);
992
- const enabled = settings[MODEL_REASONING_EFFORTS_PATCH_ID];
993
- const scopeSnapshot = (0, import_react5.useSyncExternalStore)(props.scope.subscribe, props.scope.getSnapshot, props.scope.getSnapshot);
994
- const [editing, setEditing] = (0, import_react5.useState)(null);
995
- const [data, setData] = (0, import_react5.useState)(null);
996
- const dataRef = (0, import_react5.useRef)(data);
1073
+
1074
+ // src/patches/model-capabilities/client/model-entries.ts
1075
+ function findModelEntries() {
1076
+ const entries = [];
1077
+ const catalogs = document.querySelectorAll('[class*="modelCatalog"]');
1078
+ for (const catalog of catalogs) {
1079
+ for (const entry of catalog.querySelectorAll('[class*="modelEntry"]')) entries.push(entry);
1080
+ }
1081
+ return entries;
1082
+ }
1083
+ function providerRouteOf(entry) {
1084
+ const editor = entry.closest('[class*="editor"]');
1085
+ if (editor === null) return null;
1086
+ const routeSpan = editor.querySelector('[class*="editorRoute"]');
1087
+ const route = routeSpan?.textContent?.trim();
1088
+ if (route !== void 0 && route !== "") return route;
1089
+ const rowCard = editor.closest('[class*="rowCard"]');
1090
+ const name = rowCard?.querySelector('[class*="rowName"]')?.textContent?.trim();
1091
+ return name !== void 0 && name !== "" ? name : null;
1092
+ }
1093
+ function modelIdOf(entry) {
1094
+ const input = entry.querySelector('[class*="modelRow"] input[type="text"]');
1095
+ const id = input?.value.trim();
1096
+ return id !== void 0 && id !== "" ? id : null;
1097
+ }
1098
+
1099
+ // src/patches/model-capabilities/client/styles.ts
1100
+ var capabilitiesStyles = `
1101
+ .dshmore-capabilities-button { box-sizing: border-box; width: 100%; min-height: 30px; 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: 5px 10px; font-size: 12px; line-height: 18px; text-align: left; overflow-wrap: anywhere; }
1102
+ .dshmore-capabilities-button:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
1103
+ .dshmore-capabilities-dialog, .dshmore-capabilities-fields { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
1104
+ .dshmore-capabilities-dialog { max-height: 65vh; overflow-y: auto; }
1105
+ .dshmore-capabilities-field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--dsw-alias-label-secondary); }
1106
+ .dshmore-capabilities-fields select, .dshmore-capabilities-level input[type="text"] { box-sizing: border-box; min-width: 0; width: 100%; height: 32px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary); font: inherit; font-size: 13px; }
1107
+ .dshmore-capabilities-fields :disabled { opacity: .55; cursor: default; }
1108
+ .dshmore-capabilities-fields :focus-visible, .dshmore-capabilities-button:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 2px; }
1109
+ .dshmore-capabilities-levels { display: flex; flex-direction: column; gap: 8px; margin: 0; padding: 12px; border: 1px solid var(--dsw-alias-border-l3); border-radius: 8px; min-width: 0; }
1110
+ .dshmore-capabilities-levels legend { font-size: 12px; color: var(--dsw-alias-label-secondary); }
1111
+ .dshmore-capabilities-level { display: grid; grid-template-columns: minmax(100px, 1fr) minmax(120px, 1.4fr); gap: 8px; align-items: center; min-height: 32px; }
1112
+ .dshmore-capabilities-level label { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--dsw-alias-label-secondary); }
1113
+ .dshmore-capabilities-level input[type="checkbox"] { accent-color: var(--dsw-alias-state-business-primary); }
1114
+ .dshmore-capabilities-level small { color: var(--dsw-alias-label-tertiary); }
1115
+ .dshmore-capabilities-advanced { border-top: 1px solid var(--dsw-alias-border-l3); padding-top: 12px; }
1116
+ .dshmore-capabilities-advanced summary { cursor: pointer; font-size: 13px; color: var(--dsw-alias-label-secondary); }
1117
+ .dshmore-capabilities-advanced[open] summary { margin-bottom: 12px; }
1118
+ .dshmore-capabilities-note { color: var(--dsw-alias-label-tertiary); margin: 0; font-size: 12px; line-height: 18px; }
1119
+ .dshmore-capabilities-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; }
1120
+ `;
1121
+
1122
+ // src/patches/model-capabilities/client/index.tsx
1123
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1124
+ var BUTTON_ATTR = "data-dshmore-model-capabilities";
1125
+ function ModelsPageCapabilitiesPortal({ scope, deepseekScope, activation }) {
1126
+ const settings = (0, import_react6.useSyncExternalStore)(activation.subscribe, activation.getSnapshot, activation.getSnapshot);
1127
+ const enabled = settings[MODEL_CAPABILITIES_PATCH_ID];
1128
+ const scopeSnapshot = (0, import_react6.useSyncExternalStore)(scope.subscribe, scope.getSnapshot, scope.getSnapshot);
1129
+ const deepseekSnapshot = (0, import_react6.useSyncExternalStore)(deepseekScope.subscribe, deepseekScope.getSnapshot, deepseekScope.getSnapshot);
1130
+ const [editing, setEditing] = (0, import_react6.useState)(null);
1131
+ const [data, setData] = (0, import_react6.useState)(null);
1132
+ const dataRef = (0, import_react6.useRef)(data);
997
1133
  dataRef.current = data;
998
- const generation = (0, import_react5.useRef)(0);
999
- const fillingRef = (0, import_react5.useRef)(false);
1000
- const reload = (0, import_react5.useCallback)(async () => {
1001
- const current = ++generation.current;
1002
- try {
1003
- const snapshot = await callPatchApi(MODEL_REASONING_EFFORTS_PATCH_ID, "read", {});
1004
- if (generation.current !== current) return;
1005
- setData(snapshot);
1006
- if (enabled && snapshot.writable && snapshot.rows.some((row) => row.reasoningEfforts === null) && !fillingRef.current) {
1007
- fillingRef.current = true;
1008
- void callPatchApi(MODEL_REASONING_EFFORTS_PATCH_ID, "fillDefaults", {}).catch(() => void 0).finally(() => {
1009
- fillingRef.current = false;
1010
- });
1011
- }
1012
- } catch {
1134
+ (0, import_react6.useEffect)(() => {
1135
+ let cancelled = false;
1136
+ if (!enabled) {
1137
+ setEditing(null);
1138
+ setData(null);
1139
+ return;
1013
1140
  }
1014
- }, [enabled]);
1015
- (0, import_react5.useEffect)(() => {
1016
- if (enabled) void reload();
1017
- }, [enabled, reload, scopeSnapshot]);
1018
- const syncButtons = (0, import_react5.useCallback)(() => {
1141
+ void readCapabilities().then((snapshot) => {
1142
+ if (!cancelled) setData(snapshot);
1143
+ }).catch(() => {
1144
+ if (!cancelled) setData(null);
1145
+ });
1146
+ return () => {
1147
+ cancelled = true;
1148
+ };
1149
+ }, [enabled, scopeSnapshot, deepseekSnapshot]);
1150
+ const syncButtons = (0, import_react6.useCallback)(() => {
1019
1151
  if (!enabled) return;
1020
1152
  const active = /* @__PURE__ */ new Set();
1021
1153
  for (const entry of findModelEntries()) {
1022
1154
  const provider = providerRouteOf(entry);
1023
1155
  const modelId = modelIdOf(entry);
1024
- if (provider === null || modelId === null) continue;
1156
+ const modelRow = entry.querySelector('[class*="modelRow"]');
1157
+ if (provider === null || modelId === null || modelRow === null) continue;
1025
1158
  active.add(entry);
1026
- let button = entry.querySelector(`[${EFFORT_BUTTON_ATTR}]`);
1159
+ let button = entry.querySelector(`[${BUTTON_ATTR}]`);
1027
1160
  if (button === null) {
1028
1161
  button = document.createElement("button");
1029
1162
  button.type = "button";
1030
- button.className = "dshmore-effort-row-button";
1031
- button.setAttribute(EFFORT_BUTTON_ATTR, "");
1163
+ button.className = "dshmore-capabilities-button";
1164
+ button.setAttribute(BUTTON_ATTR, "");
1032
1165
  button.addEventListener("click", () => {
1033
1166
  const route = button?.dataset.provider;
1034
1167
  const model = button?.dataset.model;
1035
- if (route !== void 0 && model !== void 0) setEditing({ provider: route, modelId: model });
1168
+ if (route !== void 0 && model !== void 0) setEditing({ namespace: route === DEEPSEEK_PROVIDER ? LLM_DEEPSEEK_SETTINGS_NAMESPACE : LLM_PI_AI_SETTINGS_NAMESPACE, provider: route, modelId: model });
1036
1169
  });
1037
- const row = entry.querySelector('[class*="modelRow"]');
1038
- if (row === null) continue;
1039
- entry.insertBefore(button, row.nextSibling);
1170
+ entry.insertBefore(button, modelRow.nextSibling);
1040
1171
  }
1041
1172
  if (button.dataset.provider !== provider) button.dataset.provider = provider;
1042
1173
  if (button.dataset.model !== modelId) button.dataset.model = modelId;
1043
- const rowData = dataRef.current?.rows.find((row) => row.provider === provider && row.modelId === modelId);
1044
- const text = rowData === void 0 ? "\u601D\u8003\u5F3A\u5EA6" : `\u601D\u8003\u5F3A\u5EA6 \xB7 ${summaryLabel(rowData.reasoningEfforts)}`;
1174
+ const row = dataRef.current?.rows.find((item) => item.provider === provider && item.modelId === modelId);
1175
+ const text = row === void 0 ? "\u6A21\u578B\u80FD\u529B \xB7 \u8BC6\u56FE / \u601D\u8003\u7C7B\u578B" : `\u6A21\u578B\u80FD\u529B \xB7 ${summaryLabel(row)}`;
1045
1176
  if (button.textContent !== text) button.textContent = text;
1046
1177
  }
1047
- document.querySelectorAll(`[${EFFORT_BUTTON_ATTR}]`).forEach((button) => {
1048
- const host = button.parentElement;
1049
- if (host === null || !active.has(host)) button.remove();
1178
+ document.querySelectorAll(`[${BUTTON_ATTR}]`).forEach((button) => {
1179
+ if (button.parentElement === null || !active.has(button.parentElement)) button.remove();
1050
1180
  });
1051
1181
  }, [enabled]);
1052
- (0, import_react5.useEffect)(() => {
1053
- if (!enabled) {
1054
- document.querySelectorAll(`[${EFFORT_BUTTON_ATTR}]`).forEach((element) => element.remove());
1055
- return;
1056
- }
1182
+ (0, import_react6.useEffect)(() => {
1183
+ if (!enabled) return;
1057
1184
  let frame = null;
1058
1185
  const schedule = () => {
1059
1186
  if (frame !== null) return;
@@ -1072,510 +1199,469 @@ function ModelsPageEffortPortal(props) {
1072
1199
  document.removeEventListener("input", schedule);
1073
1200
  document.removeEventListener("change", schedule);
1074
1201
  if (frame !== null) window.cancelAnimationFrame(frame);
1075
- document.querySelectorAll(`[${EFFORT_BUTTON_ATTR}]`).forEach((element) => element.remove());
1202
+ document.querySelectorAll(`[${BUTTON_ATTR}]`).forEach((element) => element.remove());
1076
1203
  };
1077
1204
  }, [enabled, syncButtons]);
1078
- (0, import_react5.useEffect)(() => {
1205
+ (0, import_react6.useEffect)(() => {
1079
1206
  if (enabled) syncButtons();
1080
1207
  }, [enabled, syncButtons, data]);
1081
- const editingRow = editing === null ? void 0 : data?.rows.find((row) => row.provider === editing.provider && row.modelId === editing.modelId);
1082
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1083
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: effortStyles }),
1084
- editing !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1085
- EffortEditorModal,
1208
+ if (!enabled) return null;
1209
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1210
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: capabilitiesStyles }),
1211
+ editing !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1212
+ CapabilitiesEditorModal,
1086
1213
  {
1087
- provider: editing.provider,
1088
- modelId: editing.modelId,
1089
- initial: editingRow === void 0 ? void 0 : editingRow.reasoningEfforts,
1090
- writable: data?.writable ?? true,
1214
+ ...editing,
1091
1215
  onClose: () => {
1092
1216
  setEditing(null);
1093
- }
1094
- }
1217
+ },
1218
+ onSaved: setData
1219
+ },
1220
+ `${editing.provider}/${editing.modelId}`
1095
1221
  )
1096
1222
  ] });
1097
1223
  }
1098
- var effortStyles = `
1099
- .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; }
1100
- .dshmore-effort-row-button:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
1101
- .dshmore-effort-dialog-body { box-sizing: border-box; display: flex; flex-direction: column; gap: 12px; width: 100%; min-width: 0; overflow: hidden; }
1102
- .dshmore-effort-editor { display: flex; flex-direction: column; gap: 12px; }
1103
- .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; }
1104
- .dshmore-effort-switch input, .dshmore-effort-level input[type="checkbox"] { accent-color: var(--dsw-alias-state-business-primary); cursor: pointer; }
1105
- .dshmore-effort-levels { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px 12px; }
1106
- .dshmore-effort-level-label { flex: none; }
1107
- .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; }
1108
- .dshmore-effort-wire:focus { border-color: var(--dsw-alias-brand-primary); outline: none; }
1109
- .dshmore-effort-wire::placeholder { color: var(--dsw-alias-label-dimmed); }
1110
- .dshmore-effort-note { color: var(--dsw-alias-label-tertiary); margin: 0; font-size: 12px; line-height: 18px; }
1111
- .dshmore-effort-warn { color: var(--dsw-alias-state-warn-label); margin: 0; font-size: 12px; line-height: 18px; }
1112
- .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; }
1113
- `;
1114
1224
  var clientPatch3 = {
1115
- id: MODEL_REASONING_EFFORTS_PATCH_ID,
1225
+ id: MODEL_CAPABILITIES_PATCH_ID,
1116
1226
  install: (ctx, activation) => {
1117
- const scope = ctx.settingsScope.bind({ namespace: LLM_PI_AI_SETTINGS_NAMESPACE });
1118
- const boundScope = {
1119
- getSnapshot: scope.getSnapshot.bind(scope),
1120
- subscribe: scope.subscribe.bind(scope),
1121
- set: scope.set.bind(scope),
1122
- unset: scope.unset.bind(scope),
1123
- mutate: scope.mutate.bind(scope)
1227
+ const bindScope = (namespace) => {
1228
+ const scope = ctx.settingsScope.bind({ namespace });
1229
+ return {
1230
+ getSnapshot: scope.getSnapshot.bind(scope),
1231
+ subscribe: scope.subscribe.bind(scope),
1232
+ set: scope.set.bind(scope),
1233
+ unset: scope.unset.bind(scope),
1234
+ mutate: scope.mutate.bind(scope)
1235
+ };
1124
1236
  };
1237
+ const boundScope = bindScope(LLM_PI_AI_SETTINGS_NAMESPACE);
1238
+ const deepseekScope = bindScope(LLM_DEEPSEEK_SETTINGS_NAMESPACE);
1125
1239
  ctx.slots.inject("shell.overlay", () => ctx.slots.register({
1126
1240
  name: "shell.overlay",
1127
- id: `${PLUGIN_NAME}-${MODEL_REASONING_EFFORTS_PATCH_ID}`,
1241
+ id: `${PLUGIN_NAME}-${MODEL_CAPABILITIES_PATCH_ID}`,
1128
1242
  order: 90
1129
- }, (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ModelsPageEffortPortal, { ...props, scope: boundScope, activation })));
1243
+ }, () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ModelsPageCapabilitiesPortal, { scope: boundScope, deepseekScope, activation })));
1130
1244
  }
1131
1245
  };
1132
1246
 
1133
- // src/patches/conversation-quick-navigation/client/index.tsx
1134
- var import_react6 = require("react");
1135
- var import_react_dom = require("react-dom");
1136
- var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
1247
+ // src/patches/session-auto-title/shared.ts
1248
+ var SESSION_AUTO_TITLE_PATCH_ID = "session-auto-title";
1137
1249
 
1138
- // src/kernel/message-visibility.ts
1139
- var MESSAGE_VISIBILITY_PROJECTION_KEY = "dshMoreMessageDelete";
1250
+ // src/patches/session-auto-title/client/index.ts
1251
+ var clientPatch4 = {
1252
+ id: SESSION_AUTO_TITLE_PATCH_ID,
1253
+ install: () => {
1254
+ }
1255
+ };
1140
1256
 
1141
- // src/patches/conversation-quick-navigation/shared.ts
1142
- var CONVERSATION_QUICK_NAVIGATION_PATCH_ID = "conversation-quick-navigation";
1257
+ // src/patches/projectless-tasks/shared.ts
1258
+ var PROJECTLESS_TASKS_PATCH_ID = "projectless-tasks";
1143
1259
 
1144
- // src/platform/dsh/client/message-content.ts
1145
- function contentText(content) {
1146
- return content.filter((block) => block.type === "text").map((block) => block.text).join(" ").replace(/\s+/g, " ").trim();
1147
- }
1260
+ // src/patches/projectless-tasks/client/adapter.tsx
1261
+ var import_react8 = require("react");
1148
1262
 
1149
- // src/patches/conversation-quick-navigation/client/navigation.ts
1150
- var MAX_LABEL_CODE_POINTS = 72;
1151
- function conciseLabel(content, fallbackIndex) {
1152
- const text = contentText(content);
1153
- if (text === "") return `\u7B2C ${String(fallbackIndex)} \u8F6E \xB7 \u975E\u6587\u672C\u6D88\u606F`;
1154
- const codePoints = [...text];
1155
- if (codePoints.length <= MAX_LABEL_CODE_POINTS) return text;
1156
- return `${codePoints.slice(0, MAX_LABEL_CODE_POINTS - 1).join("")}\u2026`;
1157
- }
1158
- function turnSummary(node, key, index) {
1159
- const candidate = node;
1160
- if (candidate?.kind !== "user" && candidate?.kind !== "steering") return null;
1161
- if (!Number.isSafeInteger(candidate.data?.seq) || !Array.isArray(candidate.data?.content)) return null;
1263
+ // src/patches/projectless-tasks/client/create-task.ts
1264
+ function createTaskStarter(sessions) {
1265
+ let pendingId;
1266
+ let flight;
1267
+ let disposed = false;
1162
1268
  return {
1163
- key,
1164
- seq: candidate.data.seq,
1165
- label: conciseLabel(candidate.data.content, index)
1269
+ start(beforeOpen) {
1270
+ if (disposed) return Promise.reject(new Error("\u72EC\u7ACB\u4EFB\u52A1\u8865\u4E01\u5DF2\u5173\u95ED\u3002"));
1271
+ if (flight !== void 0) return flight;
1272
+ pendingId ??= `task-${crypto.randomUUID()}`;
1273
+ const sessionId = pendingId;
1274
+ flight = (async () => {
1275
+ const location = await callPatchApi(PROJECTLESS_TASKS_PATCH_ID, "prepare", { sessionId });
1276
+ if (location.sessionId !== sessionId || typeof location.cwd !== "string" || location.cwd.length === 0) {
1277
+ throw new Error("\u72EC\u7ACB\u4EFB\u52A1\u754C\u9762\u4E0E\u540E\u53F0\u7248\u672C\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u542F DSH\u3002");
1278
+ }
1279
+ if (disposed) return;
1280
+ const id = await sessions.create({ sessionId, cwd: location.cwd });
1281
+ if (id !== sessionId) throw new Error("\u521B\u5EFA\u7ED3\u679C\u4E0E\u72EC\u7ACB\u4EFB\u52A1\u6807\u8BC6\u4E0D\u4E00\u81F4\u3002");
1282
+ if (!disposed && beforeOpen?.(id) !== false) sessions.open(id);
1283
+ pendingId = void 0;
1284
+ })().finally(() => {
1285
+ flight = void 0;
1286
+ });
1287
+ return flight;
1288
+ },
1289
+ dispose() {
1290
+ disposed = true;
1291
+ }
1166
1292
  };
1167
1293
  }
1168
- function sameTurns(left, right) {
1169
- return left.length === right.length && left.every((turn, index) => {
1170
- const other = right[index];
1171
- return other !== void 0 && turn.key === other.key && turn.seq === other.seq && turn.label === other.label;
1172
- });
1294
+
1295
+ // src/patches/projectless-tasks/client/draft.ts
1296
+ function transferDraft(source, target) {
1297
+ const from = source.state.getSnapshot();
1298
+ const to = target.state.getSnapshot();
1299
+ if (from.phase !== "plain" || to.phase !== "plain") throw new Error("\u8F93\u5165\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u5207\u6362\u4EFB\u52A1\u76EE\u5F55\u3002");
1300
+ if (from.draft !== "" && to.draft !== "" && from.draft !== to.draft) {
1301
+ throw new Error("\u76EE\u6807\u4EFB\u52A1\u5DF2\u6709\u5176\u4ED6\u8349\u7A3F\uFF0C\u672C\u6B21\u5207\u6362\u5DF2\u505C\u6B62\uFF0C\u539F\u8349\u7A3F\u5DF2\u4FDD\u7559\u3002");
1302
+ }
1303
+ if (from.imageIds.length > 0 && !target.addImages([...from.imageIds])) {
1304
+ throw new Error("\u6682\u65F6\u65E0\u6CD5\u8F6C\u79FB\u56FE\u7247\uFF0C\u539F\u8349\u7A3F\u5DF2\u4FDD\u7559\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
1305
+ }
1306
+ if (from.draft !== "") target.setDraft(from.draft);
1307
+ if (from.draft !== "") source.setDraft("");
1308
+ from.imageIds.forEach((id) => source.removeImage(id));
1309
+ }
1310
+ function transferBeforeOpen(ctx, sourceId, targetId) {
1311
+ const value = ctx.sessions;
1312
+ if (typeof value !== "object" || value === null || !("scope" in value) || typeof value.scope !== "function" || !("list" in value) || typeof value.list !== "object" || value.list === null || !("getSnapshot" in value.list) || typeof value.list.getSnapshot !== "function") {
1313
+ throw new Error("\u5F53\u524D DSH \u7248\u672C\u4E0D\u652F\u6301\u4FDD\u7559\u8349\u7A3F\u5207\u6362\uFF0C\u8BF7\u68C0\u67E5\u4F1A\u8BDD\u63A5\u53E3\u3002");
1314
+ }
1315
+ const sessions = value;
1316
+ const list = sessions.list.getSnapshot();
1317
+ if (list.current !== sourceId) return false;
1318
+ if (sourceId === void 0 || sourceId === targetId) return true;
1319
+ if (list.byId[sourceId]?.blank !== true) throw new Error("\u5F53\u524D\u4F1A\u8BDD\u5DF2\u5F00\u59CB\uFF0C\u8BF7\u65B0\u5EFA\u4F1A\u8BDD\u540E\u9009\u62E9\u72EC\u7ACB\u4EFB\u52A1\u3002");
1320
+ const source = sessions.scope(sourceId);
1321
+ const target = sessions.scope(targetId);
1322
+ if (source === void 0 || target === void 0) throw new Error("\u4EFB\u52A1\u5C1A\u672A\u51C6\u5907\u597D\uFF0C\u539F\u8349\u7A3F\u5DF2\u4FDD\u7559\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
1323
+ transferDraft(ctx.conversation.input.for(source), ctx.conversation.input.for(target));
1324
+ return true;
1173
1325
  }
1174
- function createConversationTurnSelector() {
1175
- let previous = [];
1176
- return (snapshot) => {
1177
- const next = [];
1178
- for (const key of snapshot.order) {
1179
- const summary = turnSummary(snapshot.nodes.get(key), key, next.length + 1);
1180
- if (summary !== null) next.push(summary);
1326
+
1327
+ // src/patches/projectless-tasks/client/picker.tsx
1328
+ var import_react7 = require("react");
1329
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1330
+ var INDEPENDENT_CHOICE_ID = "::dsh-more-independent-task";
1331
+ var INDEPENDENT_CHOICE = {
1332
+ workspaceId: INDEPENDENT_CHOICE_ID,
1333
+ title: "\u72EC\u7ACB\u4EFB\u52A1",
1334
+ path: "",
1335
+ sessionIds: [],
1336
+ createdAt: "",
1337
+ updatedAt: ""
1338
+ };
1339
+ var ChoiceContext = (0, import_react7.createContext)(void 0);
1340
+ function withIndependentChoice(snapshot) {
1341
+ return { ...snapshot, items: [INDEPENDENT_CHOICE, ...snapshot.items] };
1342
+ }
1343
+ function labelIndependentChip(anchor) {
1344
+ const label = anchor.querySelector('[class*="_workspaceLabel"]');
1345
+ if (label === null) return () => {
1346
+ };
1347
+ const text = label.textContent;
1348
+ const aria = anchor.getAttribute("aria-label");
1349
+ label.textContent = "\u72EC\u7ACB\u4EFB\u52A1";
1350
+ anchor.setAttribute("aria-label", "\u5DE5\u4F5C\u76EE\u5F55\uFF1A\u72EC\u7ACB\u4EFB\u52A1");
1351
+ return () => {
1352
+ if (label.textContent === "\u72EC\u7ACB\u4EFB\u52A1") label.textContent = text;
1353
+ if (anchor.getAttribute("aria-label") === "\u5DE5\u4F5C\u76EE\u5F55\uFF1A\u72EC\u7ACB\u4EFB\u52A1") {
1354
+ if (aria === null) anchor.removeAttribute("aria-label");
1355
+ else anchor.setAttribute("aria-label", aria);
1181
1356
  }
1182
- if (!sameTurns(previous, next)) previous = next;
1183
- return previous;
1184
1357
  };
1185
1358
  }
1186
- function historyWindowSignature(snapshot) {
1187
- const first = snapshot.order[0] ?? "";
1188
- const last = snapshot.order.at(-1) ?? "";
1189
- return `${first}\0${last}\0${String(snapshot.order.length)}`;
1190
- }
1191
- function shouldAutoLoadOlder(state) {
1192
- return state.enabled && state.surfaceAvailable && state.hasMore && !state.loadingOlder && !state.paused;
1359
+ function WorkspaceChoice({ owner, state, error, children }) {
1360
+ (0, import_react7.useLayoutEffect)(() => {
1361
+ const anchor = owner.anchorRef?.current;
1362
+ if (!state.independent || owner.selectedId !== void 0 || anchor === void 0 || anchor === null) return;
1363
+ return labelIndependentChip(anchor);
1364
+ });
1365
+ const clear = () => {
1366
+ owner.onClose();
1367
+ state.chooseIndependent();
1368
+ };
1369
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(ChoiceContext.Provider, { value: state, children: [
1370
+ children,
1371
+ owner.selectedId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1372
+ "button",
1373
+ {
1374
+ type: "button",
1375
+ className: "dshmore-workspace-clear",
1376
+ "aria-label": "\u6E05\u9664\u76EE\u5F55\uFF0C\u5207\u6362\u4E3A\u72EC\u7ACB\u4EFB\u52A1",
1377
+ title: "\u6E05\u9664\u76EE\u5F55\uFF0C\u5207\u6362\u4E3A\u72EC\u7ACB\u4EFB\u52A1",
1378
+ disabled: state.busy,
1379
+ onClick: clear,
1380
+ children: "\xD7"
1381
+ }
1382
+ ),
1383
+ state.busy && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dshmore-workspace-status", role: "status", children: "\u5207\u6362\u4E2D\u2026" }),
1384
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dshmore-workspace-error", role: "alert", children: error }),
1385
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
1386
+ .dshmore-workspace-clear { display:inline-flex; align-items:center; justify-content:center; flex:none; width:22px; height:22px; margin:0 4px 0 -2px; padding:0; border:0; border-radius:50%; color:var(--dsw-alias-label-secondary); background:transparent; font:18px/1 sans-serif; cursor:pointer; }
1387
+ .dshmore-workspace-clear:hover { color:var(--dsw-alias-label-primary); background:var(--dsw-alias-interactive-bg-hover); }
1388
+ .dshmore-workspace-clear:disabled { opacity:.45; cursor:wait; }
1389
+ .dshmore-workspace-status,.dshmore-workspace-error { font-size:12px; color:var(--dsw-alias-label-secondary); }
1390
+ .dshmore-workspace-error { max-width:300px; overflow-wrap:anywhere; color:var(--dsw-alias-state-error-primary); }
1391
+ ` })
1392
+ ] });
1193
1393
  }
1194
- function activeTurnAt(positions, readingLine) {
1195
- let active = positions[0]?.key ?? null;
1196
- for (const position of positions) {
1197
- if (position.top > readingLine) break;
1198
- active = position.key;
1199
- }
1200
- return active;
1394
+ function extendWorkspacePicker(original) {
1395
+ return function ProjectlessPicker(props) {
1396
+ const choice = (0, import_react7.useContext)(ChoiceContext);
1397
+ const snapshot = props.useWorkspaces((value) => value);
1398
+ const display = (0, import_react7.useMemo)(() => choice === void 0 ? snapshot : withIndependentChoice(snapshot), [snapshot, choice === void 0]);
1399
+ const useWorkspaces = (select) => select(display);
1400
+ return (0, import_react7.createElement)(original, {
1401
+ ...props,
1402
+ useWorkspaces,
1403
+ open: props.open && !choice?.busy,
1404
+ selectedId: props.selectedId ?? (choice?.independent ? INDEPENDENT_CHOICE_ID : void 0),
1405
+ onPick: (id) => {
1406
+ if (choice?.busy) return;
1407
+ if (id === INDEPENDENT_CHOICE_ID) {
1408
+ props.onClose();
1409
+ choice?.chooseIndependent();
1410
+ } else props.onPick(id);
1411
+ }
1412
+ });
1413
+ };
1201
1414
  }
1202
- function scrollOffsetForRow(currentScrollTop, scrollportTop, rowTop, topInset = 20) {
1203
- return Math.max(0, currentScrollTop + rowTop - scrollportTop - topInset);
1415
+ function installPickerAdapter(ctx) {
1416
+ const wrapped = /* @__PURE__ */ new Map();
1417
+ const sync = () => {
1418
+ for (const entry of ctx.slots.entries("conversation.hero.workspace")) {
1419
+ if (wrapped.has(entry) || entry.children?.["conversation.hero.workspace.directoryFlow"] === void 0 || typeof entry.component !== "function") continue;
1420
+ const original = entry.component;
1421
+ const component = extendWorkspacePicker(original);
1422
+ wrapped.set(entry, { original, component });
1423
+ entry.component = component;
1424
+ }
1425
+ };
1426
+ const unsubscribe = ctx.slots.subscribe("conversation.hero.workspace", sync);
1427
+ sync();
1428
+ const priorities = ctx.slots.entries("conversation.hero.workspace").map((entry) => entry.options.priority ?? 0);
1429
+ const fallback = ctx.slots.register({ name: "conversation.hero.workspace", priority: Math.max(0, ...priorities) + 1 }, () => null);
1430
+ return () => {
1431
+ unsubscribe();
1432
+ for (const [entry, patch] of wrapped) if (entry.component === patch.component) entry.component = patch.original;
1433
+ wrapped.clear();
1434
+ fallback();
1435
+ };
1204
1436
  }
1205
1437
 
1206
- // src/patches/conversation-quick-navigation/client/index.tsx
1207
- var import_jsx_runtime6 = require("react/jsx-runtime");
1208
- var MAX_NO_PROGRESS_ATTEMPTS = 3;
1209
- var MENU_LIST_ID = "dshmore-conversation-nav-list";
1210
- var navigationCollapsedPreference = false;
1211
- function conversationRow(root, key) {
1212
- for (const row of root.querySelectorAll("[data-chat-flow-key]")) {
1213
- if (row.dataset.chatFlowKey === key) return row;
1214
- }
1215
- return null;
1216
- }
1217
- function sessionRoot(marker) {
1218
- return marker?.closest("[data-phase]") ?? null;
1438
+ // src/patches/projectless-tasks/client/adapter.tsx
1439
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1440
+ function isComposerOwner(owner) {
1441
+ return "variant" in owner && (owner.variant === "hero" || owner.variant === "composer");
1219
1442
  }
1220
- function conversationScrollport(marker) {
1221
- return sessionRoot(marker)?.querySelector("[data-conversation-scroll]") ?? null;
1443
+ function isWorkspaceOwner(owner) {
1444
+ return "open" in owner && typeof owner.open === "boolean" && "onPick" in owner && typeof owner.onPick === "function" && "onClose" in owner && typeof owner.onClose === "function";
1222
1445
  }
1223
- function nativeLoadOlderButton(scrollport) {
1224
- const flow = scrollport.querySelector("[data-chat-flow]");
1225
- if (flow === null) return null;
1226
- for (const child of flow.children) {
1227
- if (child instanceof HTMLElement && child.dataset.chatFlowKey !== void 0) break;
1228
- const button = child.querySelector("button");
1229
- if (button !== null) return button;
1446
+ function clientSessionActions(ctx) {
1447
+ const sessions = ctx.sessions;
1448
+ if (typeof sessions !== "object" || sessions === null || !("create" in sessions) || !("open" in sessions) || typeof sessions.create !== "function" || typeof sessions.open !== "function") {
1449
+ throw new Error("\u5F53\u524D DSH \u7248\u672C\u4E0D\u652F\u6301\u72EC\u7ACB\u4EFB\u52A1\uFF0C\u8BF7\u68C0\u67E5\u4F1A\u8BDD\u63A5\u53E3\u3002");
1230
1450
  }
1231
- return null;
1451
+ return sessions;
1452
+ }
1453
+ function unlockComposer(owner, independent, block) {
1454
+ if (!independent || owner.disabled !== true || owner.onRequestWorkspace === void 0) return owner;
1455
+ const { disabled: _disabled, onRequestWorkspace: _request, workspacePickerOpen: _picker, placeholder: _placeholder, ...rest } = owner;
1456
+ return { ...rest, ...block === void 0 ? {} : { blocked: block, placeholder: block.reason } };
1457
+ }
1458
+ function installConversationAdapter(ctx, activation) {
1459
+ const wrapped = /* @__PURE__ */ new Map();
1460
+ let live = true;
1461
+ const listeners = /* @__PURE__ */ new Set();
1462
+ const subscribeLifetime = (listener) => {
1463
+ listeners.add(listener);
1464
+ return () => {
1465
+ listeners.delete(listener);
1466
+ };
1467
+ };
1468
+ const sync = () => {
1469
+ for (const entry of ctx.slots.entries("conversation")) {
1470
+ let ProjectlessConversation2 = function(props) {
1471
+ const active = (0, import_react8.useSyncExternalStore)(subscribeLifetime, () => live);
1472
+ const settings = (0, import_react8.useSyncExternalStore)(activation.subscribe, activation.getSnapshot);
1473
+ const workspace = props.useWorkspaces((snapshot) => snapshot);
1474
+ const cwd = props.useSessions((snapshot) => props.sessionId === void 0 ? void 0 : snapshot.byId[props.sessionId]?.cwd);
1475
+ const session = props.useSession((snapshot) => snapshot);
1476
+ const block = props.useComposerBlock((value) => value);
1477
+ const enabled = active && settings[PROJECTLESS_TASKS_PATCH_ID];
1478
+ const starter = (0, import_react8.useRef)();
1479
+ const [busy, setBusy] = (0, import_react8.useState)(false);
1480
+ const [error, setError] = (0, import_react8.useState)();
1481
+ (0, import_react8.useEffect)(() => {
1482
+ if (!enabled) return;
1483
+ setBusy(false);
1484
+ setError(void 0);
1485
+ return () => {
1486
+ starter.current?.dispose();
1487
+ starter.current = void 0;
1488
+ };
1489
+ }, [enabled]);
1490
+ const independent = enabled && props.sessionId !== void 0 && session?.openState === "open" && typeof cwd === "string" && cwd.length > 0 && workspace.phase === "ready" && !workspace.items.some((item) => item.sessionIds.includes(props.sessionId));
1491
+ const chooseIndependent = () => {
1492
+ if (!enabled || busy || independent) return;
1493
+ const operation = starter.current ??= createTaskStarter(clientSessionActions(ctx));
1494
+ setBusy(true);
1495
+ setError(void 0);
1496
+ void operation.start((id) => transferBeforeOpen(ctx, props.sessionId, id)).catch((reason) => {
1497
+ if (starter.current === operation) setError(apiErrorText(reason));
1498
+ }).finally(() => {
1499
+ if (starter.current === operation) setBusy(false);
1500
+ });
1501
+ };
1502
+ const renderSlot = (name, owner, options) => {
1503
+ if (name === "conversation.composer.bar" && isComposerOwner(owner)) {
1504
+ return props.renderSlot("conversation.composer.bar", unlockComposer(owner, independent, block), options);
1505
+ }
1506
+ if (enabled && name === "conversation.hero.workspace" && isWorkspaceOwner(owner)) {
1507
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(WorkspaceChoice, { owner, state: { independent, busy, chooseIndependent }, error, children: props.renderSlot("conversation.hero.workspace", owner, options) });
1508
+ }
1509
+ return props.renderSlot(name, owner, options);
1510
+ };
1511
+ return (0, import_react8.createElement)(original, { ...props, renderSlot });
1512
+ };
1513
+ var ProjectlessConversation = ProjectlessConversation2;
1514
+ if (wrapped.has(entry) || entry.children?.["conversation.composer.bar"] === void 0 || typeof entry.component !== "function") continue;
1515
+ const original = entry.component;
1516
+ wrapped.set(entry, { original, component: ProjectlessConversation2 });
1517
+ entry.component = ProjectlessConversation2;
1518
+ }
1519
+ };
1520
+ const unsubscribe = ctx.slots.subscribe("conversation", sync);
1521
+ sync();
1522
+ const priorities = ctx.slots.entries("conversation").map((entry) => entry.options.priority ?? 0);
1523
+ const fallback = ctx.slots.register({ name: "conversation", priority: Math.max(0, ...priorities) + 1 }, () => null);
1524
+ return () => {
1525
+ live = false;
1526
+ listeners.forEach((listener) => listener());
1527
+ unsubscribe();
1528
+ for (const [entry, patch] of wrapped) {
1529
+ if (entry.component === patch.component) entry.component = patch.original;
1530
+ }
1531
+ wrapped.clear();
1532
+ fallback();
1533
+ };
1232
1534
  }
1233
- function ConversationNavigationMenu({
1234
- turns,
1235
- activeKey,
1236
- hasMore,
1237
- loadingOlder,
1238
- autoLoadPaused,
1239
- collapsed,
1240
- onRetry,
1241
- onToggleCollapsed,
1242
- onJump,
1243
- listRef
1244
- }) {
1245
- const loading = hasMore && !autoLoadPaused;
1246
- const compactStatus = autoLoadPaused ? `${String(turns.length)} \u8F6E \xB7 \u5DF2\u6682\u505C` : loading ? `${String(turns.length)} \u8F6E \xB7 \u52A0\u8F7D\u4E2D` : `${String(turns.length)} \u8F6E`;
1247
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1248
- "nav",
1249
- {
1250
- className: "dshmore-conversation-nav-menu",
1251
- "data-collapsed": collapsed ? "true" : "false",
1252
- "aria-label": "\u5F53\u524D\u4F1A\u8BDD\u7684\u5BF9\u8BDD\u76EE\u5F55",
1253
- children: [
1254
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("header", { className: "dshmore-conversation-nav-header", children: [
1255
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-heading", children: [
1256
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-title-row", children: [
1257
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dshmore-conversation-nav-title", children: "\u5BF9\u8BDD\u76EE\u5F55" }),
1258
- collapsed && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-compact-status", role: "status", "aria-live": "polite", children: [
1259
- loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dshmore-conversation-nav-loading-dot", "aria-hidden": "true" }),
1260
- compactStatus
1261
- ] })
1262
- ] }),
1263
- !collapsed && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-count", role: "status", "aria-live": "polite", children: [
1264
- loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dshmore-conversation-nav-loading-dot", "aria-hidden": "true" }),
1265
- 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`
1266
- ] })
1267
- ] }),
1268
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-conversation-nav-actions", children: [
1269
- !collapsed && autoLoadPaused && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "dshmore-conversation-nav-retry", onClick: onRetry, children: "\u7EE7\u7EED\u52A0\u8F7D" }),
1270
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1271
- "button",
1272
- {
1273
- type: "button",
1274
- className: "dshmore-conversation-nav-toggle",
1275
- "aria-label": collapsed ? "\u5C55\u5F00\u5BF9\u8BDD\u76EE\u5F55" : "\u6298\u53E0\u5BF9\u8BDD\u76EE\u5F55",
1276
- "aria-controls": MENU_LIST_ID,
1277
- "aria-expanded": !collapsed,
1278
- onClick: onToggleCollapsed,
1279
- 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 })
1280
- }
1281
- )
1282
- ] })
1283
- ] }),
1284
- !collapsed && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { id: MENU_LIST_ID, ref: listRef, className: "dshmore-conversation-nav-list", children: [
1285
- 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" }),
1286
- turns.map((turn, index) => {
1287
- const active = turn.key === activeKey;
1288
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1289
- "button",
1290
- {
1291
- type: "button",
1292
- className: "dshmore-conversation-nav-item",
1293
- "aria-current": active ? "location" : void 0,
1294
- onClick: () => {
1295
- onJump(turn.key);
1296
- },
1297
- children: [
1298
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dshmore-conversation-nav-index", children: String(index + 1).padStart(2, "0") }),
1299
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dshmore-conversation-nav-label", children: turn.label })
1300
- ]
1301
- },
1302
- turn.key
1303
- );
1304
- })
1305
- ] })
1306
- ]
1535
+
1536
+ // src/patches/projectless-tasks/client/new-session.ts
1537
+ function newSessionTarget(list, workspaces, explicit) {
1538
+ if (explicit !== void 0) return { kind: "workspace", workspaceId: explicit };
1539
+ if (list.current === void 0) return { kind: "native" };
1540
+ if (list.phase !== "ready" || workspaces.phase !== "ready") return { kind: "pending" };
1541
+ const visited = /* @__PURE__ */ new Set();
1542
+ let id = list.current;
1543
+ while (id !== void 0 && !visited.has(id)) {
1544
+ visited.add(id);
1545
+ const workspace = workspaces.items.find((item) => item.sessionIds.includes(id));
1546
+ if (workspace !== void 0) return { kind: "workspace", workspaceId: workspace.workspaceId };
1547
+ const summary = list.byId[id];
1548
+ if (summary === void 0) return { kind: "pending" };
1549
+ if (summary.origin === "subagent") {
1550
+ id = summary.parentId;
1551
+ continue;
1307
1552
  }
1308
- );
1553
+ return typeof summary.cwd === "string" && summary.cwd.length > 0 ? { kind: "independent", sourceId: list.current } : { kind: "pending" };
1554
+ }
1555
+ return { kind: "pending" };
1309
1556
  }
1310
- function ConversationQuickNavigation(props) {
1311
- const settings = (0, import_react6.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot, props.activation.getSnapshot);
1312
- const enabled = settings[CONVERSATION_QUICK_NAVIGATION_PATCH_ID];
1313
- const selector = (0, import_react6.useMemo)(createConversationTurnSelector, [props.sessionId]);
1314
- const allTurns = props.useChat(selector);
1315
- const hasMore = props.useSession((snapshot) => snapshot.hasMore);
1316
- const loadingOlder = props.useSession((snapshot) => snapshot.loadingOlder);
1317
- const windowSignature = props.useChat(historyWindowSignature);
1318
- const projected = props.useProjection(MESSAGE_VISIBILITY_PROJECTION_KEY);
1319
- const hiddenSeqs = (0, import_react6.useMemo)(() => new Set(projected?.deletedSeqs ?? []), [projected]);
1320
- const turns = (0, import_react6.useMemo)(
1321
- () => allTurns.filter((turn) => !hiddenSeqs.has(turn.seq)),
1322
- [allTurns, hiddenSeqs]
1323
- );
1324
- const markerRef = (0, import_react6.useRef)(null);
1325
- const listRef = (0, import_react6.useRef)(null);
1326
- const pendingLoadSignatureRef = (0, import_react6.useRef)(null);
1327
- const noProgressAttemptsRef = (0, import_react6.useRef)(0);
1328
- const [portalTarget, setPortalTarget] = (0, import_react6.useState)(null);
1329
- const [activeKey, setActiveKey] = (0, import_react6.useState)(null);
1330
- const [surfaceAvailable, setSurfaceAvailable] = (0, import_react6.useState)(false);
1331
- const [composerInset, setComposerInset] = (0, import_react6.useState)(176);
1332
- const [autoLoadPaused, setAutoLoadPaused] = (0, import_react6.useState)(false);
1333
- const [loadTick, setLoadTick] = (0, import_react6.useState)(0);
1334
- const [collapsed, setCollapsed] = (0, import_react6.useState)(() => navigationCollapsedPreference);
1335
- (0, import_react6.useLayoutEffect)(() => {
1336
- const root = sessionRoot(markerRef.current);
1337
- setPortalTarget(root);
1338
- if (root === null) return;
1339
- const composer = root.querySelector("[data-composer-seat]");
1340
- const updateInset = () => {
1341
- setComposerInset(Math.max(96, (composer?.offsetHeight ?? 152) + 20));
1342
- };
1343
- updateInset();
1344
- if (composer === null || typeof ResizeObserver === "undefined") return;
1345
- const observer = new ResizeObserver(updateInset);
1346
- observer.observe(composer);
1347
- return () => {
1348
- observer.disconnect();
1349
- };
1350
- }, [props.sessionId]);
1351
- (0, import_react6.useEffect)(() => {
1352
- pendingLoadSignatureRef.current = null;
1353
- noProgressAttemptsRef.current = 0;
1354
- setAutoLoadPaused(false);
1355
- }, [enabled, props.sessionId]);
1356
- (0, import_react6.useEffect)(() => {
1357
- if (hasMore) return;
1358
- pendingLoadSignatureRef.current = null;
1359
- noProgressAttemptsRef.current = 0;
1360
- setAutoLoadPaused(false);
1361
- }, [hasMore]);
1362
- (0, import_react6.useEffect)(() => {
1557
+ function bindNewSessionNavigation({ navigation, sessions, workspaces, activation, reportError }) {
1558
+ let disposed = false;
1559
+ let uninstall;
1560
+ const sync = () => {
1561
+ const enabled = !disposed && activation.getSnapshot()[PROJECTLESS_TASKS_PATCH_ID];
1363
1562
  if (!enabled) {
1364
- setActiveKey(null);
1365
- setSurfaceAvailable(false);
1563
+ uninstall?.();
1564
+ uninstall = void 0;
1366
1565
  return;
1367
1566
  }
1368
- let frame = null;
1369
- let scrollport = null;
1370
- const schedule = () => {
1371
- if (frame !== null) return;
1372
- frame = window.requestAnimationFrame(recompute);
1567
+ if (uninstall !== void 0) return;
1568
+ const descriptor = Object.getOwnPropertyDescriptor(navigation, "startSession");
1569
+ const original = navigation.startSession;
1570
+ let active = true;
1571
+ let attempt;
1572
+ const cancel = () => {
1573
+ attempt?.starter.dispose();
1574
+ attempt = void 0;
1373
1575
  };
1374
- const bindScrollport = (next) => {
1375
- if (next === scrollport) return;
1376
- scrollport?.removeEventListener("scroll", schedule);
1377
- scrollport = next;
1378
- scrollport?.addEventListener("scroll", schedule, { passive: true });
1379
- };
1380
- const recompute = () => {
1381
- frame = null;
1382
- const nextScrollport = conversationScrollport(markerRef.current);
1383
- bindScrollport(nextScrollport);
1384
- const flowAvailable = nextScrollport !== null && nextScrollport.querySelector("[data-chat-flow]") !== null;
1385
- setSurfaceAvailable(flowAvailable);
1386
- if (nextScrollport === null || !flowAvailable) {
1387
- setActiveKey(null);
1576
+ const start = (workspaceId) => {
1577
+ if (!active) return original.call(navigation, workspaceId);
1578
+ const list = sessions.list.getSnapshot();
1579
+ const target = newSessionTarget(list, workspaces.list.getSnapshot(), workspaceId);
1580
+ if (target.kind === "workspace" || target.kind === "native") {
1581
+ cancel();
1582
+ return original.call(navigation, target.kind === "workspace" ? target.workspaceId : workspaceId);
1583
+ }
1584
+ if (target.kind === "pending") {
1585
+ cancel();
1586
+ if (list.current !== void 0) reportError(list.current, new Error("\u4F1A\u8BDD\u6765\u6E90\u4ECD\u5728\u52A0\u8F7D\uFF0C\u8BF7\u7A0D\u540E\u518D\u65B0\u5EFA\u4F1A\u8BDD\u3002"));
1388
1587
  return;
1389
1588
  }
1390
- const viewport = nextScrollport.getBoundingClientRect();
1391
- const readingLine = viewport.top + Math.min(120, nextScrollport.clientHeight * 0.24);
1392
- const positions = [];
1393
- for (const turn of turns) {
1394
- const row = conversationRow(nextScrollport, turn.key);
1395
- if (row !== null) positions.push({ key: turn.key, top: row.getBoundingClientRect().top });
1589
+ if (attempt?.sourceId !== target.sourceId) {
1590
+ cancel();
1591
+ attempt = { sourceId: target.sourceId, starter: createTaskStarter(sessions) };
1396
1592
  }
1397
- setActiveKey(activeTurnAt(positions, readingLine));
1398
- };
1399
- const observer = new MutationObserver(schedule);
1400
- const root = sessionRoot(markerRef.current);
1401
- if (root !== null) observer.observe(root, { childList: true, subtree: true });
1402
- window.addEventListener("resize", schedule);
1403
- recompute();
1404
- return () => {
1405
- observer.disconnect();
1406
- window.removeEventListener("resize", schedule);
1407
- scrollport?.removeEventListener("scroll", schedule);
1408
- if (frame !== null) window.cancelAnimationFrame(frame);
1409
- };
1410
- }, [enabled, turns, props.sessionId]);
1411
- (0, import_react6.useEffect)(() => {
1412
- if (!shouldAutoLoadOlder({ enabled, surfaceAvailable, hasMore, loadingOlder, paused: autoLoadPaused })) return;
1413
- const pendingSignature = pendingLoadSignatureRef.current;
1414
- let delay2 = 0;
1415
- if (pendingSignature !== null) {
1416
- if (pendingSignature === windowSignature) {
1417
- noProgressAttemptsRef.current += 1;
1418
- if (noProgressAttemptsRef.current >= MAX_NO_PROGRESS_ATTEMPTS) {
1419
- pendingLoadSignatureRef.current = null;
1420
- setAutoLoadPaused(true);
1421
- return;
1593
+ const current = attempt;
1594
+ if (current === void 0 || current.flight !== void 0) return;
1595
+ current.flight = current.starter.start(() => {
1596
+ if (!active || attempt !== current) return false;
1597
+ const destination = newSessionTarget(sessions.list.getSnapshot(), workspaces.list.getSnapshot());
1598
+ return destination.kind === "independent" && destination.sourceId === current.sourceId;
1599
+ }).catch((error) => {
1600
+ if (active && attempt === current && sessions.list.getSnapshot().current === current.sourceId) {
1601
+ reportError(current.sourceId, error);
1422
1602
  }
1423
- delay2 = noProgressAttemptsRef.current * 350;
1424
- } else {
1425
- noProgressAttemptsRef.current = 0;
1426
- }
1427
- pendingLoadSignatureRef.current = null;
1428
- }
1429
- let frame = null;
1430
- let retryTimer = null;
1431
- let requestTimer = null;
1432
- const request = () => {
1433
- frame = window.requestAnimationFrame(() => {
1434
- frame = null;
1435
- const scrollport = conversationScrollport(markerRef.current);
1436
- const button = scrollport === null ? null : nativeLoadOlderButton(scrollport);
1437
- if (button === null || button.disabled) {
1438
- retryTimer = window.setTimeout(() => {
1439
- setLoadTick((current) => current + 1);
1440
- }, 180);
1441
- return;
1442
- }
1443
- pendingLoadSignatureRef.current = windowSignature;
1444
- button.click();
1445
- retryTimer = window.setTimeout(() => {
1446
- setLoadTick((current) => current + 1);
1447
- }, 1600);
1603
+ }).finally(() => {
1604
+ delete current.flight;
1448
1605
  });
1449
1606
  };
1450
- if (delay2 > 0) requestTimer = window.setTimeout(request, delay2);
1451
- else request();
1452
- return () => {
1453
- if (frame !== null) window.cancelAnimationFrame(frame);
1454
- if (retryTimer !== null) window.clearTimeout(retryTimer);
1455
- if (requestTimer !== null) window.clearTimeout(requestTimer);
1607
+ navigation.startSession = start;
1608
+ uninstall = () => {
1609
+ active = false;
1610
+ cancel();
1611
+ if (Object.getOwnPropertyDescriptor(navigation, "startSession")?.value !== start) return;
1612
+ if (descriptor === void 0) Reflect.deleteProperty(navigation, "startSession");
1613
+ else Object.defineProperty(navigation, "startSession", descriptor);
1456
1614
  };
1457
- }, [autoLoadPaused, enabled, hasMore, loadTick, loadingOlder, surfaceAvailable, windowSignature]);
1458
- (0, import_react6.useLayoutEffect)(() => {
1459
- if (collapsed || activeKey === null) return;
1460
- const list = listRef.current;
1461
- const active = list?.querySelector('[aria-current="location"]');
1462
- if (list === null || active === null || active === void 0) return;
1463
- const top = active.offsetTop;
1464
- const bottom = top + active.offsetHeight;
1465
- if (top < list.scrollTop) list.scrollTop = top;
1466
- else if (bottom > list.scrollTop + list.clientHeight) list.scrollTop = bottom - list.clientHeight;
1467
- }, [activeKey, collapsed]);
1468
- const retryAutoLoad = () => {
1469
- pendingLoadSignatureRef.current = null;
1470
- noProgressAttemptsRef.current = 0;
1471
- setAutoLoadPaused(false);
1472
- setLoadTick((current) => current + 1);
1473
- };
1474
- const toggleCollapsed = () => {
1475
- setCollapsed((current) => {
1476
- navigationCollapsedPreference = !current;
1477
- return navigationCollapsedPreference;
1478
- });
1479
1615
  };
1480
- const jump = (key) => {
1481
- const scrollport = conversationScrollport(markerRef.current);
1482
- if (scrollport === null) return;
1483
- const row = conversationRow(scrollport, key);
1484
- if (row === null) return;
1485
- const viewport = scrollport.getBoundingClientRect();
1486
- const rowRect = row.getBoundingClientRect();
1487
- const top = scrollOffsetForRow(scrollport.scrollTop, viewport.top, rowRect.top);
1488
- const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1489
- scrollport.scrollTo({ top, behavior: reducedMotion ? "auto" : "smooth" });
1490
- setActiveKey(key);
1616
+ const unsubscribe = activation.subscribe(sync);
1617
+ try {
1618
+ sync();
1619
+ } catch (error) {
1620
+ unsubscribe();
1621
+ throw error;
1622
+ }
1623
+ return () => {
1624
+ disposed = true;
1625
+ unsubscribe();
1626
+ sync();
1491
1627
  };
1492
- const rootStyle = { "--dshmore-conversation-nav-bottom": `${String(composerInset)}px` };
1493
- const surface = enabled && surfaceAvailable && portalTarget !== null ? (0, import_react_dom.createPortal)(
1494
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1495
- "div",
1496
- {
1497
- className: "dshmore-conversation-nav-root",
1498
- "data-collapsed": collapsed ? "true" : "false",
1499
- style: rootStyle,
1500
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1501
- ConversationNavigationMenu,
1502
- {
1503
- turns,
1504
- activeKey,
1505
- hasMore,
1506
- loadingOlder,
1507
- autoLoadPaused,
1508
- collapsed,
1509
- onRetry: retryAutoLoad,
1510
- onToggleCollapsed: toggleCollapsed,
1511
- onJump: jump,
1512
- listRef
1513
- }
1514
- )
1515
- }
1516
- ),
1517
- portalTarget
1518
- ) : null;
1519
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1520
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { ref: markerRef, className: "dshmore-conversation-nav-marker", "aria-hidden": "true" }),
1521
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: navigationStyles }),
1522
- surface
1523
- ] });
1524
1628
  }
1525
- var navigationStyles = `
1526
- .dshmore-conversation-nav-marker { display: none; }
1527
- .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); }
1528
- .dshmore-conversation-nav-root[data-collapsed="true"] { bottom: auto; height: 58px; }
1529
- .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; }
1530
- .dshmore-conversation-nav-menu[data-collapsed="true"] { height: 58px; max-height: 58px; }
1531
- .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); }
1532
- .dshmore-conversation-nav-menu[data-collapsed="true"] .dshmore-conversation-nav-header { height: 58px; min-height: 58px; padding: 0 12px 0 14px; border-bottom: 0; }
1533
- .dshmore-conversation-nav-heading { min-width: 0; }
1534
- .dshmore-conversation-nav-title-row { min-width: 0; display: flex; align-items: baseline; gap: 6px; }
1535
- .dshmore-conversation-nav-title { font: var(--dsw-font-s-strong-14); }
1536
- .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; }
1537
- .dshmore-conversation-nav-count { margin-top: 2px; color: var(--dsw-alias-label-caption); font-size: 11px; line-height: 16px; text-wrap: pretty; }
1538
- .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; }
1539
- .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; }
1540
- .dshmore-conversation-nav-retry:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover); }
1541
- .dshmore-conversation-nav-actions { flex: none; display: flex; align-items: center; gap: 6px; }
1542
- .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; }
1543
- .dshmore-conversation-nav-toggle:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover); }
1544
- .dshmore-conversation-nav-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 6px; scrollbar-width: thin; }
1545
- .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; }
1546
- .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; }
1547
- .dshmore-conversation-nav-item:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover); }
1548
- .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; }
1549
- .dshmore-conversation-nav-item[aria-current="location"] { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover-solid); }
1550
- .dshmore-conversation-nav-index { color: var(--dsw-alias-label-caption); font-size: 11px; line-height: 20px; font-variant-numeric: tabular-nums; }
1551
- .dshmore-conversation-nav-item[aria-current="location"] .dshmore-conversation-nav-index { color: var(--dsw-alias-state-business-primary); font-weight: 600; }
1552
- .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; }
1553
- @keyframes dshmore-conversation-nav-enter { from { opacity: 0; transform: translateX(6px); } to { opacity: 1; transform: translateX(0); } }
1554
- @keyframes dshmore-conversation-nav-pulse { 50% { opacity: .35; transform: scale(.82); } }
1555
- @media (max-width: 720px) {
1556
- .dshmore-conversation-nav-root { right: 8px; top: 74px; bottom: auto; width: calc(100% - 16px); height: min(220px, 32dvh); align-items: stretch; }
1557
- .dshmore-conversation-nav-root[data-collapsed="true"] { height: 58px; }
1558
- .dshmore-conversation-nav-menu { max-height: 100%; }
1559
- }
1560
- @media (prefers-reduced-motion: reduce) {
1561
- .dshmore-conversation-nav-menu, .dshmore-conversation-nav-loading-dot { animation: none; }
1562
- .dshmore-conversation-nav-item { transition: none; }
1629
+ function installNewSessionNavigation(ctx, activation) {
1630
+ const navigation = ctx.get("uiWorkspace");
1631
+ const sessions = ctx.sessions;
1632
+ if (typeof navigation !== "object" || navigation === null || !("startSession" in navigation) || typeof navigation.startSession !== "function" || typeof sessions !== "object" || sessions === null || !("create" in sessions) || typeof sessions.create !== "function" || !("open" in sessions) || typeof sessions.open !== "function" || !("scope" in sessions) || typeof sessions.scope !== "function" || !("list" in sessions) || typeof sessions.list !== "object" || sessions.list === null || !("getSnapshot" in sessions.list) || typeof sessions.list.getSnapshot !== "function") {
1633
+ throw new Error("\u5F53\u524D DSH \u7248\u672C\u4E0D\u652F\u6301\u8DDF\u968F\u4F1A\u8BDD\u6765\u6E90\u65B0\u5EFA\u4EFB\u52A1\u3002");
1634
+ }
1635
+ const clientSessions = sessions;
1636
+ return bindNewSessionNavigation({
1637
+ navigation,
1638
+ sessions: clientSessions,
1639
+ workspaces: ctx.workspaces,
1640
+ activation,
1641
+ reportError: (sourceId, error) => {
1642
+ const scope = clientSessions.scope(sourceId);
1643
+ const message = `\u65B0\u5EFA\u4F1A\u8BDD\u5931\u8D25\uFF1A${apiErrorText(error)}`;
1644
+ if (scope !== void 0) ctx.conversation.input.for(scope).notify("error", message);
1645
+ else ctx.logger.warn(message);
1646
+ }
1647
+ });
1563
1648
  }
1564
- `;
1565
- var clientPatch4 = {
1566
- id: CONVERSATION_QUICK_NAVIGATION_PATCH_ID,
1649
+
1650
+ // src/patches/projectless-tasks/client/index.tsx
1651
+ var clientPatch5 = {
1652
+ id: PROJECTLESS_TASKS_PATCH_ID,
1567
1653
  install: (ctx, activation) => {
1568
- ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
1569
- name: "conversation.session.header.utilities",
1570
- id: `${PLUGIN_NAME}-${CONVERSATION_QUICK_NAVIGATION_PATCH_ID}`,
1571
- order: 120
1572
- }, (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ConversationQuickNavigation, { ...props, activation })));
1654
+ ctx.inject(["conversation", "uiWorkspace"], (scope) => {
1655
+ scope.effect(() => installNewSessionNavigation(scope, activation));
1656
+ scope.slots.inject("conversation", () => installConversationAdapter(scope, activation));
1657
+ scope.slots.inject("conversation.hero.workspace", () => installPickerAdapter(scope));
1658
+ });
1573
1659
  }
1574
1660
  };
1575
1661
 
1576
1662
  // src/generated/client-registry.ts
1577
1663
  var MESSAGE_ACTION_PATCHES = [{ id: "message-edit", order: 100, useActions: useMessageActions }, { id: "message-delete", order: 200, useActions: useMessageActions2 }];
1578
- var CLIENT_PATCHES = [clientPatch, clientPatch2, clientPatch3, clientPatch4];
1664
+ var CLIENT_PATCHES = [clientPatch, clientPatch2, clientPatch3, clientPatch4, clientPatch5];
1579
1665
 
1580
1666
  // src/kernel/client/activation.ts
1581
1667
  var ClientPatchActivation = class {
@@ -1598,19 +1684,19 @@ var ClientPatchActivation = class {
1598
1684
  };
1599
1685
 
1600
1686
  // src/kernel/client/config-card.tsx
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");
1687
+ var import_react9 = require("react");
1688
+ var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
1689
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1604
1690
  function PatchConfigCard({ activation, initiallyOpen = false }) {
1605
- const scope = (0, import_react7.useSyncExternalStore)(
1691
+ const scope = (0, import_react9.useSyncExternalStore)(
1606
1692
  activation.subscribe,
1607
1693
  activation.getSettingsSnapshot,
1608
1694
  activation.getSettingsSnapshot
1609
1695
  );
1610
1696
  const settings = activation.getSnapshot();
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);
1697
+ const [open, setOpen] = (0, import_react9.useState)(initiallyOpen);
1698
+ const [busy, setBusy] = (0, import_react9.useState)(/* @__PURE__ */ new Set());
1699
+ const [error, setError] = (0, import_react9.useState)(null);
1614
1700
  if (scope.status === "unavailable") return null;
1615
1701
  const update = async (id, enabled) => {
1616
1702
  setBusy((current) => /* @__PURE__ */ new Set([...current, id]));
@@ -1627,9 +1713,9 @@ function PatchConfigCard({ activation, initiallyOpen = false }) {
1627
1713
  });
1628
1714
  }
1629
1715
  };
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)(
1716
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { className: `dshmore-config-card${open ? " dshmore-config-card-open" : ""}`, children: [
1717
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: styles }),
1718
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1633
1719
  "button",
1634
1720
  {
1635
1721
  type: "button",
@@ -1640,23 +1726,23 @@ function PatchConfigCard({ activation, initiallyOpen = false }) {
1640
1726
  setOpen((current) => !current);
1641
1727
  },
1642
1728
  children: [
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" })
1729
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "dshmore-config-heading-copy", children: [
1730
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "DSH More" }),
1731
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "\u52A8\u6001\u5F00\u542F\u6216\u5173\u95ED\u72EC\u7ACB\u8865\u4E01\uFF0C\u9ED8\u8BA4\u5168\u90E8\u5F00\u542F\u3002" })
1646
1732
  ] }),
1647
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_dsh_client_ui_primitives7.IconChevronDownOutline14, { className: `dshmore-config-chevron${open ? " dshmore-config-chevron-open" : ""}` })
1733
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_dsh_client_ui_primitives6.IconChevronDownOutline14, { className: `dshmore-config-chevron${open ? " dshmore-config-chevron-open" : ""}` })
1648
1734
  ]
1649
1735
  }
1650
1736
  ),
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) => {
1737
+ open && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dshmore-config-body", children: [
1738
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dshmore-config-list", children: PATCH_CATALOG.map((patch) => {
1653
1739
  const waiting = busy.has(patch.id);
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 })
1740
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "dshmore-config-row", children: [
1741
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "dshmore-config-copy", children: [
1742
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: patch.name }),
1743
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: patch.description })
1658
1744
  ] }),
1659
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1745
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1660
1746
  "input",
1661
1747
  {
1662
1748
  type: "checkbox",
@@ -1671,9 +1757,9 @@ function PatchConfigCard({ activation, initiallyOpen = false }) {
1671
1757
  )
1672
1758
  ] }, patch.id);
1673
1759
  }) }),
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 })
1760
+ scope.status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "dshmore-config-note", children: "\u6B63\u5728\u8BFB\u53D6\u63D2\u4EF6\u914D\u7F6E\u2026" }),
1761
+ scope.status === "ready" && !scope.writable && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "dshmore-config-note", children: "\u5F53\u524D Settings \u5B58\u50A8\u4E3A\u53EA\u8BFB\u3002" }),
1762
+ error !== null && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "dshmore-config-error", children: error })
1677
1763
  ] })
1678
1764
  ] });
1679
1765
  }
@@ -1682,11 +1768,21 @@ function installPatchConfigCard(ctx, activation) {
1682
1768
  name: "settings.plugin.item",
1683
1769
  key: PATCH_SETTINGS_NAMESPACE,
1684
1770
  priority: 90
1685
- }, (props) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PatchConfigCard, { ...props, activation })));
1771
+ }, (props) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PatchConfigCard, { ...props, activation })));
1772
+ }
1773
+
1774
+ // src/kernel/message-visibility.ts
1775
+ var MESSAGE_VISIBILITY_PROJECTION_KEY = "dshMoreMessageDelete";
1776
+
1777
+ // src/platform/dsh/client/message-targets.tsx
1778
+ var import_react10 = require("react");
1779
+
1780
+ // src/platform/dsh/client/message-content.ts
1781
+ function contentText(content) {
1782
+ return content.filter((block) => block.type === "text").map((block) => block.text).join(" ").replace(/\s+/g, " ").trim();
1686
1783
  }
1687
1784
 
1688
1785
  // src/platform/dsh/client/message-targets.tsx
1689
- var import_react8 = require("react");
1690
1786
  var EMPTY_MESSAGE_SURFACE = {
1691
1787
  rows: [],
1692
1788
  byKey: /* @__PURE__ */ new Map()
@@ -1817,17 +1913,17 @@ function trajectorySourceSeq(row) {
1817
1913
  return Number.isSafeInteger(seq) && seq >= 0 ? seq : void 0;
1818
1914
  }
1819
1915
  function useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, active = true) {
1820
- const selector = (0, import_react8.useMemo)(() => createMessageSurfaceSelector(active), [active, props.sessionId]);
1916
+ const selector = (0, import_react10.useMemo)(() => createMessageSurfaceSelector(active), [active, props.sessionId]);
1821
1917
  const surface = props.useChat(selector);
1822
- const surfaceRef = (0, import_react8.useRef)(surface);
1823
- const hiddenSeqsRef = (0, import_react8.useRef)(hiddenSeqs);
1824
- const hiddenTrajectoryKeysRef = (0, import_react8.useRef)(hiddenTrajectoryKeys);
1918
+ const surfaceRef = (0, import_react10.useRef)(surface);
1919
+ const hiddenSeqsRef = (0, import_react10.useRef)(hiddenSeqs);
1920
+ const hiddenTrajectoryKeysRef = (0, import_react10.useRef)(hiddenTrajectoryKeys);
1825
1921
  surfaceRef.current = surface;
1826
1922
  hiddenSeqsRef.current = hiddenSeqs;
1827
1923
  hiddenTrajectoryKeysRef.current = hiddenTrajectoryKeys;
1828
- const [targets, setTargets] = (0, import_react8.useState)([]);
1829
- const requestFullScanRef = (0, import_react8.useRef)(null);
1830
- (0, import_react8.useLayoutEffect)(() => {
1924
+ const [targets, setTargets] = (0, import_react10.useState)([]);
1925
+ const requestFullScanRef = (0, import_react10.useRef)(null);
1926
+ (0, import_react10.useLayoutEffect)(() => {
1831
1927
  if (!active) {
1832
1928
  setTargets((current) => current.length === 0 ? current : []);
1833
1929
  return;
@@ -1951,21 +2047,21 @@ function useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, active = tru
1951
2047
  for (const host of document.querySelectorAll("[data-dshmore-message-actions]")) host.remove();
1952
2048
  };
1953
2049
  }, [active, props.sessionId]);
1954
- (0, import_react8.useLayoutEffect)(() => {
2050
+ (0, import_react10.useLayoutEffect)(() => {
1955
2051
  requestFullScanRef.current?.();
1956
2052
  }, [surface, hiddenSeqs, hiddenTrajectoryKeys]);
1957
2053
  return targets;
1958
2054
  }
1959
2055
 
1960
2056
  // src/client/index.tsx
1961
- var import_jsx_runtime8 = require("react/jsx-runtime");
2057
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1962
2058
  var inject = ["slots", "sessions", "workspaces", "settingsScope"];
1963
2059
  function MessageActionPatchController({ patch, props, targets, enabled }) {
1964
2060
  const actions = patch.useActions(props, enabled);
1965
2061
  const style = { "--dshmore-action-order": patch.order };
1966
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1967
- enabled && targets.map((target) => (0, import_react_dom2.createPortal)(
1968
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dshmore-action-contribution", style, children: actions.renderAction(target) }),
2062
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2063
+ enabled && targets.map((target) => (0, import_react_dom.createPortal)(
2064
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dshmore-action-contribution", style, children: actions.renderAction(target) }),
1969
2065
  target.host,
1970
2066
  `${patch.id}:${target.key}`
1971
2067
  )),
@@ -1973,15 +2069,15 @@ function MessageActionPatchController({ patch, props, targets, enabled }) {
1973
2069
  ] });
1974
2070
  }
1975
2071
  function MessageActionsController(props) {
1976
- const settings = (0, import_react9.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
2072
+ const settings = (0, import_react11.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
1977
2073
  const projected = props.useProjection(MESSAGE_VISIBILITY_PROJECTION_KEY);
1978
- const hiddenSeqs = (0, import_react9.useMemo)(() => new Set(projected?.deletedSeqs ?? []), [projected]);
1979
- const hiddenTrajectoryKeys = (0, import_react9.useMemo)(() => new Set(projected?.hiddenTrajectoryKeys ?? []), [projected]);
2074
+ const hiddenSeqs = (0, import_react11.useMemo)(() => new Set(projected?.deletedSeqs ?? []), [projected]);
2075
+ const hiddenTrajectoryKeys = (0, import_react11.useMemo)(() => new Set(projected?.hiddenTrajectoryKeys ?? []), [projected]);
1980
2076
  const messageActionsEnabled = MESSAGE_ACTION_PATCHES.some((patch) => settings[patch.id]);
1981
2077
  const targets = useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, messageActionsEnabled);
1982
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1983
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: styles }),
1984
- MESSAGE_ACTION_PATCHES.map((patch) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2078
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2079
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("style", { children: styles }),
2080
+ MESSAGE_ACTION_PATCHES.map((patch) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1985
2081
  MessageActionPatchController,
1986
2082
  {
1987
2083
  patch,
@@ -2004,7 +2100,7 @@ function apply(ctx) {
2004
2100
  name: "conversation.session.header.utilities",
2005
2101
  id: `${PLUGIN_NAME}-message-actions`,
2006
2102
  order: 90
2007
- }, (props) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MessageActionsController, { ...props, ctx, activation })));
2103
+ }, (props) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageActionsController, { ...props, ctx, activation })));
2008
2104
  for (const patch of CLIENT_PATCHES) patch.install(ctx, activation);
2009
2105
  }
2010
2106
  return module.exports; } });