dsh-more 0.1.0 → 0.1.2

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 (35) hide show
  1. package/CONTRIBUTING.md +13 -0
  2. package/README.md +26 -7
  3. package/README.zh-CN.md +40 -7
  4. package/cordis.patch.yml +2 -0
  5. package/dist/client.js +876 -303
  6. package/dist/fast-mode.js +34 -0
  7. package/dist/index.js +324 -35
  8. package/dist/types/generated/host-settings-schema.d.ts +21 -17
  9. package/dist/types/generated/patch-catalog.d.ts +16 -0
  10. package/dist/types/kernel/client/activation.d.ts +2 -2
  11. package/dist/types/kernel/host/activation.d.ts +1 -0
  12. package/dist/types/kernel/host/patch.d.ts +2 -0
  13. package/dist/types/kernel/host/settings.d.ts +7 -3
  14. package/dist/types/patches/fast-mode/client/index.d.ts +19 -0
  15. package/dist/types/patches/fast-mode/client/styles.d.ts +1 -0
  16. package/dist/types/patches/fast-mode/host/index.d.ts +26 -0
  17. package/dist/types/patches/fast-mode/host/settings.d.ts +6 -0
  18. package/dist/types/patches/fast-mode/shared.d.ts +17 -0
  19. package/dist/types/patches/model-capabilities/client/index.d.ts +1 -1
  20. package/dist/types/patches/projectless-tasks/client/adapter.d.ts +2 -3
  21. package/dist/types/patches/projectless-tasks/client/create-task.d.ts +2 -2
  22. package/dist/types/patches/projectless-tasks/client/groups.d.ts +2 -2
  23. package/dist/types/patches/projectless-tasks/client/new-session.d.ts +2 -1
  24. package/dist/types/patches/terminal-clipboard/client/clipboard.d.ts +5 -0
  25. package/dist/types/patches/terminal-clipboard/client/index.d.ts +2 -0
  26. package/dist/types/patches/terminal-clipboard/client/terminal.d.ts +17 -0
  27. package/dist/types/patches/terminal-clipboard/host/index.d.ts +2 -0
  28. package/dist/types/patches/terminal-clipboard/shared.d.ts +1 -0
  29. package/dist/types/platform/dsh/client/runtime.d.ts +20 -2
  30. package/dist/types/platform/dsh/client/session-menu.d.ts +10 -0
  31. package/dist/types/platform/dsh/client/settings.d.ts +15 -1
  32. package/dist/types/platform/dsh/identity.d.ts +1 -1
  33. package/docs/desktop-compatibility.md +158 -0
  34. package/dsh.plugin.json +2 -2
  35. package/package.json +72 -61
package/dist/client.js CHANGED
@@ -35,7 +35,7 @@ __export(index_exports, {
35
35
  inject: () => inject
36
36
  });
37
37
  module.exports = __toCommonJS(index_exports);
38
- var import_react13 = require("react");
38
+ var import_react15 = require("react");
39
39
  var import_react_dom = require("react-dom");
40
40
 
41
41
  // src/generated/patch-catalog.ts
@@ -45,8 +45,10 @@ var PATCH_CATALOG = [
45
45
  { "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" },
46
46
  { "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" },
47
47
  { "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" },
48
+ { "id": "fast-mode", "name": "\u52A0\u901F", "description": "\u5728\u8F93\u5165\u6846\u548C /fast \u547D\u4EE4\u4E2D\u5F00\u5173\u52A0\u901F\u3002\u54CD\u5E94\u66F4\u5FEB\uFF0C\u4F46\u4F1A\u66F4\u5FEB\u6D88\u8017\u989D\u5EA6", "defaultEnabled": true, "order": 550, "clientKind": "standalone" },
48
49
  { "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" },
49
- { "id": "projectless-tasks", "name": "\u72EC\u7ACB\u4EFB\u52A1", "description": "\u5728\u5DE5\u4F5C\u533A\u4E0B\u62C9\u6846\u521B\u5EFA\u72EC\u7ACB\u4EFB\u52A1\u5E76\u4FDD\u7559\u8349\u7A3F\uFF0C\u4E5F\u53EF\u5C06\u672A\u5206\u7EC4\u4F1A\u8BDD\u79FB\u5165\u5DE5\u4F5C\u533A\u5217\u8868", "defaultEnabled": true, "order": 700, "clientKind": "standalone" }
50
+ { "id": "projectless-tasks", "name": "\u72EC\u7ACB\u4EFB\u52A1", "description": "\u5728\u5DE5\u4F5C\u533A\u4E0B\u62C9\u6846\u521B\u5EFA\u72EC\u7ACB\u4EFB\u52A1\u5E76\u4FDD\u7559\u8349\u7A3F\uFF0C\u4E5F\u53EF\u5C06\u672A\u5206\u7EC4\u4F1A\u8BDD\u79FB\u5165\u5DE5\u4F5C\u533A\u5217\u8868", "defaultEnabled": true, "order": 700, "clientKind": "standalone" },
51
+ { "id": "terminal-clipboard", "name": "\u7EC8\u7AEF\u590D\u5236\u7C98\u8D34", "description": "\u53F3\u4FA7\u7EC8\u7AEF\u9009\u4E2D\u81EA\u52A8\u590D\u5236\u3001\u53F3\u952E\u7C98\u8D34\uFF0C\u652F\u6301 Ctrl+Shift+C/V \u548C Shift+Insert\uFF1B\u65E0\u9009\u533A\u65F6\u4FDD\u7559 Ctrl+C \u4E2D\u65AD", "defaultEnabled": true, "order": 800, "clientKind": "standalone" }
50
52
  ];
51
53
  var DEFAULT_PATCH_SETTINGS = {
52
54
  "message-edit": true,
@@ -54,8 +56,10 @@ var DEFAULT_PATCH_SETTINGS = {
54
56
  "session-delete": true,
55
57
  "conversation-markdown-export": true,
56
58
  "model-capabilities": true,
59
+ "fast-mode": true,
57
60
  "session-auto-title": true,
58
- "projectless-tasks": true
61
+ "projectless-tasks": true,
62
+ "terminal-clipboard": true
59
63
  };
60
64
  function decodePatchSettings(value) {
61
65
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -92,7 +96,7 @@ var IconChevronDownOutline14 = compatibleIcon("IconChevronDownOutlineRegular", "
92
96
 
93
97
  // src/platform/dsh/identity.ts
94
98
  var PLUGIN_NAME = "dsh-more";
95
- var PLUGIN_API_PREFIX = `/${PLUGIN_NAME}/api`;
99
+ var PLUGIN_API_PREFIX = `/api/${PLUGIN_NAME}`;
96
100
  var PLUGIN_MUTATION_HEADER = "x-dsh-more";
97
101
  var PATCH_SETTINGS_NAMESPACE = PLUGIN_NAME;
98
102
 
@@ -108,7 +112,9 @@ var DshMoreApiError = class extends Error {
108
112
  async function requestPatch(patchId, action, payload) {
109
113
  let response;
110
114
  try {
111
- response = await fetch(`${PLUGIN_API_PREFIX}/${encodeURIComponent(patchId)}/${encodeURIComponent(action)}`, {
115
+ const transport = globalThis.__DSH_TRANSPORT__;
116
+ const send = transport?.fetch?.bind(transport) ?? globalThis.fetch.bind(globalThis);
117
+ response = await send(`${PLUGIN_API_PREFIX}/${encodeURIComponent(patchId)}/${encodeURIComponent(action)}`.slice(1), {
112
118
  method: "POST",
113
119
  headers: {
114
120
  "content-type": "application/json",
@@ -146,6 +152,40 @@ function apiErrorText(error) {
146
152
  return String(error);
147
153
  }
148
154
 
155
+ // src/platform/dsh/client/runtime.ts
156
+ function currentSessionId(list) {
157
+ const legacy = list;
158
+ if (legacy.current !== void 0) return legacy.current;
159
+ return Object.values(list.byId).find((row) => {
160
+ const retained = row.retainedBy;
161
+ return (retained?.mainView ?? 0) > 0;
162
+ })?.id;
163
+ }
164
+ function clientSessions(ctx) {
165
+ const sessions = ctx.sessions;
166
+ const navigation = typeof ctx.get === "function" ? ctx.get("uiWorkspace") : void 0;
167
+ let open;
168
+ if (typeof sessions.open === "function") open = (id) => sessions.open(id);
169
+ else if (typeof navigation === "object" && navigation !== null && "openSession" in navigation && typeof navigation.openSession === "function") {
170
+ const openSession = navigation.openSession;
171
+ open = (id) => openSession.call(navigation, id);
172
+ } else throw new Error("\u5F53\u524D DSH \u7248\u672C\u4E0D\u652F\u6301\u4F1A\u8BDD\u5BFC\u822A\uFF0C\u8BF7\u68C0\u67E5\u4F1A\u8BDD\u63A5\u53E3\u3002");
173
+ return { list: sessions.list, refresh: () => sessions.refresh(), open };
174
+ }
175
+ function clientSessionActions(ctx) {
176
+ const sessions = ctx.sessions;
177
+ if (typeof sessions !== "object" || sessions === null || !("create" in sessions) || typeof sessions.create !== "function") {
178
+ throw new Error("\u5F53\u524D DSH \u7248\u672C\u4E0D\u652F\u6301\u72EC\u7ACB\u4EFB\u52A1\uFF0C\u8BF7\u68C0\u67E5\u4F1A\u8BDD\u63A5\u53E3\u3002");
179
+ }
180
+ const create = sessions.create;
181
+ const actions = { create: (options) => create.call(sessions, options), open: clientSessions(ctx).open };
182
+ if ("retain" in sessions && typeof sessions.retain === "function") {
183
+ const retain = sessions.retain;
184
+ actions.retain = (id) => retain.call(sessions, id, { source: "dsh-more-draft-transfer" });
185
+ }
186
+ return actions;
187
+ }
188
+
149
189
  // src/platform/dsh/client/session-sync.ts
150
190
  var INCREMENTAL_SYNC_GRACE_MS = 180;
151
191
  function openSessionWithoutGap(sessions, sessionId) {
@@ -223,7 +263,7 @@ async function settleSessionRemoval(sessions, workspaces, sessionId) {
223
263
  if (!settled()) throw new Error("\u4F1A\u8BDD\u5DF2\u5220\u9664\uFF0C\u4F46\u5BA2\u6237\u7AEF\u5217\u8868\u5C1A\u672A\u540C\u6B65\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u9875\u9762\u3002");
224
264
  }
225
265
  function adjacentVisibleSession(sessions, workspaces, deletingSessionId) {
226
- if (sessions.current !== deletingSessionId) return void 0;
266
+ if (currentSessionId(sessions) !== deletingSessionId) return void 0;
227
267
  const archived = new Set(workspaces.archivedSessionIds);
228
268
  const deletingIndex = sessions.ids.indexOf(deletingSessionId);
229
269
  for (let index = deletingIndex + 1; index < sessions.ids.length; index += 1) {
@@ -265,7 +305,7 @@ function useMessageActions(props, enabled) {
265
305
  if (target === null) return;
266
306
  setBusy(true);
267
307
  setError(null);
268
- const sessions = props.ctx.sessions;
308
+ const sessions = clientSessions(props.ctx);
269
309
  let handoff;
270
310
  try {
271
311
  const preview = await api.preview({ sessionId: props.sessionId, targetSeq: target.seq, text });
@@ -286,7 +326,7 @@ function useMessageActions(props, enabled) {
286
326
  const sessionList = sessions.list.getSnapshot();
287
327
  const sourceAvailable = sessionList.byId[sourceId] !== void 0;
288
328
  const sourceArchived = props.ctx.workspaces.list.getSnapshot().archivedSessionIds.includes(sourceId);
289
- if (sourceAvailable && !sourceArchived && sessionList.current !== sourceId) openSessionWithoutGap(sessions, sourceId);
329
+ if (sourceAvailable && !sourceArchived && currentSessionId(sessionList) !== sourceId) openSessionWithoutGap(sessions, sourceId);
290
330
  setError(apiErrorText(caught));
291
331
  } finally {
292
332
  setBusy(false);
@@ -373,7 +413,7 @@ function useMessageActions2(props, enabled) {
373
413
  if (target === null || preview === null) return;
374
414
  setBusy(true);
375
415
  setError(null);
376
- const sessions = props.ctx.sessions;
416
+ const sessions = clientSessions(props.ctx);
377
417
  const continuationSessionId = preview.continuationSessionId;
378
418
  const handoff = followSessionHandoff(sessions, continuationSessionId);
379
419
  try {
@@ -392,7 +432,7 @@ function useMessageActions2(props, enabled) {
392
432
  const sessionList = sessions.list.getSnapshot();
393
433
  const sourceAvailable = sessionList.byId[sourceId] !== void 0;
394
434
  const sourceArchived = props.ctx.workspaces.list.getSnapshot().archivedSessionIds.includes(sourceId);
395
- if (sourceAvailable && !sourceArchived && sessionList.current !== sourceId) openSessionWithoutGap(sessions, sourceId);
435
+ if (sourceAvailable && !sourceArchived && currentSessionId(sessionList) !== sourceId) openSessionWithoutGap(sessions, sourceId);
396
436
  setPreview(null);
397
437
  setError(apiErrorText(caught));
398
438
  } finally {
@@ -431,7 +471,7 @@ function useMessageActions2(props, enabled) {
431
471
  }
432
472
 
433
473
  // src/patches/session-delete/client/index.tsx
434
- var import_react4 = require("react");
474
+ var import_react5 = require("react");
435
475
  var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
436
476
 
437
477
  // src/platform/dsh/client/styles.ts
@@ -474,11 +514,39 @@ var styles = `
474
514
  @media (prefers-reduced-motion: no-preference) { .dshmore-config-chevron { transition: transform .16s; } }
475
515
  `;
476
516
 
517
+ // src/platform/dsh/client/session-menu.tsx
518
+ var import_react4 = require("react");
519
+ var primitives2 = __toESM(require("@deepseek-ai/dsh-client-ui-primitives"), 1);
520
+ var import_jsx_runtime3 = require("react/jsx-runtime");
521
+ var SESSION_MENU_SLOT = "sidebar.workspaces.session.menu.item";
522
+ function installSessionMenuAction(ctx, options) {
523
+ const slots = ctx.slots;
524
+ if (slots.spec?.(SESSION_MENU_SLOT) === void 0) return void 0;
525
+ const item = Reflect.get(primitives2, "MenuItemButton");
526
+ if (typeof item !== "function") return void 0;
527
+ const MenuItem = item;
528
+ return ctx.slots.register({
529
+ name: SESSION_MENU_SLOT,
530
+ id: options.id,
531
+ order: options.order
532
+ }, (props) => {
533
+ if (typeof props !== "object" || props === null || !("sessionId" in props) || typeof props.sessionId !== "string" || !("useMenuOpenState" in props) || typeof props.useMenuOpenState !== "function") return null;
534
+ return (0, import_react4.createElement)(SessionMenuAction, { ...options, MenuItem, menu: props });
535
+ });
536
+ }
537
+ function SessionMenuAction({ MenuItem, menu, label, danger = false, select }) {
538
+ const [, setOpen] = menu.useMenuOpenState();
539
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuItem, { danger, onSelect: () => {
540
+ setOpen(false);
541
+ select(menu.sessionId);
542
+ }, children: label });
543
+ }
544
+
477
545
  // src/patches/session-delete/shared.ts
478
546
  var SESSION_DELETE_PATCH_ID = "session-delete";
479
547
 
480
548
  // src/patches/session-delete/client/index.tsx
481
- var import_jsx_runtime3 = require("react/jsx-runtime");
549
+ var import_jsx_runtime4 = require("react/jsx-runtime");
482
550
  var DELETE_MENU_ATTRIBUTE = "data-dshmore-session-delete";
483
551
  var DELETE_SOURCE_ATTRIBUTE = "data-dshmore-session-delete-source";
484
552
  var sessionDeleteStyles = `
@@ -554,9 +622,9 @@ function installSessionDeleteMenuItems(onDelete) {
554
622
  flush();
555
623
  const observer = new MutationObserver((records) => {
556
624
  let removedKnownItem = false;
557
- for (const record of records) {
558
- record.addedNodes.forEach(collectButtons);
559
- if (record.removedNodes.length > 0 && deleteItems.size > 0) removedKnownItem = true;
625
+ for (const record2 of records) {
626
+ record2.addedNodes.forEach(collectButtons);
627
+ if (record2.removedNodes.length > 0 && deleteItems.size > 0) removedKnownItem = true;
560
628
  }
561
629
  if (pendingButtons.size > 0 || removedKnownItem) schedule();
562
630
  });
@@ -573,32 +641,48 @@ function installSessionDeleteMenuItems(onDelete) {
573
641
  };
574
642
  }
575
643
  function SessionDeleteController(props) {
576
- const settings = (0, import_react4.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
644
+ const settings = (0, import_react5.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
577
645
  const enabled = settings[SESSION_DELETE_PATCH_ID];
578
- const [pending, setPending] = (0, import_react4.useState)(null);
579
- const pendingRef = (0, import_react4.useRef)(null);
580
- const deleteIntentRef = (0, import_react4.useRef)(false);
581
- const [busy, setBusy] = (0, import_react4.useState)(false);
582
- const [error, setError] = (0, import_react4.useState)(null);
583
- (0, import_react4.useEffect)(() => {
646
+ const [pending, setPending] = (0, import_react5.useState)(null);
647
+ const pendingRef = (0, import_react5.useRef)(null);
648
+ const deleteIntentRef = (0, import_react5.useRef)(false);
649
+ const [busy, setBusy] = (0, import_react5.useState)(false);
650
+ const [error, setError] = (0, import_react5.useState)(null);
651
+ (0, import_react5.useEffect)(() => {
584
652
  if (!enabled) return;
585
653
  const workspaces = props.ctx.workspaces;
586
654
  const sessions = props.ctx.sessions;
655
+ const requestDelete = (sessionId, resolve = () => {
656
+ }) => {
657
+ const request = {
658
+ sessionId,
659
+ title: sessions.list.getSnapshot().byId[sessionId]?.displayTitle ?? String(sessionId),
660
+ resolve
661
+ };
662
+ pendingRef.current?.resolve();
663
+ pendingRef.current = request;
664
+ setError(null);
665
+ setPending(request);
666
+ };
667
+ const removeNativeItem = installSessionMenuAction(props.ctx, {
668
+ id: `${PLUGIN_NAME}-${SESSION_DELETE_PATCH_ID}`,
669
+ label: "\u6C38\u4E45\u5220\u9664\u4F1A\u8BDD",
670
+ order: 500,
671
+ danger: true,
672
+ select: (sessionId) => requestDelete(sessionId)
673
+ });
674
+ if (removeNativeItem !== void 0) return () => {
675
+ removeNativeItem();
676
+ pendingRef.current?.resolve();
677
+ pendingRef.current = null;
678
+ };
587
679
  const mutable = workspaces;
588
680
  const original = mutable.archiveSession;
589
681
  mutable.archiveSession = (sessionId) => {
590
682
  if (!deleteIntentRef.current) return original.call(mutable, sessionId);
591
683
  deleteIntentRef.current = false;
592
684
  return new Promise((resolve) => {
593
- const request = {
594
- sessionId,
595
- title: sessions.list.getSnapshot().byId[sessionId]?.displayTitle ?? String(sessionId),
596
- resolve
597
- };
598
- pendingRef.current?.resolve();
599
- pendingRef.current = request;
600
- setError(null);
601
- setPending(request);
685
+ requestDelete(sessionId, resolve);
602
686
  });
603
687
  };
604
688
  const removeDeleteItems = installSessionDeleteMenuItems((archiveButton) => {
@@ -627,15 +711,15 @@ function SessionDeleteController(props) {
627
711
  if (pending === null) return;
628
712
  setBusy(true);
629
713
  setError(null);
630
- const sessions = props.ctx.sessions;
714
+ const sessions = clientSessions(props.ctx);
631
715
  const workspaces = props.ctx.workspaces;
632
716
  const fallbackSessionId = adjacentVisibleSession(
633
717
  sessions.list.getSnapshot(),
634
718
  workspaces.list.getSnapshot(),
635
719
  pending.sessionId
636
720
  );
637
- if (fallbackSessionId !== void 0) openSessionWithoutGap(sessions, fallbackSessionId);
638
721
  try {
722
+ if (fallbackSessionId !== void 0) openSessionWithoutGap(sessions, fallbackSessionId);
639
723
  await callPatchApi(SESSION_DELETE_PATCH_ID, "commit", {
640
724
  sessionId: pending.sessionId,
641
725
  confirmSessionId: pending.sessionId
@@ -645,6 +729,8 @@ function SessionDeleteController(props) {
645
729
  pendingRef.current = null;
646
730
  setPending(null);
647
731
  } catch (caught) {
732
+ const list = sessions.list.getSnapshot();
733
+ if (fallbackSessionId !== void 0 && currentSessionId(list) === fallbackSessionId && list.byId[pending.sessionId] !== void 0) openSessionWithoutGap(sessions, pending.sessionId);
648
734
  setError(apiErrorText(caught));
649
735
  } finally {
650
736
  setBusy(false);
@@ -652,9 +738,9 @@ function SessionDeleteController(props) {
652
738
  };
653
739
  const title = pending?.title ?? "";
654
740
  if (!enabled) return null;
655
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
656
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: styles + sessionDeleteStyles }),
657
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
741
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
742
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: styles + sessionDeleteStyles }),
743
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
658
744
  import_dsh_client_ui_primitives3.Modal,
659
745
  {
660
746
  open: pending !== null,
@@ -662,17 +748,17 @@ function SessionDeleteController(props) {
662
748
  title: "\u6C38\u4E45\u5220\u9664\u4F1A\u8BDD\uFF1F",
663
749
  closeLabel: "\u5173\u95ED",
664
750
  description: "\u4F1A\u8BDD\u4F1A\u4ECE\u5DE6\u4FA7\u5217\u8868\u548C DSH \u6301\u4E45\u5316\u76EE\u5F55\u4E2D\u6C38\u4E45\u5220\u9664\uFF0C\u4E0D\u4F1A\u5F52\u6863\uFF0C\u4E5F\u4E0D\u4F1A\u79FB\u5165\u56DE\u6536\u76EE\u5F55\u3002",
665
- footer: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
666
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Button, { variant: "ghost", disabled: busy, onClick: close, children: "\u53D6\u6D88" }),
667
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Button, { variant: "primary", disabled: busy, onClick: () => void commit(), children: busy ? "\u6B63\u5728\u5220\u9664\u2026" : "\u6C38\u4E45\u5220\u9664" })
751
+ footer: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
752
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives3.Button, { variant: "ghost", disabled: busy, onClick: close, children: "\u53D6\u6D88" }),
753
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives3.Button, { variant: "primary", disabled: busy, onClick: () => void commit(), children: busy ? "\u6B63\u5728\u5220\u9664\u2026" : "\u6C38\u4E45\u5220\u9664" })
668
754
  ] }),
669
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dshmore-dialog-body", children: [
670
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dshmore-message-preview", children: title }),
671
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dshmore-danger", children: [
672
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(IconWarningOutline16, { size: 16 }),
755
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dshmore-dialog-body", children: [
756
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dshmore-message-preview", children: title }),
757
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dshmore-danger", children: [
758
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(IconWarningOutline16, { size: 16 }),
673
759
  " \u82E5\u4F1A\u8BDD\u6B63\u5728\u8FD0\u884C\uFF0C\u5C06\u5148\u505C\u6B62\u5F53\u524D\u4EFB\u52A1\u3002\u5220\u9664\u540E\u65E0\u6CD5\u6062\u590D\u3002"
674
760
  ] }),
675
- error !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dshmore-error", children: error })
761
+ error !== null && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dshmore-error", children: error })
676
762
  ] })
677
763
  }
678
764
  )
@@ -685,12 +771,12 @@ var clientPatch = {
685
771
  name: "shell.overlay",
686
772
  id: `${PLUGIN_NAME}-${SESSION_DELETE_PATCH_ID}`,
687
773
  order: 90
688
- }, (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SessionDeleteController, { ...props, ctx, activation })));
774
+ }, (props) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SessionDeleteController, { ...props, ctx, activation })));
689
775
  }
690
776
  };
691
777
 
692
778
  // src/patches/conversation-markdown-export/client/index.tsx
693
- var import_react5 = require("react");
779
+ var import_react6 = require("react");
694
780
  var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
695
781
 
696
782
  // src/patches/conversation-markdown-export/shared.ts
@@ -698,7 +784,8 @@ var CONVERSATION_MARKDOWN_EXPORT_PATCH_ID = "conversation-markdown-export";
698
784
 
699
785
  // src/patches/conversation-markdown-export/client/filename.ts
700
786
  function safeStem(value) {
701
- return [...value.normalize("NFKC").replace(/[\u0000-\u001f\u007f/\\?%*:|"<>]+/g, "-").replace(/\s+/g, " ").replace(/^[.\s-]+|[.\s-]+$/g, "")].slice(0, 80).join("").trim();
787
+ const stem = [...value.normalize("NFKC").replace(/[\u0000-\u001f\u007f/\\?%*:|"<>]+/g, "-").replace(/\s+/g, " ").replace(/^[.\s-]+|[.\s-]+$/g, "")].slice(0, 80).join("").replace(/[.\s]+$/g, "");
788
+ return /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?: *[.]| *$)/i.test(stem) ? `_${stem}` : stem;
702
789
  }
703
790
  function markdownFilename(title, sessionId) {
704
791
  const fallback = safeStem(`dsh-conversation-${sessionId}`) || "dsh-conversation";
@@ -707,7 +794,7 @@ function markdownFilename(title, sessionId) {
707
794
 
708
795
  // src/patches/conversation-markdown-export/client/menu.ts
709
796
  var MENU_ITEM_ATTRIBUTE = "data-dshmore-markdown-export";
710
- var MORE_BUTTON_SELECTOR = 'button[class*="_moreButton"][aria-haspopup="menu"]';
797
+ var MORE_BUTTON_SELECTOR = 'button[aria-haspopup="menu"]';
711
798
  function installMarkdownExportMenu(fallback, options) {
712
799
  const header = fallback.closest("header");
713
800
  if (header === null) return () => {
@@ -723,14 +810,18 @@ function installMarkdownExportMenu(fallback, options) {
723
810
  const sync = () => {
724
811
  frame = null;
725
812
  const trigger = Array.from(header.querySelectorAll(MORE_BUTTON_SELECTOR)).find((button2) => ["\u66F4\u591A\u64CD\u4F5C", "More actions"].includes(button2.getAttribute("aria-label") ?? ""));
726
- fallback.hidden = trigger !== void 0;
727
- const download = trigger?.parentElement?.querySelector('button[role="menuitem"]');
813
+ const open = trigger?.getAttribute("aria-expanded") === "true";
814
+ fallback.hidden = trigger !== void 0 && !open;
815
+ const download = open ? Array.from(header.querySelectorAll('button[role="menuitem"]')).find((button2) => ["\u4E0B\u8F7D Session \u65E5\u5FD7", "Download session log"].includes(button2.textContent?.trim() ?? "")) : void 0;
728
816
  const text = download?.textContent?.trim();
729
817
  if (download === void 0 || download === null || !["\u4E0B\u8F7D Session \u65E5\u5FD7", "Download session log"].includes(text ?? "")) {
730
818
  removeItem();
731
819
  return;
732
820
  }
733
- if (source === download && item?.isConnected === true) return;
821
+ if (source === download && item?.isConnected === true) {
822
+ fallback.hidden = true;
823
+ return;
824
+ }
734
825
  removeItem();
735
826
  const wrapper = download.parentElement;
736
827
  if (wrapper === null || wrapper.getAttribute("role") === "menu") return;
@@ -757,6 +848,7 @@ function installMarkdownExportMenu(fallback, options) {
757
848
  source = download;
758
849
  item = clone;
759
850
  wrapper.after(clone);
851
+ fallback.hidden = true;
760
852
  };
761
853
  sync();
762
854
  const observer = new MutationObserver(() => {
@@ -778,7 +870,7 @@ function installMarkdownExportMenu(fallback, options) {
778
870
  }
779
871
 
780
872
  // src/patches/conversation-markdown-export/client/index.tsx
781
- var import_jsx_runtime4 = require("react/jsx-runtime");
873
+ var import_jsx_runtime5 = require("react/jsx-runtime");
782
874
  var exportStyles = `
783
875
  .dshmore-markdown-export-button { box-sizing: border-box; min-width: 128px; height: 32px; color: var(--dsw-alias-label-primary); cursor: pointer; background: transparent; border: 1px solid var(--dsw-alias-border-l2); border-radius: 18px; display: inline-flex; align-items: center; justify-content: center; gap: 5px; padding: 6px 12px; font-family: var(--dsw-font-family); font-size: 13px; line-height: 20px; }
784
876
  .dshmore-markdown-export-button[hidden] { display: none; }
@@ -800,17 +892,17 @@ function saveMarkdown(filename, markdown) {
800
892
  }, 0);
801
893
  }
802
894
  function ConversationMarkdownExportButton(props) {
803
- const settings = (0, import_react5.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
895
+ const settings = (0, import_react6.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
804
896
  const enabled = settings[CONVERSATION_MARKDOWN_EXPORT_PATCH_ID];
805
897
  const title = props.useSessions((state) => state.byId[props.sessionId]?.displayTitle ?? String(props.sessionId));
806
- const [busy, setBusy] = (0, import_react5.useState)(false);
807
- const [error, setError] = (0, import_react5.useState)(null);
808
- const button = (0, import_react5.useRef)(null);
809
- const inFlight = (0, import_react5.useRef)(false);
810
- const generation = (0, import_react5.useRef)(0);
811
- const activeSession = (0, import_react5.useRef)(null);
898
+ const [busy, setBusy] = (0, import_react6.useState)(false);
899
+ const [error, setError] = (0, import_react6.useState)(null);
900
+ const button = (0, import_react6.useRef)(null);
901
+ const inFlight = (0, import_react6.useRef)(false);
902
+ const generation = (0, import_react6.useRef)(0);
903
+ const activeSession = (0, import_react6.useRef)(null);
812
904
  activeSession.current = enabled ? String(props.sessionId) : null;
813
- (0, import_react5.useEffect)(() => {
905
+ (0, import_react6.useEffect)(() => {
814
906
  generation.current += 1;
815
907
  inFlight.current = false;
816
908
  setBusy(false);
@@ -843,16 +935,16 @@ function ConversationMarkdownExportButton(props) {
843
935
  }
844
936
  }
845
937
  };
846
- (0, import_react5.useEffect)(() => {
938
+ (0, import_react6.useEffect)(() => {
847
939
  if (!enabled || button.current === null) return;
848
940
  return installMarkdownExportMenu(button.current, { busy, download: () => {
849
941
  void download();
850
942
  } });
851
943
  }, [enabled, props.sessionId, title, busy]);
852
944
  if (!enabled) return null;
853
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
854
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: exportStyles }),
855
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
945
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
946
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: exportStyles }),
947
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
856
948
  "button",
857
949
  {
858
950
  ref: button,
@@ -865,12 +957,12 @@ function ConversationMarkdownExportButton(props) {
865
957
  void download();
866
958
  },
867
959
  children: [
868
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: busy ? "\u6B63\u5728\u5BFC\u51FA\u2026" : "\u5BFC\u51FA Markdown" }),
869
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(IconDownloadOutline16, { size: 12 })
960
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: busy ? "\u6B63\u5728\u5BFC\u51FA\u2026" : "\u5BFC\u51FA Markdown" }),
961
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(IconDownloadOutline16, { size: 12 })
870
962
  ]
871
963
  }
872
964
  ),
873
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
965
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
874
966
  import_dsh_client_ui_primitives4.Modal,
875
967
  {
876
968
  open: error !== null,
@@ -878,7 +970,7 @@ function ConversationMarkdownExportButton(props) {
878
970
  title: "\u65E0\u6CD5\u5BFC\u51FA\u804A\u5929\u8BB0\u5F55",
879
971
  closeLabel: "\u5173\u95ED",
880
972
  description: error ?? "",
881
- footer: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives4.Button, { variant: "primary", onClick: () => setError(null), children: "\u5173\u95ED" })
973
+ footer: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Button, { variant: "primary", onClick: () => setError(null), children: "\u5173\u95ED" })
882
974
  }
883
975
  )
884
976
  ] });
@@ -890,12 +982,12 @@ var clientPatch2 = {
890
982
  name: "conversation.session.header.utilities",
891
983
  id: `${PLUGIN_NAME}-${CONVERSATION_MARKDOWN_EXPORT_PATCH_ID}`,
892
984
  order: 100
893
- }, (props) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ConversationMarkdownExportButton, { ...props, activation })));
985
+ }, (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ConversationMarkdownExportButton, { ...props, activation })));
894
986
  }
895
987
  };
896
988
 
897
989
  // src/patches/model-capabilities/client/index.tsx
898
- var import_react7 = require("react");
990
+ var import_react8 = require("react");
899
991
 
900
992
  // src/patches/model-capabilities/shared.ts
901
993
  var MODEL_CAPABILITIES_PATCH_ID = "model-capabilities";
@@ -977,9 +1069,9 @@ function withSettings(ctx, install2) {
977
1069
  }
978
1070
 
979
1071
  // src/patches/model-capabilities/client/editor.tsx
980
- var import_react6 = require("react");
1072
+ var import_react7 = require("react");
981
1073
  var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
982
- var import_jsx_runtime5 = require("react/jsx-runtime");
1074
+ var import_jsx_runtime6 = require("react/jsx-runtime");
983
1075
  var LEVEL_LABELS = {
984
1076
  off: "\u4E0D\u601D\u8003",
985
1077
  minimal: "\u6781\u7B80",
@@ -1033,49 +1125,49 @@ function summaryLabel(capabilities) {
1033
1125
  return `${vision} \xB7 ${thinking}`;
1034
1126
  }
1035
1127
  function CapabilitiesEditorBody({ draft, setDraft, disabled, api: api3 }) {
1036
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-capabilities-fields", children: [
1037
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-capabilities-field", children: [
1038
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u8BC6\u56FE\u80FD\u529B" }),
1039
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { "aria-label": "\u8BC6\u56FE\u80FD\u529B", value: draft.vision, disabled, onChange: (event) => {
1128
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-capabilities-fields", children: [
1129
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "dshmore-capabilities-field", children: [
1130
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u8BC6\u56FE\u80FD\u529B" }),
1131
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("select", { "aria-label": "\u8BC6\u56FE\u80FD\u529B", value: draft.vision, disabled, onChange: (event) => {
1040
1132
  const vision = event.currentTarget.value;
1041
1133
  setDraft((current) => ({ ...current, vision }));
1042
1134
  }, children: [
1043
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "default", children: "\u6CBF\u7528\u9ED8\u8BA4" }),
1044
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "yes", children: "\u652F\u6301\u8BC6\u56FE" }),
1045
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "no", children: "\u4E0D\u652F\u6301\u8BC6\u56FE\uFF08\u4EC5\u6587\u5B57\uFF09" })
1135
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "default", children: "\u6CBF\u7528\u9ED8\u8BA4" }),
1136
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "yes", children: "\u652F\u6301\u8BC6\u56FE" }),
1137
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "no", children: "\u4E0D\u652F\u6301\u8BC6\u56FE\uFF08\u4EC5\u6587\u5B57\uFF09" })
1046
1138
  ] })
1047
1139
  ] }),
1048
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-capabilities-field", children: [
1049
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u601D\u8003\u7C7B\u578B" }),
1050
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { "aria-label": "\u601D\u8003\u7C7B\u578B", value: draft.thinking, disabled, onChange: (event) => {
1140
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "dshmore-capabilities-field", children: [
1141
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u601D\u8003\u7C7B\u578B" }),
1142
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("select", { "aria-label": "\u601D\u8003\u7C7B\u578B", value: draft.thinking, disabled, onChange: (event) => {
1051
1143
  const thinking = event.currentTarget.value;
1052
1144
  setDraft((current) => ({ ...current, thinking }));
1053
1145
  }, children: [
1054
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "default", children: "\u6CBF\u7528\u9ED8\u8BA4" }),
1055
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "disabled", children: "\u4E0D\u652F\u6301\u601D\u8003" }),
1056
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "custom", children: "\u81EA\u5B9A\u4E49\u53EF\u9009\u7C7B\u578B" })
1146
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "default", children: "\u6CBF\u7528\u9ED8\u8BA4" }),
1147
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "disabled", children: "\u4E0D\u652F\u6301\u601D\u8003" }),
1148
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "custom", children: "\u81EA\u5B9A\u4E49\u53EF\u9009\u7C7B\u578B" })
1057
1149
  ] })
1058
1150
  ] }),
1059
- draft.thinking === "custom" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("fieldset", { className: "dshmore-capabilities-levels", disabled, children: [
1060
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("legend", { children: "\u6A21\u578B\u652F\u6301\u7684\u601D\u8003\u7B49\u7EA7" }),
1151
+ draft.thinking === "custom" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("fieldset", { className: "dshmore-capabilities-levels", disabled, children: [
1152
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("legend", { children: "\u6A21\u578B\u652F\u6301\u7684\u601D\u8003\u7B49\u7EA7" }),
1061
1153
  (api3 === "deepseek-native" ? DEEPSEEK_THINKING_LEVELS : THINKING_LEVELS).map((level) => {
1062
1154
  const entry = draft.levels[level];
1063
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-capabilities-level", children: [
1064
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { children: [
1065
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", checked: entry?.enabled === true, onChange: (event) => {
1155
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-capabilities-level", children: [
1156
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
1157
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "checkbox", checked: entry?.enabled === true, onChange: (event) => {
1066
1158
  const enabled = event.currentTarget.checked;
1067
1159
  setDraft((current) => ({ ...current, levels: {
1068
1160
  ...current.levels,
1069
1161
  [level]: { wire: level === "off" ? "" : level, ...current.levels[level], enabled }
1070
1162
  } }));
1071
1163
  } }),
1072
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
1164
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
1073
1165
  LEVEL_LABELS[level],
1074
1166
  " ",
1075
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { children: level })
1167
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("small", { children: level })
1076
1168
  ] })
1077
1169
  ] }),
1078
- entry?.enabled && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1170
+ entry?.enabled && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1079
1171
  "input",
1080
1172
  {
1081
1173
  type: "text",
@@ -1095,41 +1187,41 @@ function CapabilitiesEditorBody({ draft, setDraft, disabled, api: api3 }) {
1095
1187
  ] }, level);
1096
1188
  })
1097
1189
  ] }),
1098
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("details", { className: "dshmore-capabilities-advanced", children: [
1099
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("summary", { children: [
1190
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("details", { className: "dshmore-capabilities-advanced", children: [
1191
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("summary", { children: [
1100
1192
  "\u601D\u8003\u53C2\u6570\u683C\u5F0F",
1101
1193
  draft.thinkingFormat === "default" ? "" : ` \xB7 ${draft.thinkingFormat}`
1102
1194
  ] }),
1103
- api3 === null || api3 === "openai-completions" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "dshmore-capabilities-field", children: [
1104
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u63A5\u53E3\u63A5\u53D7\u7684\u683C\u5F0F" }),
1105
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { "aria-label": "\u601D\u8003\u53C2\u6570\u683C\u5F0F", disabled, value: draft.thinkingFormat, onChange: (event) => {
1195
+ api3 === null || api3 === "openai-completions" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "dshmore-capabilities-field", children: [
1196
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u63A5\u53E3\u63A5\u53D7\u7684\u683C\u5F0F" }),
1197
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("select", { "aria-label": "\u601D\u8003\u53C2\u6570\u683C\u5F0F", disabled, value: draft.thinkingFormat, onChange: (event) => {
1106
1198
  const thinkingFormat = event.currentTarget.value;
1107
1199
  setDraft((current) => ({ ...current, thinkingFormat }));
1108
1200
  }, children: [
1109
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "default", children: "\u6CBF\u7528\u9ED8\u8BA4\uFF08\u63D0\u4F9B\u65B9 / \u81EA\u52A8\u8BC6\u522B\uFF09" }),
1110
- THINKING_FORMATS.map((format) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: format, children: format }, format))
1201
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "default", children: "\u6CBF\u7528\u9ED8\u8BA4\uFF08\u63D0\u4F9B\u65B9 / \u81EA\u52A8\u8BC6\u522B\uFF09" }),
1202
+ THINKING_FORMATS.map((format) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: format, children: format }, format))
1111
1203
  ] }),
1112
- /* @__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" })
1113
- ] }) : /* @__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" })
1204
+ /* @__PURE__ */ (0, import_jsx_runtime6.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" })
1205
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.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" })
1114
1206
  ] }),
1115
- /* @__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" })
1207
+ /* @__PURE__ */ (0, import_jsx_runtime6.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" })
1116
1208
  ] });
1117
1209
  }
1118
1210
  function CapabilitiesEditorModal({ provider, modelId, namespace, onClose, onSaved }) {
1119
- const [snapshot, setSnapshot] = (0, import_react6.useState)(null);
1120
- const [draft, setDraft] = (0, import_react6.useState)(null);
1121
- const [error, setError] = (0, import_react6.useState)(null);
1122
- const [busy, setBusy] = (0, import_react6.useState)(false);
1123
- const [attempt, setAttempt] = (0, import_react6.useState)(0);
1124
- const saving = (0, import_react6.useRef)(false);
1125
- const mounted = (0, import_react6.useRef)(false);
1126
- (0, import_react6.useEffect)(() => {
1211
+ const [snapshot, setSnapshot] = (0, import_react7.useState)(null);
1212
+ const [draft, setDraft] = (0, import_react7.useState)(null);
1213
+ const [error, setError] = (0, import_react7.useState)(null);
1214
+ const [busy, setBusy] = (0, import_react7.useState)(false);
1215
+ const [attempt, setAttempt] = (0, import_react7.useState)(0);
1216
+ const saving = (0, import_react7.useRef)(false);
1217
+ const mounted = (0, import_react7.useRef)(false);
1218
+ (0, import_react7.useEffect)(() => {
1127
1219
  mounted.current = true;
1128
1220
  return () => {
1129
1221
  mounted.current = false;
1130
1222
  };
1131
1223
  }, []);
1132
- (0, import_react6.useEffect)(() => {
1224
+ (0, import_react7.useEffect)(() => {
1133
1225
  let cancelled = false;
1134
1226
  setError(null);
1135
1227
  void readCapabilities().then((next) => {
@@ -1180,7 +1272,7 @@ function CapabilitiesEditorModal({ provider, modelId, namespace, onClose, onSave
1180
1272
  if (mounted.current) setBusy(false);
1181
1273
  }
1182
1274
  };
1183
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1275
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1184
1276
  import_dsh_client_ui_primitives5.Modal,
1185
1277
  {
1186
1278
  open: true,
@@ -1190,9 +1282,9 @@ function CapabilitiesEditorModal({ provider, modelId, namespace, onClose, onSave
1190
1282
  title: `\u6A21\u578B\u80FD\u529B \xB7 ${modelId}`,
1191
1283
  closeLabel: "\u5173\u95ED",
1192
1284
  description: `\u63D0\u4F9B\u65B9 ${provider}`,
1193
- footer: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1194
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: busy, onClick: onClose, children: "\u53D6\u6D88" }),
1195
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1285
+ footer: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1286
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", disabled: busy, onClick: onClose, children: "\u53D6\u6D88" }),
1287
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1196
1288
  import_dsh_client_ui_primitives5.Button,
1197
1289
  {
1198
1290
  variant: "primary",
@@ -1204,10 +1296,10 @@ function CapabilitiesEditorModal({ provider, modelId, namespace, onClose, onSave
1204
1296
  }
1205
1297
  )
1206
1298
  ] }),
1207
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dshmore-capabilities-dialog", children: [
1208
- 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" }),
1209
- 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" }),
1210
- draft !== null && row !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1299
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dshmore-capabilities-dialog", children: [
1300
+ snapshot === null && error === null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "dshmore-capabilities-note", children: "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u914D\u7F6E\u2026" }),
1301
+ snapshot !== null && row === void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.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" }),
1302
+ draft !== null && row !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1211
1303
  CapabilitiesEditorBody,
1212
1304
  {
1213
1305
  draft,
@@ -1218,9 +1310,9 @@ function CapabilitiesEditorModal({ provider, modelId, namespace, onClose, onSave
1218
1310
  api: row.api
1219
1311
  }
1220
1312
  ),
1221
- snapshot !== null && !snapshot.writable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dshmore-capabilities-note", children: "\u5F53\u524D\u914D\u7F6E\u4E3A\u53EA\u8BFB\u3002" }),
1222
- error !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { role: "alert", className: "dshmore-capabilities-error", children: error }),
1223
- snapshot === null && error !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", onClick: () => {
1313
+ snapshot !== null && !snapshot.writable && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "dshmore-capabilities-note", children: "\u5F53\u524D\u914D\u7F6E\u4E3A\u53EA\u8BFB\u3002" }),
1314
+ error !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { role: "alert", className: "dshmore-capabilities-error", children: error }),
1315
+ snapshot === null && error !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_dsh_client_ui_primitives5.Button, { variant: "ghost", onClick: () => {
1224
1316
  setAttempt((value) => value + 1);
1225
1317
  }, children: "\u91CD\u8BD5" })
1226
1318
  ] })
@@ -1277,18 +1369,18 @@ var capabilitiesStyles = `
1277
1369
  `;
1278
1370
 
1279
1371
  // src/patches/model-capabilities/client/index.tsx
1280
- var import_jsx_runtime6 = require("react/jsx-runtime");
1372
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1281
1373
  var BUTTON_ATTR = "data-dshmore-model-capabilities";
1282
1374
  function ModelsPageCapabilitiesPortal({ scope, deepseekScope, activation }) {
1283
- const settings = (0, import_react7.useSyncExternalStore)(activation.subscribe, activation.getSnapshot, activation.getSnapshot);
1375
+ const settings = (0, import_react8.useSyncExternalStore)(activation.subscribe, activation.getSnapshot, activation.getSnapshot);
1284
1376
  const enabled = settings[MODEL_CAPABILITIES_PATCH_ID];
1285
- const scopeSnapshot = (0, import_react7.useSyncExternalStore)(scope.subscribe, scope.getSnapshot, scope.getSnapshot);
1286
- const deepseekSnapshot = (0, import_react7.useSyncExternalStore)(deepseekScope.subscribe, deepseekScope.getSnapshot, deepseekScope.getSnapshot);
1287
- const [editing, setEditing] = (0, import_react7.useState)(null);
1288
- const [data, setData] = (0, import_react7.useState)(null);
1289
- const dataRef = (0, import_react7.useRef)(data);
1377
+ const scopeSnapshot = (0, import_react8.useSyncExternalStore)(scope.subscribe, scope.getSnapshot, scope.getSnapshot);
1378
+ const deepseekSnapshot = (0, import_react8.useSyncExternalStore)(deepseekScope.subscribe, deepseekScope.getSnapshot, deepseekScope.getSnapshot);
1379
+ const [editing, setEditing] = (0, import_react8.useState)(null);
1380
+ const [data, setData] = (0, import_react8.useState)(null);
1381
+ const dataRef = (0, import_react8.useRef)(data);
1290
1382
  dataRef.current = data;
1291
- (0, import_react7.useEffect)(() => {
1383
+ (0, import_react8.useEffect)(() => {
1292
1384
  let cancelled = false;
1293
1385
  if (!enabled) {
1294
1386
  setEditing(null);
@@ -1304,7 +1396,7 @@ function ModelsPageCapabilitiesPortal({ scope, deepseekScope, activation }) {
1304
1396
  cancelled = true;
1305
1397
  };
1306
1398
  }, [enabled, scopeSnapshot, deepseekSnapshot]);
1307
- const syncButtons = (0, import_react7.useCallback)(() => {
1399
+ const syncButtons = (0, import_react8.useCallback)(() => {
1308
1400
  if (!enabled) return;
1309
1401
  const active = /* @__PURE__ */ new Set();
1310
1402
  for (const entry of findModelEntries()) {
@@ -1336,7 +1428,7 @@ function ModelsPageCapabilitiesPortal({ scope, deepseekScope, activation }) {
1336
1428
  if (button.parentElement === null || !active.has(button.parentElement)) button.remove();
1337
1429
  });
1338
1430
  }, [enabled]);
1339
- (0, import_react7.useEffect)(() => {
1431
+ (0, import_react8.useEffect)(() => {
1340
1432
  if (!enabled) return;
1341
1433
  let frame = null;
1342
1434
  const schedule = () => {
@@ -1359,13 +1451,13 @@ function ModelsPageCapabilitiesPortal({ scope, deepseekScope, activation }) {
1359
1451
  document.querySelectorAll(`[${BUTTON_ATTR}]`).forEach((element) => element.remove());
1360
1452
  };
1361
1453
  }, [enabled, syncButtons]);
1362
- (0, import_react7.useEffect)(() => {
1454
+ (0, import_react8.useEffect)(() => {
1363
1455
  if (enabled) syncButtons();
1364
1456
  }, [enabled, syncButtons, data]);
1365
1457
  if (!enabled) return null;
1366
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1367
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: capabilitiesStyles }),
1368
- editing !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1458
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1459
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: capabilitiesStyles }),
1460
+ editing !== null && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1369
1461
  CapabilitiesEditorModal,
1370
1462
  {
1371
1463
  ...editing,
@@ -1397,7 +1489,254 @@ var clientPatch3 = {
1397
1489
  name: "shell.overlay",
1398
1490
  id: `${PLUGIN_NAME}-${MODEL_CAPABILITIES_PATCH_ID}`,
1399
1491
  order: 90
1400
- }, () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ModelsPageCapabilitiesPortal, { scope: boundScope, deepseekScope, activation })));
1492
+ }, () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ModelsPageCapabilitiesPortal, { scope: boundScope, deepseekScope, activation })));
1493
+ }
1494
+ };
1495
+
1496
+ // src/patches/fast-mode/client/index.tsx
1497
+ var import_react9 = require("react");
1498
+
1499
+ // src/patches/fast-mode/shared.ts
1500
+ var FAST_MODE_PATCH_ID = "fast-mode";
1501
+
1502
+ // src/patches/fast-mode/client/styles.ts
1503
+ var fastModeStyles = `
1504
+ .dshmore-fast-btn {
1505
+ box-sizing: border-box;
1506
+ display: inline-flex;
1507
+ align-items: center;
1508
+ justify-content: center;
1509
+ gap: 5px;
1510
+ height: 28px;
1511
+ padding: 0 10px;
1512
+ font-family: var(--dsw-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);
1513
+ font-size: 12px;
1514
+ font-weight: 500;
1515
+ line-height: 1;
1516
+ border-radius: 14px;
1517
+ border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.3));
1518
+ background: var(--dsw-alias-interactive-bg-idle, rgba(128, 128, 128, 0.08));
1519
+ color: var(--dsw-alias-label-primary, inherit);
1520
+ cursor: pointer;
1521
+ transition: all 0.15s ease-in-out;
1522
+ user-select: none;
1523
+ white-space: nowrap;
1524
+ outline: none;
1525
+ margin-right: 6px;
1526
+ flex: none;
1527
+ }
1528
+
1529
+ .dshmore-fast-btn:hover:not(:disabled) {
1530
+ background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.18));
1531
+ border-color: var(--dsw-alias-border-l1, rgba(128, 128, 128, 0.5));
1532
+ }
1533
+
1534
+ .dshmore-fast-btn--active {
1535
+ background: rgba(245, 158, 11, 0.16) !important;
1536
+ color: #f59e0b !important;
1537
+ border-color: #f59e0b !important;
1538
+ box-shadow: 0 0 8px rgba(245, 158, 11, 0.3) !important;
1539
+ font-weight: 600;
1540
+ }
1541
+
1542
+ .dshmore-fast-btn:disabled,
1543
+ .dshmore-fast-btn--busy {
1544
+ opacity: 0.6;
1545
+ cursor: wait;
1546
+ }
1547
+
1548
+ .dshmore-fast-btn-icon {
1549
+ display: inline-flex;
1550
+ align-items: center;
1551
+ justify-content: center;
1552
+ flex: none;
1553
+ line-height: 1;
1554
+ }
1555
+
1556
+ .dshmore-fast-btn-label {
1557
+ display: inline-block;
1558
+ line-height: 1;
1559
+ }
1560
+ `;
1561
+
1562
+ // src/patches/fast-mode/client/index.tsx
1563
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1564
+ var IDLE_FAST_STATE = { active: false, busy: false };
1565
+ var FastModeClientStore = class {
1566
+ states = /* @__PURE__ */ new Map();
1567
+ listeners = /* @__PURE__ */ new Set();
1568
+ getState(sessionId) {
1569
+ const key = sessionId || "default";
1570
+ return this.states.get(key) ?? IDLE_FAST_STATE;
1571
+ }
1572
+ setState(sessionId, next) {
1573
+ const key = sessionId || "default";
1574
+ const prev = this.getState(key);
1575
+ this.states.set(key, { ...prev, ...next });
1576
+ this.notify();
1577
+ }
1578
+ subscribe = (listener) => {
1579
+ this.listeners.add(listener);
1580
+ return () => {
1581
+ this.listeners.delete(listener);
1582
+ };
1583
+ };
1584
+ notify() {
1585
+ for (const l of this.listeners) l();
1586
+ }
1587
+ };
1588
+ var fastModeClientStore = new FastModeClientStore();
1589
+ async function syncSessionFastState(sessionId) {
1590
+ if (!sessionId) return false;
1591
+ try {
1592
+ const res = await callPatchApi(FAST_MODE_PATCH_ID, "getState", { sessionId });
1593
+ fastModeClientStore.setState(sessionId, { active: res.enabled, busy: false });
1594
+ return res.enabled;
1595
+ } catch {
1596
+ return false;
1597
+ }
1598
+ }
1599
+ async function toggleFastMode(ctx, sessionId) {
1600
+ const currentId = sessionId || currentSessionId(ctx.sessions?.list?.getSnapshot());
1601
+ if (!currentId) return;
1602
+ const current = fastModeClientStore.getState(currentId);
1603
+ if (current.busy) return;
1604
+ fastModeClientStore.setState(currentId, { active: !current.active, busy: true });
1605
+ try {
1606
+ const res = await callPatchApi(FAST_MODE_PATCH_ID, "toggle", { sessionId: currentId });
1607
+ fastModeClientStore.setState(currentId, { active: res.enabled, busy: false });
1608
+ } catch (err) {
1609
+ console.error("Failed to toggle fast mode:", err);
1610
+ fastModeClientStore.setState(currentId, { active: current.active, busy: false });
1611
+ }
1612
+ }
1613
+ function FastModeButton({
1614
+ sessionId,
1615
+ activation,
1616
+ ctx
1617
+ }) {
1618
+ const settings = (0, import_react9.useSyncExternalStore)(activation.subscribe, activation.getSnapshot);
1619
+ const enabled = settings[FAST_MODE_PATCH_ID];
1620
+ const state = (0, import_react9.useSyncExternalStore)(
1621
+ fastModeClientStore.subscribe,
1622
+ () => fastModeClientStore.getState(sessionId)
1623
+ );
1624
+ (0, import_react9.useEffect)(() => {
1625
+ if (sessionId) {
1626
+ void syncSessionFastState(sessionId);
1627
+ }
1628
+ }, [sessionId]);
1629
+ if (!enabled) return null;
1630
+ const tooltip = state.active ? "\u52A0\u901F\u5DF2\u5F00\u542F\n\u54CD\u5E94\u66F4\u5FEB\uFF0C\u4E5F\u4F1A\u66F4\u5FEB\u6D88\u8017\u989D\u5EA6\n\u70B9\u51FB\u5173\u95ED\uFF0C\u6062\u590D\u6807\u51C6\u901F\u5EA6" : "\u52A0\u901F\n\u5F00\u542F\u540E\u54CD\u5E94\u66F4\u5FEB\uFF0C\u4F46\u4F1A\u66F4\u5FEB\u6D88\u8017\u989D\u5EA6\n\u70B9\u51FB\u5F00\u542F";
1631
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1632
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: fastModeStyles }),
1633
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1634
+ "button",
1635
+ {
1636
+ type: "button",
1637
+ className: `dshmore-fast-btn ${state.active ? "dshmore-fast-btn--active" : ""} ${state.busy ? "dshmore-fast-btn--busy" : ""}`,
1638
+ disabled: state.busy,
1639
+ title: tooltip,
1640
+ "aria-label": tooltip,
1641
+ onClick: (e) => {
1642
+ e.preventDefault();
1643
+ e.stopPropagation();
1644
+ void toggleFastMode(ctx, sessionId);
1645
+ },
1646
+ children: [
1647
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dshmore-fast-btn-icon", children: "\u26A1" }),
1648
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dshmore-fast-btn-label", children: state.busy ? "\u5207\u6362\u4E2D\u2026" : state.active ? "\u52A0\u901F (\u5F00)" : "\u52A0\u901F" })
1649
+ ]
1650
+ }
1651
+ )
1652
+ ] });
1653
+ }
1654
+ function FastModeInputContribution(props) {
1655
+ const currentList = props.useSessions ? props.useSessions((s) => s) : void 0;
1656
+ const derivedId = props.sessionId || (currentList ? currentSessionId(currentList) : void 0) || currentSessionId(props.ctx.sessions?.list?.getSnapshot());
1657
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1658
+ FastModeButton,
1659
+ {
1660
+ sessionId: derivedId ? String(derivedId) : void 0,
1661
+ activation: props.activation,
1662
+ ctx: props.ctx
1663
+ }
1664
+ );
1665
+ }
1666
+ function FastModeHeaderContribution(props) {
1667
+ const currentList = props.useSessions ? props.useSessions((s) => s) : void 0;
1668
+ const derivedId = props.sessionId || (currentList ? currentSessionId(currentList) : void 0) || currentSessionId(props.ctx.sessions?.list?.getSnapshot());
1669
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1670
+ FastModeButton,
1671
+ {
1672
+ sessionId: derivedId ? String(derivedId) : void 0,
1673
+ activation: props.activation,
1674
+ ctx: props.ctx
1675
+ }
1676
+ );
1677
+ }
1678
+ var clientPatch4 = {
1679
+ id: FAST_MODE_PATCH_ID,
1680
+ install: (ctx, activation) => {
1681
+ ctx.slots.inject(
1682
+ "conversation.input.right",
1683
+ () => ctx.slots.register(
1684
+ {
1685
+ name: "conversation.input.right",
1686
+ id: `${PLUGIN_NAME}-${FAST_MODE_PATCH_ID}`,
1687
+ order: 10,
1688
+ priority: 10,
1689
+ inject: (sessionId) => ({
1690
+ sessionId: sessionId ? String(sessionId) : void 0
1691
+ })
1692
+ },
1693
+ (props) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FastModeInputContribution, { ...props, ctx, activation })
1694
+ )
1695
+ );
1696
+ ctx.slots.inject(
1697
+ "conversation.session.header.utilities",
1698
+ () => ctx.slots.register(
1699
+ {
1700
+ name: "conversation.session.header.utilities",
1701
+ id: `${PLUGIN_NAME}-${FAST_MODE_PATCH_ID}-header`,
1702
+ order: 85
1703
+ },
1704
+ (props) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FastModeHeaderContribution, { ...props, ctx, activation })
1705
+ )
1706
+ );
1707
+ const registerCommand = (scope) => {
1708
+ const command = scope.commandUi ?? scope.get?.("commandUi");
1709
+ const sessions = scope.sessions ?? scope.get?.("sessions");
1710
+ if (command && typeof command.register === "function") {
1711
+ scope.effect(
1712
+ () => command.register({
1713
+ name: "fast",
1714
+ label: () => "\u52A0\u901F",
1715
+ description: () => "\u5F00\u542F\u6216\u5173\u95ED\u5F53\u524D\u4F1A\u8BDD\u7684\u52A0\u901F\u3002\u54CD\u5E94\u66F4\u5FEB\uFF0C\u4F46\u4F1A\u66F4\u5FEB\u6D88\u8017\u989D\u5EA6",
1716
+ available: (session) => activation.getSnapshot()[FAST_MODE_PATCH_ID] && sessions?.subagentAddress?.(session.sessionId) === void 0,
1717
+ ui: {
1718
+ kind: "action",
1719
+ run: (session) => {
1720
+ if (!activation.getSnapshot()[FAST_MODE_PATCH_ID]) return;
1721
+ void toggleFastMode(ctx, String(session.sessionId));
1722
+ }
1723
+ }
1724
+ }),
1725
+ "fast-mode: /fast command"
1726
+ );
1727
+ }
1728
+ };
1729
+ if (typeof ctx.inject === "function") {
1730
+ try {
1731
+ ctx.inject(["commandUi"], (scope) => {
1732
+ registerCommand(scope);
1733
+ });
1734
+ } catch {
1735
+ registerCommand(ctx);
1736
+ }
1737
+ } else {
1738
+ registerCommand(ctx);
1739
+ }
1401
1740
  }
1402
1741
  };
1403
1742
 
@@ -1405,7 +1744,7 @@ var clientPatch3 = {
1405
1744
  var SESSION_AUTO_TITLE_PATCH_ID = "session-auto-title";
1406
1745
 
1407
1746
  // src/patches/session-auto-title/client/index.ts
1408
- var clientPatch4 = {
1747
+ var clientPatch5 = {
1409
1748
  id: SESSION_AUTO_TITLE_PATCH_ID,
1410
1749
  install: () => {
1411
1750
  }
@@ -1415,13 +1754,14 @@ var clientPatch4 = {
1415
1754
  var PROJECTLESS_TASKS_PATCH_ID = "projectless-tasks";
1416
1755
 
1417
1756
  // src/patches/projectless-tasks/client/adapter.tsx
1418
- var import_react9 = require("react");
1757
+ var import_react11 = require("react");
1419
1758
 
1420
1759
  // src/patches/projectless-tasks/client/create-task.ts
1421
1760
  function createTaskStarter(sessions) {
1422
1761
  let pendingId;
1423
1762
  let flight;
1424
1763
  let disposed = false;
1764
+ let reference;
1425
1765
  return {
1426
1766
  start(beforeOpen) {
1427
1767
  if (disposed) return Promise.reject(new Error("\u72EC\u7ACB\u4EFB\u52A1\u8865\u4E01\u5DF2\u5173\u95ED\u3002"));
@@ -1436,8 +1776,21 @@ function createTaskStarter(sessions) {
1436
1776
  if (disposed) return;
1437
1777
  const id = await sessions.create({ sessionId, cwd: location.cwd });
1438
1778
  if (id !== sessionId) throw new Error("\u521B\u5EFA\u7ED3\u679C\u4E0E\u72EC\u7ACB\u4EFB\u52A1\u6807\u8BC6\u4E0D\u4E00\u81F4\u3002");
1439
- if (!disposed && beforeOpen?.(id) !== false) sessions.open(id);
1440
- pendingId = void 0;
1779
+ if (disposed) return;
1780
+ const retained = sessions.retain?.(id);
1781
+ reference = retained;
1782
+ try {
1783
+ if (retained !== void 0) await retained.ready;
1784
+ if (!disposed && beforeOpen?.(id) !== false) sessions.open(id);
1785
+ pendingId = void 0;
1786
+ } catch (error) {
1787
+ if (!disposed) throw error;
1788
+ } finally {
1789
+ if (reference === retained) {
1790
+ retained?.release();
1791
+ reference = void 0;
1792
+ }
1793
+ }
1441
1794
  })().finally(() => {
1442
1795
  flight = void 0;
1443
1796
  });
@@ -1445,6 +1798,8 @@ function createTaskStarter(sessions) {
1445
1798
  },
1446
1799
  dispose() {
1447
1800
  disposed = true;
1801
+ reference?.release();
1802
+ reference = void 0;
1448
1803
  }
1449
1804
  };
1450
1805
  }
@@ -1481,7 +1836,7 @@ function transferBeforeOpen(ctx, sourceId, targetId) {
1481
1836
  }
1482
1837
  const sessions = value;
1483
1838
  const list = sessions.list.getSnapshot();
1484
- if (list.current !== sourceId) return false;
1839
+ if (currentSessionId(list) !== sourceId) return false;
1485
1840
  if (sourceId === void 0 || sourceId === targetId) return true;
1486
1841
  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");
1487
1842
  const source = sessions.scope(sourceId);
@@ -1497,8 +1852,8 @@ function transferBeforeOpen(ctx, sourceId, targetId) {
1497
1852
  }
1498
1853
 
1499
1854
  // src/patches/projectless-tasks/client/picker.tsx
1500
- var import_react8 = require("react");
1501
- var import_jsx_runtime7 = require("react/jsx-runtime");
1855
+ var import_react10 = require("react");
1856
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1502
1857
  var INDEPENDENT_CHOICE_ID = "::dsh-more-independent-task";
1503
1858
  var INDEPENDENT_CHOICE = {
1504
1859
  workspaceId: INDEPENDENT_CHOICE_ID,
@@ -1508,7 +1863,7 @@ var INDEPENDENT_CHOICE = {
1508
1863
  createdAt: "",
1509
1864
  updatedAt: ""
1510
1865
  };
1511
- var ChoiceContext = (0, import_react8.createContext)(void 0);
1866
+ var ChoiceContext = (0, import_react10.createContext)(void 0);
1512
1867
  function withIndependentChoice(snapshot) {
1513
1868
  return { ...snapshot, items: [INDEPENDENT_CHOICE, ...snapshot.items] };
1514
1869
  }
@@ -1529,7 +1884,7 @@ function labelIndependentChip(anchor) {
1529
1884
  };
1530
1885
  }
1531
1886
  function WorkspaceChoice({ owner, state, error, children }) {
1532
- (0, import_react8.useLayoutEffect)(() => {
1887
+ (0, import_react10.useLayoutEffect)(() => {
1533
1888
  const anchor = owner.anchorRef?.current;
1534
1889
  if (!state.independent || owner.selectedId !== void 0 || anchor === void 0 || anchor === null) return;
1535
1890
  return labelIndependentChip(anchor);
@@ -1538,9 +1893,9 @@ function WorkspaceChoice({ owner, state, error, children }) {
1538
1893
  owner.onClose();
1539
1894
  state.chooseIndependent();
1540
1895
  };
1541
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(ChoiceContext.Provider, { value: state, children: [
1896
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(ChoiceContext.Provider, { value: state, children: [
1542
1897
  children,
1543
- owner.selectedId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1898
+ owner.selectedId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1544
1899
  "button",
1545
1900
  {
1546
1901
  type: "button",
@@ -1552,9 +1907,9 @@ function WorkspaceChoice({ owner, state, error, children }) {
1552
1907
  children: "\xD7"
1553
1908
  }
1554
1909
  ),
1555
- state.busy && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dshmore-workspace-status", role: "status", children: "\u5207\u6362\u4E2D\u2026" }),
1556
- error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dshmore-workspace-error", role: "alert", children: error }),
1557
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
1910
+ state.busy && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dshmore-workspace-status", role: "status", children: "\u5207\u6362\u4E2D\u2026" }),
1911
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dshmore-workspace-error", role: "alert", children: error }),
1912
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: `
1558
1913
  .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; }
1559
1914
  .dshmore-workspace-clear:hover { color:var(--dsw-alias-label-primary); background:var(--dsw-alias-interactive-bg-hover); }
1560
1915
  .dshmore-workspace-clear:disabled { opacity:.45; cursor:wait; }
@@ -1565,11 +1920,11 @@ function WorkspaceChoice({ owner, state, error, children }) {
1565
1920
  }
1566
1921
  function extendWorkspacePicker(original) {
1567
1922
  return function ProjectlessPicker(props) {
1568
- const choice = (0, import_react8.useContext)(ChoiceContext);
1923
+ const choice = (0, import_react10.useContext)(ChoiceContext);
1569
1924
  const snapshot = props.useWorkspaces((value) => value);
1570
- const display = (0, import_react8.useMemo)(() => choice === void 0 ? snapshot : withIndependentChoice(snapshot), [snapshot, choice === void 0]);
1925
+ const display = (0, import_react10.useMemo)(() => choice === void 0 ? snapshot : withIndependentChoice(snapshot), [snapshot, choice === void 0]);
1571
1926
  const useWorkspaces = (select) => select(display);
1572
- return (0, import_react8.createElement)(original, {
1927
+ return (0, import_react10.createElement)(original, {
1573
1928
  ...props,
1574
1929
  useWorkspaces,
1575
1930
  open: props.open && !choice?.busy,
@@ -1608,20 +1963,13 @@ function installPickerAdapter(ctx) {
1608
1963
  }
1609
1964
 
1610
1965
  // src/patches/projectless-tasks/client/adapter.tsx
1611
- var import_jsx_runtime8 = require("react/jsx-runtime");
1966
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1612
1967
  function isComposerOwner(owner) {
1613
1968
  return "variant" in owner && (owner.variant === "hero" || owner.variant === "composer");
1614
1969
  }
1615
1970
  function isWorkspaceOwner(owner) {
1616
1971
  return "open" in owner && typeof owner.open === "boolean" && "onPick" in owner && typeof owner.onPick === "function" && "onClose" in owner && typeof owner.onClose === "function";
1617
1972
  }
1618
- function clientSessionActions(ctx) {
1619
- const sessions = ctx.sessions;
1620
- if (typeof sessions !== "object" || sessions === null || !("create" in sessions) || !("open" in sessions) || typeof sessions.create !== "function" || typeof sessions.open !== "function") {
1621
- throw new Error("\u5F53\u524D DSH \u7248\u672C\u4E0D\u652F\u6301\u72EC\u7ACB\u4EFB\u52A1\uFF0C\u8BF7\u68C0\u67E5\u4F1A\u8BDD\u63A5\u53E3\u3002");
1622
- }
1623
- return sessions;
1624
- }
1625
1973
  function unlockComposer(owner, independent, block) {
1626
1974
  if (!independent || owner.disabled !== true || owner.onRequestWorkspace === void 0) return owner;
1627
1975
  const { disabled: _disabled, onRequestWorkspace: _request, workspacePickerOpen: _picker, placeholder: _placeholder, ...rest } = owner;
@@ -1644,54 +1992,11 @@ function installConversationAdapter(ctx, activation, name = "main.conversation")
1644
1992
  };
1645
1993
  const sync = () => {
1646
1994
  for (const entry of ctx.slots.entries(slot)) {
1647
- let ProjectlessConversation2 = function(props) {
1648
- const active = (0, import_react9.useSyncExternalStore)(subscribeLifetime, () => live);
1649
- const settings = (0, import_react9.useSyncExternalStore)(activation.subscribe, activation.getSnapshot);
1650
- const workspace = props.useWorkspaces((snapshot) => snapshot);
1651
- const cwd = props.useSessions((snapshot) => props.sessionId === void 0 ? void 0 : snapshot.byId[props.sessionId]?.cwd);
1652
- const session = props.useSession((snapshot) => snapshot);
1653
- const block = props.useComposerBlock((value) => value);
1654
- const enabled = active && settings[PROJECTLESS_TASKS_PATCH_ID];
1655
- const starter = (0, import_react9.useRef)();
1656
- const [busy, setBusy] = (0, import_react9.useState)(false);
1657
- const [error, setError] = (0, import_react9.useState)();
1658
- (0, import_react9.useEffect)(() => {
1659
- if (!enabled) return;
1660
- setBusy(false);
1661
- setError(void 0);
1662
- return () => {
1663
- starter.current?.dispose();
1664
- starter.current = void 0;
1665
- };
1666
- }, [enabled]);
1667
- 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));
1668
- const chooseIndependent = () => {
1669
- if (!enabled || busy || independent) return;
1670
- const operation = starter.current ??= createTaskStarter(clientSessionActions(ctx));
1671
- setBusy(true);
1672
- setError(void 0);
1673
- void operation.start((id) => transferBeforeOpen(ctx, props.sessionId, id)).catch((reason) => {
1674
- if (starter.current === operation) setError(apiErrorText(reason));
1675
- }).finally(() => {
1676
- if (starter.current === operation) setBusy(false);
1677
- });
1678
- };
1679
- const renderSlot = (name2, owner, options) => {
1680
- if (name2 === "conversation.composer.bar" && isComposerOwner(owner)) {
1681
- return props.renderSlot("conversation.composer.bar", unlockComposer(owner, independent, block), options);
1682
- }
1683
- if (enabled && name2 === "conversation.hero.workspace" && isWorkspaceOwner(owner)) {
1684
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(WorkspaceChoice, { owner, state: { independent, busy, chooseIndependent }, error, children: props.renderSlot("conversation.hero.workspace", owner, options) });
1685
- }
1686
- return props.renderSlot(name2, owner, options);
1687
- };
1688
- return (0, import_react9.createElement)(original, { ...props, renderSlot });
1689
- };
1690
- var ProjectlessConversation = ProjectlessConversation2;
1691
1995
  if (wrapped.has(entry) || entry.children?.["conversation.composer.bar"] === void 0 || typeof entry.component !== "function") continue;
1692
1996
  const original = entry.component;
1693
- wrapped.set(entry, { original, component: ProjectlessConversation2 });
1694
- entry.component = ProjectlessConversation2;
1997
+ const ProjectlessConversation = wrapConversation(ctx, activation, original, subscribeLifetime, () => live);
1998
+ wrapped.set(entry, { original, component: ProjectlessConversation });
1999
+ entry.component = ProjectlessConversation;
1695
2000
  }
1696
2001
  };
1697
2002
  const unsubscribe = ctx.slots.subscribe(slot, sync);
@@ -1709,14 +2014,95 @@ function installConversationAdapter(ctx, activation, name = "main.conversation")
1709
2014
  fallback();
1710
2015
  };
1711
2016
  }
2017
+ function wrapConversation(ctx, activation, original, subscribeLifetime, isLive) {
2018
+ return function ProjectlessConversation(props) {
2019
+ const active = (0, import_react11.useSyncExternalStore)(subscribeLifetime, isLive);
2020
+ const settings = (0, import_react11.useSyncExternalStore)(activation.subscribe, activation.getSnapshot);
2021
+ const workspace = props.useWorkspaces((snapshot) => snapshot);
2022
+ const cwd = props.useSessions((snapshot) => props.sessionId === void 0 ? void 0 : snapshot.byId[props.sessionId]?.cwd);
2023
+ const session = props.useSession((snapshot) => snapshot);
2024
+ const block = props.useComposerBlock((value) => value);
2025
+ const enabled = active && settings[PROJECTLESS_TASKS_PATCH_ID];
2026
+ const starter = (0, import_react11.useRef)();
2027
+ const [busy, setBusy] = (0, import_react11.useState)(false);
2028
+ const [error, setError] = (0, import_react11.useState)();
2029
+ (0, import_react11.useEffect)(() => {
2030
+ if (!enabled) return;
2031
+ setBusy(false);
2032
+ setError(void 0);
2033
+ return () => {
2034
+ starter.current?.dispose();
2035
+ starter.current = void 0;
2036
+ };
2037
+ }, [enabled]);
2038
+ 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));
2039
+ const chooseIndependent = () => {
2040
+ if (!enabled || busy || independent) return;
2041
+ const operation = starter.current ??= createTaskStarter(clientSessionActions(ctx));
2042
+ setBusy(true);
2043
+ setError(void 0);
2044
+ void operation.start((id) => transferBeforeOpen(ctx, props.sessionId, id)).catch((reason) => {
2045
+ if (starter.current === operation) setError(apiErrorText(reason));
2046
+ }).finally(() => {
2047
+ if (starter.current === operation) setBusy(false);
2048
+ });
2049
+ };
2050
+ const renderSlot = (name, owner, options) => {
2051
+ if (name === "conversation.composer.bar" && isComposerOwner(owner)) {
2052
+ return props.renderSlot("conversation.composer.bar", unlockComposer(owner, independent, block), options);
2053
+ }
2054
+ if (enabled && name === "conversation.hero.workspace" && isWorkspaceOwner(owner)) {
2055
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(WorkspaceChoice, { owner, state: { independent, busy, chooseIndependent }, error, children: props.renderSlot("conversation.hero.workspace", owner, options) });
2056
+ }
2057
+ return props.renderSlot(name, owner, options);
2058
+ };
2059
+ return (0, import_react11.createElement)(original, { ...props, renderSlot });
2060
+ };
2061
+ }
2062
+ function installConversationFactoryAdapter(ctx, activation) {
2063
+ const slots = ctx.slots;
2064
+ const candidate = typeof slots.hostFace === "function" ? slots.hostFace() : void 0;
2065
+ if (typeof candidate !== "object" || candidate === null || !("factoryOf" in candidate) || typeof candidate.factoryOf !== "function" || !("subscribeFactory" in candidate) || typeof candidate.subscribeFactory !== "function") return () => {
2066
+ };
2067
+ const registry = candidate;
2068
+ const wrapped = /* @__PURE__ */ new Map();
2069
+ let live = true;
2070
+ const listeners = /* @__PURE__ */ new Set();
2071
+ const subscribeLifetime = (listener) => {
2072
+ listeners.add(listener);
2073
+ return () => {
2074
+ listeners.delete(listener);
2075
+ };
2076
+ };
2077
+ const sync = () => {
2078
+ const definition = registry.factoryOf("conversation.content");
2079
+ if (definition === void 0 || wrapped.has(definition) || definition.children?.["conversation.composer.bar"] === void 0 || typeof definition.component !== "function") return;
2080
+ const original = definition.component;
2081
+ const component = wrapConversation(ctx, activation, original, subscribeLifetime, () => live);
2082
+ wrapped.set(definition, { original, component });
2083
+ definition.component = component;
2084
+ };
2085
+ const unsubscribe = registry.subscribeFactory("conversation.content", sync);
2086
+ sync();
2087
+ return () => {
2088
+ live = false;
2089
+ listeners.forEach((listener) => listener());
2090
+ unsubscribe();
2091
+ for (const [definition, patch] of wrapped) {
2092
+ if (definition.component === patch.component) definition.component = patch.original;
2093
+ }
2094
+ wrapped.clear();
2095
+ };
2096
+ }
1712
2097
 
1713
2098
  // src/patches/projectless-tasks/client/new-session.ts
1714
2099
  function newSessionTarget(list, workspaces, explicit) {
1715
2100
  if (explicit !== void 0) return { kind: "workspace", workspaceId: explicit };
1716
- if (list.current === void 0) return { kind: "native" };
2101
+ const current = currentSessionId(list);
2102
+ if (current === void 0) return { kind: "native" };
1717
2103
  if (list.phase !== "ready" || workspaces.phase !== "ready") return { kind: "pending" };
1718
2104
  const visited = /* @__PURE__ */ new Set();
1719
- let id = list.current;
2105
+ let id = current;
1720
2106
  while (id !== void 0 && !visited.has(id)) {
1721
2107
  visited.add(id);
1722
2108
  const workspace = workspaces.items.find((item) => item.sessionIds.includes(id));
@@ -1727,7 +2113,7 @@ function newSessionTarget(list, workspaces, explicit) {
1727
2113
  id = summary.parentId;
1728
2114
  continue;
1729
2115
  }
1730
- return typeof summary.cwd === "string" && summary.cwd.length > 0 ? { kind: "independent", sourceId: list.current } : { kind: "pending" };
2116
+ return typeof summary.cwd === "string" && summary.cwd.length > 0 ? { kind: "independent", sourceId: current } : { kind: "pending" };
1731
2117
  }
1732
2118
  return { kind: "pending" };
1733
2119
  }
@@ -1760,7 +2146,8 @@ function bindNewSessionNavigation({ navigation, sessions, workspaces, activation
1760
2146
  }
1761
2147
  if (target.kind === "pending") {
1762
2148
  cancel();
1763
- 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"));
2149
+ const current2 = currentSessionId(list);
2150
+ if (current2 !== void 0) reportError(current2, new Error("\u4F1A\u8BDD\u6765\u6E90\u4ECD\u5728\u52A0\u8F7D\uFF0C\u8BF7\u7A0D\u540E\u518D\u65B0\u5EFA\u4F1A\u8BDD\u3002"));
1764
2151
  return;
1765
2152
  }
1766
2153
  if (attempt?.sourceId !== target.sourceId) {
@@ -1774,7 +2161,7 @@ function bindNewSessionNavigation({ navigation, sessions, workspaces, activation
1774
2161
  const destination = newSessionTarget(sessions.list.getSnapshot(), workspaces.list.getSnapshot());
1775
2162
  return destination.kind === "independent" && destination.sourceId === current.sourceId;
1776
2163
  }).catch((error) => {
1777
- if (active && attempt === current && sessions.list.getSnapshot().current === current.sourceId) {
2164
+ if (active && attempt === current && currentSessionId(sessions.list.getSnapshot()) === current.sourceId) {
1778
2165
  reportError(current.sourceId, error);
1779
2166
  }
1780
2167
  }).finally(() => {
@@ -1806,17 +2193,17 @@ function bindNewSessionNavigation({ navigation, sessions, workspaces, activation
1806
2193
  function installNewSessionNavigation(ctx, activation) {
1807
2194
  const navigation = ctx.get("uiWorkspace");
1808
2195
  const sessions = ctx.sessions;
1809
- 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") {
2196
+ 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" || !("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") {
1810
2197
  throw new Error("\u5F53\u524D DSH \u7248\u672C\u4E0D\u652F\u6301\u8DDF\u968F\u4F1A\u8BDD\u6765\u6E90\u65B0\u5EFA\u4EFB\u52A1\u3002");
1811
2198
  }
1812
- const clientSessions = sessions;
2199
+ const clientSessions2 = sessions;
1813
2200
  return bindNewSessionNavigation({
1814
2201
  navigation,
1815
- sessions: clientSessions,
2202
+ sessions: { ...clientSessionActions(ctx), list: clientSessions2.list },
1816
2203
  workspaces: ctx.workspaces,
1817
2204
  activation,
1818
2205
  reportError: (sourceId, error) => {
1819
- const scope = clientSessions.scope(sourceId);
2206
+ const scope = clientSessions2.scope(sourceId);
1820
2207
  const message = `\u65B0\u5EFA\u4F1A\u8BDD\u5931\u8D25\uFF1A${apiErrorText(error)}`;
1821
2208
  if (scope !== void 0) ctx.conversation.input.for(scope).notify("error", message);
1822
2209
  else ctx.logger.warn(message);
@@ -1825,7 +2212,7 @@ function installNewSessionNavigation(ctx, activation) {
1825
2212
  }
1826
2213
 
1827
2214
  // src/patches/projectless-tasks/client/groups.tsx
1828
- var import_react10 = require("react");
2215
+ var import_react12 = require("react");
1829
2216
  var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
1830
2217
 
1831
2218
  // src/patches/projectless-tasks/groups.ts
@@ -1890,7 +2277,7 @@ function installMoveMenu(onMove) {
1890
2277
  }
1891
2278
 
1892
2279
  // src/patches/projectless-tasks/client/groups.tsx
1893
- var import_jsx_runtime9 = require("react/jsx-runtime");
2280
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1894
2281
  function projectSessionGroups(workspaces, sessions, groups) {
1895
2282
  const owned = new Set(workspaces.items.flatMap((item) => item.sessionIds));
1896
2283
  const items = workspaces.items.map((workspace) => {
@@ -1902,35 +2289,49 @@ function projectSessionGroups(workspaces, sessions, groups) {
1902
2289
  var SIDEBAR_SLOT = "sidebar.workspaces";
1903
2290
  var ALWAYS_LIVE = { subscribe: () => () => {
1904
2291
  }, getSnapshot: () => true };
1905
- function extendGroupedSidebar(original, activation, source, lifetime = ALWAYS_LIVE) {
2292
+ function extendGroupedSidebar(original, activation, source, lifetime = ALWAYS_LIVE, ctx) {
1906
2293
  return function GroupedSidebar(props) {
1907
- const settings = (0, import_react10.useSyncExternalStore)(activation.subscribe, activation.getSnapshot);
1908
- const binding = (0, import_react10.useMemo)(() => ({ subscribe: (listener) => source.subscribe(listener), getSnapshot: () => source.getSnapshot() }), []);
1909
- const saved = (0, import_react10.useSyncExternalStore)(binding.subscribe, binding.getSnapshot);
2294
+ const settings = (0, import_react12.useSyncExternalStore)(activation.subscribe, activation.getSnapshot);
2295
+ const binding = (0, import_react12.useMemo)(() => ({ subscribe: (listener) => source.subscribe(listener), getSnapshot: () => source.getSnapshot() }), []);
2296
+ const saved = (0, import_react12.useSyncExternalStore)(binding.subscribe, binding.getSnapshot);
1910
2297
  const native = props.useWorkspaces((value) => value);
1911
2298
  const sessions = props.useSessions((value) => value);
1912
- const active = (0, import_react10.useSyncExternalStore)(lifetime.subscribe, lifetime.getSnapshot);
2299
+ const active = (0, import_react12.useSyncExternalStore)(lifetime.subscribe, lifetime.getSnapshot);
1913
2300
  const enabled = active && settings[PROJECTLESS_TASKS_PATCH_ID];
1914
2301
  const groups = saved.value ?? EMPTY_GROUPS;
1915
- const display = (0, import_react10.useMemo)(() => enabled ? projectSessionGroups(native, sessions, groups) : native, [enabled, native, sessions, groups]);
1916
- const [pending, setPending] = (0, import_react10.useState)();
1917
- const [destination, setDestination] = (0, import_react10.useState)("");
1918
- const [busy, setBusy] = (0, import_react10.useState)(false);
1919
- const [error, setError] = (0, import_react10.useState)();
1920
- const intent = (0, import_react10.useRef)(false);
1921
- const inFlight = (0, import_react10.useRef)(false);
1922
- const live = (0, import_react10.useRef)(true);
1923
- (0, import_react10.useEffect)(() => {
2302
+ const display = (0, import_react12.useMemo)(() => enabled ? projectSessionGroups(native, sessions, groups) : native, [enabled, native, sessions, groups]);
2303
+ const [pending, setPending] = (0, import_react12.useState)();
2304
+ const [destination, setDestination] = (0, import_react12.useState)("");
2305
+ const [busy, setBusy] = (0, import_react12.useState)(false);
2306
+ const [error, setError] = (0, import_react12.useState)();
2307
+ const groupsRef = (0, import_react12.useRef)(groups);
2308
+ groupsRef.current = groups;
2309
+ const requestMove = (id) => {
2310
+ setPending(id);
2311
+ setDestination(groupsRef.current.assignments[id] ?? "");
2312
+ setError(void 0);
2313
+ };
2314
+ const intent = (0, import_react12.useRef)(false);
2315
+ const inFlight = (0, import_react12.useRef)(false);
2316
+ const live = (0, import_react12.useRef)(true);
2317
+ (0, import_react12.useEffect)(() => {
1924
2318
  live.current = true;
1925
2319
  return () => {
1926
2320
  live.current = false;
1927
2321
  };
1928
2322
  }, []);
1929
- (0, import_react10.useEffect)(() => {
2323
+ (0, import_react12.useEffect)(() => {
1930
2324
  if (!enabled) {
1931
2325
  setPending(void 0);
1932
2326
  return;
1933
2327
  }
2328
+ const removeNativeItem = ctx === void 0 ? void 0 : installSessionMenuAction(ctx, {
2329
+ id: "dsh-more-session-move",
2330
+ label: "\u79FB\u52A8\u5230\u5DE5\u4F5C\u533A\u2026",
2331
+ order: 350,
2332
+ select: requestMove
2333
+ });
2334
+ if (removeNativeItem !== void 0) return removeNativeItem;
1934
2335
  return installMoveMenu((archive) => {
1935
2336
  intent.current = true;
1936
2337
  try {
@@ -1943,9 +2344,7 @@ function extendGroupedSidebar(original, activation, source, lifetime = ALWAYS_LI
1943
2344
  const archiveSession = (id) => {
1944
2345
  if (!intent.current) return props.archiveSession(id);
1945
2346
  intent.current = false;
1946
- setPending(id);
1947
- setDestination(groups.assignments[id] ?? "");
1948
- setError(void 0);
2347
+ requestMove(id);
1949
2348
  return Promise.resolve();
1950
2349
  };
1951
2350
  const useWorkspaces = (select) => select(display);
@@ -1971,9 +2370,9 @@ function extendGroupedSidebar(original, activation, source, lifetime = ALWAYS_LI
1971
2370
  const subagent = pending !== void 0 && sessions.byId[pending]?.origin === "subagent";
1972
2371
  const selectedMissing = destination !== "" && !native.items.some((item) => item.workspaceId === destination);
1973
2372
  const unavailable = groupedNatively ? "\u8FD9\u6761\u4F1A\u8BDD\u5DF2\u6709\u539F\u751F\u5DE5\u4F5C\u533A\uFF0C\u53EA\u652F\u6301\u79FB\u52A8\u672A\u5206\u7EC4\u6216\u624B\u52A8\u5F52\u7EC4\u7684\u4F1A\u8BDD\u3002" : subagent ? "\u5B50\u4F1A\u8BDD\u8DDF\u968F\u4E3B\u4F1A\u8BDD\u5F52\u7EC4\uFF0C\u8BF7\u79FB\u52A8\u4E3B\u4F1A\u8BDD\u3002" : saved.status !== "ready" ? "\u5F52\u7EC4\u8BBE\u7F6E\u5C1A\u672A\u5C31\u7EEA\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u91CD\u542F DSH \u540E\u53F0\u5E76\u5237\u65B0\u9875\u9762\u3002" : !saved.writable ? "\u5F53\u524D\u914D\u7F6E\u4E3A\u53EA\u8BFB\uFF0C\u65E0\u6CD5\u79FB\u52A8\u4F1A\u8BDD\u3002" : selectedMissing ? "\u76EE\u6807\u5DE5\u4F5C\u533A\u5DF2\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u3002" : void 0;
1974
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1975
- (0, import_react10.createElement)(original, { ...props, useWorkspaces, archiveSession }),
1976
- enabled && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2373
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2374
+ (0, import_react12.createElement)(original, { ...props, useWorkspaces, archiveSession }),
2375
+ enabled && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1977
2376
  import_dsh_client_ui_primitives6.Modal,
1978
2377
  {
1979
2378
  open: pending !== void 0,
@@ -1981,15 +2380,15 @@ function extendGroupedSidebar(original, activation, source, lifetime = ALWAYS_LI
1981
2380
  title: "\u79FB\u52A8\u5230\u5DE5\u4F5C\u533A",
1982
2381
  closeLabel: "\u5173\u95ED",
1983
2382
  description: "\u4FDD\u7559\u4F1A\u8BDD\u5386\u53F2\u548C\u539F\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u4EC5\u8C03\u6574\u5217\u8868\u5F52\u5C5E\u3002",
1984
- footer: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1985
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_dsh_client_ui_primitives6.Button, { variant: "ghost", disabled: busy, onClick: close, children: "\u53D6\u6D88" }),
1986
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_dsh_client_ui_primitives6.Button, { variant: "primary", disabled: busy || unavailable !== void 0 || pending === void 0 || (groups.assignments[pending] ?? "") === destination, onClick: () => void move(), children: busy ? "\u6B63\u5728\u79FB\u52A8\u2026" : "\u79FB\u52A8" })
2383
+ footer: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2384
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_dsh_client_ui_primitives6.Button, { variant: "ghost", disabled: busy, onClick: close, children: "\u53D6\u6D88" }),
2385
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_dsh_client_ui_primitives6.Button, { variant: "primary", disabled: busy || unavailable !== void 0 || pending === void 0 || (groups.assignments[pending] ?? "") === destination, onClick: () => void move(), children: busy ? "\u6B63\u5728\u79FB\u52A8\u2026" : "\u79FB\u52A8" })
1987
2386
  ] }),
1988
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "grid", gap: 12 }, children: [
1989
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { children: pending === void 0 ? "" : sessions.byId[pending]?.displayTitle ?? pending }),
1990
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { style: { display: "grid", gap: 8 }, children: [
2387
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "grid", gap: 12 }, children: [
2388
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: pending === void 0 ? "" : sessions.byId[pending]?.displayTitle ?? pending }),
2389
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "grid", gap: 8 }, children: [
1991
2390
  "\u76EE\u6807\u5DE5\u4F5C\u533A",
1992
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2391
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1993
2392
  "select",
1994
2393
  {
1995
2394
  "aria-label": "\u76EE\u6807\u5DE5\u4F5C\u533A",
@@ -1998,13 +2397,13 @@ function extendGroupedSidebar(original, activation, source, lifetime = ALWAYS_LI
1998
2397
  onChange: (event) => setDestination(event.target.value),
1999
2398
  style: { width: "100%", minHeight: 40, borderRadius: 10, padding: "8px 12px", color: "var(--dsw-alias-label-primary)", background: "var(--dsw-alias-button-elevated-fill)", border: "1px solid var(--dsw-alias-border-l4)" },
2000
2399
  children: [
2001
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "", children: "\u672A\u5206\u7EC4" }),
2002
- native.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: item.workspaceId, children: item.title || item.path }, item.workspaceId))
2400
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "", children: "\u672A\u5206\u7EC4" }),
2401
+ native.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: item.workspaceId, children: item.title || item.path }, item.workspaceId))
2003
2402
  ]
2004
2403
  }
2005
2404
  )
2006
2405
  ] }),
2007
- (error ?? unavailable) !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { role: "alert", style: { color: "var(--dsw-alias-state-error-primary)" }, children: error ?? unavailable })
2406
+ (error ?? unavailable) !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { role: "alert", style: { color: "var(--dsw-alias-state-error-primary)" }, children: error ?? unavailable })
2008
2407
  ] })
2009
2408
  }
2010
2409
  )
@@ -2027,7 +2426,7 @@ function installSessionGrouping(ctx, activation) {
2027
2426
  for (const entry of ctx.slots.entries(SIDEBAR_SLOT)) {
2028
2427
  if (wrapped.has(entry) || entry.children?.["sidebar.workspaces.directoryFlow"] === void 0 || typeof entry.component !== "function") continue;
2029
2428
  const original = entry.component;
2030
- const component = extendGroupedSidebar(original, activation, source, lifetime);
2429
+ const component = extendGroupedSidebar(original, activation, source, lifetime, ctx);
2031
2430
  wrapped.set(entry, { original, component });
2032
2431
  entry.component = component;
2033
2432
  }
@@ -2048,12 +2447,13 @@ function installSessionGrouping(ctx, activation) {
2048
2447
  }
2049
2448
 
2050
2449
  // src/patches/projectless-tasks/client/index.tsx
2051
- var clientPatch5 = {
2450
+ var clientPatch6 = {
2052
2451
  id: PROJECTLESS_TASKS_PATCH_ID,
2053
2452
  install: (ctx, activation) => {
2054
2453
  installSessionGrouping(ctx, activation);
2055
2454
  ctx.inject(["conversation", "uiWorkspace"], (scope) => {
2056
2455
  scope.effect(() => installNewSessionNavigation(scope, activation));
2456
+ scope.effect(() => installConversationFactoryAdapter(scope, activation));
2057
2457
  for (const name of CONVERSATION_SLOTS) {
2058
2458
  scope.slots.inject(conversationSlot(name), () => installConversationAdapter(scope, activation, name));
2059
2459
  }
@@ -2062,9 +2462,181 @@ var clientPatch5 = {
2062
2462
  }
2063
2463
  };
2064
2464
 
2465
+ // src/patches/terminal-clipboard/shared.ts
2466
+ var TERMINAL_CLIPBOARD_PATCH_ID = "terminal-clipboard";
2467
+
2468
+ // src/patches/terminal-clipboard/client/terminal.ts
2469
+ function record(value) {
2470
+ return value !== null && typeof value === "object" ? value : void 0;
2471
+ }
2472
+ function terminal(value, root) {
2473
+ const candidate = record(value);
2474
+ if (candidate?.element !== root || !candidate.textarea || candidate.textarea !== root.querySelector("textarea.xterm-helper-textarea")) return;
2475
+ if (!record(candidate.options) || typeof candidate.getSelection !== "function" || typeof candidate.paste !== "function" || typeof candidate.focus !== "function") return;
2476
+ return candidate;
2477
+ }
2478
+ function resolveTerminal(root) {
2479
+ for (let node = root, depth = 0; node && depth < 4; node = node.parentElement, depth++) {
2480
+ const key = Object.keys(node).find((key2) => key2.startsWith("__reactFiber$"));
2481
+ if (!key) continue;
2482
+ let fiber = record(node[key]);
2483
+ for (let level = 0; fiber && level < 12; level++, fiber = record(fiber.return)) {
2484
+ for (const version of [fiber, record(fiber.alternate)]) {
2485
+ let hook = record(version?.memoizedState);
2486
+ for (let index = 0; hook && index < 32; index++, hook = record(hook.next)) {
2487
+ const found = terminal(record(hook.memoizedState)?.current, root);
2488
+ if (found) return found;
2489
+ }
2490
+ }
2491
+ }
2492
+ }
2493
+ }
2494
+
2495
+ // src/patches/terminal-clipboard/client/clipboard.ts
2496
+ function installTerminalClipboard(doc, resolve = resolveTerminal) {
2497
+ let active = true;
2498
+ let gesture;
2499
+ let pasteRevision = 0;
2500
+ let notice;
2501
+ let noticeTimer;
2502
+ const clipboard = doc.defaultView?.navigator.clipboard;
2503
+ const rootAt = (target) => {
2504
+ if (!(target instanceof Element)) return;
2505
+ return target.closest(".xterm") ?? void 0;
2506
+ };
2507
+ const report = (action) => {
2508
+ if (!active) return;
2509
+ notice?.remove();
2510
+ clearTimeout(noticeTimer);
2511
+ notice = doc.createElement("div");
2512
+ notice.setAttribute("role", "status");
2513
+ notice.setAttribute("data-dshmore-terminal-notice", "");
2514
+ notice.textContent = "\u7EC8\u7AEF" + action + "\u5931\u8D25\uFF1A\u8BF7\u5141\u8BB8\u526A\u8D34\u677F\u8BBF\u95EE\uFF0C\u6216\u7528 Shift+\u53F3\u952E\u6253\u5F00\u539F\u751F\u83DC\u5355\uFF1B\u4E5F\u53EF\u4F7F\u7528 macOS \u7684 \u2318C/\u2318V \u6216\u7CFB\u7EDF\u539F\u751F\u7C98\u8D34\u5FEB\u6377\u952E\u3002";
2515
+ notice.style.cssText = "position:fixed;bottom:24px;right:24px;z-index:10000;max-width:360px;padding:12px 16px;border-radius:8px;background:#252525;color:#fff;font-size:13px;box-shadow:0 4px 20px #0005";
2516
+ doc.body.append(notice);
2517
+ noticeTimer = setTimeout(() => {
2518
+ notice?.remove();
2519
+ notice = void 0;
2520
+ }, 6e3);
2521
+ };
2522
+ const copy = async (text) => {
2523
+ if (!text || !active) return;
2524
+ try {
2525
+ if (!clipboard?.writeText) throw new Error("Clipboard unavailable");
2526
+ await clipboard.writeText(text);
2527
+ } catch {
2528
+ report("\u590D\u5236");
2529
+ }
2530
+ };
2531
+ const paste = async (root, term) => {
2532
+ const revision = ++pasteRevision;
2533
+ if (term.options.disableStdin) return;
2534
+ term.focus();
2535
+ try {
2536
+ if (!clipboard?.readText) throw new Error("Clipboard unavailable");
2537
+ const text = await clipboard.readText();
2538
+ if (!active || revision !== pasteRevision || !root.isConnected || resolve(root) !== term || term.options.disableStdin || !root.contains(doc.activeElement)) return;
2539
+ if (text) term.paste(text);
2540
+ } catch {
2541
+ report("\u7C98\u8D34");
2542
+ }
2543
+ };
2544
+ const consume = (event) => {
2545
+ event.preventDefault();
2546
+ event.stopImmediatePropagation();
2547
+ };
2548
+ const contextmenu = (event) => {
2549
+ if (event.shiftKey) return;
2550
+ const root = rootAt(event.target);
2551
+ const term = root && resolve(root);
2552
+ if (!root || !term || term.options.disableStdin) return;
2553
+ consume(event);
2554
+ void paste(root, term);
2555
+ };
2556
+ const keydown = (event) => {
2557
+ if (event.isComposing || event.altKey) return;
2558
+ const root = rootAt(event.target);
2559
+ const term = root && resolve(root);
2560
+ if (!root || !term) return;
2561
+ const key = event.key.toLowerCase();
2562
+ if (key === "c" && (event.ctrlKey || event.metaKey)) {
2563
+ const selection = term.getSelection();
2564
+ if (!selection) return;
2565
+ if (event.metaKey && !event.ctrlKey) return;
2566
+ consume(event);
2567
+ if (!event.repeat) void copy(selection);
2568
+ } else if (key === "v" && event.ctrlKey && event.shiftKey && !event.metaKey || key === "insert" && event.shiftKey && !event.ctrlKey && !event.metaKey) {
2569
+ if (term.options.disableStdin) return;
2570
+ consume(event);
2571
+ if (!event.repeat) void paste(root, term);
2572
+ }
2573
+ };
2574
+ const mousedown = (event) => {
2575
+ gesture = void 0;
2576
+ if (event.button !== 0 || event.ctrlKey || event.metaKey || event.altKey) return;
2577
+ const root = rootAt(event.target);
2578
+ const term = root && resolve(root);
2579
+ if (root && term) gesture = { root, before: term.getSelection() };
2580
+ };
2581
+ const mouseup = (event) => {
2582
+ const started = gesture;
2583
+ gesture = void 0;
2584
+ if (event.button !== 0 || !started) return;
2585
+ queueMicrotask(() => {
2586
+ if (!active || !started.root.isConnected) return;
2587
+ const text = resolve(started.root)?.getSelection();
2588
+ if (text && text !== started.before) void copy(text);
2589
+ });
2590
+ };
2591
+ const blur = () => {
2592
+ gesture = void 0;
2593
+ pasteRevision++;
2594
+ };
2595
+ doc.addEventListener("contextmenu", contextmenu, true);
2596
+ doc.addEventListener("keydown", keydown, true);
2597
+ doc.addEventListener("mousedown", mousedown, true);
2598
+ doc.addEventListener("mouseup", mouseup, true);
2599
+ doc.defaultView?.addEventListener("blur", blur);
2600
+ return () => {
2601
+ active = false;
2602
+ blur();
2603
+ doc.removeEventListener("contextmenu", contextmenu, true);
2604
+ doc.removeEventListener("keydown", keydown, true);
2605
+ doc.removeEventListener("mousedown", mousedown, true);
2606
+ doc.removeEventListener("mouseup", mouseup, true);
2607
+ doc.defaultView?.removeEventListener("blur", blur);
2608
+ clearTimeout(noticeTimer);
2609
+ notice?.remove();
2610
+ };
2611
+ }
2612
+
2613
+ // src/patches/terminal-clipboard/client/index.ts
2614
+ var clientPatch7 = {
2615
+ id: TERMINAL_CLIPBOARD_PATCH_ID,
2616
+ install: (ctx, activation) => {
2617
+ ctx.effect(() => {
2618
+ let dispose;
2619
+ const sync = () => {
2620
+ if (activation.getSnapshot()[TERMINAL_CLIPBOARD_PATCH_ID]) {
2621
+ dispose ??= installTerminalClipboard(document);
2622
+ } else {
2623
+ dispose?.();
2624
+ dispose = void 0;
2625
+ }
2626
+ };
2627
+ const unsubscribe = activation.subscribe(sync);
2628
+ sync();
2629
+ return () => {
2630
+ unsubscribe();
2631
+ dispose?.();
2632
+ };
2633
+ });
2634
+ }
2635
+ };
2636
+
2065
2637
  // src/generated/client-registry.ts
2066
2638
  var MESSAGE_ACTION_PATCHES = [{ id: "message-edit", order: 100, useActions: useMessageActions }, { id: "message-delete", order: 200, useActions: useMessageActions2 }];
2067
- var CLIENT_PATCHES = [clientPatch, clientPatch2, clientPatch3, clientPatch4, clientPatch5];
2639
+ var CLIENT_PATCHES = [clientPatch, clientPatch2, clientPatch3, clientPatch4, clientPatch5, clientPatch6, clientPatch7];
2068
2640
 
2069
2641
  // src/kernel/client/activation.ts
2070
2642
  var ClientPatchActivation = class {
@@ -2087,18 +2659,18 @@ var ClientPatchActivation = class {
2087
2659
  };
2088
2660
 
2089
2661
  // src/kernel/client/config-card.tsx
2090
- var import_react11 = require("react");
2091
- var import_jsx_runtime10 = require("react/jsx-runtime");
2662
+ var import_react13 = require("react");
2663
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2092
2664
  function PatchConfigCard({ activation, initiallyOpen = false }) {
2093
- const scope = (0, import_react11.useSyncExternalStore)(
2665
+ const scope = (0, import_react13.useSyncExternalStore)(
2094
2666
  activation.subscribe,
2095
2667
  activation.getSettingsSnapshot,
2096
2668
  activation.getSettingsSnapshot
2097
2669
  );
2098
2670
  const settings = activation.getSnapshot();
2099
- const [open, setOpen] = (0, import_react11.useState)(initiallyOpen);
2100
- const [busy, setBusy] = (0, import_react11.useState)(/* @__PURE__ */ new Set());
2101
- const [error, setError] = (0, import_react11.useState)(null);
2671
+ const [open, setOpen] = (0, import_react13.useState)(initiallyOpen);
2672
+ const [busy, setBusy] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
2673
+ const [error, setError] = (0, import_react13.useState)(null);
2102
2674
  if (scope.status === "unavailable") return null;
2103
2675
  const update = async (id, enabled) => {
2104
2676
  setBusy((current) => /* @__PURE__ */ new Set([...current, id]));
@@ -2115,9 +2687,9 @@ function PatchConfigCard({ activation, initiallyOpen = false }) {
2115
2687
  });
2116
2688
  }
2117
2689
  };
2118
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("li", { className: `dshmore-config-card${open ? " dshmore-config-card-open" : ""}`, children: [
2119
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("style", { children: styles }),
2120
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2690
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("li", { className: `dshmore-config-card${open ? " dshmore-config-card-open" : ""}`, children: [
2691
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("style", { children: styles }),
2692
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2121
2693
  "button",
2122
2694
  {
2123
2695
  type: "button",
@@ -2128,23 +2700,23 @@ function PatchConfigCard({ activation, initiallyOpen = false }) {
2128
2700
  setOpen((current) => !current);
2129
2701
  },
2130
2702
  children: [
2131
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "dshmore-config-heading-copy", children: [
2132
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "DSH More" }),
2133
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "\u52A8\u6001\u5F00\u542F\u6216\u5173\u95ED\u72EC\u7ACB\u8865\u4E01\uFF0C\u9ED8\u8BA4\u5168\u90E8\u5F00\u542F\u3002" })
2703
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "dshmore-config-heading-copy", children: [
2704
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "DSH More" }),
2705
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "\u52A8\u6001\u5F00\u542F\u6216\u5173\u95ED\u72EC\u7ACB\u8865\u4E01\uFF0C\u9ED8\u8BA4\u5168\u90E8\u5F00\u542F\u3002" })
2134
2706
  ] }),
2135
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconChevronDownOutline14, { size: 14, className: `dshmore-config-chevron${open ? " dshmore-config-chevron-open" : ""}` })
2707
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconChevronDownOutline14, { size: 14, className: `dshmore-config-chevron${open ? " dshmore-config-chevron-open" : ""}` })
2136
2708
  ]
2137
2709
  }
2138
2710
  ),
2139
- open && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dshmore-config-body", children: [
2140
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dshmore-config-list", children: PATCH_CATALOG.map((patch) => {
2711
+ open && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "dshmore-config-body", children: [
2712
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dshmore-config-list", children: PATCH_CATALOG.map((patch) => {
2141
2713
  const waiting = busy.has(patch.id);
2142
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "dshmore-config-row", children: [
2143
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "dshmore-config-copy", children: [
2144
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: patch.name }),
2145
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: patch.description })
2714
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "dshmore-config-row", children: [
2715
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "dshmore-config-copy", children: [
2716
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: patch.name }),
2717
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: patch.description })
2146
2718
  ] }),
2147
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2719
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2148
2720
  "input",
2149
2721
  {
2150
2722
  type: "checkbox",
@@ -2159,9 +2731,9 @@ function PatchConfigCard({ activation, initiallyOpen = false }) {
2159
2731
  )
2160
2732
  ] }, patch.id);
2161
2733
  }) }),
2162
- scope.status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "dshmore-config-note", children: "\u6B63\u5728\u8BFB\u53D6\u63D2\u4EF6\u914D\u7F6E\u2026" }),
2163
- scope.status === "ready" && !scope.writable && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "dshmore-config-note", children: "\u5F53\u524D Settings \u5B58\u50A8\u4E3A\u53EA\u8BFB\u3002" }),
2164
- error !== null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "dshmore-config-error", children: error })
2734
+ scope.status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "dshmore-config-note", children: "\u6B63\u5728\u8BFB\u53D6\u63D2\u4EF6\u914D\u7F6E\u2026" }),
2735
+ scope.status === "ready" && !scope.writable && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "dshmore-config-note", children: "\u5F53\u524D Settings \u5B58\u50A8\u4E3A\u53EA\u8BFB\u3002" }),
2736
+ error !== null && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "dshmore-config-error", children: error })
2165
2737
  ] })
2166
2738
  ] });
2167
2739
  }
@@ -2172,21 +2744,22 @@ function installPatchConfigCard(ctx, activation) {
2172
2744
  id: PATCH_SETTINGS_NAMESPACE,
2173
2745
  order: 90,
2174
2746
  label: "DSH More"
2175
- }, () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PatchConfigCard, { activation, initiallyOpen: true }) })));
2747
+ }, () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PatchConfigCard, { activation, initiallyOpen: true }) })));
2176
2748
  return;
2177
2749
  }
2178
- ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
2750
+ const legacy = ctx.slots;
2751
+ legacy.inject("settings.plugin.item", () => legacy.register({
2179
2752
  name: "settings.plugin.item",
2180
2753
  key: PATCH_SETTINGS_NAMESPACE,
2181
2754
  priority: 90
2182
- }, () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PatchConfigCard, { activation })));
2755
+ }, () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PatchConfigCard, { activation })));
2183
2756
  }
2184
2757
 
2185
2758
  // src/kernel/message-visibility.ts
2186
2759
  var MESSAGE_VISIBILITY_PROJECTION_KEY = "dshMoreMessageDelete";
2187
2760
 
2188
2761
  // src/platform/dsh/client/message-targets.tsx
2189
- var import_react12 = require("react");
2762
+ var import_react14 = require("react");
2190
2763
 
2191
2764
  // src/platform/dsh/client/message-content.ts
2192
2765
  function contentText(content) {
@@ -2324,17 +2897,17 @@ function trajectorySourceSeq(row) {
2324
2897
  return Number.isSafeInteger(seq) && seq >= 0 ? seq : void 0;
2325
2898
  }
2326
2899
  function useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, active = true) {
2327
- const selector = (0, import_react12.useMemo)(() => createMessageSurfaceSelector(active), [active, props.sessionId]);
2900
+ const selector = (0, import_react14.useMemo)(() => createMessageSurfaceSelector(active), [active, props.sessionId]);
2328
2901
  const surface = props.useChat(selector);
2329
- const surfaceRef = (0, import_react12.useRef)(surface);
2330
- const hiddenSeqsRef = (0, import_react12.useRef)(hiddenSeqs);
2331
- const hiddenTrajectoryKeysRef = (0, import_react12.useRef)(hiddenTrajectoryKeys);
2902
+ const surfaceRef = (0, import_react14.useRef)(surface);
2903
+ const hiddenSeqsRef = (0, import_react14.useRef)(hiddenSeqs);
2904
+ const hiddenTrajectoryKeysRef = (0, import_react14.useRef)(hiddenTrajectoryKeys);
2332
2905
  surfaceRef.current = surface;
2333
2906
  hiddenSeqsRef.current = hiddenSeqs;
2334
2907
  hiddenTrajectoryKeysRef.current = hiddenTrajectoryKeys;
2335
- const [targets, setTargets] = (0, import_react12.useState)([]);
2336
- const requestFullScanRef = (0, import_react12.useRef)(null);
2337
- (0, import_react12.useLayoutEffect)(() => {
2908
+ const [targets, setTargets] = (0, import_react14.useState)([]);
2909
+ const requestFullScanRef = (0, import_react14.useRef)(null);
2910
+ (0, import_react14.useLayoutEffect)(() => {
2338
2911
  if (!active) {
2339
2912
  setTargets((current) => current.length === 0 ? current : []);
2340
2913
  return;
@@ -2437,12 +3010,12 @@ function useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, active = tru
2437
3010
  };
2438
3011
  requestFullScanRef.current = requestFullScan;
2439
3012
  const observer = new MutationObserver((records) => {
2440
- for (const record of records) {
2441
- if (record.removedNodes.length > 0) {
3013
+ for (const record2 of records) {
3014
+ if (record2.removedNodes.length > 0) {
2442
3015
  pruneDisconnected = true;
2443
- collectRows(record.target);
3016
+ collectRows(record2.target);
2444
3017
  }
2445
- record.addedNodes.forEach(collectRows);
3018
+ record2.addedNodes.forEach(collectRows);
2446
3019
  }
2447
3020
  if (pendingChatRows.size > 0 || pendingTrajectoryRows.size > 0 || pruneDisconnected) schedule();
2448
3021
  });
@@ -2458,21 +3031,21 @@ function useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, active = tru
2458
3031
  for (const host of document.querySelectorAll("[data-dshmore-message-actions]")) host.remove();
2459
3032
  };
2460
3033
  }, [active, props.sessionId]);
2461
- (0, import_react12.useLayoutEffect)(() => {
3034
+ (0, import_react14.useLayoutEffect)(() => {
2462
3035
  requestFullScanRef.current?.();
2463
3036
  }, [surface, hiddenSeqs, hiddenTrajectoryKeys]);
2464
3037
  return targets;
2465
3038
  }
2466
3039
 
2467
3040
  // src/client/index.tsx
2468
- var import_jsx_runtime11 = require("react/jsx-runtime");
3041
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2469
3042
  var inject = ["slots", "sessions", "workspaces"];
2470
3043
  function MessageActionPatchController({ patch, props, targets, enabled }) {
2471
3044
  const actions = patch.useActions(props, enabled);
2472
3045
  const style = { "--dshmore-action-order": patch.order };
2473
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3046
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2474
3047
  enabled && targets.map((target) => (0, import_react_dom.createPortal)(
2475
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dshmore-action-contribution", style, children: actions.renderAction(target) }),
3048
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dshmore-action-contribution", style, children: actions.renderAction(target) }),
2476
3049
  target.host,
2477
3050
  `${patch.id}:${target.key}`
2478
3051
  )),
@@ -2480,15 +3053,15 @@ function MessageActionPatchController({ patch, props, targets, enabled }) {
2480
3053
  ] });
2481
3054
  }
2482
3055
  function MessageActionsController(props) {
2483
- const settings = (0, import_react13.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
3056
+ const settings = (0, import_react15.useSyncExternalStore)(props.activation.subscribe, props.activation.getSnapshot);
2484
3057
  const projected = props.useProjection(MESSAGE_VISIBILITY_PROJECTION_KEY);
2485
- const hiddenSeqs = (0, import_react13.useMemo)(() => new Set(projected?.deletedSeqs ?? []), [projected]);
2486
- const hiddenTrajectoryKeys = (0, import_react13.useMemo)(() => new Set(projected?.hiddenTrajectoryKeys ?? []), [projected]);
3058
+ const hiddenSeqs = (0, import_react15.useMemo)(() => new Set(projected?.deletedSeqs ?? []), [projected]);
3059
+ const hiddenTrajectoryKeys = (0, import_react15.useMemo)(() => new Set(projected?.hiddenTrajectoryKeys ?? []), [projected]);
2487
3060
  const messageActionsEnabled = MESSAGE_ACTION_PATCHES.some((patch) => settings[patch.id]);
2488
3061
  const targets = useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, messageActionsEnabled);
2489
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2490
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("style", { children: styles }),
2491
- MESSAGE_ACTION_PATCHES.map((patch) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3062
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3063
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("style", { children: styles }),
3064
+ MESSAGE_ACTION_PATCHES.map((patch) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2492
3065
  MessageActionPatchController,
2493
3066
  {
2494
3067
  patch,
@@ -2514,7 +3087,7 @@ function install(ctx) {
2514
3087
  name: "conversation.session.header.utilities",
2515
3088
  id: `${PLUGIN_NAME}-message-actions`,
2516
3089
  order: 90
2517
- }, (props) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MessageActionsController, { ...props, ctx, activation })));
3090
+ }, (props) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageActionsController, { ...props, ctx, activation })));
2518
3091
  for (const patch of CLIENT_PATCHES) patch.install(ctx, activation);
2519
3092
  }
2520
3093
  return module.exports; } });